10 REM Y2K fix for CMOS clock
20 REM Copyright (C) Mark Bush 2002
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 static RAM (only
80 REM 4 bytes are used).
90 :
100 ZP=&70
110 ZP1=&71
120 OSBYTE=&FFF4
130 DIM C% 1000
140 FOR D% = 4 TO 7 STEP 3
150 P%=&8000
160 O%=C%
170 [OPT D%
180 \ setup ROM header
190 EQUB &00
200 EQUW &00
210 JMP SERVICE
220 EQUB &82 \ code for a normal service ROM
230 EQUB COPY-&8000
240 EQUB &02
250 EQUS "MJB Y2K Fix"
260 EQUB &00
270 EQUS "2.00"
280 .COPY
290 EQUB &00
300 EQUS "(C)2002 Mark Bush"
310 EQUB &00
320 .SERVICE
330 CMP #&02 \ claim static RAM
340 BEQ WKSP
350 CMP #&27 \ a reset has occurred
360 BEQ RESET
370 RTS
380 .WKSP
390 TYA
400 STA &0DF0,X \ save our workspace page number
410 LDA #&02
420 INY \ claim 1 page for our use
430 RTS
440 .RESET
450 \ after a reset, the MOS vectors will have been reset
460 \ so we need to redo the redirection of OSWORD through
470 \ our routine
480 TYA
490 PHA
500 \ save zero page locations
510 LDA ZP
520 PHA
530 LDA ZP1
540 PHA
550 \ OSBYTE &A8 retrieves start of extended vector area
560 LDX #&00
570 LDY #&FF
580 LDA #&A8
590 JSR OSBYTE
600 \ (X;Y) returned
610 STX ZP
620 STY ZP1
630 \ each vector is 3 bytes long and OSWORD is the 7th so
640 \ we need to offset 18 bytes (6 vectors) to reach it
650 LDY #&12
660 \ save new vector as:
670 \ byte 1: target low byte
680 \ byte 2: target high byte
690 \ byte 3: ROM number to page in to access target
700 LDA #TIM MOD 256
710 STA (ZP),Y
720 INY
730 LDA #TIM DIV 256
740 STA (ZP),Y
750 INY
760 LDX &F4 \ our ROM number
770 STA (ZP),Y
780 \ retrieve our saved workspace page number
790 LDA &0DF0,X
800 STA ZP1
810 LDA #&00
820 STA ZP
830 \ get current address of the OSWORD routine (which may
840 \ already be redirected) and save 1 less in our workspace
850 \ (we use the trick of pushing the address on the stack
860 \ and using RTS to go there which adds 1 to the address)
870 LDA &020C
880 SEC
890 SBC #&01
900 STA (ZP)
910 INC ZP
920 LDA &020D
930 SBC #&00
940 STA (ZP)
950 \ do the same for the address we want OSWORD to return to
960 \ for call &0E so we can process the output
970 INC ZP
980 LDA #RET MOD 256
990 SEC
1000 SBC #&01
1010 STA (ZP)
1020 INC ZP
1030 LDA #RET DIV 256
1040 SBC #&00
1050 STA (ZP)
1060 \ restore the zero page locations
1070 PLA
1080 STA ZP1
1090 PLA
1100 STA ZP
1110 \ set WORDV to now redirect through extended vectors
1120 LDA #&12
1130 STA &020C
1140 LDA #&FF
1150 STA &020D
1160 \ restore state and return
1170 PLA
1180 TAY
1190 LDA #&27
1200 RTS
1210 .TIM
1220 \ OSWORD now always redirects here first
1230 \ check if it is call &0E for the CMOS
1240 \ clock routine
1250 CMP #&0E
1260 BEQ CLOCK
1270 \ save call number
1280 PHA
1290 \ keep 2 stack places for the OSWORD address
1300 \ to return to
1310 PHA
1320 PHA
1330 \ preserve X
1340 TXA
1350 PHA
1360 \ preserve zero page locations
1370 LDA ZP
1380 PHA
1390 LDA ZP1
1400 PHA
1410 \ get our ROM number, retrieve our workspace page and
1420 \ extract the saved OSWORD address and put it in the
1430 \ stack over the 2 places saved for it above
1440 LDX &F4
1450 LDA &0DF0,X
1460 STA ZP1
1470 LDA #&00
1480 STA ZP
1490 TSX
1500 LDA (ZP)
1510 STA &0105,X
1520 INC ZP
1530 LDA (ZP)
1540 STA &0106,X
1550 \ restore zero page
1560 PLA
1570 STA ZP1
1580 PLA
1590 STA ZP
1600 \ restore X and A
1610 PLA
1620 TAX
1630 PLA
1640 \ stack now has the address (less 1) of OSWORD
1650 \ so RTS will go there as if it had been called
1660 \ normally
1670 RTS
1680 .CLOCK
1690 \ we now know that we are in the CMOS clock OSWORD (&0E)
1700 \ preserve Y and X
1710 TYA
1720 PHA
1730 TXA
1740 PHA
1750 \ keep 1 space to hold the type of call this is (X;Y):
1760 \ 0: return string of date and time
1770 \ 1: return BCD format not including the century
1780 \ 2: turn BCD format into string format
1790 PHA
1800 \ keep 4 stack places
1810 \ these will be the OSWORD address and our address of
1820 \ RET so that a return from the real OSWORD comes back to us
1830 PHA
1840 PHA
1850 PHA
1860 PHA
1870 \ preserve zero page locations
1880 LDA ZP
1890 PHA
1900 LDA ZP1
1910 PHA
1920 \ as before, get the OSWORD and RET addresses and
1930 \ put them into their places in the stack
1940 LDX &F4
1950 LDA &0DF0,X
1960 STA ZP1
1970 LDA #&00
1980 STA ZP
1990 TSX
2000 \ OSWORD address
2010 LDA (ZP)
2020 STA &0103,X
2030 INC ZP
2040 LDA (ZP)
2050 STA &0104,X
2060 \ RET address
2070 INC ZP
2080 LDA (ZP)
2090 STA &0105,X
2100 INC ZP
2110 LDA (ZP)
2120 STA &0106,X
2130 \ save (X;Y)
2140 STY ZP1
2150 LDA &0108,X
2160 STA ZP
2170 LDA (ZP)
2180 STA &0107,X
2190 \ restore X
2200 LDA &0108,X
2210 TAX
2220 \ restore zero page
2230 PLA
2240 STA ZP1
2250 PLA
2260 STA ZP
2270 \ restore A
2280 LDA #&0E
2290 \ "return" to OSWORD
2300 RTS
2310 .RET
2320 \ OSWORD will return to this point
2330 \ retrieve the call type (X;Y)
2340 PLA
2350 \ if it is 1 then we are done
2360 CMP #&01
2370 BEQ DONE
2380 \ otherwise preserve zero page locations
2390 LDA ZP
2400 PHA
2410 LDA ZP1
2420 PHA
2430 \ get X and Y to access the return string
2440 TSX
2450 LDA &0103,X
2460 STA ZP
2470 LDA &0104,X
2480 STA ZP1
2490 \ set century to "20"
2500 LDA #ASC("2")
2510 LDY #&0B
2520 STA (ZP),Y
2530 LDA #ASC("0")
2540 INY
2550 STA (ZP),Y
2560 \ restore zero page
2570 PLA
2580 STA ZP1
2590 PLA
2600 STA ZP
2610 .DONE
2620 \ we are done
2630 \ restore X, Y and A and return
2640 PLA
2650 TAX
2660 PLA
2670 TAY
2680 LDA #&0E
2690 RTS
2700 .DNE
2710 ]
2720 NEXT
2730 S$=STR$ ~C%
2740 E$=STR$ ~(DNE-&8000+C%)
2750 OSCLI "SAVE Y2KROM "+S$+" "+E$