[Back to TIMING SWAG index] [Back to Main SWAG index] [Original]

    {$S-,R-,I-,V-,B-}

    {*********************************************************}
    {*                   TPTIMER.PAS 2.00                    *}
    {*                by TurboPower Software                 *}
    {*********************************************************}

    Unit TpTimer;
      {-Allows events to be timed With 1 microsecond resolution}

    Interface
    Const
      TimerResolution = 1193181.667;
    Procedure InitializeTimer;
      {-ReProgram the timer chip to allow 1 microsecond resolution}

    Procedure RestoreTimer;
      {-Restore the timer chip to its normal state}

    Function ReadTimer : LongInt;
      {-Read the timer With 1 microsecond resolution}

    Function ElapsedTime(Start, Stop : LongInt) : Real;
      {-Calculate time elapsed (in milliseconds) between Start and Stop}

    Function ElapsedTimeString(Start, Stop : LongInt) : String;
      {-Return time elapsed (in milliseconds) between Start and Stop as a String}

      {==========================================================================}

    Implementation

    Var
      SaveExitProc : Pointer;
      Delta : LongInt;

      Function Cardinal(L : LongInt) : Real;
        {-Return the unsigned equivalent of L as a Real}
      begin                      {Cardinal}
        if L < 0 then
          Cardinal := 4294967296.0+L
        else
          Cardinal := L;
      end;                       {Cardinal}

      Function ElapsedTime(Start, Stop : LongInt) : Real;
        {-Calculate time elapsed (in milliseconds) between Start and Stop}
      begin                      {ElapsedTime}
        ElapsedTime := 1000.0*Cardinal(Stop-(Start+Delta))/TimerResolution;
      end;                       {ElapsedTime}

      Function ElapsedTimeString(Start, Stop : LongInt) : String;
        {-Return time elapsed (in milliseconds) between Start and Stop as a String}
      Var
        R : Real;
        S : String;
      begin                      {ElapsedTimeString}
        R := ElapsedTime(Start, Stop);
        Str(R:0:3, S);
        ElapsedTimeString := S;
      end;                       {ElapsedTimeString}

      Procedure InitializeTimer;
        {-ReProgram the timer chip to allow 1 microsecond resolution}
      begin                      {InitializeTimer}
        {select timer mode 2, read/Write channel 0}
        Port[$43] := $34;        {00110100b}
        Inline($EB/$00);         {jmp short $+2 ;Delay}
        Port[$40] := $00;        {LSB = 0}
        Inline($EB/$00);         {jmp short $+2 ;Delay}
        Port[$40] := $00;        {MSB = 0}
      end;                       {InitializeTimer}

      Procedure RestoreTimer;
        {-Restore the timer chip to its normal state}
      begin                      {RestoreTimer}
        {select timer mode 3, read/Write channel 0}
        Port[$43] := $36;        {00110110b}
        Inline($EB/$00);         {jmp short $+2 ;Delay}
        Port[$40] := $00;        {LSB = 0}
        Inline($EB/$00);         {jmp short $+2 ;Delay}
        Port[$40] := $00;        {MSB = 0}
      end;                       {RestoreTimer}

      Function ReadTimer : LongInt;
        {-Read the timer With 1 microsecond resolution}
      begin                      {ReadTimer}
        Inline(
          $FA/                   {cli             ;Disable interrupts}
          $BA/$20/$00/           {mov  dx,$20     ;Address PIC ocw3}
          $B0/$0A/               {mov  al,$0A     ;Ask to read irr}
          $EE/                   {out  dx,al}
          $B0/$00/               {mov  al,$00     ;Latch timer 0}
          $E6/$43/               {out  $43,al}
          $EC/                   {in   al,dx      ;Read irr}
          $89/$C7/               {mov  di,ax      ;Save it in DI}
          $E4/$40/               {in   al,$40     ;Counter --> bx}
          $88/$C3/               {mov  bl,al      ;LSB in BL}
          $E4/$40/               {in   al,$40}
          $88/$C7/               {mov  bh,al      ;MSB in BH}
          $F7/$D3/               {not  bx         ;Need ascending counter}
          $E4/$21/               {in   al,$21     ;Read PIC imr}
          $89/$C6/               {mov  si,ax      ;Save it in SI}
          $B0/$FF/               {mov  al,$0FF    ;Mask all interrupts}
          $E6/$21/               {out  $21,al}
          $B8/$40/$00/           {mov  ax,$40     ;read low Word of time}
          $8E/$C0/               {mov  es,ax      ;from BIOS data area}
          $26/$8B/$16/$6C/$00/   {mov  dx,es:[$6C]}
          $89/$F0/               {mov  ax,si      ;Restore imr from SI}
          $E6/$21/               {out  $21,al}
          $FB/                   {sti             ;Enable interrupts}
          $89/$F8/               {mov  ax,di      ;Retrieve old irr}
          $A8/$01/               {test al,$01     ;Counter hit 0?}
          $74/$07/               {jz   done       ;Jump if not}
          $81/$FB/$FF/$00/       {cmp  bx,$FF     ;Counter > $FF?}
          $77/$01/               {ja   done       ;Done if so}
          $42/                   {inc  dx         ;else count int req.}
          {done:}
          $89/$5E/$FC/           {mov [bp-4],bx   ;set Function result}
          $89/$56/$FE);          {mov [bp-2],dx}
      end;                       {ReadTimer}

      Procedure Calibrate;
        {-Calibrate the timer}
      Const
        Reps = 1000;
      Var
        I : Word;
        L1, L2, Diff : LongInt;
      begin                      {Calibrate}
        Delta := MaxInt;
        For I := 1 to Reps do begin
          L1 := ReadTimer;
          L2 := ReadTimer;
          {use the minimum difference}
          Diff := L2-L1;
          if Diff < Delta then
            Delta := Diff;
        end;
      end;                       {Calibrate}

      {$F+}
      Procedure OurExitProc;
        {-Restore timer chip to its original state}
      begin                      {OurExitProc}
        ExitProc := SaveExitProc;
        RestoreTimer;
      end;                       {OurExitProc}
      {$F-}

    begin
      {set up our Exit handler}
      SaveExitProc := ExitProc;
      ExitProc := @OurExitProc;

      {reProgram the timer chip}
      InitializeTimer;

      {adjust For speed of machine}
      Calibrate;
    end.

[Back to TIMING SWAG index] [Back to Main SWAG index] [Original]