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 *******************************************************************/
21 /* PRIVATE VARIABLES **********************************************************/
23 FAST486_STATE EmulatorContext
;
25 static BOOLEAN A20Line
= FALSE
;
27 /* PRIVATE FUNCTIONS **********************************************************/
29 static VOID WINAPI
EmulatorReadMemory(PFAST486_STATE State
, ULONG Address
, PVOID Buffer
, ULONG Size
)
31 UNREFERENCED_PARAMETER(State
);
33 /* If the A20 line is disabled, mask bit 20 */
34 if (!A20Line
) Address
&= ~(1 << 20);
36 /* Make sure the requested address is valid */
37 if ((Address
+ Size
) >= MAX_ADDRESS
) return;
39 /* Read the data from the virtual address space and store it in the buffer */
40 RtlCopyMemory(Buffer
, (LPVOID
)((ULONG_PTR
)BaseAddress
+ Address
), Size
);
42 /* Check if we modified the console video memory */
43 if (((Address
+ Size
) >= VgaGetVideoBaseAddress())
44 && (Address
< VgaGetVideoLimitAddress()))
46 DWORD VgaAddress
= max(Address
, VgaGetVideoBaseAddress());
47 LPBYTE VgaBuffer
= (LPBYTE
)((ULONG_PTR
)Buffer
+ VgaAddress
- Address
);
49 /* Read from the VGA memory */
50 VgaReadMemory(VgaAddress
, VgaBuffer
, Size
);
54 static VOID WINAPI
EmulatorWriteMemory(PFAST486_STATE State
, ULONG Address
, PVOID Buffer
, ULONG Size
)
56 UNREFERENCED_PARAMETER(State
);
58 /* If the A20 line is disabled, mask bit 20 */
59 if (!A20Line
) Address
&= ~(1 << 20);
61 /* Make sure the requested address is valid */
62 if ((Address
+ Size
) >= MAX_ADDRESS
) return;
64 /* Make sure we don't write to the ROM area */
65 if ((Address
+ Size
) >= ROM_AREA_START
&& (Address
< ROM_AREA_END
)) return;
67 /* Read the data from the buffer and store it in the virtual address space */
68 RtlCopyMemory((LPVOID
)((ULONG_PTR
)BaseAddress
+ Address
), Buffer
, Size
);
70 /* Check if we modified the console video memory */
71 if (((Address
+ Size
) >= VgaGetVideoBaseAddress())
72 && (Address
< VgaGetVideoLimitAddress()))
74 DWORD VgaAddress
= max(Address
, VgaGetVideoBaseAddress());
75 LPBYTE VgaBuffer
= (LPBYTE
)((ULONG_PTR
)Buffer
+ VgaAddress
- Address
);
77 /* Write to the VGA memory */
78 VgaWriteMemory(VgaAddress
, VgaBuffer
, Size
);
82 static VOID WINAPI
EmulatorReadIo(PFAST486_STATE State
, ULONG Port
, PVOID Buffer
, ULONG Size
)
84 LPBYTE Address
= (LPBYTE
)Buffer
;
86 UNREFERENCED_PARAMETER(State
);
87 UNREFERENCED_PARAMETER(Size
);
94 *Address
= PicReadCommand(Port
);
101 *Address
= PicReadData(Port
);
105 case PIT_DATA_PORT(0):
106 case PIT_DATA_PORT(1):
107 case PIT_DATA_PORT(2):
109 *Address
= PitReadData(Port
- PIT_DATA_PORT(0));
113 case PS2_CONTROL_PORT
:
115 *Address
= KeyboardReadStatus();
121 *Address
= KeyboardReadData();
129 case VGA_DAC_READ_INDEX
:
130 case VGA_DAC_WRITE_INDEX
:
141 *Address
= VgaReadPort(Port
);
147 DPRINT1("Read from unknown port: 0x%X\n", Port
);
152 static VOID WINAPI
EmulatorWriteIo(PFAST486_STATE State
, ULONG Port
, PVOID Buffer
, ULONG Size
)
154 BYTE Byte
= *(LPBYTE
)Buffer
;
156 UNREFERENCED_PARAMETER(State
);
157 UNREFERENCED_PARAMETER(Size
);
161 case PIT_COMMAND_PORT
:
163 PitWriteCommand(Byte
);
167 case PIT_DATA_PORT(0):
168 case PIT_DATA_PORT(1):
169 case PIT_DATA_PORT(2):
171 PitWriteData(Port
- PIT_DATA_PORT(0), Byte
);
178 PicWriteCommand(Port
, Byte
);
182 case PIC_MASTER_DATA
:
185 PicWriteData(Port
, Byte
);
189 case PS2_CONTROL_PORT
:
191 KeyboardWriteCommand(Byte
);
197 KeyboardWriteData(Byte
);
205 case VGA_DAC_READ_INDEX
:
206 case VGA_DAC_WRITE_INDEX
:
217 VgaWritePort(Port
, Byte
);
223 DPRINT1("Write to unknown port: 0x%X\n", Port
);
228 VOID WINAPI
ControlBop(LPWORD Stack
);
229 static VOID WINAPI
EmulatorBiosOperation(PFAST486_STATE State
, UCHAR BopCode
)
231 WORD StackSegment
, StackPointer
;
235 StackSegment
= State
->SegmentRegs
[FAST486_REG_SS
].Selector
;
236 StackPointer
= State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
;
239 Stack
= (LPWORD
)SEG_OFF_TO_PTR(StackSegment
, StackPointer
);
243 case EMULATOR_INT_BOP
:
248 DPRINT1("Invalid BOP code %u\n", BopCode
);
253 static VOID WINAPI
EmulatorIdle(PFAST486_STATE State
)
257 static UCHAR WINAPI
EmulatorIntAcknowledge(PFAST486_STATE State
)
259 UNREFERENCED_PARAMETER(State
);
261 /* Get the interrupt number from the PIC */
262 return PicGetInterrupt();
265 /* PUBLIC FUNCTIONS ***********************************************************/
267 BOOLEAN
EmulatorInitialize()
269 /* Allocate memory for the 16-bit address space */
270 BaseAddress
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, MAX_ADDRESS
);
271 if (BaseAddress
== NULL
) return FALSE
;
273 /* Set the callbacks */
274 EmulatorContext
.MemReadCallback
= EmulatorReadMemory
;
275 EmulatorContext
.MemWriteCallback
= EmulatorWriteMemory
;
276 EmulatorContext
.IoReadCallback
= EmulatorReadIo
; // Must be != NULL
277 EmulatorContext
.IoWriteCallback
= EmulatorWriteIo
; // Must be != NULL
278 EmulatorContext
.IdleCallback
= EmulatorIdle
; // Must be != NULL
279 EmulatorContext
.BopCallback
= EmulatorBiosOperation
;
280 EmulatorContext
.IntAckCallback
= EmulatorIntAcknowledge
;
283 Fast486Reset(&EmulatorContext
);
285 /* Enable interrupts */
286 EmulatorSetFlag(EMULATOR_FLAG_IF
);
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
EmulatorCleanup(VOID
)
370 /* Free the memory allocated for the 16-bit address space */
371 if (BaseAddress
!= NULL
) HeapFree(GetProcessHeap(), 0, BaseAddress
);
374 VOID
EmulatorSetA20(BOOLEAN Enabled
)