[REACTOS]
[reactos.git] / reactos / subsystems / 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
16 // #include "clock.h"
17
18 #include "hardware/cmos.h"
19 #include "hardware/ps2.h"
20 #include "hardware/timer.h"
21 #include "hardware/vga.h"
22
23 /* DEFINES ********************************************************************/
24
25 /*
26 * Activate IPS_DISPLAY if you want to display the
27 * number of instructions per second, as well as
28 * the computed number of ticks for the PIT.
29 */
30 // #define IPS_DISPLAY
31
32 /*
33 * Activate WORKING_TIMER when the PIT timing problem is fixed.
34 */
35 // #define WORKING_TIMER
36
37
38 /* Processor speed */
39 #define STEPS_PER_CYCLE 256
40 #define KBD_INT_CYCLES 16
41
42 /* VARIABLES ******************************************************************/
43
44 LARGE_INTEGER StartPerfCount, Frequency;
45
46 LARGE_INTEGER LastTimerTick, LastRtcTick, Counter;
47 LONGLONG TimerTicks;
48 DWORD StartTickCount, CurrentTickCount;
49 DWORD LastClockUpdate;
50 DWORD LastVerticalRefresh;
51 INT KeyboardIntCounter = 0;
52
53 #ifdef IPS_DISPLAY
54 DWORD LastCyclePrintout;
55 DWORD Cycles = 0;
56 #endif
57
58 /* PUBLIC FUNCTIONS ***********************************************************/
59
60 VOID ClockUpdate(VOID)
61 {
62 extern BOOLEAN CpuSimulate;
63 UINT i;
64
65 #ifdef WORKING_TIMER
66 DWORD PitResolution = PitGetResolution();
67 #endif
68 DWORD RtcFrequency = RtcGetTicksPerSecond();
69
70 /* Get the current number of ticks */
71 CurrentTickCount = GetTickCount();
72
73 #ifdef WORKING_TIMER
74 if ((PitResolution <= 1000) && (RtcFrequency <= 1000))
75 {
76 /* Calculate the approximate performance counter value instead */
77 Counter.QuadPart = StartPerfCount.QuadPart
78 + (CurrentTickCount - StartTickCount)
79 * (Frequency.QuadPart / 1000);
80 }
81 else
82 #endif
83 {
84 /* Get the current performance counter value */
85 QueryPerformanceCounter(&Counter);
86 }
87
88 /* Get the number of PIT ticks that have passed */
89 TimerTicks = ((Counter.QuadPart - LastTimerTick.QuadPart)
90 * PIT_BASE_FREQUENCY) / Frequency.QuadPart;
91
92 /* Update the PIT */
93 if (TimerTicks > 0)
94 {
95 PitClock(TimerTicks);
96 LastTimerTick = Counter;
97 }
98
99 /* Check for RTC update */
100 if ((CurrentTickCount - LastClockUpdate) >= 1000)
101 {
102 RtcTimeUpdate();
103 LastClockUpdate = CurrentTickCount;
104 }
105
106 /* Check for RTC periodic tick */
107 if ((Counter.QuadPart - LastRtcTick.QuadPart)
108 >= (Frequency.QuadPart / (LONGLONG)RtcFrequency))
109 {
110 RtcPeriodicTick();
111 LastRtcTick = Counter;
112 }
113
114 /* Check for vertical retrace */
115 if ((CurrentTickCount - LastVerticalRefresh) >= 15)
116 {
117 VgaRefreshDisplay();
118 LastVerticalRefresh = CurrentTickCount;
119 }
120
121 if (++KeyboardIntCounter == KBD_INT_CYCLES)
122 {
123 GenerateKeyboardInterrupts();
124 KeyboardIntCounter = 0;
125 }
126
127 /* Horizontal retrace occurs as fast as possible */
128 VgaHorizontalRetrace();
129
130 /* Continue CPU emulation */
131 for (i = 0; VdmRunning && CpuSimulate && (i < STEPS_PER_CYCLE); i++)
132 {
133 EmulatorStep();
134 #ifdef IPS_DISPLAY
135 Cycles++;
136 #endif
137 }
138
139 #ifdef IPS_DISPLAY
140 if ((CurrentTickCount - LastCyclePrintout) >= 1000)
141 {
142 DPRINT1("NTVDM: %lu Instructions Per Second; TimerTicks = %I64d\n", Cycles, TimerTicks);
143 LastCyclePrintout = CurrentTickCount;
144 Cycles = 0;
145 }
146 #endif
147 }
148
149 BOOLEAN ClockInitialize(VOID)
150 {
151 /* Initialize the performance counter (needed for hardware timers) */
152 if (!QueryPerformanceFrequency(&Frequency))
153 {
154 wprintf(L"FATAL: Performance counter not available\n");
155 return FALSE;
156 }
157
158 /* Find the starting performance and tick count */
159 StartTickCount = GetTickCount();
160 QueryPerformanceCounter(&StartPerfCount);
161
162 /* Set the different last counts to the starting count */
163 LastClockUpdate = LastVerticalRefresh =
164 #ifdef IPS_DISPLAY
165 LastCyclePrintout =
166 #endif
167 StartTickCount;
168
169 /* Set the last timer ticks to the current time */
170 LastTimerTick = LastRtcTick = StartPerfCount;
171
172 return TRUE;
173 }