summaryrefslogtreecommitdiff
path: root/fpcsrc/packages/numlib/src/timer.pas
blob: 9a2c1ea5238de499cb6d1e50907a5f8f4a0701a4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
unit timer;

{ NOT PORTED YET, BUT NOT USED BY OTHER LIBS/AND OR DLL AND MOST DEMOES}


{$r-,s-}

INTERFACE

var
  timeractive: boolean;
  exacttime, mstime: longint;

function timervalue: longint;          {Return time in 10 usec units}
function mstimer: longint;             {Return time in ms}

IMPLEMENTATION

uses dos, crt;

var
  lowbyte, highbyte, ref: word;
  timerid: integer;
  saveint, exitsave: pointer;

function inport(x: integer): byte;     {Read i/o port}
  inline($5a/$eb/$00/$ec);

{$F+}
procedure clock(p: pointer); interrupt;
{$F-}
  {Interrupt service routine to update timer reference values}

  const
    incr = 5493;                       {Timer increment per interrupt}

  begin
    port[$43] := $00;                  {Latch timer 0}
    lowbyte := inport($40);
    highbyte := inport($40);
    ref := (highbyte shl 8) + lowbyte; {Base for subsequent readings
                                          within current clock interval}
    exacttime := exacttime + incr;     {New 10 usec timer value}
    mstime := mstime + 55;             {New ms timer value}
    inline($9c/$ff/$1e/saveint);       {Chain to old interrupt}
  end;

function timervalue: longint;

  {Get value of 10-usec timer}

  var
    dif, low, high: word;
    t: longint;

  begin
    inline($fa);                         {Disable interrupts}
    port[$43] := $00;                    {Latch timer}
    low := inport($40);                  {Timer LSB}
    high := inport($40);                 {MSB}
    dif := ref - ((high shl 8) + low);   {Delta from last sync}
    timervalue := exacttime + (longint(dif)*100 div 1193);
    inline($fb);                         {Re-enable interrupts}
  end;

function mstimer: longint;

  {Get value of millisecond timer}

  var
    dif, low, high: word;
    t: longint;

  begin
    inline($fa);
    port[$43] := $00;
    low := inport($40);
    high := inport($40);
    inline($fb);
    dif := ref - ((high shl 8) + low);
    mstimer := mstime + (dif div 1193);
  end;

procedure inittimer;

  begin
    exacttime := 0;
    mstime := 0;
    if not timeractive then
      begin
        port[$43] := $34;   {Mode 2 - countdown
                             (approx .84 microsecond ticks)}
        port[$40] := $ff;   {Initialize timer value}
        port[$40] := $ff;
        getintvec(8, saveint);         {Save old interrupt address}
        setintvec(8, @clock);          {Install new service routine}
        timeractive := true;
        delay(60);                     {Allow for first tick}
      end;
  end;

{$f+} procedure myexit; {$f-}

  {Assure timer interrupt restored before exit}

  begin
    if timeractive then
      setintvec(8, saveint);
    exitproc := exitsave;             {Restore TP exit chain}
  end;

begin  {unit initialization}
  timeractive := false;
  exitsave := exitproc;               {Insert exit routine}
  exitproc := @myexit;
  InitTimer
end.