home *** CD-ROM | disk | FTP | other *** search
/ RBBS in a Box Volume 1 #3.1 / RBBSIABOX31.cdr / mlpc / micrtm.inc < prev    next >
Encoding:
Text File  |  1990-09-29  |  6.4 KB  |  173 lines

  1. {----------------------------------------------------------------------------}
  2. {                                                                            }
  3. {                                TIMER.INC                                   }
  4. {                     for IBM PC* and close compatibles                      }
  5. {                                                                            }
  6. {                              copyright 1987                                }
  7. {                            by Peter J. Becker                              }
  8. {                            all rights reserved                             }
  9. {                                                                            }
  10. {     These routines may be used for private, non-commercial purposes and    }
  11. { may be distributed unchanged for said purposes.  Any other use or distri-  }
  12. { bution is expressly forbidden.                                             }
  13. {                                                                            }
  14. {----------------------------------------------------------------------------}
  15.  
  16. {                               USAGE NOTES
  17.  
  18.    1. These routines work only on the IBM PC, PC/XT, PC/AT, and close
  19. compatibles.  This is because the routines directly access system hardware.
  20. If your machine won't run the PC version of Turbo Pascal, you probably can't
  21. use these routines.
  22.  
  23.    2. The timer must be calibrated before running it.  To do this, your
  24. program must call the procedure 'Calibrate' at least once before the first
  25. call to StartTimer.
  26.  
  27.    3. To use the timer, simply surround the code to be timed with calls to
  28. StartTimer and StopTimer, just as if you were using a stopwatch.  For example:
  29.  
  30.    StartTimer;
  31.    delay(30000);
  32.    StopTimer(Time);
  33.    writeln( 'Elapsed time: ', Time:10:6 );
  34.  
  35. will display the actual delay produced by 'delay(30000)'.  This may not be
  36. exactly the value you expect, so compare the time given by the timer with the
  37. time given by a stopwatch.
  38.  
  39.    4. StopTimer takes an argument of type real, and it sets this argument to
  40. the time, in seconds, since the last call to StartTimer.
  41.  
  42.    5. The clock counter has a period of ~838 nanoseconds.  At the moment,
  43. however, there is a little jitter in the timing, so measured times are only
  44. accurate to within about 3 microseconds.  So, don't try to measure anything
  45. shorter than about 30 microseconds if you want any degree of accuracy.
  46.  
  47.    6. Any timing interval that begins before midnight and ends after midnight
  48. will give strange results.
  49.  
  50.    7. Questions, comments, or suggestions should be forwarded to me on
  51. CompuServe, User ID 76347,3151.
  52.  
  53. * IBM is a registered trademark and PC, PC/XT, and PC/AT are trademarks of
  54. International Business Machines Corporation.
  55.  
  56. * Turbo Pascal is a registered trademark of Borland International.
  57. }
  58.  
  59. type
  60.   doubleword = record
  61.                  Lo : integer;
  62.                  Hi : integer;
  63.                end;
  64.  
  65. const
  66.   Time_per_Count = 0.838097E-6;  { count rate of hardware timer }
  67.  
  68.   Adjust      : integer = 0;     { Adjustment for timer overhead }
  69.  
  70. var
  71.   DOS_Time   : doubleword absolute $0040:$006C; { System master clock count }
  72.   Start_Time : doubleword;                      { used to hold starting time }
  73.  
  74. function IntReal( Num : integer ) : real;
  75.   { converts an unsigned integer to a real number }
  76. begin
  77.   if Num < 0 then
  78.      IntReal := 65536. + Num
  79.   else
  80.      IntReal := Num;
  81. end; { function IntReal( Num : integer )  }
  82.  
  83. function DoubleReal( Num : doubleword ) : real ;
  84.   { converts an unsigned double word to a real number }
  85. begin
  86.   DoubleReal := 65536.*IntReal( Num.Hi ) + IntReal( Num.Lo );
  87. end; { function DoubleReal( Num : doubleword ) }
  88.  
  89. procedure StartTimer;
  90.   { set clock timer for pulse output and reset it, then }
  91.   { save system time in Start_Ticks                     }
  92. begin
  93.   Inline(
  94.     $B0/$34                {mov al,$34        ; counter 0, LSB then MSB, mode 2, binary}
  95.     /$E6/$43               {out $43, al       ; set mode}
  96.     /$29/$C0               {sub ax,ax         ; will set timer registers to 0 for max count}
  97.     /$E6/$40               {out $40,al        ; LSB first}
  98.     /$E6/$40               {out $40,al        ; MSB next}
  99.   );
  100.  
  101.   Start_Time.Lo := DOS_Time.Lo;
  102.   Start_Time.Hi := DOS_Time.Hi;
  103.  
  104. end; { procedure StartTimer }
  105.  
  106. procedure GetTime( var Count : integer; var Time : doubleword );
  107.   { return value of clock timer in Count and system time in Time }
  108. begin
  109.   Inline(
  110.     $B0/$00                {mov al,$00        ; latch counter}
  111.     /$E6/$43               {out $43,al}
  112.     /$E4/$40               {in  al,$40        ; read lo byte}
  113.     /$88/$C2               {mov dl,al         ; save it}
  114.     /$E4/$40               {in  al,$40        ; read hi byte}
  115.     /$88/$C6               {mov dh,al         ; save it}
  116.     /$1E                   {push ds           ; save value of data segment}
  117.     /$C5/$B6/>COUNT        {lds si,[bp+>Count]; get address of variable 'Count'}
  118.     /$89/$14               {mov [si],dx       ; store count}
  119.     /$1F                   {pop ds            ; restore data segment}
  120.     );
  121.  
  122.   Time.Lo := DOS_Time.Lo;
  123.   Time.Hi := DOS_Time.Hi;
  124.  
  125. end; { procedure GetTime( var Counter : integer; var Time : doubleword ) }
  126.  
  127. procedure StopTimer( var Time : real );
  128.   { get current system time and count from clock timer, convert to seconds }
  129. var
  130.   Count      : integer;
  131.   Stop_Time  : doubleword;
  132. begin
  133.   GetTime( Count, Stop_Time );
  134.   Time := Time_per_Count*((65536. - IntReal( Count) - Adjust)
  135.           + 65536.*( DoubleReal( Stop_Time ) - DoubleReal( Start_Time ) ));
  136. end; { procedure StopTimer }
  137.  
  138. procedure Calibrate;
  139.   { get the average number of counts for 10 empty measurements and   }
  140.   { store it in Adjust so that it can be subtracted from subsequent  }
  141.   { measurements                                                     }
  142. var
  143.   I, Sum : integer;
  144.   Time   : real;
  145. begin
  146.   Adjust := 0;
  147.   Sum := 0;
  148.   for I := 1 to 10 do
  149.   begin
  150.     StartTimer;
  151.     StopTimer( Time );
  152.     Sum := Sum + Round( Time / Time_per_Count );
  153.   end;
  154.   Adjust := (Sum + 5) div 10;   { round off }
  155. end; { procedure Calibrate }
  156.  
  157. (* delete this line for demonstration program
  158. var
  159.   del,d1  : integer;
  160.   Time : real;
  161. begin
  162.   Calibrate;
  163.   for del := 0 to 10 do
  164.   begin
  165.     d1 := del*100;
  166.     StartTimer;
  167.     delay(d1);
  168.     StopTimer( Time );
  169.     writeln( d1:4,'ms., actual time = ', Time:10:6, ' sec.' );
  170.   end;
  171. end.
  172. (**)
  173.