[FAST486]
[reactos.git] / reactos / lib / fast486 / fast486.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * fast486.c
4 *
5 * Copyright (C) 2014 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 #include <windef.h>
25
26 // #define NDEBUG
27 #include <debug.h>
28
29 #include <fast486.h>
30 #include "common.h"
31 #include "opcodes.h"
32 #include "fpu.h"
33
34 /* DEFINES ********************************************************************/
35
36 typedef enum
37 {
38 FAST486_STEP_INTO,
39 FAST486_STEP_OVER,
40 FAST486_STEP_OUT,
41 FAST486_CONTINUE
42 } FAST486_EXEC_CMD;
43
44 /* PRIVATE FUNCTIONS **********************************************************/
45
46 static
47 inline
48 VOID
49 NTAPI
50 Fast486ExecutionControl(PFAST486_STATE State, FAST486_EXEC_CMD Command)
51 {
52 UCHAR Opcode;
53 FAST486_OPCODE_HANDLER_PROC CurrentHandler;
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) State->SavedInstPtr = State->InstPtr;
61
62 /* Perform an instruction fetch */
63 if (!Fast486FetchByte(State, &Opcode))
64 {
65 /* Exception occurred */
66 State->PrefixFlags = 0;
67 continue;
68 }
69
70 // TODO: Check for CALL/RET to update ProcedureCallCount.
71
72 /* Call the opcode handler */
73 CurrentHandler = Fast486OpcodeHandlers[Opcode];
74 CurrentHandler(State, Opcode);
75
76 /* If this is a prefix, go to the next instruction immediately */
77 if (CurrentHandler == Fast486OpcodePrefix) continue;
78
79 /* A non-prefix opcode has been executed, reset the prefix flags */
80 State->PrefixFlags = 0;
81
82 /*
83 * Check if there is an interrupt to execute, or a hardware interrupt signal
84 * while interrupts are enabled.
85 */
86 if (State->IntStatus == FAST486_INT_EXECUTE)
87 {
88 /* Perform the interrupt */
89 Fast486PerformInterrupt(State, State->PendingIntNum);
90
91 /* Clear the interrupt status */
92 State->IntStatus = FAST486_INT_NONE;
93 }
94 else if (State->Flags.If && (State->IntStatus == FAST486_INT_SIGNAL)
95 && (State->IntAckCallback != NULL))
96 {
97 /* Acknowledge the interrupt to get the number */
98 State->PendingIntNum = State->IntAckCallback(State);
99
100 /* Set the interrupt status to execute on the next instruction */
101 State->IntStatus = FAST486_INT_EXECUTE;
102 }
103 else if (State->IntStatus == FAST486_INT_DELAYED)
104 {
105 /* Restore the old state */
106 State->IntStatus = FAST486_INT_EXECUTE;
107 }
108 }
109 while ((CurrentHandler == Fast486OpcodePrefix) ||
110 (Command == FAST486_CONTINUE) ||
111 (Command == FAST486_STEP_OVER && ProcedureCallCount > 0) ||
112 (Command == FAST486_STEP_OUT && ProcedureCallCount >= 0));
113 }
114
115 /* DEFAULT CALLBACKS **********************************************************/
116
117 static VOID
118 NTAPI
119 Fast486MemReadCallback(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
120 {
121 UNREFERENCED_PARAMETER(State);
122
123 RtlMoveMemory(Buffer, (PVOID)Address, Size);
124 }
125
126 static VOID
127 NTAPI
128 Fast486MemWriteCallback(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
129 {
130 UNREFERENCED_PARAMETER(State);
131
132 RtlMoveMemory((PVOID)Address, Buffer, Size);
133 }
134
135 static VOID
136 NTAPI
137 Fast486IoReadCallback(PFAST486_STATE State, ULONG Port, PVOID Buffer, ULONG DataCount, UCHAR DataSize)
138 {
139 UNREFERENCED_PARAMETER(State);
140 UNREFERENCED_PARAMETER(Port);
141 UNREFERENCED_PARAMETER(Buffer);
142 UNREFERENCED_PARAMETER(DataCount);
143 UNREFERENCED_PARAMETER(DataSize);
144 }
145
146 static VOID
147 NTAPI
148 Fast486IoWriteCallback(PFAST486_STATE State, ULONG Port, PVOID Buffer, ULONG DataCount, UCHAR DataSize)
149 {
150 UNREFERENCED_PARAMETER(State);
151 UNREFERENCED_PARAMETER(Port);
152 UNREFERENCED_PARAMETER(Buffer);
153 UNREFERENCED_PARAMETER(DataCount);
154 UNREFERENCED_PARAMETER(DataSize);
155 }
156
157 static VOID
158 NTAPI
159 Fast486IdleCallback(PFAST486_STATE State)
160 {
161 UNREFERENCED_PARAMETER(State);
162 }
163
164 static VOID
165 NTAPI
166 Fast486BopCallback(PFAST486_STATE State, UCHAR BopCode)
167 {
168 UNREFERENCED_PARAMETER(State);
169 UNREFERENCED_PARAMETER(BopCode);
170 }
171
172 static UCHAR
173 NTAPI
174 Fast486IntAckCallback(PFAST486_STATE State)
175 {
176 UNREFERENCED_PARAMETER(State);
177
178 /* Return something... */
179 return 0;
180 }
181
182 /* PUBLIC FUNCTIONS ***********************************************************/
183
184 VOID
185 NTAPI
186 Fast486Initialize(PFAST486_STATE State,
187 FAST486_MEM_READ_PROC MemReadCallback,
188 FAST486_MEM_WRITE_PROC MemWriteCallback,
189 FAST486_IO_READ_PROC IoReadCallback,
190 FAST486_IO_WRITE_PROC IoWriteCallback,
191 FAST486_IDLE_PROC IdleCallback,
192 FAST486_BOP_PROC BopCallback,
193 FAST486_INT_ACK_PROC IntAckCallback,
194 PULONG Tlb)
195 {
196 /* Set the callbacks (or use default ones if some are NULL) */
197 State->MemReadCallback = (MemReadCallback ? MemReadCallback : Fast486MemReadCallback );
198 State->MemWriteCallback = (MemWriteCallback ? MemWriteCallback : Fast486MemWriteCallback);
199 State->IoReadCallback = (IoReadCallback ? IoReadCallback : Fast486IoReadCallback );
200 State->IoWriteCallback = (IoWriteCallback ? IoWriteCallback : Fast486IoWriteCallback );
201 State->IdleCallback = (IdleCallback ? IdleCallback : Fast486IdleCallback );
202 State->BopCallback = (BopCallback ? BopCallback : Fast486BopCallback );
203 State->IntAckCallback = (IntAckCallback ? IntAckCallback : Fast486IntAckCallback );
204
205 /* Set the TLB (if given) */
206 State->Tlb = Tlb;
207
208 /* Reset the CPU */
209 Fast486Reset(State);
210 }
211
212 VOID
213 NTAPI
214 Fast486Reset(PFAST486_STATE State)
215 {
216 FAST486_SEG_REGS i;
217
218 FAST486_MEM_READ_PROC MemReadCallback = State->MemReadCallback;
219 FAST486_MEM_WRITE_PROC MemWriteCallback = State->MemWriteCallback;
220 FAST486_IO_READ_PROC IoReadCallback = State->IoReadCallback;
221 FAST486_IO_WRITE_PROC IoWriteCallback = State->IoWriteCallback;
222 FAST486_IDLE_PROC IdleCallback = State->IdleCallback;
223 FAST486_BOP_PROC BopCallback = State->BopCallback;
224 FAST486_INT_ACK_PROC IntAckCallback = State->IntAckCallback;
225 PULONG Tlb = State->Tlb;
226
227 /* Clear the entire structure */
228 RtlZeroMemory(State, sizeof(*State));
229
230 /* Initialize the registers */
231 State->Flags.AlwaysSet = 1;
232 State->InstPtr.LowWord = 0xFFF0;
233
234 /* Set the CPL to 0 */
235 State->Cpl = 0;
236
237 /* Initialize segments */
238 for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
239 {
240 State->SegmentRegs[i].Selector = 0;
241 State->SegmentRegs[i].Base = 0;
242 State->SegmentRegs[i].Limit = 0xFFFF;
243 State->SegmentRegs[i].Present = TRUE;
244 State->SegmentRegs[i].ReadWrite = TRUE;
245 State->SegmentRegs[i].Executable = FALSE;
246 State->SegmentRegs[i].DirConf = FALSE;
247 State->SegmentRegs[i].SystemType = 1; // Segment descriptor
248 State->SegmentRegs[i].Dpl = 0;
249 State->SegmentRegs[i].Size = FALSE; // 16-bit
250 }
251
252 /* Initialize the code segment */
253 State->SegmentRegs[FAST486_REG_CS].Executable = TRUE;
254 State->SegmentRegs[FAST486_REG_CS].Selector = 0xF000;
255 State->SegmentRegs[FAST486_REG_CS].Base = 0xFFFF0000;
256
257 /* Initialize the IDT */
258 State->Idtr.Size = 0x3FF;
259 State->Idtr.Address = 0;
260
261 #ifndef FAST486_NO_FPU
262 /* Initialize CR0 */
263 State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_ET;
264
265 /* Initialize the FPU control and tag registers */
266 State->FpuControl.Value = FAST486_FPU_DEFAULT_CONTROL;
267 State->FpuStatus.Value = 0;
268 State->FpuTag = 0xFFFF;
269 #endif
270
271 /* Restore the callbacks and TLB */
272 State->MemReadCallback = MemReadCallback;
273 State->MemWriteCallback = MemWriteCallback;
274 State->IoReadCallback = IoReadCallback;
275 State->IoWriteCallback = IoWriteCallback;
276 State->IdleCallback = IdleCallback;
277 State->BopCallback = BopCallback;
278 State->IntAckCallback = IntAckCallback;
279 State->Tlb = Tlb;
280 }
281
282 VOID
283 NTAPI
284 Fast486DumpState(PFAST486_STATE State)
285 {
286 DbgPrint("\nFast486DumpState -->\n");
287 DbgPrint("\nCPU currently executing in %s mode at %04X:%08X\n",
288 (State->ControlRegisters[0] & FAST486_CR0_PE) ? "protected" : "real",
289 State->SegmentRegs[FAST486_REG_CS].Selector,
290 State->InstPtr.Long);
291 DbgPrint("\nGeneral purpose registers:\n"
292 "EAX = %08X\tECX = %08X\tEDX = %08X\tEBX = %08X\n"
293 "ESP = %08X\tEBP = %08X\tESI = %08X\tEDI = %08X\n",
294 State->GeneralRegs[FAST486_REG_EAX].Long,
295 State->GeneralRegs[FAST486_REG_ECX].Long,
296 State->GeneralRegs[FAST486_REG_EDX].Long,
297 State->GeneralRegs[FAST486_REG_EBX].Long,
298 State->GeneralRegs[FAST486_REG_ESP].Long,
299 State->GeneralRegs[FAST486_REG_EBP].Long,
300 State->GeneralRegs[FAST486_REG_ESI].Long,
301 State->GeneralRegs[FAST486_REG_EDI].Long);
302 DbgPrint("\nSegment registers:\n"
303 "ES = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n"
304 "CS = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n"
305 "SS = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n"
306 "DS = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n"
307 "FS = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n"
308 "GS = %04X (Base: %08X, Limit: %08X, Dpl: %u)\n",
309 State->SegmentRegs[FAST486_REG_ES].Selector,
310 State->SegmentRegs[FAST486_REG_ES].Base,
311 State->SegmentRegs[FAST486_REG_ES].Limit,
312 State->SegmentRegs[FAST486_REG_ES].Dpl,
313 State->SegmentRegs[FAST486_REG_CS].Selector,
314 State->SegmentRegs[FAST486_REG_CS].Base,
315 State->SegmentRegs[FAST486_REG_CS].Limit,
316 State->SegmentRegs[FAST486_REG_CS].Dpl,
317 State->SegmentRegs[FAST486_REG_SS].Selector,
318 State->SegmentRegs[FAST486_REG_SS].Base,
319 State->SegmentRegs[FAST486_REG_SS].Limit,
320 State->SegmentRegs[FAST486_REG_SS].Dpl,
321 State->SegmentRegs[FAST486_REG_DS].Selector,
322 State->SegmentRegs[FAST486_REG_DS].Base,
323 State->SegmentRegs[FAST486_REG_DS].Limit,
324 State->SegmentRegs[FAST486_REG_DS].Dpl,
325 State->SegmentRegs[FAST486_REG_FS].Selector,
326 State->SegmentRegs[FAST486_REG_FS].Base,
327 State->SegmentRegs[FAST486_REG_FS].Limit,
328 State->SegmentRegs[FAST486_REG_FS].Dpl,
329 State->SegmentRegs[FAST486_REG_GS].Selector,
330 State->SegmentRegs[FAST486_REG_GS].Base,
331 State->SegmentRegs[FAST486_REG_GS].Limit,
332 State->SegmentRegs[FAST486_REG_GS].Dpl);
333 DbgPrint("\nFlags: %08X (%s %s %s %s %s %s %s %s %s %s %s %s %s) Iopl: %u\n",
334 State->Flags.Long,
335 State->Flags.Cf ? "CF" : "cf",
336 State->Flags.Pf ? "PF" : "pf",
337 State->Flags.Af ? "AF" : "af",
338 State->Flags.Zf ? "ZF" : "zf",
339 State->Flags.Sf ? "SF" : "sf",
340 State->Flags.Tf ? "TF" : "tf",
341 State->Flags.If ? "IF" : "if",
342 State->Flags.Df ? "DF" : "df",
343 State->Flags.Of ? "OF" : "of",
344 State->Flags.Nt ? "NT" : "nt",
345 State->Flags.Rf ? "RF" : "rf",
346 State->Flags.Vm ? "VM" : "vm",
347 State->Flags.Ac ? "AC" : "ac",
348 State->Flags.Iopl);
349 DbgPrint("\nControl Registers:\n"
350 "CR0 = %08X\tCR2 = %08X\tCR3 = %08X\n",
351 State->ControlRegisters[FAST486_REG_CR0],
352 State->ControlRegisters[FAST486_REG_CR2],
353 State->ControlRegisters[FAST486_REG_CR3]);
354 DbgPrint("\nDebug Registers:\n"
355 "DR0 = %08X\tDR1 = %08X\tDR2 = %08X\n"
356 "DR3 = %08X\tDR4 = %08X\tDR5 = %08X\n",
357 State->DebugRegisters[FAST486_REG_DR0],
358 State->DebugRegisters[FAST486_REG_DR1],
359 State->DebugRegisters[FAST486_REG_DR2],
360 State->DebugRegisters[FAST486_REG_DR3],
361 State->DebugRegisters[FAST486_REG_DR4],
362 State->DebugRegisters[FAST486_REG_DR5]);
363
364 #ifndef FAST486_NO_FPU
365 DbgPrint("\nFPU Registers:\n"
366 "ST0 = %04X%016llX\tST1 = %04X%016llX\n"
367 "ST2 = %04X%016llX\tST3 = %04X%016llX\n"
368 "ST4 = %04X%016llX\tST5 = %04X%016llX\n"
369 "ST6 = %04X%016llX\tST7 = %04X%016llX\n"
370 "Status: %04X\tControl: %04X\tTag: %04X\n",
371 FPU_ST(0).Exponent | ((USHORT)FPU_ST(0).Sign << 15),
372 FPU_ST(0).Mantissa,
373 FPU_ST(1).Exponent | ((USHORT)FPU_ST(1).Sign << 15),
374 FPU_ST(1).Mantissa,
375 FPU_ST(2).Exponent | ((USHORT)FPU_ST(2).Sign << 15),
376 FPU_ST(2).Mantissa,
377 FPU_ST(3).Exponent | ((USHORT)FPU_ST(3).Sign << 15),
378 FPU_ST(3).Mantissa,
379 FPU_ST(4).Exponent | ((USHORT)FPU_ST(4).Sign << 15),
380 FPU_ST(4).Mantissa,
381 FPU_ST(5).Exponent | ((USHORT)FPU_ST(5).Sign << 15),
382 FPU_ST(5).Mantissa,
383 FPU_ST(6).Exponent | ((USHORT)FPU_ST(6).Sign << 15),
384 FPU_ST(6).Mantissa,
385 FPU_ST(7).Exponent | ((USHORT)FPU_ST(7).Sign << 15),
386 FPU_ST(7).Mantissa,
387 State->FpuStatus,
388 State->FpuControl,
389 State->FpuTag);
390 #endif
391
392 DbgPrint("\n<-- Fast486DumpState\n\n");
393 }
394
395 VOID
396 NTAPI
397 Fast486Continue(PFAST486_STATE State)
398 {
399 /* Call the internal function */
400 Fast486ExecutionControl(State, FAST486_CONTINUE);
401 }
402
403 VOID
404 NTAPI
405 Fast486StepInto(PFAST486_STATE State)
406 {
407 /* Call the internal function */
408 Fast486ExecutionControl(State, FAST486_STEP_INTO);
409 }
410
411 VOID
412 NTAPI
413 Fast486StepOver(PFAST486_STATE State)
414 {
415 /* Call the internal function */
416 Fast486ExecutionControl(State, FAST486_STEP_OVER);
417 }
418
419 VOID
420 NTAPI
421 Fast486StepOut(PFAST486_STATE State)
422 {
423 /* Call the internal function */
424 Fast486ExecutionControl(State, FAST486_STEP_OUT);
425 }
426
427 VOID
428 NTAPI
429 Fast486Interrupt(PFAST486_STATE State, UCHAR Number)
430 {
431 /* Set the interrupt status and the number */
432 State->IntStatus = FAST486_INT_EXECUTE;
433 State->PendingIntNum = Number;
434 }
435
436 VOID
437 NTAPI
438 Fast486InterruptSignal(PFAST486_STATE State)
439 {
440 /* Set the interrupt status */
441 State->IntStatus = FAST486_INT_SIGNAL;
442 }
443
444 VOID
445 NTAPI
446 Fast486ExecuteAt(PFAST486_STATE State, USHORT Segment, ULONG Offset)
447 {
448 /* Load the new CS */
449 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
450 {
451 /* An exception occurred, let the handler execute instead */
452 return;
453 }
454
455 /* Set the new IP */
456 State->InstPtr.Long = Offset;
457 }
458
459 VOID
460 NTAPI
461 Fast486SetStack(PFAST486_STATE State, USHORT Segment, ULONG Offset)
462 {
463 /* Load the new SS */
464 if (!Fast486LoadSegment(State, FAST486_REG_SS, Segment))
465 {
466 /* An exception occurred, let the handler execute instead */
467 return;
468 }
469
470 /* Set the new SP */
471 State->GeneralRegs[FAST486_REG_ESP].Long = Offset;
472 }
473
474 VOID
475 NTAPI
476 Fast486SetSegment(PFAST486_STATE State,
477 FAST486_SEG_REGS Segment,
478 USHORT Selector)
479 {
480 /* Call the internal function */
481 Fast486LoadSegment(State, Segment, Selector);
482 }
483
484 /* EOF */