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:
Aleksandar Andrejevic 2013-06-26 17:15:45 +00:00
parent 53fbdf6bc9
commit 44f2787b1f
4 changed files with 314 additions and 6 deletions

View file

@ -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:
{

View file

@ -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 */

View file

@ -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;

View file

@ -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 */