Author: aandrejevic
Date: Fri Jun 21 13:55:31 2013
New Revision: 59273
URL:
http://svn.reactos.org/svn/reactos?rev=59273&view=rev
Log:
[NTVDM]
Change the PIT code to use only one thread, to avoid race conditions.
Implement PIT counter reading and latch command.
Modified:
branches/ntvdm/subsystems/ntvdm/bios.c
branches/ntvdm/subsystems/ntvdm/hardware.c
branches/ntvdm/subsystems/ntvdm/ntvdm.c
branches/ntvdm/subsystems/ntvdm/ntvdm.h
Modified: branches/ntvdm/subsystems/ntvdm/bios.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/bios.c?r…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/bios.c [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/bios.c [iso-8859-1] Fri Jun 21 13:55:31 2013
@@ -76,7 +76,9 @@
PicWriteData(PIC_MASTER_DATA, 0x00);
PicWriteData(PIC_SLAVE_DATA, 0x00);
- PitInitialize();
+ PitWriteCommand(0x34);
+ PitWriteData(0, 0x00);
+ PitWriteData(0, 0x00);
return TRUE;
}
Modified: branches/ntvdm/subsystems/ntvdm/hardware.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/hardware…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/hardware.c [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/hardware.c [iso-8859-1] Fri Jun 21 13:55:31 2013
@@ -24,64 +24,31 @@
BOOLEAN ReadIsr;
} PIC, *PPIC;
+enum
+{
+ PIT_MODE_INT_ON_TERMINAL_COUNT,
+ PIT_MODE_HARDWARE_ONE_SHOT,
+ PIT_MODE_RATE_GENERATOR,
+ PIT_MODE_SQUARE_WAVE,
+ PIT_MODE_SOFTWARE_STROBE,
+ PIT_MODE_HARDWARE_STROBE
+};
+
typedef struct _PIT_CHANNEL
{
- BOOLEAN RateGenerator;
+ WORD ReloadValue;
+ WORD CurrentValue;
+ WORD LatchedValue;
+ INT Mode;
BOOLEAN Pulsed;
- BOOLEAN FlipFlop;
+ BOOLEAN LatchSet;
+ BOOLEAN InputFlipFlop;
+ BOOLEAN OutputFlipFlop;
BYTE AccessMode;
- WORD ReloadValue;
} PIT_CHANNEL, *PPIT_CHANNEL;
static PIC MasterPic, SlavePic;
static PIT_CHANNEL PitChannels[PIT_CHANNELS];
-
-static DWORD WINAPI PitThread(PVOID Parameter)
-{
- LARGE_INTEGER Frequency, CurrentTime, LastTickTime;
- LONGLONG Elapsed, Milliseconds, TicksNeeded;
- UNREFERENCED_PARAMETER(Parameter);
-
- /* Get the performance counter frequency */
- if (!QueryPerformanceFrequency(&Frequency)) return EXIT_FAILURE;
- if (!QueryPerformanceCounter(&LastTickTime)) return EXIT_FAILURE;
-
- while (VdmRunning)
- {
- if (!QueryPerformanceCounter(&CurrentTime)) return EXIT_FAILURE;
-
- /* Calculate the elapsed time, in PIT ticks */
- Elapsed = ((CurrentTime.QuadPart - LastTickTime.QuadPart)
- * PIT_BASE_FREQUENCY)
- / Frequency.QuadPart;
-
- /* A reload value of 0 indicates 65536 */
- if (PitChannels[0].ReloadValue) TicksNeeded = PitChannels[0].ReloadValue;
- else TicksNeeded = 65536;
-
- if (Elapsed < TicksNeeded)
- {
- /* Get the number of milliseconds */
- Milliseconds = (Elapsed * 1000LL) / PIT_BASE_FREQUENCY;
-
- /* If this number is non-zero, put the thread in the waiting state */
- if (Milliseconds > 0LL) Sleep((DWORD)Milliseconds);
-
- continue;
- }
-
- LastTickTime = CurrentTime;
-
- /* Do the IRQ */
- if (PitChannels[0].RateGenerator || !PitChannels[0].Pulsed)
- {
- PitChannels[0].Pulsed = TRUE;
- PicInterruptRequest(0);
- }
- }
-
- return EXIT_SUCCESS;
-}
/* PUBLIC FUNCTIONS ***********************************************************/
@@ -275,39 +242,110 @@
BYTE Channel = Value >> 6;
BYTE Mode = (Value >> 1) & 0x07;
- /* Set the access mode and reset flip-flop */
- // TODO: Support latch command!
+ /* Check if this is a counter latch command */
+ if (((Value >> 4) & 3) == 0)
+ {
+ PitChannels[Channel].LatchSet = TRUE;
+ PitChannels[Channel].LatchedValue = PitChannels[Channel].CurrentValue;
+ return;
+ }
+
+ /* Set the access mode and reset flip-flops */
PitChannels[Channel].AccessMode = (Value >> 4) & 3;
- PitChannels[Channel].FlipFlop = FALSE;
+ PitChannels[Channel].Pulsed = FALSE;
+ PitChannels[Channel].LatchSet = FALSE;
+ PitChannels[Channel].InputFlipFlop = FALSE;
+ PitChannels[Channel].OutputFlipFlop = FALSE;
switch (Mode)
{
case 0:
- case 4:
- {
- PitChannels[Channel].RateGenerator = FALSE;
- break;
- }
-
+ case 1:
case 2:
case 3:
- {
- PitChannels[Channel].RateGenerator = TRUE;
+ case 4:
+ case 5:
+ {
+ PitChannels[Channel].Mode = Mode;
break;
}
- }
+
+ case 6:
+ {
+ PitChannels[Channel].Mode = PIT_MODE_RATE_GENERATOR;
+ break;
+ }
+
+ case 7:
+ {
+ PitChannels[Channel].Mode = PIT_MODE_SQUARE_WAVE;
+ break;
+ }
+ }
+}
+
+BYTE PitReadData(BYTE Channel)
+{
+ WORD CurrentValue = PitChannels[Channel].CurrentValue;
+ BYTE AccessMode = PitChannels[Channel].AccessMode;
+
+ /* Check if the value was latched */
+ if (PitChannels[Channel].LatchSet)
+ {
+ CurrentValue = PitChannels[Channel].LatchedValue;
+
+ if (AccessMode == 1 || AccessMode == 2)
+ {
+ /* The latched value was read as one byte */
+ PitChannels[Channel].LatchSet = FALSE;
+ }
+ }
+
+ /* Use the flip-flop for access mode 3 */
+ if (AccessMode == 3)
+ {
+ AccessMode = PitChannels[Channel].InputFlipFlop ? 1 : 2;
+ PitChannels[Channel].InputFlipFlop = !PitChannels[Channel].InputFlipFlop;
+
+ /* Check if this was the last read for the latched value */
+ if (!PitChannels[Channel].InputFlipFlop)
+ {
+ /* Yes, the latch value was read as two bytes */
+ PitChannels[Channel].LatchSet = FALSE;
+ }
+ }
+
+ switch (AccessMode)
+ {
+ case 1:
+ {
+ /* Low byte */
+ return CurrentValue & 0x00FF;
+ }
+
+ case 2:
+ {
+ /* High byte */
+ return CurrentValue >> 8;
+ }
+ }
+
+ /* Shouldn't get here */
+ return 0;
}
VOID PitWriteData(BYTE Channel, BYTE Value)
{
+ BYTE AccessMode = PitChannels[Channel].AccessMode;
+
/* Use the flip-flop for access mode 3 */
if (PitChannels[Channel].AccessMode == 3)
{
- PitChannels[Channel].AccessMode = PitChannels[Channel].FlipFlop ? 1 : 2;
- PitChannels[Channel].FlipFlop = !PitChannels[Channel].FlipFlop;
- }
-
- switch (PitChannels[Channel].AccessMode)
+ AccessMode = PitChannels[Channel].InputFlipFlop ? 1 : 2;
+ PitChannels[Channel].InputFlipFlop = !PitChannels[Channel].InputFlipFlop;
+ }
+
+ switch (AccessMode)
{
case 1:
{
@@ -326,20 +364,90 @@
}
}
-VOID PitInitialize()
-{
- HANDLE ThreadHandle;
-
- /* Set up channel 0 */
- PitChannels[0].ReloadValue = 0;
- PitChannels[0].RateGenerator = TRUE;
- PitChannels[0].Pulsed = FALSE;
- PitChannels[0].AccessMode = 3;
- PitChannels[0].FlipFlop = FALSE;
-
- /* Create the PIT timer thread */
- ThreadHandle = CreateThread(NULL, 0, PitThread, NULL, 0, NULL);
-
- /* We don't need the handle */
- CloseHandle(ThreadHandle);
-}
+VOID PitDecrementCount()
+{
+ INT i;
+
+ for (i = 0; i < PIT_CHANNELS; i++)
+ {
+ switch (PitChannels[i].Mode)
+ {
+ case PIT_MODE_INT_ON_TERMINAL_COUNT:
+ {
+ /* Decrement the value */
+ PitChannels[i].CurrentValue--;
+
+ /* Did it fall to the terminal count? */
+ if (PitChannels[i].CurrentValue == 0 && !PitChannels[i].Pulsed)
+ {
+ /* Yes, raise the output line */
+ if (i == 0) PicInterruptRequest(0);
+ PitChannels[i].Pulsed = TRUE;
+ }
+ break;
+ }
+
+ case PIT_MODE_RATE_GENERATOR:
+ {
+ /* Decrement the value */
+ PitChannels[i].CurrentValue--;
+
+ /* Did it fall to zero? */
+ if (PitChannels[i].CurrentValue != 0) break;
+
+ /* Yes, raise the output line and reload */
+ if (i == 0) PicInterruptRequest(0);
+ PitChannels[i].CurrentValue = PitChannels[i].ReloadValue;
+
+ break;
+ }
+
+ case PIT_MODE_SQUARE_WAVE:
+ {
+ /* Decrement the value by 2 */
+ PitChannels[i].CurrentValue -= 2;
+
+ /* Did it fall to zero? */
+ if (PitChannels[i].CurrentValue != 0) break;
+
+ /* Yes, toggle the flip-flop */
+ PitChannels[i].OutputFlipFlop = !PitChannels[i].OutputFlipFlop;
+
+ /* Did this create a rising edge in the signal? */
+ if (PitChannels[i].OutputFlipFlop)
+ {
+ /* Yes, IRQ 0 if this is channel 0 */
+ if (i == 0) PicInterruptRequest(0);
+ }
+
+ /* Reload the value, but make sure it's even */
+ if (PitChannels[i].ReloadValue % 2)
+ {
+ /* It's odd, reduce it by 1 */
+ PitChannels[i].CurrentValue = PitChannels[i].ReloadValue - 1;
+ }
+ else
+ {
+ /* It was even */
+ PitChannels[i].CurrentValue = PitChannels[i].ReloadValue;
+ }
+
+ break;
+ }
+
+ case PIT_MODE_SOFTWARE_STROBE:
+ {
+ // TODO: NOT IMPLEMENTED
+ break;
+ }
+
+ case PIT_MODE_HARDWARE_ONE_SHOT:
+ case PIT_MODE_HARDWARE_STROBE:
+ {
+ /* These modes do not work on x86 PCs */
+ break;
+ }
+ }
+ }
+}
+
Modified: branches/ntvdm/subsystems/ntvdm/ntvdm.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/ntvdm.c?…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/ntvdm.c [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/ntvdm.c [iso-8859-1] Fri Jun 21 13:55:31 2013
@@ -57,6 +57,8 @@
INT i;
BOOLEAN PrintUsage = TRUE;
CHAR CommandLine[128];
+ LARGE_INTEGER Frequency, LastTimerTick, Counter;
+ LONGLONG TimerTicks;
/* Set the handler routine */
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
@@ -96,6 +98,13 @@
}
if (!EmulatorInitialize()) return 1;
+
+ /* Initialize the performance counter (needed for hardware timers) */
+ if (!QueryPerformanceFrequency(&Frequency))
+ {
+ wprintf(L"FATAL: Performance counter not available\n");
+ goto Cleanup;
+ }
/* Initialize the system BIOS */
if (!BiosInitialize())
@@ -117,9 +126,27 @@
DisplayMessage(L"Could not start program: %S", CommandLine);
return -1;
}
+
+ /* Set the last timer tick to the current time */
+ QueryPerformanceCounter(&LastTimerTick);
/* Main loop */
- while (VdmRunning) EmulatorStep();
+ while (VdmRunning)
+ {
+ /* Get the current time */
+ QueryPerformanceCounter(&Counter);
+
+ /* Get the number of PIT ticks that have passed */
+ TimerTicks = ((Counter.QuadPart - LastTimerTick.QuadPart)
+ * PIT_BASE_FREQUENCY) / Frequency.QuadPart;
+
+ /* Update the PIT */
+ for (i = 0; i < TimerTicks; i++) PitDecrementCount();
+ LastTimerTick = Counter;
+
+ /* Continue CPU emulation */
+ EmulatorStep();
+ }
Cleanup:
EmulatorCleanup();
Modified: branches/ntvdm/subsystems/ntvdm/ntvdm.h
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/ntvdm.h?…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/ntvdm.h [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/ntvdm.h [iso-8859-1] Fri Jun 21 13:55:31 2013
@@ -216,7 +216,9 @@
VOID PicInterruptRequest(BYTE Number);
VOID PitInitialize();
VOID PitWriteCommand(BYTE Value);
+BYTE PitReadData(BYTE Channel);
VOID PitWriteData(BYTE Channel, BYTE Value);
+VOID PitDecrementCount();
VOID EmulatorSetStack(WORD Segment, WORD Offset);
VOID EmulatorExecute(WORD Segment, WORD Offset);
VOID EmulatorInterrupt(BYTE Number);