📄 ptime.asm
字号:
mov daycnt2,2 ; read of r-t clock successful
call bcd_verify ; verify bcd values in range
jc r_d_ret ; jmp some value out of range
mov daycnt2,3 ; read of r-t clock successful
call date_verify ; verify date values in range
jc r_d_ret ; jmp some value out of range
mov daycnt2,0 ; verify successful
call in_bin ; convert date to binary
; ******* years since 1-1-80 *********
mov al,byte ptr bin_date_time ; get years into century
cbw ;
cmp byte ptr bin_date_time+1,20 ; 20th century?
jnz century_19 ; jmp no
add ax,100 ; add in a century
century_19: ;
sub ax,80 ; subtract off 1-1-80
mov cl,4 ; leap year every 4
div cl ; al= # leap year blocks, ah= remainder
mov bl,ah ; save odd years
cbw ; zero ah
mov cx,366+3*365 ; # of days in leap year blocks
mul cx ; dx:ax is result
mov daycnt2,ax ; save count of days
mov al,bl ; get odd years count
cbw ;
or ax,ax ; is ax= 0?
jz leap_year ; jmp if none
mov cx,365 ; days in year
mul cx ; dx:ax is result
add daycnt2,ax ; add on days in odd years
jmp short leap_adjustment ; account for leap year
leap_year: ; possibly account for a leap day
cmp byte ptr bin_date_time+3,2 ; is month february
jbe no_leap_adjustment ; jan or feb. no leap day yet.
leap_adjustment: ; account for leap day
inc daycnt2
no_leap_adjustment: ; ******* get days of month *******
mov cl,byte ptr bin_date_time+2
xor ch,ch
dec cx ; because of offset from day 1, not day 0
add daycnt2,cx ; ******* get days in months preceeing *****
mov cl,byte ptr bin_date_time+3 ; get month
xor ch,ch
dec cx ; january starts at offset 0
shl cx,1 ; word offset
mov si,offset month_table ; beginning of month_table
add si,cx ; point into month table
mov ax,word ptr [si]; get # days in previous months
add daycnt2,ax
r_d_ret:
mov si,daycnt2 ; result in si
pop dx
pop cx
pop bx
pop ax
ret
r_t_retj:
xor cx,cx
xor dx,dx
jmp short r_t_ret
read_real_date endp
;--------------------------------------------------------------------
; read_real_time reads the time from the rtc. on exit, it has the number of
; ticks (at 18.2 ticks per sec.) in cx:dx.
read_real_time proc near
assume ds:Bios_Data,es:nothing
mov ah,2
int 1ah
jc r_t_retj
oktime:
mov word ptr bin_date_time,cx ; hours + minutes
mov byte ptr bin_date_time+3,dh ; seconds
mov byte ptr bin_date_time+2,0 ; unused for time
call bcd_verify
jc r_t_retj
call time_verify
jc r_t_retj
call in_bin
mov cx,word ptr bin_date_time
mov dx,word ptr bin_date_time+2
; get time in ticks in cx:dx
IFDEF POWERALONE
call time_to_ticks
ELSE
call ttticks
ENDIF
r_t_ret:
ret
read_real_time endp
;--------------------------------------------------------------------
; in_bin converts bin_date_time values from bcd to bin
in_bin proc near
assume ds:Bios_Data,es:nothing
mov al,byte ptr bin_date_time+0 ; years or minutes
call bcd_to_bin
mov byte ptr bin_date_time+0,al
mov al,byte ptr bin_date_time+1 ;century or hours
call bcd_to_bin
mov byte ptr bin_date_time+1,al
mov al,byte ptr bin_date_time+2 ; days (not used for time)
call bcd_to_bin
mov byte ptr bin_date_time+2,al
mov al,byte ptr bin_date_time+3 ; months or seconds
call bcd_to_bin
mov byte ptr bin_date_time+3,al
ret
in_bin endp
;--------------------------------------------------------------------
; bcd_to_bin converts two bcd nibbles in al (value <= 99.) to
; a binary representation in al
; ah is destroyed
bcd_to_bin proc near
assume ds:nothing,es:nothing
mov ah, al ; M048
and al, 0fh ; M048
mov cl, 4 ; M048
shr ah, cl ; M048
aad ; M048
ret
bcd_to_bin endp
;--------------------------------------------------------------------
; date_verify loosely checks bcd date values to be in range in bin_date_time
date_verify proc near
assume ds:Bios_Data,es:nothing
cmp byte ptr bin_date_time+1,20h ; century check
ja date_error ; error
jz century_20 ; jmp in 20th century
cmp byte ptr bin_date_time+1,19h ; century check
jb date_error ; error
cmp byte ptr bin_date_time+0,80h ; year check
jb date_error ; error
century_20:
cmp byte ptr bin_date_time+0,99h ; year check
ja date_error ; error
cmp byte ptr bin_date_time+3,12h ; month check
ja date_error ; error
cmp byte ptr bin_date_time+3,00h ; month check
jbe date_error ; error
cmp byte ptr bin_date_time+2,31h ; day check
ja date_error ; error
cmp byte ptr bin_date_time+2,00h ; day check
jbe date_error ; error
clc ; set success flag
ret
date_error:
stc ; set error flag
ret
date_verify endp
;--------------------------------------------------------------------
; time_verify very loosely checks bcd date values to be in range in bin_date_time
time_verify proc near
assume ds:Bios_Data,es:nothing
cmp byte ptr bin_date_time+1,24h
ja time_error
cmp byte ptr bin_date_time+0,59h
ja time_error
cmp byte ptr bin_date_time+3,59h
ja time_error
clc
ret
time_error:
stc
ret
time_verify endp
;--------------------------------------------------------------------
; bcd_verify checks values in bin_date_time to be valid
; bcd numerals. carry set if any nibble out of range
bcd_verify proc near
assume ds:Bios_Data,es:nothing
mov cx,4 ; 4 bytes to check
mov bx,offset bin_date_time
bv_loop:
mov al,[bx] ; get a bcd number (0..99)
mov ah,al
and ax,0f00fh ; 10's place in high ah, 1's in al
cmp al,10 ; is 1's place in range?
ja bv_error ; jmp out of range
shr ah,1 ; swap nibbles
shr ah,1
shr ah,1
shr ah,1
and ah,0fh ; get rid of any erroneous bits
cmp ah,10 ; is 10's place in range
ja bv_error ; jmp out of range
inc bx ; next byte
dec cx
jnz bv_loop
clc ; set success flag
ret
bv_error:
stc ; set error flag
ret
bcd_verify endp
;--------------------------------------------------------------------
daycnttoday proc near ; for real time clock support
;entry: [daycnt] = number of days since 1-1-80
;
;return: ch - centry in bcd
; cl - year in bcd
; dh - month in bcd
; dl - day in bcd
push di
mov di,daycnt
cmp di,(365*20+(20/4)) ;# of days from 1-1-1980 to 1-1-2000
jae century20
mov base_century,19
mov base_year,80
jmp short years
century20: ;20th century
mov base_century,20
mov base_year,0
sub di,(365*20+(20/4)) ;adjust daycnt
years:
xor dx,dx
mov ax,di
mov bx,(366+365*3) ;# of days in a leap year block
div bx ;ax = # of leap block, dx = daycnt
mov di,dx ;save daycnt left
mov bl,4
mul bl ;ax = # of years. less than 100 years!
add base_year,al ;so, ah = 0. adjust year accordingly.
inc di ;set daycnt to 1 base
cmp di,366 ;the daycnt here is the remainder of the leap year block.
jbe leapyear ;so, it should within 366+355+355+355 days.
inc base_year ;first if daycnt <= 366, then leap year
sub di,366 ;else daycnt--, base_year++;
;and the next three years are regular years.
mov cx,3
regularyear:
cmp di,365 ;for(i=1; i>3 or daycnt <=365;i++)
jbe yeardone ;{if (daycnt > 365)
inc base_year ; { daycnt -= 365
sub di,365 ; }
loop regularyear ;}
; should never fall through loop
leapyear:
mov byte ptr month_tab+1,29 ;leap year. change the month table.
yeardone:
xor bx,bx
xor dx,dx
mov ax,di
mov si,offset month_tab
mov cx,12
months:
inc bl
mov dl,byte ptr ds:[si] ;compare daycnt for each month until fits
cmp ax,dx ;dh=0.
jbe month_done
inc si ;next month
sub ax,dx ;adjust daycnt
loop months
; should never fall through loop
month_done:
mov byte ptr month_tab+1,28 ;restore month table value
mov dl,bl
mov dh,base_year
mov cl,base_century ;now, al=day, dl=month,dh=year,cl=century
call bintobcd ;oh my!!! to save 15 bytes, bin_to_bcd proc
;was relocated seperately from daycnt_to_day proc.
xchg dl,al ;dl = bcd day, al = month
call bintobcd
xchg dh,al ;dh = bcd month, al = year
call bintobcd
xchg cl,al ;cl = bcd year, al = century
call bintobcd
mov ch,al ;ch = bcd century
pop di ;restore original value
ret
daycnttoday endp
IFDEF POWERALONE ; needed only for standalone version
; for resident version use the one in
; mschar.asm
;--------------------------------------------------------------------
; convert time to ticks
; input : time in cx and dx
; ticks returned in cx:dx
time_to_ticks proc near
; first convert from hour,min,sec,hund. to
; total number of 100th of seconds
mov al,60
mul ch ;hours to minutes
mov ch,0
add ax,cx ;total minutes
mov cx,6000 ;60*100
mov bx,dx ;get out of the way of the multiply
mul cx ;convert to 1/100 sec
mov cx,ax
mov al,100
mul bh ;convert seconds to 1/100 sec
add cx,ax ;combine seconds with hours and min.
adc dx,0 ;ripple carry
mov bh,0
add cx,bx ;combine 1/100 sec
adc dx,0
; dx:cx is time in 1/100 sec
xchg ax,dx
xchg ax,cx ;now time is in cx:ax
mov bx,59659
mul bx ;multiply low half
xchg dx,cx
xchg ax,dx ;cx->ax, ax->dx, dx->cx
mul bx ;multiply high half
add ax,cx ;combine overlapping products
adc dx,0
xchg ax,dx ;ax:dx=time*59659
mov bx,5
div bl ;divide high half by 5
mov cl,al
mov ch,0
mov al,ah ;remainder of divide-by-5
cbw
xchg ax,dx ;use it to extend low half
div bx ;divde low half by 5
mov dx,ax
; cx:dx is now number of ticks in time
ret
time_to_ticks endp
ENDIF
Bios_Code ends
ENDIF
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -