?? ptime.asm
字號:
;
;------------------------------------------------------------------------------
;M074 - ptime.asm added, containing clock/time routines for power.asm.
;
; 09/11/91 SMR M077: B#2669. Registered POWER's 2f channels in mult.inc
;
; 09/25/91 NSM M090: B#2729. Try to update our time from CMOS under
; WIN ENH mode once in 1024 I1c ticks.
; (approx. once in a minute)
; This update happens only if DOS calls us for time and
; does not exactly happen once in a minute.
;
; (this is changed to 20 secs from 1 minute)
;
; 11/26/91 NSM M101: We lose date sometimes under windows. To fix this
; do Int 1a's to get tick count instead of looking at 40:
; 6ch and if we get rollover, then go & update date
; and time from CMOS.
;------------------------------------------------------------------------------
;
;
.xlist
include version.inc ; set build flags
IFDEF POWER ; generate code only if power management
; is enabled
IFNDEF POWERALONE ; segment declarations for resident version
include biosseg.inc ; establish bios segment structure
ELSE ; segment declarations for standalonde version
.SEQ
Bios_Code segment word public 'Bios_Code'
Bios_Code ends
Bios_Data segment word public 'Bios_Data'
Bios_Data ends
SysInitSeg segment word public 'system_init'
SysInitSeg ends
; following segment definitions used by transient part of code
ENDIF
include msequ.inc
include devsym.inc
include bpb.inc
include ioctl.inc
include mult.inc ; M077
include power.inc
IFDEF INCL_APM
include apmequ.inc ; M001
ENDIF
break macro
endm
include error.inc
.list
include msgroup.inc ; define Bios_Data segment
extrn month_table:word
IFDEF POWERALONE ; standalone device driver version
Bios_Res dw Bios_Code ; Our code segment address
ELSE ; resident BIOS version
extrn Bios_Res:word ; Code segment address supplied externally
extrn ttticks:dword ; far ptr to time_to_ticks routine
extrn bintobcd:dword ; ptr to bin_to_bcd routine
IFDEF INCL_APM
extrn Check_and_Init_APM_Ptr:dword ; ptr to APM init routine
ENDIF ;INCL_APM
extrn P_UpdFromCMOS_Ptr:dword ; ptr to CMOS clock read ; M081
ENDIF ;NOT POWERALONE
extrn daycnt:word ; extrns for both resident and stand-alone
extrn daycnt2:word ; versions
extrn base_century:byte
extrn base_year:byte
extrn month_tab:byte
extrn bin_date_time:byte
extrn CMOSUpdFlg:byte
extrn CMOSPollCount:word
tocode
IFDEF POWERALONE ; stand alone version
Bios_Data_Word dw Bios_Data ; Our data segment
bintobcd proc near ;for real time clock support
;convert a binary input in al (less than 63h or 99 decimal)
;into a bcd value in al. ah destroyed.
push cx
aam ; M048
mov cl, 4 ; M048
shl ah, cl ; M048
or al, ah ; M048
pop cx
ret
bintobcd endp
ELSE ; resident version
extrn Bios_Data_word:word
ENDIF
public tim_read
public tim_writ
;--------------------------------------------------------------------
;
; tim_writ sets the current time
;
; on entry es:[di] has the current time:
;
; number of days since 1-1-80 (word)
; minutes (0-59) (byte)
; hours (0-23) (byte)
; hundredths of seconds (0-99) (byte)
; seconds (0-59) (byte)
;
; each number has been checked for the correct range.
;
tim_writ proc near
assume ds:Bios_Data
mov ax,word ptr es:[di]
push ax ;daycnt. we need to set this at the very
; end to avoid tick windows.
; Set hardware clock time.
mov al,es:[di+3] ;get binary hours
call bintobcd ;convert to bcd
mov ch,al ;ch = bcd hours
mov al,es:[di+2] ;get binary minutes
call bintobcd ;convert to bcd
mov cl,al ;cl = bcd minutes
mov al,es:[di+5] ;get binary seconds
call bintobcd ;convert to bcd
mov dh,al ;dh = bcd seconds
mov dl,0 ;dl = 0 (st) or 1 (dst)
cli ;turn off timer
mov ah,03h ;set rtc time
int 1ah ;call rom bios clock routine
sti
mov cx,word ptr es:[di+2]
mov dx,word ptr es:[di+4]
IFDEF POWERALONE
call time_to_ticks
ELSE
call ttticks
ENDIF
;cx:dx now has time in ticks
cli ; turn off timer
mov ah, 1 ; command is set time in clock
int 1ah ; call rom-bios clock routines
pop [daycnt]
sti
call daycnttoday ; convert to bcd format
cli ; turn off timer
mov ah,05h ; set rtc date
int 1ah ; call rom-bios clock routines
sti
clc
ret
tim_writ endp
;
; gettime reads date and time
; and returns the following information:
; es:[di] =count of days since 1-1-80
; es:[di+2]=hours
; es:[di+3]=minutes
; es:[di+4]=seconds
; es:[di+5]=hundredths of seconds
tim_read proc near
; M090 BEGIN - See if we have to update our time from CMOS before
; returning date and time to caller.
cmp [CMOSUpdFlg],0 ; M090 do we need to update from CMOS
je tr_NoCMOSUpdate ;
tr_CMOSUpd: ; M101
IFDEF POWERALONE ; M081
call far ptr P_UpdFromCMOS
ELSE
call P_UpdFromCMOS_ptr ; M074 update our date and time
; from CMOS RTC
ENDIF
mov [CMOSPollCount],MAXCMOSPOLLCOUNT
mov [CMOSUpdFlg],0 ;
; M090 END
tr_NoCMOSUpdate:
; M101 - BEGIN - get tick count through 1a instead of looking at 40:6ch
; and check for rollover
mov ax,0 ; get tick count
int 1ah ; cx:dx = tick count
or al,al ; al != 0 if midnight passed
jnz tr_CMOSUpd ; rollover; update date and time
; M101 - END
mov si,[daycnt]
; we now need to convert the time in tick to the time in 100th of
; seconds. the relation between tick and seconds is:
;
; 65536 seconds
; ----------------
; 1,193,180 tick
;
; to get to 100th of second we need to multiply by 100. the equation is:
;
; ticks from clock * 65536 * 100
; --------------------------------- = time in 100th of seconds
; 1,193,180
;
; fortunately this fromula simplifies to:
;
; ticks from clock * 5 * 65,536
; --------------------------------- = time in 100th of seconds
; 59,659
;
; the calculation is done by first multipling tick by 5. next we divide by
; 59,659. in this division we multiply by 65,536 by shifting the dividend
; my 16 bits to the left.
;
; start with ticks in cx:dx
; multiply by 5
mov ax,cx
mov bx,dx
shl dx,1
rcl cx,1 ;times 2
shl dx,1
rcl cx,1 ;times 4
add dx,bx
adc ax,cx ;times 5
xchg ax,dx
; now have ticks * 5 in dx:ax
; we now need to multiply by 65,536 and divide by 59659 d.
mov cx,59659 ; get divisor
div cx
; dx now has remainder
; ax has high word of final quotient
mov bx,ax ; put high work if safe place
xor ax,ax ; this is the multiply by 65536
div cx ; bx:ax now has time in 100th of seconds
;rounding based on the remainder may be added here
;the result in bx:ax is time in 1/100 second.
mov dx,bx
mov cx,200 ;extract 1/100's
;division by 200 is necessary to ensure no overflow--max result
;is number of seconds in a day/2 = 43200.
div cx
cmp dl,100 ;remainder over 100?
jb noadj
sub dl,100 ;keep 1/100's less than 100
noadj:
cmc ;if we subtracted 100, carry is now set
mov bl,dl ;save 1/100's
;to compensate for dividing by 200 instead of 100, we now multiply
;by two, shifting a one in if the remainder had exceeded 100.
rcl ax,1
mov dl,0
rcl dx,1
mov cx,60 ;divide out seconds
div cx
mov bh,dl ;save the seconds
div cl ;break into hours and minutes
xchg al,ah
;time is now in ax:bx (hours, minutes, seconds, 1/100 sec)
push ax
mov ax,si ; daycnt
stosw
pop ax
stosw
mov ax,bx
stosw
clc
ret
tim_read endp
assume es:nothing
; the following routine is executed at resume time when the system
; powered on after suspension. it reads the real time clock and
; resets the system time and date
;
; This can be patched to be the INT6C vector so that this can be
; used by other people to update DOS time from CMOS (after taking
; care for IRET)
public P_UpdFromCMOS
P_UpdFromCMOS proc far
assume ds:nothing
push ds
mov ds,cs:Bios_Data_Word
assume ds:Bios_Data
call read_real_date ; get the date from the clock
PUFC_UpdDate: ; M101
mov ds:daycnt,si ; update our copy of date
call read_real_time ; get the time from the rtc
cli
mov ah,01h ; command to set the time
int 1ah ; call rom-bios time routine
sti
; M101 BEGIN - check back to see if date changed when we were reading the
; time; if so, update date and time all over again ( Paranoid?)
call read_real_date ; get the date from the clock
; BUGBUG- nagara - Store the ret.value of date from int 1a in this
; procedure read_real_date so that at the end we don't really have to
; call read_real_date again; we just need to call int 1a and compare the
; date registers against the stored values of these registers.
cmp si,ds:daycnt ; is the date changed ?
jne PUFC_UpdDate ; yes, go back and set the new date
; M101 END
pop ds
ret
P_UpdFromCMOS endp
;************************************************************************
;
; read_real_date reads real-time clock for date and returns the number
; of days elapsed since 1-1-80 in si
;
read_real_date proc near
assume ds:Bios_Data,es:nothing
push ax
push cx
push dx
xor ah,ah ; throw away clock roll over
int 1ah
pop dx
pop cx
pop ax ; cas - bad code!
push ax
push bx
push cx
push dx
mov daycnt2,1 ; real time clock error flag (+1 day)
mov ah,4 ; read date function code
int 1ah ; read real-time clock
jnc read_ok ; jmp success
jmp r_d_ret ; jmp error
read_ok: ; ******* get bcd values in binary *****
mov word ptr bin_date_time+0,cx ; store as hex value
mov word ptr bin_date_time+2,dx ; ...
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -