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 *******************************************************************/
12 #include <softx86/softx86.h>
13 #include <softx86/softx87.h>
15 softx86_ctx EmulatorContext
;
16 softx87_ctx FpuEmulatorContext
;
18 static VOID
EmulatorReadMemory(PVOID Context
, UINT Address
, LPBYTE Buffer
, INT Size
)
20 /* Make sure the requested address is valid */
21 if ((Address
+ Size
) >= MAX_ADDRESS
) return;
23 /* Are we reading some of the console video memory? */
24 if (((Address
+ Size
) >= CONSOLE_VIDEO_MEM_START
)
25 && (Address
< CONSOLE_VIDEO_MEM_END
))
27 /* Call the VDM BIOS to update the video memory */
28 BiosUpdateConsole(max(Address
, CONSOLE_VIDEO_MEM_START
),
29 min(Address
+ Size
, CONSOLE_VIDEO_MEM_END
));
32 /* Read the data from the virtual address space and store it in the buffer */
33 RtlCopyMemory(Buffer
, (LPVOID
)((ULONG_PTR
)BaseAddress
+ Address
), Size
);
36 static VOID
EmulatorWriteMemory(PVOID Context
, UINT Address
, LPBYTE Buffer
, INT Size
)
38 /* Make sure the requested address is valid */
39 if ((Address
+ Size
) >= MAX_ADDRESS
) return;
41 /* Make sure we don't write to the ROM area */
42 if ((Address
+ Size
) >= ROM_AREA_START
&& (Address
< ROM_AREA_END
)) return;
44 /* Read the data from the buffer and store it in the virtual address space */
45 RtlCopyMemory((LPVOID
)((ULONG_PTR
)BaseAddress
+ Address
), Buffer
, Size
);
47 /* Check if we modified the console video memory */
48 if (((Address
+ Size
) >= CONSOLE_VIDEO_MEM_START
)
49 && (Address
< CONSOLE_VIDEO_MEM_END
))
51 /* Call the VDM BIOS to update the screen */
52 BiosUpdateConsole(max(Address
, CONSOLE_VIDEO_MEM_START
),
53 min(Address
+ Size
, CONSOLE_VIDEO_MEM_END
));
57 static VOID
EmulatorReadIo(PVOID Context
, UINT Address
, LPBYTE Buffer
, INT Size
)
64 *Buffer
= PicReadCommand(Address
);
71 *Buffer
= PicReadData(Address
);
77 static VOID
EmulatorWriteIo(PVOID Context
, UINT Address
, LPBYTE Buffer
, INT Size
)
83 case PIT_COMMAND_PORT
:
85 PitWriteCommand(Byte
);
89 case PIT_DATA_PORT(0):
90 case PIT_DATA_PORT(1):
91 case PIT_DATA_PORT(2):
93 PitWriteData(Address
- PIT_DATA_PORT(0), Byte
);
100 PicWriteCommand(Address
, Byte
);
104 case PIC_MASTER_DATA
:
107 PicWriteData(Address
, Byte
);
113 static VOID
EmulatorSoftwareInt(PVOID Context
, BYTE Number
)
115 WORD StackSegment
, StackPointer
, CodeSegment
, InstructionPointer
;
118 /* Check if this is the special interrupt */
119 if (Number
== SPECIAL_INT_NUM
)
122 StackSegment
= EmulatorContext
.state
->segment_reg
[SX86_SREG_SS
].val
;
123 StackPointer
= EmulatorContext
.state
->general_reg
[SX86_REG_SP
].val
;
125 /* Get the interrupt number */
126 IntNum
= *(LPBYTE
)((ULONG_PTR
)BaseAddress
+ TO_LINEAR(StackSegment
, StackPointer
));
128 /* Move the stack pointer forward one word to skip the interrupt number */
129 StackPointer
+= sizeof(WORD
);
132 InstructionPointer
= *(LPWORD
)((ULONG_PTR
)BaseAddress
133 + TO_LINEAR(StackSegment
, StackPointer
));
134 CodeSegment
= *(LPWORD
)((ULONG_PTR
)BaseAddress
135 + TO_LINEAR(StackSegment
, StackPointer
+ sizeof(WORD
)));
137 /* Check if this was an exception */
140 /* Display a message to the user */
141 DisplayMessage(L
"Exception: %s occured at %04X:%04X",
142 ExceptionName
[IntNum
],
151 /* Check if this was an PIC IRQ */
152 if (IntNum
>= BIOS_PIC_MASTER_INT
&& IntNum
< BIOS_PIC_MASTER_INT
+ 8)
154 /* It was an IRQ from the master PIC */
155 BiosHandleIrq(IntNum
- BIOS_PIC_MASTER_INT
);
157 else if (IntNum
>= BIOS_PIC_SLAVE_INT
&& IntNum
< BIOS_PIC_SLAVE_INT
+ 8)
159 /* It was an IRQ from the slave PIC */
160 BiosHandleIrq(IntNum
- BIOS_PIC_SLAVE_INT
+ 8);
165 case VIDEO_BIOS_INTERRUPT
:
167 /* This is the video BIOS interrupt, call the BIOS */
173 DosInt20h(CodeSegment
);
178 DosInt21h(CodeSegment
);
190 /* PUBLIC FUNCTIONS ***********************************************************/
192 BOOLEAN
EmulatorInitialize()
194 /* Allocate memory for the 16-bit address space */
195 BaseAddress
= HeapAlloc(GetProcessHeap(), 0, MAX_ADDRESS
);
196 if (BaseAddress
== NULL
) return FALSE
;
198 /* Initialize the softx86 CPU emulator */
199 if (!softx86_init(&EmulatorContext
, SX86_CPULEVEL_80186
))
201 HeapFree(GetProcessHeap(), 0, BaseAddress
);
205 /* Initialize the softx87 FPU emulator*/
206 if(!softx87_init(&FpuEmulatorContext
, SX87_FPULEVEL_8087
))
208 softx86_free(&EmulatorContext
);
209 HeapFree(GetProcessHeap(), 0, BaseAddress
);
213 /* Set memory read/write callbacks */
214 EmulatorContext
.callbacks
->on_read_memory
= EmulatorReadMemory
;
215 EmulatorContext
.callbacks
->on_write_memory
= EmulatorWriteMemory
;
217 /* Set MMIO read/write callbacks */
218 EmulatorContext
.callbacks
->on_read_io
= EmulatorReadIo
;
219 EmulatorContext
.callbacks
->on_write_io
= EmulatorWriteIo
;
221 /* Set interrupt callbacks */
222 EmulatorContext
.callbacks
->on_sw_int
= EmulatorSoftwareInt
;
224 /* Connect the emulated FPU to the emulated CPU */
225 softx87_connect_to_CPU(&EmulatorContext
, &FpuEmulatorContext
);
230 VOID
EmulatorSetStack(WORD Segment
, WORD Offset
)
232 /* Call the softx86 API */
233 softx86_set_stack_ptr(&EmulatorContext
, Segment
, Offset
);
236 VOID
EmulatorExecute(WORD Segment
, WORD Offset
)
238 /* Call the softx86 API */
239 softx86_set_instruction_ptr(&EmulatorContext
, Segment
, Offset
);
242 VOID
EmulatorInterrupt(BYTE Number
)
244 LPDWORD IntVecTable
= (LPDWORD
)((ULONG_PTR
)BaseAddress
);
245 UINT Segment
, Offset
;
247 /* Get the segment and offset */
248 Segment
= HIWORD(IntVecTable
[Number
]);
249 Offset
= LOWORD(IntVecTable
[Number
]);
251 /* Call the softx86 API */
252 softx86_make_simple_interrupt_call(&EmulatorContext
, &Segment
, &Offset
);
255 ULONG
EmulatorGetRegister(ULONG Register
)
257 if (Register
< EMULATOR_REG_CS
)
259 return EmulatorContext
.state
->general_reg
[Register
].val
;
263 return EmulatorContext
.state
->segment_reg
[(Register
>> 3) - 1].val
;
267 VOID
EmulatorSetRegister(ULONG Register
, ULONG Value
)
269 if (Register
< EMULATOR_REG_CS
)
271 EmulatorContext
.state
->general_reg
[Register
].val
= Value
;
275 EmulatorContext
.state
->segment_reg
[(Register
>> 3) - 1].val
= Value
;
279 BOOLEAN
EmulatorGetFlag(ULONG Flag
)
281 return (EmulatorContext
.state
->reg_flags
.val
& Flag
);
284 VOID
EmulatorSetFlag(ULONG Flag
)
286 EmulatorContext
.state
->reg_flags
.val
|= Flag
;
289 VOID
EmulatorClearFlag(ULONG Flag
)
291 EmulatorContext
.state
->reg_flags
.val
&= ~Flag
;
296 /* Call the softx86 API */
297 softx86_step(&EmulatorContext
);
300 VOID
EmulatorCleanup()
302 /* Free the memory allocated for the 16-bit address space */
303 if (BaseAddress
!= NULL
) HeapFree(GetProcessHeap(), 0, BaseAddress
);
305 /* Free the softx86 CPU and FPU emulator */
306 softx86_free(&EmulatorContext
);
307 softx87_free(&FpuEmulatorContext
);