; ;================================================================================================== ; MC146818/DS1285/DS12885 PC style CLOCK DRIVER ;================================================================================================== ; PCRTC_BUFSIZ .EQU 6 ; SIX BYTE BUFFER (YYMMDDHHMMSS) ;; Addressing is via first writing the address byte to IO port PCRTC_BASE ;; Then read from or write to PCRTC_DAT ;; PCRTC_BASE must be set in config files PCRTC_REG .EQU PCRTC_BASE PCRTC_DAT .EQU PCRTC_BASE + $01 PCRTC_REG_SEC .EQU $00 PCRTC_REG_SEC_ALM .EQU $01 PCRTC_REG_MIN .EQU $02 PCRTC_REG_MIN_ALM .EQU $03 PCRTC_REG_HOUR .EQU $04 PCRTC_REG_HOUR_ALM .EQU $05 PCRTC_REG_DOW .EQU $06 ; day of week PCRTC_REG_DAY .EQU $07 PCRTC_REG_MONTH .EQU $08 PCRTC_REG_YEAR .EQU $09 PCRTC_REG_CTLA .EQU $0A PCRTC_REG_CTLB .EQU $0B PCRTC_REG_CTLC .EQU $0C PCRTC_REG_CTLD .EQU $0D PCRTC_CTLA_VAL .EQU $2F PCRTC_CTLB_VAL .EQU $0A PCRTC_NVBASE .EQU $10 PCRTC_NVSIZE .EQU $30 ; 64 bytes in total is what DS1285 and MC146818 had DEVECHO "PCRTC: IO=" DEVECHO PCRTC_BASE DEVECHO "\n" ; ;-------------------------------------------------------------------------------------------------- ; HBIOS MODULE HEADER ;-------------------------------------------------------------------------------------------------- ; ORG_PCRTC .EQU $ ; .DW SIZ_PCRTC ; MODULE SIZE .DW PCRTC_INITPHASE ; ADR OF INIT PHASE HANDLER ; PCRTC_INITPHASE: ; INIT PHASE HANDLER, A=PHASE ;CP HB_PHASE_PREINIT ; PREINIT PHASE? ;JP Z,PCRTC_PREINIT ; DO PREINIT CP HB_PHASE_INIT ; INIT PHASE? JP Z,PCRTC_INIT ; DO INIT RET ; DONE ; PCRTC_INIT: LD A, (RTC_DISPACT) ; RTC DISPATCHER ALREADY SET? OR A ; SET FLAGS RET NZ ; IF ALREADY ACTIVE, ABORT CALL NEWLINE ; FORMATTING PRTS("PCRTC: $") ; PRINT RTC REGISTER NR PORT ADDRESS PRTS("IO=0x$") ; LABEL FOR IO ADDRESS LD A,PCRTC_REG ; GET IO ADDRESS CALL PRTHEXBYTE ; PRINT IT CALL PC_SPACE ; FORMATTING ; CHECK PRESENCE STATUS CALL PCRTC_DETECT ; HARDWARE DETECTION JR Z, PCRTC_INIT1 ; IF ZERO, ALL GOOD PRTS("NOT PRESENT$") ; NOT ZERO, H/W NOT PRESENT OR $FF ; SIGNAL FAILURE RET ; BAIL OUT PCRTC_INIT1: CALL PCRTC_RDTIM ; DISPLAY CURRENT TIME LD HL, PCRTC_BCDBUF ; POINT TO BCD BUF CALL PRTDT ; LD BC, PCRTC_DISPATCH CALL RTC_SETDISP ; XOR A ; SIGNAL SUCCESS RET ; ; DETECT RTC HARDWARE PRESENCE ; PCRTC_DETECT: LD C, 0 ; NVRAM INDEX 0 CALL PCRTC_GETBYT ; GET VALUE LD A, E ; TO ACCUM LD L, A ; SAVE IT XOR $FF ; FLIP ALL BITS LD E, A ; TO E LD C, 0 ; NVRAM INDEX 0 CALL PCRTC_SETBYT ; WRITE IT LD C, 0 ; NVRAM INDEX 0 CALL PCRTC_GETBYT ; GET VALUE LD A, L ; GET SAVED VALUE XOR $FF ; FLIP ALL BITS CP E ; COMPARE WITH VALUE READ LD A, 0 ; ASSUME OK JR Z, PCRTC_DETECT1 ; IF MATCH, GO AHEAD LD A, $FF ; ELSE STATUS IS ERROR PCRTC_DETECT1: PUSH AF ; SAVE STATUS LD E, L ; GET SAVED VALUE LD C, 0 ; NVRAM INDEX 0 CALL PCRTC_SETBYT ; SAVE IT POP AF ; RECOVER STATUS OR A ; SET FLAGS RET ; ; RTC DEVICE FUNCTION DISPATCH ENTRY ; A: RESULT (OUT), 0=OK, Z=OK, NZ=ERR ; B: FUNCTION (IN) ; PCRTC_DISPATCH: LD A,B ; GET REQUESTED FUNCTION AND $0F ; ISOLATE SUB-FUNCTION JP Z,PCRTC_GETTIM ; GET TIME DEC A JP Z,PCRTC_SETTIM ; SET TIME DEC A JP Z,PCRTC_GETBYT ; GET NVRAM BYTE VALUE DEC A JP Z,PCRTC_SETBYT ; SET NVRAM BYTE VALUE DEC A JP Z,PCRTC_GETBLK ; GET NVRAM DATA BLOCK VALUES DEC A JP Z,PCRTC_SETBLK ; SET NVRAM DATA BLOCK VALUES DEC A JP Z,PCRTC_GETALM ; GET ALARM DEC A JP Z,PCRTC_SETALM ; SET ALARM DEC A JP Z,PCRTC_DEVICE ; REPORT RTC DEVICE INFO SYSCHKERR(ERR_NOFUNC) RET ; ; RTC GET NVRAM BYTE ; C: INDEX ; E: VALUE (OUTPUT) ; A:0 IF OK, ERR_RANGE IF OUT OF RANGE ; PCRTC_GETBYT: LD A, C CP PCRTC_NVSIZE JR NC, PCRTC_BADIDX ADD A, PCRTC_NVBASE EZ80_IO OUT (PCRTC_REG), A EZ80_IO IN A, (PCRTC_DAT) LD E, A XOR A ; SIGNAL SUCCESS RET ; AND RETURN PCRTC_BADIDX: LD E, 00 LD A, ERR_RANGE RET ; ; RTC SET NVRAM BYTE ; C: INDEX ; E: VALUE ; A:0 IF OK, ERR_RANGE IF OUT OF RANGE ; PCRTC_SETBYT: LD A, C CP PCRTC_NVSIZE JR NC, PCRTC_BADIDX ADD A, PCRTC_NVBASE EZ80_IO OUT (PCRTC_REG), A LD A, E EZ80_IO OUT (PCRTC_DAT), A XOR A ; SIGNAL SUCCESS RET ; AND RETURN PCRTC_GETBLK: PCRTC_SETBLK: PCRTC_GETALM: PCRTC_SETALM: SYSCHKERR(ERR_NOTIMPL) RET ; ; RTC GET TIME ; A: RESULT (OUT), 0=OK, Z=OK, NZ=ERR ; HL: DATE/TIME BUFFER (OUT) ; BUFFER FORMAT IS BCD: YYMMDDHHMMSS ; 24 HOUR TIME FORMAT IS ASSUMED ; PCRTC_GETTIM: ; GET THE TIME INTO TEMP BUF PUSH HL ; SAVE PTR TO CALLERS BUFFER ; CALL PCRTC_RDTIM ; NOW COPY TO REAL DESTINATION (INTERBANK SAFE) LD A,BID_BIOS ; COPY FROM BIOS BANK LD (HB_SRCBNK),A ; SET IT LD A,(HB_INVBNK) ; COPY TO CURRENT USER BANK LD (HB_DSTBNK),A ; SET IT LD HL,PCRTC_BCDBUF ; SOURCE ADR POP DE ; DEST ADR LD BC,PCRTC_BUFSIZ ; LENGTH CALL HB_BNKCPY ; COPY THE CLOCK DATA XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; ; ; RTC SET TIME ; A: RESULT (OUT), 0=OK, Z=OK, NZ=ERR ; HL: DATE/TIME BUFFER (IN) ; BUFFER FORMAT IS BCD: YYMMDDHHMMSSWW ; 24 HOUR TIME FORMAT IS ASSUMED ; PCRTC_SETTIM: ; COPY TO BCD BUF LD A,(HB_INVBNK) ; COPY FROM CURRENT USER BANK LD (HB_SRCBNK),A ; SET IT LD A,BID_BIOS ; COPY TO BIOS BANK LD (HB_DSTBNK),A ; SET IT LD DE,PCRTC_BCDBUF ; DEST ADR LD BC,PCRTC_BUFSIZ ; LENGTH CALL HB_BNKCPY ; COPY THE RPC DATA ; LD A, PCRTC_REG_CTLA ; Set Ctl Reg A EZ80_IO OUT (PCRTC_REG), A LD A, PCRTC_CTLA_VAL EZ80_IO OUT (PCRTC_DAT), A LD A, PCRTC_REG_CTLB ; Set Ctl Reg B EZ80_IO OUT (PCRTC_REG), A LD A, PCRTC_CTLB_VAL|$80 ; Set the SET bit to stop updates EZ80_IO OUT (PCRTC_DAT), A LD A, PCRTC_REG_SEC ; Set seconds EZ80_IO OUT (PCRTC_REG), A LD A, (PCRTC_SS) EZ80_IO OUT (PCRTC_DAT), A LD A, PCRTC_REG_MIN ; Set minutes EZ80_IO OUT (PCRTC_REG), A LD A, (PCRTC_MM) EZ80_IO OUT (PCRTC_DAT), A LD A, PCRTC_REG_HOUR ; Set hours EZ80_IO OUT (PCRTC_REG), A LD A, (PCRTC_HH) EZ80_IO OUT (PCRTC_DAT), A LD A, PCRTC_REG_DAY ; Set date EZ80_IO OUT (PCRTC_REG), A LD A, (PCRTC_DT) EZ80_IO OUT (PCRTC_DAT), A LD A, PCRTC_REG_MONTH ; Set month EZ80_IO OUT (PCRTC_REG), A LD A, (PCRTC_MO) EZ80_IO OUT (PCRTC_DAT), A LD A, PCRTC_REG_YEAR ; Set year EZ80_IO OUT (PCRTC_REG), A LD A, (PCRTC_YR) EZ80_IO OUT (PCRTC_DAT), A LD A, PCRTC_REG_CTLB ; Set Ctl Reg B EZ80_IO OUT (PCRTC_REG), A LD A, PCRTC_CTLB_VAL ; Reset the SET bit to start clock EZ80_IO OUT (PCRTC_DAT), A XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; ; REPORT RTC DEVICE INFO ; PCRTC_DEVICE: LD D,RTCDEV_PC ; D := DEVICE TYPE LD E,0 ; E := PHYSICAL DEVICE NUMBER LD H,0 ; H := 0, DRIVER HAS NO MODES LD L, PCRTC_BASE ; L := 0, NO I/O ADDRESS XOR A ; SIGNAL SUCCESS RET ; ; READ OUT THE TIME PCRTC_RDTIM: ;; Need to wait until update-in-progress flag is reset LD A, PCRTC_REG_CTLA ; Set Ctl Reg A EZ80_IO OUT (PCRTC_REG), A EZ80_IO IN A, (PCRTC_DAT) BIT 7, A JP NZ, PCRTC_RDTIM ; Jump back if update in progress. LD A, PCRTC_REG_SEC ; Set seconds EZ80_IO OUT (PCRTC_REG), A EZ80_IO IN A, (PCRTC_DAT) LD (PCRTC_SS), A LD A, PCRTC_REG_MIN ; Set minutes EZ80_IO OUT (PCRTC_REG), A EZ80_IO IN A, (PCRTC_DAT) LD (PCRTC_MM), A LD A, PCRTC_REG_HOUR ; Set hours EZ80_IO OUT (PCRTC_REG), A EZ80_IO IN A, (PCRTC_DAT) LD (PCRTC_HH), A LD A, PCRTC_REG_DAY ; Set day EZ80_IO OUT (PCRTC_REG), A EZ80_IO IN A, (PCRTC_DAT) LD (PCRTC_DT), A LD A, PCRTC_REG_MONTH ; Set month EZ80_IO OUT (PCRTC_REG), A EZ80_IO IN A, (PCRTC_DAT) LD (PCRTC_MO), A LD A, PCRTC_REG_YEAR ; Set year EZ80_IO OUT (PCRTC_REG), A EZ80_IO IN A, (PCRTC_DAT) LD (PCRTC_YR), A RET ; ; REGISTER EXTRACTED VALUES ; PCRTC_BCDBUF: PCRTC_YR .DB $25 PCRTC_MO .DB $01 PCRTC_DT .DB $01 PCRTC_HH .DB $00 PCRTC_MM .DB $00 PCRTC_SS .DB $00 ; ;-------------------------------------------------------------------------------------------------- ; HBIOS MODULE TRAILER ;-------------------------------------------------------------------------------------------------- ; END_PCRTC .EQU $ SIZ_PCRTC .EQU END_PCRTC - ORG_PCRTC ; MEMECHO "PCRTC occupies " MEMECHO SIZ_PCRTC MEMECHO " bytes.\n"