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 *******************************************************************/
23 * Activate this line if you want to be able to test NTVDM with:
28 /* PUBLIC VARIABLES ***********************************************************/
30 BOOLEAN VdmRunning
= TRUE
;
31 LPVOID BaseAddress
= NULL
;
32 LPCWSTR ExceptionName
[] =
39 L
"Bound Range Exceeded",
44 /* PUBLIC FUNCTIONS ***********************************************************/
46 VOID
DisplayMessage(LPCWSTR Format
, ...)
51 va_start(Parameters
, Format
);
52 _vsnwprintf(Buffer
, 256, Format
, Parameters
);
53 MessageBoxW(NULL
, Buffer
, L
"NTVDM Subsystem", MB_OK
);
57 BOOL WINAPI
ConsoleCtrlHandler(DWORD ControlType
)
62 case CTRL_BREAK_EVENT
:
64 /* Perform interrupt 0x23 */
65 EmulatorInterrupt(0x23);
70 /* Stop the VDM if the user logs out or closes the console */
77 INT
wmain(INT argc
, WCHAR
*argv
[])
80 CHAR CommandLine
[DOS_CMDLINE_LENGTH
];
81 DWORD CurrentTickCount
;
83 DWORD LastCyclePrintout
= GetTickCount();
84 DWORD LastVerticalRefresh
= GetTickCount();
85 LARGE_INTEGER Frequency
, LastTimerTick
, Counter
;
87 HANDLE InputThread
= NULL
;
89 /* Set the handler routine */
90 SetConsoleCtrlHandler(ConsoleCtrlHandler
, TRUE
);
93 UNREFERENCED_PARAMETER(argc
);
94 UNREFERENCED_PARAMETER(argv
);
96 /* The DOS command line must be ASCII */
97 WideCharToMultiByte(CP_ACP
, 0, GetCommandLine(), -1, CommandLine
, sizeof(CommandLine
), NULL
, NULL
);
99 if (argc
== 2 && argv
[1] != NULL
)
101 WideCharToMultiByte(CP_ACP
, 0, argv
[1], -1, CommandLine
, sizeof(CommandLine
), NULL
, NULL
);
105 wprintf(L
"\nReactOS Virtual DOS Machine\n\n"
106 L
"Usage: NTVDM <executable>\n");
111 if (!EmulatorInitialize())
113 wprintf(L
"FATAL: Failed to initialize the CPU emulator\n");
117 /* Initialize the performance counter (needed for hardware timers) */
118 if (!QueryPerformanceFrequency(&Frequency
))
120 wprintf(L
"FATAL: Performance counter not available\n");
124 /* Initialize the system BIOS */
125 if (!BiosInitialize())
127 wprintf(L
"FATAL: Failed to initialize the VDM BIOS.\n");
131 /* Initialize the VDM DOS kernel */
132 if (!DosInitialize())
134 wprintf(L
"FATAL: Failed to initialize the VDM DOS kernel.\n");
138 /* Start the process from the command line */
139 if (!DosCreateProcess(CommandLine
, 0))
141 DisplayMessage(L
"Could not start program: %S", CommandLine
);
145 /* Start the input thread */
146 InputThread
= CreateThread(NULL
, 0, &InputThreadProc
, NULL
, 0, NULL
);
148 /* Set the last timer tick to the current time */
149 QueryPerformanceCounter(&LastTimerTick
);
154 /* Get the resolution of the system timer */
155 DWORD TimerResolution
= PitGetResolution();
157 /* Get the current number of ticks */
158 CurrentTickCount
= GetTickCount();
160 if (TimerResolution
> 1000)
162 /* Get the current performance counter value */
163 QueryPerformanceCounter(&Counter
);
165 /* Get the number of PIT ticks that have passed */
166 TimerTicks
= ((Counter
.QuadPart
- LastTimerTick
.QuadPart
)
167 * PIT_BASE_FREQUENCY
) / Frequency
.QuadPart
;
171 /* Use the standard tick count */
172 Counter
.QuadPart
= CurrentTickCount
;
174 /* Get the number of PIT ticks that have passed */
175 TimerTicks
= ((Counter
.QuadPart
- LastTimerTick
.QuadPart
)
176 * PIT_BASE_FREQUENCY
) / 1000;
182 for (i
= 0; i
< TimerTicks
; i
++) PitDecrementCount();
183 LastTimerTick
= Counter
;
186 /* Check for vertical retrace */
187 if ((CurrentTickCount
- LastVerticalRefresh
) >= 16)
190 LastVerticalRefresh
= CurrentTickCount
;
193 /* Horizontal retrace occurs as fast as possible */
194 VgaHorizontalRetrace();
196 /* Continue CPU emulation */
197 for (i
= 0; (i
< STEPS_PER_CYCLE
) && VdmRunning
; i
++)
203 if ((CurrentTickCount
- LastCyclePrintout
) >= 1000)
205 DPRINT1("NTVDM: %lu Instructions Per Second\n", Cycles
);
206 LastCyclePrintout
= CurrentTickCount
;
211 /* Perform another screen refresh */
215 if (InputThread
!= NULL
) CloseHandle(InputThread
);