[NTVDM]
[reactos.git] / subsystems / ntvdm / emulator.c
index bce9afb..de52f91 100644 (file)
@@ -8,15 +8,26 @@
 
 /* INCLUDES *******************************************************************/
 
-#include "ntvdm.h"
-#include <softx86/softx86.h>
-#include <softx86/softx87.h>
+#include "emulator.h"
+#include "bios.h"
+#include "dos.h"
+#include "pic.h"
+#include "ps2.h"
+#include "timer.h"
 
-softx86_ctx EmulatorContext;
-softx87_ctx FpuEmulatorContext;
+/* PRIVATE VARIABLES **********************************************************/
+
+static softx86_ctx EmulatorContext;
+static softx87_ctx FpuEmulatorContext;
+static BOOLEAN A20Line = FALSE;
+
+/* PRIVATE FUNCTIONS **********************************************************/
 
 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 +46,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;
 
@@ -64,20 +78,40 @@ static VOID EmulatorReadIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size)
             *Buffer = PicReadCommand(Address);
             break;
         }
-        
+
         case PIC_MASTER_DATA:
         case PIC_SLAVE_DATA:
         {
             *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;
+        }
     }
 }
 
 static VOID EmulatorWriteIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size)
 {
     BYTE Byte = *Buffer;
-    
+
     switch (Address)
     {
         case PIT_COMMAND_PORT:
@@ -85,7 +119,7 @@ static VOID EmulatorWriteIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size
             PitWriteCommand(Byte);
             break;
         }
-        
+
         case PIT_DATA_PORT(0):
         case PIT_DATA_PORT(1):
         case PIT_DATA_PORT(2):
@@ -93,20 +127,32 @@ static VOID EmulatorWriteIo(PVOID Context, UINT Address, LPBYTE Buffer, INT Size
             PitWriteData(Address - PIT_DATA_PORT(0), Byte);
             break;
         }
-        
+
         case PIC_MASTER_CMD:
         case PIC_SLAVE_CMD:
         {
             PicWriteCommand(Address, Byte);
             break;
         }
-        
+
         case PIC_MASTER_DATA:
         case PIC_SLAVE_DATA:
         {
             PicWriteData(Address, Byte);
             break;
         }
+
+        case PS2_CONTROL_PORT:
+        {
+            KeyboardWriteCommand(Byte);
+            break;
+        }
+
+        case PS2_DATA_PORT:
+        {
+            KeyboardWriteData(Byte);
+            break;
+        }
     }
 }
 
@@ -147,7 +193,7 @@ static VOID EmulatorSoftwareInt(PVOID Context, BYTE Number)
             VdmRunning = FALSE;
             return;
         }
-        
+
         /* Check if this was an PIC IRQ */
         if (IntNum >= BIOS_PIC_MASTER_INT && IntNum < BIOS_PIC_MASTER_INT + 8)
         {
@@ -168,6 +214,12 @@ static VOID EmulatorSoftwareInt(PVOID Context, BYTE Number)
                 BiosVideoService();
                 break;
             }
+            case VIDEO_KBD_INTERRUPT:
+            {
+                /* This is the keyboard BIOS interrupt, call the BIOS */
+                BiosKeyboardService();
+                break;
+            }
             case 0x20:
             {
                 DosInt20h(CodeSegment);
@@ -187,6 +239,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 +258,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 +282,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,15 +319,21 @@ 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_CS)
+    if (Register < EMULATOR_REG_ES)
     {
         return EmulatorContext.state->general_reg[Register].val;
     }
     else
     {
-        return EmulatorContext.state->segment_reg[(Register >> 3) - 1].val;
+        return EmulatorContext.state->segment_reg[Register - EMULATOR_REG_ES].val;
     }
 }
 
@@ -272,7 +345,7 @@ VOID EmulatorSetRegister(ULONG Register, ULONG Value)
     }
     else
     {
-        EmulatorContext.state->segment_reg[(Register >> 3) - 1].val = Value;
+        EmulatorContext.state->segment_reg[Register - EMULATOR_REG_ES].val = Value;
     }
 }
 
@@ -294,7 +367,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 +384,9 @@ VOID EmulatorCleanup()
     softx87_free(&FpuEmulatorContext);
 }
 
+VOID EmulatorSetA20(BOOLEAN Enabled)
+{
+    A20Line = Enabled;
+}
+
 /* EOF */