2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: Clock for VDM
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 /* INCLUDES *******************************************************************/
19 #include "hardware/cmos.h"
20 #include "hardware/ps2.h"
21 #include "hardware/pit.h"
22 #include "hardware/video/vga.h"
24 /* Extra PSDK/NDK Headers */
25 #include <ndk/kefuncs.h>
27 /* DEFINES ********************************************************************/
30 * Activate IPS_DISPLAY if you want to display the
31 * number of instructions per second, as well as
32 * the computed number of ticks for the PIT.
34 // #define IPS_DISPLAY
37 * Activate WORKING_TIMER when the PIT timing problem is fixed.
39 // #define WORKING_TIMER
43 #define STEPS_PER_CYCLE 256
44 #define IRQ1_CYCLES 16
45 #define IRQ12_CYCLES 16
47 /* VARIABLES ******************************************************************/
49 static LARGE_INTEGER StartPerfCount
, Frequency
;
51 static LARGE_INTEGER LastTimerTick
, LastRtcTick
, Counter
;
52 static LONGLONG TimerTicks
;
53 static DWORD StartTickCount
, CurrentTickCount
;
54 static DWORD LastClockUpdate
;
55 static DWORD LastVerticalRefresh
;
57 static DWORD LastIrq1Tick
= 0, LastIrq12Tick
= 0;
60 static DWORD LastCyclePrintout
;
61 static ULONGLONG Cycles
= 0;
64 /* PUBLIC FUNCTIONS ***********************************************************/
66 VOID
ClockUpdate(VOID
)
68 extern BOOLEAN CpuRunning
;
70 // LARGE_INTEGER Counter;
77 while (VdmRunning
&& CpuRunning
)
81 PitResolution
= PitGetResolution();
83 RtcFrequency
= RtcGetTicksPerSecond();
85 /* Get the current number of ticks */
86 CurrentTickCount
= GetTickCount();
89 if ((PitResolution
<= 1000) && (RtcFrequency
<= 1000))
91 /* Calculate the approximate performance counter value instead */
92 Counter
.QuadPart
= StartPerfCount
.QuadPart
93 + (CurrentTickCount
- StartTickCount
)
94 * (Frequency
.QuadPart
/ 1000);
99 /* Get the current performance counter value */
100 /// DWORD_PTR oldmask = SetThreadAffinityMask(GetCurrentThread(), 0);
101 NtQueryPerformanceCounter(&Counter
, NULL
);
102 /// SetThreadAffinityMask(GetCurrentThread(), oldmask);
105 /* Get the number of PIT ticks that have passed */
106 TimerTicks
= ((Counter
.QuadPart
- LastTimerTick
.QuadPart
)
107 * PIT_BASE_FREQUENCY
) / Frequency
.QuadPart
;
112 PitClock(TimerTicks
);
113 LastTimerTick
= Counter
;
116 /* Check for RTC update */
117 if ((CurrentTickCount
- LastClockUpdate
) >= 1000)
120 LastClockUpdate
= CurrentTickCount
;
123 /* Check for RTC periodic tick */
124 if ((Counter
.QuadPart
- LastRtcTick
.QuadPart
)
125 >= (Frequency
.QuadPart
/ (LONGLONG
)RtcFrequency
))
128 LastRtcTick
= Counter
;
131 /* Check for vertical retrace */
132 if ((CurrentTickCount
- LastVerticalRefresh
) >= 15)
135 LastVerticalRefresh
= CurrentTickCount
;
138 if ((CurrentTickCount
- LastIrq1Tick
) >= IRQ1_CYCLES
)
141 LastIrq1Tick
= CurrentTickCount
;
144 if ((CurrentTickCount
- LastIrq12Tick
) >= IRQ12_CYCLES
)
147 LastIrq12Tick
= CurrentTickCount
;
150 /* Horizontal retrace occurs as fast as possible */
151 VgaHorizontalRetrace();
153 /* Continue CPU emulation */
154 for (i
= 0; VdmRunning
&& CpuRunning
&& (i
< STEPS_PER_CYCLE
); i
++)
163 if ((CurrentTickCount
- LastCyclePrintout
) >= 1000)
165 DPRINT1("NTVDM: %I64u Instructions Per Second; TimerTicks = %I64d\n", Cycles
* 1000 / (CurrentTickCount
- LastCyclePrintout
), TimerTicks
);
166 LastCyclePrintout
= CurrentTickCount
;
174 BOOLEAN
ClockInitialize(VOID
)
176 /* Initialize the performance counter (needed for hardware timers) */
177 /* Find the starting performance */
178 NtQueryPerformanceCounter(&StartPerfCount
, &Frequency
);
179 if (Frequency
.QuadPart
== 0)
181 wprintf(L
"FATAL: Performance counter not available\n");
185 /* Find the starting tick count */
186 StartTickCount
= GetTickCount();
188 /* Set the different last counts to the starting count */
189 LastClockUpdate
= LastVerticalRefresh
=
195 /* Set the last timer ticks to the current time */
196 LastTimerTick
= LastRtcTick
= StartPerfCount
;