ReactOS 0.4.16-dev-334-g4d9f67c
pit.c
Go to the documentation of this file.
1/*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/hardware/pit.c
5 * PURPOSE: Programmable Interval Timer emulation -
6 * i82C54/8254 compatible
7 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
8 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
9 */
10
11/* INCLUDES *******************************************************************/
12
13#include "ntvdm.h"
14
15#define NDEBUG
16#include <debug.h>
17
18#include "emulator.h"
19#include "pit.h"
20
21#include "io.h"
22#include "pic.h"
23#include "clock.h"
24
25/* PRIVATE VARIABLES **********************************************************/
26
29
30/* PRIVATE FUNCTIONS **********************************************************/
31
33{
34 if (Channel >= PIT_CHANNELS) return;
35
36 /*
37 * A given counter can be latched only one time until it gets unlatched.
38 * If the counter is latched and then is latched again later before the
39 * value is read, then this last latch command is ignored and the value
40 * will be the value at the time the first command was issued.
41 */
42 if (PitChannels[Channel].LatchStatusSet == FALSE)
43 {
44 BYTE StatusLatch = 0;BYTE NullCount = 0;
47 StatusLatch = PitChannels[Channel].Out << 7 | NullCount << 6;
48 StatusLatch |= (PitChannels[Channel].ReadWriteMode & 0x03) << 4;
49 StatusLatch |= (PitChannels[Channel].Mode & 0x07) << 1;
50 StatusLatch |= (PitChannels[Channel].Bcd & 0x01);
51
52 /* Latch the counter's status */
54 PitChannels[Channel].StatusLatch = StatusLatch;
55 }
56}
57
59{
60 if (Channel >= PIT_CHANNELS) return;
61
62 /*
63 * A given counter can be latched only one time until it gets unlatched.
64 * If the counter is latched and then is latched again later before the
65 * value is read, then this last latch command is ignored and the value
66 * will be the value at the time the first command was issued.
67 */
68 if (PitChannels[Channel].ReadStatus == 0x00)
69 {
70 /* Latch the counter's value */
72
73 /* Convert the current value to BCD if needed */
74 PitChannels[Channel].OutputLatch =
75 READ_PIT_VALUE(PitChannels[Channel], PitChannels[Channel].CurrentValue);
76 }
77}
78
80{
83 /* Set the new state of the OUT pin */
84 Channel->Out = State;
85
86 /* Call the callback */
87 if (!Channel->Gate) return; // HACK: This is a HACK until gates are properly used (needed for the speaker to work properly).
88 if (Channel->OutFunction) Channel->OutFunction(Channel->OutParam, State);
89}
90
92{
93 switch (Channel->Mode)
94 {
96 PitSetOut(Channel, FALSE);
97 break;
98
104 PitSetOut(Channel, TRUE);
105 break;
106 }
107}
108
110{
111 BYTE Channel = (Value >> 6) & 0x03;
112 BYTE ReadWriteMode = (Value >> 4) & 0x03;
113 BYTE Mode = (Value >> 1) & 0x07;
114 BOOLEAN IsBcd = Value & 0x01;
115
116 /*
117 * Check for valid PIT channel - Possible values: 0, 1, 2.
118 * A value of 3 is for Read-Back Command.
119 */
120 if (Channel > PIT_CHANNELS) return;
121
122 /* Read-Back Command */
123 if (Channel == PIT_CHANNELS)
124 {
125 if ((Value & 0x20) == 0) // Bit 5 (Count) == 0: We latch multiple counters' counts
126 {
127 if (Value & 0x02) PitLatchChannelCount(0);
128 if (Value & 0x04) PitLatchChannelCount(1);
129 if (Value & 0x08) PitLatchChannelCount(2);
130 }
131 if ((Value & 0x10) == 0) // Bit 4 (Status) == 0: We latch multiple counters' statuses
132 {
133 if (Value & 0x02) PitLatchChannelStatus(0);
134 if (Value & 0x04) PitLatchChannelStatus(1);
135 if (Value & 0x08) PitLatchChannelStatus(2);
136 }
137 return;
138 }
139
140 /* Check if this is a counter latch command... */
141 if (ReadWriteMode == 0)
142 {
143 PitLatchChannelCount(Channel);
144 return;
145 }
146
147 /* ... otherwise, set the modes and reset flip-flops */
149 PitChannels[Channel].ReadStatus = 0x00;
150 PitChannels[Channel].WriteStatus = 0x00;
151
153 PitChannels[Channel].StatusLatch = 0x00;
154
155 PitChannels[Channel].CountRegister = 0x00;
156 PitChannels[Channel].OutputLatch = 0x00;
157PitChannels[Channel].FlipFlop = FALSE;
160 /* Fix the current value if we switch to BCD counting */
161 PitChannels[Channel].Bcd = IsBcd;
162 if (IsBcd && PitChannels[Channel].CurrentValue > 9999)
163 PitChannels[Channel].CurrentValue = 9999;
164
165 switch (Mode)
166 {
167 case 0:
168 case 1:
169 case 2:
170 case 3:
171 case 4:
172 case 5:
173 {
174 PitChannels[Channel].Mode = Mode;
175 break;
176 }
177
178 case 6:
179 case 7:
180 {
181 /*
182 * Modes 6 and 7 become PIT_MODE_RATE_GENERATOR
183 * and PIT_MODE_SQUARE_WAVE respectively.
184 */
185 PitChannels[Channel].Mode = Mode - 4;
186 break;
187 }
188 }
189
190 PitInitCounter(&PitChannels[Channel]);
191}
192
193static BYTE PitReadData(BYTE Channel)
194{
196 LPWORD CurrentValue = NULL;
197
198 /*
199 * If the status was latched, the first read operation will return the
200 * latched status, whichever value (count or status) was latched first.
201 */
202 if (PitChannels[Channel].LatchStatusSet)
203 {
205 return PitChannels[Channel].StatusLatch;
206 }
207
208 /* To be able to read the count asynchronously, latch it first if needed */
209 if (PitChannels[Channel].ReadStatus == 0) PitLatchChannelCount(Channel);
210
211 /* The count is now latched */
212 ASSERT(PitChannels[Channel].ReadStatus != 0);
213
215 CurrentValue = &PitChannels[Channel].OutputLatch;
216
217 if (*ReadWriteMode & 1)
218 {
219 /* Read LSB */
220 *ReadWriteMode &= ~1;
221 return LOBYTE(*CurrentValue);
222 }
223
224 if (*ReadWriteMode & 2)
225 {
226 /* Read MSB */
227 *ReadWriteMode &= ~2;
228 return HIBYTE(*CurrentValue);
229 }
230
231 /* Shouldn't get here */
232 ASSERT(FALSE);
233 return 0;
234}
235
237{
239
240 if (PitChannels[Channel].WriteStatus == 0x00)
241 {
243 }
244
245 ASSERT(PitChannels[Channel].WriteStatus != 0);
246
248
249 if (*ReadWriteMode & 1)
250 {
251 /* Write LSB */
252 *ReadWriteMode &= ~1;
253 PitChannels[Channel].CountRegister &= 0xFF00;
254 PitChannels[Channel].CountRegister |= Value;
255 }
256 else if (*ReadWriteMode & 2)
257 {
258 /* Write MSB */
259 *ReadWriteMode &= ~2;
260 PitChannels[Channel].CountRegister &= 0x00FF;
261 PitChannels[Channel].CountRegister |= Value << 8;
262 }
263
264 /* ReadWriteMode went to zero: we are going to load the new count */
265 if (*ReadWriteMode == 0x00)
266 {
267 if (PitChannels[Channel].CountRegister == 0x0000)
268 {
269 /* Wrap around to the highest count */
270 if (PitChannels[Channel].Bcd)
271 PitChannels[Channel].CountRegister = 9999;
272 else
273 PitChannels[Channel].CountRegister = 0xFFFF; // 0x10000; // 65536
274 }
275
276 /* Convert the current value from BCD if needed */
277 PitChannels[Channel].CountRegister =
278 WRITE_PIT_VALUE(PitChannels[Channel], PitChannels[Channel].CountRegister);
280
281 /* Reload now the new count */
283 }
284}
285
287{
288 switch (Port)
289 {
290 case PIT_DATA_PORT(0):
291 case PIT_DATA_PORT(1):
292 case PIT_DATA_PORT(2):
293 {
294 return PitReadData(Port - PIT_DATA_PORT(0));
295 }
296 }
297
298 return 0;
299}
300
302{
303 switch (Port)
304 {
305 case PIT_COMMAND_PORT:
306 {
308 break;
309 }
310
311 case PIT_DATA_PORT(0):
312 case PIT_DATA_PORT(1):
313 case PIT_DATA_PORT(2):
314 {
316 break;
317 }
318 }
319}
320
322{
323 if (Count == 0) return;
324
325 switch (Channel->Mode)
326 {
328 {
329 /* Decrement the value */
330 if (Count > Channel->CurrentValue)
331 {
332 /* The value does not reload in this case */
333 Channel->CurrentValue = 0;
334 }
335 else Channel->CurrentValue -= Count;
336
337 /* Did it fall to the terminal count? */
338 if (Channel->CurrentValue == 0 && !Channel->Out)
339 {
340 /* Yes, raise the output line */
341 PitSetOut(Channel, TRUE);
342 }
343 break;
344 }
345
347 {
348 BOOLEAN Reloaded = FALSE;
349
350 while (Count)
351 {
352 if ((Count > Channel->CurrentValue)
353 && (Channel->CurrentValue != 0))
354 {
355 /* Decrement the count */
356 Count -= Channel->CurrentValue;
357
358 /* Reload the value */
359 Channel->CurrentValue = Channel->ReloadValue;
360
361 /* Set the flag */
362 Reloaded = TRUE;
363 }
364 else
365 {
366 /* Decrement the value */
367 Channel->CurrentValue -= Count;
368
369 /* Clear the count */
370 Count = 0;
371
372 /* Did it fall to zero? */
373 if (Channel->CurrentValue == 0)
374 {
375 Channel->CurrentValue = Channel->ReloadValue;
376 Reloaded = TRUE;
377 }
378 }
379 }
380
381 /* If there was a reload, raise the output line */
382 if (Reloaded) PitSetOut(Channel, TRUE);
383
384 break;
385 }
386
388 {
389 INT ReloadCount = 0;
390 WORD ReloadValue = Channel->ReloadValue;
391
392 /* The reload value must be even */
393 ReloadValue &= ~1;
394
395 while (Count)
396 {
397 if (((Count * 2) > Channel->CurrentValue)
398 && (Channel->CurrentValue != 0))
399 {
400 /* Decrement the count */
401 Count -= Channel->CurrentValue / 2;
402
403 /* Reload the value */
404 Channel->CurrentValue = ReloadValue;
405
406 /* Increment the reload count */
407 ReloadCount++;
408 }
409 else
410 {
411 /* Decrement the value */
412 Channel->CurrentValue -= Count * 2;
413
414 /* Clear the count */
415 Count = 0;
416
417 /* Did it fall to zero? */
418 if (Channel->CurrentValue == 0)
419 {
420 /* Reload the value */
421 Channel->CurrentValue = ReloadValue;
422
423 /* Increment the reload count */
424 ReloadCount++;
425 }
426 }
427 }
428
429 if (ReloadCount == 0) break;
430
431 /* Toggle the flip-flop if the number of reloads was odd */
432 if (ReloadCount & 1)
433 {
434 Channel->FlipFlop = !Channel->FlipFlop;
435 PitSetOut(Channel, !Channel->Out);
436 }
437
438 /* Was there any rising edge? */
439 if ((Channel->FlipFlop && (ReloadCount == 1)) || (ReloadCount > 1))
440 {
441 /* Yes, raise the output line */
442 PitSetOut(Channel, TRUE);
443 }
444
445 break;
446 }
447
449 {
450 // TODO: NOT IMPLEMENTED
451 break;
452 }
453
456 {
457 /* These modes do not work on x86 PCs */
458 break;
459 }
460 }
461}
462
464{
465 UCHAR i;
466
467 for (i = 0; i < PIT_CHANNELS; i++)
468 {
469 // if (!PitChannels[i].Counting) continue;
471 }
472}
473
474/* PUBLIC FUNCTIONS ***********************************************************/
475
477{
478 if (Channel >= PIT_CHANNELS) return;
479
480 PitChannels[Channel].OutParam = Param;
481 PitChannels[Channel].OutFunction = OutFunction;
482}
483
485{
486 if (Channel >= PIT_CHANNELS) return;
487 if (State == PitChannels[Channel].Gate) return;
488
489 /* UNIMPLEMENTED */
490 PitChannels[Channel].Gate = State;
491}
492
494{
495 if (Channel >= PIT_CHANNELS) return 0xFFFF;
496
497 if (PitChannels[Channel].ReloadValue == 0)
498 return 0xFFFF;
499 else
500 return PitChannels[Channel].ReloadValue;
501}
502
504{
505 /* Set up the timers to their default value */
507 PitSetGate(0, TRUE);
509 PitSetGate(1, TRUE);
511 PitSetGate(2, FALSE);
512
513 /* Register the I/O Ports */
518
519 /* Register the hardware timer */
522 PitClock);
523}
524
525/* EOF */
unsigned char BOOLEAN
#define HARDWARE_TIMER_ENABLED
Definition: clock.h:15
#define HARDWARE_TIMER_PRECISE
Definition: clock.h:17
#define HZ_TO_NS(Freq)
Definition: clock.h:20
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
static VOID ReadWriteMode(_In_ UCHAR Mode)
Definition: vga.c:74
static UCHAR ReadStatus(_In_ PUCHAR ReadDataPort)
Definition: hardware.c:172
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned short WORD
Definition: ntddk_ex.h:93
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
CPPORT Port[4]
Definition: headless.c:35
_In_ ULONG Mode
Definition: hubbusif.h:303
#define LOBYTE(W)
Definition: jmemdos.c:487
#define HIBYTE(W)
Definition: jmemdos.c:486
#define ASSERT(a)
Definition: mode.c:44
int Count
Definition: noreturn.cpp:7
#define FASTCALL
Definition: nt_native.h:50
unsigned short USHORT
Definition: pedump.c:61
static VOID PitWriteData(BYTE Channel, BYTE Value)
Definition: pit.c:236
static VOID PitInitCounter(PPIT_CHANNEL Channel)
Definition: pit.c:91
static VOID FASTCALL PitClock(ULONGLONG Count)
Definition: pit.c:463
static VOID WINAPI PitWritePort(USHORT Port, BYTE Data)
Definition: pit.c:301
VOID PitSetOutFunction(BYTE Channel, LPVOID Param, PIT_OUT_FUNCTION OutFunction)
Definition: pit.c:476
VOID PitSetGate(BYTE Channel, BOOLEAN State)
Definition: pit.c:484
static BYTE WINAPI PitReadPort(USHORT Port)
Definition: pit.c:286
WORD PitGetReloadValue(BYTE Channel)
Definition: pit.c:493
static VOID PitDecrementCount(PPIT_CHANNEL Channel, DWORD Count)
Definition: pit.c:321
static VOID PitSetOut(PPIT_CHANNEL Channel, BOOLEAN State)
Definition: pit.c:79
static PIT_CHANNEL PitChannels[PIT_CHANNELS]
Definition: pit.c:27
static VOID PitLatchChannelCount(BYTE Channel)
Definition: pit.c:58
static VOID PitLatchChannelStatus(BYTE Channel)
Definition: pit.c:32
static BYTE PitReadData(BYTE Channel)
Definition: pit.c:193
VOID PitInitialize(VOID)
Definition: pit.c:503
static PHARDWARE_TIMER MasterClock
Definition: pit.c:28
static VOID PitWriteCommand(BYTE Value)
Definition: pit.c:109
BOOLEAN Bcd
Definition: pit.h:43
BOOLEAN LatchStatusSet
Definition: pit.h:51
BYTE ReadWriteMode
Definition: pit.h:44
WORD ReloadValue
Definition: pit.h:61
BYTE WriteStatus
Definition: pit.h:48
PIT_OUT_FUNCTION OutFunction
Definition: pit.h:68
BYTE ReadStatus
Definition: pit.h:47
WORD CountRegister
Definition: pit.h:57
BYTE StatusLatch
Definition: pit.h:52
PIT_MODE Mode
Definition: pit.h:42
WORD CurrentValue
Definition: pit.h:62
BOOLEAN FlipFlop
Definition: pit.h:66
BOOLEAN Gate
Definition: pit.h:55
LPVOID OutParam
Definition: pit.h:67
WORD OutputLatch
Definition: pit.h:58
BOOLEAN Out
Definition: pit.h:65
PHARDWARE_TIMER CreateHardwareTimer(ULONG Flags, ULONGLONG Delay, PHARDWARE_TIMER_PROC Callback)
Definition: clock.c:144
#define PIT_DATA_PORT(x)
Definition: pit.h:18
#define PIT_COMMAND_PORT
Definition: pit.h:19
VOID(WINAPI * PIT_OUT_FUNCTION)(LPVOID Param, BOOLEAN State)
Definition: pit.h:37
#define WRITE_PIT_VALUE(PitChannel, Value)
Definition: pit.h:21
#define PIT_CHANNELS
Definition: pit.h:16
#define PIT_BASE_FREQUENCY
Definition: pit.h:17
@ PIT_MODE_HARDWARE_ONE_SHOT
Definition: pit.h:30
@ PIT_MODE_HARDWARE_STROBE
Definition: pit.h:34
@ PIT_MODE_RATE_GENERATOR
Definition: pit.h:31
@ PIT_MODE_SOFTWARE_STROBE
Definition: pit.h:33
@ PIT_MODE_SQUARE_WAVE
Definition: pit.h:32
@ PIT_MODE_INT_ON_TERMINAL_COUNT
Definition: pit.h:29
#define READ_PIT_VALUE(PitChannel, Value)
Definition: pit.h:24
VOID RegisterIoPort(USHORT Port, EMULATOR_INB_PROC InHandler, EMULATOR_OUTB_PROC OutHandler)
Definition: io.c:320
unsigned char * LPBYTE
Definition: typedefs.h:53
uint16_t * LPWORD
Definition: typedefs.h:56
int32_t INT
Definition: typedefs.h:58
uint64_t ULONGLONG
Definition: typedefs.h:67
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
#define WINAPI
Definition: msvc.h:6
unsigned char UCHAR
Definition: xmlstorage.h:181
unsigned char BYTE
Definition: xxhash.c:193