]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/MAI/bios_emulator/scitech/src/pm/ztimer.c
* Patch by Thomas Frieden, 13 Nov 2002:
[karo-tx-uboot.git] / board / MAI / bios_emulator / scitech / src / pm / ztimer.c
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:     ANSI C
25 * Environment:  Any
26 *
27 * Description:  Module to implement high precision timing on each OS.
28 *
29 ****************************************************************************/
30
31 #include "ztimer.h"
32 #include "pmapi.h"
33 #include "oshdr.h"
34
35 /*---------------------------- Global variables ---------------------------*/
36
37 static LZTimerObject    LZTimer;
38 static ulong            start,finish;
39 #ifdef  __INTEL__
40 static long             cpuSpeed = -1;
41 static ibool            haveRDTSC = false;
42 #endif
43
44 /*----------------------------- Implementation ----------------------------*/
45
46 /* External Intel assembler functions */
47 #ifdef  __INTEL__
48 /* {secret} */
49 void  _ASMAPI _CPU_readTimeStamp(CPU_largeInteger *time);
50 /* {secret} */
51 ulong _ASMAPI _CPU_diffTime64(CPU_largeInteger *t1,CPU_largeInteger *t2,CPU_largeInteger *t);
52 /* {secret} */
53 ulong _ASMAPI _CPU_calcMicroSec(CPU_largeInteger *count,ulong freq);
54 #endif
55
56 #if     defined(__SMX32__)
57 #include "smx/ztimer.c"
58 #elif   defined(__RTTARGET__)
59 #include "rttarget/ztimer.c"
60 #elif   defined(__REALDOS__)
61 #include "dos/ztimer.c"
62 #elif   defined(__NT_DRIVER__)
63 #include "ntdrv/ztimer.c"
64 #elif   defined(__WIN32_VXD__)
65 #include "vxd/ztimer.c"
66 #elif   defined(__WINDOWS32__)
67 #include "win32/ztimer.c"
68 #elif   defined(__OS2_VDD__)
69 #include "vdd/ztimer.c"
70 #elif   defined(__OS2__)
71 #include "os2/ztimer.c"
72 #elif   defined(__LINUX__)
73 #include "linux/ztimer.c"
74 #elif   defined(__QNX__)
75 #include "qnx/ztimer.c"
76 #elif   defined(__BEOS__)
77 #include "beos/ztimer.c"
78 #else
79 #error  Timer library not ported to this platform yet!
80 #endif
81
82 /*------------------------ Public interface routines ----------------------*/
83
84 /****************************************************************************
85 DESCRIPTION:
86 Initializes the Zen Timer library (extended)
87
88 PARAMETERS:
89 accurate    - True of the speed should be measured accurately
90
91 HEADER:
92 ztimer.h
93
94 REMARKS:
95 This function initializes the Zen Timer library, and /must/ be called before
96 any of the remaining Zen Timer library functions are called. The accurate
97 parameter is used to determine whether highly accurate timing should be
98 used or not. If high accuracy is needed, more time is spent profiling the
99 actual speed of the CPU so that we can obtain highly accurate timing
100 results, but the time spent in the initialisation routine will be
101 significantly longer (on the order of 5 seconds).
102 ****************************************************************************/
103 void ZAPI ZTimerInitExt(
104     ibool accurate)
105 {
106     if (cpuSpeed == -1) {
107         __ZTimerInit();
108 #ifdef  __INTEL__
109         cpuSpeed = CPU_getProcessorSpeedInHZ(accurate);
110         haveRDTSC = CPU_haveRDTSC() && (cpuSpeed > 0);
111 #endif
112         }
113 }
114
115 /****************************************************************************
116 DESCRIPTION:
117 Initializes the Zen Timer library.
118
119 HEADER:
120 ztimer.h
121
122 REMARKS:
123 This function initializes the Zen Timer library, and /must/ be called before
124 any of the remaining Zen Timer library functions are called.
125 ****************************************************************************/
126 void ZAPI ZTimerInit(void)
127 {
128     ZTimerInitExt(false);
129 }
130
131 /****************************************************************************
132 DESCRIPTION:
133 Starts the Long Period Zen Timer counting.
134
135 HEADER:
136 ztimer.h
137
138 PARAMETERS:
139 tm  - Timer object to start timing with
140
141 REMARKS:
142 Starts the Long Period Zen Timer counting. Once you have started the timer,
143 you can stop it with LZTimerOff or you can latch the current count with
144 LZTimerLap.
145
146 The Long Period Zen Timer uses a number of different high precision timing
147 mechanisms to obtain microsecond accurate timings results whenever possible.
148 The following different techniques are used depending on the operating
149 system, runtime environment and CPU on the target machine. If the target
150 system has a Pentium CPU installed which supports the Read Time Stamp
151 Counter instruction (RDTSC), the Zen Timer library will use this to
152 obtain the maximum timing precision available.
153
154 Under 32-bit Windows, if the Pentium RDTSC instruction is not available, we
155 first try to use the Win32 QueryPerformanceCounter API, and if that is not
156 available we fall back on the timeGetTime API which is always supported.
157
158 Under 32-bit DOS, if the Pentium RDTSC instruction is not available, we
159 then do all timing using the old style 8253 timer chip. The 8253 timer
160 routines provide highly accurate timings results in pure DOS mode, however
161 in a DOS box under Windows or other Operating Systems the virtualization
162 of the timer can produce inaccurate results.
163
164 Note: Because the Long Period Zen Timer stores the results in a 32-bit
165       unsigned integer, you can only time periods of up to 2^32 microseconds,
166       or about 1hr 20mins. For timing longer periods use the Ultra Long
167       Period Zen Timer.
168
169 SEE ALSO:
170 LZTimerOff, LZTimerLap, LZTimerCount
171 ****************************************************************************/
172 void ZAPI LZTimerOnExt(
173     LZTimerObject *tm)
174 {
175 #ifdef  __INTEL__
176     if (haveRDTSC) {
177         _CPU_readTimeStamp(&tm->start);
178         }
179     else
180 #endif
181         __LZTimerOn(tm);
182 }
183
184 /****************************************************************************
185 DESCRIPTION:
186 Returns the current count for the Long Period Zen Timer and keeps it
187 running.
188
189 HEADER:
190 ztimer.h
191
192 PARAMETERS:
193 tm  - Timer object to do lap timing with
194
195 RETURNS:
196 Count that has elapsed in microseconds.
197
198 REMARKS:
199 Returns the current count that has elapsed since the last call to
200 LZTimerOn in microseconds. The time continues to run after this function is
201 called so you can call this function repeatedly.
202
203 SEE ALSO:
204 LZTimerOn, LZTimerOff, LZTimerCount
205 ****************************************************************************/
206 ulong ZAPI LZTimerLapExt(
207     LZTimerObject *tm)
208 {
209 #ifdef  __INTEL__
210     CPU_largeInteger    tmLap,tmCount;
211
212     if (haveRDTSC) {
213         _CPU_readTimeStamp(&tmLap);
214         _CPU_diffTime64(&tm->start,&tmLap,&tmCount);
215         return _CPU_calcMicroSec(&tmCount,cpuSpeed);
216         }
217     else
218 #endif
219         return __LZTimerLap(tm);
220 }
221
222 /****************************************************************************
223 DESCRIPTION:
224 Stops the Long Period Zen Timer counting.
225
226 HEADER:
227 ztimer.h
228
229 PARAMETERS:
230 tm  - Timer object to stop timing with
231
232 REMARKS:
233 Stops the Long Period Zen Timer counting and latches the count. Once you
234 have stopped the timer you can read the count with LZTimerCount. If you need
235 highly accurate timing, you should use the on and off functions rather than
236 the lap function since the lap function does not subtract the overhead of
237 the function calls from the timed count.
238
239 SEE ALSO:
240 LZTimerOn, LZTimerLap, LZTimerCount
241 ****************************************************************************/
242 void ZAPI LZTimerOffExt(
243     LZTimerObject *tm)
244 {
245 #ifdef  __INTEL__
246     if (haveRDTSC) {
247         _CPU_readTimeStamp(&tm->end);
248         }
249     else
250 #endif
251         __LZTimerOff(tm);
252 }
253
254 /****************************************************************************
255 DESCRIPTION:
256 Returns the current count for the Long Period Zen Timer.
257
258 HEADER:
259 ztimer.h
260
261 PARAMETERS:
262 tm  - Timer object to compute the elapsed time with.
263
264 RETURNS:
265 Count that has elapsed in microseconds.
266
267 REMARKS:
268 Returns the current count that has elapsed between calls to
269 LZTimerOn and LZTimerOff in microseconds.
270
271 SEE ALSO:
272 LZTimerOn, LZTimerOff, LZTimerLap
273 ****************************************************************************/
274 ulong ZAPI LZTimerCountExt(
275     LZTimerObject *tm)
276 {
277 #ifdef  __INTEL__
278     CPU_largeInteger    tmCount;
279
280     if (haveRDTSC) {
281         _CPU_diffTime64(&tm->start,&tm->end,&tmCount);
282         return _CPU_calcMicroSec(&tmCount,cpuSpeed);
283         }
284     else
285 #endif
286         return __LZTimerCount(tm);
287 }
288
289 /****************************************************************************
290 DESCRIPTION:
291 Starts the Long Period Zen Timer counting.
292
293 HEADER:
294 ztimer.h
295
296 REMARKS:
297 Obsolete function. You should use the LZTimerOnExt function instead
298 which allows for multiple timers running at the same time.
299 ****************************************************************************/
300 void ZAPI LZTimerOn(void)
301 { LZTimerOnExt(&LZTimer); }
302
303 /****************************************************************************
304 DESCRIPTION:
305 Returns the current count for the Long Period Zen Timer and keeps it
306 running.
307
308 HEADER:
309 ztimer.h
310
311 RETURNS:
312 Count that has elapsed in microseconds.
313
314 REMARKS:
315 Obsolete function. You should use the LZTimerLapExt function instead
316 which allows for multiple timers running at the same time.
317 ****************************************************************************/
318 ulong ZAPI LZTimerLap(void)
319 { return LZTimerLapExt(&LZTimer); }
320
321 /****************************************************************************
322 DESCRIPTION:
323 Stops the Long Period Zen Timer counting.
324
325 HEADER:
326 ztimer.h
327
328 REMARKS:
329 Obsolete function. You should use the LZTimerOffExt function instead
330 which allows for multiple timers running at the same time.
331 ****************************************************************************/
332 void ZAPI LZTimerOff(void)
333 { LZTimerOffExt(&LZTimer); }
334
335 /****************************************************************************
336 DESCRIPTION:
337 Returns the current count for the Long Period Zen Timer.
338
339 HEADER:
340 ztimer.h
341
342 RETURNS:
343 Count that has elapsed in microseconds.
344
345 REMARKS:
346 Obsolete function. You should use the LZTimerCountExt function instead
347 which allows for multiple timers running at the same time.
348 ****************************************************************************/
349 ulong ZAPI LZTimerCount(void)
350 { return LZTimerCountExt(&LZTimer); }
351
352 /****************************************************************************
353 DESCRIPTION:
354 Starts the Ultra Long Period Zen Timer counting.
355
356 HEADER:
357 ztimer.h
358
359 REMARKS:
360 Starts the Ultra Long Period Zen Timer counting. Once you have started the
361 timer, you can stop it with ULZTimerOff or you can latch the current count
362 with ULZTimerLap.
363
364 The Ultra Long Period Zen Timer uses the available operating system services
365 to obtain accurate timings results with as much precision as the operating
366 system provides, but with enough granularity to time longer periods of
367 time than the Long Period Zen Timer. Note that the resolution of the timer
368 ticks is not constant between different platforms, and you should use the
369 ULZTimerResolution function to determine the number of seconds in a single
370 tick of the timer, and use this to convert the timer counts to seconds.
371
372 Under 32-bit Windows, we use the timeGetTime function which provides a
373 resolution of 1 millisecond (0.001 of a second). Given that the timer
374 count is returned as an unsigned 32-bit integer, this we can time intervals
375 that are a maximum of 2^32 milliseconds in length (or about 1,200 hours or
376 50 days!).
377
378 Under 32-bit DOS, we use the system timer tick which runs at 18.2 times per
379 second. Given that the timer count is returned as an unsigned 32-bit integer,
380 this we can time intervals that are a maximum of 2^32 * (1/18.2) in length
381 (or about 65,550 hours or 2731 days!).
382
383 SEE ALSO:
384 ULZTimerOff, ULZTimerLap, ULZTimerCount, ULZElapsedTime, ULZReadTime
385 ****************************************************************************/
386 void ZAPI ULZTimerOn(void)
387 { start = __ULZReadTime(); }
388
389 /****************************************************************************
390 DESCRIPTION:
391 Returns the current count for the Ultra Long Period Zen Timer and keeps it
392 running.
393
394 HEADER:
395 ztimer.h
396
397 RETURNS:
398 Count that has elapsed in resolution counts.
399
400 REMARKS:
401 Returns the current count that has elapsed since the last call to
402 ULZTimerOn in microseconds. The time continues to run after this function is
403 called so you can call this function repeatedly.
404
405 SEE ALSO:
406 ULZTimerOn, ULZTimerOff, ULZTimerCount
407 ****************************************************************************/
408 ulong ZAPI ULZTimerLap(void)
409 { return (__ULZReadTime() - start); }
410
411 /****************************************************************************
412 DESCRIPTION:
413 Stops the Long Period Zen Timer counting.
414
415 HEADER:
416 ztimer.h
417
418 REMARKS:
419 Stops the Ultra Long Period Zen Timer counting and latches the count. Once
420 you have stopped the timer you can read the count with ULZTimerCount.
421
422 SEE ALSO:
423 ULZTimerOn, ULZTimerLap, ULZTimerCount
424 ****************************************************************************/
425 void ZAPI ULZTimerOff(void)
426 { finish = __ULZReadTime(); }
427
428 /****************************************************************************
429 DESCRIPTION:
430 Returns the current count for the Ultra Long Period Zen Timer.
431
432 HEADER:
433 ztimer.h
434
435 RETURNS:
436 Count that has elapsed in resolution counts.
437
438 REMARKS:
439 Returns the current count that has elapsed between calls to
440 ULZTimerOn and ULZTimerOff in resolution counts.
441
442 SEE ALSO:
443 ULZTimerOn, ULZTimerOff, ULZTimerLap, ULZTimerResolution
444 ****************************************************************************/
445 ulong ZAPI ULZTimerCount(void)
446 { return (finish - start); }
447
448 /****************************************************************************
449 DESCRIPTION:
450 Reads the current time from the Ultra Long Period Zen Timer.
451
452 HEADER:
453 ztimer.h
454
455 RETURNS:
456 Current timer value in resolution counts.
457
458 REMARKS:
459 Reads the current Ultra Long Period Zen Timer and returns it\92s current
460 count. You can use the ULZElapsedTime function to find the elapsed time
461 between two timer count readings.
462
463 SEE ALSO:
464 ULZElapsedTime, ULZTimerResolution
465 ****************************************************************************/
466 ulong ZAPI ULZReadTime(void)
467 { return __ULZReadTime(); }
468
469 /****************************************************************************
470 DESCRIPTION:
471 Compute the elapsed time between two timer counts.
472
473 HEADER:
474 ztimer.h
475
476 PARAMETERS:
477 start   - Starting time for elapsed count
478 finish  - Ending time for elapsed count
479
480 RETURNS:
481 Elapsed timer in resolution counts.
482
483 REMARKS:
484 Returns the elapsed time for the Ultra Long Period Zen Timer in units of the
485 timers resolution (1/18th of a second under DOS). This function correctly
486 computes the difference even if a midnight boundary has been crossed
487 during the timing period.
488
489 SEE ALSO:
490 ULZReadTime, ULZTimerResolution
491 ****************************************************************************/
492 ulong ZAPI ULZElapsedTime(
493     ulong start,
494     ulong finish)
495 { return __ULZElapsedTime(start,finish); }
496
497 /****************************************************************************
498 DESCRIPTION:
499 Returns the resolution of the Ultra Long Period Zen Timer.
500
501 HEADER:
502 ztimer.h
503
504 PARAMETERS:
505 resolution   - Place to store the timer in microseconds per timer count.
506
507 REMARKS:
508 Returns the resolution of the Ultra Long Period Zen Timer as a 32-bit
509 integer value measured in microseconds per timer count.
510
511 SEE ALSO:
512 ULZReadTime, ULZElapsedTime, ULZTimerCount
513 ****************************************************************************/
514 void ZAPI ULZTimerResolution(
515         ulong *resolution)
516 { *resolution = ULZTIMER_RESOLUTION; }
517