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/timer.h"
22 #include "hardware/vga.h"
24 /* DEFINES ********************************************************************/
27 * Activate IPS_DISPLAY if you want to display the
28 * number of instructions per second, as well as
29 * the computed number of ticks for the PIT.
31 // #define IPS_DISPLAY
34 * Activate WORKING_TIMER when the PIT timing problem is fixed.
36 // #define WORKING_TIMER
40 #define STEPS_PER_CYCLE 256
41 #define IRQ1_CYCLES 16
42 #define IRQ12_CYCLES 16
44 /* VARIABLES ******************************************************************/
46 LARGE_INTEGER StartPerfCount
, Frequency
;
48 LARGE_INTEGER LastTimerTick
, LastRtcTick
, Counter
;
50 DWORD StartTickCount
, CurrentTickCount
;
51 DWORD LastClockUpdate
;
52 DWORD LastVerticalRefresh
;
55 UINT Irq12Counter
= 0;
58 DWORD LastCyclePrintout
;
62 /* PUBLIC FUNCTIONS ***********************************************************/
64 VOID
ClockUpdate(VOID
)
66 extern BOOLEAN CpuRunning
;
70 DWORD PitResolution
= PitGetResolution();
72 DWORD RtcFrequency
= RtcGetTicksPerSecond();
74 /* Get the current number of ticks */
75 CurrentTickCount
= GetTickCount();
78 if ((PitResolution
<= 1000) && (RtcFrequency
<= 1000))
80 /* Calculate the approximate performance counter value instead */
81 Counter
.QuadPart
= StartPerfCount
.QuadPart
82 + (CurrentTickCount
- StartTickCount
)
83 * (Frequency
.QuadPart
/ 1000);
88 /* Get the current performance counter value */
89 QueryPerformanceCounter(&Counter
);
92 /* Get the number of PIT ticks that have passed */
93 TimerTicks
= ((Counter
.QuadPart
- LastTimerTick
.QuadPart
)
94 * PIT_BASE_FREQUENCY
) / Frequency
.QuadPart
;
100 LastTimerTick
= Counter
;
103 /* Check for RTC update */
104 if ((CurrentTickCount
- LastClockUpdate
) >= 1000)
107 LastClockUpdate
= CurrentTickCount
;
110 /* Check for RTC periodic tick */
111 if ((Counter
.QuadPart
- LastRtcTick
.QuadPart
)
112 >= (Frequency
.QuadPart
/ (LONGLONG
)RtcFrequency
))
115 LastRtcTick
= Counter
;
118 /* Check for vertical retrace */
119 if ((CurrentTickCount
- LastVerticalRefresh
) >= 15)
122 LastVerticalRefresh
= CurrentTickCount
;
125 if (++Irq1Counter
== IRQ1_CYCLES
)
131 if (++Irq12Counter
== IRQ12_CYCLES
)
137 /* Horizontal retrace occurs as fast as possible */
138 VgaHorizontalRetrace();
140 /* Continue CPU emulation */
141 for (i
= 0; VdmRunning
&& CpuRunning
&& (i
< STEPS_PER_CYCLE
); i
++)
150 if ((CurrentTickCount
- LastCyclePrintout
) >= 1000)
152 DPRINT1("NTVDM: %I64u Instructions Per Second; TimerTicks = %I64d\n", Cycles
* 1000 / (CurrentTickCount
- LastCyclePrintout
), TimerTicks
);
153 LastCyclePrintout
= CurrentTickCount
;
159 BOOLEAN
ClockInitialize(VOID
)
161 /* Initialize the performance counter (needed for hardware timers) */
162 if (!QueryPerformanceFrequency(&Frequency
))
164 wprintf(L
"FATAL: Performance counter not available\n");
168 /* Find the starting performance and tick count */
169 StartTickCount
= GetTickCount();
170 QueryPerformanceCounter(&StartPerfCount
);
172 /* Set the different last counts to the starting count */
173 LastClockUpdate
= LastVerticalRefresh
=
179 /* Set the last timer ticks to the current time */
180 LastTimerTick
= LastRtcTick
= StartPerfCount
;