⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ptime.asm

📁 DOS 源码 系列之 BIOS ,上传与大家分享
💻 ASM
📖 第 1 页 / 共 2 页
字号:
;
;------------------------------------------------------------------------------
;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 + -