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 &03 250 EQUS "MJB Y2K Fix" 260 EQUB &00 270 EQUS "3.00" 280 .COPY 290 EQUB &00 300 EQUS "(C)2002,2005 Mark Bush" 310 EQUB &00 320 .SERVICE 330 CMP #&02 \ claim dynamic 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 TXA 780 STA (ZP),Y 790 \ retrieve our saved workspace page number 800 LDA &0DF0,X 810 STA ZP1 820 LDA #&00 830 STA ZP 840 \ get current address of the OSWORD routine (which may 850 \ already be redirected) and save 1 less in our workspace 860 \ (we use the trick of pushing the address on the stack 870 \ and using RTS to go there which adds 1 to the address) 880 LDA &020C 890 SEC 900 SBC #&01 910 STA (ZP) 920 INC ZP 930 LDA &020D 940 SBC #&00 950 STA (ZP) 960 \ do the same for the address we want OSWORD to return to 970 \ for call &0E so we can process the output 980 INC ZP 990 LDA #RET MOD 256 1000 SEC 1010 SBC #&01 1020 STA (ZP) 1030 INC ZP 1040 LDA #RET DIV 256 1050 SBC #&00 1060 STA (ZP) 1070 \ restore the zero page locations 1080 PLA 1090 STA ZP1 1100 PLA 1110 STA ZP 1120 \ set WORDV to now redirect through extended vectors 1130 LDA #&12 1140 STA &020C 1150 LDA #&FF 1160 STA &020D 1170 \ restore state and return 1180 PLA 1190 TAY 1200 LDA #&27 1210 RTS 1220 .TIM 1230 \ OSWORD now always redirects here first 1240 \ check if it is call &0E for the CMOS 1250 \ clock routine 1260 CMP #&0E 1270 BEQ CLOCK 1280 \ save call number 1290 PHA 1300 \ keep 2 stack places for the OSWORD address 1310 \ to return to 1320 PHA 1330 PHA 1340 \ preserve X 1350 TXA 1360 PHA 1370 \ preserve zero page locations 1380 LDA ZP 1390 PHA 1400 LDA ZP1 1410 PHA 1420 \ get our ROM number, retrieve our workspace page and 1430 \ extract the saved OSWORD address and put it in the 1440 \ stack over the 2 places saved for it above 1450 LDX &F4 1460 LDA &0DF0,X 1470 STA ZP1 1480 LDA #&00 1490 STA ZP 1500 TSX 1510 LDA (ZP) 1520 STA &0105,X 1530 INC ZP 1540 LDA (ZP) 1550 STA &0106,X 1560 \ restore zero page 1570 PLA 1580 STA ZP1 1590 PLA 1600 STA ZP 1610 \ restore X and A 1620 PLA 1630 TAX 1640 PLA 1650 \ stack now has the address (less 1) of OSWORD 1660 \ so RTS will go there as if it had been called 1670 \ normally 1680 RTS 1690 .CLOCK 1700 \ we now know that we are in the CMOS clock OSWORD (&0E) 1710 \ preserve Y and X 1720 TYA 1730 PHA 1740 TXA 1750 PHA 1760 \ keep 1 space to hold the type of call this is (X;Y): 1770 \ 0 - return string of date and time 1780 \ 1 - return BCD format not including the century 1790 \ 2 - turn BCD format into string format 1800 PHA 1810 \ keep 4 stack places 1820 \ these will be the OSWORD address and our address of 1830 \ RET so that a return from the real OSWORD comes back to us 1840 PHA 1850 PHA 1860 PHA 1870 PHA 1880 \ preserve zero page locations 1890 LDA ZP 1900 PHA 1910 LDA ZP1 1920 PHA 1930 \ as before, get the OSWORD and RET addresses and 1940 \ put them into their places in the stack 1950 LDX &F4 1960 LDA &0DF0,X 1970 STA ZP1 1980 LDA #&00 1990 STA ZP 2000 TSX 2010 \ OSWORD address 2020 LDA (ZP) 2030 STA &0103,X 2040 INC ZP 2050 LDA (ZP) 2060 STA &0104,X 2070 \ RET address 2080 INC ZP 2090 LDA (ZP) 2100 STA &0105,X 2110 INC ZP 2120 LDA (ZP) 2130 STA &0106,X 2140 \ save (X;Y) 2150 STY ZP1 2160 LDA &0108,X 2170 STA ZP 2180 LDA (ZP) 2190 STA &0107,X 2200 \ restore X 2210 LDA &0108,X 2220 TAX 2230 \ restore zero page 2240 PLA 2250 STA ZP1 2260 PLA 2270 STA ZP 2280 \ restore A 2290 LDA #&0E 2300 \ "return" to OSWORD 2310 RTS 2320 .RET 2330 \ OSWORD will return to this point 2340 \ retrieve the call type (X;Y) 2350 PLA 2360 \ if it is 1 then we are done 2370 CMP #&01 2380 BEQ DONE 2390 \ otherwise preserve zero page locations 2400 LDA ZP 2410 PHA 2420 LDA ZP1 2430 PHA 2440 \ get X and Y to access the return string 2450 TSX 2460 LDA &0103,X 2470 STA ZP 2480 LDA &0104,X 2490 STA ZP1 2500 \ set century to "20" 2510 LDA #ASC "2" 2520 LDY #&0B 2530 STA (ZP),Y 2540 LDA #ASC "0" 2550 INY 2560 STA (ZP),Y 2570 \ restore zero page 2580 PLA 2590 STA ZP1 2600 PLA 2610 STA ZP 2620 .DONE 2630 \ we are done 2640 \ restore X, Y and A and return 2650 PLA 2660 TAX 2670 PLA 2680 TAY 2690 LDA #&0E 2700 RTS 2710 .DNE 2720 ] 2730 NEXT 2740 S$=STR$ ~C% 2750 E$=STR$ ~(DNE-&8000+C%) 2760 OSCLI "SAVE Y2KROM "+S$+" "+E$