xref: /reactos/sdk/lib/fast486/fast486.c (revision 53221834)
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
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
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
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
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
76 Fast486BopCallback(PFAST486_STATE State, UCHAR BopCode)
77 {
78     UNREFERENCED_PARAMETER(State);
79     UNREFERENCED_PARAMETER(BopCode);
80 }
81 
82 static UCHAR
83 FASTCALL
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
94 Fast486FpuCallback(PFAST486_STATE State)
95 {
96     UNREFERENCED_PARAMETER(State);
97 }
98 
99 /* PUBLIC FUNCTIONS ***********************************************************/
100 
101 VOID
102 NTAPI
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
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
205 Fast486InterruptSignal(PFAST486_STATE State)
206 {
207     State->IntSignaled = TRUE;
208 }
209 
210 VOID
211 NTAPI
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
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
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
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