-
Notifications
You must be signed in to change notification settings - Fork 1
/
PIT.PAS
167 lines (120 loc) · 3.66 KB
/
PIT.PAS
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
{$G-,N-,E-}
{**************************************************************
PIT.pas - Handle the PIT (Programmable Interval Time)
Author: Jan Knipperts
Program: TNDY-Tracker
Version: 1.12
***************************************************************
}
unit PIT;
interface
type
TimerType = record
Frequency : Real;
Divider : word;
Clock_counter : Real;
end;
var
Timer : TimerType;
procedure Set_Timer(Hz : Real);
procedure ResetTimer;
Procedure Program_PIT(mode : byte; countdown : word);
procedure DisableTimerIRQ;
procedure EnableTimerIRQ;
implementation
procedure DisableTimerIRQ;
assembler;
asm
in al,21h
or al,1
out 21h,al
end;
procedure EnableTimerIRQ;
assembler;
asm
in al,21h
and al,0feh
out 21h,al
end;
Procedure Program_PIT(mode : byte; countdown : word);
{Mode:
Bit 0 : Counter Format bit (0 = binary counter, 1 decade BCD counter)
Bit 1-3 : Counter Mode bits
Bit 4,5 : read/write/latch format bits
Bit 6,7 : Counter Select Bits
Default: 36h, 00110110
bit 7,6 = (00) timer counter 0
bit 5,4 = (11) write LSB then MSB
bit 3-1 = (011) generate square wave
bit 0 = (0) binary counter
Counter Select Bits
00 select counter 0
01 select counter 1
10 select counter 2
11 read back command (8254 only, illegal on 8253!)
Read/Write/Latch Format Bits
00 latch present counter value
01 read/write of MSB only
10 read/write of LSB only
11 read/write LSB, followed by write of MSB
Counter Mode Bits
000 mode 0, interrupt on terminal count; countdown, interrupt,
then wait for a new mode or count; loading a new count in the
middle of a count stops the countdown
001 mode 1, programmable one-shot; countdown with optional
restart; reloading the counter will not affect the countdown
until after the following trigger
010 mode 2, rate generator; generate one pulse after 'count' CLK
cycles; output remains high until after the new countdown has
begun; reloading the count mid-period does not take affect
until after the period
011 mode 3, square wave rate generator; generate one pulse after
'count' CLK cycles; output remains high until 1/2 of the next
countdown; it does this by decrementing by 2 until zero, at
which time it lowers the output signal, reloads the counter
and counts down again until interrupting at 0; reloading the
count mid-period does not take affect until after the period
100 mode 4, software triggered strobe; countdown with output high
until counter zero; at zero output goes low for one CLK
period; countdown is triggered by loading counter; reloading
counter takes effect on next CLK pulse
101 mode 5, hardware triggered strobe; countdown after triggering
with output high until counter zero; at zero output goes low
for one CLK period }
assembler;
asm
cli
mov al,mode
out 43h,al
mov ax,countdown
out 40h,al
mov al,ah
out 40h,al
sti
end;
procedure ResetTimer;
begin
DisableTimerIRQ;
Program_PIT($36,0);
EnableTimerIRQ;
end;
procedure set_timer(Hz : Real);
begin
If (Hz > 1193180) then Hz := 1193180;
If (Hz < 19) then Hz := 19;
DisableTimerIRQ;
if Hz > 32 then
begin
Timer.divider := round(1193180 / Hz);
Timer.Frequency := Hz;
end
else
begin
Timer.divider := ($0ffff div Round(32/18.2));
Timer.Frequency := 32;
end;
Program_PIT($34,Timer.divider);
Timer.Clock_Counter := round(Timer.Frequency / 18.2);
EnableTimerIRQ;
end;
end.