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 *******************************************************************/
25 * Activate this line if you want to be able to test NTVDM with:
30 /* PUBLIC VARIABLES ***********************************************************/
32 BOOLEAN VdmRunning
= TRUE
;
33 LPVOID BaseAddress
= NULL
;
35 /* PUBLIC FUNCTIONS ***********************************************************/
37 VOID
DisplayMessage(LPCWSTR Format
, ...)
42 va_start(Parameters
, Format
);
43 _vsnwprintf(Buffer
, 256, Format
, Parameters
);
44 DPRINT1("\n\nNTVDM Subsystem\n%S\n\n", Buffer
);
45 MessageBoxW(NULL
, Buffer
, L
"NTVDM Subsystem", MB_OK
);
49 BOOL WINAPI
ConsoleCtrlHandler(DWORD ControlType
)
54 case CTRL_BREAK_EVENT
:
56 /* Perform interrupt 0x23 */
57 EmulatorInterrupt(0x23);
62 /* Stop the VDM if the user logs out or closes the console */
69 INT
wmain(INT argc
, WCHAR
*argv
[])
72 CHAR CommandLine
[DOS_CMDLINE_LENGTH
];
73 DWORD CurrentTickCount
;
75 DWORD LastCyclePrintout
= GetTickCount();
76 DWORD LastVerticalRefresh
= GetTickCount();
77 DWORD LastClockUpdate
= GetTickCount();
78 LARGE_INTEGER Frequency
, LastTimerTick
, LastRtcTick
, Counter
;
80 LARGE_INTEGER StartPerfCount
;
83 /* Set the handler routine */
84 SetConsoleCtrlHandler(ConsoleCtrlHandler
, TRUE
);
87 UNREFERENCED_PARAMETER(argc
);
88 UNREFERENCED_PARAMETER(argv
);
90 /* The DOS command line must be ASCII */
91 WideCharToMultiByte(CP_ACP
, 0, GetCommandLine(), -1, CommandLine
, sizeof(CommandLine
), NULL
, NULL
);
93 if (argc
== 2 && argv
[1] != NULL
)
95 WideCharToMultiByte(CP_ACP
, 0, argv
[1], -1, CommandLine
, sizeof(CommandLine
), NULL
, NULL
);
99 wprintf(L
"\nReactOS Virtual DOS Machine\n\n"
100 L
"Usage: NTVDM <executable>\n");
105 DPRINT1("\n\n\nNTVDM - Starting '%s'...\n\n\n", CommandLine
);
107 if (!EmulatorInitialize())
109 wprintf(L
"FATAL: Failed to initialize the CPU emulator\n");
113 /* Initialize the performance counter (needed for hardware timers) */
114 if (!QueryPerformanceFrequency(&Frequency
))
116 wprintf(L
"FATAL: Performance counter not available\n");
120 /* Initialize the CMOS */
121 if (!CmosInitialize())
123 wprintf(L
"FATAL: Failed to initialize the VDM CMOS.\n");
127 /* Initialize the system BIOS */
128 if (!BiosInitialize())
130 wprintf(L
"FATAL: Failed to initialize the VDM BIOS.\n");
134 /* Initialize the PC Speaker */
137 /* Initialize the VDM DOS kernel */
138 if (!DosInitialize())
140 wprintf(L
"FATAL: Failed to initialize the VDM DOS kernel.\n");
144 /* Start the process from the command line */
145 if (!DosCreateProcess(CommandLine
, 0))
147 DisplayMessage(L
"Could not start program: %S", CommandLine
);
151 /* Find the starting performance and tick count */
152 StartTickCount
= GetTickCount();
153 QueryPerformanceCounter(&StartPerfCount
);
155 /* Set the last timer ticks to the current time */
156 LastTimerTick
= LastRtcTick
= StartPerfCount
;
161 DWORD PitResolution
= PitGetResolution();
162 DWORD RtcFrequency
= RtcGetTicksPerSecond();
164 /* Get the current number of ticks */
165 CurrentTickCount
= GetTickCount();
167 if ((PitResolution
<= 1000) && (RtcFrequency
<= 1000))
169 /* Calculate the approximate performance counter value instead */
170 Counter
.QuadPart
= StartPerfCount
.QuadPart
171 + (CurrentTickCount
- StartTickCount
)
172 * (Frequency
.QuadPart
/ 1000);
176 /* Get the current performance counter value */
177 QueryPerformanceCounter(&Counter
);
180 /* Get the number of PIT ticks that have passed */
181 TimerTicks
= ((Counter
.QuadPart
- LastTimerTick
.QuadPart
)
182 * PIT_BASE_FREQUENCY
) / Frequency
.QuadPart
;
187 PitDecrementCount(TimerTicks
);
188 LastTimerTick
= Counter
;
191 /* Check for RTC update */
192 if ((CurrentTickCount
- LastClockUpdate
) >= 1000)
195 LastClockUpdate
= CurrentTickCount
;
198 /* Check for RTC periodic tick */
199 if ((Counter
.QuadPart
- LastRtcTick
.QuadPart
)
200 >= (Frequency
.QuadPart
/ (LONGLONG
)RtcFrequency
))
203 LastRtcTick
= Counter
;
206 /* Check for vertical retrace */
207 if ((CurrentTickCount
- LastVerticalRefresh
) >= 16)
210 LastVerticalRefresh
= CurrentTickCount
;
213 /* Horizontal retrace occurs as fast as possible */
214 VgaHorizontalRetrace();
216 /* Continue CPU emulation */
217 for (i
= 0; (i
< STEPS_PER_CYCLE
) && VdmRunning
; i
++)
223 if ((CurrentTickCount
- LastCyclePrintout
) >= 1000)
225 DPRINT1("NTVDM: %lu Instructions Per Second\n", Cycles
);
226 LastCyclePrintout
= CurrentTickCount
;
231 /* Perform another screen refresh */
240 DPRINT1("\n\n\nNTVDM - Exiting...\n\n\n");