Unit QwkTimer;

{
 *********************************************************************
 **                                                                 **
 ** Author....: Chris Wood                                          **
 ** Date......: 7-11-1992                                           **
 ** Internet..: woodc@jacobs.cs.orst.edu                            **
 ** BBS.......: A Separate Reality (503)926-6991                    **
 **             (Leave mail to the sysop)                           **
 **                                                                 **
 **   This source code is being released as Free-Ware.  You may use **
 ** this code in your programs and modify it to fit your needs. The **
 ** only  restrictions are that you  may not distribute the  source **
 ** code in modified form or charge for the source code itself.  If **
 ** you  discover any  errors  in the  source code  or find a  more **
 ** efficient way to handle any of the following code, please leave **
 ** me e-mail at the internet address or the BBS listed above.  All **
 ** comments are welcome.                                           **
 **                                                                 **
 *********************************************************************
}

Interface

uses
  crt, dos;

Var ClockTicks : LongInt;  { Number of ticks elapsed }

Procedure TimerOn ( Freq : LongInt );
Procedure TimerOff;
Procedure ResetTimer;
Function TimeElapsed : Real;

Implementation

Const MaxRate = 1193180;

Var OldInt08        : procedure;
    OldInt1C        : procedure;
    IntCount08      : Word;
    Trigger         : Word;
    TimerAlreadySet : Boolean;
    Frequency       : Word;

Procedure IrqOn; Inline($FB);

Procedure IrqOff; Inline($FA);

{$F+}
Procedure NewInt1C; Interrupt;
Begin
  Inc(ClockTicks);
End;
{$F-}

{$F+}
Procedure NewInt08; Interrupt;
Begin
  IrqOff;
  Inline($CD/$1C); {Generate INT 1Ch instruction to call interrupt 1Ch}
  If IntCount08=Trigger then
  Begin
    IntCount08:=0;
    Inline($9C);
    OldInt08;
  End
    Else
  Begin
    Inc(IntCount08);
  End;
  Port[$20]:=$20; {Sends non-specific EOI to the PIC}
  IrqOn;
End;
{$F-}

Procedure TimerOn ( Freq : LongInt );
Var Temp  : LongInt;
    Count : Word;
Begin
  If Not(TimerAlreadySet) then
  Begin
    ClockTicks:=0;
    IntCount08:=0;
    Frequency:=Freq;
    Trigger:=Trunc(Freq/18.2);
    Temp:=MaxRate;
    Temp:=Trunc(Temp/Freq);
    Count:=Temp;
    GetIntVec($08,@OldInt08);
    SetIntVec($08,Addr(NewInt08));
    GetIntVec($1C,@OldInt1C);
    SetIntVec($1C,Addr(NewInt1C));
    Port[$43]:=$B6;
    Port[$40]:=Lo(Count);
    Port[$40]:=Hi(Count);
    TimerAlreadySet:=True;
  End;
End;

Procedure TimerOff;
Begin
  If TimerAlreadySet then
  Begin
    Port[$43]:=$B6;
    Port[$40]:=$FF;
    Port[$40]:=$FF;
    SetIntVec($08,@OldInt08);
    SetIntvec($1C,@OldInt1C);
    TimerAlreadySet:=False;
  End;
End;

Procedure ResetTimer;
Begin
  ClockTicks:=0;
End;

Function TimeElapsed : Real;
Begin
  TimeElapsed:=ClockTicks/Frequency;
End;

Begin
  TimerAlreadySet:=False;
End.
