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$