home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR9 / QWIK71A.ZIP / TIMER24.PAS < prev   
Pascal/Delphi Source File  |  1993-09-23  |  6KB  |  196 lines

  1. { ========================================================================== }
  2. { Timer24.pas - High-resolution timer                     ver 7.1a, 09-23-93 }
  3. {                                                                            }
  4. { A precise 24 hour timer with resolution of 1 micro-second to measure       }
  5. { elapsed time in seconds.                                                   }
  6. {                                                                            }
  7. { Can be used in DOS or Windows.  It will only perform adequately in Windows }
  8. { standard mode.                                                             }
  9. {                                                                            }
  10. {  Copyright (C) 1992,1993 James H. LeMay for Eagle Performance Software     }
  11. { ========================================================================== }
  12.  
  13. {$A+,F-,R-,S- }
  14.  
  15. UNIT Timer24;
  16.  
  17.  
  18. INTERFACE
  19.  
  20. type
  21.   StartStop = (Start, Stop, Sync);
  22.  
  23. var
  24.   ElapsedTime: real;  { Time between last start and last stop. (seconds) }
  25.  
  26. procedure Timer (SS: StartStop);
  27. procedure WaitForTick;
  28.  
  29.  
  30. IMPLEMENTATION
  31.  
  32. {$ifdef Windows }
  33. uses
  34.   WinProcs, WinTypes;
  35. {$endif }
  36.  
  37. type
  38.   TicksArray = array [1..5] of byte;
  39.  
  40. var
  41.   PrevExitProc:    pointer;
  42.   T1array,T2array: TicksArray;
  43.   t0,              { Timer overhead     (ticks) }
  44.   t1,              { Time at last Start (ticks) }
  45.   t2: real;        { Time at last Stop  (ticks) }
  46.   LowClock: word absolute $0040:$006C;
  47.  
  48. const
  49.   TicksPerDay = 103090749440.0;        { 2^16 * 1573040 DOS timer ticks/day. }
  50.   TicksPerSec = TicksPerDay/86400.0;
  51.  
  52. procedure SetTimerMode; assembler;
  53.   asm
  54.     mov   al,$34    { For counter 0, mode 2 }
  55.     out   $43,al    { Set timer for input   }
  56.     jmp   @1        { Null jump             }
  57. @1: xor   ax,ax     { Set ax=0 (Max count)  }
  58.     out   $40,al    { LSB first             }
  59.     jmp   @2        { Null jump             }
  60. @2: out   $40,al    { MSB second            }
  61. end;
  62.  
  63. procedure GetTicks (VAR Ticks: TicksArray);
  64. begin
  65.   asm
  66.     mov   dx,$40         { Data port for timer }
  67.     mov   es,dx          { Segment for DOS timer }
  68.     mov   al,dh          { 0 to latch counter 0 }
  69.  
  70.     cli                  { Prevent interrupts }
  71.     seges mov bl,[$006C] { Low byte of system timer }
  72.     seges mov si,[$006D] { Mid word of system timer }
  73.  
  74.     out   $43,al         { Latch timer }
  75.     jmp   @0             { Null jump }
  76. @0: in    al,dx          { Timer chip LSB }
  77.     jmp   @1             { Null jump }
  78. @1: mov   cl,al          { Save in CL }
  79.     in    al,dx          { Timer chip MSB }
  80.     sti                  { Enable interrupts AFTER MOV }
  81.                          {   Interrupts not enabled yet in DOS }
  82.                          {   Interrupts enabled in Windows }
  83.     mov   ax,ax          { Fast NOP }
  84.                          {   Now interrupts enabled in DOS }
  85.                          { Let system clock be updated now }
  86.     seges mov bh,[$006C] { Again copy of the Low byte }
  87.     mov   ch,al          { Move in CH }
  88.     not   cx             { Convert count-down to up }
  89.  
  90.     cmp   ch,10          { Time since system tick <2560 ticks? }
  91.     adc   dh,dh          { Save copy of CF }
  92.     sub   bh,bl          { BH=1 if before<>after }
  93.     and   dh,bh          { DH=1 if pending tick INT }
  94.     add   bl,dh          { Inc if INT was pending }
  95.     adc   si,$0000       { Just propogate carry bit }
  96.  
  97.     les   di,Ticks       { Load address of ticks }
  98.     mov   es:[di],cx     { Store chip timer word }
  99.     mov   es:[di+2],bl   { Store system low byte }
  100.     mov   es:[di+3],si   { Store system mid word }
  101.   end;
  102. end;
  103.  
  104. function ArrayToReal (Ticks: TicksArray): real;
  105. var
  106.   T: record
  107.       B: byte;
  108.       L: longint;
  109.      end absolute Ticks;
  110. begin
  111.   ArrayToReal := (T.L)*256.0 + T.B;
  112. end;
  113.  
  114. procedure Timer;
  115. begin
  116.   case SS of
  117.     Stop:  begin
  118.              GetTicks (T2array);
  119.              t1 := ArrayToReal (T1array);        { Convert AFTER the event! }
  120.              t2 := ArrayToReal (T2array);
  121.              if t2<t1 then
  122.                t2 := t2+TicksPerDay;
  123.              ElapsedTime := (t2-t1-t0)/TicksPerSec   { units of seconds }
  124.            end;
  125.     Start: begin
  126.              ElapsedTime := 0;
  127.              GetTicks (T1array)
  128.            end;
  129.     Sync:  begin
  130.              ElapsedTime := 0;
  131.              SetTimerMode;
  132.              GetTicks (T1array)
  133.            end;
  134.   end;
  135. end;
  136.  
  137. procedure WaitForTick;
  138. var Tick: real;
  139. begin
  140.   Tick := LowClock;
  141.   repeat
  142.   until LowClock<>Tick;
  143. end;
  144.  
  145. procedure TimerInit;
  146. var
  147.   least: real;
  148.   b:     byte;
  149. begin
  150.   t0    := 0.0;                        { Initial value to prevent overflow }
  151.   least := 1000000.0;                  { Initial value that's too high }
  152.   WaitForTick;
  153.   for b:=1 to 5 do
  154.     begin                              { Check timer overhead by timing }
  155.       Timer (Start);                   { itself.  Do it 5 times to get the }
  156.       Timer (Stop);                    { least value.  }
  157.       t0 := ArrayToReal(T2array) - ArrayToReal(T1array);
  158.       if t0<least then
  159.         least:=t0;
  160.     end;
  161.   t0 := least;                         { Minimum overhead for timer }
  162. end;
  163.  
  164. {$F+}
  165. procedure ExitTimer24;
  166. begin
  167.   ExitProc := PrevExitProc;
  168.   { -- Restore default timer mode -- }
  169.   asm
  170.     mov   al,$36     { For counter 0, mode 3 }
  171.     out   $43,al     { Set timer for input   }
  172.     jmp   @1         { Null jump             }
  173. @1: xor   ax,ax      { Set ax=0 (Max count)  }
  174.     out   $40,al     { LSB first             }
  175.     jmp   @2         { Null jump             }
  176. @2: out   $40,al     { MSB second            }
  177.   end;
  178. end;
  179. {$F-}
  180.  
  181. BEGIN
  182.    {$ifdef Windows }
  183.   if (GetWinFlags and wf_Standard)=0 then
  184.     begin
  185.       MessageBox (0,'Must run Timer24 unit in standard mode',nil,
  186.                   mb_OK+mb_TaskModal);
  187.       Halt(1);
  188.     end;
  189.    {$endif }
  190.  
  191.   PrevExitProc := ExitProc;
  192.   ExitProc     := @ExitTimer24;
  193.   SetTimerMode;
  194.   TimerInit;
  195. END.
  196.