
; B5C-CPM3.INS - Clock routine for CP/M Plus
;
; (8/28/85)	Added option to use standard BDOS calls for non-interrupt
;		driven CP/M Plus systems.  Unless the BIOS uses an
;		interrupt driven clock, the SCB doesn't get updated.
;		Also removed surrounding IF CLOCK OR RSPEED.
;						-- Paul Bartholomew
;
; (8/17/85)	Initial release for BYE501 and above.  This INSert uses
;		time/date routines originally written by Sigi Kluger.
;						-- George Peace
;----------------------------------------------------------------
;
; This clock insert uses BCDBIN and BINBCD subroutines.  It requires that
; configuration tags BCD2BIN and BIN2BCD as well as CLOCK be set to YES.
;
;	Note- This is an insert--not an overlay
;
CLKINT	EQU	YES		; YES if SCB time is updated by interrupts
				;     as on Osborne Executive (OX)
				; NO  if BDOS access required to update SCB
				;     as on Morrow hard disk (MH) series
;
CENTURY	EQU	19H		; Current century (19xx) in BCD
;
TIME:	 IF	CLKINT
	DI			; Disable interrupts while checking time (SCB)
	LHLD	SCBBASE		; Get SCB base address
	MVI	L,SCBTIM	; Build SCB time field address
	MOV	A,M		; Get hours (BCD)
	 ENDIF			; CLKINT

	 IF	NOT CLKINT
	MVI	C,105		; CP/M Plus Get date/time call
	LXI	D,DTDAT		; Address of DAT buffer
	DI			; Disable interrupts while checking time
	CALL	BDOS		; Get info through BDOS
	EI			; Re-enable interrupts
	STA	RTCBUF+2	; Seconds returned in A (BCD)
	LDA	DTHR		; Get Hour
	 ENDIF			; NOT CLKINT

	STA	RTCBUF		; Store BCD hours in RTCBUF
	CALL	BCDBIN		; Convert to binary
	STA	CCHOUR		; And save as current hour

	 IF	CLKINT
	INX	H		; Point to minute byte
	MOV	A,M		; Get minutes (BCD)
	 ENDIF			; CLKINT

	 IF	NOT CLKINT
	LDA	DTMN		; Get minutes
	 ENDIF			; NOT CLKINT

	STA	RTCBUF+1	; Store BCD minutes in RTCBUF
	CALL	BCDBIN		; Convert to binary
	STA	CCMIN		; And save as current minute

	 IF	CLKINT
	INX	H		; Point to seconds byte
	MOV	A,M		; Get seconds (BCD)
	STA	RTCBUF+2	; Store BCD seconds in RTCBUF
	 ENDIF			; CLKINT
;
	MVI	A,CENTURY	; Get current century
	STA	RTCBUF+3	; And store in RTC buffer
;
; Get the date
;
	 IF	CLKINT
	LHLD	SCBBASE		; Get SCB base address
	MVI	L,SCBDAT	; Build SCB date field address
	MOV	E,M
	INX	H
	MOV	D,M
	EI			; Enable interrupts after SCB access is done
	XCHG			; Transfer date to HL
	 ENDIF			; CLKINT

	 IF	NOT CLKINT
	LHLD	DTDAT		; Date in HL
	 ENDIF			; NOT CLKINT
;
	MVI	B,78		; Set years counter
;
LOOP:	CALL	CKLEAP
	LXI	D,-365		; Set up for subtract
	JNZ	NOLPY		; Skip if no leap year
	DCX	D		; Set for leap year
;
NOLPY:	DAD	D		; Subtract
	JNC	YDONE		; Continue if years done
	MOV	A,H
	ORA	L
	JZ	YDONE
	SHLD	DTDAT		; Else save days count
	INR	B		; Increment years count
	JMP	LOOP		; And do again
;
;
; The years are now finished, the years count is in 'B' and DTDAT holds
; the days (HL is invalid)
;
YDONE:	MOV	A,B
	CALL	BINBCD
	STA	RTCBUF+4
	CALL	CKLEAP		; Check if leap year
	MVI	A,-28
	JNZ	FEBNO		; February not 29 days
	MVI	A,-29		; Leap year
;
FEBNO:	STA	FEB		; Set february
	LHLD	DTDAT		; Get days count
	LXI	D,MTABLE	; Point to months table
	MVI	B,0FFH		; Set up 'B' for subtract
	MVI	A,0		; Set a for # of months
;
MLOOP:	PUSH	PSW
	LDAX	D		; Get month
	MOV	C,A		; Put in 'C' for subtract
	POP	PSW
	SHLD	DTDAT		; Save days count
	DAD	B		; Subtract
	INX	D		; Increment months counter
	INR	A
	JC	MLOOP		; Loop for next month
;
;
; The months are finished, days count is on stack.  First, calculate
; month.
;
MDONE:	MOV	B,A		; Save months
	LHLD	DTDAT
	MOV	A,H
	ORA	L
	JNZ	NZD
	DCX	D
	DCX	D
	LDAX	D
	CMA
	INR	A
	MOV	L,A
	DCR	B
;
NZD:	MOV	A,B		; Retrieve the binary month
	CALL	BINBCD		; Convert binary month to BCD
	STA	RTCBUF+5	; Store BCD month in RTCBUF
	MOV	A,L		; Retrieve binary day of month
	CALL	BINBCD		; Convert to BCD
	STA	RTCBUF+6	; Store BCD day of month in RTCBUF
;
	RET
;.....
;
;
; This routine checks for leap years.
;
CKLEAP:	MOV	A,B
	ANI	0FCH
	CMP	B
	RET
;.....
;
;
; This is the month's table
;
MTABLE:	DB	-31		;January
FEB:	DB	-28		;February
	DB	-31,-30,-31,-30	;Mar-Jun
	DB	-31,-31,-30	;Jul-Sep
	DB	-31,-30,-31	;Oct-Dec
;
DTDAT:	DW	0		; Storage for DATE

	 IF	NOT CLKINT
DTHR:	DB	0		; Hour in BCD
DTMN:	DB	0		; Minute in BCD
	 ENDIF			; NOT CLKINT
