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 *******************************************************************/
18 #include "hardware/cmos.h"
19 #include "hardware/ps2.h"
20 #include "hardware/timer.h"
21 #include "hardware/vga.h"
23 /* DEFINES ********************************************************************/
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.
30 // #define IPS_DISPLAY
33 * Activate WORKING_TIMER when the PIT timing problem is fixed.
35 // #define WORKING_TIMER
39 #define STEPS_PER_CYCLE 256
40 #define KBD_INT_CYCLES 16
42 /* VARIABLES ******************************************************************/
44 LARGE_INTEGER StartPerfCount
, Frequency
;
46 LARGE_INTEGER LastTimerTick
, LastRtcTick
, Counter
;
48 DWORD StartTickCount
, CurrentTickCount
;
49 DWORD LastClockUpdate
;
50 DWORD LastVerticalRefresh
;
51 INT KeyboardIntCounter
= 0;
54 DWORD LastCyclePrintout
;
58 /* PUBLIC FUNCTIONS ***********************************************************/
60 VOID
ClockUpdate(VOID
)
62 extern BOOLEAN CpuSimulate
;
66 DWORD PitResolution
= PitGetResolution();
68 DWORD RtcFrequency
= RtcGetTicksPerSecond();
70 /* Get the current number of ticks */
71 CurrentTickCount
= GetTickCount();
74 if ((PitResolution
<= 1000) && (RtcFrequency
<= 1000))
76 /* Calculate the approximate performance counter value instead */
77 Counter
.QuadPart
= StartPerfCount
.QuadPart
78 + (CurrentTickCount
- StartTickCount
)
79 * (Frequency
.QuadPart
/ 1000);
84 /* Get the current performance counter value */
85 QueryPerformanceCounter(&Counter
);
88 /* Get the number of PIT ticks that have passed */
89 TimerTicks
= ((Counter
.QuadPart
- LastTimerTick
.QuadPart
)
90 * PIT_BASE_FREQUENCY
) / Frequency
.QuadPart
;
96 LastTimerTick
= Counter
;
99 /* Check for RTC update */
100 if ((CurrentTickCount
- LastClockUpdate
) >= 1000)
103 LastClockUpdate
= CurrentTickCount
;
106 /* Check for RTC periodic tick */
107 if ((Counter
.QuadPart
- LastRtcTick
.QuadPart
)
108 >= (Frequency
.QuadPart
/ (LONGLONG
)RtcFrequency
))
111 LastRtcTick
= Counter
;
114 /* Check for vertical retrace */
115 if ((CurrentTickCount
- LastVerticalRefresh
) >= 15)
118 LastVerticalRefresh
= CurrentTickCount
;
121 if (++KeyboardIntCounter
== KBD_INT_CYCLES
)
123 GenerateKeyboardInterrupts();
124 KeyboardIntCounter
= 0;
127 /* Horizontal retrace occurs as fast as possible */
128 VgaHorizontalRetrace();
130 /* Continue CPU emulation */
131 for (i
= 0; VdmRunning
&& CpuSimulate
&& (i
< STEPS_PER_CYCLE
); i
++)
140 if ((CurrentTickCount
- LastCyclePrintout
) >= 1000)
142 DPRINT1("NTVDM: %lu Instructions Per Second; TimerTicks = %I64d\n", Cycles
, TimerTicks
);
143 LastCyclePrintout
= CurrentTickCount
;
149 BOOLEAN
ClockInitialize(VOID
)
151 /* Initialize the performance counter (needed for hardware timers) */
152 if (!QueryPerformanceFrequency(&Frequency
))
154 wprintf(L
"FATAL: Performance counter not available\n");
158 /* Find the starting performance and tick count */
159 StartTickCount
= GetTickCount();
160 QueryPerformanceCounter(&StartPerfCount
);
162 /* Set the different last counts to the starting count */
163 LastClockUpdate
= LastVerticalRefresh
=
169 /* Set the last timer ticks to the current time */
170 LastTimerTick
= LastRtcTick
= StartPerfCount
;