mirror of
https://github.com/reactos/reactos.git
synced 2024-07-06 12:45:16 +00:00
[NTVDM]
Use 286 mode in softx86. Implement "Get / Set Disk Transfer Area". Start implementation of PS/2 controller. Improve hardware interrupts. Fix CLI / STI / HLT instruction support. svn path=/branches/ntvdm/; revision=59343
This commit is contained in:
parent
53fbdf6bc9
commit
44f2787b1f
|
@ -9,6 +9,7 @@
|
|||
#include "ntvdm.h"
|
||||
|
||||
WORD CurrentPsp = SYSTEM_PSP, LastError = 0;
|
||||
DWORD DiskTransferArea;
|
||||
|
||||
static VOID DosCombineFreeBlocks(WORD StartBlock)
|
||||
{
|
||||
|
@ -433,6 +434,7 @@ BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock)
|
|||
|
||||
/* Execute */
|
||||
CurrentPsp = Segment;
|
||||
DiskTransferArea = MAKELONG(0x80, Segment);
|
||||
EmulatorExecute(Segment + Header->e_cs, sizeof(DOS_PSP) + Header->e_ip);
|
||||
|
||||
Success = TRUE;
|
||||
|
@ -466,6 +468,7 @@ BOOLEAN DosCreateProcess(LPCSTR CommandLine, WORD EnvBlock)
|
|||
|
||||
/* Execute */
|
||||
CurrentPsp = Segment;
|
||||
DiskTransferArea = MAKELONG(0x80, Segment);
|
||||
EmulatorExecute(Segment, 0x100);
|
||||
|
||||
Success = TRUE;
|
||||
|
@ -635,6 +638,13 @@ VOID DosInt21h(WORD CodeSegment)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Set Disk Transfer Area */
|
||||
case 0x1A:
|
||||
{
|
||||
DiskTransferArea = MAKELONG(LOWORD(Edx), DataSegment);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Set Interrupt Vector */
|
||||
case 0x25:
|
||||
{
|
||||
|
@ -721,6 +731,15 @@ VOID DosInt21h(WORD CodeSegment)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Get Disk Transfer Area */
|
||||
case 0x2F:
|
||||
{
|
||||
EmulatorSetRegister(EMULATOR_REG_ES, HIWORD(DiskTransferArea));
|
||||
EmulatorSetRegister(EMULATOR_REG_BX, LOWORD(DiskTransferArea));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get Interrupt Vector */
|
||||
case 0x35:
|
||||
{
|
||||
|
|
|
@ -14,9 +14,13 @@
|
|||
|
||||
softx86_ctx EmulatorContext;
|
||||
softx87_ctx FpuEmulatorContext;
|
||||
static BOOLEAN A20Line = FALSE;
|
||||
|
||||
static VOID EmulatorReadMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT Size)
|
||||
{
|
||||
/* If the A20 line is disabled, mask bit 20 */
|
||||
if (!A20Line) Address &= ~(1 << 20);
|
||||
|
||||
/* Make sure the requested address is valid */
|
||||
if ((Address + Size) >= MAX_ADDRESS) return;
|
||||
|
||||
|
@ -35,6 +39,9 @@ static VOID EmulatorReadMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT S
|
|||
|
||||
static VOID EmulatorWriteMemory(PVOID Context, UINT Address, LPBYTE Buffer, INT Size)
|
||||
{
|
||||
/* If the A20 line is disabled, mask bit 20 */
|
||||
if (!A20Line) Address &= ~(1 << 20);
|
||||
|
||||
/* Make sure the requested address is valid */
|
||||
if ((Address + Size) >= MAX_ADDRESS) return;
|
||||
|
||||
|
@ -71,6 +78,26 @@ static VOID EmulatorReadIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size)
|
|||
*Buffer = PicReadData(Address);
|
||||
break;
|
||||
}
|
||||
|
||||
case PIT_DATA_PORT(0):
|
||||
case PIT_DATA_PORT(1):
|
||||
case PIT_DATA_PORT(2):
|
||||
{
|
||||
*Buffer = PitReadData(Address - PIT_DATA_PORT(0));
|
||||
break;
|
||||
}
|
||||
|
||||
case PS2_CONTROL_PORT:
|
||||
{
|
||||
*Buffer = KeyboardReadStatus();
|
||||
break;
|
||||
}
|
||||
|
||||
case PS2_DATA_PORT:
|
||||
{
|
||||
*Buffer = KeyboardReadData();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,6 +134,18 @@ static VOID EmulatorWriteIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size
|
|||
PicWriteData(Address, Byte);
|
||||
break;
|
||||
}
|
||||
|
||||
case PS2_CONTROL_PORT:
|
||||
{
|
||||
KeyboardWriteCommand(Byte);
|
||||
break;
|
||||
}
|
||||
|
||||
case PS2_DATA_PORT:
|
||||
{
|
||||
KeyboardWriteData(Byte);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,6 +226,16 @@ static VOID EmulatorSoftwareInt(PVOID Context, BYTE Number)
|
|||
}
|
||||
}
|
||||
|
||||
static VOID EmulatorHardwareInt(PVOID Context, BYTE Number)
|
||||
{
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
static VOID EmulatorHardwareIntAck(PVOID Context, BYTE Number)
|
||||
{
|
||||
/* Do nothing */
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
BOOLEAN EmulatorInitialize()
|
||||
|
@ -196,7 +245,7 @@ BOOLEAN EmulatorInitialize()
|
|||
if (BaseAddress == NULL) return FALSE;
|
||||
|
||||
/* Initialize the softx86 CPU emulator */
|
||||
if (!softx86_init(&EmulatorContext, SX86_CPULEVEL_80186))
|
||||
if (!softx86_init(&EmulatorContext, SX86_CPULEVEL_80286))
|
||||
{
|
||||
HeapFree(GetProcessHeap(), 0, BaseAddress);
|
||||
return FALSE;
|
||||
|
@ -220,10 +269,15 @@ BOOLEAN EmulatorInitialize()
|
|||
|
||||
/* Set interrupt callbacks */
|
||||
EmulatorContext.callbacks->on_sw_int = EmulatorSoftwareInt;
|
||||
EmulatorContext.callbacks->on_hw_int = EmulatorHardwareInt;
|
||||
EmulatorContext.callbacks->on_hw_int_ack = EmulatorHardwareIntAck;
|
||||
|
||||
/* Connect the emulated FPU to the emulated CPU */
|
||||
softx87_connect_to_CPU(&EmulatorContext, &FpuEmulatorContext);
|
||||
|
||||
/* Enable interrupts */
|
||||
EmulatorSetFlag(EMULATOR_FLAG_IF);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -252,6 +306,12 @@ VOID EmulatorInterrupt(BYTE Number)
|
|||
softx86_make_simple_interrupt_call(&EmulatorContext, &Segment, &Offset);
|
||||
}
|
||||
|
||||
VOID EmulatorExternalInterrupt(BYTE Number)
|
||||
{
|
||||
/* Call the softx86 API */
|
||||
softx86_ext_hw_signal(&EmulatorContext, Number);
|
||||
}
|
||||
|
||||
ULONG EmulatorGetRegister(ULONG Register)
|
||||
{
|
||||
if (Register < EMULATOR_REG_ES)
|
||||
|
@ -294,7 +354,11 @@ VOID EmulatorClearFlag(ULONG Flag)
|
|||
VOID EmulatorStep()
|
||||
{
|
||||
/* Call the softx86 API */
|
||||
softx86_step(&EmulatorContext);
|
||||
if (!softx86_step(&EmulatorContext))
|
||||
{
|
||||
/* Invalid opcode */
|
||||
EmulatorInterrupt(EMULATOR_EXCEPTION_INVALID_OPCODE);
|
||||
}
|
||||
}
|
||||
|
||||
VOID EmulatorCleanup()
|
||||
|
@ -307,4 +371,9 @@ VOID EmulatorCleanup()
|
|||
softx87_free(&FpuEmulatorContext);
|
||||
}
|
||||
|
||||
VOID EmulatorSetA20(BOOLEAN Enabled)
|
||||
{
|
||||
A20Line = Enabled;
|
||||
}
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -53,6 +53,9 @@ static BYTE KeyboardQueue[KEYBOARD_BUFFER_SIZE];
|
|||
static BOOLEAN KeyboardQueueEmpty = TRUE;
|
||||
static UINT KeyboardQueueStart = 0;
|
||||
static UINT KeyboardQueueEnd = 0;
|
||||
static BYTE KeyboardResponse = 0;
|
||||
static BOOLEAN KeyboardReadResponse = FALSE, KeyboardWriteResponse = FALSE;
|
||||
static BYTE KeyboardConfig = PS2_DEFAULT_CONFIG;
|
||||
|
||||
static BOOLEAN KeyboardQueuePush(BYTE ScanCode)
|
||||
{
|
||||
|
@ -73,7 +76,6 @@ static BOOLEAN KeyboardQueuePush(BYTE ScanCode)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static BOOLEAN KeyboardQueuePop(BYTE *ScanCode)
|
||||
{
|
||||
/* Make sure the keyboard queue is not empty */
|
||||
|
@ -94,7 +96,6 @@ static BOOLEAN KeyboardQueuePop(BYTE *ScanCode)
|
|||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||
|
||||
|
@ -248,7 +249,7 @@ VOID PicInterruptRequest(BYTE Number)
|
|||
|
||||
/* Set the appropriate bit in the ISR and interrupt the CPU */
|
||||
if (!MasterPic.AutoEoi) MasterPic.InServiceRegister |= 1 << Number;
|
||||
EmulatorInterrupt(MasterPic.IntOffset + Number);
|
||||
EmulatorExternalInterrupt(MasterPic.IntOffset + Number);
|
||||
}
|
||||
else if (Number >= 8 && Number < 16)
|
||||
{
|
||||
|
@ -279,7 +280,7 @@ VOID PicInterruptRequest(BYTE Number)
|
|||
|
||||
/* Set the appropriate bit in the ISR and interrupt the CPU */
|
||||
if (!SlavePic.AutoEoi) SlavePic.InServiceRegister |= 1 << Number;
|
||||
EmulatorInterrupt(SlavePic.IntOffset + Number);
|
||||
EmulatorExternalInterrupt(SlavePic.IntOffset + Number);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -497,6 +498,203 @@ VOID PitDecrementCount()
|
|||
}
|
||||
}
|
||||
|
||||
BYTE KeyboardReadStatus()
|
||||
{
|
||||
BYTE Status = 0;
|
||||
|
||||
/* Set the first bit if the data can be read */
|
||||
if (KeyboardReadResponse || !KeyboardQueueEmpty) Status |= 1 << 0;
|
||||
|
||||
/* Always set bit 2 */
|
||||
Status |= 1 << 2;
|
||||
|
||||
/* Set bit 3 if the next byte goes to the controller */
|
||||
if (KeyboardWriteResponse) Status |= 1 << 3;
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
VOID KeyboardWriteCommand(BYTE Command)
|
||||
{
|
||||
switch (Command)
|
||||
{
|
||||
/* Read configuration byte */
|
||||
case 0x20:
|
||||
{
|
||||
KeyboardResponse = KeyboardConfig;
|
||||
KeyboardReadResponse = TRUE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Write configuration byte */
|
||||
case 0x60:
|
||||
/* Write controller output port */
|
||||
case 0xD1:
|
||||
/* Write keyboard output buffer */
|
||||
case 0xD2:
|
||||
/* Write mouse output buffer */
|
||||
case 0xD3:
|
||||
/* Write mouse input buffer */
|
||||
case 0xD4:
|
||||
{
|
||||
/* These commands require a response */
|
||||
KeyboardResponse = Command;
|
||||
KeyboardWriteResponse = TRUE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Disable mouse */
|
||||
case 0xA7:
|
||||
{
|
||||
// TODO: Mouse support
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable mouse */
|
||||
case 0xA8:
|
||||
{
|
||||
// TODO: Mouse support
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Test mouse port */
|
||||
case 0xA9:
|
||||
{
|
||||
KeyboardResponse = 0;
|
||||
KeyboardReadResponse = TRUE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Test PS/2 controller */
|
||||
case 0xAA:
|
||||
{
|
||||
KeyboardResponse = 0x55;
|
||||
KeyboardReadResponse = TRUE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* Disable keyboard */
|
||||
case 0xAD:
|
||||
{
|
||||
// TODO: Not implemented
|
||||
break;
|
||||
}
|
||||
|
||||
/* Enable keyboard */
|
||||
case 0xAE:
|
||||
{
|
||||
// TODO: Not implemented
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read controller output port */
|
||||
case 0xD0:
|
||||
{
|
||||
// TODO: Not implemented
|
||||
break;
|
||||
}
|
||||
|
||||
/* CPU Reset */
|
||||
case 0xF0:
|
||||
case 0xF2:
|
||||
case 0xF4:
|
||||
case 0xF6:
|
||||
case 0xF8:
|
||||
case 0xFA:
|
||||
case 0xFC:
|
||||
case 0xFE:
|
||||
{
|
||||
/* Stop the simulation */
|
||||
VdmRunning = FALSE;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BYTE KeyboardReadData()
|
||||
{
|
||||
BYTE Value = 0;
|
||||
|
||||
/* If there was a response byte from the controller, return it */
|
||||
if (KeyboardReadResponse)
|
||||
{
|
||||
KeyboardReadResponse = FALSE;
|
||||
return KeyboardResponse;
|
||||
}
|
||||
|
||||
/* Otherwise, read the data from the queue */
|
||||
KeyboardQueuePop(&Value);
|
||||
|
||||
return Value;
|
||||
}
|
||||
|
||||
VOID KeyboardWriteData(BYTE Data)
|
||||
{
|
||||
/* Check if the controller is waiting for a response */
|
||||
if (KeyboardWriteResponse)
|
||||
{
|
||||
KeyboardWriteResponse = FALSE;
|
||||
|
||||
/* Check which command it was */
|
||||
switch (KeyboardResponse)
|
||||
{
|
||||
/* Write configuration byte */
|
||||
case 0x60:
|
||||
{
|
||||
KeyboardConfig = Data;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Write controller output */
|
||||
case 0xD1:
|
||||
{
|
||||
/* Check if bit 0 is unset */
|
||||
if (!(Data & (1 << 0)))
|
||||
{
|
||||
/* CPU disabled - end simulation */
|
||||
VdmRunning = FALSE;
|
||||
}
|
||||
|
||||
/* Update the A20 line setting */
|
||||
EmulatorSetA20(Data & (1 << 1));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xD2:
|
||||
{
|
||||
/* Push the data byte to the keyboard queue */
|
||||
KeyboardQueuePush(Data);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xD3:
|
||||
{
|
||||
// TODO: Mouse support
|
||||
break;
|
||||
}
|
||||
|
||||
case 0xD4:
|
||||
{
|
||||
// TODO: Mouse support
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Implement PS/2 device commands
|
||||
}
|
||||
|
||||
VOID CheckForInputEvents()
|
||||
{
|
||||
PINPUT_RECORD Buffer;
|
||||
|
|
|
@ -74,6 +74,9 @@
|
|||
#define KEYBOARD_BUFFER_SIZE 32
|
||||
#define PS2_DATA_PORT 0x60
|
||||
#define PS2_CONTROL_PORT 0x64
|
||||
#define PS2_DEFAULT_CONFIG 0x05
|
||||
#define KEYBOARD_ACK 0xFA
|
||||
#define KEYBOARD_RESEND 0xFE
|
||||
|
||||
#define EMULATOR_FLAG_CF (1 << 0)
|
||||
#define EMULATOR_FLAG_PF (1 << 2)
|
||||
|
@ -92,6 +95,18 @@
|
|||
#define EMULATOR_FLAG_VIP (1 << 20)
|
||||
#define EMULATOR_FLAG_ID (1 << 21)
|
||||
|
||||
enum
|
||||
{
|
||||
EMULATOR_EXCEPTION_DIVISION_BY_ZERO,
|
||||
EMULATOR_EXCEPTION_DEBUG,
|
||||
EMULATOR_EXCEPTION_NMI,
|
||||
EMULATOR_EXCEPTION_BREAKPOINT,
|
||||
EMULATOR_EXCEPTION_OVERFLOW,
|
||||
EMULATOR_EXCEPTION_BOUND,
|
||||
EMULATOR_EXCEPTION_INVALID_OPCODE,
|
||||
EMULATOR_EXCEPTION_NO_FPU
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
EMULATOR_REG_AX,
|
||||
|
@ -226,9 +241,14 @@ BYTE PitReadData(BYTE Channel);
|
|||
VOID PitWriteData(BYTE Channel, BYTE Value);
|
||||
VOID PitDecrementCount();
|
||||
VOID CheckForInputEvents();
|
||||
BYTE KeyboardReadStatus();
|
||||
VOID KeyboardWriteCommand(BYTE Command);
|
||||
BYTE KeyboardReadData();
|
||||
VOID KeyboardWriteData(BYTE Data);
|
||||
VOID EmulatorSetStack(WORD Segment, WORD Offset);
|
||||
VOID EmulatorExecute(WORD Segment, WORD Offset);
|
||||
VOID EmulatorInterrupt(BYTE Number);
|
||||
VOID EmulatorExternalInterrupt(BYTE Number);
|
||||
ULONG EmulatorGetRegister(ULONG Register);
|
||||
VOID EmulatorSetRegister(ULONG Register, ULONG Value);
|
||||
VOID EmulatorSetFlag(ULONG Flag);
|
||||
|
@ -237,5 +257,7 @@ BOOLEAN EmulatorGetFlag(ULONG Flag);
|
|||
BOOLEAN EmulatorInitialize();
|
||||
VOID EmulatorStep();
|
||||
VOID EmulatorCleanup();
|
||||
VOID EmulatorHalt();
|
||||
VOID EmulatorSetA20(BOOLEAN Enabled);
|
||||
|
||||
/* EOF */
|
||||
|
|
Loading…
Reference in a new issue