Author: aandrejevic
Date: Wed Jun 26 17:15:45 2013
New Revision: 59343
URL:
http://svn.reactos.org/svn/reactos?rev=59343&view=rev
Log:
[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.
Modified:
branches/ntvdm/subsystems/ntvdm/dos.c
branches/ntvdm/subsystems/ntvdm/emulator.c
branches/ntvdm/subsystems/ntvdm/hardware.c
branches/ntvdm/subsystems/ntvdm/ntvdm.h
Modified: branches/ntvdm/subsystems/ntvdm/dos.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/dos.c?re…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/dos.c [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/dos.c [iso-8859-1] Wed Jun 26 17:15:45 2013
@@ -9,6 +9,7 @@
#include "ntvdm.h"
WORD CurrentPsp = SYSTEM_PSP, LastError = 0;
+DWORD DiskTransferArea;
static VOID DosCombineFreeBlocks(WORD StartBlock)
{
@@ -433,6 +434,7 @@
/* Execute */
CurrentPsp = Segment;
+ DiskTransferArea = MAKELONG(0x80, Segment);
EmulatorExecute(Segment + Header->e_cs, sizeof(DOS_PSP) + Header->e_ip);
Success = TRUE;
@@ -466,6 +468,7 @@
/* Execute */
CurrentPsp = Segment;
+ DiskTransferArea = MAKELONG(0x80, Segment);
EmulatorExecute(Segment, 0x100);
Success = TRUE;
@@ -635,6 +638,13 @@
break;
}
+ /* Set Disk Transfer Area */
+ case 0x1A:
+ {
+ DiskTransferArea = MAKELONG(LOWORD(Edx), DataSegment);
+ break;
+ }
+
/* Set Interrupt Vector */
case 0x25:
{
@@ -721,6 +731,15 @@
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:
{
Modified: branches/ntvdm/subsystems/ntvdm/emulator.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/emulator…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/emulator.c [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/emulator.c [iso-8859-1] Wed Jun 26 17:15:45 2013
@@ -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 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,25 +78,45 @@
*Buffer = PicReadData(Address);
break;
}
- }
-}
-
-static VOID EmulatorWriteIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size)
-{
- BYTE Byte = *Buffer;
-
- switch (Address)
- {
- case PIT_COMMAND_PORT:
- {
- PitWriteCommand(Byte);
- 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;
+ }
+ }
+}
+
+static VOID EmulatorWriteIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size)
+{
+ BYTE Byte = *Buffer;
+
+ switch (Address)
+ {
+ case PIT_COMMAND_PORT:
+ {
+ PitWriteCommand(Byte);
+ break;
+ }
+
+ case PIT_DATA_PORT(0):
+ case PIT_DATA_PORT(1):
+ case PIT_DATA_PORT(2):
+ {
PitWriteData(Address - PIT_DATA_PORT(0), Byte);
break;
}
@@ -105,6 +132,18 @@
case PIC_SLAVE_DATA:
{
PicWriteData(Address, Byte);
+ break;
+ }
+
+ case PS2_CONTROL_PORT:
+ {
+ KeyboardWriteCommand(Byte);
+ break;
+ }
+
+ case PS2_DATA_PORT:
+ {
+ KeyboardWriteData(Byte);
break;
}
}
@@ -187,6 +226,16 @@
}
}
+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 @@
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,9 +269,14 @@
/* 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 @@
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 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 @@
softx87_free(&FpuEmulatorContext);
}
+VOID EmulatorSetA20(BOOLEAN Enabled)
+{
+ A20Line = Enabled;
+}
+
/* EOF */
Modified: branches/ntvdm/subsystems/ntvdm/hardware.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/hardware…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/hardware.c [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/hardware.c [iso-8859-1] Wed Jun 26 17:15:45 2013
@@ -53,6 +53,9 @@
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 @@
return TRUE;
}
-#if 0
static BOOLEAN KeyboardQueuePop(BYTE *ScanCode)
{
/* Make sure the keyboard queue is not empty */
@@ -94,7 +96,6 @@
return TRUE;
}
-#endif
/* PUBLIC FUNCTIONS ***********************************************************/
@@ -248,7 +249,7 @@
/* 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 @@
/* 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 @@
}
}
+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;
Modified: branches/ntvdm/subsystems/ntvdm/ntvdm.h
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/ntvdm.h?…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/ntvdm.h [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/ntvdm.h [iso-8859-1] Wed Jun 26 17:15:45 2013
@@ -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)
@@ -91,6 +94,18 @@
#define EMULATOR_FLAG_VIF (1 << 19)
#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
{
@@ -226,9 +241,14 @@
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 EmulatorInitialize();
VOID EmulatorStep();
VOID EmulatorCleanup();
+VOID EmulatorHalt();
+VOID EmulatorSetA20(BOOLEAN Enabled);
/* EOF */