The BBC and Master Computer Public Domain Library
Y2K Fix BASIC Listing
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$