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