[NTVDM]
[reactos.git] / reactos / subsystems / mvdm / ntvdm / cpu / cpu.c
1 /*
2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
4 * FILE: emulator.c
5 * PURPOSE: Minimal x86 machine emulator for the VDM
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #define NDEBUG
12
13 #include "cpu.h"
14
15 #include "emulator.h"
16 #include "memory.h"
17 #include "callback.h"
18 #include "bop.h"
19 #include <isvbop.h>
20 #include <pseh/pseh2.h>
21
22 #include "clock.h"
23 #include "bios/rom.h"
24 #include "hardware/cmos.h"
25 #include "hardware/keyboard.h"
26 #include "hardware/mouse.h"
27 #include "hardware/pic.h"
28 #include "hardware/ps2.h"
29 #include "hardware/sound/speaker.h"
30 #include "hardware/pit.h"
31 #include "hardware/video/vga.h"
32
33 #include "io.h"
34
35 /* PRIVATE VARIABLES **********************************************************/
36
37 FAST486_STATE EmulatorContext;
38 BOOLEAN CpuRunning = FALSE;
39
40 /* No more than 'MaxCpuCallLevel' recursive CPU calls are allowed */
41 static const INT MaxCpuCallLevel = 32;
42 static INT CpuCallLevel = 0; // == 0: CPU stopped; >= 1: CPU running or halted
43
44 #if 0
45 LPCWSTR ExceptionName[] =
46 {
47 L"Division By Zero",
48 L"Debug",
49 L"Unexpected Error",
50 L"Breakpoint",
51 L"Integer Overflow",
52 L"Bound Range Exceeded",
53 L"Invalid Opcode",
54 L"FPU Not Available"
55 };
56 #endif
57
58 // /* BOP Identifiers */
59 // #define BOP_DEBUGGER 0x56 // Break into the debugger from a 16-bit app
60
61 /* PRIVATE FUNCTIONS **********************************************************/
62
63 #if 0
64 VOID EmulatorException(BYTE ExceptionNumber, LPWORD Stack)
65 {
66 WORD CodeSegment, InstructionPointer;
67 PBYTE Opcode;
68
69 ASSERT(ExceptionNumber < 8);
70
71 /* Get the CS:IP */
72 InstructionPointer = Stack[STACK_IP];
73 CodeSegment = Stack[STACK_CS];
74 Opcode = (PBYTE)SEG_OFF_TO_PTR(CodeSegment, InstructionPointer);
75
76 /* Display a message to the user */
77 DisplayMessage(L"Exception: %s occured at %04X:%04X\n"
78 L"Opcode: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
79 ExceptionName[ExceptionNumber],
80 CodeSegment,
81 InstructionPointer,
82 Opcode[0],
83 Opcode[1],
84 Opcode[2],
85 Opcode[3],
86 Opcode[4],
87 Opcode[5],
88 Opcode[6],
89 Opcode[7],
90 Opcode[8],
91 Opcode[9]);
92
93 /* Stop the VDM */
94 EmulatorTerminate();
95 return;
96 }
97 #endif
98
99 // FIXME: This function assumes 16-bit mode!!!
100 VOID CpuExecute(WORD Segment, WORD Offset)
101 {
102 /* Tell Fast486 to move the instruction pointer */
103 Fast486ExecuteAt(&EmulatorContext, Segment, Offset);
104 }
105
106 VOID CpuStep(VOID)
107 {
108 /* Dump the state for debugging purposes */
109 // Fast486DumpState(&EmulatorContext);
110
111 /* Execute the next instruction */
112 Fast486StepInto(&EmulatorContext);
113 }
114
115 VOID CpuSimulate(VOID)
116 {
117 EXCEPTION_RECORD LocalExceptionRecord;
118
119 if (CpuCallLevel > MaxCpuCallLevel)
120 {
121 DisplayMessage(L"Too many CPU levels of recursion (%d, expected maximum %d)",
122 CpuCallLevel, MaxCpuCallLevel);
123
124 /* Stop the VDM */
125 EmulatorTerminate();
126 return;
127 }
128 CpuCallLevel++;
129 DPRINT("CpuSimulate --> Level %d\n", CpuCallLevel);
130
131 CpuRunning = TRUE;
132 while (VdmRunning && CpuRunning)
133 {
134 _SEH2_TRY
135 {
136 while (VdmRunning && CpuRunning) ClockUpdate();
137 }
138 _SEH2_EXCEPT(LocalExceptionRecord = *_SEH2_GetExceptionInformation()->ExceptionRecord,
139 EXCEPTION_EXECUTE_HANDLER)
140 {
141 BOOLEAN Writing = (LocalExceptionRecord.ExceptionInformation[0] == 1);
142 ULONG FaultAddress = (ULONG)LocalExceptionRecord.ExceptionInformation[1];
143
144 /* Make sure this was an access violation */
145 ASSERT(LocalExceptionRecord.ExceptionCode == EXCEPTION_ACCESS_VIOLATION);
146
147 /* Fix the CPU state */
148 Fast486Rewind(&EmulatorContext);
149
150 /* Call the handler */
151 MemExceptionHandler(FaultAddress, Writing);
152 }
153 _SEH2_END;
154 }
155
156 DPRINT("CpuSimulate <-- Level %d\n", CpuCallLevel);
157 CpuCallLevel--;
158 if (!VdmRunning || CpuCallLevel < 0) CpuCallLevel = 0;
159
160 /* This takes into account for reentrance */
161 if (VdmRunning && (CpuCallLevel > 0)) CpuRunning = TRUE;
162 }
163
164 VOID CpuUnsimulate(VOID)
165 {
166 /* Stop simulation */
167 CpuRunning = FALSE;
168 }
169
170 static VOID WINAPI CpuUnsimulateBop(LPWORD Stack)
171 {
172 CpuUnsimulate();
173 }
174
175 /* PUBLIC FUNCTIONS ***********************************************************/
176
177 BOOLEAN CpuInitialize(VOID)
178 {
179 // /* Initialize the internal clock */
180 // if (!ClockInitialize())
181 // {
182 // wprintf(L"FATAL: Failed to initialize the clock\n");
183 // return FALSE;
184 // }
185
186 /* Initialize the CPU */
187 Fast486Initialize(&EmulatorContext,
188 EmulatorReadMemory,
189 EmulatorWriteMemory,
190 EmulatorReadIo,
191 EmulatorWriteIo,
192 EmulatorBiosOperation,
193 EmulatorIntAcknowledge,
194 EmulatorFpu,
195 NULL /* TODO: Use a TLB */);
196
197 /* Initialize the software callback system and register the emulator BOPs */
198 // RegisterBop(BOP_DEBUGGER , EmulatorDebugBreakBop);
199 RegisterBop(BOP_UNSIMULATE, CpuUnsimulateBop);
200
201 return TRUE;
202 }
203
204 VOID CpuCleanup(VOID)
205 {
206 // Fast486Cleanup();
207 }
208
209 /* EOF */