
;
;==================================================================================================
; Maxim DS1501/DS1511 Y2K-Compliant Watchdog RTC Driver
;==================================================================================================
;
; THIS DRIVER CODE WAS CONTRIBUTED TO ROMWBW BY JPELLETIER 3:59 PM 7/24/2022
;
;  Register Addresses (HEX / BCD):
;
;  +---+-----+---------------+-------------------+------------------+----------------+
;  |ADR|  D7 | D6  | D5 | D4 | D3 | D2 | D1 | D0 | RANGE            | REGISTER       |
;  +---+-----+---------------+-------------------+------------------+----------------+
;  | 0 |  0  |     10-Second |          1-Second |            00-59 | Seconds        |
;  +---+-----+-----+---------+-------------------+------------------+----------------+
;  | 1 |  0  |     10-Minute |          1-Minute |            00-59 | Minutes        |
;  +---+-----+-----+---------+-------------------+------------------+----------------+
;  | 2 |  0  |  0  | 10-Hour |            1-Hour |            00-23 | Hours          |
;  +---+-----+-----+----+----+-------------------+------------------+----------------+
;  | 3 |  0  |  0  |  0 |  0 |  0 |  Day Of Week |            01-07 | Day Of Week    |
;  +---+-----+-----+----+----+----+--------------+------------------+----------------+
;  | 4 |  0  |  0  | 10-Date |            1-Date |            01-31 | Date           |
;  +---+-----+-----+----+----+-------------------+------------------+----------------+
;  | 5 |/EOSC|/E32K|BB32|10Mo|           1-Month |            01-12 | Month          |
;  +---+-----+-----+----+----+-------------------+------------------+----------------+
;  | 6 |             10-Year |            1-Year |            00-99 | Year           |
;  +---+-----+-----+----+----+----+----+----+----+------------------+----------------+
;  | 7 |          10-Century |         1-Century |            00-39 | Century        |
;  +---+-----+-----+----+----+----+----+----+----+------------------+----------------+
;  | 8 |  AM1|     10-Second |          1-Second |            00-59 | Seconds Alarm  |
;  +---+-----+---------------+-------------------+------------------+----------------+
;  | 9 |  AM2|     10-Minute |          1-Minute |            00-59 | Minutes Alarm  |
;  +---+-----+-----+---------+-------------------+------------------+----------------+
;  | A |  AM3|  0  | 10-Hour |            1-Hour |            00-23 | Hours Alarm    |
;  +---+-----+-----+----+----+-------------------+------------------+----------------+
;  | B |  AM4|DY/DT| 10-date |          Day/Date |        1-7/01-31 | Day/Date Alarm |
;  +---+-----+-----+----+----+----+--------------+------------------+----------------+
;  | C |          0.1-Second |       0.01-Second |            00-99 | Watchdog       |
;  +---+-----+-----+---------+-------------------+------------------+----------------+
;  | D |           10-Second |          1-Second |            00-99 | Watchdog       |
;  +---+-----+-----+---------+-------------------+------------------+----------------+
;  | E | BLF1| BLF2| PRS| PAB| TDF| KSF| WDF|IRQF|                  | ControlA       |
;  +---+-----+-----+----+----+----+----+----+----+------------------+----------------+
;  | F |   TE|   CS| BME| TPE| TIE| KIE| WDE| WDS|                  | ControlB       |
;  +---+-----+-----+----+----+----+----+----+----+------------------+----------------+
;  |10 |           Extended RAM Address          |            00-FF | RAM Address    |
;  +---+-----+-----+----+----+----+----+----+----+------------------+----------------+
;  |11 |                 Reserved                |                  |                |
;  +---+-----+-----+----+----+----+----+----+----+------------------+----------------+
;  |12 |                 Reserved                |                  |                |
;  +---+--+--+-----+----+----+----+----+----+----+------------------+----------------+
;  |13 |             Extended RAM Data           |            00-FF | RAM Data       |
;  +---+--+--+-----+----+----+----+----+----+----+------------------+----------------+
;  |14-1F |              Reserved                |                  |                |
;  +------+--+-----+----+----+----+----+----+----+------------------+----------------+
;
;  * = Unused bits; unwritable and read as 0.
;  0 = should be set to 0 for valid time/calendar range.
;  Clock calendar data is BCD. Automatic leap year adjustment.
;  Day-Of-Week coded as Sunday = 1 through Saturday = 7.
;
; Constants
;
; By defining 2 bases, this allows some flexibility for address decoding
DS1501NVM_BASE		.EQU	DS1501RTC_BASE + $10

DS1501RTC_SEC		.EQU	DS1501RTC_BASE + $00
DS1501RTC_MIN		.EQU	DS1501RTC_BASE + $01
DS1501RTC_HOUR		.EQU	DS1501RTC_BASE + $02
DS1501RTC_WEEK_DAY	.EQU	DS1501RTC_BASE + $03
DS1501RTC_DAY		.EQU	DS1501RTC_BASE + $04
DS1501RTC_MONTH		.EQU	DS1501RTC_BASE + $05
DS1501RTC_YEAR		.EQU	DS1501RTC_BASE + $06
DS1501RTC_CENT		.EQU	DS1501RTC_BASE + $07
DS1501RTC_SEC_ALM	.EQU	DS1501RTC_BASE + $08
DS1501RTC_MIN_ALM	.EQU	DS1501RTC_BASE + $09
DS1501RTC_HOUR_ALM	.EQU	DS1501RTC_BASE + $0A
DS1501RTC_DAY_ALM	.EQU	DS1501RTC_BASE + $0B
DS1501RTC_WDOG1		.EQU	DS1501RTC_BASE + $0C
DS1501RTC_WDOG2		.EQU	DS1501RTC_BASE + $0D
DS1501RTC_CONTROLA	.EQU	DS1501RTC_BASE + $0E
DS1501RTC_CONTROLB	.EQU	DS1501RTC_BASE + $0F
;
DS1501RTC_RAMADDR	.EQU	DS1501NVM_BASE + $00
DS1501RTC_RAMDATA	.EQU	DS1501NVM_BASE + $03
;
DS1501RTC_HIGH		.EQU	%11110000
DS1501RTC_LOW		.EQU	%00001111
;
; ControlA bit masks
; BLF1| BLF2| PRS| PAB| TDF| KSF| WDF|IRQF
DS1501RTC_IRQF	.EQU	%00000001
DS1501RTC_WDF	.EQU	%00000010
DS1501RTC_KSF	.EQU	%00000100
DS1501RTC_TDF	.EQU	%00001000
DS1501RTC_PAB	.EQU	%00010000
DS1501RTC_PRS 	.EQU	%00100000
DS1501RTC_BLF2  .EQU	%01000000
DS1501RTC_BLF1	.EQU	%10000000
;
; ControlB bit masks
; TE| CS| BME| TPE| TIE| KIE| WDE| WDS|
DS1501RTC_WDS 	.EQU	%00000001
DS1501RTC_WDE	.EQU	%00000010
DS1501RTC_KIE	.EQU	%00000100
DS1501RTC_TIE	.EQU	%00001000
DS1501RTC_TPE	.EQU	%00010000
DS1501RTC_BME 	.EQU	%00100000
DS1501RTC_CS    .EQU	%01000000
DS1501RTC_TE	.EQU	%10000000
;
DS1501RTC_BUFSIZE	.EQU	6		; 6 BYTE BUFFER (YYMMDDHHMMSS)

	DEVECHO	"DS1501RTC: RTCIO="
	DEVECHO	DS1501RTC_BASE
	DEVECHO	", NVMIO="
	DEVECHO	DS1501NVM_BASE
	DEVECHO	"\n"
;
; RTC Device Initialization Entry
;
DS1501RTC_INIT:
	CALL	NEWLINE				; Formatting
	PRTS("DS1501RTC: IO=0x$")
	LD	A, DS1501RTC_BASE
	CALL	PRTHEXBYTE
;
	CALL	NEWLINE				; Formatting
	PRTS("DS1501NVM: IO=0x$")
	LD	A, DS1501NVM_BASE
	CALL	PRTHEXBYTE
;
	IN	A,(DS1501RTC_CONTROLB)		; Clear any pending interrupt flags
;
	XOR	A				; Zero A
	OR	DS1501RTC_TE			; Enable time updates
	OUT	(DS1501RTC_CONTROLB), A
;
	CALL	DS1501RTC_LOAD
;
	; DISPLAY CURRENT TIME
	PRTS("  $")
	LD	A, (DS1501RTC_BUF_MON)
	CALL	PRTHEXBYTE
	PRTS("/$")
	LD	A, (DS1501RTC_BUF_DAY)
	CALL	PRTHEXBYTE
	PRTS("/$")
	LD	A, (DS1501RTC_BUF_YEAR)
	CALL	PRTHEXBYTE
	PRTS(" $")
	LD	A, (DS1501RTC_BUF_HOUR)
	CALL	PRTHEXBYTE
	PRTS(":$")
	LD	A, (DS1501RTC_BUF_MIN)
	CALL	PRTHEXBYTE
	PRTS(":$")
	LD	A, (DS1501RTC_BUF_SEC)
	CALL	PRTHEXBYTE
;
	LD	BC,DS1501RTC_DISPATCH
	CALL	RTC_SETDISP
;
	XOR	A				; Signal success
	RET
;
; RTC Device Function Dispatch Entry
;   A: Result (OUT), 0=OK, Z=OK, NZ=Error
;   B: Function (IN)
;
DS1501RTC_DISPATCH:
	LD	A, B				; Get requested function
	AND	$0F				; Isolate Sub-Function
	JP	Z, DS1501RTC_GETTIM		; Get Time
	DEC	A
	JP	Z, DS1501RTC_SETTIM		; Set Time
	DEC	A
	JP	Z, DS1501RTC_GETBYT		; Get NVRAM Byte Value
	DEC	A
	JP	Z, DS1501RTC_SETBYT		; Set NVRAM Byte Value
	DEC	A
	JP	Z, DS1501RTC_GETBLK		; Get NVRAM Data Block Value
	DEC	A
	JP	Z, DS1501RTC_SETBLK		; Set NVRAM Data Block Value
	DEC	A
	JP	Z, DS1501RTC_GETALM		; Get Alarm
	DEC	A
	JP	Z, DS1501RTC_SETALM		; Set Alarm
;
; RTC Get Time
;   A: Result (OUT), 0=OK, Z=OK, NZ=Error
;   HL: Date/Time Buffer (OUT)
; Buffer format is BCD: YYMMDDHHMMSS
; 24 hour time format is assumed
;
DS1501RTC_GETTIM:
	EX	DE, HL
	CALL	DS1501RTC_LOAD
	; Now copy to read destination (Interbank Save)
	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	BC, DS1501RTC_BUFSIZE		; 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
;   A: Result (OUT), 0=OK, Z=OK, NZ=Error
;   HL: Date/Time Buffer (IN)
; Buffer Format is BCD: YYMMDDHHMMSS
; 24 hour time format is assumed
;
DS1501RTC_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, DS1501RTC_BUF		; Destination Address
	LD	BC, DS1501RTC_BUFSIZE		; 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, DS1501RTC_BUF
	CALL	DS1501RTC_SUSPEND
	LD	A, (HL)
	OUT	(DS1501RTC_YEAR), A		; Write Year
	INC	HL
	LD	A, (HL)
	OUT	(DS1501RTC_MONTH), A		; Write Month
	INC	HL
	LD	A, (HL)
	OUT	(DS1501RTC_DAY), A		; Write Day
	INC	HL
	LD	A, (HL)
	OUT	(DS1501RTC_HOUR), A		; Write Hour
	INC	HL
	LD	A, (HL)
	OUT	(DS1501RTC_MIN), A		; Write Minute
	INC	HL
	LD	A, (HL)
	OUT	(DS1501RTC_SEC), A		; Write Second
	CALL	DS1501RTC_RESUME
;
	; Clean up and return
	XOR	A				; Signal success
	RET					; And return
;
; RTC Get Byte
;
DS1501RTC_GETBYT:
;
; C Index
; E Value
; Set address
;
	LD	B, C
	LD	C, DS1501RTC_RAMADDR
	OUT	(C), B
;
	; Get data
	IN	A, (DS1501RTC_RAMDATA)
	LD	E,A
;
	; Return success
	XOR	A
	RET
;
; RTC Set Byte
;
DS1501RTC_SETBYT:
;
; C Index
; E Value
; Set address
;
	LD	B, C
	LD	C, DS1501RTC_RAMADDR
	OUT	(C), B
;	
	; Set data
	LD	A,E
	OUT	(DS1501RTC_RAMDATA), A
;	
	; Return success
	XOR	A
	RET
;
; RTC Get Block
;
DS1501RTC_GETBLK:
;
; HL Buffer Address
;
	LD	B, 0				; 256 Bytes
;	
	; Set BME
	IN	A, (DS1501RTC_CONTROLB)
	OR	DS1501RTC_BME
	OUT	(DS1501RTC_CONTROLB), A
;	
	XOR	A
	OUT	(DS1501RTC_RAMADDR), A
	LD	C, DS1501RTC_RAMDATA
	INIR
;	
	; Clear BME
	IN	A, (DS1501RTC_CONTROLB)
	AND	~DS1501RTC_BME
	OUT	(DS1501RTC_CONTROLB), A
;	
	; Return success
	XOR	A
	RET
;
; RTC Set Block
;
DS1501RTC_SETBLK:
;
; HL Buffer Address
;
	LD B, 0					; 256 Bytes
;
	; Set BME
	IN	A, (DS1501RTC_CONTROLB)
	OR	DS1501RTC_BME
	OUT	(DS1501RTC_CONTROLB), A
;
	XOR	A
	OUT	(DS1501RTC_RAMADDR), A
	LD	C, DS1501RTC_RAMDATA
	OTIR
;
	; Clear BME
	IN	A, (DS1501RTC_CONTROLB)
	AND	~DS1501RTC_BME
	OUT	(DS1501RTC_CONTROLB), A
;
	; Return success
	XOR	A
	RET
;
; RTC Get Alarm
;   A: Result (OUT), 0=OK, Z=OK, NZ=Error
;   HL: Date/Time Buffer (OUT)
; Buffer format is BCD: YYMMDDHHMMSS
; 24 hour time format is assumed
;
DS1501RTC_GETALM:
	EX	DE, HL
	LD	HL, DS1501RTC_BUF
	PUSH	HL				; Save address of source buffer
	CALL	DS1501RTC_SUSPEND
	XOR	A
	LD	(HL), A				; Read Year
	INC	HL
	LD	(HL), A				; Read Month
	INC	HL
	IN	A, (DS1501RTC_DAY_ALM)		; Read Day
	LD	(HL), A
	INC	HL
	IN	A, (DS1501RTC_HOUR_ALM)		; Read Hour
	LD	(HL), A
	INC	HL
	IN	A, (DS1501RTC_MIN_ALM)		; Read Minute
	LD	(HL), A
	INC	HL
	IN	A, (DS1501RTC_SEC_ALM)		; Read Second
	LD	(HL), A
	CALL	DS1501RTC_RESUME
	POP	HL				; Restore address of source buffer
;
	; Now copy to read destination (Interbank Save)
	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	BC, DS1501RTC_BUFSIZE		; 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 Alarm
;   A: Result (OUT), 0=OK, Z=OK, NZ=Error
;   HL: Date/Time Buffer (IN)
; Buffer Format is BCD: YYMMDDHHMMSS
; 24 hour time format is assumed
;
DS1501RTC_SETALM:
	; 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, DS1501RTC_BUF		; Destination Address
	LD	BC, DS1501RTC_BUFSIZE		; 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, DS1501RTC_BUF_DAY
	CALL	DS1501RTC_SUSPEND
	LD	A, (HL)
	OUT	(DS1501RTC_DAY_ALM), A		; Write Day
	INC	HL
	LD	A, (HL)
	OUT	(DS1501RTC_HOUR_ALM), A		; Write Hour
	INC	HL
	LD	A, (HL)
	OUT	(DS1501RTC_MIN_ALM), A		; Write Minute
	INC	HL
	LD	A, (HL)
	OUT	(DS1501RTC_SEC_ALM), A		; Write Second
	CALL	DS1501RTC_RESUME
;
	; Clean up and return
	XOR	A				; Signal success
	RET					; And return
;
DS1501RTC_SUSPEND:
	IN	A, (DS1501RTC_CONTROLB)		; Suspend Clock
	AND	~DS1501RTC_TE
	OUT	(DS1501RTC_CONTROLB), A
	RET
;
DS1501RTC_RESUME:
	IN	A, (DS1501RTC_CONTROLB)		; Resume Clock
	OR	DS1501RTC_TE
	OUT	(DS1501RTC_CONTROLB), A
	RET
;
DS1501RTC_LOAD:
	LD	HL, DS1501RTC_BUF
	PUSH	HL				; Save address of source buffer
	CALL	DS1501RTC_SUSPEND
	IN	A, (DS1501RTC_YEAR)		; Read Year
	LD	(HL), A
	INC	HL
	IN	A, (DS1501RTC_MONTH)		; Read Month
	LD	(HL), A
	INC	HL
	IN	A, (DS1501RTC_DAY)		; Read Day
	LD	(HL), A
	INC	HL
	IN	A, (DS1501RTC_HOUR)		; Read Hour
	LD	(HL), A
	INC	HL
	IN	A, (DS1501RTC_MIN)		; Read Minute
	LD	(HL), A
	INC	HL
	IN	A, (DS1501RTC_SEC)		; Read Second
	LD	(HL), A
	CALL	DS1501RTC_RESUME
	POP	HL				; Restore address of source buffer
	RET
;
; Working Variables
;
DS1501RTC_BUF:
DS1501RTC_BUF_YEAR:	.DB	0		; Year
DS1501RTC_BUF_MON:	.DB	0		; Month
DS1501RTC_BUF_DAY:	.DB	0		; Day
DS1501RTC_BUF_HOUR:	.DB	0		; Hour
DS1501RTC_BUF_MIN:	.DB	0		; Minute
DS1501RTC_BUF_SEC:	.DB	0		; Second
