Mastering Sideways ROM & RAM - Module 16 - *HELP ------------------------------------------------ When you type *HELP the MOS responds by issuing service call 9 to all the active ROMs. All ROMs, except BASIC, have the opportunity to respond to service call 9, the *HELP service call. The way in which a ROM responds to this call usually depends on whether it is a language or a service ROM. There are no hard and fast rules about how an individual ROM should respond to a help request but language ROMs usually print the title string from the ROM header and service ROMs print an identification string followed by the argument to be used to get extended help. The response required from a language ROM will be covered in the next module of the course. The interpreter simply needs to intercept service call 9, make sure that no argument has been typed, and then print every byte of the title string. This will be demonstrated by the example program in Module 17. The response required from a service ROM is more elaborate than that provided by a language ROM. It is illustrated in figures 16.1 and 16.2 in which the help service provided by the example program HELP is shown with the service call trace active in a higher priority ROM. >*HELP 6502 TUBE 1.10 A=09 X=0F Y=05 Help COLOURED TEXT COLOURS OS 1.20 > Figure 16.1 Simple *HELP with trace active. ----------- ------------------------------- When you type *HELP each active ROM is entered with A=9, X=the ROM number, and Y=the offset to the first non-space character after the *HELP command. This indicates that any argument typed after the *HELP command is not initialised quite as you would expect it to be by the Gsinit MOS subroutine. If you intend to write an extended help service in which the argument can be enclosed in quotation marks, the argument will first need to be initialised with Gsinit. If you don't feel it is necessary to include this extra refinement then there is no need to initialise the argument. >*HELP COLOURS 6502 TUBE 1.10 A=09 X=0F Y=06 Help BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE BLAWHIT REDCYAN GREEMAG YELLBLU BLUYELL MAGREEN CYANRED WHIBLAC OS 1.20 > Figure 16.2 *HELP COLOURS with trace active. ----------- -------------------------------- The trace in figure 16.2 shows that the Y register points to the first character of the argument, as long as the argument is not enclosed in quotation marks. In spite of this, the example program still uses Gsinit to initialise the argument to allow the program to respond to *HELP "COLOURS" as well as to *HELP COLOURS shown in figure 16.2. The program HELP uses the multiple command interpreter first introduced in Module 15. I will not explain again how it works but there is one important feature worth looking at, namely the command table starting in line 1320. It is quite clear that the new commands are included in the table with the longest commands at the head and the shortest commands at the foot of the table. This order must be maintained if you add new commands to the table. The text of the two possible responses to the *HELP command have to be included in the program. The text of the response to *HELP is labeled ".helpmsg" and starts in line 1820. The extended help message starts at the label ".helpinfo" in line 1910. The label ".helptitle" (line 1870) marks the start of the argument used for extended help. The content of the simple help text starting at ".helpmsg" is reproduced in figure 16.3. The structure of this text is important to the proper working of the help interpreter. The string starting at the label ".helptitle" is terminated with &FF. This argument termination byte must be included to mark the end of the argument used to request extended help. Any character with the most significant bit set is ignored by the print subroutine (lines 2250-2350). The extended help argument string is compared with any argument typed after *HELP to see if extended help is required. The zero byte at the end of the simple help text is used to indicate the end of text to the print subroutine. .helpmsg EQUB &0D \ carriage return EQUS "COLOURED TEXT" \ ROM contents EQUB &0D \ carriage return EQUS " " \ two spaces .helptitle EQUS "COLOURS" \ expected extended help argument EQUS &FF \ argument termination byte EQUW &0D \ carriage return BRK \ end of message Figure 16.3 The text of the simple help message. ----------- ------------------------------------ The text starting at label ".helpinfo" in line 1910 is printed when extended help is requested. This text can be up to 255 bytes long and must end with a zero byte. Any byte with the most significant bit set is not printed. It is usual to include the syntax of the commands implemented in the ROM in the extended help, but you are free to write whatever you like. The example program prints the syntax of sixteen new commands which can be used to change actual colour of the default text colour in modes 0-6. The default text colour is white in all modes but you can change it to red with *RED or flashing red-cyan with *REDCYAN. The program uses the machine code equivalent of the VDU19 command to achieve this effect. The order of the commands in the extended help message does not have to be the same as the order in the command table. In the example program the order reflects the logical order of the sixteen available colours. The interpreter in the program HELP pushes the registers and two zero page bytes on the stack (lines 320-400), intercepts service call 9 (line 430) and initialises the *HELP argument (lines 450-460). The X register is reset to zero (line 470) ready to be used as an index on the expected extended help argument. The first byte of the argument is read (line 480) and, if an argument is present, a branch is made to the label ".tryextended" (line 490 and line 570). If an argument is not found the simple help message is printed (lines 500-520) and the registers and zero page bytes are restored before returning control to the MOS (line 530 and lines 1060-1160). The extended help interpreter (lines 540-700) compares every byte of the typed argument with every byte of the expected argument (lines 540-640) and if a match is found, or a suitable shortened argument is typed, the extended help message is printed (lines 670-690) before returning control to the MOS with the registers and zero page bytes restored (line 700 and lines 1060-1160). 10 REM: HELP 20 MODE7 30 HIMEM=&3C00 40 DIM save 50 50 diff=&8000-HIMEM 60 address=&A8 70 comvec=&F2 80 errstack=&100 90 stack=&105 100 gsinit=&FFC2 110 gsread=&FFC5 120 osasci=&FFE3 130 osword=&FFF1 140 osbyte=&FFF4 150 oscli=&FFF7 160 FOR pass = 0 TO 2 STEP 2 170 P%=HIMEM 180 [ OPT pass 190 BRK 200 BRK 210 BRK 220 JMP service+diff 230 OPT FNequb(&82) 240 OPT FNequb((copyright+diff) MOD 256) 250 BRK 260 OPT FNequs("COLOURED TEXT") 270 .copyright 280 BRK 290 OPT FNequs("(C)1987 Gordon Horsington") 300 BRK 310 .service 320 PHA 330 TXA 340 PHA 350 TYA 360 PHA 370 LDA address 380 PHA 390 LDA address+1 400 PHA 410 TSX 420 LDA stack,X 430 CMP #9 440 BNE tryfour 450 SEC 460 JSR gsinit 470 LDX #0 480 JSR gsread 490 BCC tryextended 500 LDX #(helpmsg+diff) MOD 256 510 LDY #(helpmsg+diff) DIV 256 520 JSR printer+diff 530 BEQ quit 540 .helploop 550 INX 560 JSR gsread 570 .tryextended 580 CMP #ASC(".") 590 BEQ okextended 600 AND #&DF 610 CMP helptitle+diff,X 620 BEQ helploop 630 LDA #&FF 640 CMP helptitle+diff,X 650 BNE quit 660 .okextended 670 LDX #(helpinfo+diff) MOD 256 680 LDY #(helpinfo+diff) DIV 256 690 JSR printer+diff 700 BEQ quit 710 .tryfour 720 CMP #4 730 BNE quit 740 LDX #&FE 750 TYA 760 PHA 770 .firstchar 780 INX 790 PLA 800 TAY 810 PHA 820 LDA (comvec),Y 830 AND #&DF 840 CMP #ASC("X") 850 BNE interpret 860 INY 870 .interpret 880 INX 890 LDA commtable+diff,X 900 BMI found 910 LDA (comvec),Y 920 INY 930 CMP #ASC(".") 940 BEQ founddot 950 AND #&DF 960 CMP commtable+diff,X 970 BEQ interpret 980 .another 990 INX 1000 LDA commtable+diff,X 1010 BPL another 1020 CMP #&FF 1030 BNE firstchar 1040 .exit 1050 PLA 1060 .quit 1070 PLA 1080 STA address+1 1090 PLA 1100 STA address 1110 PLA 1120 TAY 1130 PLA 1140 TAX 1150 PLA 1160 RTS 1170 .founddot 1180 INX 1190 LDA commtable+diff,X 1200 BPL founddot 1210 .found 1220 CMP #&FF 1230 BEQ exit 1240 STA address+1 1250 INX 1260 LDA commtable+diff,X 1270 STA address 1280 PLA 1290 SEC 1300 JSR gsinit 1310 JMP (address) 1320 .commtable 1330 OPT FNequs("BLAWHIT") 1340 OPT FNequb((blawhit+diff) DIV 256) 1350 OPT FNequb((blawhit+diff) MOD 256) 1360 OPT FNequs("REDCYAN") 1370 OPT FNequb((redcyan+diff) DIV 256) 1380 OPT FNequb((redcyan+diff) MOD 256) 1390 OPT FNequs("GREEMAG") 1400 OPT FNequb((greemag+diff) DIV 256) 1410 OPT FNequb((greemag+diff) MOD 256) 1420 OPT FNequs("YELLBLU") 1430 OPT FNequb((yellblu+diff) DIV 256) 1440 OPT FNequb((yellblu+diff) MOD 256) 1450 OPT FNequs("BLUYELL") 1460 OPT FNequb((bluyell+diff) DIV 256) 1470 OPT FNequb((bluyell+diff) MOD 256) 1480 OPT FNequs("MAGREEN") 1490 OPT FNequb((magreen+diff) DIV 256) 1500 OPT FNequb((magreen+diff) MOD 256) 1510 OPT FNequs("CYANRED") 1520 OPT FNequb((cyanred+diff) DIV 256) 1530 OPT FNequb((cyanred+diff) MOD 256) 1540 OPT FNequs("WHIBLAC") 1550 OPT FNequb((whiblac+diff) DIV 256) 1560 OPT FNequb((whiblac+diff) MOD 256) 1570 OPT FNequs("MAGENTA") 1580 OPT FNequb((magenta+diff) DIV 256) 1590 OPT FNequb((magenta+diff) MOD 256) 1600 OPT FNequs("YELLOW") 1610 OPT FNequb((yellow+diff) DIV 256) 1620 OPT FNequb((yellow+diff) MOD 256) 1630 OPT FNequs("WHITE") 1640 OPT FNequb((white+diff) DIV 256) 1650 OPT FNequb((white+diff) MOD 256) 1660 OPT FNequs("GREEN") 1670 OPT FNequb((green+diff) DIV 256) 1680 OPT FNequb((green+diff) MOD 256) 1690 OPT FNequs("BLACK") 1700 OPT FNequb((black+diff) DIV 256) 1710 OPT FNequb((black+diff) MOD 256) 1720 OPT FNequs("CYAN") 1730 OPT FNequb((cyan+diff) DIV 256) 1740 OPT FNequb((cyan+diff) MOD 256) 1750 OPT FNequs("BLUE") 1760 OPT FNequb((blue+diff) DIV 256) 1770 OPT FNequb((blue+diff) MOD 256) 1780 OPT FNequs("RED") 1790 OPT FNequb((red+diff) DIV 256) 1800 OPT FNequb((red+diff) MOD 256) 1810 OPT FNequb(&FF) 1820 .helpmsg 1830 OPT FNequb(&0D) 1840 OPT FNequs("COLOURED TEXT") 1850 OPT FNequb(&0D) 1860 OPT FNequw(&2020) 1870 .helptitle 1880 OPT FNequs("COLOURS") 1890 OPT FNequw(&0DFF) 1900 BRK 1910 .helpinfo 1920 OPT FNequw(&200D) 1930 OPT FNequs(" BLACK") 1940 OPT FNequw(&200D) 1950 OPT FNequs(" RED") 1960 OPT FNequw(&200D) 1970 OPT FNequs(" GREEN") 1980 OPT FNequw(&200D) 1990 OPT FNequs(" YELLOW") 2000 OPT FNequw(&200D) 2010 OPT FNequs(" BLUE") 2020 OPT FNequw(&200D) 2030 OPT FNequs(" MAGENTA") 2040 OPT FNequw(&200D) 2050 OPT FNequs(" CYAN") 2060 OPT FNequw(&200D) 2070 OPT FNequs(" WHITE") 2080 OPT FNequw(&200D) 2090 OPT FNequs(" BLAWHIT") 2100 OPT FNequw(&200D) 2110 OPT FNequs(" REDCYAN") 2120 OPT FNequw(&200D) 2130 OPT FNequs(" GREEMAG") 2140 OPT FNequw(&200D) 2150 OPT FNequs(" YELLBLU") 2160 OPT FNequw(&200D) 2170 OPT FNequs(" BLUYELL") 2180 OPT FNequw(&200D) 2190 OPT FNequs(" MAGREEN") 2200 OPT FNequw(&200D) 2210 OPT FNequs(" CYANRED") 2220 OPT FNequw(&200D) 2230 OPT FNequs(" WHIBLAC") 2240 OPT FNequw(&000D) 2250 .printer 2260 STX address 2270 STY address+1 2280 LDY #&FF 2290 .printloop 2300 INY 2310 LDA (address),Y 2320 BEQ endprint 2330 BMI printloop 2340 JSR osasci 2350 JMP printloop+diff 2360 .endprint 2370 RTS 2380 .black 2390 LDA #0 2400 BEQ mode 2410 .red 2420 LDA #1 2430 BNE mode 2440 .green 2450 LDA #2 2460 BNE mode 2470 .yellow 2480 LDA #3 2490 BNE mode 2500 .blue 2510 LDA #4 2520 BNE mode 2530 .magenta 2540 LDA #5 2550 BNE mode 2560 .cyan 2570 LDA #6 2580 BNE mode 2590 .white 2600 LDA #7 2610 BNE mode 2620 .blawhit 2630 LDA #8 2640 BNE mode 2650 .redcyan 2660 LDA #9 2670 BNE mode 2680 .greemag 2690 LDA #10 2700 BNE mode 2710 .yellblu 2720 LDA #11 2730 BNE mode 2740 .bluyell 2750 LDA #12 2760 BNE mode 2770 .magreen 2780 LDA #13 2790 BNE mode 2800 .cyanred 2810 LDA #14 2820 BNE mode 2830 .whiblac 2840 LDA #15 2850 .mode 2860 PHA 2870 LDA #&87 2880 JSR osbyte \ Check screen mode 2890 CPY #7 2900 BNE mode0to6 2910 PLA 2920 LDA #(wrongmode+diff) MOD 256 2930 STA address 2940 LDA #(wrongmode+diff) DIV 256 2950 STA address+1 2960 LDY #&FF 2970 .errorloop 2980 INY 2990 LDA (address),Y 3000 STA errstack,Y 3010 BPL errorloop 3020 PLA 3030 STA address+1 3040 PLA 3050 STA address 3060 JMP errstack 3070 .mode0to6 3080 LDA colours+diff,Y 3090 PHA 3100 LDA #19 3110 JSR osasci 3120 PLA 3130 JSR osasci 3140 PLA 3150 JSR osasci 3160 LDA #0 3170 JSR osasci 3180 JSR osasci 3190 JSR osasci 3200 .pullout 3210 PLA 3220 STA address+1 3230 PLA 3240 STA address 3250 PLA 3260 PLA 3270 PLA 3280 LDA #0 3290 RTS 3300 .colours 3310 OPT FNequd(&01070301) 3320 OPT FNequw(&0301) 3330 OPT FNequb(&01) 3340 .wrongmode 3350 BRK 3360 OPT FNequb(&FE) 3370 OPT FNequs("Modes 0-6 only") 3380 BRK 3390 OPT FNequb(&FF) 3400 .lastbyte 3410 ] 3420 NEXT 3430 INPUT'"Save filename = "filename$ 3440 IF filename$="" END 3450 $save="SAVE "+filename$+" "+STR$~(HIMEM)+" "+STR$~(las tbyte)+" FFFF8000 FFFF8000" 3460 X%=save 3470 Y%=X% DIV 256 3480 *OPT1,2 3490 CALL oscli 3500 *OPT1,0 3510 END 3520 DEFFNequb(byte) 3530 ?P%=byte 3540 P%=P%+1 3550 =pass 3560 DEFFNequw(word) 3570 ?P%=word 3580 P%?1=word DIV 256 3590 P%=P%+2 3600 =pass 3610 DEFFNequd(double) 3620 !P%=double 3630 P%=P%+4 3640 =pass 3650 DEFFNequs(string$) 3660 $P%=string$ 3670 P%=P%+LEN(string$) 3680 =pass