Mastering Sideways ROM & RAM - Module 21 - RFS language ROM ----------------------------------------------------------- In Module 20 you were shown one way in which programs stored in the RFS can be run with * commands. The programs used to demonstrate the technique created a service ROM image. In this module I will show you how a language ROM design can be used to achieve a similar effect. One reason why you might choose to implement an RFS language ROM is that it will enable you to design a so called turnkey system as well as allow you to run the RFS software with a new * command. A turnkey computer system is one which automatically runs custom software when it is switched on. If you have a language ROM in socket &0F, or in a battery backed-up sideways RAM socket &0F, then that ROM image will be booted when the computer is switched on and when Ctrl+Break is pressed. This is true for all language ROMs in the highest priority ROM socket but, if your custom software is written in BASIC, you would normally have to re-write your program as an independant machine code language to run it in this way. Using an RFS language ROM will allow you to use your software in a turnkey system without translating it into an independant machine code program. An RFS language ROM can be used in socket &0F of the BBC B simply by moving the other ROM chips to make room for it. On the BBC B+ it is necessary to alter link S13 (to the right of IC46) to give the highest priority ROM socket on the circuit board priority over BASIC. The RFS language ROM image can be configured as the start up language on the Master by using the *CONFIGURE LANG command. The RFS language ROM can also be used in a lower priority socket than BASIC when it will function like any other language ROM and it will be selected when called with *FX142,n or its * command. In the program RFSERV the interpreter passed control to a service routine which selected the RFS, stored a Chain command in the keyboard buffer, and then entered BASIC which executed the command in the keyboard buffer. The program RFSLANG achieves the same result by entering a language which eventually executes the same coding used by the service routine in RFSERV. The one command interpreter is used in the program RFSLANG to compare an unrecognised command with the title string of the ROM. If a match is found the ROM uses Osbyte &8E to enter the ROM at its language entry point. When the ROM is entered at its language entry point it must first enable interupts, reset the stack, and re-vector the break vector to point to an error handling routine (see module 17). The complete language coding from RFSLANG is shown in figure 21.1 .language CLI \ enable interupt requests LDX #&FF TXS \ reset stack LDA #basic MOD 256 \ low byte of enter BASIC address STA &202 \ store in Break vector low byte LDA #basic DIV 256 \ high byte of enter BASIC address STA &203 \ store in Break vector high byte LDA #&8D \ Osbyte &8D JSR &FFF4 \ *ROM LDA #&8B \ Osbyte &8B LDX #1 LDY #0 JSR &FFF4 \ *OPT 1,0 LDA #&0F \ Osbyte &0F LDX #0 JSR &FFF4 \ flush all buffers LDA #&FF \ initialise offset PHA \ store offset .keyboard PLA \ restore offset TAX \ transfer offset to X INX \ increment offset TXA \ copy offset to A PHA \ store offset LDY rfscomm,X \ load character BEQ basic \ branch if end of text character LDA #&8A \ Osbyte &8A LDX #0 JSR &FFF4 \ character into keyboard buffer JMP keyboard \ go for next character .basic LDA #&BB \ Osbyte &BB LDX #0 LDY #&FF JSR &FFF4 \ find BASIC LDA #&8E \ Osbyte &8E JMP &FFF4 \ enter BASIC no return . . . .rfscomm EQUS "CHAIN""DEMO""" \ chain command for BASIC EQUB &0D \ BRK \ end of text marker Figure 21.1 The language coding from RFSLANG. ----------- --------------------------------- The break vector in RFSLANG points to the code which finds and enters BASIC so that, if an error is generated while the language is active, it responds by entering BASIC. The language defined by RFSLANG will only ever be active for a few milli-seconds before it selects BASIC to replace it and generating an error is quite unlikely. I have been unable to generate an error within the language when testing the program. This short cut method of dealing with errors by ignoring them means that the ROM will need to be re-booted if they occur. After initialising the language the coding does the same job as the service routine in RFSERV. It selects the RFS, inserts the Chain command into the keyboard buffer, and finds and enters BASIC. When BASIC is entered in this way it executes the command in the keyboard buffer and chains the file from the RFS. The program RFSLANG must be used with the formatting program RFSGEN and whatever programs you want to store in the RFS. These programs are used to create the RFS ROM image and detailed instructions on using them were included in Module 18. RFSLANG was written to be used with the supplied demonstration program DEMO. If you want to use it with any other program you will need to alter the command string in lines 1310 to 1330. You can also alter the ROM title string in line 220 if you would prefer to select the language with a command other than *RFS. 10 REM: RFSLANG 20 MODE7 30 HIMEM=&3C00 40 diff=&8000-HIMEM 50 H%=HIMEM 60 comvec=&F2 70 ROMnumber=&F4 80 phROM=&F5 90 ROMpoint=&F6 100 breakv=&202 110 gsread=&FFC5 120 osbyte=&FFF4 130 FOR pass = 0 TO 2 STEP 2 140 P%=HIMEM 150 [ OPT pass 160 JMP language+diff 170 JMP service+diff 180 OPT FNequb(&C2) 190 OPT FNequb((copyright+diff) MOD 256) 200 BRK 210 .title 220 OPT FNequs("RFS") 230 .copyright 240 BRK 250 OPT FNequs("(C)1987 Gordon Horsington") 260 BRK 270 .service 280 PHA 290 CMP #4 300 BNE trythirteen 310 TXA 320 PHA 330 TYA 340 PHA 350 LDX #&FF 360 .comloop 370 INX 380 LDA title+diff,X 390 BEQ found 400 LDA (comvec),Y 410 INY 420 CMP #ASC(".") 430 BEQ found 440 AND #&DF 450 CMP title+diff,X 460 BEQ comloop 470 PLA 480 TAY 490 PLA 500 TAX 510 PLA 520 RTS 530 .found 540 LDA #&8E 550 LDX ROMnumber 560 JMP osbyte \ Enter this ROM 570 .trythirteen 580 CMP #13 590 BNE fourteen 600 TYA 610 EOR #&F 620 CMP ROMnumber 630 BCC out 640 LDA #(lastbyte+diff) MOD 256 650 STA ROMpoint 660 LDA #(lastbyte+diff) DIV 256 670 STA ROMpoint+1 680 LDA ROMnumber 690 EOR #&F 700 STA phROM 710 .exit 720 PLA 730 LDA #0 740 RTS 750 .fourteen 760 CMP #14 770 BNE out 780 LDA phROM 790 EOR #&F 800 CMP ROMnumber 810 BNE out 820 LDY #0 830 LDA (ROMpoint),Y 840 TAY 850 INC ROMpoint 860 BNE exit 870 INC ROMpoint+1 880 JMP exit+diff 890 .out 900 PLA 910 RTS 920 .language 930 CLI \ Enable interupt requests 940 LDX #&FF 950 TXS \ Reset stack 960 LDA #(basic+diff) MOD 256 970 STA breakv 980 LDA #(basic+diff) DIV 256 990 STA breakv+1 1000 LDA #&8D 1010 JSR osbyte \ *ROM 1020 LDA #&8B 1030 LDX #1 1040 LDY #0 1050 JSR osbyte \ *OPT1,0 1060 LDA #&0F 1070 LDX #0 1080 JSR osbyte \ Flush all buffers 1090 LDA #&FF 1100 PHA 1110 .keyboard 1120 PLA 1130 TAX 1140 INX 1150 TXA 1160 PHA 1170 LDY rfscomm+diff,X 1180 BEQ basic 1190 LDA #&8A 1200 LDX #0 1210 JSR osbyte 1220 JMP keyboard+diff 1230 .basic 1240 LDA #&BB 1250 LDX #0 1260 LDY #&FF 1270 JSR osbyte \ Find BASIC 1280 LDA #&8E 1290 JMP osbyte \ Enter BASIC 1300 .rfscomm 1310 OPT FNequs("CHAIN""DEMO""") 1320 OPT FNequb(&0D) 1330 BRK 1340 .lastbyte 1350 ] 1360 NEXT 1370 O%=lastbyte 1380 CHAIN"RFSGEN" 1390 DEFFNequb(byte) 1400 ?P%=byte 1410 P%=P%+1 1420 =pass 1430 DEFFNequw(word) 1440 ?P%=word 1450 P%?1=word DIV 256 1460 P%=P%+2 1470 =pass 1480 DEFFNequd(double) 1490 !P%=double 1500 P%=P%+4 1510 =pass 1520 DEFFNequs(string$) 1530 $P%=string$ 1540 P%=P%+LEN(string$) 1550 =pass