; ;================================================================================================== ; DALLAS SEMICONDUCTOR DS1288X REAL TIME CLOCK ;================================================================================================== ; ; THIS DRIVER IS FOR THE DS1288X REAL-TIME CLOCK AND NVRAM. ; THE INTERFACE IS ASSUMED TO BE LIKE AN IBM PC AT PORT 0X70. ; ; TODO: ; CHECK CONTROL REG A, BIT 7 (VALID RAM/TIME) AND NOTIFY ; USER IF BATTERY IS DISCHARGED. ; ; REGISTER ADDRESSES (HEX / BCD): ; ; +---------+----------------------------------------------+--------+ ; | REG | FUNCTION | RANGE | ; +---------+----------------------------------------------+--------+ ; | $00 | SECONDS | 0-59 | ; | $01 | SECONDS ALARM | 0-59 | ; | $02 | MINUTES | 0-59 | ; | $03 | MINUTES ALARM | 0-59 | ; | $04 | HOURS | 00-23 | ; | $05 | HOURS ALARM | 00-23 | ; | $06 | DAY | 01-07 | ; | $07 | DATE | 01-31 | ; | $08 | MONTH | 01-12 | ; | $09 | YEAR | 00-99 | ; | $0A | CONTROL (SEE BELOW) | -- | ; | $0B | CONTROL (SEE BELOW) | -- | ; | $0C | CONTROL (SEE BELOW) | -- | ; | $0D | CONTROL (SEE BELOW) | -- | ; | $0E-$31 | RAM | -- | ; | $32 | CENTURY | 00-99 | ; | $33-$7F | RAM | -- | ; +---------+----------------------------------------------+--------+ ; ; +-----+-------+-------+-------+-------+-------+-------+-------+-------+ ; | REG | BIT 7 | BIT 6 | BIT 5 | BIT 4 | BIT 3 | BIT 2 | BIT 1 | BIT 0 | ; +-----+-------+-------+-------+-------+-------+-------+-------+-------+ ; | $0A | UIP | DV2 | DV1 | DV0 | RS3 | RS2 | RS1 | RS0 | ; | $0B | SET | PIE | AIE | UIE | SQWE | DM | 24/12 | DSE | ; | $0C | IRQF | PF | AF | UF | 0 | 0 | 0 | 0 | ; | $0D | VRT | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ; +-----+-------+-------+-------+-------+-------+-------+-------+-------+ ; ; NOTE: THE IBM PC CMOS USES REGISTER ADDRESSES UP TO $5F. THIS RTC ; IS SOMETIMES USED IN SYSTEMS THAT HAVE A X86 BOARD, SO WE AVOID ANY ; CONFLICT BY OFFSETTING OUR REGISTER INDEXES BY $60. THIS MEANS WE ; MAP REQUESTS FOR $00-$1F TO NVRAM REGISTERS $60-$7F. ; DS12RTC_IO .EQU $70 DS12RTC_SEL .EQU DS12RTC_IO + 0 DS12RTC_DATA .EQU DS12RTC_IO + 1 ; DEVECHO "DS12RTC:" ; DEVECHO " IO=" DEVECHO DS12RTC_IO DEVECHO "\n" ; ; RTC DEVICE PRE-INITIALIZATION ENTRY ; DS12RTC_PREINIT: XOR A ; SIGNAL SUCCESS RET ; DONE ; ; RTC DEVICE INITIALIZATION ENTRY ; DS12RTC_INIT: CALL NEWLINE ; FORMATTING PRTS("DS12RTC:$") ; ; PRINT RTC PORT ADDRESS PRTS(" IO=0x$") ; LABEL FOR IO ADDRESS LD A,DS12RTC_IO ; GET IO ADDRESS CALL PRTHEXBYTE ; PRINT IT ; CALL DS12RTC_DETECT ; HARDWARE DETECTION JR Z,DS12RTC_INIT1 ; CONTINUE IF FOUND ; ; HANDLE HARDWARE MISSING PRTS(" NOT PRESENT$") ; NOT ZERO, H/W NOT PRESENT OR $FF ; SIGNAL FAILURE RET ; BAIL OUT ; DS12RTC_INIT1: ; INITIALIZE RTC CALL DS12RTC_INITDEV ; ; DISPLAY CURRENT TIME CALL PC_SPACE LD HL,DS12RTC_TIMBUF CALL DS12RTC_RDCLK LD HL,DS12RTC_TIMBUF CALL PRTDT ; ; REGISTER THE RTC LD BC,DS12RTC_DISPATCH CALL RTC_SETDISP ; XOR A ; SIGNAL SUCCESS RET ; ; RTC DEVICE FUNCTION DISPATCH ENTRY ; A: RESULT (OUT), 0=OK, Z=OK, NZ=ERR ; B: FUNCTION (IN) ; DS12RTC_DISPATCH: LD A,B ; GET REQUESTED FUNCTION AND $0F ; ISOLATE SUB-FUNCTION JP Z,DS12RTC_GETTIM ; GET TIME DEC A JP Z,DS12RTC_SETTIM ; SET TIME DEC A JP Z,DS12RTC_GETBYT ; GET NVRAM BYTE VALUE DEC A JP Z,DS12RTC_SETBYT ; SET NVRAM BYTE VALUE DEC A JP Z,DS12RTC_GETBLK ; GET NVRAM DATA BLOCK VALUES DEC A JP Z,DS12RTC_SETBLK ; SET NVRAM DATA BLOCK VALUES DEC A JP Z,DS12RTC_GETALM ; GET ALARM DEC A JP Z,DS12RTC_SETALM ; SET ALARM DEC A JP Z,DS12RTC_DEVICE ; REPORT RTC DEVICE INFO ; SYSCHKERR(ERR_NOFUNC) RET ; ; ALARM FUNCTIONALITY NOT IMPLEMENTED ; DS12RTC_GETBLK: DS12RTC_SETBLK: DS12RTC_GETALM: DS12RTC_SETALM: SYSCHKERR(ERR_NOTIMPL) RET ; ; RTC GET TIME ; BUFFER FORMAT IS BCD: YYMMDDHHMMSS ; 24 HOUR TIME FORMAT IS ASSUMED ; DS12RTC_GETTIM: PUSH HL ; SAVE ADR OF OUTPUT BUF ; LD HL,DS12RTC_TIMBUF ; POINTER TO CLK DATA CALL DS12RTC_RDCLK ; READ IT ; ; 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,DS12RTC_TIMBUF ; SOURCE ADR POP DE ; DEST ADR LD BC,6 ; LENGTH IS 6 BYTES #IF (INTMODE == 1) DI #ENDIF CALL HB_BNKCPY ; COPY THE CLOCK DATA #IF (INTMODE == 1) EI #ENDIF ; ; CLEAN UP AND RETURN XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; ; RTC SET TIME ; BUFFER FORMAT IS BCD: YYMMDDHHMMSS ; 24 HOUR TIME FORMAT IS ASSUMED ; DS12RTC_SETTIM: ; COPY INCOMING TIME DATA TO OUR TIME BUFFER 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,DS12RTC_TIMBUF ; DEST ADR LD BC,6 ; LENGTH IS 6 BYTES #IF (INTMODE == 1) DI #ENDIF CALL HB_BNKCPY ; COPY THE CLOCK DATA #IF (INTMODE == 1) EI #ENDIF ; ; WRITE TO CLOCK LD HL,DS12RTC_TIMBUF ; POINTER TO CLK DATA CALL DS12RTC_WRCLK ; WRITE TO THE CLOCK ; ; CLEAN UP AND RETURN XOR A ; SIGNAL SUCCESS RET ; AND RETURN ; ; RTC GET NVRAM BYTE ; C: INDEX ; E: VALUE (OUTPUT) ; DS12RTC_GETBYT: LD A,C ; INDEX TO ACCUM ADD A,$60 ; WE USE NVRAM STARTING AT $60 LD C,A ; INDEX BACK TO C CALL DS12RTC_RDREG ; GET THE VALUE LD E,A ; PUT IN E TO RETURN XOR A ; SIGNAL SUCCESS RET ; DONE ; ; RTC SET NVRAM BYTE ; C: INDEX ; E: VALUE ; DS12RTC_SETBYT: LD A,C ; INDEX TO ACCUM ADD A,$60 ; WE USE NVRAM STARTING AT $60 LD C,A ; INDEX BACK TO C LD A,E ; PUT VALUE IN A CALL DS12RTC_WRREG ; WRITE IT XOR A ; SIGNAL SUCCESS RET ; DONE ; ; REPORT RTC DEVICE INFO ; DS12RTC_DEVICE: LD D,RTCDEV_DS12 ; D := DEVICE TYPE LD E,0 ; E := PHYSICAL DEVICE NUMBER LD H,0 ; H := MODE LD L,DS12RTC_IO ; L := BASE I/O ADDRESS XOR A ; SIGNAL SUCCESS RET ; ; DETECT RTC HARDWARE PRESENCE ; RETURN Z IF PRESENT ; DS12RTC_DETECT: LD C,$7F ; USE LAST RAM BYTE FOR TESTING CALL DS12RTC_RDREG ; GET CURRENT VALUE LD B,A ; SAVE IT LD A,$A5 ; TEST VALUE CALL DS12RTC_WRREG ; WRITE IT CALL DS12RTC_RDREG ; READ IT BACK CP $A5 ; COMPARE TO TEST VALUE PUSH AF ; SAVE RESULTS LD A,B ; RECOVER ORIGINAL VALUE CALL DS12RTC_WRREG ; RESTORE IT POP AF ; RECOVER RESULT RET ; AND RETURN ; ; READ CLOCK DATA INTO BUFFER AT HL (YYMMDDHHMMSS) ; DS12RTC_RDCLK: LD D,H ; RESET DE LD E,L ; ... IN CASE OF RESTART LD C,$09 ; START WITH YEAR REG CALL DS12RTC_RDCLK1 ; DO YEAR (REG $09) JR NZ,DS12RTC_RDCLK ; RESTART IF UIP DETECTED CALL DS12RTC_RDCLK1 ; DO MONTH (REG $08) JR NZ,DS12RTC_RDCLK ; RESTART IF UIP DETECTED CALL DS12RTC_RDCLK1 ; DO DAY OF MONTH (REG $07) JR NZ,DS12RTC_RDCLK ; RESTART IF UIP DETECTED DEC C ; SKIP DAY OF WEEK (REG $06) DEC C ; SKIP HOURS ALARM (REG $05) CALL DS12RTC_RDCLK1 ; DO HOUR (REG $04) JR NZ,DS12RTC_RDCLK ; RESTART IF UIP DETECTED DEC C ; SKIP MINUTES ALARM (REG $03) CALL DS12RTC_RDCLK1 ; DO MINUTES (REG $02) JR NZ,DS12RTC_RDCLK ; RESTART IF UIP DETECTED DEC C ; SKIP SECONDS ALARM (REG $01) CALL DS12RTC_RDCLK1 ; DO SECONDS (REG $00) ; XOR A ; SIGNAL SUCCESS RET ; DONE ; DS12RTC_RDCLK1: CALL DS12RTC_RDREG ; GET IT LD (DE),A ; STORE IN BUF INC DE ; BUMP BUF PTR DEC C ; DEC REGISTER JR DS12RTC_UIP ; RETURN VIA CHECK FOR UPDATE IN PROGRESS ; ; WRITE CLOCK DATA FROM BUFFER AT HL ; DS12RTC_WRCLK: LD D,H ; RESET DE LD E,L ; ... IN CASE OF RESTART LD C,$09 ; START WITH YEAR REG CALL DS12RTC_WRCLK1 ; DO YEAR (REG $09) JR NZ,DS12RTC_WRCLK ; RESTART IF UIP DETECTED CALL DS12RTC_WRCLK1 ; DO MONTH (REG $08) JR NZ,DS12RTC_WRCLK ; RESTART IF UIP DETECTED CALL DS12RTC_WRCLK1 ; DO DAY OF MONTH (REG $07) JR NZ,DS12RTC_WRCLK ; RESTART IF UIP DETECTED DEC C ; SKIP DAY OF WEEK (REG $06) DEC C ; SKIP HOURS ALARM (REG $05) CALL DS12RTC_WRCLK1 ; DO HOUR (REG $04) JR NZ,DS12RTC_WRCLK ; RESTART IF UIP DETECTED DEC C ; SKIP MINUTES ALARM (REG $03) CALL DS12RTC_WRCLK1 ; DO MINUTES (REG $02) JR NZ,DS12RTC_WRCLK ; RESTART IF UIP DETECTED DEC C ; SKIP SECONDS ALARM (REG $01) CALL DS12RTC_WRCLK1 ; DO SECONDS (REG $00) ; XOR A ; SIGNAL SUCCESS RET ; DONE ; DS12RTC_WRCLK1: LD A,(DE) ; GET VALUE CALL DS12RTC_WRREG ; WRITE IT INC DE ; BUMP BUF PTR DEC C ; DEC REGISTER JR DS12RTC_UIP ; RETURN VIA CHECK FOR UPDATE IN PROGRESS ; ; INITIALIZE RTC ; DS12RTC_INITDEV: ; ; GET CLOCK STATUS LD C,$0A ; CONTROL REGISTER A CALL DS12RTC_RDREG ; READ IT PUSH AF ; SAVE IT ; ; SET THE CONTROL REGISTERS LD C,$0A ; CONTROL REGISTER A LD A,%00100110 ; START CLOCK, 1.024KHZ SQUARE WAVE OUTPOUT CALL DS12RTC_WRREG ; SEND IT INC C ; CONTROL REGISTER B LD A,%00000010 ; NO INTS, NO ALM, NO SQW, BCD, 24HR, NO DS CALL DS12RTC_WRREG ; SEND IT ; POP AF ; RECOVER ORIGINAL STATUS AND %01110000 ; ISOLATE DV BITS CP %00100000 ; NORMAL RUNNING VALUE? RET Z ; IF SO, DONE ; ; PROGRAM DEFAULT DATE/TIME LD HL,DS12RTC_TIMDEF ; POINT TO DEFAULT DATE/TIME BUF CALL DS12RTC_WRCLK ; WRITE TO THE CLOCK RET ; DONE ; ; READ REGSITER ; C=REGISTER ; A=VALUE ; DS12RTC_RDREG: HB_DI ; NO INTS BETWEEN REG SEL AND DATA LD A,C ; REGSITER TO A OUT (DS12RTC_SEL),A ; SELECT IT IN A,(DS12RTC_DATA) ; GET REG VALUE HB_EI ; RESTORE INTS RET ; DONE ; ; WRITE REGSITER ; C=REGSITER ; A=VALUE ; DS12RTC_WRREG: HB_DI ; NO INTS BETWEEN REG SEL AND DATA PUSH AF ; SAVE VALUE TO WRITE LD A,C ; REGSITER TO A OUT (DS12RTC_SEL),A ; SELECT IT POP AF ; RECOVER VALUE TO WRITE OUT (DS12RTC_DATA),A ; GET REG VALUE HB_EI ; RESTORE INTS RET ; DONE ; ; CHECK FOR UPDATE IN PROGRESS ; RETURN NZ IF SO, RETURN Z IF CLEAR TO PROCEED ; ASSUMES THAT RTC EXISTS AND IS FUNCTIONING ; ; UIP BIT WILL BE SET 244US BEFORE AN UPDATE BEGINS. ; THE UIP BIT MAY NEED TO BE CHECKED REPEATEDLY DURING ; MULTIPLE BYTE READS/WRITES IF THE PROCESSING MAY ; TAKE MORE THAN 240US. ; DS12RTC_UIP: PUSH BC LD C,$0A CALL DS12RTC_RDREG ; GET CONTROL REG $0A AND $80 ; ISOLATE UIP BIT POP BC RET ; ; DS12RTC_TIMBUF IS DRIVER'S INTERNAL CLOCK DATA BUFFER ; DS12RTC_TIMBUF .FILL 6,0 ; 6 BYTES FOR GETTIM, YYMMDDHHMMSS DS12RTC_TIMDEF .DB $00,$01,$01,$00,$00,$00 ; DEFAULT DATE/TIME