Files
RomWBW/Source/BPBIOS/tim-dx.z80
2015-03-23 01:50:45 +00:00

415 lines
13 KiB
Z80 Assembly
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
;:::::::::::::::::::::::::::::::::::::::***************************
; 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 ==================================