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

📄 rtc.8

📁 tiny bios--了解BIOS非常好的资料
💻 8
字号:
	;
	; Timer / RTC functions
	;
	; (C)1997-2001 Pascal Dornier / PC Engines; All rights reserved.
	; This file is licensed pursuant to the COMMON PUBLIC LICENSE 0.5.

	;
	; Limitations:
	;
	; - Wait function not supported.
	; - Reinitialization doesn't set SET bit.
	; - We don't use CMOS RAM for configuration data
	;   (exception: extended memory size).
	; - There is no CMOS checksum.
	;
	
	; Year 2000 issue:
	;
	; - Years below 1980 are considered century roll-over, replaced
	;   by year 2000.
	; - Please note that DOS will force default date for anything
	;   before 1980.

	; pd 000817 add TICK_RATE option to support AMD Elan SC520
	;           (needs modified tick rate)
	; pd 990211 move tests from cm_shut to cm_test	
	; pd 980416 fix alarm function (interrupt mask, CX saved)
	
	;
	; INT1A timer BIOS
	;
int1a:
#if def	PCI		;transfer to PCI BIOS if necessary
	cmp	ah,0b1h	;PCI
	jnz	int1a1
	jmp	pci_i1a	;go to PCI BIOS
int1a1:
#endif
	sti		;enable interrupts
	push	ds
	push	bx
	xor	bx,bx	;BIOS segment
	mov	ds,bx
	cmp	ah,7
	ja	int1a_err	;:bad command code
	mov	bl,ah
	shl	bx,1
	cli		;disable interrupts
	jmp	[cs:bx+int1atab]	;dispatch function
	;
	; AH=2: get RTC time
	;
rtc_get:	call	rtc_uip	;check for RTC update
	jb	int1a_err	;:error
	mov	ah,cm_ss	;read seconds -> DH
	call	rtc_read
	mov	dh,al
	mov	ah,cm_mm	;read minutes -> CL
	call	rtc_read
	mov	cl,al
	mov	ah,cm_hh	;read hours -> CH
	call	rtc_read
	mov	ch,al
	mov	ah,cm_b	;read daylight savings bit -> DL
	call	rtc_read
	and	al,1
	mov	dl,al
	jmp	short int1a_ok
	;
	; AH=3: set RTC time
	;
rtc_set:	push	cx
	call	rtc_uip	;check for RTC update
	pop	cx
	mov	ah,cm_ss	;DH -> seconds
	mov	al,dh
	call	rtc_write
	mov	ah,cm_mm	;CL -> minutes
	mov	al,cl
	call	rtc_write
	mov	ah,cm_hh	;CH -> hours
	mov	al,ch
	call	rtc_write
	mov	ah,cm_b	;read status register B
	call	rtc_read
	and	al,01100010xb	;mask off set, update interrupt,
			;square wave, daylight savings
	or	al,2	;set 24 hour mode
	or	al,dl	;add daylight savings bit from DL
	call	rtc_write	;update status register B
int1a_ok:	clc
int1a_ret: sti
	pop	bx
	pop	ds
	retf	2

int1a_err: stc
	jmp	short int1a_ret
	;
	; AH=4: get RTC date
	;
rtc_date:	call	rtc_uip	;check for RTC update
	jb	int1a_err
	mov	ah,cm_dd	;day -> DL
	call	rtc_read
	mov	dl,al
	mov	ah,cm_mo	;month -> DH
	call	rtc_read
	mov	dh,al
	mov	ah,cm_yy	;year -> CL
	call	rtc_read
	mov	cl,al
	mov	ah,cm_cent	;century -> CH
	call	rtc_read
	mov	ch,al
	cmp	cx,1980h	;century roll-over ?
	jae	rtc_date9
	mov	ax,cm_cent*256+20h	;update century register
	call	rtc_write
	mov	ch,20h	;force 2000
rtc_date9: jmp	int1a_ok
	;
	; AH=5: set RTC date
	;
rtc_sdat:	push	cx
	call	rtc_uip	;check for RTC update
	pop	cx
	mov	ax,cm_day*256	;0 -> day of week (not used)
	call	rtc_write
	mov	ah,cm_dd	;DL -> day
	mov	al,dl
	call	rtc_write
	mov	ah,cm_mo	;DH -> month
	mov	al,dh
	call	rtc_write
	mov	ah,cm_yy	;CL -> year
	mov	al,cl
	call	rtc_write
	mov	ah,cm_cent	;CH -> century
	mov	al,ch
	call	rtc_write
	jmp	int1a_ok
	;
	; AH=6: set RTC alarm
	;
rtc_alrm:	mov	ah,cm_b	;read status B
	call	rtc_read
	and	al,20h	;alarm enabled ?
	jnz	int1a_err	;:error
	push	cx	;save CX !
	call	rtc_uip	;check for RTC update
	pop	cx	;restore...
	mov	ah,cm_ssa	;DH -> alarm second
	mov	al,dh
	call	rtc_write
	mov	ah,cm_mma	;CL -> alarm minute
	mov	al,cl
	call	rtc_write
	mov	ah,cm_hha	;CH -> alarm hour
	mov	al,ch
	call	rtc_write
	
	in	al,pic1+1	;read mask register
	and	al,0feh	;enable RTC interrupt (8)
	out	pic1+1,al
	
	mov	ah,cm_b	;read status B
	call	rtc_read
	or	al,20h	;enable alarm
	call	rtc_write
	jmp	int1a_ok
	;
	; AH=7: clear RTC alarm
	;
rtc_snz:	mov	ah,cm_b	;read status B
	call	rtc_read
	and	al,5fh	;disable alarm interrupt
	call	rtc_write
	jmp	int1a_ok
	;
	; AH=0: get time
	;
tm_get:	mov	dx,[m_timer]	;DX = timer low
	mov	cx,[m_timer+2]	;CX = timer high
	mov	al,0
	xchg	al,[m_timofl]	;AL = timer overflow, reset flag
	jmp	int1a_ok
	;
	; AH=1: set time
	;
tm_set:	mov	byte [m_timofl],0	;clear timer overflow flag
	mov	[m_timer],dx	;DX = timer low
	mov	[m_timer+2],cx	;CX = timer high
	jmp	int1a_ok
	;
	; INT1A dispatch table
	;
	even
int1atab:	dw	tm_get	;AH=0: get time
	dw	tm_set	;AH=1: set time
	dw	rtc_get	;AH=2: get RTC time
	dw	rtc_set	;AH=3: set RTC time
	dw	rtc_date	;AH=4: get RTC date
	dw	rtc_sdat	;AH=5: set RTC date
	dw	rtc_alrm	;AH=6: set RTC alarm
	dw	rtc_snz	;AH=7: clear RTC alarm
	;
	; Clear RTC interrupt, test shutdown byte
	;
	; Be sure to leave cm_test non-zero, as this is used by the
	; master reset code in cs_clr to determine whether to reset
	; the bus.
	;
rtc_test:	mov	al,cm_nmi+cm_c	;clear pending interrupt
	out	cm_idx,al
	out	iowait,al
	in	al,cm_dat

	mov	bx,8000h+cm_nmi+cm_test	;bit to test, test register
rtc_test1: mov	al,bl	;write pattern
	out	cm_idx,al
	out	iowait,al
	mov	al,bh
	out	cm_dat,al
	out	iowait,al
	
	mov	al,bl	;read back
	out	cm_idx,al
	out	iowait,al
	in	al,cm_dat
	out	iowait,al
	cmp	al,bh
	jnz	rtc_test8	;:error - clc -> inverted -> error
	shr	bh,1	;shift pattern right
	jnb	rtc_test1	;:another bit
rtc_test8: cmc		;last bit inverted -> no carry if ok
	ret
	;
	; Wait for RTC UIP bit cleared
	;
	; This bit is set about 250鎠 before the next update. If clear,
	; we have at least 250鎠 to read or write the RTC without
	; updates coming in between.
	;
rtc_uip:	mov	cx,1000
	mov	ah,cm_a
rtc_uip1:	cli
	call	rtc_read
	and	al,80h	;UIP ?
	jz	rtc_uip9	;:ok, carry clear
	sti		;give interrupts a chance
	loop	rtc_uip1	;:try again
	mov	ax,cm_a*256+26h	;set 32768 Hz oscillator, 1 ms int
	call	rtc_write	;to restart...
	stc
rtc_uip9:	ret
	;
	; read RTC register [AH] -> AL
	;
rtc_read:	mov	al,ah
	out	cm_idx,al
	out	iowait,al
	in	al,cm_dat
	out	iowait,al
	ret
	;
	; write RTC register AL -> [AH]
	;
rtc_write: xchg	al,ah
	out	cm_idx,al
	out	iowait,al
	xchg	al,ah
	out	cm_dat,al
	ret
	;
	; clock tick (IRQ0)
	;
irq0:	sti		;enable interrupts
	push	ax
	push	dx
	push	ds

#if def	debug
	call	diag_csip	;debug: display CS:IP on MDA
#endif

	xor	ax,ax	;access BIOS segment
	mov	ds,ax

	mov	ax,[m_timer]	;update timer
	mov	dx,[m_timer+2]
	add	ax,1
	adc	dx,0
	cmp	ax,00b2h	;24 hours ?
	jnz	irq0_1
	cmp	dx,0018h
	jnz	irq0_1
	xor	ax,ax	;timer overflow - back to 0
	xor	dx,dx
	mov	byte [m_timofl],1
irq0_1:	mov	[m_timer],ax
	mov	[m_timer+2],dx
	
	dec	byte [m_fdcnt]	;floppy motor timer
	jnz	irq0_2	;:not yet
	mov	al,0ch
	mov	dx,fdc_ctrl
	out	dx,al	;turn off motor
	and	byte [m_fdmot],0f0h	;turn off motor bits

irq0_2:	int	1ch	;call user hook
	
	pop	ds
	pop	dx
	mov	al,eoi	;signal end of interrupt
	cli
	out	pic0,al
	pop	ax
	iret
	;
	; RTC interrupt (IRQ8)
	;
irq8:	push	ax
	mov	al,cm_c	;check alarm interrupt bit
	out	cm_idx,al
	out	iowait,al
	in	al,cm_dat
	test	al,20h
	jz	irq8_1
	push	ax
	int	4ah	;call user hook
	pop	ax
irq8_1:	mov	al,eoi	;signal end of interrupt
	out	pic1,al
	out	pic0,al
	pop	ax
	iret
	;
	; Timer initialization -> 18.2 Hz tick
	; Unmask timer and keyboard interrupts
	;
tim_init:	mov	al,36h
	out	timer+3,al
#if def	TICK_RATE
	mov	al,low(TICK_RATE)	;LSB
	out	timer,al
	mov	al,high(TICK_RATE)	;MSB
	out	timer,al
#else
	mov	al,0
	out	timer,al
	out	timer,al
#endif

	in	al,pic0+1	;enable timer, keyboard interrupt
	and	al,11111100xb
	out	iowait,al
	out	pic0+1,al
	out	iowait,al
	mov	al,eoi
	out	pic0,al
	ret
	;
	; RTC init
	;
rtc_ini:	mov	ah,cm_d	;read status register D
	call	rtc_read
	and	al,80h	;battery low ?
	jz	rtc_ini0	;:yes

	; battery ok - validate the time / date

	mov	ah,2	;get RTC time
	int	1ah
	jb	rtc_ini0	;:error
	mov	al,dh	;validate seconds
	mov	ah,60h
	call	rtc_val
	jb	rtc_ini0	;:bad
	mov	al,cl	;validate minutes	
	mov	ah,60h
	call	rtc_val
	jb	rtc_ini0	;:bad
	mov	al,ch	;validate hours
	mov	ah,24h
	call	rtc_val
	jb	rtc_ini0	;:bad

	mov	ah,4	;get RTC date
	int	1ah
	mov	al,dl	;day
	mov	ah,31h
	call	rtc_val
	jb	rtc_ini0	;:bad
	mov	al,dh	;month
	mov	ah,12h
	call	rtc_val
	jb	rtc_ini0	;:bad
	mov	ax,cx
	cmp	ax,1980h	;minimum 1980
	jb	rtc_ini0
	cmp	ax,2099h	;maximum 2099
	ja	rtc_ini0
	mov	ah,99h	;maximum year
	call	rtc_val
	jb	rtc_ini0	;:bad
	
	mov	ax,cm_dia*256	;clear diag register
	call	rtc_write
	jmp	short rtc_ini2
	
	; battery was low or invalid time - initialize the RTC	

rtc_ini0:	inc	byte [tmp_rtc]	;set RTC failure flag
	mov	si,offset rtc_tab
rtc_ini1:	cs:	lodsw	;get value from table
	call	rtc_write	;write to RTC
	cmp	si,offset rtc_tab9	;end of table ?
	jb	rtc_ini1	;:no
	
	; Set timer tick value from RTC time
	;
	; Please note that there are different algorithms with varying
	; accuracy for doing this, there can be slight time discrepancies
	; depending on what algorithm is used by the OS.
	
rtc_ini2:	mov	ah,2	;get RTC time
	int	1ah
	jb	rtc_ini9	;:error
	mov	[tmp_ss],dh	;save second for run check
	mov	[tmp_mm],cl	;save minute for run check
	push	dx
	xor 	ebx,ebx
	mov	al,ch	;hour
	mov 	edx,01000755h	;18.206 * 3600 * 256
	call	rtc_mul
	mov	al,cl	;minute
	mov 	edx,00044464h	;18.206 * 60 * 256
	call	rtc_mul
	pop	ax	;second
	mov	al,ah
	mov	dx,4661	;18.206 * 256
	call	rtc_mul
	shr 	ebx,8	;timer / 256
	mov 	dword [m_timer],ebx	;set timer
	mov	[tmp_timer],bx	;backup for run check
rtc_ini9:	ret
	;
	; convert number in AL from BCD -> binary, * EDX -> add to EBX
	;
rtc_mul:	mov	ah,al	;high digit
	and	al,15	;mask low digit
	shr	ah,4	;high -> low nibble
	aad		;convert to binary
	db	066h
	cbw		;clear top of eax
	mul 	edx
	add 	ebx,eax	;add ebx,eax
	ret
	;
	; validate a BCD number in AL, AH = limit
	;
rtc_val:	cmp	al,ah	;exceed limit ?
	ja	rtc_val9	;(no carry -> cmc -> error)
	and	al,15	;high digit is ok, now check low digit
	cmp	al,10	;(less than 10 -> carry -> cmc -> ok)
rtc_val9:	cmc		;return error status
	ret
	;
	; Timer & RTC test
	;
tim_test:	mov	ax,[m_timer]	;did we get at least one timer tick ?
	cmp	ax,[tmp_timer]
	jnz	tim_test0	;:ok
	
	; Could fail if floppy and IDE init were super fast. Give it
	; another chance.
	
	mov	bx,60	;wait 60 ms
	call	cs_waitbx
	mov	ax,[m_timer]	;did we get at least one timer tick ?
	cmp	ax,[tmp_timer]
	jz	tim_test8	;no: error

tim_test0: add	ax,20	;wait max. of one second
	xchg	ax,bx
tim_test1: mov	ah,2	;read RTC
	int	1ah
	jb	tim_test8	;:error
	cmp	dh,[tmp_ss]	;compare second
	jnz	tim_test9	;:ok
	cmp	cl,[tmp_mm]	;compare minute
	jnz	tim_test9	;:ok
	cmp	bx,[m_timer]	;time-out ?
	js	tim_test8	;:yes
	hlt		;wait for next interrupt
	jmp	tim_test1	;look again

tim_test8: inc	byte [tmp_tim]	;set error flag	
tim_test9: ret

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -