1c2c66affSColin Finck /*
2c2c66affSColin Finck * COPYRIGHT: GPL - See COPYING in the top level directory
3c2c66affSColin Finck * PROJECT: ReactOS Virtual DOS Machine
4c2c66affSColin Finck * FILE: subsystems/mvdm/ntvdm/emulator.c
5c2c66affSColin Finck * PURPOSE: Minimal x86 machine emulator for the VDM
6c2c66affSColin Finck * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7c2c66affSColin Finck */
8c2c66affSColin Finck
9c2c66affSColin Finck /* INCLUDES *******************************************************************/
10c2c66affSColin Finck
11c2c66affSColin Finck #include "ntvdm.h"
12c2c66affSColin Finck
13c2c66affSColin Finck #define NDEBUG
14c2c66affSColin Finck #include <debug.h>
15c2c66affSColin Finck
16c2c66affSColin Finck #include "emulator.h"
17c2c66affSColin Finck #include "memory.h"
18c2c66affSColin Finck
19c2c66affSColin Finck #include "cpu/callback.h"
20c2c66affSColin Finck #include "cpu/cpu.h"
21c2c66affSColin Finck #include "cpu/bop.h"
22c2c66affSColin Finck #include <isvbop.h>
23c2c66affSColin Finck
24c2c66affSColin Finck #include "int32.h"
25c2c66affSColin Finck
26c2c66affSColin Finck #include "clock.h"
27c2c66affSColin Finck #include "bios/rom.h"
28c2c66affSColin Finck #include "hardware/cmos.h"
29c2c66affSColin Finck #include "hardware/disk.h"
30c2c66affSColin Finck #include "hardware/dma.h"
31c2c66affSColin Finck #include "hardware/keyboard.h"
32c2c66affSColin Finck #include "hardware/mouse.h"
33c2c66affSColin Finck #include "hardware/pic.h"
34c2c66affSColin Finck #include "hardware/pit.h"
35c2c66affSColin Finck #include "hardware/ppi.h"
36c2c66affSColin Finck #include "hardware/ps2.h"
37c2c66affSColin Finck #include "hardware/sound/speaker.h"
38c2c66affSColin Finck #include "hardware/video/svga.h"
39c2c66affSColin Finck /**/
40c2c66affSColin Finck #include "./console/video.h"
41c2c66affSColin Finck /**/
42c2c66affSColin Finck
43c2c66affSColin Finck #include "vddsup.h"
44c2c66affSColin Finck #include "io.h"
45c2c66affSColin Finck
46c2c66affSColin Finck /* PRIVATE VARIABLES **********************************************************/
47c2c66affSColin Finck
48c2c66affSColin Finck LPVOID BaseAddress = NULL;
49c2c66affSColin Finck BOOLEAN VdmRunning = TRUE;
50c2c66affSColin Finck
51c2c66affSColin Finck HANDLE VdmTaskEvent = NULL;
52c2c66affSColin Finck static HANDLE InputThread = NULL;
53c2c66affSColin Finck
54c2c66affSColin Finck LPCWSTR ExceptionName[] =
55c2c66affSColin Finck {
56c2c66affSColin Finck L"Division By Zero",
57c2c66affSColin Finck L"Debug",
58c2c66affSColin Finck L"Unexpected Error",
59c2c66affSColin Finck L"Breakpoint",
60c2c66affSColin Finck L"Integer Overflow",
61c2c66affSColin Finck L"Bound Range Exceeded",
62c2c66affSColin Finck L"Invalid Opcode",
63c2c66affSColin Finck L"FPU Not Available"
64c2c66affSColin Finck };
65c2c66affSColin Finck
66c2c66affSColin Finck /* BOP Identifiers */
67c2c66affSColin Finck #define BOP_DEBUGGER 0x56 // Break into the debugger from a 16-bit app
68c2c66affSColin Finck
69c2c66affSColin Finck /* PRIVATE FUNCTIONS **********************************************************/
70c2c66affSColin Finck
EmulatorIntAcknowledge(PFAST486_STATE State)71c2c66affSColin Finck UCHAR FASTCALL EmulatorIntAcknowledge(PFAST486_STATE State)
72c2c66affSColin Finck {
73c2c66affSColin Finck UNREFERENCED_PARAMETER(State);
74c2c66affSColin Finck
75c2c66affSColin Finck /* Get the interrupt number from the PIC */
76c2c66affSColin Finck return PicGetInterrupt();
77c2c66affSColin Finck }
78c2c66affSColin Finck
EmulatorFpu(PFAST486_STATE State)79c2c66affSColin Finck VOID FASTCALL EmulatorFpu(PFAST486_STATE State)
80c2c66affSColin Finck {
81c2c66affSColin Finck /* The FPU is wired to IRQ 13 */
82c2c66affSColin Finck PicInterruptRequest(13);
83c2c66affSColin Finck }
84c2c66affSColin Finck
EmulatorException(BYTE ExceptionNumber,LPWORD Stack)85c2c66affSColin Finck VOID EmulatorException(BYTE ExceptionNumber, LPWORD Stack)
86c2c66affSColin Finck {
87c2c66affSColin Finck WORD CodeSegment, InstructionPointer;
88c2c66affSColin Finck PBYTE Opcode;
89c2c66affSColin Finck
90c2c66affSColin Finck ASSERT(ExceptionNumber < 8);
91c2c66affSColin Finck
92c2c66affSColin Finck /* Get the CS:IP */
93c2c66affSColin Finck InstructionPointer = Stack[STACK_IP];
94c2c66affSColin Finck CodeSegment = Stack[STACK_CS];
95c2c66affSColin Finck Opcode = (PBYTE)SEG_OFF_TO_PTR(CodeSegment, InstructionPointer);
96c2c66affSColin Finck
97c2c66affSColin Finck /* Display a message to the user */
98c2c66affSColin Finck DisplayMessage(L"Exception: %s occurred at %04X:%04X\n"
99c2c66affSColin Finck L"Opcode: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
100c2c66affSColin Finck ExceptionName[ExceptionNumber],
101c2c66affSColin Finck CodeSegment,
102c2c66affSColin Finck InstructionPointer,
103c2c66affSColin Finck Opcode[0],
104c2c66affSColin Finck Opcode[1],
105c2c66affSColin Finck Opcode[2],
106c2c66affSColin Finck Opcode[3],
107c2c66affSColin Finck Opcode[4],
108c2c66affSColin Finck Opcode[5],
109c2c66affSColin Finck Opcode[6],
110c2c66affSColin Finck Opcode[7],
111c2c66affSColin Finck Opcode[8],
112c2c66affSColin Finck Opcode[9]);
113c2c66affSColin Finck
114c2c66affSColin Finck Fast486DumpState(&EmulatorContext);
115c2c66affSColin Finck
116c2c66affSColin Finck /* Stop the VDM */
117c2c66affSColin Finck EmulatorTerminate();
118c2c66affSColin Finck }
119c2c66affSColin Finck
EmulatorInterruptSignal(VOID)120c2c66affSColin Finck VOID EmulatorInterruptSignal(VOID)
121c2c66affSColin Finck {
122c2c66affSColin Finck /* Call the Fast486 API */
123c2c66affSColin Finck Fast486InterruptSignal(&EmulatorContext);
124c2c66affSColin Finck }
125c2c66affSColin Finck
EmulatorDebugBreakBop(LPWORD Stack)126c2c66affSColin Finck static VOID WINAPI EmulatorDebugBreakBop(LPWORD Stack)
127c2c66affSColin Finck {
128c2c66affSColin Finck DPRINT1("NTVDM: BOP_DEBUGGER\n");
129c2c66affSColin Finck DebugBreak();
130c2c66affSColin Finck }
131c2c66affSColin Finck
PitChan0Out(LPVOID Param,BOOLEAN State)132c2c66affSColin Finck static VOID WINAPI PitChan0Out(LPVOID Param, BOOLEAN State)
133c2c66affSColin Finck {
134c2c66affSColin Finck if (State)
135c2c66affSColin Finck {
136c2c66affSColin Finck DPRINT("PicInterruptRequest\n");
137c2c66affSColin Finck PicInterruptRequest(0); // Raise IRQ 0
138c2c66affSColin Finck }
139c2c66affSColin Finck // else < Lower IRQ 0 >
140c2c66affSColin Finck }
141c2c66affSColin Finck
PitChan1Out(LPVOID Param,BOOLEAN State)142c2c66affSColin Finck static VOID WINAPI PitChan1Out(LPVOID Param, BOOLEAN State)
143c2c66affSColin Finck {
144c2c66affSColin Finck #if 0
145c2c66affSColin Finck if (State)
146c2c66affSColin Finck {
147c2c66affSColin Finck /* Set bit 4 of Port 61h */
148c2c66affSColin Finck Port61hState |= 1 << 4;
149c2c66affSColin Finck }
150c2c66affSColin Finck else
151c2c66affSColin Finck {
152c2c66affSColin Finck /* Clear bit 4 of Port 61h */
153c2c66affSColin Finck Port61hState &= ~(1 << 4);
154c2c66affSColin Finck }
155c2c66affSColin Finck #else
156c2c66affSColin Finck Port61hState = (Port61hState & 0xEF) | (State << 4);
157c2c66affSColin Finck #endif
158c2c66affSColin Finck }
159c2c66affSColin Finck
PitChan2Out(LPVOID Param,BOOLEAN State)160c2c66affSColin Finck static VOID WINAPI PitChan2Out(LPVOID Param, BOOLEAN State)
161c2c66affSColin Finck {
162c2c66affSColin Finck BYTE OldPort61hState = Port61hState;
163c2c66affSColin Finck
164c2c66affSColin Finck #if 0
165c2c66affSColin Finck if (State)
166c2c66affSColin Finck {
167c2c66affSColin Finck /* Set bit 5 of Port 61h */
168c2c66affSColin Finck Port61hState |= 1 << 5;
169c2c66affSColin Finck }
170c2c66affSColin Finck else
171c2c66affSColin Finck {
172c2c66affSColin Finck /* Clear bit 5 of Port 61h */
173c2c66affSColin Finck Port61hState &= ~(1 << 5);
174c2c66affSColin Finck }
175c2c66affSColin Finck #else
176c2c66affSColin Finck Port61hState = (Port61hState & 0xDF) | (State << 5);
177c2c66affSColin Finck #endif
178c2c66affSColin Finck
179c2c66affSColin Finck if ((OldPort61hState ^ Port61hState) & 0x20)
180c2c66affSColin Finck {
181c2c66affSColin Finck DPRINT("PitChan2Out -- Port61hState changed\n");
182c2c66affSColin Finck SpeakerChange(Port61hState);
183c2c66affSColin Finck }
184c2c66affSColin Finck }
185c2c66affSColin Finck
186c2c66affSColin Finck
187c2c66affSColin Finck static DWORD
188c2c66affSColin Finck WINAPI
ConsoleEventThread(LPVOID Parameter)189c2c66affSColin Finck ConsoleEventThread(LPVOID Parameter)
190c2c66affSColin Finck {
191c2c66affSColin Finck HANDLE ConsoleInput = (HANDLE)Parameter;
192c2c66affSColin Finck HANDLE WaitHandles[2];
193c2c66affSColin Finck DWORD WaitResult;
194c2c66affSColin Finck
195c2c66affSColin Finck /*
196c2c66affSColin Finck * For optimization purposes, Windows (and hence ReactOS, too, for
197c2c66affSColin Finck * compatibility reasons) uses a static buffer if no more than five
198c2c66affSColin Finck * input records are read. Otherwise a new buffer is used.
199c2c66affSColin Finck * The client-side expects that we know this behaviour.
200c2c66affSColin Finck * See consrv/coninput.c
201c2c66affSColin Finck *
202c2c66affSColin Finck * We exploit here this optimization by also using a buffer of 5 records.
203c2c66affSColin Finck */
204c2c66affSColin Finck INPUT_RECORD InputRecords[5];
205c2c66affSColin Finck ULONG NumRecords, i;
206c2c66affSColin Finck
207c2c66affSColin Finck WaitHandles[0] = VdmTaskEvent;
208c2c66affSColin Finck WaitHandles[1] = GetConsoleInputWaitHandle();
209c2c66affSColin Finck
210c2c66affSColin Finck while (VdmRunning)
211c2c66affSColin Finck {
212c2c66affSColin Finck /* Make sure the task event is signaled */
213c2c66affSColin Finck WaitResult = WaitForMultipleObjects(ARRAYSIZE(WaitHandles),
214c2c66affSColin Finck WaitHandles,
215c2c66affSColin Finck TRUE,
216c2c66affSColin Finck INFINITE);
217c2c66affSColin Finck switch (WaitResult)
218c2c66affSColin Finck {
219c2c66affSColin Finck case WAIT_OBJECT_0 + 0:
220c2c66affSColin Finck case WAIT_OBJECT_0 + 1:
221c2c66affSColin Finck break;
222c2c66affSColin Finck default:
223c2c66affSColin Finck return GetLastError();
224c2c66affSColin Finck }
225c2c66affSColin Finck
226c2c66affSColin Finck /* Wait for an input record */
227c2c66affSColin Finck if (!ReadConsoleInputExW(ConsoleInput,
228c2c66affSColin Finck InputRecords,
229c2c66affSColin Finck ARRAYSIZE(InputRecords),
230c2c66affSColin Finck &NumRecords,
231*3a49e26fSHermès Bélusca-Maïto CONSOLE_READ_NOWAIT))
232c2c66affSColin Finck {
233c2c66affSColin Finck DWORD LastError = GetLastError();
234c2c66affSColin Finck DPRINT1("Error reading console input (0x%p, %lu) - Error %lu\n", ConsoleInput, NumRecords, LastError);
235c2c66affSColin Finck return LastError;
236c2c66affSColin Finck }
237c2c66affSColin Finck
238c2c66affSColin Finck // ASSERT(NumRecords != 0);
239c2c66affSColin Finck if (NumRecords == 0)
240c2c66affSColin Finck {
241c2c66affSColin Finck DPRINT1("Got NumRecords == 0!\n");
242c2c66affSColin Finck continue;
243c2c66affSColin Finck }
244c2c66affSColin Finck
245c2c66affSColin Finck /* Dispatch the events */
246c2c66affSColin Finck for (i = 0; i < NumRecords; i++)
247c2c66affSColin Finck {
248c2c66affSColin Finck /* Check the event type */
249c2c66affSColin Finck switch (InputRecords[i].EventType)
250c2c66affSColin Finck {
251c2c66affSColin Finck /*
252c2c66affSColin Finck * Hardware events
253c2c66affSColin Finck */
254c2c66affSColin Finck case KEY_EVENT:
255c2c66affSColin Finck KeyboardEventHandler(&InputRecords[i].Event.KeyEvent);
256c2c66affSColin Finck break;
257c2c66affSColin Finck
258c2c66affSColin Finck case MOUSE_EVENT:
259c2c66affSColin Finck MouseEventHandler(&InputRecords[i].Event.MouseEvent);
260c2c66affSColin Finck break;
261c2c66affSColin Finck
262c2c66affSColin Finck case WINDOW_BUFFER_SIZE_EVENT:
263c2c66affSColin Finck ScreenEventHandler(&InputRecords[i].Event.WindowBufferSizeEvent);
264c2c66affSColin Finck break;
265c2c66affSColin Finck
266c2c66affSColin Finck /*
267c2c66affSColin Finck * Interface events
268c2c66affSColin Finck */
269c2c66affSColin Finck case MENU_EVENT:
270c2c66affSColin Finck MenuEventHandler(&InputRecords[i].Event.MenuEvent);
271c2c66affSColin Finck break;
272c2c66affSColin Finck
273c2c66affSColin Finck case FOCUS_EVENT:
274c2c66affSColin Finck FocusEventHandler(&InputRecords[i].Event.FocusEvent);
275c2c66affSColin Finck break;
276c2c66affSColin Finck
277c2c66affSColin Finck default:
278c2c66affSColin Finck DPRINT1("Unknown input event type 0x%04x\n", InputRecords[i].EventType);
279c2c66affSColin Finck break;
280c2c66affSColin Finck }
281c2c66affSColin Finck }
282c2c66affSColin Finck
283c2c66affSColin Finck /* Let the console subsystem queue some new events */
284c2c66affSColin Finck Sleep(10);
285c2c66affSColin Finck }
286c2c66affSColin Finck
287c2c66affSColin Finck return 0;
288c2c66affSColin Finck }
289c2c66affSColin Finck
PauseEventThread(VOID)290c2c66affSColin Finck static VOID PauseEventThread(VOID)
291c2c66affSColin Finck {
292c2c66affSColin Finck ResetEvent(VdmTaskEvent);
293c2c66affSColin Finck }
294c2c66affSColin Finck
ResumeEventThread(VOID)295c2c66affSColin Finck static VOID ResumeEventThread(VOID)
296c2c66affSColin Finck {
297c2c66affSColin Finck SetEvent(VdmTaskEvent);
298c2c66affSColin Finck }
299c2c66affSColin Finck
300c2c66affSColin Finck
301c2c66affSColin Finck /* PUBLIC FUNCTIONS ***********************************************************/
302c2c66affSColin Finck
303c2c66affSColin Finck static VOID
DumpMemoryRaw(HANDLE hFile)304c2c66affSColin Finck DumpMemoryRaw(HANDLE hFile)
305c2c66affSColin Finck {
306c2c66affSColin Finck PVOID Buffer;
30780733143STimo Kreuzer DWORD Size;
308c2c66affSColin Finck
309c2c66affSColin Finck /* Dump the VM memory */
310c2c66affSColin Finck SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
311c2c66affSColin Finck Buffer = REAL_TO_PHYS(NULL);
312c2c66affSColin Finck Size = MAX_ADDRESS - (ULONG_PTR)(NULL);
313c2c66affSColin Finck WriteFile(hFile, Buffer, Size, &Size, NULL);
314c2c66affSColin Finck }
315c2c66affSColin Finck
316c2c66affSColin Finck static VOID
DumpMemoryTxt(HANDLE hFile)317c2c66affSColin Finck DumpMemoryTxt(HANDLE hFile)
318c2c66affSColin Finck {
319c2c66affSColin Finck #define LINE_SIZE 75 + 2
320c2c66affSColin Finck ULONG i;
321c2c66affSColin Finck PBYTE Ptr1, Ptr2;
322c2c66affSColin Finck CHAR LineBuffer[LINE_SIZE];
323c2c66affSColin Finck PCHAR Line;
32480733143STimo Kreuzer DWORD LineSize;
325c2c66affSColin Finck
326c2c66affSColin Finck /* Dump the VM memory */
327c2c66affSColin Finck SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
328c2c66affSColin Finck Ptr1 = Ptr2 = REAL_TO_PHYS(NULL);
329c2c66affSColin Finck while (MAX_ADDRESS - (ULONG_PTR)PHYS_TO_REAL(Ptr1) > 0)
330c2c66affSColin Finck {
331c2c66affSColin Finck Ptr1 = Ptr2;
332c2c66affSColin Finck Line = LineBuffer;
333c2c66affSColin Finck
334c2c66affSColin Finck /* Print the address */
33580733143STimo Kreuzer Line += snprintf(Line, LINE_SIZE + LineBuffer - Line, "%08Ix ", (ULONG_PTR)PHYS_TO_REAL(Ptr1));
336c2c66affSColin Finck
337c2c66affSColin Finck /* Print up to 16 bytes... */
338c2c66affSColin Finck
339c2c66affSColin Finck /* ... in hexadecimal form first... */
340c2c66affSColin Finck i = 0;
341c2c66affSColin Finck while (i++ <= 0x0F && (MAX_ADDRESS - (ULONG_PTR)PHYS_TO_REAL(Ptr1) > 0))
342c2c66affSColin Finck {
343c2c66affSColin Finck Line += snprintf(Line, LINE_SIZE + LineBuffer - Line, " %02x", *Ptr1);
344c2c66affSColin Finck ++Ptr1;
345c2c66affSColin Finck }
346c2c66affSColin Finck
347c2c66affSColin Finck /* ... align with spaces if needed... */
348c2c66affSColin Finck RtlFillMemory(Line, (0x0F + 2 - i) * 3 + 2, ' ');
349c2c66affSColin Finck Line += (0x0F + 2 - i) * 3 + 2;
350c2c66affSColin Finck
351c2c66affSColin Finck /* ... then in character form. */
352c2c66affSColin Finck i = 0;
353c2c66affSColin Finck while (i++ <= 0x0F && (MAX_ADDRESS - (ULONG_PTR)PHYS_TO_REAL(Ptr2) > 0))
354c2c66affSColin Finck {
355c2c66affSColin Finck *Line++ = ((*Ptr2 >= 0x20 && *Ptr2 <= 0x7E) || (*Ptr2 >= 0x80 && *Ptr2 < 0xFF) ? *Ptr2 : '.');
356c2c66affSColin Finck ++Ptr2;
357c2c66affSColin Finck }
358c2c66affSColin Finck
359c2c66affSColin Finck /* Newline */
360c2c66affSColin Finck *Line++ = '\r';
361c2c66affSColin Finck *Line++ = '\n';
362c2c66affSColin Finck
363c2c66affSColin Finck /* Finally write the line to the file */
364c2c66affSColin Finck LineSize = Line - LineBuffer;
365c2c66affSColin Finck WriteFile(hFile, LineBuffer, LineSize, &LineSize, NULL);
366c2c66affSColin Finck }
367c2c66affSColin Finck }
368c2c66affSColin Finck
DumpMemory(BOOLEAN TextFormat)369c2c66affSColin Finck VOID DumpMemory(BOOLEAN TextFormat)
370c2c66affSColin Finck {
371c2c66affSColin Finck static ULONG DumpNumber = 0;
372c2c66affSColin Finck
373c2c66affSColin Finck HANDLE hFile;
374c2c66affSColin Finck WCHAR FileName[MAX_PATH];
375c2c66affSColin Finck
376c2c66affSColin Finck /* Build a suitable file name */
377c2c66affSColin Finck _snwprintf(FileName, MAX_PATH,
378c2c66affSColin Finck L"memdump%lu.%s",
379c2c66affSColin Finck DumpNumber,
380c2c66affSColin Finck TextFormat ? L"txt" : L"dat");
381c2c66affSColin Finck ++DumpNumber;
382c2c66affSColin Finck
383c2c66affSColin Finck DPRINT1("Creating memory dump file '%S'...\n", FileName);
384c2c66affSColin Finck
385c2c66affSColin Finck /* Always create the dump file */
386c2c66affSColin Finck hFile = CreateFileW(FileName,
387c2c66affSColin Finck GENERIC_WRITE,
388c2c66affSColin Finck 0,
389c2c66affSColin Finck NULL,
390c2c66affSColin Finck CREATE_ALWAYS,
391c2c66affSColin Finck FILE_ATTRIBUTE_NORMAL,
392c2c66affSColin Finck NULL);
393c2c66affSColin Finck
394c2c66affSColin Finck if (hFile == INVALID_HANDLE_VALUE)
395c2c66affSColin Finck {
396c2c66affSColin Finck DPRINT1("Error when creating '%S' for memory dumping, GetLastError() = %u\n",
397c2c66affSColin Finck FileName, GetLastError());
398c2c66affSColin Finck return;
399c2c66affSColin Finck }
400c2c66affSColin Finck
401c2c66affSColin Finck /* Dump the VM memory in the chosen format */
402c2c66affSColin Finck if (TextFormat)
403c2c66affSColin Finck DumpMemoryTxt(hFile);
404c2c66affSColin Finck else
405c2c66affSColin Finck DumpMemoryRaw(hFile);
406c2c66affSColin Finck
407c2c66affSColin Finck /* Close the file */
408c2c66affSColin Finck CloseHandle(hFile);
409c2c66affSColin Finck
410c2c66affSColin Finck DPRINT1("Memory dump done\n");
411c2c66affSColin Finck }
412c2c66affSColin Finck
MountFloppy(IN ULONG DiskNumber)413c2c66affSColin Finck VOID MountFloppy(IN ULONG DiskNumber)
414c2c66affSColin Finck {
415c2c66affSColin Finck // FIXME: This should be present in PSDK commdlg.h
416c2c66affSColin Finck //
417c2c66affSColin Finck // FlagsEx Values
418c2c66affSColin Finck #if (_WIN32_WINNT >= 0x0500)
419c2c66affSColin Finck #define OFN_EX_NOPLACESBAR 0x00000001
420c2c66affSColin Finck #endif // (_WIN32_WINNT >= 0x0500)
421c2c66affSColin Finck
422c2c66affSColin Finck BOOLEAN Success;
423c2c66affSColin Finck OPENFILENAMEW ofn;
424c2c66affSColin Finck WCHAR szFile[MAX_PATH] = L"";
425c2c66affSColin Finck
426c2c66affSColin Finck ASSERT(DiskNumber < ARRAYSIZE(GlobalSettings.FloppyDisks));
427c2c66affSColin Finck
428c2c66affSColin Finck RtlZeroMemory(&ofn, sizeof(ofn));
429c2c66affSColin Finck ofn.lStructSize = sizeof(ofn);
430c2c66affSColin Finck ofn.hwndOwner = hConsoleWnd;
431c2c66affSColin Finck ofn.lpstrTitle = L"Select a virtual floppy image";
432c2c66affSColin Finck ofn.Flags = OFN_EXPLORER | OFN_ENABLESIZING | OFN_LONGNAMES | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
433c2c66affSColin Finck // ofn.FlagsEx = OFN_EX_NOPLACESBAR;
434c2c66affSColin Finck ofn.lpstrFilter = L"Virtual floppy images (*.vfd;*.img;*.ima;*.dsk)\0*.vfd;*.img;*.ima;*.dsk\0All files (*.*)\0*.*\0\0";
435c2c66affSColin Finck ofn.lpstrDefExt = L"vfd";
436c2c66affSColin Finck ofn.nFilterIndex = 0;
437c2c66affSColin Finck ofn.lpstrFile = szFile;
438c2c66affSColin Finck ofn.nMaxFile = ARRAYSIZE(szFile);
439c2c66affSColin Finck
440c2c66affSColin Finck if (!GetOpenFileNameW(&ofn))
441c2c66affSColin Finck {
442c2c66affSColin Finck DPRINT1("CommDlgExtendedError = %d\n", CommDlgExtendedError());
443c2c66affSColin Finck return;
444c2c66affSColin Finck }
445c2c66affSColin Finck
446c2c66affSColin Finck /* Free the old string */
447c2c66affSColin Finck if (GlobalSettings.FloppyDisks[DiskNumber].Buffer)
448c2c66affSColin Finck RtlFreeUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber]);
449c2c66affSColin Finck
450c2c66affSColin Finck /* Reinitialize the string */
451c2c66affSColin Finck Success = RtlCreateUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber], szFile);
452c2c66affSColin Finck ASSERT(Success);
453c2c66affSColin Finck
454c2c66affSColin Finck /* Mount the disk */
455c2c66affSColin Finck if (!MountDisk(FLOPPY_DISK, DiskNumber, GlobalSettings.FloppyDisks[DiskNumber].Buffer, !!(ofn.Flags & OFN_READONLY)))
456c2c66affSColin Finck {
457c2c66affSColin Finck DisplayMessage(L"An error happened when mounting disk %d", DiskNumber);
458c2c66affSColin Finck RtlFreeUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber]);
459c2c66affSColin Finck RtlInitEmptyUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber], NULL, 0);
460c2c66affSColin Finck return;
461c2c66affSColin Finck }
462c2c66affSColin Finck
463c2c66affSColin Finck /* Refresh the menu state */
464c2c66affSColin Finck UpdateVdmMenuDisks();
465c2c66affSColin Finck }
466c2c66affSColin Finck
EjectFloppy(IN ULONG DiskNumber)467c2c66affSColin Finck VOID EjectFloppy(IN ULONG DiskNumber)
468c2c66affSColin Finck {
469c2c66affSColin Finck ASSERT(DiskNumber < ARRAYSIZE(GlobalSettings.FloppyDisks));
470c2c66affSColin Finck
471c2c66affSColin Finck /* Unmount the disk */
472c2c66affSColin Finck if (!UnmountDisk(FLOPPY_DISK, DiskNumber))
473c2c66affSColin Finck DisplayMessage(L"An error happened when ejecting disk %d", DiskNumber);
474c2c66affSColin Finck
475c2c66affSColin Finck /* Free the old string */
476c2c66affSColin Finck if (GlobalSettings.FloppyDisks[DiskNumber].Buffer)
477c2c66affSColin Finck {
478c2c66affSColin Finck RtlFreeUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber]);
479c2c66affSColin Finck RtlInitEmptyUnicodeString(&GlobalSettings.FloppyDisks[DiskNumber], NULL, 0);
480c2c66affSColin Finck }
481c2c66affSColin Finck
482c2c66affSColin Finck /* Refresh the menu state */
483c2c66affSColin Finck UpdateVdmMenuDisks();
484c2c66affSColin Finck }
485c2c66affSColin Finck
486c2c66affSColin Finck
EmulatorPause(VOID)487c2c66affSColin Finck VOID EmulatorPause(VOID)
488c2c66affSColin Finck {
489c2c66affSColin Finck /* Pause the VDM */
490c2c66affSColin Finck VDDBlockUserHook();
491c2c66affSColin Finck VgaRefreshDisplay();
492c2c66affSColin Finck PauseEventThread();
493c2c66affSColin Finck }
494c2c66affSColin Finck
EmulatorResume(VOID)495c2c66affSColin Finck VOID EmulatorResume(VOID)
496c2c66affSColin Finck {
497c2c66affSColin Finck /* Resume the VDM */
498c2c66affSColin Finck ResumeEventThread();
499c2c66affSColin Finck VgaRefreshDisplay();
500c2c66affSColin Finck VDDResumeUserHook();
501c2c66affSColin Finck }
502c2c66affSColin Finck
EmulatorTerminate(VOID)503c2c66affSColin Finck VOID EmulatorTerminate(VOID)
504c2c66affSColin Finck {
505c2c66affSColin Finck /* Stop the VDM */
506c2c66affSColin Finck CpuUnsimulate(); // Halt the CPU
507c2c66affSColin Finck VdmRunning = FALSE;
508c2c66affSColin Finck }
509c2c66affSColin Finck
EmulatorInitialize(HANDLE ConsoleInput,HANDLE ConsoleOutput)510c2c66affSColin Finck BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
511c2c66affSColin Finck {
512c2c66affSColin Finck USHORT i;
513c2c66affSColin Finck
514c2c66affSColin Finck /* Initialize memory */
515c2c66affSColin Finck if (!MemInitialize())
516c2c66affSColin Finck {
517c2c66affSColin Finck wprintf(L"Memory initialization failed.\n");
518c2c66affSColin Finck return FALSE;
519c2c66affSColin Finck }
520c2c66affSColin Finck
521c2c66affSColin Finck /* Initialize I/O ports */
522c2c66affSColin Finck /* Initialize RAM */
523c2c66affSColin Finck
524c2c66affSColin Finck /* Initialize the CPU */
525c2c66affSColin Finck
526c2c66affSColin Finck /* Initialize the internal clock */
527c2c66affSColin Finck if (!ClockInitialize())
528c2c66affSColin Finck {
529c2c66affSColin Finck wprintf(L"FATAL: Failed to initialize the clock\n");
530c2c66affSColin Finck EmulatorCleanup();
531c2c66affSColin Finck return FALSE;
532c2c66affSColin Finck }
533c2c66affSColin Finck
534c2c66affSColin Finck /* Initialize the CPU */
535c2c66affSColin Finck CpuInitialize();
536c2c66affSColin Finck
537c2c66affSColin Finck /* Initialize DMA */
538c2c66affSColin Finck DmaInitialize();
539c2c66affSColin Finck
540c2c66affSColin Finck /* Initialize PIC, PIT, CMOS, PC Speaker and PS/2 */
541c2c66affSColin Finck PicInitialize();
542c2c66affSColin Finck
543c2c66affSColin Finck PitInitialize();
544c2c66affSColin Finck PitSetOutFunction(0, NULL, PitChan0Out);
545c2c66affSColin Finck PitSetOutFunction(1, NULL, PitChan1Out);
546c2c66affSColin Finck PitSetOutFunction(2, NULL, PitChan2Out);
547c2c66affSColin Finck
548c2c66affSColin Finck CmosInitialize();
549c2c66affSColin Finck SpeakerInitialize();
550c2c66affSColin Finck PpiInitialize();
551c2c66affSColin Finck
552c2c66affSColin Finck PS2Initialize();
553c2c66affSColin Finck
554c2c66affSColin Finck /* Initialize the keyboard and mouse and connect them to their PS/2 ports */
555c2c66affSColin Finck KeyboardInit(0);
556c2c66affSColin Finck MouseInit(1);
557c2c66affSColin Finck
558c2c66affSColin Finck /**************** ATTACH INPUT WITH CONSOLE *****************/
559c2c66affSColin Finck /* Create the task event */
560c2c66affSColin Finck VdmTaskEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
561c2c66affSColin Finck ASSERT(VdmTaskEvent != NULL);
562c2c66affSColin Finck
563c2c66affSColin Finck /* Start the input thread */
564c2c66affSColin Finck InputThread = CreateThread(NULL, 0, &ConsoleEventThread, ConsoleInput, 0, NULL);
565c2c66affSColin Finck if (InputThread == NULL)
566c2c66affSColin Finck {
567c2c66affSColin Finck wprintf(L"FATAL: Failed to create the console input thread.\n");
568c2c66affSColin Finck EmulatorCleanup();
569c2c66affSColin Finck return FALSE;
570c2c66affSColin Finck }
571c2c66affSColin Finck ResumeEventThread();
572c2c66affSColin Finck /************************************************************/
573c2c66affSColin Finck
574c2c66affSColin Finck /* Initialize the VGA */
575c2c66affSColin Finck if (!VgaInitialize(ConsoleOutput))
576c2c66affSColin Finck {
577c2c66affSColin Finck wprintf(L"FATAL: Failed to initialize VGA support.\n");
578c2c66affSColin Finck EmulatorCleanup();
579c2c66affSColin Finck return FALSE;
580c2c66affSColin Finck }
581c2c66affSColin Finck
582c2c66affSColin Finck /* Initialize the disk controller */
583c2c66affSColin Finck if (!DiskCtrlInitialize())
584c2c66affSColin Finck {
585c2c66affSColin Finck wprintf(L"FATAL: Failed to completely initialize the disk controller.\n");
586c2c66affSColin Finck EmulatorCleanup();
587c2c66affSColin Finck return FALSE;
588c2c66affSColin Finck }
589c2c66affSColin Finck
590c2c66affSColin Finck /* Mount the available floppy disks */
591c2c66affSColin Finck for (i = 0; i < ARRAYSIZE(GlobalSettings.FloppyDisks); ++i)
592c2c66affSColin Finck {
593c2c66affSColin Finck if (GlobalSettings.FloppyDisks[i].Length != 0 &&
594c2c66affSColin Finck GlobalSettings.FloppyDisks[i].Buffer &&
5955bfe6a53SAndrew Cook *GlobalSettings.FloppyDisks[i].Buffer != L'\0')
596c2c66affSColin Finck {
597c2c66affSColin Finck if (!MountDisk(FLOPPY_DISK, i, GlobalSettings.FloppyDisks[i].Buffer, FALSE))
598c2c66affSColin Finck {
599c2c66affSColin Finck DPRINT1("Failed to mount floppy disk file '%wZ'.\n", &GlobalSettings.FloppyDisks[i]);
600c2c66affSColin Finck RtlFreeUnicodeString(&GlobalSettings.FloppyDisks[i]);
601c2c66affSColin Finck RtlInitEmptyUnicodeString(&GlobalSettings.FloppyDisks[i], NULL, 0);
602c2c66affSColin Finck }
603c2c66affSColin Finck }
604c2c66affSColin Finck }
605c2c66affSColin Finck
606c2c66affSColin Finck /*
607c2c66affSColin Finck * Mount the available hard disks. Contrary to floppies, failing
608c2c66affSColin Finck * mounting a hard disk is considered as an unrecoverable error.
609c2c66affSColin Finck */
610c2c66affSColin Finck for (i = 0; i < ARRAYSIZE(GlobalSettings.HardDisks); ++i)
611c2c66affSColin Finck {
612c2c66affSColin Finck if (GlobalSettings.HardDisks[i].Length != 0 &&
613c2c66affSColin Finck GlobalSettings.HardDisks[i].Buffer &&
6145bfe6a53SAndrew Cook *GlobalSettings.HardDisks[i].Buffer != L'\0')
615c2c66affSColin Finck {
616c2c66affSColin Finck if (!MountDisk(HARD_DISK, i, GlobalSettings.HardDisks[i].Buffer, FALSE))
617c2c66affSColin Finck {
618c2c66affSColin Finck wprintf(L"FATAL: Failed to mount hard disk file '%wZ'.\n", &GlobalSettings.HardDisks[i]);
619c2c66affSColin Finck EmulatorCleanup();
620c2c66affSColin Finck return FALSE;
621c2c66affSColin Finck }
622c2c66affSColin Finck }
623c2c66affSColin Finck }
624c2c66affSColin Finck
625c2c66affSColin Finck /* Refresh the menu state */
626c2c66affSColin Finck UpdateVdmMenuDisks();
627c2c66affSColin Finck
628c2c66affSColin Finck /* Initialize the software callback system and register the emulator BOPs */
629c2c66affSColin Finck InitializeInt32();
630c2c66affSColin Finck RegisterBop(BOP_DEBUGGER , EmulatorDebugBreakBop);
631c2c66affSColin Finck // RegisterBop(BOP_UNSIMULATE, CpuUnsimulateBop);
632c2c66affSColin Finck
633c2c66affSColin Finck /* Initialize VDD support */
634c2c66affSColin Finck VDDSupInitialize();
635c2c66affSColin Finck
636c2c66affSColin Finck return TRUE;
637c2c66affSColin Finck }
638c2c66affSColin Finck
EmulatorCleanup(VOID)639c2c66affSColin Finck VOID EmulatorCleanup(VOID)
640c2c66affSColin Finck {
641c2c66affSColin Finck DiskCtrlCleanup();
642c2c66affSColin Finck
643c2c66affSColin Finck VgaCleanup();
644c2c66affSColin Finck
645c2c66affSColin Finck /* Close the input thread handle */
646c2c66affSColin Finck if (InputThread != NULL) CloseHandle(InputThread);
647c2c66affSColin Finck InputThread = NULL;
648c2c66affSColin Finck
649c2c66affSColin Finck /* Close the task event */
650c2c66affSColin Finck if (VdmTaskEvent != NULL) CloseHandle(VdmTaskEvent);
651c2c66affSColin Finck VdmTaskEvent = NULL;
652c2c66affSColin Finck
653c2c66affSColin Finck PS2Cleanup();
654c2c66affSColin Finck
655c2c66affSColin Finck SpeakerCleanup();
656c2c66affSColin Finck CmosCleanup();
657c2c66affSColin Finck // PitCleanup();
658c2c66affSColin Finck // PicCleanup();
659c2c66affSColin Finck
660c2c66affSColin Finck // DmaCleanup();
661c2c66affSColin Finck
662c2c66affSColin Finck CpuCleanup();
663c2c66affSColin Finck MemCleanup();
664c2c66affSColin Finck }
665c2c66affSColin Finck
666c2c66affSColin Finck
667c2c66affSColin Finck
668c2c66affSColin Finck VOID
669c2c66affSColin Finck WINAPI
VDDSimulate16(VOID)670c2c66affSColin Finck VDDSimulate16(VOID)
671c2c66affSColin Finck {
672c2c66affSColin Finck CpuSimulate();
673c2c66affSColin Finck }
674c2c66affSColin Finck
675c2c66affSColin Finck VOID
676c2c66affSColin Finck WINAPI
VDDTerminateVDM(VOID)677c2c66affSColin Finck VDDTerminateVDM(VOID)
678c2c66affSColin Finck {
679c2c66affSColin Finck /* Stop the VDM */
680c2c66affSColin Finck EmulatorTerminate();
681c2c66affSColin Finck }
682c2c66affSColin Finck
683c2c66affSColin Finck /* EOF */
684