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

323 lines
9.4 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
IF SIMHCLK
SIMHPORT EQU 0FEH
READCLOCK EQU 7
WRITECLOCK EQU 8
PARBLOCKSIZE EQU 6
TIME:
EX DE,HL ; GET DE TO HL
LD A,C
OR A
JR NZ,WRCLK
;
GETTIM: LD A,READCLOCK
OUT (SIMHPORT),A
LD BC,256*(PARBLOCKSIZE-1)+SIMHPORT ; B := 5, C := 0FEH
INIR
LD E,(HL) ; Save original seconds in E
INI ; READ SECONDS
DEC HL
LD A,1 ; Set OK status return
LD BC,DCNTR ; Get Address of User Down-Counter
RET
;
WRCLK: LD A,WRITECLOCK
OUT (SIMHPORT),A
LD A,L
OUT (SIMHPORT),A
LD A,H
OUT (SIMHPORT),A
LD A,1
LD BC,DCNTR ; Get Address of User Down-Counter
RET
ENDIF ; SIMHCLK
IF HBCLK
TIME:
LD A,C
OR A
JR NZ,WRCLK
;
RDCLK:
PUSH DE ; Save the final destination
LD HL,TIMBUF ; Point HL to temp buf
LD B,20H ; HBIOS function to read RTC
CALL HBX_INVOKE ; Do it
LD HL,TIMBUF ; Setup HL as source
POP DE ; And recover final destination
LD BC,5 ; Copy first 5 bytes
LDIR ; Do it
LD A,(DE) ; Now get the original seconds value to A
INC BC ; Setup to copy last byte, BC := 1
LDIR ; Do it
EX DE,HL ; Set HL to seconds dest for return
DEC HL ; Decrement to point back at seconds value
LD D,0 ; Tenths is always zero
LD E,A ; Get original seconds value
LD BC,DCNTR ; BC must point to countdown timer on return
LD A,1 ; Signal success
RET
;
WRCLK:
EX DE,HL ; Make incoming DE the copy source in HL
LD DE,TIMBUF ; We are copying to time buffer
LD BC,6 ; For 6 bytes
LDIR ; Do it, time buffer now ready
LD HL,TIMBUF ; Point to time buffer
LD B,21H ; Set clock function
CALL HBX_INVOKE ; Do it via HBIOS
LD BC,DCNTR ; BC must point to countdown timer on return
LD A,1 ; Signal success
RET
ENDIF ; HBCLK
ENDIF ;Clock & Ds1202
JP ISTRUE ; Handle fall thru if no clock driver
IF HBCLK
TIMBUF DEFS 6
ENDIF
;:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
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 ==================================