2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: Virtual DOS Machine
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
16 #include "bios/bios.h"
17 #include "hardware/cmos.h"
18 #include "hardware/pic.h"
19 #include "hardware/ps2.h"
20 #include "hardware/speaker.h"
21 #include "hardware/timer.h"
22 #include "hardware/vga.h"
26 * Activate this line if you want to be able to test NTVDM with:
31 /* PUBLIC VARIABLES ***********************************************************/
33 BOOLEAN VdmRunning
= TRUE
;
34 LPVOID BaseAddress
= NULL
;
36 /* PUBLIC FUNCTIONS ***********************************************************/
38 VOID
DisplayMessage(LPCWSTR Format
, ...)
43 va_start(Parameters
, Format
);
44 _vsnwprintf(Buffer
, 256, Format
, Parameters
);
45 DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer
);
46 MessageBoxW(NULL
, Buffer
, L
"NTVDM Subsystem", MB_OK
);
50 BOOL WINAPI
ConsoleCtrlHandler(DWORD ControlType
)
55 case CTRL_BREAK_EVENT
:
57 /* Perform interrupt 0x23 */
58 EmulatorInterrupt(0x23);
63 /* Stop the VDM if the user logs out or closes the console */
70 INT
wmain(INT argc
, WCHAR
*argv
[])
73 CHAR CommandLine
[DOS_CMDLINE_LENGTH
];
74 LARGE_INTEGER StartPerfCount
;
75 LARGE_INTEGER Frequency
, LastTimerTick
, LastRtcTick
, Counter
;
77 DWORD StartTickCount
, CurrentTickCount
;
78 DWORD LastClockUpdate
;
79 DWORD LastVerticalRefresh
;
80 DWORD LastCyclePrintout
;
82 INT KeyboardIntCounter
= 0;
84 /* Set the handler routine */
85 SetConsoleCtrlHandler(ConsoleCtrlHandler
, TRUE
);
88 UNREFERENCED_PARAMETER(argc
);
89 UNREFERENCED_PARAMETER(argv
);
91 /* The DOS command line must be ASCII */
92 WideCharToMultiByte(CP_ACP
, 0, GetCommandLine(), -1, CommandLine
, sizeof(CommandLine
), NULL
, NULL
);
94 if (argc
== 2 && argv
[1] != NULL
)
96 WideCharToMultiByte(CP_ACP
, 0, argv
[1], -1, CommandLine
, sizeof(CommandLine
), NULL
, NULL
);
100 wprintf(L
"\nReactOS Virtual DOS Machine\n\n"
101 L
"Usage: NTVDM <executable>\n");
106 DPRINT1("\n\n\nNTVDM - Starting '%s'...\n\n\n", CommandLine
);
108 /* Initialize the emulator */
109 if (!EmulatorInitialize())
111 wprintf(L
"FATAL: Failed to initialize the CPU emulator\n");
115 /* Initialize the performance counter (needed for hardware timers) */
116 if (!QueryPerformanceFrequency(&Frequency
))
118 wprintf(L
"FATAL: Performance counter not available\n");
122 /* Initialize the PIC */
123 if (!PicInitialize())
125 wprintf(L
"FATAL: Failed to initialize the PIC.\n");
129 /* Initialize the PIT */
130 if (!PitInitialize())
132 wprintf(L
"FATAL: Failed to initialize the PIT.\n");
136 /* Initialize the CMOS */
137 if (!CmosInitialize())
139 wprintf(L
"FATAL: Failed to initialize the VDM CMOS.\n");
143 /* Initialize the PC Speaker */
152 /* Initialize the system BIOS */
153 if (!BiosInitialize())
155 wprintf(L
"FATAL: Failed to initialize the VDM BIOS.\n");
159 /* Initialize the VDM DOS kernel */
160 if (!DosInitialize())
162 wprintf(L
"FATAL: Failed to initialize the VDM DOS kernel.\n");
166 /* Start the process from the command line */
167 if (!DosCreateProcess(CommandLine
, 0))
169 DisplayMessage(L
"Could not start program: %S", CommandLine
);
173 /* Find the starting performance and tick count */
174 StartTickCount
= GetTickCount();
175 QueryPerformanceCounter(&StartPerfCount
);
177 /* Set the different last counts to the starting count */
178 LastClockUpdate
= LastVerticalRefresh
= LastCyclePrintout
= StartTickCount
;
180 /* Set the last timer ticks to the current time */
181 LastTimerTick
= LastRtcTick
= StartPerfCount
;
186 DWORD PitResolution
= PitGetResolution();
187 DWORD RtcFrequency
= RtcGetTicksPerSecond();
189 /* Get the current number of ticks */
190 CurrentTickCount
= GetTickCount();
192 if ((PitResolution
<= 1000) && (RtcFrequency
<= 1000))
194 /* Calculate the approximate performance counter value instead */
195 Counter
.QuadPart
= StartPerfCount
.QuadPart
196 + (CurrentTickCount
- StartTickCount
)
197 * (Frequency
.QuadPart
/ 1000);
201 /* Get the current performance counter value */
202 QueryPerformanceCounter(&Counter
);
205 /* Get the number of PIT ticks that have passed */
206 TimerTicks
= ((Counter
.QuadPart
- LastTimerTick
.QuadPart
)
207 * PIT_BASE_FREQUENCY
) / Frequency
.QuadPart
;
212 PitDecrementCount(TimerTicks
);
213 LastTimerTick
= Counter
;
216 /* Check for RTC update */
217 if ((CurrentTickCount
- LastClockUpdate
) >= 1000)
220 LastClockUpdate
= CurrentTickCount
;
223 /* Check for RTC periodic tick */
224 if ((Counter
.QuadPart
- LastRtcTick
.QuadPart
)
225 >= (Frequency
.QuadPart
/ (LONGLONG
)RtcFrequency
))
228 LastRtcTick
= Counter
;
231 /* Check for vertical retrace */
232 if ((CurrentTickCount
- LastVerticalRefresh
) >= 15)
235 LastVerticalRefresh
= CurrentTickCount
;
238 KeyboardIntCounter
++;
239 if (KeyboardIntCounter
== KBD_INT_CYCLES
)
241 GenerateKeyboardInterrupts();
242 KeyboardIntCounter
= 0;
245 /* Horizontal retrace occurs as fast as possible */
246 VgaHorizontalRetrace();
248 /* Continue CPU emulation */
249 for (i
= 0; (i
< STEPS_PER_CYCLE
) && VdmRunning
; i
++)
255 if ((CurrentTickCount
- LastCyclePrintout
) >= 1000)
257 DPRINT1("NTVDM: %lu Instructions Per Second\n", Cycles
);
258 LastCyclePrintout
= CurrentTickCount
;
263 /* Perform another screen refresh */
272 DPRINT1("\n\n\nNTVDM - Exiting...\n\n\n");