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 static 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 LPBYTE VgaBuffer
= (LPBYTE
)((ULONG_PTR
)Buffer
+ VgaAddress
- Address
);
52 /* Read from the VGA memory */
53 VgaReadMemory(VgaAddress
, VgaBuffer
, Size
);
57 static VOID WINAPI
EmulatorWriteMemory(PFAST486_STATE State
, ULONG Address
, PVOID Buffer
, ULONG Size
)
59 UNREFERENCED_PARAMETER(State
);
61 /* If the A20 line is disabled, mask bit 20 */
62 if (!A20Line
) Address
&= ~(1 << 20);
64 /* Make sure the requested address is valid */
65 if ((Address
+ Size
) >= MAX_ADDRESS
) return;
67 /* Make sure we don't write to the ROM area */
68 if ((Address
+ Size
) >= ROM_AREA_START
&& (Address
< ROM_AREA_END
)) return;
70 /* Read the data from the buffer and store it in the virtual address space */
71 RtlCopyMemory((LPVOID
)((ULONG_PTR
)BaseAddress
+ Address
), Buffer
, Size
);
73 /* Check if we modified the console video memory */
74 if (((Address
+ Size
) >= VgaGetVideoBaseAddress())
75 && (Address
< VgaGetVideoLimitAddress()))
77 DWORD VgaAddress
= max(Address
, VgaGetVideoBaseAddress());
78 LPBYTE VgaBuffer
= (LPBYTE
)((ULONG_PTR
)Buffer
+ VgaAddress
- Address
);
80 /* Write to the VGA memory */
81 VgaWriteMemory(VgaAddress
, VgaBuffer
, Size
);
85 static VOID WINAPI
EmulatorReadIo(PFAST486_STATE State
, ULONG Port
, PVOID Buffer
, ULONG DataCount
, UCHAR DataSize
)
88 LPBYTE Address
= (LPBYTE
)Buffer
;
90 UNREFERENCED_PARAMETER(State
);
92 for (i
= 0; i
< DataCount
; i
++) for (j
= 0; j
< DataSize
; j
++)
94 ULONG CurrentPort
= Port
+ j
;
101 *(Address
++) = PicReadCommand(CurrentPort
);
105 case PIC_MASTER_DATA
:
108 *(Address
++) = PicReadData(CurrentPort
);
112 case PIT_DATA_PORT(0):
113 case PIT_DATA_PORT(1):
114 case PIT_DATA_PORT(2):
116 *(Address
++) = PitReadData(CurrentPort
- PIT_DATA_PORT(0));
120 case PS2_CONTROL_PORT
:
122 *(Address
++) = KeyboardReadStatus();
128 *(Address
++) = KeyboardReadData();
134 *(Address
++) = CmosReadData();
138 case SPEAKER_CONTROL_PORT
:
140 *(Address
++) = SpeakerReadStatus();
148 case VGA_DAC_READ_INDEX
:
149 case VGA_DAC_WRITE_INDEX
:
160 *(Address
++) = VgaReadPort(CurrentPort
);
166 DPRINT1("Read from unknown port: 0x%X\n", CurrentPort
);
172 static VOID WINAPI
EmulatorWriteIo(PFAST486_STATE State
, ULONG Port
, PVOID Buffer
, ULONG DataCount
, UCHAR DataSize
)
175 LPBYTE Address
= (LPBYTE
)Buffer
;
177 UNREFERENCED_PARAMETER(State
);
179 for (i
= 0; i
< DataCount
; i
++) for (j
= 0; j
< DataSize
; j
++)
181 ULONG CurrentPort
= Port
+ j
;
185 case PIT_COMMAND_PORT
:
187 PitWriteCommand(*(Address
++));
191 case PIT_DATA_PORT(0):
192 case PIT_DATA_PORT(1):
193 case PIT_DATA_PORT(2):
195 PitWriteData(CurrentPort
- PIT_DATA_PORT(0), *(Address
++));
202 PicWriteCommand(CurrentPort
, *(Address
++));
206 case PIC_MASTER_DATA
:
209 PicWriteData(CurrentPort
, *(Address
++));
213 case PS2_CONTROL_PORT
:
215 KeyboardWriteCommand(*(Address
++));
221 KeyboardWriteData(*(Address
++));
225 case CMOS_ADDRESS_PORT
:
227 CmosWriteAddress(*(Address
++));
233 CmosWriteData(*(Address
++));
237 case SPEAKER_CONTROL_PORT
:
239 SpeakerWriteCommand(*(Address
++));
247 case VGA_DAC_READ_INDEX
:
248 case VGA_DAC_WRITE_INDEX
:
259 VgaWritePort(CurrentPort
, *(Address
++));
265 DPRINT1("Write to unknown port: 0x%X\n", CurrentPort
);
271 static VOID WINAPI
EmulatorBiosOperation(PFAST486_STATE State
, UCHAR BopCode
)
273 WORD StackSegment
, StackPointer
;
277 StackSegment
= State
->SegmentRegs
[FAST486_REG_SS
].Selector
;
278 StackPointer
= State
->GeneralRegs
[FAST486_REG_ESP
].LowWord
;
281 Stack
= (LPWORD
)SEG_OFF_TO_PTR(StackSegment
, StackPointer
);
283 if (BopProc
[BopCode
] != NULL
)
284 BopProc
[BopCode
](Stack
);
286 DPRINT1("Invalid BOP code %u\n", BopCode
);
289 static UCHAR WINAPI
EmulatorIntAcknowledge(PFAST486_STATE State
)
291 UNREFERENCED_PARAMETER(State
);
293 /* Get the interrupt number from the PIC */
294 return PicGetInterrupt();
297 /* PUBLIC FUNCTIONS ***********************************************************/
299 BOOLEAN
EmulatorInitialize(VOID
)
301 /* Allocate memory for the 16-bit address space */
302 BaseAddress
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, MAX_ADDRESS
);
303 if (BaseAddress
== NULL
) return FALSE
;
305 /* Initialize the CPU */
306 Fast486Initialize(&EmulatorContext
,
312 EmulatorBiosOperation
,
313 EmulatorIntAcknowledge
);
315 /* Enable interrupts */
316 EmulatorSetFlag(EMULATOR_FLAG_IF
);
321 VOID
EmulatorCleanup(VOID
)
323 /* Free the memory allocated for the 16-bit address space */
324 if (BaseAddress
!= NULL
) HeapFree(GetProcessHeap(), 0, BaseAddress
);
327 VOID
EmulatorSetStack(WORD Segment
, DWORD Offset
)
329 Fast486SetStack(&EmulatorContext
, Segment
, Offset
);
332 // FIXME: This function assumes 16-bit mode!!!
333 VOID
EmulatorExecute(WORD Segment
, WORD Offset
)
335 /* Tell Fast486 to move the instruction pointer */
336 Fast486ExecuteAt(&EmulatorContext
, Segment
, Offset
);
339 VOID
EmulatorInterrupt(BYTE Number
)
341 /* Call the Fast486 API */
342 Fast486Interrupt(&EmulatorContext
, Number
);
345 VOID
EmulatorInterruptSignal(VOID
)
347 /* Call the Fast486 API */
348 Fast486InterruptSignal(&EmulatorContext
);
351 ULONG
EmulatorGetRegister(ULONG Register
)
353 if (Register
< EMULATOR_REG_ES
)
355 return EmulatorContext
.GeneralRegs
[Register
].Long
;
359 return EmulatorContext
.SegmentRegs
[Register
- EMULATOR_REG_ES
].Selector
;
363 VOID
EmulatorSetRegister(ULONG Register
, ULONG Value
)
365 if (Register
< EMULATOR_REG_ES
)
367 EmulatorContext
.GeneralRegs
[Register
].Long
= Value
;
371 Fast486SetSegment(&EmulatorContext
, Register
- EMULATOR_REG_ES
, (USHORT
)Value
);
375 ULONG
EmulatorGetProgramCounter(VOID
)
377 return EmulatorContext
.InstPtr
.Long
;
380 BOOLEAN
EmulatorGetFlag(ULONG Flag
)
382 return (EmulatorContext
.Flags
.Long
& Flag
) ? TRUE
: FALSE
;
385 VOID
EmulatorSetFlag(ULONG Flag
)
387 EmulatorContext
.Flags
.Long
|= Flag
;
390 VOID
EmulatorClearFlag(ULONG Flag
)
392 EmulatorContext
.Flags
.Long
&= ~Flag
;
395 VOID
EmulatorStep(VOID
)
397 /* Dump the state for debugging purposes */
398 // Fast486DumpState(&EmulatorContext);
400 /* Execute the next instruction */
401 Fast486StepInto(&EmulatorContext
);
404 VOID
EmulatorSetA20(BOOLEAN Enabled
)