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

📄 _lztimer.asm

📁 BIOS emulator and interface to Realmode X86 Emulator Library Can emulate a PCI Graphic Controller V
💻 ASM
字号:
;****************************************************************************;*;*					SciTech OS Portability Manager Library;*;*  ========================================================================;*;*    The contents of this file are subject to the SciTech MGL Public;*    License Version 1.0 (the "License"); you may not use this file;*    except in compliance with the License. You may obtain a copy of;*    the License at http://www.scitechsoft.com/mgl-license.txt;*;*    Software distributed under the License is distributed on an;*    "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or;*    implied. See the License for the specific language governing;*    rights and limitations under the License.;*;*    The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.;*;*    The Initial Developer of the Original Code is SciTech Software, Inc.;*    All Rights Reserved.;*;*  ========================================================================;*;* Language:	NASM or TASM Assembler;* Environment:	IBM PC (MS DOS);*;* Description:	Uses the 8253 timer and the BIOS time-of-day count to time;*				the performance of code that takes less than an hour to;*				execute.;*;*				The routines in this package only works with interrupts;*				enabled, and in fact will explicitly turn interrupts on;*				in order to ensure we get accurate results from the timer.;*;*	Externally 'C' callable routines:;*;*	LZ_timerOn:		Saves the BIOS time of day count and starts the;*					long period Zen Timer.;*;*	LZ_timerLap:	Latches the current count, and keeps the timer running;*;*	LZ_timerOff:	Stops the long-period Zen Timer and saves the timer;*					count and the BIOS time of day count.;*;*	LZ_timerCount:	Returns an unsigned long representing the timed count;*					in microseconds. If more than an hour passed during;*					the timing interval, LZ_timerCount will return the;*					value 0xFFFFFFFF (an invalid count).;*;*	Note:	If either more than an hour passes between calls to LZ_timerOn;*			and LZ_timerOff, an error is reported. For timing code that takes;*			more than a few minutes to execute, use the low resolution;*			Ultra Long Period Zen Timer code, which should be accurate;*			enough for most purposes.;*;*	Note:	Each block of code being timed should ideally be run several;*			times, with at least two similar readings required to;*			establish a true measurement, in order to eliminate any;*			variability caused by interrupts.;*;*	Note:	Interrupts must not be disabled for more than 54 ms at a;*			stretch during the timing interval. Because interrupts are;*			enabled, key, mice, and other devices that generate interrupts;*			should not be used during the timing interval.;*;*	Note:	Any extra code running off the timer interrupt (such as;*			some memory resident utilities) will increase the time;*			measured by the Zen Timer.;*;*	Note:	These routines can introduce inaccuracies of up to a few;*			tenths of a second into the system clock count for each;*			code section being timed. Consequently, it's a good idea to;*			reboot at the conclusion of timing sessions. (The;*			battery-backed clock, if any, is not affected by the Zen;*			timer.);*;*  All registers and all flags are preserved by all routines, except;*	interrupts which are always turned on;*;****************************************************************************		IDEALinclude "scitech.mac";****************************************************************************;; Equates used by long period Zen Timer;;****************************************************************************; Base address of 8253 timer chipBASE_8253		equ		40h; The address of the timer 0 count registers in the 8253TIMER_0_8253	equ		BASE_8253 + 0; The address of the mode register in the 8253MODE_8253		equ		BASE_8253 + 3; The address of the BIOS timer count variable in the BIOS data area.TIMER_COUNT		equ		6Ch; Macro to delay briefly to ensure that enough time has elapsed between; successive I/O accesses so that the device being accessed can respond; to both accesses even on a very fast PC.ifdef	USE_NASM%macro	DELAY 0		jmp		short $+2		jmp		short $+2		jmp		short $+2%endmacroelsemacro	DELAY		jmp		short $+2		jmp		short $+2		jmp		short $+2endmendifheader		_lztimerbegdataseg	_lztimer		cextern  _ZTimerBIOSPtr,DPTRStartBIOSCount      dd  0       ; Starting BIOS count dwordEndBIOSCount		dd	0		; Ending BIOS count dwordEndTimedCount		dw	0		; Timer 0 count at the end of timing periodenddataseg	_lztimerbegcodeseg	_lztimer				; Start of code segment;----------------------------------------------------------------------------; void LZ_timerOn(void);;----------------------------------------------------------------------------; Starts the Long period Zen timer counting.;----------------------------------------------------------------------------cprocstart	LZ_timerOn; Set the timer 0 of the 8253 to mode 2 (divide-by-N), to cause; linear counting rather than count-by-two counting. Also stops; timer 0 until the timer count is loaded, except on PS/2 computers.		mov		al,00110100b		; mode 2		out		MODE_8253,al; Set the timer count to 0, so we know we won't get another timer; interrupt right away. Note: this introduces an inaccuracy of up to 54 ms; in the system clock count each time it is executed.		DELAY		sub		al,al		out		TIMER_0_8253,al		; lsb		DELAY		out		TIMER_0_8253,al		; msb; Store the timing start BIOS count		use_esifdef	flatmodel		mov		ebx,[_ZTimerBIOSPtr]else		les		bx,[_ZTimerBIOSPtr]endif		cli							; No interrupts while we grab the count		mov		eax,[_ES _bx+TIMER_COUNT]		sti		mov		[StartBIOSCount],eax		unuse_es; Set the timer count to 0 again to start the timing interval.		mov		al,00110100b		; set up to load initial		out		MODE_8253,al		; timer count		DELAY		sub		al,al		out		TIMER_0_8253,al		; load count lsb		DELAY		out		TIMER_0_8253,al		; load count msb		retcprocend;----------------------------------------------------------------------------; void LZ_timerOff(void);;----------------------------------------------------------------------------; Stops the long period Zen timer and saves count.;----------------------------------------------------------------------------cprocstart	LZ_timerOff; Latch the timer count.		mov		al,00000000b		; latch timer 0		out		MODE_8253,al		cli							; Stop the BIOS count; Read the BIOS count. (Since interrupts are disabled, the BIOS; count won't change).		use_esifdef	flatmodel		mov		ebx,[_ZTimerBIOSPtr]else		les		bx,[_ZTimerBIOSPtr]endif		mov		eax,[_ES _bx+TIMER_COUNT]		mov		[EndBIOSCount],eax		unuse_es; Read out the count we latched earlier.		in		al,TIMER_0_8253		; least significant byte		DELAY		mov		ah,al		in		al,TIMER_0_8253		; most significant byte		xchg	ah,al		neg		ax					; Convert from countdown remaining									;  to elapsed count		mov		[EndTimedCount],ax		sti							; Let the BIOS count continue		retcprocend;----------------------------------------------------------------------------; unsigned long LZ_timerLap(void);----------------------------------------------------------------------------; Latches the current count and converts it to a microsecond timing value,; but leaves the timer still running. We dont check for and overflow,; where the time has gone over an hour in this routine, since we want it; to execute as fast as possible.;----------------------------------------------------------------------------cprocstart	LZ_timerLap		push	ebx					; Save EBX for 32 bit code; Latch the timer count.        mov     al,00000000b        ; latch timer 0		out		MODE_8253,al        cli                         ; Stop the BIOS count; Read the BIOS count. (Since interrupts are disabled, the BIOS; count wont change).		use_esifdef	flatmodel		mov		ebx,[_ZTimerBIOSPtr]else		les		bx,[_ZTimerBIOSPtr]endif		mov		eax,[_ES _bx+TIMER_COUNT]		mov		[EndBIOSCount],eax		unuse_es; Read out the count we latched earlier.		in		al,TIMER_0_8253		; least significant byte		DELAY		mov		ah,al		in		al,TIMER_0_8253		; most significant byte		xchg	ah,al		neg		ax					; Convert from countdown remaining									;  to elapsed count		mov		[EndTimedCount],ax		sti							; Let the BIOS count continue; See if a midnight boundary has passed and adjust the finishing BIOS; count by the number of ticks in 24 hours. We wont be able to detect; more than 24 hours, but at least we can time across a midnight; boundary		mov		eax,[EndBIOSCount]		; Is end < start?		cmp		eax,[StartBIOSCount]		jae		@@CalcBIOSTime			; No, calculate the time taken; Adjust the finishing time by adding the number of ticks in 24 hours; (1573040).		add		[DWORD EndBIOSCount],1800B0h; Convert the BIOS time to microseconds@@CalcBIOSTime:		mov		ax,[WORD EndBIOSCount]		sub		ax,[WORD StartBIOSCount]		mov		dx,54925			; Number of microseconds each									;  BIOS count represents.		mul		dx		mov		bx,ax				; set aside BIOS count in		mov		cx,dx				;  microseconds; Convert timer count to microseconds		push	_si		mov		ax,[EndTimedCount]		mov		si,8381		mul		si		mov		si,10000		div		si					; * 0.8381 = * 8381 / 10000		pop		_si; Add the timer and BIOS counts together to get an overall time in; microseconds.		add		ax,bx		adc		cx,0ifdef flatmodel		shl		ecx,16		mov		cx,ax		mov		eax,ecx				; EAX := timer countelse		mov		dx,cxendif		pop		ebx					; Restore EBX for 32 bit code		retcprocend;----------------------------------------------------------------------------; unsigned long LZ_timerCount(void);;----------------------------------------------------------------------------; Returns an unsigned long representing the net time in microseconds.;; If an hour has passed while timing, we return 0xFFFFFFFF as the count; (which is not a possible count in itself).;----------------------------------------------------------------------------cprocstart	LZ_timerCount		push	ebx					; Save EBX for 32 bit code; See if a midnight boundary has passed and adjust the finishing BIOS; count by the number of ticks in 24 hours. We wont be able to detect; more than 24 hours, but at least we can time across a midnight; boundary		mov		eax,[EndBIOSCount]		; Is end < start?		cmp		eax,[StartBIOSCount]		jae		@@CheckForHour			; No, check for hour passing; Adjust the finishing time by adding the number of ticks in 24 hours; (1573040).		add		[DWORD EndBIOSCount],1800B0h; See if more than an hour passed during timing. If so, notify the user.@@CheckForHour:		mov		ax,[WORD StartBIOSCount+2]		cmp		ax,[WORD EndBIOSCount+2]		jz		@@CalcBIOSTime		; Hour count didn't change, so									;  everything is fine		inc		ax		cmp		ax,[WORD EndBIOSCount+2]		jnz		@@TestTooLong		; Two hour boundaries passed, so the									;  results are no good		mov 	ax,[WORD EndBIOSCount]		cmp		ax,[WORD StartBIOSCount]		jb		@@CalcBIOSTime		; a single hour boundary passed. That's									; OK, so long as the total time wasn't									; more than an hour.; Over an hour elapsed passed during timing, which renders; the results invalid. Notify the user. This misses the case where a; multiple of 24 hours has passed, but we'll rely on the perspicacity of; the user to detect that case :-).@@TestTooLong:ifdef	flatmodel		mov		eax,0FFFFFFFFhelse		mov		ax,0FFFFh		mov		dx,0FFFFhendif		jmp		short @@Done; Convert the BIOS time to microseconds@@CalcBIOSTime:		mov		ax,[WORD EndBIOSCount]		sub		ax,[WORD StartBIOSCount]		mov		dx,54925			; Number of microseconds each									;  BIOS count represents.		mul		dx		mov		bx,ax				; set aside BIOS count in		mov		cx,dx				;  microseconds; Convert timer count to microseconds		push	_si		mov		ax,[EndTimedCount]		mov		si,8381		mul		si		mov		si,10000		div		si					; * 0.8381 = * 8381 / 10000		pop		_si; Add the timer and BIOS counts together to get an overall time in; microseconds.		add		ax,bx		adc		cx,0ifdef flatmodel		shl		ecx,16		mov		cx,ax		mov		eax,ecx				; EAX := timer countelse		mov		dx,cxendif@@Done:	pop		ebx					; Restore EBX for 32 bit code		retcprocendcprocstart   LZ_disable		cli		retcprocendcprocstart   LZ_enable		sti		retcprocendendcodeseg	_lztimer		END

⌨️ 快捷键说明

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