2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: Programmable Interval Timer emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
16 /* PRIVATE VARIABLES **********************************************************/
18 static PIT_CHANNEL PitChannels
[PIT_CHANNELS
];
20 /* PUBLIC FUNCTIONS ***********************************************************/
22 VOID
PitWriteCommand(BYTE Value
)
24 BYTE Channel
= Value
>> 6;
25 BYTE Mode
= (Value
>> 1) & 0x07;
27 /* Check if this is a counter latch command */
28 if (((Value
>> 4) & 3) == 0)
30 PitChannels
[Channel
].LatchSet
= TRUE
;
31 PitChannels
[Channel
].LatchedValue
= PitChannels
[Channel
].CurrentValue
;
35 /* Set the access mode and reset flip-flops */
36 PitChannels
[Channel
].AccessMode
= (Value
>> 4) & 3;
37 PitChannels
[Channel
].Pulsed
= FALSE
;
38 PitChannels
[Channel
].LatchSet
= FALSE
;
39 PitChannels
[Channel
].InputFlipFlop
= FALSE
;
40 PitChannels
[Channel
].OutputFlipFlop
= FALSE
;
51 PitChannels
[Channel
].Mode
= Mode
;
57 PitChannels
[Channel
].Mode
= PIT_MODE_RATE_GENERATOR
;
63 PitChannels
[Channel
].Mode
= PIT_MODE_SQUARE_WAVE
;
69 BYTE
PitReadData(BYTE Channel
)
71 WORD CurrentValue
= PitChannels
[Channel
].CurrentValue
;
72 BYTE AccessMode
= PitChannels
[Channel
].AccessMode
;
74 /* Check if the value was latched */
75 if (PitChannels
[Channel
].LatchSet
)
77 CurrentValue
= PitChannels
[Channel
].LatchedValue
;
79 if (AccessMode
== 1 || AccessMode
== 2)
81 /* The latched value was read as one byte */
82 PitChannels
[Channel
].LatchSet
= FALSE
;
86 /* Use the flip-flop for access mode 3 */
89 AccessMode
= PitChannels
[Channel
].InputFlipFlop
? 1 : 2;
90 PitChannels
[Channel
].InputFlipFlop
= !PitChannels
[Channel
].InputFlipFlop
;
92 /* Check if this was the last read for the latched value */
93 if (!PitChannels
[Channel
].InputFlipFlop
)
95 /* Yes, the latch value was read as two bytes */
96 PitChannels
[Channel
].LatchSet
= FALSE
;
105 return CurrentValue
& 0x00FF;
111 return CurrentValue
>> 8;
115 /* Shouldn't get here */
119 VOID
PitWriteData(BYTE Channel
, BYTE Value
)
121 BYTE AccessMode
= PitChannels
[Channel
].AccessMode
;
123 /* Use the flip-flop for access mode 3 */
124 if (PitChannels
[Channel
].AccessMode
== 3)
126 AccessMode
= PitChannels
[Channel
].InputFlipFlop
? 1 : 2;
127 PitChannels
[Channel
].InputFlipFlop
= !PitChannels
[Channel
].InputFlipFlop
;
135 PitChannels
[Channel
].ReloadValue
&= 0xFF00;
136 PitChannels
[Channel
].ReloadValue
|= Value
;
143 PitChannels
[Channel
].ReloadValue
&= 0x00FF;
144 PitChannels
[Channel
].ReloadValue
|= Value
<< 8;
149 VOID
PitDecrementCount(DWORD Count
)
153 for (i
= 0; i
< PIT_CHANNELS
; i
++)
155 switch (PitChannels
[i
].Mode
)
157 case PIT_MODE_INT_ON_TERMINAL_COUNT
:
159 /* Decrement the value */
160 if (Count
> PitChannels
[i
].CurrentValue
)
162 /* The value does not reload in this case */
163 PitChannels
[i
].CurrentValue
= 0;
165 else PitChannels
[i
].CurrentValue
-= Count
;
167 /* Did it fall to the terminal count? */
168 if (PitChannels
[i
].CurrentValue
== 0 && !PitChannels
[i
].Pulsed
)
170 /* Yes, raise the output line */
171 if (i
== 0) PicInterruptRequest(0);
172 PitChannels
[i
].Pulsed
= TRUE
;
177 case PIT_MODE_RATE_GENERATOR
:
179 BOOLEAN Reloaded
= FALSE
;
183 if ((Count
> PitChannels
[i
].CurrentValue
)
184 && (PitChannels
[i
].CurrentValue
!= 0))
186 /* Decrease the count */
187 Count
-= PitChannels
[i
].CurrentValue
;
189 /* Reload the value */
190 PitChannels
[i
].CurrentValue
= PitChannels
[i
].ReloadValue
;
197 /* Decrease the value */
198 PitChannels
[i
].CurrentValue
-= Count
;
200 /* Clear the count */
203 /* Did it fall to zero? */
204 if (PitChannels
[i
].CurrentValue
== 0)
206 PitChannels
[i
].CurrentValue
= PitChannels
[i
].ReloadValue
;
212 /* If there was a reload on channel 0, raise IRQ 0 */
213 if ((i
== 0) && Reloaded
) PicInterruptRequest(0);
218 case PIT_MODE_SQUARE_WAVE
:
221 WORD ReloadValue
= PitChannels
[i
].ReloadValue
;
223 /* The reload value must be even */
228 if (((Count
* 2) > PitChannels
[i
].CurrentValue
)
229 && (PitChannels
[i
].CurrentValue
!= 0))
231 /* Decrease the count */
232 Count
-= PitChannels
[i
].CurrentValue
/ 2;
234 /* Reload the value */
235 PitChannels
[i
].CurrentValue
= ReloadValue
;
237 /* Increment the reload count */
242 /* Clear the count */
245 /* Decrease the value */
246 PitChannels
[i
].CurrentValue
-= Count
* 2;
248 /* Did it fall to zero? */
249 if (PitChannels
[i
].CurrentValue
== 0)
251 /* Reload the value */
252 PitChannels
[i
].CurrentValue
= ReloadValue
;
254 /* Increment the reload count */
260 if (ReloadCount
== 0) break;
262 /* Toggle the flip-flop if the number of reloads was odd */
265 PitChannels
[i
].OutputFlipFlop
= !PitChannels
[i
].OutputFlipFlop
;
268 /* Was there any rising edge on channel 0 ? */
269 if ((PitChannels
[i
].OutputFlipFlop
|| ReloadCount
) && (i
== 0))
272 PicInterruptRequest(0);
278 case PIT_MODE_SOFTWARE_STROBE
:
280 // TODO: NOT IMPLEMENTED
284 case PIT_MODE_HARDWARE_ONE_SHOT
:
285 case PIT_MODE_HARDWARE_STROBE
:
287 /* These modes do not work on x86 PCs */
294 DWORD
PitGetResolution(VOID
)
297 DWORD MinReloadValue
= 65536;
299 for (i
= 0; i
< PIT_CHANNELS
; i
++)
301 DWORD ReloadValue
= PitChannels
[i
].ReloadValue
;
304 if (ReloadValue
== 0) ReloadValue
= 65536;
306 if (ReloadValue
< MinReloadValue
) MinReloadValue
= ReloadValue
;
309 /* Return the frequency resolution */
310 return PIT_BASE_FREQUENCY
/ MinReloadValue
;