forked from MirrorRepos/RomWBW
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
415 lines
13 KiB
415 lines
13 KiB
;:::::::::::::::::::::::::::::::::::::::***************************
|
|
; Time-handling Routines ** Machine-Dependant **
|
|
; D-X Designs Pty Ltd, P112 ***************************
|
|
;
|
|
; This module incorporates provisions for an interrupt-driven clock, or
|
|
; the Dallas DS-1202 Real Time Clock for obtaining Time and Date Info.
|
|
;
|
|
; 1.0 - 18 Jul 96 - Initial Release. HFB
|
|
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
; This code module should handle all Time-related segments, to include
|
|
; Interrupt handlers for Real Time update, motor timeouts, user down-
|
|
; counter and any necessary time format conversion routines.
|
|
|
|
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; TIMER
|
|
; This routine keeps the Real Time Clock, Diskette Time Out
|
|
; counter, and General-Purpose down-counters. An interrupt is
|
|
; generated every 50 mS by the Z-182 Programmable Interrupt Timer
|
|
; and used to update parameters. Every other interrupt (100 mS
|
|
; intervals) is used to update the 100 mS counters and Time string
|
|
; if using Interrupt-driven Time and Date.
|
|
; Enter: No parameters needed (Interrupt)
|
|
; Exit : None
|
|
; Uses : None. All registers preserved. Decrements MTM, User and BIOS
|
|
; general-purpose counter bytes every 100 mS.
|
|
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
CSEG
|
|
|
|
; Come here every 50 milliseconds from Programmable Reload Timer 0
|
|
|
|
TIMER: DI ; Don't Interrupt from here
|
|
LD (TIMSTK),SP ; Save entry Stack Pointer
|
|
LD SP,TIMSTK ; ..set up Local Interrupt Stack
|
|
PUSH HL
|
|
PUSH AF ; Save the registers
|
|
|
|
IN0 A,(TCR)
|
|
IN0 A,(TMDR0L)
|
|
IN0 A,(TMDR0H) ; Clear the interrupt
|
|
|
|
LD HL,FLAG50 ; Point to 50 mS Flag
|
|
LD A,(HL) ; fetch
|
|
XOR 01H ; and toggle LSB
|
|
LD (HL),A ; Re-save
|
|
JR NZ,TDONE ; ..exit if Odd 50 mS Tick
|
|
|
|
LD HL,DCNTR ; Adjust User GP Down-Counter
|
|
DEC (HL)
|
|
|
|
LD HL,MTM ; Adjust Bios GP Down-Counter
|
|
DEC (HL)
|
|
|
|
INC HL ; Point to Motor On-timer (MOTIM)
|
|
LD A,(HL)
|
|
OR A ; Already Timed Out?
|
|
JR Z,TIMER0 ; ..jump if So
|
|
DEC (HL) ; Else count down
|
|
CALL Z,MOTOFF ; turning Motors Off if timed out
|
|
TIMER0:
|
|
|
|
; Adjust the Interrupt-driven Real Clock (if no Real Time Clock exists).
|
|
; This "Clock" maintains Date and Time in a DateStamper(C) compatible
|
|
; string per ZSDOS specifications.
|
|
|
|
IF CLOCK AND [NOT DS1202]
|
|
LD HL,TENTHS ; 100ms counter
|
|
INC (HL) ; Bump Tenths-of-Seconds
|
|
LD A,(HL) ; get the value
|
|
SUB 10 ; Subtract limit value (in decimal times 2)
|
|
JR NZ,TDONE ; jump to exit if no rollover
|
|
LD (HL),A ; Else save a zero
|
|
DEC HL ; back down time string
|
|
|
|
LD A,(HL) ; Get Seconds
|
|
INC A ; bump
|
|
DAA ; in BCD
|
|
LD (HL),A ; and save
|
|
SUB 60H ; Subtract limit value
|
|
JR NZ,TDONE ; ..jump to exit if no rollover
|
|
LD (HL),A ; Else save a zero
|
|
DEC HL ; back down time string
|
|
|
|
LD A,(HL) ; Get Minutes
|
|
INC A ; bump
|
|
DAA ; in BCD
|
|
LD (HL),A ; and save
|
|
SUB 60H ; Subtract limit value
|
|
JR NZ,TDONE ; ..jump to exit if no rollover
|
|
LD (HL),A ; Else save a zero
|
|
DEC HL ; back down time string
|
|
|
|
LD A,(HL) ; Get Hours
|
|
INC A ; bump
|
|
DAA ; in BCD
|
|
LD (HL),A ; and save
|
|
SUB 24H ; Subtract limit value
|
|
JR NZ,TDONE ; ..jump to exit if no rollover
|
|
LD (HL),A ; Else save a zero
|
|
DEC HL ; back down time string
|
|
|
|
LD A,(HL) ; Get Day
|
|
INC A ; bump
|
|
DAA ; in BCD
|
|
LD (HL),A ; and save
|
|
PUSH DE ; Save regs
|
|
PUSH AF
|
|
EX DE,HL
|
|
LD HL,DPM-1 ; Point to days per month table indexed base 1
|
|
DEC DE ; back up to Months byte
|
|
LD A,(DE)
|
|
INC DE ; move ptr back
|
|
CP 10 ; >Sept?
|
|
JR C,TIMER1 ; ..jump if Not
|
|
SUB 6 ; Else convert BCD to binary
|
|
TIMER1: CALL ADDAHL ; Offset into table based on Month
|
|
POP AF ; Get current day count
|
|
CP (HL) ; Time for new month?
|
|
EX DE,HL ; (put regs back)
|
|
POP DE
|
|
JR C,TDONE ; ..exit here if not time
|
|
LD (HL),1 ; Else start out on first of month
|
|
DEC HL ; back down to month
|
|
|
|
LD A,(HL) ; Get month
|
|
INC A ; Bump
|
|
DAA ; in BCD
|
|
LD (HL),A ; and save
|
|
SUB 13H ; Time for new year?
|
|
JR C,TDONE ; ..exit if not
|
|
LD (HL),1 ; Else start at month 1 (Jan)
|
|
DEC HL ; back up to Years byte
|
|
|
|
LD A,(HL) ; Get Year
|
|
INC A ; bump
|
|
DAA ; in BCD
|
|
LD (HL),A ; and save
|
|
SUB 99H ; Time for next century?
|
|
JR NZ,TDONE ; ..exit if not
|
|
LD (HL),A ; Else save 0 year
|
|
|
|
ENDIF ;Clock & Not DS1202
|
|
|
|
TDONE: POP AF
|
|
POP HL ; Restore registers
|
|
LD SP,(TIMSTK) ; and Stack Pointer
|
|
EI ; allow Ints again
|
|
RET
|
|
|
|
IF CLOCK AND [NOT DS1202] ; Table of Days-per-Month
|
|
DPM: DEFB 31H+1, 28H+1, 31H+1 ; January, February, March
|
|
DEFB 30H+1, 31H+1, 30H+1 ; April, May, June
|
|
DEFB 31H+1, 31H+1, 30H+1 ; July, August, September
|
|
DEFB 31H+1, 30H+1, 31H+1 ; October, November, December
|
|
ENDIF ;Clock & Not Ds1202
|
|
|
|
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
; TIME - Set or Return the time string as defined for ZSDOS. If Reading,
|
|
; The Six digit BCD ZSDOS Clock string is copied to the location
|
|
; addressed by Register pair DE. As an enhancement, the tenths-of-seconds
|
|
; value is returned in Reg D. If Setting the Clock, the RTC clock string
|
|
; will be set from the 6 bytes addressed by DE.
|
|
;
|
|
; ENTER: C - 0 to Read the Clock, Non-0 (1 recommended) to Set the Clock
|
|
; DE = Pointer to receive 6-byte Time/Date on Read, Source for Set
|
|
;
|
|
; EXIT : E = Original contents of Target Seconds field
|
|
; D = Tenths of Seconds field
|
|
; HL = Pointer to Target Seconds field
|
|
; A = 1 for success, 0 if Unable to Set or Read
|
|
; BC = Address of User General-Purpose Down-Counter
|
|
;
|
|
; NOTE: The Wall Clock string is arranged as BCD digits with Tenths-
|
|
; of-Seconds byte appended. The entire string is:
|
|
;
|
|
; YR MO DA HH MM SS TT
|
|
;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
|
|
IF CLOCK AND DS1202
|
|
; Dallas DS-1202 Clock Interface on the D-X Designs Pty Ltd P112.
|
|
; Read the Clock to a buffer area in Memory. Seven bytes (Six used) are
|
|
; read in burst mode from the clock chip, one bit at a time via three bits
|
|
; from one of the Z-182 parallel ports. When Setting the clock from this
|
|
; code fragment, the DOW is forced to 01H, which will probably be invalid.
|
|
; The Clock is accessed serially (LSB first) one byte at a time with a
|
|
; command byte being written to begin the Read/Write. Burst Mode is used
|
|
; with a 0BFH byte for Reading, 0BEH for Writing as the Command. Clock
|
|
; Setting clears the Write Protect bit before setting, and resets the chip
|
|
; to Read-Only when finished. The Entire Date/Time String is eight bytes
|
|
; read as:
|
|
;
|
|
; Sec Min Hour Day Mon DOW Year WProt
|
|
; (12/24) (MSB)
|
|
;
|
|
; In this implementation, the DOW field is not used, and the 12/24 hour bit
|
|
; is always set to 24-hour mode by setting the MSB to 1.
|
|
|
|
RTCRst EQU 2 ; DS-1202 Reset\ Bit
|
|
RTCClk EQU 1 ; DS-1202 Clock Bit
|
|
RTCDat EQU 0 ; DS-1202 Data IO Bit
|
|
|
|
TIME: DI ; NO INTERRUPTS in This Routine
|
|
LD (TIMSTK),SP ; Save Entry Stack Ptr
|
|
LD SP,TIMSTK ; and Set Local Stack
|
|
LD A,C ; Get Clock Operation Flag
|
|
OR A ; Is it a Write?
|
|
PUSH AF ; (save)
|
|
CALL CSETUP ; Set Clock to Read, returning BC->DRA Port
|
|
LD DE,5 ; (above also moved ptr to HL)
|
|
ADD HL,DE ; offset to Seconds Field
|
|
POP AF ; (restore Write flag)
|
|
IF CLKSET
|
|
JR NZ,TIMSET ; ..jump if Write and Set allowed
|
|
ELSE
|
|
LD A,00 ; (preset Error Condition)
|
|
JR NZ,NOCLOK ; ..jump to Error if Set Not allowed
|
|
ENDIF
|
|
LD E,(HL) ; Else Read, so fetch orig contents
|
|
PUSH DE ; (Save for Exit)
|
|
PUSH HL ; (and preserve ptr)
|
|
|
|
; Command the DS-1202 for Burst Read of Clock
|
|
|
|
LD A,0BFH ; Load the Burst Clock Read Command
|
|
CALL Wr1202 ; and Send it
|
|
|
|
; Read the Clock Data. D still 0 from above Load, use as Byte Index
|
|
|
|
RdTim0: PUSH HL ; Save Ptr
|
|
LD E,8 ; Gather 8 bit for a byte
|
|
RdTim1: IN A,(C) ; Read Port
|
|
RES RTCClk,A ; Clock LO
|
|
OUT (C),A ; Set
|
|
NOP ; (settle)
|
|
IN A,(C) ; Read Bit to LSB
|
|
RRCA ; Data Bit to Carry
|
|
RR L ; to MSB of Accum
|
|
RLCA ; restore Parallel Port bits
|
|
SET RTCClk,A ; Clock HI
|
|
OUT (C),A ; Set
|
|
DEC E ; Byte Done?
|
|
JR NZ,RdTim1 ; ..jump if Not
|
|
|
|
LD E,L ; Else Get Byte
|
|
POP HL ; Restore Ptr to Dest
|
|
LD A,D ; Get Index
|
|
CP 5 ; Day-Of-Week?
|
|
JR Z,RdTim2 ; ..jump if So, bypassing save
|
|
LD (HL),E ; Save value in output string
|
|
DEC HL ; back down to previous byte in output
|
|
RdTim2: INC D ; increment index
|
|
CP 6 ; Did we just save Year?
|
|
JR NZ,RdTim0 ; ..get another byte if So
|
|
CALL CClose ; Else Deselect Clock
|
|
POP HL ; Restore Ptr
|
|
POP DE ; Orig Seconds content (and 0 Tenths)
|
|
ClkExt: LD A,01H ; Set Good Exit
|
|
NOCLOK: LD SP,(TIMSTK) ; Restore entry Stack
|
|
LD BC,DCNTR ; Get Address of User Down-Counter
|
|
EI ; Ints Ok now
|
|
RET ; and Quit
|
|
|
|
;.....
|
|
; Set the Clock if code assembly option set
|
|
; Enter: BC = DRA Address
|
|
; D = 0 (used as count of bytes written)
|
|
; HL -> Seconds of ZSTime string
|
|
|
|
IF CLKSET
|
|
WrTim: LD A,8EH
|
|
CALL Wr1202 ; Turn Write Protect OFF
|
|
XOR A
|
|
CALL Wr1202 ; by clearing MSB of Time+6
|
|
CALL CClose ; then terminate Clock Access
|
|
CALL COpen ; Start Clock access again
|
|
WrTim0: LD A,D ; Get Index 0..7 of Write String
|
|
CP 8 ; At End?
|
|
JR Z,WrTimX ; ..quit if So
|
|
CP 6 ; Year or WrProtect?
|
|
JR C,WrTim1 ; .jump if Not
|
|
JR Z,WrTim2 ; ..jump if Year
|
|
LD A,80H ; Else Write Protect On since last byte
|
|
JR WrTim3 ; ..do It!
|
|
|
|
WrTim1: CP 5 ; DOW?
|
|
LD A,01H ; (set default if So)
|
|
JR Z,WrTim3 ; ..set if So
|
|
WrTim2: LD A,(HL) ; Else Get Byte from ZSTime String
|
|
DEC HL ; back up for Next Byte
|
|
WrTim3: CALL Wr1202 ; Write Byte to Clock
|
|
INC D ; bump index of bytes written
|
|
JR WrTim0 ; ..continue til Done
|
|
|
|
WrTimX: CALL CClose ; Terminate Clock Access
|
|
JR ClkExt ; ..and Exit
|
|
ENDIF
|
|
|
|
;.....
|
|
; Set up DS-1202 interface from Z80182 Parallel port
|
|
; Entry: None
|
|
; Exit : BC -> Data Port w/Clk at bits 0-2
|
|
; Uses : AF,BC,DE
|
|
|
|
CSETUP: EX DE,HL ; Move Pointer to HL
|
|
COpen: LD BC,DDRA ; Address Parallel Port A Control
|
|
IN A,(C) ; Read Settings
|
|
SET RTCDat,A ; Data Line to Input
|
|
OUT (C),A ; and Set
|
|
INC BC ; Address Parallel Port A (DRA)
|
|
IN A,(C) ; Fetch settings
|
|
RES RTCClk,A ; Clk LO to Start
|
|
OUT (C),A ; (set)
|
|
SET RTCRst,A ; Clear Reset to HI
|
|
OUT (C),A ; (set)
|
|
RET
|
|
|
|
;.....
|
|
; Write the Byte in A to the clock (used for Command)
|
|
; Entry: BC -> Data Port (DRA)
|
|
; Exit : None
|
|
; Uses : AF,E
|
|
|
|
Wr1202: PUSH HL ; Save Regs
|
|
LD L,A ; Store byte
|
|
LD E,8 ; set bit count
|
|
IN0 A,(DDRA) ; Fetch Def'n Reg contents
|
|
RES RTCDat,A ; Data Line to Output
|
|
OUT0 (DDRA),A ; (set)
|
|
Wr120L: IN A,(C) ; Read Parallel Port
|
|
RES RTCClk,A ; Clk LO
|
|
OUT (C),A ; (set)
|
|
SRL A ; (clear LSB)
|
|
RR L ; Data Byte LSB to Carry
|
|
RLA ; then to Parallel Port LSB
|
|
OUT (C),A ; (set)
|
|
SET RTCClk,A ; Clk HI
|
|
OUT (C),A ; (set)
|
|
DEC E ; Eight Bits Sent?
|
|
JR NZ,Wr120L ; ..loop if Not
|
|
|
|
IN0 A,(DDRA)
|
|
SET RTCDat,A ; Set Port to Data IN
|
|
OUT0 (DDRA),A
|
|
POP HL ; Restore Regs
|
|
RET
|
|
|
|
;.....
|
|
; Deselect the Clock for Exit
|
|
; Enter: BC -> Z80182 Parallel Port A
|
|
; Exit : None
|
|
; Uses : AF
|
|
|
|
CClose: IN A,(C) ; Fetch Parallel Port
|
|
SET RTCClk,A ; Clk to HI
|
|
OUT (C),A
|
|
RES RTCRst,A ; Reset Active LO
|
|
OUT (C),A
|
|
RET
|
|
|
|
ENDIF ;Clock & Ds1202
|
|
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
|
IF CLOCK AND [NOT DS1202] ; Not Dallas, make Intrpt Code
|
|
|
|
TIME: LD A,C ; Get Clock Operation Flag
|
|
LD BC,5 ; and set up for ZSDOS Read/Write
|
|
LD HL,YEAR ; Pointing to Clock String
|
|
OR A ; Is it a Read?
|
|
JR Z,TIMES ; ..jump it so
|
|
EX DE,HL ; Else swap pointers for write
|
|
TIMES: DI ; disable Interrupts
|
|
LDIR ; and move 5 bytes of 6 bytes (.1 Sec = 7)
|
|
LD C,(HL) ; Get the Seconds byte
|
|
INC HL ; bump to 1/10th Seconds
|
|
LD H,(HL) ; and Get
|
|
EI ; Re-enable Interrupts
|
|
EX DE,HL ; Swap pointers
|
|
LD E,(HL) ; Preserve original Sec field contents in E
|
|
LD (HL),C ; and store the Seconds byte (.1 Sec in D)
|
|
LD BC,DCNTR ; Get Address of User Down-Counter
|
|
LD A,01 ; Set Ok exit value of 1
|
|
RET
|
|
|
|
ENDIF ;Clock & Not Ds1202
|
|
IF NOT CLOCK ; If No Clock..
|
|
XOR A ; Set Error Return
|
|
RET ; and exit
|
|
|
|
ELSE
|
|
DSEG
|
|
|
|
; Real Time Clock Buffer
|
|
IF NOT DS1202 ; Don't need this if D-X Designs P112
|
|
YEAR: DEFS 1 ; Year - packed BCD
|
|
DEFS 1 ; Month - packed BCD
|
|
DEFS 1 ; Day - packed BCD
|
|
DEFS 1 ; Hour - packed BCD
|
|
DEFS 1 ; Minute - packed BCD
|
|
DEFS 1 ; Seconds - packed BCD
|
|
TENTHS: DEFS 1 ; Tenths of Seconds - Binary (Int, else..)
|
|
ENDIF
|
|
ENDIF ;Clock
|
|
|
|
;.....
|
|
; Save some space in the Common RAM Area for a local stack
|
|
|
|
DSEG
|
|
DCNTR: DEFS 1 ; User 100 mS General-Purpose Down-Counter
|
|
FLAG50: DEFS 1 ; Flag for dividing 50mS to 100mS ticks
|
|
DEFS 12 ; We use 6 levels of stack (worst case)
|
|
TIMSTK: DEFS 2 ; Store the entry Stack pointer here
|
|
CSEG ; End up by restoring CSEG
|
|
|
|
;=========================== END of TIM-DX ==================================
|
|
|