Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
439 lines (393 sloc) 6.91 KB
;
;=======================================================================
;
; CP/M 3 Z80 DarkStar (NE Z80) Porting
;
;=======================================================================
;;---------------------------------------------------------------------
;; Version : 1.0 - 20140904
;; Assemble : SLR z80asm
;; Revisions:
;; 20140905 - Code start
;; 20180819 - Lowecased
;; 20180823 - fixed, changed main routines
;;---------------------------------------------------------------------
title 'time module for the modular cp/m 3 bios'
.z80
; define logical values:
include common.inc
public macclk
extrn @date,@hour,@min,@sec
extrn @bios$stack
if banked
extrn ?bank
extrn @cbnk
endif
cseg ; time must be done from resident memory
macclk:
ld (spsave),sp
ld sp,@bios$stack ; switch to a local stack
if banked
ld a,(@cbnk)
push af ; save current bank number
ld a,0
call ?bank
endif
call dotime
if banked
pop af
call ?bank ; restore caller's bank
endif
ld sp,(spsave)
ret
spsave: dw 0
; zds clock support. hardware details behind sysbios
if banked
dseg ; following goes to banked memory
endif
dotime:
ld a,c ; set time ?
or a
jp nz,settime
push hl
push de
ld hl,timstr ; point to the destination time string
di
call bbrdtime ; read clock
ei
ld a,(dsmon) ; fetch month
call bcd2bin
dec a ; month = 0...11
add a,a
ld e,a
ld d,0
ld hl,mdays
add hl,de
ld c,(hl)
inc hl
ld b,(hl) ; month_days[month]
ld a,(dsyear) ; fetch year
call bcd2bin
sub 78 ; 1978
jr nc,t1
add a,100
t1: ld de,365
ld l,a
ld h,d
call mlthl
ld h,l
ld l,0
ld d,a
call mltde
add hl,de ; HL = A * 365
add hl,bc ; + month_days[month]
ld a,(dsday) ; fetch day
call bcd2bin
ld c,a ; day = 1...29,30, or 31
ld b,0
add hl,bc ; + day
push hl
ld hl,78 ; 1978
ld de,0
call leapdays
ex de,hl
pop hl
or a
sbc hl,de ; - leap_days(78, 0)
push hl
ld a,(dsyear) ; year
call bcd2bin
cp 78
jr nc,t2
add a,100
t2: ld l,a
ld h,0
ld a,(dsmon) ; month
call bcd2bin
dec a ; month = 0...11
ld e,a
ld d,0
call leapdays
pop de
add hl,de ; + leap_days(year, month)
ld (@date),hl
ld a,(dshour)
call cvthour ; convert hour to 24-hours format
ld (@hour),a
ld a,(dsmin)
ld (@min),a
ld a,(dssec)
ld (@sec),a
pop de
pop hl
ret
settime:
push hl
push de
ld hl,(@date)
call convdate
ld a,(@hour)
ld (dshour),a
ld a,(@min)
ld (dsmin),a
ld a,(@sec)
ld (dssec),a
ei
ld hl,timstr
di
call bbwrtime ; activate and set the clock
ei
pop de
pop hl
ret
; Support routines
leapdays:
ld h,0 ; just in case...
ld a,l
rrca
rrca
and 3Fh
ld l,a ; HL = year / 4
and 3
ret nz
push hl
ld hl,mdays
add hl,de
add hl,de
ld e,(hl)
inc hl
ld d,(hl) ; month_days[month]
pop hl
ld a,d
or a
ret nz
ld a,59
cp d
ret nc
dec hl
ret
bcd2bin:
push de
ld d,a
and 0F0h
ld e,a
ld a,d
and 0Fh
srl e
add a,e
srl e
srl e
add a,e
pop de
ret
bin2bcd:
push bc
ld b,10
ld c,-1
sb1: inc c
sub b
jr nc,sb1
add a,b
sla c
sla c
sla c
sla c
or c
pop bc
ret
; convert DS1302 hour to 24-hour format
cvthour:
bit 7,a ; already in 24-hour format?
ret z ; return if yes
and 7Fh
bit 5,a ; check AM/PM bit
ret z ; return if AM
and 1Fh
add a,12h ; correct if PM
cp 24h ; hour >= 24?
ret c ; return if not
sub 24h ; otherwise correct it
ret
; compute day of week from number of days
computedow:
push hl
dec hl
ld e,7
call mydiv16 ; day of week = (num days - 1) mod 7
pop hl
ret
; compute year from number of days, returns year in BC and
; remaining number of days in HL
computeyear:
ld bc,78 ; base year
cy1: ld de,365 ; year length
ld a,c
and 3 ; leap year?
jr nz,cy2
inc de ; 366
cy2: push hl
dec de
or a
sbc hl,de ; rem days - year length
jr c,cy3 ; return if <= 0
pop af
dec hl
inc bc ; ++year
jr cy1
cy3: pop hl
ret
; compute month from remaining number of days
; on entry, C = leap bias, HL = rem days
; returns month in DE, rem days in HL
computemonth:
push hl
ld de,11 ; E = month, D = 0
ld b,d ; B = 0
cm1: ld a,e
cp 2 ; jan or feb?
jr nc,cm2
ld c,b ; leap bias = 0
cm2: ld hl,mdays
add hl,de
add hl,de
ld a,(hl)
inc hl
ld h,(hl)
ld l,a ; HL = month_days[month]
add hl,bc ; + leap bias
ex de,hl
ex (sp),hl ; HL = rem days
ld a,e
sub l
ld a,d
sbc a,h
ex (sp),hl
ex de,hl ; mdays[month] + leap_bias < rem days?
jr c,cm3 ; return if yes
dec e
jp p,cm1
cm3: pop hl
ret
; convert CP/M date (num of days) to dd mm yy
; HL - number of days (1 = Jan 1, 1978)
convdate:
call computedow ; compute day of week
inc a ; base 1
ld (dsdow),a
call computeyear ; compute year, return remaining days
ld a,c
cp 100 ; above year 2000?
jr c,cvd0
sub 100 ; correct if yes
cvd0: call bin2bcd
ld (dsyear),a
ld e,0 ; leap bias
ld a,c
and 3 ; (year & 3) == 0 ?
jr nz,cvd1
ld a,l
sub 59+1 ; ..and (rem days > 59) ?
ld a,h ; (after feb 29 on leap year)
sbc a,0
jr c,cvd1
inc e ; ..then leap bias = 1
cvd1: ld c,e
call computemonth
push de
push hl
ld hl,mdays
add hl,de
add hl,de
ld a,(hl)
inc hl
ld h,(hl)
ld l,a ; HL = month_days[month]
ld b,0
add hl,bc ; + leap bias
ex de,hl
pop hl
or a
sbc hl,de ; day = rem days - HL
ld a,l
call bin2bcd
ld (dsday),a
pop de
inc de ; ++month (conver to base 1)
ld a,e
call bin2bcd
ld (dsmon),a
ret
mlthl:
push af
push bc
push de
ld e,l
ld d,0
ld c,h
ld b,0
call mul16
pop de
pop bc
pop af
ret
mltde:
push af
push bc
push hl
ld a,d
ld d,0
ld c,a
ld b,0
call mul16
ex de,hl
pop hl
pop bc
pop af
ret
;.....
; divide 16-bit number in hl by 8-bit number in e.
; returns 16-bit quotient in hl, 8-bit remainder in a.
mydiv16:
ld b,16+1
xor a
mydiv: adc a,a
sbc a,e
jr nc,mydiv0
add a,e
mydiv0: ccf
adc hl,hl
djnz mydiv
ret
;
;; mul16 - 16x16 bit multiplication
;;
;; in de = multiplicand
;; bc = multiplier
;; out de = result
mul16: ld a,c ; a = low mpler
ld c,b ; c = high mpler
ld b,16 ; counter
ld hl,0
ml1601: srl c ; right shift mpr high
rra ; rot. right mpr low
jr nc,ml1602 ; test carry
add hl,de ; add mpd to result
ml1602: ex de,hl
add hl,hl ; double shift mpd
ex de,hl
djnz ml1601
ret
mdays:
; jan feb mar apr may jun jul aug sep oct nov dec
dw 000,031,059,090,120,151,181,212,243,273,304,334
timstr:
ds 8 ; string for reading/setting date/time
dssec equ timstr+0
dsmin equ timstr+1
dshour equ timstr+2
dsday equ timstr+3
dsmon equ timstr+4
dsdow equ timstr+5
dsyear equ timstr+6
db 0
end