MAKEROM
A program to construct a "ROM image" from a number of individual files, which when blown into ROM and installed in a BBC micro, will allow the BBC to read the files using its ROM filing system.
by
Christopher J Adie
Copyright (C) 1984 ERCC. This documentation and the accompanying program may be used and distributed for educational and academic purposes only. Copying or publishing for commercial gain is prohibited.
This document describes how to take a number of files (of any description) on the BBC micro, and combine them together with some machine code into an output file which can then be blown onto ROM and installed in a BBC micro without disks. The main use of this is to provide a quick and easy way of loading one or more BASIC programs into a BBC without having to have a disk drive attached.
The BBC micro has a number of "Filing Systems" which it uses for all file I/O operations. The major ones with which most users are likely to be familiar are the Tape Filing System and the Disk Filing System (DFS). Only one Filing System can be active at a time. The active Filing System can be changed using a star command such as *TAPE or *DISK. Each Filing System generally comes on a sideways ROM chip (an exception being *TAPE, which is on the operating system chip.
As well as the above mentioned, there are a variety of other Filing Systems, such as the Econet Filing System (*NET), the IEEE488 Filing System (*IEEE), and the ROM Filing System (*ROM). It is the last which concerns us here.
There are two kinds of ROM which are supported by this program. They are type numbers 2764 and 27128, holding 8 Kbytes and 16 Kbytes of data respectively. Note that this program will be of little use to you unless you have access to facilities for blowing these chips using a BBC micro.
Decide which files you wish to store on ROM. Note that the total space available to you on the ROM is reduced by about 108 bytes, to allow for necessary machine code at the beginning of the ROM, and further reduced by up to 60 bytes for every file stored and by one further byte for every 256 bytes of file data stored. The program will tell you if there is no room for the file you wish to store.
The output file will be in "ROM image" form, and should be suitable for blowing into EPROM using an EPROM programmer and corresponding software.
The program should be LOADed and RUN just like any other BASIC program. It will prompt for the ROM type (2764 or 27128) to which an appropriate response should be made.
It will then obtain the file LOAD and EXECUTE addresses from the directory of the disk, and print them. The file will be stored on ROM together with this information. You are then asked for the name of the file on the ROM, which need not be the same as the name on disk. Readine the file from disk and formatting it for the ROM takes a few seconds. You are asked if you wish to store another file on the ROM, in which case it will go back and prompt for the file name on disk. Otherwise, it will ask for a filename to use for the output ROM image file. This is the file to program into your EPROM.
Having installed the EPROM containing your files, you must select the ROM Filing System. Type *ROM followed by return. You will now be able to use *CAT to see what files you have and *INFO to look at their load and execute addresses.
If one of the files is a BASIC program, it may be LOADed or CHAINed in the usual way. Note that if you enter LOAD "" or CHAIN "", the first file on the ROM will be accessed. Other files must be referred to by name. In this and some other respects, the ROM Filing System is more like the Tape Filing System than the DFS.
Finally, you should note that it is impossible to write to files using the ROM Filing System. Thus, you cannot SAVE a BASIC program, for instance.
For further information, see the Advanced User Guide for the BBC Micro, by Bray, Dickens and Holmes. Relevant sections are Chapter 16, particularly sections 6.10 and 6.11, and section 15.4.
Contributed by ERCC Real Time Support Group Tel 031 667 1081 ext 2611
This document describes how to take a number of files (of any description) on the BBC micro, and combine them together with some machine code into an output file which can then be blown onto ROM and installed in a BBC micro without disks. The main use of this is to provide a quick and easy way of loading one or more BASIC programs into a BBC without having to have a disk drive attached.
10REM ******************************************************
20REM * MAKEROM - Generating a ROM Filing System *
30REM * Paged ROM *
40REM * *
50REM * This program generates a ROM containing a filing *
60REM * system which accesses data files held in the *
70REM * ROM itself. See the Advanced User Guide pages *
80REM * 330-331 and 349f for more information. *
90REM * *
100REM * Christopher J Adie ERCC RTSG 16 Nov 1983 V.1.0 *
110REM ******************************************************
120REM
130
140MODE7
150B%=&3F00 :REM B% points to the bottom of the buffer.
160HIMEM=B%
170
180DIM CODE 64
190OSFILE=&FFDD
200offset = &8000 - B%
210
220PROCassemblesidecode
230
240REPEAT
250INPUT "ROM Type (2764/27128) ? "ROMTYPE%
260UNTIL ROMTYPE%=2764 OR ROMTYPE%=27128
270endofROM = (ROMTYPE% MOD 10)*2048 + B%
275PRINT
280
290REPEAT
300PROCsavefile
310PRINT ~(endofROM-D%);" bytes left"
320REPEAT
325PRINT
330INPUT "Another file (Y/N) ? "ANSWER$
340UNTIL ANSWER$="Y" OR ANSWER$="y" OR ANSWER$="N" OR ANSWER$="n"
350UNTIL ANSWER$="N" OR ANSWER$="n"
360?D%=&2B
370
380INPUT "ROM image filename ? "FILENAME$
390A$=FNhex(B%)
400B$=FNhex(endofROM)
410OSCLI "SAVE "+FILENAME$+" "+A$+" "+B$
420END
430
440REM ------------------End of main program--------------------------
450
460DEF FNhex(NUM%)
470REM Return a string containing the hex equivalent of the argument
480LOCAL N1%,N2%,N3%,N4%
490N4%=NUM% MOD 16 : NUM%=NUM% DIV 16
500N3%=NUM% MOD 16 : NUM%=NUM% DIV 16
510N2%=NUM% MOD 16 : NUM%=NUM% DIV 16
520N1%=NUM% MOD 16
530=FNhexdgt(N1%)+FNhexdgt(N2%)+FNhexdgt(N3%)+FNhexdgt(N4%)
540
550DEF FNhexdgt(NX%)
560REM Return character = the hex digit corresponding to the argument
570IF NX%<10 THEN =CHR$(NX%+48) ELSE =CHR$(NX%+55)
580
590DEF PROCsavefile
600startoffile=D%
610handle=FNgetfile
620PROCgetparameters
630filelength=EXT#(handle)
650REPEAT
660INPUT "Filename on ROM ? "ROMfilename$
670UNTIL LEN(ROMfilename$)<=10
675IF NOT FNenoughroom THEN PRINT"Insufficient room in ROM":CLOSE# handle:ENDPROC
680bytesremaining=filelength
690block=0
700IF bytesremaining=0 THEN PRINT "File empty":CLOSE# handle:ENDPROC
710IF bytesremaining>256 THEN PROCfirstblock ELSE PROClastblock:ENDPROC
720REPEAT
730block=block+1
740IF bytesremaining>256 THEN PROCsaveblock ELSE PROClastblock
750UNTIL bytesremaining=0
760ENDPROC
770
780DEF FNgetfile
790LOCAL X
800REPEAT
810INPUT "File to save ? "FILENAME$
820X=OPENIN(FILENAME$)
830IF X=0 PRINT"File not found"
840UNTIL X<>0
850=X
860
870DEF PROCgetparameters
880LOCAL pblock,fname
890DIM pblock 18
900DIM fname 32
910$fname=FILENAME$+CHR$(13)
920?pblock=fname MOD 256
930?(pblock+1)=fname DIV 256
940A%=5
950X%=pblock MOD 256
960Y%=pblock DIV 256
970CALL OSFILE
980loadaddress=!(pblock+2)
990executionaddress=!(pblock+6)
1000PRINT "Load address is ";~loadaddress
1010PRINT "Execution address is ";~executionaddress
1020ENDPROC
1030
1040DEF FNenoughroom
1050LOCAL blocks,headerlength
1060blocks=((filelength-1)DIV256)+1
1070headerlength=21+LEN(ROMfilename$)
1080IF blocks>1 THEN headerlength=2*headerlength
1090ROMfilelength=filelength+headerlength
1095IF blocks>2 THEN ROMfilelength=ROMfilelength+blocks-2
1096ROMfilelength=ROMfilelength+2*blocks
1100IF D%+ROMfilelength+1<endofROM THEN =TRUE ELSE =FALSE
1110
1120DEF PROCfirstblock
1130PROCheader(0,256,FALSE)
1140PROCsavedata(256)
1150ENDPROC
1160
1170DEF PROClastblock
1180PROCheader(block,bytesremaining,TRUE)
1190PROCsavedata(bytesremaining)
1200CLOSE# handle
1210ENDPROC
1220
1230DEF PROCsaveblock
1240?D%=&23 : D%=D%+1
1250PROCsavedata(256)
1260ENDPROC
1270
1280DEF PROCheader(blocknumber,blocklength,lastblock)
1300?D%=&2A:D%=D%+1
1305headerpointer=D%
1310$D%=ROMfilename$:D%=D%+LEN(ROMfilename$)
1320?D%=0:D%=D%+1
1330!D%=loadaddress:D%=D%+4
1340!D%=executionaddress:D%=D%+4
1350?D%=blocknumber AND &FF:?(D%+1)=blocknumber DIV 256:D%=D%+2
1360?D%=blocklength AND &FF:?(D%+1)=blocklength DIV 256:D%=D%+2
1370IF lastblock THEN blockflag=&80 ELSE blockflag=0
1380?D%=blockflag:D%=D%+1
1390!D%=(startoffile+ROMfilelength+offset) OR &FFFF0000:D%=D%+4
1400PROCappendCRC(headerpointer)
1410ENDPROC
1420
1430DEF PROCsavedata(length)
1440startofdata=D%
1450FOR count=1 TO length
1460?D%=BGET#(handle)
1470D%=D%+1
1480NEXT count
1490PROCappendCRC(startofdata)
1500bytesremaining=bytesremaining-length
1510ENDPROC
1520
1530DEF PROCappendCRC(data)
1540LOCAL pass,pass1,pass2,H,L,lblk
1550pass1=0:pass2=2
1560lblk=D%-data
1570H=D%:L=D%+1
1580FOR pass=pass1 TO pass2 STEP pass2-pass1
1590P%=CODE
1600[OPT pass
1610LDA #0
1620STA H \Initialise CRC
1630STA L
1640TAY \Initialise data pointer
1650.nbyt
1660LDA H
1670EOR data,Y
1680STA H
1690LDX #8
1700.loop
1710LDA H
1720ROL A
1730BCC b7z
1740LDA H
1750EOR #8
1760STA H
1770LDA L
1780EOR #&10
1790STA L
1800.b7z
1810ROL L
1820ROL H
1830DEX
1840BNE loop
1850INY
1860CPY #lblk AND &FF
1870BNE nbyt
1880RTS
1890]
1900NEXT pass
1910CALL CODE
1920D%=D%+2
1930ENDPROC
1940
1950
1960DEF PROCassemblesidecode
1970
1980pass1=4 : pass2=6
1990FOR pass=pass1 TO pass2 STEP pass2-pass1
2000P%=&8000
2010O%=B%
2020[OPT pass
2030
2040.startsidecode
2050BRK:BRK:BRK No language entry point
2060JMP serviceentry
2070EQUB &82 Service, no language
2080EQUB (cstring-startsidecode) AND &FF
2090EQUB 1 Version number in binary
2100EQUS "ROM Filing System"
2110.cstring: EQUB 0
2120EQUS "(C) ERCC 1983"
2130EQUB 0
2140
2150.serviceentry Despatch on the service call type
2160CMP #&0D
2170BNE not0D
2180JMP call0D
2190.not0D
2200CMP #&0E
2210BNE not0E
2220JMP call0E
2230.not0E
2240.exit Call not recognised by this ROM
2250RTS
2260
2270.call0D Initialise ROM filing system
2280PHA Save the service call number
2290TYA Logical ROM number
2300EOR #&0F Adjust it
2310CMP &F4 Is it for us?
2320BCC notus No, it is less, so this ROM done already
2330LDA #data MOD 256
2340STA &F6
2350LDA #data DIV 256
2360STA &F7 Initialise data pointer at &F6 and 7
2370LDA &F4 Get our ROM number
2380EOR #&0F Readjust it
2390STA &F5 Pass over any higher non-filing-system ROMs
2400PLA Discard service call number
2410LDA #0 Service type becomes no-op
2420RTS Exit
2430
2440.notus
2450PLA Call not for us, so restore service call no
2460RTS And return
2470
2480.call0E Byte request call
2490PHA Save the service call number
2500LDA &F5 Get current ROM number
2510EOR #&0F
2520CMP &F4 Is it us?
2530BNE notus No
2540LDY #0
2550LDA (&F6),Y Get the data
2560TAY Returned in Y
2570INC &F6
2580BNE ninc7 Increment data pointer
2590INC &F7
2600.ninc7
2610PLA Discard service type
2620LDA #0 Service type becomes no-op
2630RTS Exit
2640
2650.endsidecode
2660.data
2670
2680]
2690NEXT pass
2700
2710D% = data + (B%-&8000)
2720
2730ENDPROC
Fails: Unbalanced brackets