10 REM Y2K REPAIR for CMOS clock
20 REM Copyright (C) Mark Bush, Raffaele Giaccio
30 REM For BBC Micros with CMOS clock
40 :
50 REM Uses 2 bytes of zero page at
60 REM &70, &71, preserving contents
70 REM and a page of dynamic filing system RAM (only
80 REM 4 bytes are used) and preserving PAGE
90 :
100 ZP=&70
110 ZP1=&71
120 OSASCI=&FFE3
130 OSBYTE=&FFF4
140 OSNEWL=&FFE7
150 DIM C% 1000
160 FOR D% = 4 TO 7 STEP 3
170 P%=&8000
180 O%=C%
190 [OPT D%
200 \ setup ROM header
210 EQUB &00
220 EQUW &00
230 JMP SERVICE
240 EQUB &82 \ code for a normal ROM
250 EQUB COPY-&8000
260 EQUB &02
270.title
280 EQUS "Y2K REPAIR"
290 EQUB &00
300 EQUS "2.10"
310 .COPY
320 EQUB &00
330 EQUS "(C)2002-03 Mark Bush, Raffaele Giaccio"
340 EQUB &00
350 .SERVICE
360 CMP #&22 \ claim dynamic filing system workspace
370 BEQ WKSP
380 CMP #&27 \ a reset has occurred
390 BEQ RESET
400 CMP #&24 \ count dynamic filing system workspace RAM
410 BNE out
420 DEY:RTS
430 .out CMP #&09 \ respond to *HELP
440 BEQ helpjmp:RTS
450 .helpjmp JMP help
460 .WKSP
470 TYA
480 STA &0DF0,X \ save our workspace page number
490 LDA #&22
500 INY \ claim 1 page for our use
510 RTS
520 .RESET
530 \ after a reset, the MOS vectors will have been reset
540 \ so we need to redo the redirection of OSWORD through
550 \ our routine
560 TYA
570 PHA
580 \ save zero page locations
590 LDA ZP
600 PHA
610 LDA ZP1
620 PHA
630 \ OSBYTE &A8 retrieves start of extended vector area
640 LDX #&00
650 LDY #&FF
660 LDA #&A8
670 JSR OSBYTE
680 \ (X;Y) returned
690 STX ZP
700 STY ZP1
710 \ each vector is 3 bytes long and OSWORD is the 7th so
720 \ we need to offset 18 bytes (6 vectors) to reach it
730 LDY #&12
740 \ save new vector as:
750 \ byte 1 target low byte
760 \ byte 2 target high byte
770 \ byte 3 ROM number to page in to access target
780 LDA #TIM MOD 256
790 STA (ZP),Y
800 INY
810 LDA #TIM DIV 256
820 STA (ZP),Y
830 INY
840 LDX &F4 \ our ROM number
850 TXA
860 STA (ZP),Y
870 \ retrieve our saved workspace page number
880 LDA &0DF0,X
890 STA ZP1
900 LDA #&00
910 STA ZP
920 \ get current address of the OSWORD routine (which may
930 \ already be redirected) and save 1 less in our workspace
940 \ (we use the trick of pushing the address on the stack
950 \ and using RTS to go there which adds 1 to the address)
960 LDA &020C
970 SEC
980 SBC #&01
990 STA (ZP)
1000 INC ZP
1010 LDA &020D
1020 SBC #&00
1030 STA (ZP)
1040 \ do the same for the address we want OSWORD to return to
1050 \ for call &0E so we can process the output
1060 INC ZP
1070 LDA #RET MOD 256
1080 SEC
1090 SBC #&01
1100 STA (ZP)
1110 INC ZP
1120 LDA #RET DIV 256
1130 SBC #&00
1140 STA (ZP)
1150 \ restore the zero page locations
1160 PLA
1170 STA ZP1
1180 PLA
1190 STA ZP
1200 \ set WORDV to now redirect through extended vectors
1210 LDA #&12
1220 STA &020C
1230 LDA #&FF
1240 STA &020D
1250 \ restore state and return
1260 PLA
1270 TAY
1280 LDA #&27
1290 RTS
1300 .TIM
1310 \ OSWORD now always redirects here first
1320 \ check if it is call &0E for the CMOS
1330 \ clock routine
1340 CMP #&0E
1350 BEQ CLOCK
1360 \ save call number
1370 PHA
1380 \ keep 2 stack places for the OSWORD address
1390 \ to return to
1400 PHA
1410 PHA
1420 \ preserve X
1430 TXA
1440 PHA
1450 \ preserve zero page locations
1460 LDA ZP
1470 PHA
1480 LDA ZP1
1490 PHA
1500 \ get our ROM number, retrieve our workspace page and
1510 \ extract the saved OSWORD address and put it in the
1520 \ stack over the 2 places saved for it above
1530 LDX &F4
1540 LDA &0DF0,X
1550 STA ZP1
1560 LDA #&00
1570 STA ZP
1580 TSX
1590 LDA (ZP)
1600 STA &0105,X
1610 INC ZP
1620 LDA (ZP)
1630 STA &0106,X
1640 \ restore zero page
1650 PLA
1660 STA ZP1
1670 PLA
1680 STA ZP
1690 \ restore X and A
1700 PLA
1710 TAX
1720 PLA
1730 \ stack now has the address (less 1) of OSWORD
1740 \ so RTS will go there as if it had been called
1750 \ normally
1760 RTS
1770 .CLOCK
1780 \ we now know that we are in the CMOS clock OSWORD (&0E)
1790 \ preserve Y and X
1800 TYA
1810 PHA
1820 TXA
1830 PHA
1840 \ keep 1 space to hold the type of call this is (X;Y);
1850 \ 0 - return string of date and time
1860 \ 1 - return BCD format not including the century
1870 \ 2 - turn BCD format into string format
1880 PHA
1890 \ keep 4 stack places
1900 \ these will be the OSWORD address and our address of
1910 \ RET so that a return from the real OSWORD comes back to us
1920 PHA
1930 PHA
1940 PHA
1950 PHA
1960 \ preserves zero page locations
1970 LDA ZP
1980 PHA
1990 LDA ZP1
2000 PHA
2010 \ as before, get the OSWORD and RET addresses and
2020 \ put them into their places in the stack
2030 LDX &F4
2040 LDA &0DF0,X
2050 STA ZP1
2060 LDA #&00
2070 STA ZP
2080 TSX
2090 \ OSWORD address
2100 LDA (ZP)
2110 STA &0103,X
2120 INC ZP
2130 LDA (ZP)
2140 STA &0104,X
2150 \ RET address
2160 INC ZP
2170 LDA (ZP)
2180 STA &0105,X
2190 INC ZP
2200 LDA (ZP)
2210 STA &0106,X
2220 \ save (X;Y)
2230 STY ZP1
2240 LDA &0108,X
2250 STA ZP
2260 LDA (ZP)
2270 STA &0107,X
2280 \ restore X
2290 LDA &0108,X
2300 TAX
2310 \ restore zero page
2320 PLA
2330 STA ZP1
2340 PLA
2350 STA ZP
2360 \ restore A
2370 LDA #&0E
2380 \ "return" to OSWORD
2390 RTS
2400 .RET
2410 \ OSWORD will return to this point
2420 \ retrieve the call type (X;Y)
2430 PLA
2440 \ if it is 1 then we are done
2450 CMP #&01
2460 BEQ DONE
2470 \ otherwise preserve zero page locations
2480 LDA ZP
2490 PHA
2500 LDA ZP1
2510 PHA
2520 \ get X and Y to access the return string
2530 TSX
2540 LDA &0103,X
2550 STA ZP
2560 LDA &0104,X
2570 STA ZP1
2580 \ set century to "20"
2590 LDA #ASC("2")
2600 LDY #&0B
2610 STA (ZP),Y
2620 LDA #ASC("0")
2630 INY
2640 STA (ZP),Y
2650 \ restore zero page
2660 PLA
2670 STA ZP1
2680 PLA
2690 STA ZP
2700 .DONE
2710 \ we are done
2720 \ restore X, Y and A and return
2730 PLA
2740 TAX
2750 PLA
2760 TAY
2770 LDA #&0E
2780 RTS
2790 \
2800 .help
2810 \ preserve all registers and check syntax
2820 PHP:PHA:TXA:PHA:TYA:PHA
2830 JSR OSNEWL
2840 LDX#0:.loop LDA (&F2),Y:CMP#0D:BEQ proceed:CMP#ASC("."):BEQ nextbit
2850 AND #&DF:CMP#63:BMI next:CMP title,X:BNE stop
2860 .next CMP#&0D:BEQ proceed:INY:INX:CPX#10:BNE loop
2870 .proceed CPX#0:BEQ nextbit:CPX#10:BEQ nextchr:JMP stop
2880 .nextchr DEX:DEY:LDA (&F2),Y:AND #&DF:CMP title,X:BNE stop
2890 INY:LDA (&F2),Y:CMP#&0D:BEQ nextbit:CMP#ASC(" "):BNE stop
2900 \
2910 .nextbit
2940 LDX#0:.loophlp LDA string,X:BEQ out2:JSR OSASCI
2950 INX:JMP loophlp
2960 .out2 JSR OSNEWL
2970 \ restore registers and return
2980 .stop PLA:TAY:PLA:TAX:PLA:PLP:RTS
2990 \
3000 .string EQUB&0D
3010 EQUS"Y2K REPAIR":EQUB&0D
3020 EQUS"  Y2KROM 2.10":EQUB&0D
3030 EQUS"  CMOS clock millenium correction"
3040 EQUB&0D:EQUB&0D:EQUB&00
3050 .DNE
3060 \
3070 ]:NEXT
3080 S$=STR$ ~C%
3090 E$=STR$ ~(DNE-&8000+C%)
3100 OSCLI "SAVE Y2KROM "+S$+" "+E$
3110 OSCLI "SRLOAD Y2KROM 8000 7 Q"
3120 REM ** Save this program before running unless using 2nd/co-processor **
3130 REM Remove 'Q' from line 3110 if not compatible with your machine
3140 REM Remember to press 'CTRL and BREAK' after running.
3150 REM SAVE"CLOCKSC"