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

📄 ptime.asm

📁 DOS 源码 系列之 BIOS ,上传与大家分享
💻 ASM
📖 第 1 页 / 共 2 页
字号:

	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 + -