[FAST486]
[reactos.git] / lib / fast486 / fast486.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * fast486.c
4 *
5 * Copyright (C) 2013 Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 // #define WIN32_NO_STATUS
25 // #define _INC_WINDOWS
26 #include <windef.h>
27
28 // #define NDEBUG
29 #include <debug.h>
30
31 #include <fast486.h>
32 #include "common.h"
33 #include "opcodes.h"
34
35 /* DEFINES ********************************************************************/
36
37 typedef enum
38 {
39 FAST486_STEP_INTO,
40 FAST486_STEP_OVER,
41 FAST486_STEP_OUT,
42 FAST486_CONTINUE
43 } FAST486_EXEC_CMD;
44
45 /* PRIVATE FUNCTIONS **********************************************************/
46
47 static
48 inline
49 VOID
50 NTAPI
51 Fast486ExecutionControl(PFAST486_STATE State, INT Command)
52 {
53 UCHAR Opcode;
54 INT ProcedureCallCount = 0;
55
56 /* Main execution loop */
57 do
58 {
59 /* Check if this is a new instruction */
60 if (State->PrefixFlags == 0)
61 {
62 State->SavedInstPtr = State->InstPtr;
63
64 /*
65 * Check if there is an interrupt to execute, or a hardware interrupt signal
66 * while interrupts are enabled.
67 */
68 if ((State->IntStatus == FAST486_INT_EXECUTE)
69 || (State->Flags.If
70 && (State->IntAckCallback != NULL)
71 && (State->IntStatus == FAST486_INT_SIGNAL)))
72 {
73 FAST486_IDT_ENTRY IdtEntry;
74
75 if (State->IntStatus == FAST486_INT_SIGNAL)
76 {
77 /* Acknowledge the interrupt to get the number */
78 State->PendingIntNum = State->IntAckCallback(State);
79 }
80
81 /* Get the interrupt vector */
82 if (Fast486GetIntVector(State, State->PendingIntNum, &IdtEntry))
83 {
84 /* Perform the interrupt */
85 Fast486InterruptInternal(State,
86 IdtEntry.Selector,
87 MAKELONG(IdtEntry.Offset, IdtEntry.OffsetHigh),
88 IdtEntry.Type);
89 }
90
91 /* Clear the interrupt status */
92 State->IntStatus = FAST486_INT_NONE;
93 }
94 }
95
96 /* Perform an instruction fetch */
97 if (!Fast486FetchByte(State, &Opcode)) continue;
98
99 // TODO: Check for CALL/RET to update ProcedureCallCount.
100
101 if (Fast486OpcodeHandlers[Opcode] != NULL)
102 {
103 /* Call the opcode handler */
104 Fast486OpcodeHandlers[Opcode](State, Opcode);
105 }
106 else
107 {
108 /* This is not a valid opcode */
109 Fast486Exception(State, FAST486_EXCEPTION_UD);
110 }
111
112 if (Fast486OpcodeHandlers[Opcode] != Fast486OpcodePrefix)
113 {
114 /* A non-prefix opcode has been executed, reset the prefix flags */
115 State->PrefixFlags = 0;
116 }
117 else
118 {
119 /* This is a prefix, go to the next instruction immediately */
120 continue;
121 }
122 }
123 while ((Command == FAST486_CONTINUE)
124 || (Command == FAST486_STEP_OVER && ProcedureCallCount > 0)
125 || (Command == FAST486_STEP_OUT && ProcedureCallCount >= 0)
126 || (Fast486OpcodeHandlers[Opcode] == Fast486OpcodePrefix));
127 }
128
129 /* PUBLIC FUNCTIONS ***********************************************************/
130
131 VOID
132 NTAPI
133 Fast486Continue(PFAST486_STATE State)
134 {
135 /* Call the internal function */
136 Fast486ExecutionControl(State, FAST486_CONTINUE);
137 }
138
139 VOID
140 NTAPI
141 Fast486StepInto(PFAST486_STATE State)
142 {
143 /* Call the internal function */
144 Fast486ExecutionControl(State, FAST486_STEP_INTO);
145 }
146
147 VOID
148 NTAPI
149 Fast486StepOver(PFAST486_STATE State)
150 {
151 /* Call the internal function */
152 Fast486ExecutionControl(State, FAST486_STEP_OVER);
153 }
154
155 VOID
156 NTAPI
157 Fast486StepOut(PFAST486_STATE State)
158 {
159 /* Call the internal function */
160 Fast486ExecutionControl(State, FAST486_STEP_OUT);
161 }
162
163 VOID
164 NTAPI
165 Fast486DumpState(PFAST486_STATE State)
166 {
167 DPRINT1("\nCPU currently executing in %s mode at %04X:%08X\n",
168 (State->ControlRegisters[0] & FAST486_CR0_PE) ? "protected" : "real",
169 State->SegmentRegs[FAST486_REG_CS].Selector,
170 State->InstPtr.Long);
171 DPRINT1("\nGeneral purpose registers:\n"
172 "EAX = %08X\tECX = %08X\tEDX = %08X\tEBX = %08X\n"
173 "ESP = %08X\tEBP = %08X\tESI = %08X\tEDI = %08X\n",
174 State->GeneralRegs[FAST486_REG_EAX].Long,
175 State->GeneralRegs[FAST486_REG_ECX].Long,
176 State->GeneralRegs[FAST486_REG_EDX].Long,
177 State->GeneralRegs[FAST486_REG_EBX].Long,
178 State->GeneralRegs[FAST486_REG_ESP].Long,
179 State->GeneralRegs[FAST486_REG_EBP].Long,
180 State->GeneralRegs[FAST486_REG_ESI].Long,
181 State->GeneralRegs[FAST486_REG_EDI].Long);
182 DPRINT1("\nSegment registers:\n"
183 "ES = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n"
184 "CS = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n"
185 "SS = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n"
186 "DS = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n"
187 "FS = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n"
188 "GS = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n",
189 State->SegmentRegs[FAST486_REG_ES].Selector,
190 State->SegmentRegs[FAST486_REG_ES].Base,
191 State->SegmentRegs[FAST486_REG_ES].Limit,
192 State->SegmentRegs[FAST486_REG_ES].Dpl,
193 State->SegmentRegs[FAST486_REG_CS].Selector,
194 State->SegmentRegs[FAST486_REG_CS].Base,
195 State->SegmentRegs[FAST486_REG_CS].Limit,
196 State->SegmentRegs[FAST486_REG_CS].Dpl,
197 State->SegmentRegs[FAST486_REG_SS].Selector,
198 State->SegmentRegs[FAST486_REG_SS].Base,
199 State->SegmentRegs[FAST486_REG_SS].Limit,
200 State->SegmentRegs[FAST486_REG_SS].Dpl,
201 State->SegmentRegs[FAST486_REG_DS].Selector,
202 State->SegmentRegs[FAST486_REG_DS].Base,
203 State->SegmentRegs[FAST486_REG_DS].Limit,
204 State->SegmentRegs[FAST486_REG_DS].Dpl,
205 State->SegmentRegs[FAST486_REG_FS].Selector,
206 State->SegmentRegs[FAST486_REG_FS].Base,
207 State->SegmentRegs[FAST486_REG_FS].Limit,
208 State->SegmentRegs[FAST486_REG_FS].Dpl,
209 State->SegmentRegs[FAST486_REG_GS].Selector,
210 State->SegmentRegs[FAST486_REG_GS].Base,
211 State->SegmentRegs[FAST486_REG_GS].Limit,
212 State->SegmentRegs[FAST486_REG_GS].Dpl);
213 DPRINT1("\nFlags: %08X (%s %s %s %s %s %s %s %s %s %s %s %s %s %s %s) Iopl: %u\n",
214 State->Flags.Long,
215 State->Flags.Cf ? "CF" : "cf",
216 State->Flags.Pf ? "PF" : "pf",
217 State->Flags.Af ? "AF" : "af",
218 State->Flags.Zf ? "ZF" : "zf",
219 State->Flags.Sf ? "SF" : "sf",
220 State->Flags.Tf ? "TF" : "tf",
221 State->Flags.If ? "IF" : "if",
222 State->Flags.Df ? "DF" : "df",
223 State->Flags.Of ? "OF" : "of",
224 State->Flags.Nt ? "NT" : "nt",
225 State->Flags.Rf ? "RF" : "rf",
226 State->Flags.Vm ? "VM" : "vm",
227 State->Flags.Ac ? "AC" : "ac",
228 State->Flags.Vif ? "VIF" : "vif",
229 State->Flags.Vip ? "VIP" : "vip",
230 State->Flags.Iopl);
231 DPRINT1("\nControl Registers:\n"
232 "CR0 = %08X\tCR2 = %08X\tCR3 = %08X\n",
233 State->ControlRegisters[FAST486_REG_CR0],
234 State->ControlRegisters[FAST486_REG_CR2],
235 State->ControlRegisters[FAST486_REG_CR3]);
236 DPRINT1("\nDebug Registers:\n"
237 "DR0 = %08X\tDR1 = %08X\tDR2 = %08X\n"
238 "DR3 = %08X\tDR4 = %08X\tDR5 = %08X\n",
239 State->DebugRegisters[FAST486_REG_DR0],
240 State->DebugRegisters[FAST486_REG_DR1],
241 State->DebugRegisters[FAST486_REG_DR2],
242 State->DebugRegisters[FAST486_REG_DR3],
243 State->DebugRegisters[FAST486_REG_DR4],
244 State->DebugRegisters[FAST486_REG_DR5]);
245 }
246
247 VOID
248 NTAPI
249 Fast486Reset(PFAST486_STATE State)
250 {
251 INT i;
252 FAST486_MEM_READ_PROC MemReadCallback = State->MemReadCallback;
253 FAST486_MEM_WRITE_PROC MemWriteCallback = State->MemWriteCallback;
254 FAST486_IO_READ_PROC IoReadCallback = State->IoReadCallback;
255 FAST486_IO_WRITE_PROC IoWriteCallback = State->IoWriteCallback;
256 FAST486_IDLE_PROC IdleCallback = State->IdleCallback;
257 FAST486_BOP_PROC BopCallback = State->BopCallback;
258 FAST486_INT_ACK_PROC IntAckCallback = State->IntAckCallback;
259
260 /* Clear the entire structure */
261 RtlZeroMemory(State, sizeof(*State));
262
263 /* Initialize the registers */
264 State->Flags.AlwaysSet = 1;
265 State->InstPtr.LowWord = 0xFFF0;
266
267 /* Initialize segments */
268 for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
269 {
270 /* Set the selector, base and limit, other values don't apply in real mode */
271 State->SegmentRegs[i].Selector = 0;
272 State->SegmentRegs[i].Base = 0;
273 State->SegmentRegs[i].Limit = 0xFFFF;
274 }
275
276 /* Initialize the code segment */
277 State->SegmentRegs[FAST486_REG_CS].Selector = 0xF000;
278 State->SegmentRegs[FAST486_REG_CS].Base = 0xFFFF0000;
279
280 /* Initialize the IDT */
281 State->Idtr.Size = 0x3FF;
282 State->Idtr.Address = 0;
283
284 /* Initialize CR0 */
285 State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_ET;
286
287 /* Restore the callbacks */
288 State->MemReadCallback = MemReadCallback;
289 State->MemWriteCallback = MemWriteCallback;
290 State->IoReadCallback = IoReadCallback;
291 State->IoWriteCallback = IoWriteCallback;
292 State->IdleCallback = IdleCallback;
293 State->BopCallback = BopCallback;
294 State->IntAckCallback = IntAckCallback;
295 }
296
297 VOID
298 NTAPI
299 Fast486Interrupt(PFAST486_STATE State, UCHAR Number)
300 {
301 /* Set the interrupt status and the number */
302 State->IntStatus = FAST486_INT_EXECUTE;
303 State->PendingIntNum = Number;
304 }
305
306 VOID
307 NTAPI
308 Fast486InterruptSignal(PFAST486_STATE State)
309 {
310 /* Set the interrupt status */
311 State->IntStatus = FAST486_INT_SIGNAL;
312 }
313
314 VOID
315 NTAPI
316 Fast486ExecuteAt(PFAST486_STATE State, USHORT Segment, ULONG Offset)
317 {
318 /* Load the new CS */
319 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
320 {
321 /* An exception occurred, let the handler execute instead */
322 return;
323 }
324
325 /* Set the new IP */
326 State->InstPtr.Long = Offset;
327 }
328
329 VOID
330 NTAPI
331 Fast486SetStack(PFAST486_STATE State, USHORT Segment, ULONG Offset)
332 {
333 /* Load the new SS */
334 if (!Fast486LoadSegment(State, FAST486_REG_SS, Segment))
335 {
336 /* An exception occurred, let the handler execute instead */
337 return;
338 }
339
340 /* Set the new SP */
341 State->GeneralRegs[FAST486_REG_ESP].Long = Offset;
342 }
343
344 VOID
345 NTAPI
346 Fast486SetSegment(PFAST486_STATE State,
347 FAST486_SEG_REGS Segment,
348 USHORT Selector)
349 {
350 /* Call the internal function */
351 Fast486LoadSegment(State, Segment, Selector);
352 }
353
354 /* EOF */