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
)
59 // TODO: NOT IMPLEMENTED!
62 static VOID
EmulatorWriteIo(PVOID Context
, UINT Address
, LPBYTE Buffer
, INT Size
)
64 // TODO: NOT IMPLEMENTED!
67 static VOID
EmulatorSoftwareInt(PVOID Context
, BYTE Number
)
69 WORD StackSegment
, StackPointer
, CodeSegment
, InstructionPointer
;
72 /* Check if this is the special interrupt */
73 if (Number
== SPECIAL_INT_NUM
)
76 StackSegment
= EmulatorContext
.state
->segment_reg
[SX86_SREG_SS
].val
;
77 StackPointer
= EmulatorContext
.state
->general_reg
[SX86_REG_SP
].val
;
79 /* Get the interrupt number */
80 IntNum
= *(LPBYTE
)((ULONG_PTR
)BaseAddress
+ TO_LINEAR(StackSegment
, StackPointer
));
82 /* Move the stack pointer forward one word to skip the interrupt number */
83 StackPointer
+= sizeof(WORD
);
86 InstructionPointer
= *(LPWORD
)((ULONG_PTR
)BaseAddress
87 + TO_LINEAR(StackSegment
, StackPointer
));
88 CodeSegment
= *(LPWORD
)((ULONG_PTR
)BaseAddress
89 + TO_LINEAR(StackSegment
, StackPointer
+ sizeof(WORD
)));
91 /* Check if this was an exception */
94 /* Display a message to the user */
95 DisplayMessage(L
"Exception: %s occured at %04X:%04X",
96 ExceptionName
[IntNum
],
107 case VIDEO_BIOS_INTERRUPT
:
109 /* This is the video BIOS interrupt, call the BIOS */
115 DosInt20h(CodeSegment
);
120 DosInt21h(CodeSegment
);
132 /* PUBLIC FUNCTIONS ***********************************************************/
134 BOOLEAN
EmulatorInitialize()
136 /* Allocate memory for the 16-bit address space */
137 BaseAddress
= HeapAlloc(GetProcessHeap(), 0, MAX_ADDRESS
);
138 if (BaseAddress
== NULL
) return FALSE
;
140 /* Initialize the softx86 CPU emulator */
141 if (!softx86_init(&EmulatorContext
, SX86_CPULEVEL_80186
))
143 HeapFree(GetProcessHeap(), 0, BaseAddress
);
147 /* Initialize the softx87 FPU emulator*/
148 if(!softx87_init(&FpuEmulatorContext
, SX87_FPULEVEL_8087
))
150 softx86_free(&EmulatorContext
);
151 HeapFree(GetProcessHeap(), 0, BaseAddress
);
155 /* Set memory read/write callbacks */
156 EmulatorContext
.callbacks
->on_read_memory
= EmulatorReadMemory
;
157 EmulatorContext
.callbacks
->on_write_memory
= EmulatorWriteMemory
;
159 /* Set MMIO read/write callbacks */
160 EmulatorContext
.callbacks
->on_read_io
= EmulatorReadIo
;
161 EmulatorContext
.callbacks
->on_write_io
= EmulatorWriteIo
;
163 /* Set interrupt callbacks */
164 EmulatorContext
.callbacks
->on_sw_int
= EmulatorSoftwareInt
;
166 /* Connect the emulated FPU to the emulated CPU */
167 softx87_connect_to_CPU(&EmulatorContext
, &FpuEmulatorContext
);
172 VOID
EmulatorSetStack(WORD Segment
, WORD Offset
)
174 /* Call the softx86 API */
175 softx86_set_stack_ptr(&EmulatorContext
, Segment
, Offset
);
178 VOID
EmulatorExecute(WORD Segment
, WORD Offset
)
180 /* Call the softx86 API */
181 softx86_set_instruction_ptr(&EmulatorContext
, Segment
, Offset
);
184 VOID
EmulatorInterrupt(BYTE Number
)
186 LPWORD IntVecTable
= (LPWORD
)((ULONG_PTR
)BaseAddress
);
187 UINT Segment
, Offset
;
189 /* Get the segment and offset */
190 Segment
= HIWORD(IntVecTable
[Number
]);
191 Offset
= LOWORD(IntVecTable
[Number
]);
193 /* Call the softx86 API */
194 softx86_make_simple_interrupt_call(&EmulatorContext
, &Segment
, &Offset
);
197 ULONG
EmulatorGetRegister(ULONG Register
)
199 if (Register
< EMULATOR_REG_CS
)
201 return EmulatorContext
.state
->general_reg
[Register
].val
;
205 return EmulatorContext
.state
->segment_reg
[(Register
>> 3) - 1].val
;
209 VOID
EmulatorSetRegister(ULONG Register
, ULONG Value
)
211 if (Register
< EMULATOR_REG_CS
)
213 EmulatorContext
.state
->general_reg
[Register
].val
= Value
;
217 EmulatorContext
.state
->segment_reg
[(Register
>> 3) - 1].val
= Value
;
221 BOOLEAN
EmulatorGetFlag(ULONG Flag
)
223 return (EmulatorContext
.state
->reg_flags
.val
& Flag
);
226 VOID
EmulatorSetFlag(ULONG Flag
)
228 EmulatorContext
.state
->reg_flags
.val
|= Flag
;
231 VOID
EmulatorClearFlag(ULONG Flag
)
233 EmulatorContext
.state
->reg_flags
.val
&= ~Flag
;
238 /* Call the softx86 API */
239 softx86_step(&EmulatorContext
);
242 VOID
EmulatorCleanup()
244 /* Free the memory allocated for the 16-bit address space */
245 if (BaseAddress
!= NULL
) HeapFree(GetProcessHeap(), 0, BaseAddress
);
247 /* Free the softx86 CPU and FPU emulator */
248 softx86_free(&EmulatorContext
);
249 softx87_free(&FpuEmulatorContext
);