#include "emulator.h"
#include "cpu/cpu.h"
-// #include "clock.h"
+#include "clock.h"
#include "hardware/cmos.h"
#include "hardware/ps2.h"
#include "hardware/pit.h"
#include "hardware/video/vga.h"
+#include "hardware/mouse.h"
/* Extra PSDK/NDK Headers */
#include <ndk/kefuncs.h>
/*
* Activate IPS_DISPLAY if you want to display the
- * number of instructions per second, as well as
- * the computed number of ticks for the PIT.
+ * number of instructions per second.
*/
// #define IPS_DISPLAY
*/
// #define WORKING_TIMER
-
/* Processor speed */
#define STEPS_PER_CYCLE 256
-#define IRQ1_CYCLES 16
-#define IRQ12_CYCLES 16
/* VARIABLES ******************************************************************/
+static LIST_ENTRY Timers;
static LARGE_INTEGER StartPerfCount, Frequency;
+static DWORD StartTickCount;
-static LARGE_INTEGER LastTimerTick, LastRtcTick, Counter;
-static LONGLONG TimerTicks;
-static DWORD StartTickCount, CurrentTickCount;
-static DWORD LastClockUpdate;
-static DWORD LastVerticalRefresh;
+#ifdef IPS_DISPLAY
+static ULONGLONG Cycles = 0ULL;
+#endif
-static DWORD LastIrq1Tick = 0, LastIrq12Tick = 0;
+/* PRIVATE FUNCTIONS **********************************************************/
#ifdef IPS_DISPLAY
- static DWORD LastCyclePrintout;
- static ULONGLONG Cycles = 0;
+static VOID FASTCALL IpsDisplayCallback(ULONGLONG ElapsedTime)
+{
+ DPRINT1("NTVDM: %I64u Instructions Per Second\n", Cycles / ElapsedTime);
+ Cycles = 0ULL;
+}
#endif
/* PUBLIC FUNCTIONS ***********************************************************/
{
extern BOOLEAN CpuRunning;
UINT i;
- // LARGE_INTEGER Counter;
-
-#ifdef WORKING_TIMER
- DWORD PitResolution;
-#endif
- DWORD RtcFrequency;
+ PLIST_ENTRY Entry;
+ LARGE_INTEGER Counter;
while (VdmRunning && CpuRunning)
{
+ /* Get the current number of ticks */
+ DWORD CurrentTickCount = GetTickCount();
#ifdef WORKING_TIMER
- PitResolution = PitGetResolution();
+ if ((PitResolution <= 1000) && (RtcFrequency <= 1000))
+ {
+ /* Calculate the approximate performance counter value instead */
+ Counter.QuadPart = StartPerfCount.QuadPart
+ + ((CurrentTickCount - StartTickCount)
+ * Frequency.QuadPart) / 1000;
+ }
+ else
#endif
- RtcFrequency = RtcGetTicksPerSecond();
-
- /* Get the current number of ticks */
- CurrentTickCount = GetTickCount();
+ {
+ /* Get the current performance counter value */
+ /// DWORD_PTR oldmask = SetThreadAffinityMask(GetCurrentThread(), 0);
+ NtQueryPerformanceCounter(&Counter, NULL);
+ /// SetThreadAffinityMask(GetCurrentThread(), oldmask);
+ }
+
+ /* Continue CPU emulation */
+ for (i = 0; VdmRunning && CpuRunning && (i < STEPS_PER_CYCLE); i++)
+ {
+ CpuStep();
-#ifdef WORKING_TIMER
- if ((PitResolution <= 1000) && (RtcFrequency <= 1000))
- {
- /* Calculate the approximate performance counter value instead */
- Counter.QuadPart = StartPerfCount.QuadPart
- + (CurrentTickCount - StartTickCount)
- * (Frequency.QuadPart / 1000);
- }
- else
+#ifdef IPS_DISPLAY
+ ++Cycles;
#endif
- {
- /* Get the current performance counter value */
- /// DWORD_PTR oldmask = SetThreadAffinityMask(GetCurrentThread(), 0);
- NtQueryPerformanceCounter(&Counter, NULL);
- /// SetThreadAffinityMask(GetCurrentThread(), oldmask);
+ }
+
+ for (Entry = Timers.Flink; Entry != &Timers; Entry = Entry->Flink)
+ {
+ ULONGLONG Ticks = (ULONGLONG)-1;
+ PHARDWARE_TIMER Timer = CONTAINING_RECORD(Entry, HARDWARE_TIMER, Link);
+
+ ASSERT((Timer->EnableCount > 0) && (Timer->Flags & HARDWARE_TIMER_ENABLED));
+
+ if (Timer->Delay)
+ {
+ if (Timer->Flags & HARDWARE_TIMER_PRECISE)
+ {
+ /* Use the performance counter for precise timers */
+ if (Counter.QuadPart <= Timer->LastTick.QuadPart) continue;
+ Ticks = (Counter.QuadPart - Timer->LastTick.QuadPart) / Timer->Delay;
+ }
+ else
+ {
+ /* Use the regular tick count for normal timers */
+ if (CurrentTickCount <= Timer->LastTick.LowPart) continue;
+ Ticks = (CurrentTickCount - Timer->LastTick.LowPart) / (ULONG)Timer->Delay;
+ }
+
+ if (Ticks == 0) continue;
+ }
+
+ Timer->Callback(Ticks);
+
+ if (Timer->Flags & HARDWARE_TIMER_ONESHOT)
+ {
+ /* Disable this timer */
+ DisableHardwareTimer(Timer);
+ }
+
+ /* Update the time of the last timer tick */
+ Timer->LastTick.QuadPart += Ticks * Timer->Delay;
+ }
}
+}
- /* Get the number of PIT ticks that have passed */
- TimerTicks = ((Counter.QuadPart - LastTimerTick.QuadPart)
- * PIT_BASE_FREQUENCY) / Frequency.QuadPart;
+PHARDWARE_TIMER CreateHardwareTimer(ULONG Flags, ULONG Delay, PHARDWARE_TIMER_PROC Callback)
+{
+ PHARDWARE_TIMER Timer;
+
+ Timer = (PHARDWARE_TIMER)RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(HARDWARE_TIMER));
+ if (Timer == NULL) return NULL;
+
+ Timer->Flags = Flags & ~HARDWARE_TIMER_ENABLED;
+ Timer->EnableCount = 0;
+ Timer->Callback = Callback;
+ SetHardwareTimerDelay(Timer, (ULONGLONG)Delay);
+
+ if (Flags & HARDWARE_TIMER_ENABLED) EnableHardwareTimer(Timer);
+ return Timer;
+}
- /* Update the PIT */
- if (TimerTicks > 0)
- {
- PitClock(TimerTicks);
- LastTimerTick = Counter;
- }
+VOID EnableHardwareTimer(PHARDWARE_TIMER Timer)
+{
+ /* Increment the count */
+ Timer->EnableCount++;
- /* Check for RTC update */
- if ((CurrentTickCount - LastClockUpdate) >= 1000)
+ /* Check if the count is above 0 but the timer isn't enabled */
+ if ((Timer->EnableCount > 0) && !(Timer->Flags & HARDWARE_TIMER_ENABLED))
{
- RtcTimeUpdate();
- LastClockUpdate = CurrentTickCount;
+ if (Timer->Flags & HARDWARE_TIMER_PRECISE)
+ {
+ NtQueryPerformanceCounter(&Timer->LastTick, NULL);
+ }
+ else
+ {
+ Timer->LastTick.LowPart = GetTickCount();
+ }
+
+ Timer->Flags |= HARDWARE_TIMER_ENABLED;
+ InsertTailList(&Timers, &Timer->Link);
}
+}
- /* Check for RTC periodic tick */
- if ((Counter.QuadPart - LastRtcTick.QuadPart)
- >= (Frequency.QuadPart / (LONGLONG)RtcFrequency))
- {
- RtcPeriodicTick();
- LastRtcTick = Counter;
- }
+VOID DisableHardwareTimer(PHARDWARE_TIMER Timer)
+{
+ /* Decrement the count */
+ Timer->EnableCount--;
- /* Check for vertical retrace */
- if ((CurrentTickCount - LastVerticalRefresh) >= 15)
+ /* Check if the count is 0 or less but the timer is enabled */
+ if ((Timer->EnableCount <= 0) && (Timer->Flags & HARDWARE_TIMER_ENABLED))
{
- VgaRefreshDisplay();
- LastVerticalRefresh = CurrentTickCount;
+ /* Disable the timer */
+ Timer->Flags &= ~HARDWARE_TIMER_ENABLED;
+ RemoveEntryList(&Timer->Link);
}
+}
- if ((CurrentTickCount - LastIrq1Tick) >= IRQ1_CYCLES)
+VOID SetHardwareTimerDelay(PHARDWARE_TIMER Timer, ULONGLONG NewDelay)
+{
+ if (Timer->Flags & HARDWARE_TIMER_PRECISE)
{
- GenerateIrq1();
- LastIrq1Tick = CurrentTickCount;
+ /* Convert the delay from nanoseconds to performance counter ticks */
+ Timer->Delay = (NewDelay * Frequency.QuadPart + 500000000ULL) / 1000000000ULL;
}
-
- if ((CurrentTickCount - LastIrq12Tick) >= IRQ12_CYCLES)
+ else
{
- GenerateIrq12();
- LastIrq12Tick = CurrentTickCount;
+ Timer->Delay = NewDelay;
}
+}
- /* Horizontal retrace occurs as fast as possible */
- VgaHorizontalRetrace();
+VOID DestroyHardwareTimer(PHARDWARE_TIMER Timer)
+{
+ if (Timer->Flags & HARDWARE_TIMER_ENABLED) RemoveEntryList(&Timer->Link);
+ RtlFreeHeap(RtlGetProcessHeap(), 0, Timer);
+}
- /* Continue CPU emulation */
- for (i = 0; VdmRunning && CpuRunning && (i < STEPS_PER_CYCLE); i++)
- {
- CpuStep();
+BOOLEAN ClockInitialize(VOID)
+{
#ifdef IPS_DISPLAY
- ++Cycles;
+ PHARDWARE_TIMER IpsTimer;
#endif
- }
-#ifdef IPS_DISPLAY
- if ((CurrentTickCount - LastCyclePrintout) >= 1000)
- {
- DPRINT1("NTVDM: %I64u Instructions Per Second; TimerTicks = %I64d\n", Cycles * 1000 / (CurrentTickCount - LastCyclePrintout), TimerTicks);
- LastCyclePrintout = CurrentTickCount;
- Cycles = 0;
- }
-#endif
-
- }
-}
+ InitializeListHead(&Timers);
-BOOLEAN ClockInitialize(VOID)
-{
/* Initialize the performance counter (needed for hardware timers) */
/* Find the starting performance */
NtQueryPerformanceCounter(&StartPerfCount, &Frequency);
/* Find the starting tick count */
StartTickCount = GetTickCount();
- /* Set the different last counts to the starting count */
- LastClockUpdate = LastVerticalRefresh =
#ifdef IPS_DISPLAY
- LastCyclePrintout =
-#endif
- StartTickCount;
- /* Set the last timer ticks to the current time */
- LastTimerTick = LastRtcTick = StartPerfCount;
+ IpsTimer = CreateHardwareTimer(HARDWARE_TIMER_ENABLED, 1000, IpsDisplayCallback);
+ if (IpsTimer == NULL)
+ {
+ wprintf(L"FATAL: Cannot create IPS display timer.\n");
+ return FALSE;
+ }
+
+#endif
return TRUE;
}