home *** CD-ROM | disk | FTP | other *** search
- {----------------------------------------------------------------------------}
- { }
- { TIMER.INC }
- { for IBM PC* and close compatibles }
- { }
- { copyright 1987 }
- { by Peter J. Becker }
- { all rights reserved }
- { }
- { These routines may be used for private, non-commercial purposes and }
- { may be distributed unchanged for said purposes. Any other use or distri- }
- { bution is expressly forbidden. }
- { }
- {----------------------------------------------------------------------------}
-
- { USAGE NOTES
-
- 1. These routines work only on the IBM PC, PC/XT, PC/AT, and close
- compatibles. This is because the routines directly access system hardware.
- If your machine won't run the PC version of Turbo Pascal, you probably can't
- use these routines.
-
- 2. The timer must be calibrated before running it. To do this, your
- program must call the procedure 'Calibrate' at least once before the first
- call to StartTimer.
-
- 3. To use the timer, simply surround the code to be timed with calls to
- StartTimer and StopTimer, just as if you were using a stopwatch. For example:
-
- StartTimer;
- delay(30000);
- StopTimer(Time);
- writeln( 'Elapsed time: ', Time:10:6 );
-
- will display the actual delay produced by 'delay(30000)'. This may not be
- exactly the value you expect, so compare the time given by the timer with the
- time given by a stopwatch.
-
- 4. StopTimer takes an argument of type real, and it sets this argument to
- the time, in seconds, since the last call to StartTimer.
-
- 5. The clock counter has a period of ~838 nanoseconds. At the moment,
- however, there is a little jitter in the timing, so measured times are only
- accurate to within about 3 microseconds. So, don't try to measure anything
- shorter than about 30 microseconds if you want any degree of accuracy.
-
- 6. Any timing interval that begins before midnight and ends after midnight
- will give strange results.
-
- 7. Questions, comments, or suggestions should be forwarded to me on
- CompuServe, User ID 76347,3151.
-
- * IBM is a registered trademark and PC, PC/XT, and PC/AT are trademarks of
- International Business Machines Corporation.
-
- * Turbo Pascal is a registered trademark of Borland International.
- }
-
- type
- doubleword = record
- Lo : integer;
- Hi : integer;
- end;
-
- const
- Time_per_Count = 0.838097E-6; { count rate of hardware timer }
-
- Adjust : integer = 0; { Adjustment for timer overhead }
-
- var
- DOS_Time : doubleword absolute $0040:$006C; { System master clock count }
- Start_Time : doubleword; { used to hold starting time }
-
- function IntReal( Num : integer ) : real;
- { converts an unsigned integer to a real number }
- begin
- if Num < 0 then
- IntReal := 65536. + Num
- else
- IntReal := Num;
- end; { function IntReal( Num : integer ) }
-
- function DoubleReal( Num : doubleword ) : real ;
- { converts an unsigned double word to a real number }
- begin
- DoubleReal := 65536.*IntReal( Num.Hi ) + IntReal( Num.Lo );
- end; { function DoubleReal( Num : doubleword ) }
-
- procedure StartTimer;
- { set clock timer for pulse output and reset it, then }
- { save system time in Start_Ticks }
- begin
- Inline(
- $B0/$34 {mov al,$34 ; counter 0, LSB then MSB, mode 2, binary}
- /$E6/$43 {out $43, al ; set mode}
- /$29/$C0 {sub ax,ax ; will set timer registers to 0 for max count}
- /$E6/$40 {out $40,al ; LSB first}
- /$E6/$40 {out $40,al ; MSB next}
- );
-
- Start_Time.Lo := DOS_Time.Lo;
- Start_Time.Hi := DOS_Time.Hi;
-
- end; { procedure StartTimer }
-
- procedure GetTime( var Count : integer; var Time : doubleword );
- { return value of clock timer in Count and system time in Time }
- begin
- Inline(
- $B0/$00 {mov al,$00 ; latch counter}
- /$E6/$43 {out $43,al}
- /$E4/$40 {in al,$40 ; read lo byte}
- /$88/$C2 {mov dl,al ; save it}
- /$E4/$40 {in al,$40 ; read hi byte}
- /$88/$C6 {mov dh,al ; save it}
- /$1E {push ds ; save value of data segment}
- /$C5/$B6/>COUNT {lds si,[bp+>Count]; get address of variable 'Count'}
- /$89/$14 {mov [si],dx ; store count}
- /$1F {pop ds ; restore data segment}
- );
-
- Time.Lo := DOS_Time.Lo;
- Time.Hi := DOS_Time.Hi;
-
- end; { procedure GetTime( var Counter : integer; var Time : doubleword ) }
-
- procedure StopTimer( var Time : real );
- { get current system time and count from clock timer, convert to seconds }
- var
- Count : integer;
- Stop_Time : doubleword;
- begin
- GetTime( Count, Stop_Time );
- Time := Time_per_Count*((65536. - IntReal( Count) - Adjust)
- + 65536.*( DoubleReal( Stop_Time ) - DoubleReal( Start_Time ) ));
- end; { procedure StopTimer }
-
- procedure Calibrate;
- { get the average number of counts for 10 empty measurements and }
- { store it in Adjust so that it can be subtracted from subsequent }
- { measurements }
- var
- I, Sum : integer;
- Time : real;
- begin
- Adjust := 0;
- Sum := 0;
- for I := 1 to 10 do
- begin
- StartTimer;
- StopTimer( Time );
- Sum := Sum + Round( Time / Time_per_Count );
- end;
- Adjust := (Sum + 5) div 10; { round off }
- end; { procedure Calibrate }
-
- (* delete this line for demonstration program
- var
- del,d1 : integer;
- Time : real;
- begin
- Calibrate;
- for del := 0 to 10 do
- begin
- d1 := del*100;
- StartTimer;
- delay(d1);
- StopTimer( Time );
- writeln( d1:4,'ms., actual time = ', Time:10:6, ' sec.' );
- end;
- end.
- (**)
-