[FAST486]
[reactos.git] / reactos / lib / fast486 / fast486.c
1 /*
2 * Fast486 386/486 CPU Emulation Library
3 * fast486.c
4 *
5 * Copyright (C) 2015 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 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 BOOLEAN Trap;
54
55 /* Main execution loop */
56 do
57 {
58 Trap = State->Flags.Tf;
59
60 if (!State->Halted)
61 {
62 NextInst:
63 /* Check if this is a new instruction */
64 if (State->PrefixFlags == 0) State->SavedInstPtr = State->InstPtr;
65
66 /* Perform an instruction fetch */
67 if (!Fast486FetchByte(State, &Opcode))
68 {
69 /* Exception occurred */
70 State->PrefixFlags = 0;
71 continue;
72 }
73
74 // TODO: Check for CALL/RET to update ProcedureCallCount.
75
76 /* Call the opcode handler */
77 CurrentHandler = Fast486OpcodeHandlers[Opcode];
78 CurrentHandler(State, Opcode);
79
80 /* If this is a prefix, go to the next instruction immediately */
81 if (CurrentHandler == Fast486OpcodePrefix) goto NextInst;
82
83 /* A non-prefix opcode has been executed, reset the prefix flags */
84 State->PrefixFlags = 0;
85 }
86
87 /*
88 * Check if there is an interrupt to execute, or a hardware interrupt signal
89 * while interrupts are enabled.
90 */
91 if (State->DoNotInterrupt)
92 {
93 /* Clear the interrupt delay flag */
94 State->DoNotInterrupt = FALSE;
95 }
96 else if (Trap && !State->Halted)
97 {
98 /* Perform the interrupt */
99 Fast486PerformInterrupt(State, FAST486_EXCEPTION_DB);
100 }
101 else if (State->Flags.If && State->IntSignaled)
102 {
103 /* No longer halted */
104 State->Halted = FALSE;
105
106 /* Acknowledge the interrupt and perform it */
107 Fast486PerformInterrupt(State, State->IntAckCallback(State));
108
109 /* Clear the interrupt status */
110 State->IntSignaled = FALSE;
111 }
112 }
113 while ((Command == FAST486_CONTINUE) ||
114 (Command == FAST486_STEP_OVER && ProcedureCallCount > 0) ||
115 (Command == FAST486_STEP_OUT && ProcedureCallCount >= 0));
116 }
117
118 /* DEFAULT CALLBACKS **********************************************************/
119
120 static VOID
121 NTAPI
122 Fast486MemReadCallback(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
123 {
124 UNREFERENCED_PARAMETER(State);
125 RtlMoveMemory(Buffer, (PVOID)Address, Size);
126 }
127
128 static VOID
129 NTAPI
130 Fast486MemWriteCallback(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
131 {
132 UNREFERENCED_PARAMETER(State);
133 RtlMoveMemory((PVOID)Address, Buffer, Size);
134 }
135
136 static VOID
137 NTAPI
138 Fast486IoReadCallback(PFAST486_STATE State, USHORT Port, PVOID Buffer, ULONG DataCount, UCHAR DataSize)
139 {
140 UNREFERENCED_PARAMETER(State);
141 UNREFERENCED_PARAMETER(Port);
142 UNREFERENCED_PARAMETER(Buffer);
143 UNREFERENCED_PARAMETER(DataCount);
144 UNREFERENCED_PARAMETER(DataSize);
145 }
146
147 static VOID
148 NTAPI
149 Fast486IoWriteCallback(PFAST486_STATE State, USHORT Port, PVOID Buffer, ULONG DataCount, UCHAR DataSize)
150 {
151 UNREFERENCED_PARAMETER(State);
152 UNREFERENCED_PARAMETER(Port);
153 UNREFERENCED_PARAMETER(Buffer);
154 UNREFERENCED_PARAMETER(DataCount);
155 UNREFERENCED_PARAMETER(DataSize);
156 }
157
158 static VOID
159 NTAPI
160 Fast486BopCallback(PFAST486_STATE State, UCHAR BopCode)
161 {
162 UNREFERENCED_PARAMETER(State);
163 UNREFERENCED_PARAMETER(BopCode);
164 }
165
166 static UCHAR
167 NTAPI
168 Fast486IntAckCallback(PFAST486_STATE State)
169 {
170 UNREFERENCED_PARAMETER(State);
171
172 /* Return something... defaulted to single-step interrupt */
173 return 0x01;
174 }
175
176 static VOID NTAPI
177 Fast486FpuCallback(PFAST486_STATE State)
178 {
179 UNREFERENCED_PARAMETER(State);
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_BOP_PROC BopCallback,
192 FAST486_INT_ACK_PROC IntAckCallback,
193 FAST486_FPU_PROC FpuCallback,
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->BopCallback = (BopCallback ? BopCallback : Fast486BopCallback );
202 State->IntAckCallback = (IntAckCallback ? IntAckCallback : Fast486IntAckCallback );
203 State->FpuCallback = (FpuCallback ? FpuCallback : Fast486FpuCallback );
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 /* Save the callbacks and TLB */
219 FAST486_MEM_READ_PROC MemReadCallback = State->MemReadCallback;
220 FAST486_MEM_WRITE_PROC MemWriteCallback = State->MemWriteCallback;
221 FAST486_IO_READ_PROC IoReadCallback = State->IoReadCallback;
222 FAST486_IO_WRITE_PROC IoWriteCallback = State->IoWriteCallback;
223 FAST486_BOP_PROC BopCallback = State->BopCallback;
224 FAST486_INT_ACK_PROC IntAckCallback = State->IntAckCallback;
225 FAST486_FPU_PROC FpuCallback = State->FpuCallback;
226 PULONG Tlb = State->Tlb;
227
228 /* Clear the entire structure */
229 RtlZeroMemory(State, sizeof(*State));
230
231 /* Initialize the registers */
232 State->Flags.AlwaysSet = 1;
233 State->InstPtr.LowWord = 0xFFF0;
234
235 /* Set the CPL to 0 */
236 State->Cpl = 0;
237
238 /* Initialize segments */
239 for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
240 {
241 State->SegmentRegs[i].Selector = 0;
242 State->SegmentRegs[i].Base = 0;
243 State->SegmentRegs[i].Limit = 0xFFFF;
244 State->SegmentRegs[i].Present = TRUE;
245 State->SegmentRegs[i].ReadWrite = TRUE;
246 State->SegmentRegs[i].Executable = FALSE;
247 State->SegmentRegs[i].DirConf = FALSE;
248 State->SegmentRegs[i].SystemType = 1; // Segment descriptor
249 State->SegmentRegs[i].Dpl = 0;
250 State->SegmentRegs[i].Size = FALSE; // 16-bit
251 }
252
253 /* Initialize the code segment */
254 State->SegmentRegs[FAST486_REG_CS].Executable = TRUE;
255 State->SegmentRegs[FAST486_REG_CS].Selector = 0xF000;
256 State->SegmentRegs[FAST486_REG_CS].Base = 0xFFFF0000;
257
258 /* Initialize the IDT */
259 State->Idtr.Size = 0x3FF;
260 State->Idtr.Address = 0;
261
262 #ifndef FAST486_NO_FPU
263 /* Initialize CR0 */
264 State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_ET;
265
266 /* Initialize the FPU control and tag registers */
267 State->FpuControl.Value = FAST486_FPU_DEFAULT_CONTROL;
268 State->FpuStatus.Value = 0;
269 State->FpuTag = 0xFFFF;
270 #endif
271
272 /* Restore the callbacks and TLB */
273 State->MemReadCallback = MemReadCallback;
274 State->MemWriteCallback = MemWriteCallback;
275 State->IoReadCallback = IoReadCallback;
276 State->IoWriteCallback = IoWriteCallback;
277 State->BopCallback = BopCallback;
278 State->IntAckCallback = IntAckCallback;
279 State->FpuCallback = FpuCallback;
280 State->Tlb = Tlb;
281
282 /* Flush the TLB */
283 Fast486FlushTlb(State);
284 }
285
286 VOID
287 NTAPI
288 Fast486InterruptSignal(PFAST486_STATE State)
289 {
290 State->IntSignaled = TRUE;
291 }
292
293 VOID
294 NTAPI
295 Fast486ExecuteAt(PFAST486_STATE State, USHORT Segment, ULONG Offset)
296 {
297 /* Load the new CS */
298 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
299 {
300 /* An exception occurred, let the handler execute instead */
301 return;
302 }
303
304 /* Set the new IP */
305 State->InstPtr.Long = Offset;
306 }
307
308 VOID
309 NTAPI
310 Fast486SetStack(PFAST486_STATE State, USHORT Segment, ULONG Offset)
311 {
312 /* Load the new SS */
313 if (!Fast486LoadSegment(State, FAST486_REG_SS, Segment))
314 {
315 /* An exception occurred, let the handler execute instead */
316 return;
317 }
318
319 /* Set the new SP */
320 State->GeneralRegs[FAST486_REG_ESP].Long = Offset;
321 }
322
323 VOID
324 NTAPI
325 Fast486SetSegment(PFAST486_STATE State,
326 FAST486_SEG_REGS Segment,
327 USHORT Selector)
328 {
329 /* Call the internal function */
330 Fast486LoadSegment(State, Segment, Selector);
331 }
332
333 VOID
334 NTAPI
335 Fast486Rewind(PFAST486_STATE State)
336 {
337 /* This function is used when an instruction has been interrupted remotely */
338 State->PrefixFlags = 0;
339 State->InstPtr.Long = State->SavedInstPtr.Long;
340
341 #ifndef FAST486_NO_PREFETCH
342 State->PrefetchValid = FALSE;
343 #endif
344 }
345
346 /* EOF */