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 *******************************************************************/
24 /* PRIVATE VARIABLES **********************************************************/
26 FAST486_STATE EmulatorContext
;
28 static BOOLEAN A20Line
= FALSE
;
30 /* PRIVATE FUNCTIONS **********************************************************/
32 VOID WINAPI
EmulatorReadMemory(PFAST486_STATE State
, ULONG Address
, PVOID Buffer
, ULONG Size
)
34 UNREFERENCED_PARAMETER(State
);
36 /* If the A20 line is disabled, mask bit 20 */
37 if (!A20Line
) Address
&= ~(1 << 20);
39 /* Make sure the requested address is valid */
40 if ((Address
+ Size
) >= MAX_ADDRESS
) return;
42 /* Read the data from the virtual address space and store it in the buffer */
43 RtlCopyMemory(Buffer
, (LPVOID
)((ULONG_PTR
)BaseAddress
+ Address
), Size
);
45 /* Check if we modified the console video memory */
46 if (((Address
+ Size
) >= VgaGetVideoBaseAddress())
47 && (Address
< VgaGetVideoLimitAddress()))
49 DWORD VgaAddress
= max(Address
, VgaGetVideoBaseAddress());
50 DWORD ActualSize
= min(Address
+ Size
- 1, VgaGetVideoLimitAddress())
52 LPBYTE VgaBuffer
= (LPBYTE
)((ULONG_PTR
)Buffer
+ VgaAddress
- Address
);
54 /* Read from the VGA memory */
55 VgaReadMemory(VgaAddress
, VgaBuffer
, ActualSize
);
59 VOID WINAPI
EmulatorWriteMemory(PFAST486_STATE State
, ULONG Address
, PVOID Buffer
, ULONG Size
)
61 UNREFERENCED_PARAMETER(State
);
63 /* If the A20 line is disabled, mask bit 20 */
64 if (!A20Line
) Address
&= ~(1 << 20);
66 /* Make sure the requested address is valid */
67 if ((Address
+ Size
) >= MAX_ADDRESS
) return;
69 /* Make sure we don't write to the ROM area */
70 if ((Address
+ Size
) >= ROM_AREA_START
&& (Address
< ROM_AREA_END
)) return;
72 /* Read the data from the buffer and store it in the virtual address space */
73 RtlCopyMemory((LPVOID
)((ULONG_PTR
)BaseAddress
+ Address
), Buffer
, Size
);
75 /* Check if we modified the console video memory */
76 if (((Address
+ Size
) >= VgaGetVideoBaseAddress())
77 && (Address
< VgaGetVideoLimitAddress()))
79 DWORD VgaAddress
= max(Address
, VgaGetVideoBaseAddress());
80 DWORD ActualSize
= min(Address
+ Size
- 1, VgaGetVideoLimitAddress())
82 LPBYTE VgaBuffer
= (LPBYTE
)((ULONG_PTR
)Buffer
+ VgaAddress
- Address
);
84 /* Write to the VGA memory */
85 VgaWriteMemory(VgaAddress
, VgaBuffer
, ActualSize
);
89 VOID WINAPI
EmulatorReadIo(PFAST486_STATE State
, ULONG Port
, PVOID Buffer
, ULONG DataCount
, UCHAR DataSize
)
92 LPBYTE Address
= (LPBYTE
)Buffer
;
94 UNREFERENCED_PARAMETER(State
);
96 for (i
= 0; i
< DataCount
; i
++) for (j
= 0; j
< DataSize
; j
++)
98 ULONG CurrentPort
= Port
+ j
;
105 *(Address
++) = PicReadCommand(CurrentPort
);
109 case PIC_MASTER_DATA
:
112 *(Address
++) = PicReadData(CurrentPort
);
116 case PIT_DATA_PORT(0):
117 case PIT_DATA_PORT(1):
118 case PIT_DATA_PORT(2):
120 *(Address
++) = PitReadData(CurrentPort
- PIT_DATA_PORT(0));
124 case PS2_CONTROL_PORT
:
126 *(Address
++) = KeyboardReadStatus();
132 *(Address
++) = KeyboardReadData();
138 *(Address
++) = CmosReadData();
142 case SPEAKER_CONTROL_PORT
:
144 *(Address
++) = SpeakerReadStatus();
152 case VGA_DAC_READ_INDEX
:
153 case VGA_DAC_WRITE_INDEX
:
164 *(Address
++) = VgaReadPort(CurrentPort
);
170 DPRINT1("Read from unknown port: 0x%X\n", CurrentPort
);
176 VOID WINAPI
EmulatorWriteIo(PFAST486_STATE State
, ULONG Port
, PVOID Buffer
, ULONG DataCount
, UCHAR DataSize
)
179 LPBYTE Address
= (LPBYTE
)Buffer
;
181 UNREFERENCED_PARAMETER(State
);
183 for (i
= 0; i
< DataCount
; i
++) for (j
= 0; j
< DataSize
; j
++)
185 ULONG CurrentPort
= Port
+ j
;
189 case PIT_COMMAND_PORT
:
191 PitWriteCommand(*(Address
++));
195 case PIT_DATA_PORT(0):
196 case PIT_DATA_PORT(1):
197 case PIT_DATA_PORT(2):
199 PitWriteData(CurrentPort
- PIT_DATA_PORT(0), *(Address
++));
206 PicWriteCommand(CurrentPort
, *(Address
++));
210 case PIC_MASTER_DATA
:
213 PicWriteData(CurrentPort
, *(Address
++));
217 case PS2_CONTROL_PORT
:
219 KeyboardWriteCommand(*(Address
++));
225 KeyboardWriteData(*(Address
++));
229 case CMOS_ADDRESS_PORT
:
231 CmosWriteAddress(*(Address
++));
237 CmosWriteData(*(Address
++));
241 case SPEAKER_CONTROL_PORT
:
243 SpeakerWriteCommand(*(Address
++));
251 case VGA_DAC_READ_INDEX
:
252 case VGA_DAC_WRITE_INDEX
:
263 VgaWritePort(CurrentPort
, *(Address
++));
269 DPRINT1("Write to unknown port: 0x%X\n", CurrentPort
);
275 VOID WINAPI
EmulatorBiosOperation(PFAST486_STATE State
, UCHAR BopCode
)
277 WORD StackSegment
, StackPointer
;
281 StackSegment
= State
->SegmentRegs
[FAST486_REG_SS
].Selector
;
282 StackPointer
= State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
;
285 Stack
= (LPWORD
)SEG_OFF_TO_PTR(StackSegment
, StackPointer
);
287 if (BopProc
[BopCode
] != NULL
)
288 BopProc
[BopCode
](Stack
);
290 DPRINT1("Invalid BOP code %u\n", BopCode
);
293 UCHAR WINAPI
EmulatorIntAcknowledge(PFAST486_STATE State
)
295 UNREFERENCED_PARAMETER(State
);
297 /* Get the interrupt number from the PIC */
298 return PicGetInterrupt();
301 /* PUBLIC FUNCTIONS ***********************************************************/
303 BOOLEAN
EmulatorInitialize(VOID
)
305 /* Allocate memory for the 16-bit address space */
306 BaseAddress
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, MAX_ADDRESS
);
307 if (BaseAddress
== NULL
) return FALSE
;
309 /* Initialize the CPU */
310 Fast486Initialize(&EmulatorContext
,
316 EmulatorBiosOperation
,
317 EmulatorIntAcknowledge
);
319 /* Enable interrupts */
320 EmulatorSetFlag(EMULATOR_FLAG_IF
);
325 VOID
EmulatorCleanup(VOID
)
327 /* Free the memory allocated for the 16-bit address space */
328 if (BaseAddress
!= NULL
) HeapFree(GetProcessHeap(), 0, BaseAddress
);
331 VOID
EmulatorSetStack(WORD Segment
, DWORD Offset
)
333 Fast486SetStack(&EmulatorContext
, Segment
, Offset
);
336 // FIXME: This function assumes 16-bit mode!!!
337 VOID
EmulatorExecute(WORD Segment
, WORD Offset
)
339 /* Tell Fast486 to move the instruction pointer */
340 Fast486ExecuteAt(&EmulatorContext
, Segment
, Offset
);
343 VOID
EmulatorInterrupt(BYTE Number
)
345 /* Call the Fast486 API */
346 Fast486Interrupt(&EmulatorContext
, Number
);
349 VOID
EmulatorInterruptSignal(VOID
)
351 /* Call the Fast486 API */
352 Fast486InterruptSignal(&EmulatorContext
);
355 ULONG
EmulatorGetRegister(ULONG Register
)
357 if (Register
< EMULATOR_REG_ES
)
359 return EmulatorContext
.GeneralRegs
[Register
].Long
;
363 return EmulatorContext
.SegmentRegs
[Register
- EMULATOR_REG_ES
].Selector
;
367 VOID
EmulatorSetRegister(ULONG Register
, ULONG Value
)
369 if (Register
< EMULATOR_REG_ES
)
371 EmulatorContext
.GeneralRegs
[Register
].Long
= Value
;
375 Fast486SetSegment(&EmulatorContext
, Register
- EMULATOR_REG_ES
, (USHORT
)Value
);
379 ULONG
EmulatorGetProgramCounter(VOID
)
381 return EmulatorContext
.InstPtr
.Long
;
384 BOOLEAN
EmulatorGetFlag(ULONG Flag
)
386 return (EmulatorContext
.Flags
.Long
& Flag
) ? TRUE
: FALSE
;
389 VOID
EmulatorSetFlag(ULONG Flag
)
391 EmulatorContext
.Flags
.Long
|= Flag
;
394 VOID
EmulatorClearFlag(ULONG Flag
)
396 EmulatorContext
.Flags
.Long
&= ~Flag
;
399 VOID
EmulatorStep(VOID
)
401 /* Dump the state for debugging purposes */
402 // Fast486DumpState(&EmulatorContext);
404 /* Execute the next instruction */
405 Fast486StepInto(&EmulatorContext
);
408 VOID
EmulatorSetA20(BOOLEAN Enabled
)