2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: subsystems/mvdm/ntvdm/cpu/cpu.c
5 * PURPOSE: Minimal x86 machine emulator for the VDM
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
26 #include "hardware/cmos.h"
27 #include "hardware/keyboard.h"
28 #include "hardware/mouse.h"
29 #include "hardware/pic.h"
30 #include "hardware/ps2.h"
31 #include "hardware/sound/speaker.h"
32 #include "hardware/pit.h"
33 #include "hardware/video/svga.h"
37 /* PRIVATE VARIABLES **********************************************************/
39 FAST486_STATE EmulatorContext
;
40 BOOLEAN CpuRunning
= FALSE
;
42 /* No more than 'MaxCpuCallLevel' recursive CPU calls are allowed */
43 static const INT MaxCpuCallLevel
= 32;
44 static INT CpuCallLevel
= 0; // == 0: CPU stopped; >= 1: CPU running or halted
47 LPCWSTR ExceptionName
[] =
54 L
"Bound Range Exceeded",
60 // /* BOP Identifiers */
61 // #define BOP_DEBUGGER 0x56 // Break into the debugger from a 16-bit app
63 /* PRIVATE FUNCTIONS **********************************************************/
66 VOID
EmulatorException(BYTE ExceptionNumber
, LPWORD Stack
)
68 WORD CodeSegment
, InstructionPointer
;
71 ASSERT(ExceptionNumber
< 8);
74 InstructionPointer
= Stack
[STACK_IP
];
75 CodeSegment
= Stack
[STACK_CS
];
76 Opcode
= (PBYTE
)SEG_OFF_TO_PTR(CodeSegment
, InstructionPointer
);
78 /* Display a message to the user */
79 DisplayMessage(L
"Exception: %s occured at %04X:%04X\n"
80 L
"Opcode: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
81 ExceptionName
[ExceptionNumber
],
101 // FIXME: This function assumes 16-bit mode!!!
102 VOID
CpuExecute(WORD Segment
, WORD Offset
)
104 /* Tell Fast486 to move the instruction pointer */
105 Fast486ExecuteAt(&EmulatorContext
, Segment
, Offset
);
110 /* Dump the state for debugging purposes */
111 // Fast486DumpState(&EmulatorContext);
113 /* Execute the next instruction */
114 Fast486StepInto(&EmulatorContext
);
117 LONG
CpuExceptionFilter(IN PEXCEPTION_POINTERS ExceptionInfo
)
119 /* Get the exception record */
120 PEXCEPTION_RECORD ExceptionRecord
= ExceptionInfo
->ExceptionRecord
;
122 switch (ExceptionRecord
->ExceptionCode
)
124 /* We only handle access violations so far */
125 case EXCEPTION_ACCESS_VIOLATION
:
127 BOOLEAN Writing
= (ExceptionRecord
->ExceptionInformation
[0] == 1);
129 /* Retrieve the address to which a read or write attempt was made */
130 ULONG_PTR Address
= ExceptionRecord
->ExceptionInformation
[1];
133 * Check whether the access exception was done inside the virtual memory space
134 * (caused by an emulated app) or outside (casued by a bug in ourselves).
136 if (Address
< (ULONG_PTR
)BaseAddress
||
137 Address
>= (ULONG_PTR
)BaseAddress
+ MAX_ADDRESS
)
139 DPRINT1("NTVDM: %s access violation at 0x%p outside the virtual memory space!\n",
140 (Writing
? "Write" : "Read"), Address
);
141 return EXCEPTION_CONTINUE_SEARCH
;
144 /* We are good to go, dispatch to our memory handlers */
146 /* Fix the CPU state */
147 Fast486Rewind(&EmulatorContext
);
149 /* Call the memory handler */
150 MemExceptionHandler((ULONG
)PHYS_TO_REAL(Address
), Writing
);
152 /* The execution of the CPU opcode handler MUST NOT continue */
153 return EXCEPTION_EXECUTE_HANDLER
;
158 DPRINT1("NTVDM: Exception 0x%08lx not handled!\n", ExceptionRecord
->ExceptionCode
);
163 /* Continue to search for a handler */
164 return EXCEPTION_CONTINUE_SEARCH
;
167 VOID
CpuSimulate(VOID
)
169 if (CpuCallLevel
> MaxCpuCallLevel
)
171 DisplayMessage(L
"Too many CPU levels of recursion (%d, expected maximum %d)",
172 CpuCallLevel
, MaxCpuCallLevel
);
179 DPRINT("CpuSimulate --> Level %d\n", CpuCallLevel
);
182 while (VdmRunning
&& CpuRunning
)
186 while (VdmRunning
&& CpuRunning
) ClockUpdate();
188 _SEH2_EXCEPT(CpuExceptionFilter(_SEH2_GetExceptionInformation()))
190 DPRINT("VDM exception handler called\n");
195 DPRINT("CpuSimulate <-- Level %d\n", CpuCallLevel
);
197 if (!VdmRunning
|| CpuCallLevel
< 0) CpuCallLevel
= 0;
199 /* This takes into account for reentrance */
200 if (VdmRunning
&& (CpuCallLevel
> 0)) CpuRunning
= TRUE
;
203 VOID
CpuUnsimulate(VOID
)
205 /* Stop simulation */
209 static VOID WINAPI
CpuUnsimulateBop(LPWORD Stack
)
214 /* PUBLIC FUNCTIONS ***********************************************************/
216 BOOLEAN
CpuInitialize(VOID
)
218 // /* Initialize the internal clock */
219 // if (!ClockInitialize())
221 // wprintf(L"FATAL: Failed to initialize the clock\n");
225 /* Initialize the CPU */
226 Fast486Initialize(&EmulatorContext
,
231 EmulatorBiosOperation
,
232 EmulatorIntAcknowledge
,
234 NULL
/* TODO: Use a TLB */);
236 /* Initialize the software callback system and register the emulator BOPs */
237 // RegisterBop(BOP_DEBUGGER , EmulatorDebugBreakBop);
238 RegisterBop(BOP_UNSIMULATE
, CpuUnsimulateBop
);
243 VOID
CpuCleanup(VOID
)