[NTVDM]
[reactos.git] / subsystems / ntvdm / emulator.c
index 71e2741..4e8f9e8 100644 (file)
 #define NDEBUG
 
 #include "emulator.h"
-#include "bios.h"
+
+#include "bios/bios.h"
+#include "hardware/cmos.h"
+#include "hardware/pic.h"
+#include "hardware/ps2.h"
+#include "hardware/speaker.h"
+#include "hardware/timer.h"
+#include "hardware/vga.h"
+
 #include "bop.h"
 #include "vddsup.h"
 #include "io.h"
-#include "registers.h"
-#include "vga.h"
-#include "pic.h"
-
-// HACK
-typedef INT VDM_MODE;
 
 /* PRIVATE VARIABLES **********************************************************/
 
 FAST486_STATE EmulatorContext;
+LPVOID  BaseAddress = NULL;
+BOOLEAN VdmRunning  = TRUE;
 
 static BOOLEAN A20Line = FALSE;
+static BYTE Port61hState = 0x00;
+
+LPCWSTR ExceptionName[] =
+{
+    L"Division By Zero",
+    L"Debug",
+    L"Unexpected Error",
+    L"Breakpoint",
+    L"Integer Overflow",
+    L"Bound Range Exceeded",
+    L"Invalid Opcode",
+    L"FPU Not Available"
+};
 
 /* BOP Identifiers */
 #define BOP_DEBUGGER    0x56    // Break into the debugger from a 16-bit app
@@ -109,13 +126,103 @@ VOID WINAPI EmulatorDebugBreak(LPWORD Stack)
     DebugBreak();
 }
 
+
+static BYTE WINAPI Port61hRead(ULONG Port)
+{
+    return Port61hState;
+}
+
+static VOID WINAPI Port61hWrite(ULONG Port, BYTE Data)
+{
+    // BOOLEAN SpeakerChange = FALSE;
+    BYTE OldPort61hState = Port61hState;
+
+    /* Only the four lowest bytes can be written */
+    Port61hState = (Port61hState & 0xF0) | (Data & 0x0F);
+
+    if ((OldPort61hState ^ Port61hState) & 0x01)
+    {
+        DPRINT("PIT 2 Gate %s\n", Port61hState & 0x01 ? "on" : "off");
+        // SpeakerChange = TRUE;
+    }
+
+    PitSetGate(2, !!(Port61hState & 0x01));
+
+    if ((OldPort61hState ^ Port61hState) & 0x02)
+    {
+        /* There were some change for the speaker... */
+        DPRINT("Speaker %s\n", Port61hState & 0x02 ? "on" : "off");
+        // SpeakerChange = TRUE;
+    }
+    // if (SpeakerChange) SpeakerChange();
+    SpeakerChange();
+}
+
+static VOID WINAPI PitChan0Out(LPVOID Param, BOOLEAN State)
+{
+    if (State)
+    {
+        DPRINT("PicInterruptRequest\n");
+        PicInterruptRequest(0); // Raise IRQ 0
+    }
+    // else < Lower IRQ 0 >
+}
+
+static VOID WINAPI PitChan1Out(LPVOID Param, BOOLEAN State)
+{
+#if 0
+    if (State)
+    {
+        /* Set bit 4 of Port 61h */
+        Port61hState |= 1 << 4;
+    }
+    else
+    {
+        /* Clear bit 4 of Port 61h */
+        Port61hState &= ~(1 << 4);
+    }
+#else
+    Port61hState = (Port61hState & 0xEF) | (State << 4);
+#endif
+}
+
+static VOID WINAPI PitChan2Out(LPVOID Param, BOOLEAN State)
+{
+    // BYTE OldPort61hState = Port61hState;
+
+#if 0
+    if (State)
+    {
+        /* Set bit 5 of Port 61h */
+        Port61hState |= 1 << 5;
+    }
+    else
+    {
+        /* Clear bit 5 of Port 61h */
+        Port61hState &= ~(1 << 5);
+    }
+#else
+    Port61hState = (Port61hState & 0xDF) | (State << 5);
+#endif
+    DPRINT("Speaker PIT out\n");
+    // if ((OldPort61hState ^ Port61hState) & 0x20)
+        // SpeakerChange();
+}
+
 /* PUBLIC FUNCTIONS ***********************************************************/
 
-BOOLEAN EmulatorInitialize(VOID)
+BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
 {
     /* Allocate memory for the 16-bit address space */
     BaseAddress = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_ADDRESS);
-    if (BaseAddress == NULL) return FALSE;
+    if (BaseAddress == NULL)
+    {
+        wprintf(L"FATAL: Failed to allocate VDM memory.\n");
+        return FALSE;
+    }
+
+    /* Initialize I/O ports */
+    /* Initialize RAM */
 
     /* Initialize the CPU */
     Fast486Initialize(&EmulatorContext,
@@ -131,21 +238,89 @@ BOOLEAN EmulatorInitialize(VOID)
     /* Enable interrupts */
     setIF(1);
 
-    /* Initialize VDD support */
-    VDDSupInitialize();
+    /* Initialize the PIC, the PIT, the CMOS and the PC Speaker */
+    PicInitialize();
+    PitInitialize();
+    CmosInitialize();
+    SpeakerInitialize();
+
+    /* Set output functions */
+    PitSetOutFunction(0, NULL, PitChan0Out);
+    PitSetOutFunction(1, NULL, PitChan1Out);
+    PitSetOutFunction(2, NULL, PitChan2Out);
+
+    /* Register the I/O Ports */
+    RegisterIoPort(CONTROL_SYSTEM_PORT61H, Port61hRead, Port61hWrite);
+
+    /* Initialize the PS2 port */
+    PS2Initialize(ConsoleInput);
+
+    /* Set the console input mode */
+    // SetConsoleMode(ConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT);
+
+    /* Initialize the VGA */
+    // if (!VgaInitialize(ConsoleOutput)) return FALSE;
+    VgaInitialize(ConsoleOutput);
 
     /* Register the DebugBreak BOP */
     RegisterBop(BOP_DEBUGGER, EmulatorDebugBreak);
 
+    /* Initialize VDD support */
+    VDDSupInitialize();
+
     return TRUE;
 }
 
 VOID EmulatorCleanup(VOID)
 {
+    // VgaCleanup();
+    PS2Cleanup();
+
+    SpeakerCleanup();
+    CmosCleanup();
+    // PitCleanup();
+    // PicCleanup();
+
+    // Fast486Cleanup();
+
     /* Free the memory allocated for the 16-bit address space */
     if (BaseAddress != NULL) HeapFree(GetProcessHeap(), 0, BaseAddress);
 }
 
+VOID EmulatorException(BYTE ExceptionNumber, LPWORD Stack)
+{
+    WORD CodeSegment, InstructionPointer;
+    PBYTE Opcode;
+
+    ASSERT(ExceptionNumber < 8);
+
+    /* Get the CS:IP */
+    InstructionPointer = Stack[STACK_IP];
+    CodeSegment = Stack[STACK_CS];
+    Opcode = (PBYTE)SEG_OFF_TO_PTR(CodeSegment, InstructionPointer);
+
+    /* Display a message to the user */
+    DisplayMessage(L"Exception: %s occured at %04X:%04X\n"
+                   L"Opcode: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X",
+                   ExceptionName[ExceptionNumber],
+                   CodeSegment,
+                   InstructionPointer,
+                   Opcode[0],
+                   Opcode[1],
+                   Opcode[2],
+                   Opcode[3],
+                   Opcode[4],
+                   Opcode[5],
+                   Opcode[6],
+                   Opcode[7],
+                   Opcode[8],
+                   Opcode[9]);
+
+    /* Stop the VDM */
+    VdmRunning = FALSE;
+    return;
+}
+
 // FIXME: This function assumes 16-bit mode!!!
 VOID EmulatorExecute(WORD Segment, WORD Offset)
 {
@@ -181,6 +356,14 @@ VOID EmulatorSetA20(BOOLEAN Enabled)
 
 
 
+VOID
+WINAPI
+VDDTerminateVDM(VOID)
+{
+    /* Stop the VDM */
+    VdmRunning = FALSE;
+}
+
 PBYTE
 WINAPI
 Sim32pGetVDMPointer(IN ULONG   Address,
@@ -219,7 +402,7 @@ VdmMapFlat(IN USHORT   Segment,
     return SEG_OFF_TO_PTR(Segment, Offset);
 }
 
-BOOL 
+BOOL
 WINAPI
 VdmFlushCache(IN USHORT   Segment,
               IN ULONG    Offset,