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 /* DEFAULT CALLBACKS **********************************************************/
35
36 static VOID
37 FASTCALL
Fast486MemReadCallback(PFAST486_STATE State,ULONG Address,PVOID Buffer,ULONG Size)38 Fast486MemReadCallback(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
39 {
40 UNREFERENCED_PARAMETER(State);
41 RtlMoveMemory(Buffer, UlongToPtr(Address), Size);
42 }
43
44 static VOID
45 FASTCALL
Fast486MemWriteCallback(PFAST486_STATE State,ULONG Address,PVOID Buffer,ULONG Size)46 Fast486MemWriteCallback(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
47 {
48 UNREFERENCED_PARAMETER(State);
49 RtlMoveMemory(UlongToPtr(Address), Buffer, Size);
50 }
51
52 static VOID
53 FASTCALL
Fast486IoReadCallback(PFAST486_STATE State,USHORT Port,PVOID Buffer,ULONG DataCount,UCHAR DataSize)54 Fast486IoReadCallback(PFAST486_STATE State, USHORT Port, PVOID Buffer, ULONG DataCount, UCHAR DataSize)
55 {
56 UNREFERENCED_PARAMETER(State);
57 UNREFERENCED_PARAMETER(Port);
58 UNREFERENCED_PARAMETER(Buffer);
59 UNREFERENCED_PARAMETER(DataCount);
60 UNREFERENCED_PARAMETER(DataSize);
61 }
62
63 static VOID
64 FASTCALL
Fast486IoWriteCallback(PFAST486_STATE State,USHORT Port,PVOID Buffer,ULONG DataCount,UCHAR DataSize)65 Fast486IoWriteCallback(PFAST486_STATE State, USHORT Port, PVOID Buffer, ULONG DataCount, UCHAR DataSize)
66 {
67 UNREFERENCED_PARAMETER(State);
68 UNREFERENCED_PARAMETER(Port);
69 UNREFERENCED_PARAMETER(Buffer);
70 UNREFERENCED_PARAMETER(DataCount);
71 UNREFERENCED_PARAMETER(DataSize);
72 }
73
74 static VOID
75 FASTCALL
Fast486BopCallback(PFAST486_STATE State,UCHAR BopCode)76 Fast486BopCallback(PFAST486_STATE State, UCHAR BopCode)
77 {
78 UNREFERENCED_PARAMETER(State);
79 UNREFERENCED_PARAMETER(BopCode);
80 }
81
82 static UCHAR
83 FASTCALL
Fast486IntAckCallback(PFAST486_STATE State)84 Fast486IntAckCallback(PFAST486_STATE State)
85 {
86 UNREFERENCED_PARAMETER(State);
87
88 /* Return something... defaulted to single-step interrupt */
89 return 0x01;
90 }
91
92 static VOID
93 FASTCALL
Fast486FpuCallback(PFAST486_STATE State)94 Fast486FpuCallback(PFAST486_STATE State)
95 {
96 UNREFERENCED_PARAMETER(State);
97 }
98
99 /* PUBLIC FUNCTIONS ***********************************************************/
100
101 VOID
102 NTAPI
Fast486Initialize(PFAST486_STATE State,FAST486_MEM_READ_PROC MemReadCallback,FAST486_MEM_WRITE_PROC MemWriteCallback,FAST486_IO_READ_PROC IoReadCallback,FAST486_IO_WRITE_PROC IoWriteCallback,FAST486_BOP_PROC BopCallback,FAST486_INT_ACK_PROC IntAckCallback,FAST486_FPU_PROC FpuCallback,PULONG Tlb)103 Fast486Initialize(PFAST486_STATE State,
104 FAST486_MEM_READ_PROC MemReadCallback,
105 FAST486_MEM_WRITE_PROC MemWriteCallback,
106 FAST486_IO_READ_PROC IoReadCallback,
107 FAST486_IO_WRITE_PROC IoWriteCallback,
108 FAST486_BOP_PROC BopCallback,
109 FAST486_INT_ACK_PROC IntAckCallback,
110 FAST486_FPU_PROC FpuCallback,
111 PULONG Tlb)
112 {
113 /* Set the callbacks (or use default ones if some are NULL) */
114 State->MemReadCallback = (MemReadCallback ? MemReadCallback : Fast486MemReadCallback );
115 State->MemWriteCallback = (MemWriteCallback ? MemWriteCallback : Fast486MemWriteCallback);
116 State->IoReadCallback = (IoReadCallback ? IoReadCallback : Fast486IoReadCallback );
117 State->IoWriteCallback = (IoWriteCallback ? IoWriteCallback : Fast486IoWriteCallback );
118 State->BopCallback = (BopCallback ? BopCallback : Fast486BopCallback );
119 State->IntAckCallback = (IntAckCallback ? IntAckCallback : Fast486IntAckCallback );
120 State->FpuCallback = (FpuCallback ? FpuCallback : Fast486FpuCallback );
121
122 /* Set the TLB (if given) */
123 State->Tlb = Tlb;
124
125 /* Reset the CPU */
126 Fast486Reset(State);
127 }
128
129 VOID
130 NTAPI
Fast486Reset(PFAST486_STATE State)131 Fast486Reset(PFAST486_STATE State)
132 {
133 FAST486_SEG_REGS i;
134
135 /* Save the callbacks and TLB */
136 FAST486_MEM_READ_PROC MemReadCallback = State->MemReadCallback;
137 FAST486_MEM_WRITE_PROC MemWriteCallback = State->MemWriteCallback;
138 FAST486_IO_READ_PROC IoReadCallback = State->IoReadCallback;
139 FAST486_IO_WRITE_PROC IoWriteCallback = State->IoWriteCallback;
140 FAST486_BOP_PROC BopCallback = State->BopCallback;
141 FAST486_INT_ACK_PROC IntAckCallback = State->IntAckCallback;
142 FAST486_FPU_PROC FpuCallback = State->FpuCallback;
143 PULONG Tlb = State->Tlb;
144
145 /* Clear the entire structure */
146 RtlZeroMemory(State, sizeof(*State));
147
148 /* Initialize the registers */
149 State->Flags.AlwaysSet = 1;
150 State->InstPtr.LowWord = 0xFFF0;
151
152 /* Set the CPL to 0 */
153 State->Cpl = 0;
154
155 /* Initialize segments */
156 for (i = 0; i < FAST486_NUM_SEG_REGS; i++)
157 {
158 State->SegmentRegs[i].Selector = 0;
159 State->SegmentRegs[i].Base = 0;
160 State->SegmentRegs[i].Limit = 0xFFFF;
161 State->SegmentRegs[i].Present = TRUE;
162 State->SegmentRegs[i].ReadWrite = TRUE;
163 State->SegmentRegs[i].Executable = FALSE;
164 State->SegmentRegs[i].DirConf = FALSE;
165 State->SegmentRegs[i].SystemType = 1; // Segment descriptor
166 State->SegmentRegs[i].Dpl = 0;
167 State->SegmentRegs[i].Size = FALSE; // 16-bit
168 }
169
170 /* Initialize the code segment */
171 State->SegmentRegs[FAST486_REG_CS].Executable = TRUE;
172 State->SegmentRegs[FAST486_REG_CS].Selector = 0xF000;
173 State->SegmentRegs[FAST486_REG_CS].Base = 0xFFFF0000;
174
175 /* Initialize the IDT */
176 State->Idtr.Size = 0x3FF;
177 State->Idtr.Address = 0;
178
179 #ifndef FAST486_NO_FPU
180 /* Initialize CR0 */
181 State->ControlRegisters[FAST486_REG_CR0] |= FAST486_CR0_ET;
182
183 /* Initialize the FPU control and tag registers */
184 State->FpuControl.Value = FAST486_FPU_DEFAULT_CONTROL;
185 State->FpuStatus.Value = 0;
186 State->FpuTag = 0xFFFF;
187 #endif
188
189 /* Restore the callbacks and TLB */
190 State->MemReadCallback = MemReadCallback;
191 State->MemWriteCallback = MemWriteCallback;
192 State->IoReadCallback = IoReadCallback;
193 State->IoWriteCallback = IoWriteCallback;
194 State->BopCallback = BopCallback;
195 State->IntAckCallback = IntAckCallback;
196 State->FpuCallback = FpuCallback;
197 State->Tlb = Tlb;
198
199 /* Flush the TLB */
200 Fast486FlushTlb(State);
201 }
202
203 VOID
204 NTAPI
Fast486InterruptSignal(PFAST486_STATE State)205 Fast486InterruptSignal(PFAST486_STATE State)
206 {
207 State->IntSignaled = TRUE;
208 }
209
210 VOID
211 NTAPI
Fast486ExecuteAt(PFAST486_STATE State,USHORT Segment,ULONG Offset)212 Fast486ExecuteAt(PFAST486_STATE State, USHORT Segment, ULONG Offset)
213 {
214 /* Load the new CS */
215 if (!Fast486LoadSegment(State, FAST486_REG_CS, Segment))
216 {
217 /* An exception occurred, let the handler execute instead */
218 return;
219 }
220
221 /* Set the new IP */
222 State->InstPtr.Long = Offset;
223 }
224
225 VOID
226 NTAPI
Fast486SetStack(PFAST486_STATE State,USHORT Segment,ULONG Offset)227 Fast486SetStack(PFAST486_STATE State, USHORT Segment, ULONG Offset)
228 {
229 /* Load the new SS */
230 if (!Fast486LoadSegment(State, FAST486_REG_SS, Segment))
231 {
232 /* An exception occurred, let the handler execute instead */
233 return;
234 }
235
236 /* Set the new SP */
237 State->GeneralRegs[FAST486_REG_ESP].Long = Offset;
238 }
239
240 VOID
241 NTAPI
Fast486SetSegment(PFAST486_STATE State,FAST486_SEG_REGS Segment,USHORT Selector)242 Fast486SetSegment(PFAST486_STATE State,
243 FAST486_SEG_REGS Segment,
244 USHORT Selector)
245 {
246 /* Call the internal function */
247 Fast486LoadSegment(State, Segment, Selector);
248 }
249
250 VOID
251 NTAPI
Fast486Rewind(PFAST486_STATE State)252 Fast486Rewind(PFAST486_STATE State)
253 {
254 /* This function is used when an instruction has been interrupted remotely */
255 State->PrefixFlags = 0;
256 State->InstPtr.Long = State->SavedInstPtr.Long;
257
258 #ifndef FAST486_NO_PREFETCH
259 State->PrefetchValid = FALSE;
260 #endif
261 }
262
263 /* EOF */
264