home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
bdos
/
dosplsor.ark
/
TIME.MAC
< prev
next >
Wrap
Text File
|
1986-11-15
|
10KB
|
514 lines
;
; syntax:
; TIME<cr> (to report current time)
; TIME yy/mm/dd hh:mm (to set time)
; TIME ? (for help)
;
; using ISO std date format and 24 hour (00 <= hh <= 23) time
;
ver equ 10
;
bdos equ 5
fcb equ 05ch
defdma equ 080h
;
; DOS+/CPM calls
cout equ 2
tstr equ 9
dosver equ 12
;
; Following for DOS+/CPM3 only
setime equ 104
getime equ 105
getinfo equ 210; Only on DOS+
;
; getinfo sub-calls
getbase equ 0
;
; Ascii controls
cr equ 0dh
lf equ 0ah
;
; -------------
;
begin: lxi h,0
shld tod; mark no time by default
dad sp; so GO can re-execute correctly
lxi sp,stack
push h; save entry sp
lda fcb+1
cpi '?'
jz help; 'TIME ?' entered
mvi c,dosver
call bdos
inr h
dcr h
jnz badver; MPM or something
cpi 24h
jnc bgn2; Dos+ 2.4 up, or CPM 3, ok
cpi 22h
jc badver; 1.4 or CPM2.0/1, no timers
mvi c,getinfo
mvi e,getbase
call bdos; Check for DOS+ in compatibility mode
ora h
jz badver; If base returned, all is well
; " "
; Running DOS+ or CPM3 if here. Check parameters
bgn2: lxi h,defdma
mov a,m
inx h
push h
add l
mov l,a
adc h
sub l
mov h,a
mvi m,0; mark line end
pop h
call skipbk
jc show; no chars, show time
; " "
; try for valid input time string
set: call getn
jc badnum; get year
cpi '/'
jnz badnum
inx h
push d; save year
call getn; get month
jc badnum
sui '/'
ora d
jnz badnum; too large or bad terminator
ora e
jz badnum
cpi 13
jnc badnum
push d; save month
inx h
call getn; get day
sui ' '
ora d
jnz badnum; too large or bad terminator
ora e
jz badnum
cpi 32
jnc badnum
pop b
mov d,c; d := month
push d; save month/day
call skipbk; past terminating blanks to time
call getn
jc badnum
sui ':'
ora d
jnz badnum
push d; save hour
inx h
call getn; get minute
jc badnum
mov a,d
ora a
jnz badnum; too big
pop b
mov d,c; de is hr/min
xchg; to hl
pop d; month/day
pop b; year
push h; save hr/min
lxi h,-1900
dad b
jnc set2; user did not enter the 19
mov b,h
mov c,l
set2: mov a,b
ora a
jnz badnum; date too large
call cnvt; to dr format in hl
shld tod
pop b
mov a,b
cpi 24
jnc badnum
call binbcd
sta tod+2; hour
mov a,c
cpi 60
jnc badnum
call binbcd
sta tod+3; minute
lxi d,tod
mvi c,setime
call bdos
jmp exit
;
; display current time
show: mvi c,getime
lxi d,tod
call bdos
sta tod+4; save seconds value
lhld tod
lxi d,notmsg
mov a,h
ora l
jz msgxit; no time
call date
call blk
lhld tod+2
call time
mvi a,':'
call couta
lda tod+4
call t2hx
jmp exit
;
; illegal numeric
badnum: lxi d,syntax
jmp msgxit
;
; Bad DOS version message and exit
badver: lxi d,vermsg
jmp msgxit
;
; help message and exit
help: lxi d,hlpmsg
; " "
; message de^ and exit
msgxit: mvi c,tstr
call bdos
; " "
exit: lhld stack-2; allows aborts from down in stack
sphl
ret
;
; -------------
;
; skip blanks, string hl^. Exit with a=hl^ non-blank, cy for eol.
skipbk: mov a,m
cpi ' '
rc; control or 0, end of line
rnz; non-blank
inx h
jmp skipbk
;
; check a for numeric char, carry if not
qnum: cpi '0'
rc
cpi '9'+1
cmc
ret
;
; get numeric value from string hl^ to de. Exit hl^ is terminator
; a,f,b,c,d,e,h,l
getn: lxi d,0
mov a,m
call qnum
rc; invalid number
getn1: ani 0fh
xchg
mov b,h
mov c,l
dad h; 2*
dad h; 4*
dad b; 5*
dad h; 10*
call index; incorporate digit
xchg
inx h
mov a,m
call qnum
jnc getn1
cmc
ret
;
; show date in hl
; a,f,b,c,d,e,h,l
date: mov a,h
ora l
rz
call day; show day of week
call drtodate
mov a,c
call t2dec
mov a,d
call date1
mov a,e
date1: push psw
mvi a,'/'
call couta
pop psw
; " "
; show a as 2 dig. decimal no.
; a,f
t2dec: call binbcd
jmp t2hx
;
; show time in hl (BCD)
; a,f
time: mov a,l
call t2hx
mvi a,':'
call couta
mov a,h
; " "
t2hx: push psw
rlc
rlc
rlc
rlc
call t1hx
pop psw
; " "
t1hx: ani 0fh
adi 090h
daa
aci 040h
daa
jmp couta
;
; Convert (a) in binary to BCD. No overflow check. Return z flag.
; a,f
binbcd: push b
lxi b,0affh; b := 10, c := -1
bbcd1: inr c ! sub b
jnc bbcd1; divide by 10
add b; correct remainder
mov b,a
mov a,c; quotient
add a ! add a ! add a ! add a; * 16. Cy for o'flow
add b; + remainder. clears cy
pop b
ret
;
; show day of week. hl = drdate (days since 77/12/31 = Sat.)
; a,f,d,e
day: push h
lxi d,-7
call divd
dad h
dad h
lxi d,dtbl
dad d
mvi d,4
day1: mov a,m
inx h
call couta
dcr d
jnz day1
call blk
pop h
ret
;
dtbl: db 'Sat.Sun.Mon.Tue.Wed.Thu.Fri.'
;
; PROCEDURE drtodate(thedate : integer; VAR yr, mo, day : integer);
; (* 1 Jan 1978 corresponds to Digital Research date = 1 *)
; (* BUG - cannot handle negative values for dates > 2067 *)
;
; VAR
; i, y1 : integer;
; dayspermonth : ARRAY[1..12] OF 1..31;
;
; BEGIN (* drtodate *)
; FOR i := 1 TO 12 DO dayspermonth[i] := 31;
; dayspermonth[4] := 30; dayspermonth[6] := 30;
; dayspermonth[9] := 30; dayspermonth[11] := 30;
; IF thedate > 731 THEN BEGIN (* avoid overflows *)
; yr := 1980; thedate := thedate - 731; END
; ELSE BEGIN
; thedate := thedate + 730; yr := 1976; END;
; (* 0..365=y0; 366..730=y1; 731..1095=y2; 1096..1460=y3 *)
; i := thedate DIV 1461; thedate := thedate MOD 1461;
; y1 := (thedate-1) DIV 365; yr := yr + y1 + 4*i;
; IF y1 = 0 THEN (* leap year *) dayspermonth[2] := 29
; ELSE BEGIN
; thedate := thedate - 1; (* 366 -> 365 -> 1 Jan *)
; dayspermonth[2] := 28; END;
; day := thedate - 365*y1 + 1; mo := 1;
; WHILE day > dayspermonth[mo] DO BEGIN
; day := day - dayspermonth[mo];
; mo := succ(mo); END;
; END; (* drtodate *)
;
; Incorporate (a) in year (c), overflows to century (b)
addyr: add c
jnc addyr1; <256
sui 100; 256..276
jmp addyr2
addyr1: dcr b
addyr2: inr b
sui 100
jnc addyr2
adi 100; b = century, c = year MOD 100
mov c,a
ret
;
; divide hl by -de, rdr to hl, quotient to a
; a,f,d,e,h,l
divd: mvi a,-1
divd1: inr a
dad d
jc divd1
push psw
mov a,l
sub e
mov l,a
mov a,h
sbb d
mov h,a
pop psw
ret
;
; days per month, except leap year. Leading dummy 0 for month 0
mtbl: db 0,31,28,31,30,31,30,31,31,30,31,30,31
;
; Input : hl = drdate (days since 78/1/1, 1 = 78/1/1)
; Output : b, c, d, e = cent, year, month, day (binary)
; a,f,b,c,d,e,h,l
drtodate:
lxi b,256*19 + 76; 731 represents 80/1/1
push h
lxi d,-731
dad d
pop h
jnc drd1; before 80/1/1
dad d; on or after 80/1/1
mvi c,80; now 0 represents 80/1/1
jmp drd2
drd1: lxi d,730
dad d; now 731 represents 78/1/1
drd2: lxi d,-1461
call divd; get quad years since base (in c)
add a
add a; 4 * i. 180 max
call addyr; yr := yr + 4 * i
mov a,h
ora l
jz drd3; At Jan 1, leap year
dcx h; thedate := thedate - 1
lxi d,-365; so year thresholds come out right
call divd; thedate := thedate MOD 365
push psw; y1 := a := thedate DIV 365
call addyr; yr := yr+y1
pop psw; 0 for leapyear
jnz drd5; not a leap year
inx h; thedate := thedate+1 (1..365)
drd3: mvi a,29
sta mtbl+2
drd5: xchg
lxi h,mtbl
push b
mvi b,0; mo := 0
drd6: inx h; WHILE
inr b; day := day-dayspermo[mo := mo+1] >= 0
mov a,e; DO (* again *)
sub m
mov e,a
mov a,d
sbi 0
mov d,a
jnc drd6
mov a,e; day := day+dayspermo[mo]
add m
mov e,a; range 0..pred(dayspermo[mo])
adc d
sub e
mov d,a
xchg
mov d,b
pop b
mov e,l
inr e; make result 1 based
mvi a,28
sta mtbl+2; restore month table
ret
;
; Input: b, c, d, e = cent, year, month, day (binary)
; Output: hl = drdate (days since 78/1/1, 1=78/1/1)
; hl = 0 for some invalid dates, including 1977.
; Century = ignored, assumed 1900 base + year.
; Operates 1978 Jan. 1 to 2155 Dec. 31 inclusive.
; a,f,b,c,d,e,h,l
cnvt: lxi h,0; default for errors
mov a,c ! sui 78;
rc; < 1978 illegal, return 0
cnvt2: adi 2 ! mov b,a; years since 1976 makes leaps easy
ani 3 ! mov c,a; yr := year mod 4
mov a,b ! sub c
rrc ! rrc ! mov b,a; i := year div 4
mov a,d ! ora a; month
rz; invalid, return 0
mov a,e ! ora a; day
rz; invalid, return 0
lxi h,-730-1461-365; 76/1/1 & pre-corrections
call index; drdate := day + drdate
push d
lxi d,1461; 4 years of days
inr b; allow for zero input, pre-corrected
cnvt3: dad d ! dcr b
jnz cnvt3; drdate := day - 730 + (i * 1461) - 365
pop d
mov a,c; yr
ora a
mov a,d; month
jnz cnvt4; IF (yr = 0) AND (month < 3) THEN
cpi 3 ! jnc cnvt4; drdate := drdate-1; (2000 is leapyr)
dcx h; (leap year correction)
cnvt4: mov b,c; yr, 0..3
lxi d,365; 1 year of days
inr b; allow for zero, pre-corrected
cnvt5: dad d ! dcr b
jnz cnvt5; drdate := drdate + 365 * (yr+1)
mov b,a; month
lxi d,mtbl
cnvt6: ldax d; for i := 1 to month-1 DO
call index; drdate := drdate + dpermo[i];
inx d ! dcr b
jnz cnvt6
ret
;
; index hl := hl + a (max a = 127)
; a,f,h,l
index: add l
mov l,a
rnc
inr h
ret
;
; one blank to console
; a,f
blk: mvi a,' '
; " "
; console output from (a)
; a,f
couta: push b
push d
push h
mov e,a
mvi c,cout
call bdos
pop h
pop d
pop b
ret
;
syntax: db 'Bad time specification',cr,lf,cr,lf
hlpmsg: db 'TIME v. '
db ver / 10 + '0', '.', ver MOD 10 + '0'
db ' (c) 1986 C.B. Falconer',cr,lf,cr,lf
db 'Usage: (ISO standard format)',cr,lf
db ' TIME<cr> (to show current time)',cr,lf
db ' TIME yy/mm/dd hh:mm (to set time)',cr,lf
db ' TIME ? (for help)',cr,lf,cr,lf
db 'ex: TIME 86/11/15 17:12 (uses 24hr time)$'
vermsg: db 'Needs DOS+ or CPM3$'
notmsg: db 'No time set$'
;
tod: ds 5; time string
;
ds 64
stack:
end
=