2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: Minimal x86 machine emulator for the VDM
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
22 /* PRIVATE VARIABLES **********************************************************/
24 FAST486_STATE EmulatorContext
;
26 static BOOLEAN A20Line
= FALSE
;
28 /* PRIVATE FUNCTIONS **********************************************************/
30 static VOID WINAPI
EmulatorReadMemory(PFAST486_STATE State
, ULONG Address
, PVOID Buffer
, ULONG Size
)
32 UNREFERENCED_PARAMETER(State
);
34 /* If the A20 line is disabled, mask bit 20 */
35 if (!A20Line
) Address
&= ~(1 << 20);
37 /* Make sure the requested address is valid */
38 if ((Address
+ Size
) >= MAX_ADDRESS
) return;
40 /* Read the data from the virtual address space and store it in the buffer */
41 RtlCopyMemory(Buffer
, (LPVOID
)((ULONG_PTR
)BaseAddress
+ Address
), Size
);
43 /* Check if we modified the console video memory */
44 if (((Address
+ Size
) >= VgaGetVideoBaseAddress())
45 && (Address
< VgaGetVideoLimitAddress()))
47 DWORD VgaAddress
= max(Address
, VgaGetVideoBaseAddress());
48 LPBYTE VgaBuffer
= (LPBYTE
)((ULONG_PTR
)Buffer
+ VgaAddress
- Address
);
50 /* Read from the VGA memory */
51 VgaReadMemory(VgaAddress
, VgaBuffer
, Size
);
55 static VOID WINAPI
EmulatorWriteMemory(PFAST486_STATE State
, ULONG Address
, PVOID Buffer
, ULONG Size
)
57 UNREFERENCED_PARAMETER(State
);
59 /* If the A20 line is disabled, mask bit 20 */
60 if (!A20Line
) Address
&= ~(1 << 20);
62 /* Make sure the requested address is valid */
63 if ((Address
+ Size
) >= MAX_ADDRESS
) return;
65 /* Make sure we don't write to the ROM area */
66 if ((Address
+ Size
) >= ROM_AREA_START
&& (Address
< ROM_AREA_END
)) return;
68 /* Read the data from the buffer and store it in the virtual address space */
69 RtlCopyMemory((LPVOID
)((ULONG_PTR
)BaseAddress
+ Address
), Buffer
, Size
);
71 /* Check if we modified the console video memory */
72 if (((Address
+ Size
) >= VgaGetVideoBaseAddress())
73 && (Address
< VgaGetVideoLimitAddress()))
75 DWORD VgaAddress
= max(Address
, VgaGetVideoBaseAddress());
76 LPBYTE VgaBuffer
= (LPBYTE
)((ULONG_PTR
)Buffer
+ VgaAddress
- Address
);
78 /* Write to the VGA memory */
79 VgaWriteMemory(VgaAddress
, VgaBuffer
, Size
);
83 static VOID WINAPI
EmulatorReadIo(PFAST486_STATE State
, ULONG Port
, PVOID Buffer
, ULONG Size
)
86 LPBYTE Address
= (LPBYTE
)Buffer
;
88 UNREFERENCED_PARAMETER(State
);
90 for (i
= 0; i
< Size
; i
++)
97 *(Address
++) = PicReadCommand(Port
);
101 case PIC_MASTER_DATA
:
104 *(Address
++) = PicReadData(Port
);
108 case PIT_DATA_PORT(0):
109 case PIT_DATA_PORT(1):
110 case PIT_DATA_PORT(2):
112 *(Address
++) = PitReadData(Port
- PIT_DATA_PORT(0));
116 case PS2_CONTROL_PORT
:
118 *(Address
++) = KeyboardReadStatus();
124 *(Address
++) = KeyboardReadData();
132 case VGA_DAC_READ_INDEX
:
133 case VGA_DAC_WRITE_INDEX
:
144 *(Address
++) = VgaReadPort(Port
);
150 DPRINT1("Read from unknown port: 0x%X\n", Port
);
156 static VOID WINAPI
EmulatorWriteIo(PFAST486_STATE State
, ULONG Port
, PVOID Buffer
, ULONG Size
)
159 LPBYTE Address
= (LPBYTE
)Buffer
;
161 UNREFERENCED_PARAMETER(State
);
163 for (i
= 0; i
< Size
; i
++)
167 case PIT_COMMAND_PORT
:
169 PitWriteCommand(*(Address
++));
173 case PIT_DATA_PORT(0):
174 case PIT_DATA_PORT(1):
175 case PIT_DATA_PORT(2):
177 PitWriteData(Port
- PIT_DATA_PORT(0), *(Address
++));
184 PicWriteCommand(Port
, *(Address
++));
188 case PIC_MASTER_DATA
:
191 PicWriteData(Port
, *(Address
++));
195 case PS2_CONTROL_PORT
:
197 KeyboardWriteCommand(*(Address
++));
203 KeyboardWriteData(*(Address
++));
211 case VGA_DAC_READ_INDEX
:
212 case VGA_DAC_WRITE_INDEX
:
223 VgaWritePort(Port
, *(Address
++));
229 DPRINT1("Write to unknown port: 0x%X\n", Port
);
235 static VOID WINAPI
EmulatorBiosOperation(PFAST486_STATE State
, UCHAR BopCode
)
237 WORD StackSegment
, StackPointer
;
241 StackSegment
= State
->SegmentRegs
[FAST486_REG_SS
].Selector
;
242 StackPointer
= State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
;
245 Stack
= (LPWORD
)SEG_OFF_TO_PTR(StackSegment
, StackPointer
);
247 if (BopProc
[BopCode
] != NULL
)
248 BopProc
[BopCode
](Stack
);
250 DPRINT1("Invalid BOP code %u\n", BopCode
);
253 static UCHAR WINAPI
EmulatorIntAcknowledge(PFAST486_STATE State
)
255 UNREFERENCED_PARAMETER(State
);
257 /* Get the interrupt number from the PIC */
258 return PicGetInterrupt();
261 /* PUBLIC FUNCTIONS ***********************************************************/
263 BOOLEAN
EmulatorInitialize(VOID
)
265 /* Allocate memory for the 16-bit address space */
266 BaseAddress
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, MAX_ADDRESS
);
267 if (BaseAddress
== NULL
) return FALSE
;
269 /* Initialize the CPU */
270 Fast486Initialize(&EmulatorContext
,
276 EmulatorBiosOperation
,
277 EmulatorIntAcknowledge
);
279 /* Enable interrupts */
280 EmulatorSetFlag(EMULATOR_FLAG_IF
);
285 VOID
EmulatorCleanup(VOID
)
287 /* Free the memory allocated for the 16-bit address space */
288 if (BaseAddress
!= NULL
) HeapFree(GetProcessHeap(), 0, BaseAddress
);
291 VOID
EmulatorSetStack(WORD Segment
, DWORD Offset
)
293 Fast486SetStack(&EmulatorContext
, Segment
, Offset
);
296 // FIXME: This function assumes 16-bit mode!!!
297 VOID
EmulatorExecute(WORD Segment
, WORD Offset
)
299 /* Tell Fast486 to move the instruction pointer */
300 Fast486ExecuteAt(&EmulatorContext
, Segment
, Offset
);
303 VOID
EmulatorInterrupt(BYTE Number
)
305 /* Call the Fast486 API */
306 Fast486Interrupt(&EmulatorContext
, Number
);
309 VOID
EmulatorInterruptSignal(VOID
)
311 /* Call the Fast486 API */
312 Fast486InterruptSignal(&EmulatorContext
);
315 ULONG
EmulatorGetRegister(ULONG Register
)
317 if (Register
< EMULATOR_REG_ES
)
319 return EmulatorContext
.GeneralRegs
[Register
].Long
;
323 return EmulatorContext
.SegmentRegs
[Register
- EMULATOR_REG_ES
].Selector
;
327 VOID
EmulatorSetRegister(ULONG Register
, ULONG Value
)
329 if (Register
< EMULATOR_REG_ES
)
331 EmulatorContext
.GeneralRegs
[Register
].Long
= Value
;
335 Fast486SetSegment(&EmulatorContext
, Register
- EMULATOR_REG_ES
, (USHORT
)Value
);
339 ULONG
EmulatorGetProgramCounter(VOID
)
341 return EmulatorContext
.InstPtr
.Long
;
344 BOOLEAN
EmulatorGetFlag(ULONG Flag
)
346 return (EmulatorContext
.Flags
.Long
& Flag
) ? TRUE
: FALSE
;
349 VOID
EmulatorSetFlag(ULONG Flag
)
351 EmulatorContext
.Flags
.Long
|= Flag
;
354 VOID
EmulatorClearFlag(ULONG Flag
)
356 EmulatorContext
.Flags
.Long
&= ~Flag
;
359 VOID
EmulatorStep(VOID
)
361 /* Dump the state for debugging purposes */
362 // Fast486DumpState(&EmulatorContext);
364 /* Execute the next instruction */
365 Fast486StepInto(&EmulatorContext
);
368 VOID
EmulatorSetA20(BOOLEAN Enabled
)