]> git.ipfire.org Git - people/ms/u-boot.git/blob - board/MAI/bios_emulator/scitech/src/pm/dos/_lztimer.asm
USB: This patch fix readl in ohci swap reg access.
[people/ms/u-boot.git] / board / MAI / bios_emulator / scitech / src / pm / dos / _lztimer.asm
1 ;****************************************************************************
2 ;*
3 ;* SciTech OS Portability Manager Library
4 ;*
5 ;* ========================================================================
6 ;*
7 ;* The contents of this file are subject to the SciTech MGL Public
8 ;* License Version 1.0 (the "License"); you may not use this file
9 ;* except in compliance with the License. You may obtain a copy of
10 ;* the License at http://www.scitechsoft.com/mgl-license.txt
11 ;*
12 ;* Software distributed under the License is distributed on an
13 ;* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 ;* implied. See the License for the specific language governing
15 ;* rights and limitations under the License.
16 ;*
17 ;* The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
18 ;*
19 ;* The Initial Developer of the Original Code is SciTech Software, Inc.
20 ;* All Rights Reserved.
21 ;*
22 ;* ========================================================================
23 ;*
24 ;* Language: NASM or TASM Assembler
25 ;* Environment: IBM PC (MS DOS)
26 ;*
27 ;* Description: Uses the 8253 timer and the BIOS time-of-day count to time
28 ;* the performance of code that takes less than an hour to
29 ;* execute.
30 ;*
31 ;* The routines in this package only works with interrupts
32 ;* enabled, and in fact will explicitly turn interrupts on
33 ;* in order to ensure we get accurate results from the timer.
34 ;*
35 ;* Externally 'C' callable routines:
36 ;*
37 ;* LZ_timerOn: Saves the BIOS time of day count and starts the
38 ;* long period Zen Timer.
39 ;*
40 ;* LZ_timerLap: Latches the current count, and keeps the timer running
41 ;*
42 ;* LZ_timerOff: Stops the long-period Zen Timer and saves the timer
43 ;* count and the BIOS time of day count.
44 ;*
45 ;* LZ_timerCount: Returns an unsigned long representing the timed count
46 ;* in microseconds. If more than an hour passed during
47 ;* the timing interval, LZ_timerCount will return the
48 ;* value 0xFFFFFFFF (an invalid count).
49 ;*
50 ;* Note: If either more than an hour passes between calls to LZ_timerOn
51 ;* and LZ_timerOff, an error is reported. For timing code that takes
52 ;* more than a few minutes to execute, use the low resolution
53 ;* Ultra Long Period Zen Timer code, which should be accurate
54 ;* enough for most purposes.
55 ;*
56 ;* Note: Each block of code being timed should ideally be run several
57 ;* times, with at least two similar readings required to
58 ;* establish a true measurement, in order to eliminate any
59 ;* variability caused by interrupts.
60 ;*
61 ;* Note: Interrupts must not be disabled for more than 54 ms at a
62 ;* stretch during the timing interval. Because interrupts are
63 ;* enabled, key, mice, and other devices that generate interrupts
64 ;* should not be used during the timing interval.
65 ;*
66 ;* Note: Any extra code running off the timer interrupt (such as
67 ;* some memory resident utilities) will increase the time
68 ;* measured by the Zen Timer.
69 ;*
70 ;* Note: These routines can introduce inaccuracies of up to a few
71 ;* tenths of a second into the system clock count for each
72 ;* code section being timed. Consequently, it's a good idea to
73 ;* reboot at the conclusion of timing sessions. (The
74 ;* battery-backed clock, if any, is not affected by the Zen
75 ;* timer.)
76 ;*
77 ;* All registers and all flags are preserved by all routines, except
78 ;* interrupts which are always turned on
79 ;*
80 ;****************************************************************************
81
82 IDEAL
83
84 include "scitech.mac"
85
86 ;****************************************************************************
87 ;
88 ; Equates used by long period Zen Timer
89 ;
90 ;****************************************************************************
91
92 ; Base address of 8253 timer chip
93
94 BASE_8253 equ 40h
95
96 ; The address of the timer 0 count registers in the 8253
97
98 TIMER_0_8253 equ BASE_8253 + 0
99
100 ; The address of the mode register in the 8253
101
102 MODE_8253 equ BASE_8253 + 3
103
104 ; The address of the BIOS timer count variable in the BIOS data area.
105
106 TIMER_COUNT equ 6Ch
107
108 ; Macro to delay briefly to ensure that enough time has elapsed between
109 ; successive I/O accesses so that the device being accessed can respond
110 ; to both accesses even on a very fast PC.
111
112 ifdef USE_NASM
113 %macro DELAY 0
114 jmp short $+2
115 jmp short $+2
116 jmp short $+2
117 %endmacro
118 else
119 macro DELAY
120 jmp short $+2
121 jmp short $+2
122 jmp short $+2
123 endm
124 endif
125
126 header _lztimer
127
128 begdataseg _lztimer
129
130 cextern _ZTimerBIOSPtr,DPTR
131
132 StartBIOSCount dd 0 ; Starting BIOS count dword
133 EndBIOSCount dd 0 ; Ending BIOS count dword
134 EndTimedCount dw 0 ; Timer 0 count at the end of timing period
135
136 enddataseg _lztimer
137
138 begcodeseg _lztimer ; Start of code segment
139
140 ;----------------------------------------------------------------------------
141 ; void LZ_timerOn(void);
142 ;----------------------------------------------------------------------------
143 ; Starts the Long period Zen timer counting.
144 ;----------------------------------------------------------------------------
145 cprocstart LZ_timerOn
146
147 ; Set the timer 0 of the 8253 to mode 2 (divide-by-N), to cause
148 ; linear counting rather than count-by-two counting. Also stops
149 ; timer 0 until the timer count is loaded, except on PS/2 computers.
150
151 mov al,00110100b ; mode 2
152 out MODE_8253,al
153
154 ; Set the timer count to 0, so we know we won't get another timer
155 ; interrupt right away. Note: this introduces an inaccuracy of up to 54 ms
156 ; in the system clock count each time it is executed.
157
158 DELAY
159 sub al,al
160 out TIMER_0_8253,al ; lsb
161 DELAY
162 out TIMER_0_8253,al ; msb
163
164 ; Store the timing start BIOS count
165
166 use_es
167 ifdef flatmodel
168 mov ebx,[_ZTimerBIOSPtr]
169 else
170 les bx,[_ZTimerBIOSPtr]
171 endif
172 cli ; No interrupts while we grab the count
173 mov eax,[_ES _bx+TIMER_COUNT]
174 sti
175 mov [StartBIOSCount],eax
176 unuse_es
177
178 ; Set the timer count to 0 again to start the timing interval.
179
180 mov al,00110100b ; set up to load initial
181 out MODE_8253,al ; timer count
182 DELAY
183 sub al,al
184 out TIMER_0_8253,al ; load count lsb
185 DELAY
186 out TIMER_0_8253,al ; load count msb
187
188 ret
189
190 cprocend
191
192 ;----------------------------------------------------------------------------
193 ; void LZ_timerOff(void);
194 ;----------------------------------------------------------------------------
195 ; Stops the long period Zen timer and saves count.
196 ;----------------------------------------------------------------------------
197 cprocstart LZ_timerOff
198
199 ; Latch the timer count.
200
201 mov al,00000000b ; latch timer 0
202 out MODE_8253,al
203 cli ; Stop the BIOS count
204
205 ; Read the BIOS count. (Since interrupts are disabled, the BIOS
206 ; count won't change).
207
208 use_es
209 ifdef flatmodel
210 mov ebx,[_ZTimerBIOSPtr]
211 else
212 les bx,[_ZTimerBIOSPtr]
213 endif
214 mov eax,[_ES _bx+TIMER_COUNT]
215 mov [EndBIOSCount],eax
216 unuse_es
217
218 ; Read out the count we latched earlier.
219
220 in al,TIMER_0_8253 ; least significant byte
221 DELAY
222 mov ah,al
223 in al,TIMER_0_8253 ; most significant byte
224 xchg ah,al
225 neg ax ; Convert from countdown remaining
226 ; to elapsed count
227 mov [EndTimedCount],ax
228 sti ; Let the BIOS count continue
229
230 ret
231
232 cprocend
233
234 ;----------------------------------------------------------------------------
235 ; unsigned long LZ_timerLap(void)
236 ;----------------------------------------------------------------------------
237 ; Latches the current count and converts it to a microsecond timing value,
238 ; but leaves the timer still running. We dont check for and overflow,
239 ; where the time has gone over an hour in this routine, since we want it
240 ; to execute as fast as possible.
241 ;----------------------------------------------------------------------------
242 cprocstart LZ_timerLap
243
244 push ebx ; Save EBX for 32 bit code
245
246 ; Latch the timer count.
247
248 mov al,00000000b ; latch timer 0
249 out MODE_8253,al
250 cli ; Stop the BIOS count
251
252 ; Read the BIOS count. (Since interrupts are disabled, the BIOS
253 ; count wont change).
254
255 use_es
256 ifdef flatmodel
257 mov ebx,[_ZTimerBIOSPtr]
258 else
259 les bx,[_ZTimerBIOSPtr]
260 endif
261 mov eax,[_ES _bx+TIMER_COUNT]
262 mov [EndBIOSCount],eax
263 unuse_es
264
265 ; Read out the count we latched earlier.
266
267 in al,TIMER_0_8253 ; least significant byte
268 DELAY
269 mov ah,al
270 in al,TIMER_0_8253 ; most significant byte
271 xchg ah,al
272 neg ax ; Convert from countdown remaining
273 ; to elapsed count
274 mov [EndTimedCount],ax
275 sti ; Let the BIOS count continue
276
277 ; See if a midnight boundary has passed and adjust the finishing BIOS
278 ; count by the number of ticks in 24 hours. We wont be able to detect
279 ; more than 24 hours, but at least we can time across a midnight
280 ; boundary
281
282 mov eax,[EndBIOSCount] ; Is end < start?
283 cmp eax,[StartBIOSCount]
284 jae @@CalcBIOSTime ; No, calculate the time taken
285
286 ; Adjust the finishing time by adding the number of ticks in 24 hours
287 ; (1573040).
288
289 add [DWORD EndBIOSCount],1800B0h
290
291 ; Convert the BIOS time to microseconds
292
293 @@CalcBIOSTime:
294 mov ax,[WORD EndBIOSCount]
295 sub ax,[WORD StartBIOSCount]
296 mov dx,54925 ; Number of microseconds each
297 ; BIOS count represents.
298 mul dx
299 mov bx,ax ; set aside BIOS count in
300 mov cx,dx ; microseconds
301
302 ; Convert timer count to microseconds
303
304 push _si
305 mov ax,[EndTimedCount]
306 mov si,8381
307 mul si
308 mov si,10000
309 div si ; * 0.8381 = * 8381 / 10000
310 pop _si
311
312 ; Add the timer and BIOS counts together to get an overall time in
313 ; microseconds.
314
315 add ax,bx
316 adc cx,0
317 ifdef flatmodel
318 shl ecx,16
319 mov cx,ax
320 mov eax,ecx ; EAX := timer count
321 else
322 mov dx,cx
323 endif
324 pop ebx ; Restore EBX for 32 bit code
325 ret
326
327 cprocend
328
329 ;----------------------------------------------------------------------------
330 ; unsigned long LZ_timerCount(void);
331 ;----------------------------------------------------------------------------
332 ; Returns an unsigned long representing the net time in microseconds.
333 ;
334 ; If an hour has passed while timing, we return 0xFFFFFFFF as the count
335 ; (which is not a possible count in itself).
336 ;----------------------------------------------------------------------------
337 cprocstart LZ_timerCount
338
339 push ebx ; Save EBX for 32 bit code
340
341 ; See if a midnight boundary has passed and adjust the finishing BIOS
342 ; count by the number of ticks in 24 hours. We wont be able to detect
343 ; more than 24 hours, but at least we can time across a midnight
344 ; boundary
345
346 mov eax,[EndBIOSCount] ; Is end < start?
347 cmp eax,[StartBIOSCount]
348 jae @@CheckForHour ; No, check for hour passing
349
350 ; Adjust the finishing time by adding the number of ticks in 24 hours
351 ; (1573040).
352
353 add [DWORD EndBIOSCount],1800B0h
354
355 ; See if more than an hour passed during timing. If so, notify the user.
356
357 @@CheckForHour:
358 mov ax,[WORD StartBIOSCount+2]
359 cmp ax,[WORD EndBIOSCount+2]
360 jz @@CalcBIOSTime ; Hour count didn't change, so
361 ; everything is fine
362
363 inc ax
364 cmp ax,[WORD EndBIOSCount+2]
365 jnz @@TestTooLong ; Two hour boundaries passed, so the
366 ; results are no good
367 mov ax,[WORD EndBIOSCount]
368 cmp ax,[WORD StartBIOSCount]
369 jb @@CalcBIOSTime ; a single hour boundary passed. That's
370 ; OK, so long as the total time wasn't
371 ; more than an hour.
372
373 ; Over an hour elapsed passed during timing, which renders
374 ; the results invalid. Notify the user. This misses the case where a
375 ; multiple of 24 hours has passed, but we'll rely on the perspicacity of
376 ; the user to detect that case :-).
377
378 @@TestTooLong:
379 ifdef flatmodel
380 mov eax,0FFFFFFFFh
381 else
382 mov ax,0FFFFh
383 mov dx,0FFFFh
384 endif
385 jmp short @@Done
386
387 ; Convert the BIOS time to microseconds
388
389 @@CalcBIOSTime:
390 mov ax,[WORD EndBIOSCount]
391 sub ax,[WORD StartBIOSCount]
392 mov dx,54925 ; Number of microseconds each
393 ; BIOS count represents.
394 mul dx
395 mov bx,ax ; set aside BIOS count in
396 mov cx,dx ; microseconds
397
398 ; Convert timer count to microseconds
399
400 push _si
401 mov ax,[EndTimedCount]
402 mov si,8381
403 mul si
404 mov si,10000
405 div si ; * 0.8381 = * 8381 / 10000
406 pop _si
407
408 ; Add the timer and BIOS counts together to get an overall time in
409 ; microseconds.
410
411 add ax,bx
412 adc cx,0
413 ifdef flatmodel
414 shl ecx,16
415 mov cx,ax
416 mov eax,ecx ; EAX := timer count
417 else
418 mov dx,cx
419 endif
420
421 @@Done: pop ebx ; Restore EBX for 32 bit code
422 ret
423
424 cprocend
425
426 cprocstart LZ_disable
427 cli
428 ret
429 cprocend
430
431 cprocstart LZ_enable
432 sti
433 ret
434 cprocend
435
436 endcodeseg _lztimer
437
438 END