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
)
85 LPBYTE Address
= (LPBYTE
)Buffer
;
87 UNREFERENCED_PARAMETER(State
);
88 UNREFERENCED_PARAMETER(Size
);
95 *Address
= PicReadCommand(Port
);
102 *Address
= PicReadData(Port
);
106 case PIT_DATA_PORT(0):
107 case PIT_DATA_PORT(1):
108 case PIT_DATA_PORT(2):
110 *Address
= PitReadData(Port
- PIT_DATA_PORT(0));
114 case PS2_CONTROL_PORT
:
116 *Address
= KeyboardReadStatus();
122 *Address
= KeyboardReadData();
130 case VGA_DAC_READ_INDEX
:
131 case VGA_DAC_WRITE_INDEX
:
142 *Address
= VgaReadPort(Port
);
148 DPRINT1("Read from unknown port: 0x%X\n", Port
);
153 static VOID WINAPI
EmulatorWriteIo(PFAST486_STATE State
, ULONG Port
, PVOID Buffer
, ULONG Size
)
155 BYTE Byte
= *(LPBYTE
)Buffer
;
157 UNREFERENCED_PARAMETER(State
);
158 UNREFERENCED_PARAMETER(Size
);
162 case PIT_COMMAND_PORT
:
164 PitWriteCommand(Byte
);
168 case PIT_DATA_PORT(0):
169 case PIT_DATA_PORT(1):
170 case PIT_DATA_PORT(2):
172 PitWriteData(Port
- PIT_DATA_PORT(0), Byte
);
179 PicWriteCommand(Port
, Byte
);
183 case PIC_MASTER_DATA
:
186 PicWriteData(Port
, Byte
);
190 case PS2_CONTROL_PORT
:
192 KeyboardWriteCommand(Byte
);
198 KeyboardWriteData(Byte
);
206 case VGA_DAC_READ_INDEX
:
207 case VGA_DAC_WRITE_INDEX
:
218 VgaWritePort(Port
, Byte
);
224 DPRINT1("Write to unknown port: 0x%X\n", Port
);
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
);
241 if (BopProc
[BopCode
] != NULL
)
242 BopProc
[BopCode
](Stack
);
244 DPRINT1("Invalid BOP code %u\n", BopCode
);
247 static UCHAR WINAPI
EmulatorIntAcknowledge(PFAST486_STATE State
)
249 UNREFERENCED_PARAMETER(State
);
251 /* Get the interrupt number from the PIC */
252 return PicGetInterrupt();
255 /* PUBLIC FUNCTIONS ***********************************************************/
257 BOOLEAN
EmulatorInitialize(VOID
)
259 /* Allocate memory for the 16-bit address space */
260 BaseAddress
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, MAX_ADDRESS
);
261 if (BaseAddress
== NULL
) return FALSE
;
263 /* Initialize the CPU */
264 Fast486Initialize(&EmulatorContext
,
270 EmulatorBiosOperation
,
271 EmulatorIntAcknowledge
);
273 /* Enable interrupts */
274 EmulatorSetFlag(EMULATOR_FLAG_IF
);
279 VOID
EmulatorCleanup(VOID
)
281 /* Free the memory allocated for the 16-bit address space */
282 if (BaseAddress
!= NULL
) HeapFree(GetProcessHeap(), 0, BaseAddress
);
285 VOID
EmulatorSetStack(WORD Segment
, DWORD Offset
)
287 Fast486SetStack(&EmulatorContext
, Segment
, Offset
);
290 // FIXME: This function assumes 16-bit mode!!!
291 VOID
EmulatorExecute(WORD Segment
, WORD Offset
)
293 /* Tell Fast486 to move the instruction pointer */
294 Fast486ExecuteAt(&EmulatorContext
, Segment
, Offset
);
297 VOID
EmulatorInterrupt(BYTE Number
)
299 /* Call the Fast486 API */
300 Fast486Interrupt(&EmulatorContext
, Number
);
303 VOID
EmulatorInterruptSignal(VOID
)
305 /* Call the Fast486 API */
306 Fast486InterruptSignal(&EmulatorContext
);
309 ULONG
EmulatorGetRegister(ULONG Register
)
311 if (Register
< EMULATOR_REG_ES
)
313 return EmulatorContext
.GeneralRegs
[Register
].Long
;
317 return EmulatorContext
.SegmentRegs
[Register
- EMULATOR_REG_ES
].Selector
;
321 VOID
EmulatorSetRegister(ULONG Register
, ULONG Value
)
323 if (Register
< EMULATOR_REG_ES
)
325 EmulatorContext
.GeneralRegs
[Register
].Long
= Value
;
329 Fast486SetSegment(&EmulatorContext
, Register
- EMULATOR_REG_ES
, (USHORT
)Value
);
333 ULONG
EmulatorGetProgramCounter(VOID
)
335 return EmulatorContext
.InstPtr
.Long
;
338 BOOLEAN
EmulatorGetFlag(ULONG Flag
)
340 return (EmulatorContext
.Flags
.Long
& Flag
) ? TRUE
: FALSE
;
343 VOID
EmulatorSetFlag(ULONG Flag
)
345 EmulatorContext
.Flags
.Long
|= Flag
;
348 VOID
EmulatorClearFlag(ULONG Flag
)
350 EmulatorContext
.Flags
.Long
&= ~Flag
;
353 VOID
EmulatorStep(VOID
)
355 /* Dump the state for debugging purposes */
356 // Fast486DumpState(&EmulatorContext);
358 /* Execute the next instruction */
359 Fast486StepInto(&EmulatorContext
);
362 VOID
EmulatorSetA20(BOOLEAN Enabled
)