305ccc2226afb569bc60088536b17ff86e3afaf4
[reactos.git] / reactos / subsystems / mvdm / ntvdm / clock.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: clock.c
5 * PURPOSE: Clock for VDM
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #define NDEBUG
13
14 #include "emulator.h"
15 #include "cpu/cpu.h"
16
17 // #include "clock.h"
18
19 #include "hardware/cmos.h"
20 #include "hardware/ps2.h"
21 #include "hardware/pit.h"
22 #include "hardware/video/vga.h"
23
24 /* Extra PSDK/NDK Headers */
25 #include <ndk/kefuncs.h>
26
27 /* DEFINES ********************************************************************/
28
29 /*
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.
33 */
34 // #define IPS_DISPLAY
35
36 /*
37 * Activate WORKING_TIMER when the PIT timing problem is fixed.
38 */
39 // #define WORKING_TIMER
40
41
42 /* Processor speed */
43 #define STEPS_PER_CYCLE 256
44 #define IRQ1_CYCLES 16
45 #define IRQ12_CYCLES 16
46
47 /* VARIABLES ******************************************************************/
48
49 static LARGE_INTEGER StartPerfCount, Frequency;
50
51 static LARGE_INTEGER LastTimerTick, LastRtcTick, Counter;
52 static LONGLONG TimerTicks;
53 static DWORD StartTickCount, CurrentTickCount;
54 static DWORD LastClockUpdate;
55 static DWORD LastVerticalRefresh;
56
57 static DWORD LastIrq1Tick = 0, LastIrq12Tick = 0;
58
59 #ifdef IPS_DISPLAY
60 static DWORD LastCyclePrintout;
61 static ULONGLONG Cycles = 0;
62 #endif
63
64 /* PUBLIC FUNCTIONS ***********************************************************/
65
66 VOID ClockUpdate(VOID)
67 {
68 extern BOOLEAN CpuRunning;
69 UINT i;
70 // LARGE_INTEGER Counter;
71
72 #ifdef WORKING_TIMER
73 DWORD PitResolution;
74 #endif
75 DWORD RtcFrequency;
76
77 while (VdmRunning && CpuRunning)
78 {
79
80 #ifdef WORKING_TIMER
81 PitResolution = PitGetResolution();
82 #endif
83 RtcFrequency = RtcGetTicksPerSecond();
84
85 /* Get the current number of ticks */
86 CurrentTickCount = GetTickCount();
87
88 #ifdef WORKING_TIMER
89 if ((PitResolution <= 1000) && (RtcFrequency <= 1000))
90 {
91 /* Calculate the approximate performance counter value instead */
92 Counter.QuadPart = StartPerfCount.QuadPart
93 + (CurrentTickCount - StartTickCount)
94 * (Frequency.QuadPart / 1000);
95 }
96 else
97 #endif
98 {
99 /* Get the current performance counter value */
100 /// DWORD_PTR oldmask = SetThreadAffinityMask(GetCurrentThread(), 0);
101 NtQueryPerformanceCounter(&Counter, NULL);
102 /// SetThreadAffinityMask(GetCurrentThread(), oldmask);
103 }
104
105 /* Get the number of PIT ticks that have passed */
106 TimerTicks = ((Counter.QuadPart - LastTimerTick.QuadPart)
107 * PIT_BASE_FREQUENCY) / Frequency.QuadPart;
108
109 /* Update the PIT */
110 if (TimerTicks > 0)
111 {
112 PitClock(TimerTicks);
113 LastTimerTick = Counter;
114 }
115
116 /* Check for RTC update */
117 if ((CurrentTickCount - LastClockUpdate) >= 1000)
118 {
119 RtcTimeUpdate();
120 LastClockUpdate = CurrentTickCount;
121 }
122
123 /* Check for RTC periodic tick */
124 if ((Counter.QuadPart - LastRtcTick.QuadPart)
125 >= (Frequency.QuadPart / (LONGLONG)RtcFrequency))
126 {
127 RtcPeriodicTick();
128 LastRtcTick = Counter;
129 }
130
131 /* Check for vertical retrace */
132 if ((CurrentTickCount - LastVerticalRefresh) >= 15)
133 {
134 VgaRefreshDisplay();
135 LastVerticalRefresh = CurrentTickCount;
136 }
137
138 if ((CurrentTickCount - LastIrq1Tick) >= IRQ1_CYCLES)
139 {
140 GenerateIrq1();
141 LastIrq1Tick = CurrentTickCount;
142 }
143
144 if ((CurrentTickCount - LastIrq12Tick) >= IRQ12_CYCLES)
145 {
146 GenerateIrq12();
147 LastIrq12Tick = CurrentTickCount;
148 }
149
150 /* Horizontal retrace occurs as fast as possible */
151 VgaHorizontalRetrace();
152
153 /* Continue CPU emulation */
154 for (i = 0; VdmRunning && CpuRunning && (i < STEPS_PER_CYCLE); i++)
155 {
156 CpuStep();
157 #ifdef IPS_DISPLAY
158 ++Cycles;
159 #endif
160 }
161
162 #ifdef IPS_DISPLAY
163 if ((CurrentTickCount - LastCyclePrintout) >= 1000)
164 {
165 DPRINT1("NTVDM: %I64u Instructions Per Second; TimerTicks = %I64d\n", Cycles * 1000 / (CurrentTickCount - LastCyclePrintout), TimerTicks);
166 LastCyclePrintout = CurrentTickCount;
167 Cycles = 0;
168 }
169 #endif
170
171 }
172 }
173
174 BOOLEAN ClockInitialize(VOID)
175 {
176 /* Initialize the performance counter (needed for hardware timers) */
177 /* Find the starting performance */
178 NtQueryPerformanceCounter(&StartPerfCount, &Frequency);
179 if (Frequency.QuadPart == 0)
180 {
181 wprintf(L"FATAL: Performance counter not available\n");
182 return FALSE;
183 }
184
185 /* Find the starting tick count */
186 StartTickCount = GetTickCount();
187
188 /* Set the different last counts to the starting count */
189 LastClockUpdate = LastVerticalRefresh =
190 #ifdef IPS_DISPLAY
191 LastCyclePrintout =
192 #endif
193 StartTickCount;
194
195 /* Set the last timer ticks to the current time */
196 LastTimerTick = LastRtcTick = StartPerfCount;
197
198 return TRUE;
199 }