[NTVDM]
[reactos.git] / subsystems / ntvdm / emulator.c
index 826ff39..ab2fabe 100644 (file)
 #define NDEBUG
 
 #include "emulator.h"
+#include "callback.h"
 
 #include "clock.h"
-#include "bios/bios.h"
+#include "bios/rom.h"
 #include "hardware/cmos.h"
 #include "hardware/pic.h"
 #include "hardware/ps2.h"
 /* PRIVATE VARIABLES **********************************************************/
 
 FAST486_STATE EmulatorContext;
+BOOLEAN CpuSimulate = FALSE;
+
+/* No more than 'MaxCpuCallLevel' recursive CPU calls are allowed */
+const static INT MaxCpuCallLevel = 32;
+static INT CpuCallLevel = 0;
+
 LPVOID  BaseAddress = NULL;
 BOOLEAN VdmRunning  = TRUE;
 
@@ -59,6 +66,10 @@ VOID WINAPI EmulatorReadMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer
 {
     UNREFERENCED_PARAMETER(State);
 
+    // BIG HACK!!!! To make BIOS images working correctly,
+    // until Aleksander rewrites memory management!!
+    if (Address >= 0xFFFFFFF0) Address -= 0xFFF00000;
+
     /* If the A20 line is disabled, mask bit 20 */
     if (!A20Line) Address &= ~(1 << 20);
 
@@ -75,20 +86,24 @@ VOID WINAPI EmulatorReadMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer
         DWORD VgaAddress = max(Address, VgaGetVideoBaseAddress());
         DWORD ActualSize = min(Address + Size - 1, VgaGetVideoLimitAddress())
                            - VgaAddress + 1;
-        LPBYTE DestBuffer = (LPBYTE)((ULONG_PTR)BaseAddress + VgaAddress);
+        LPBYTE DestBuffer = (LPBYTE)REAL_TO_PHYS(VgaAddress);
 
         /* Read from the VGA memory */
         VgaReadMemory(VgaAddress, DestBuffer, ActualSize);
     }
 
     /* Read the data from the virtual address space and store it in the buffer */
-    RtlCopyMemory(Buffer, (LPVOID)((ULONG_PTR)BaseAddress + Address), Size);
+    RtlCopyMemory(Buffer, REAL_TO_PHYS(Address), Size);
 }
 
 VOID WINAPI EmulatorWriteMemory(PFAST486_STATE State, ULONG Address, PVOID Buffer, ULONG Size)
 {
     UNREFERENCED_PARAMETER(State);
 
+    // BIG HACK!!!! To make BIOS images working correctly,
+    // until Aleksander rewrites memory management!!
+    if (Address >= 0xFFFFFFF0) Address -= 0xFFF00000;
+
     /* If the A20 line is disabled, mask bit 20 */
     if (!A20Line) Address &= ~(1 << 20);
 
@@ -99,7 +114,7 @@ VOID WINAPI EmulatorWriteMemory(PFAST486_STATE State, ULONG Address, PVOID Buffe
     if ((Address + Size) >= ROM_AREA_START && (Address < ROM_AREA_END)) return;
 
     /* Read the data from the buffer and store it in the virtual address space */
-    RtlCopyMemory((LPVOID)((ULONG_PTR)BaseAddress + Address), Buffer, Size);
+    RtlCopyMemory(REAL_TO_PHYS(Address), Buffer, Size);
 
     /*
      * Check if we modified the VGA memory.
@@ -110,7 +125,7 @@ VOID WINAPI EmulatorWriteMemory(PFAST486_STATE State, ULONG Address, PVOID Buffe
         DWORD VgaAddress = max(Address, VgaGetVideoBaseAddress());
         DWORD ActualSize = min(Address + Size - 1, VgaGetVideoLimitAddress())
                            - VgaAddress + 1;
-        LPBYTE SrcBuffer = (LPBYTE)((ULONG_PTR)BaseAddress + VgaAddress);
+        LPBYTE SrcBuffer = (LPBYTE)REAL_TO_PHYS(VgaAddress);
 
         /* Write to the VGA memory */
         VgaWriteMemory(VgaAddress, SrcBuffer, ActualSize);
@@ -177,12 +192,31 @@ VOID EmulatorStep(VOID)
 
 VOID EmulatorSimulate(VOID)
 {
-    UNIMPLEMENTED;
+    if (CpuCallLevel > MaxCpuCallLevel)
+    {
+        DisplayMessage(L"Too many CPU levels of recursion (%d, expected maximum %d)",
+                       CpuCallLevel, MaxCpuCallLevel);
+
+        /* Stop the VDM */
+        VdmRunning = FALSE;
+        return;
+    }
+    CpuCallLevel++;
+
+    CpuSimulate = TRUE;
+    while (VdmRunning && CpuSimulate) ClockUpdate();
+
+    CpuCallLevel--;
+    if (CpuCallLevel < 0) CpuCallLevel = 0;
+
+    /* This takes into account for reentrance */
+    CpuSimulate = TRUE;
 }
 
 VOID EmulatorUnsimulate(VOID)
 {
-    UNIMPLEMENTED;
+    /* Stop simulation */
+    CpuSimulate = FALSE;
 }
 
 VOID EmulatorInterrupt(BYTE Number)
@@ -330,9 +364,6 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
                       EmulatorIntAcknowledge,
                       NULL /* TODO: Use a TLB */);
 
-    /* Enable interrupts */
-    setIF(1);
-
     /* Initialize DMA */
 
     /* Initialize the PIC, the PIT, the CMOS and the PC Speaker */
@@ -353,7 +384,9 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
     PS2Initialize(ConsoleInput);
 
     /* Set the console input mode */
-    // SetConsoleMode(ConsoleInput, ENABLE_MOUSE_INPUT | ENABLE_PROCESSED_INPUT);
+    // FIXME: Activate ENABLE_WINDOW_INPUT when we will want to perform actions
+    // upon console window events (screen buffer resize, ...).
+    SetConsoleMode(ConsoleInput, ENABLE_PROCESSED_INPUT /* | ENABLE_WINDOW_INPUT */);
 
     /* Start the input thread */
     InputThread = CreateThread(NULL, 0, &PumpConsoleInput, ConsoleInput, 0, NULL);
@@ -363,7 +396,8 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
     // if (!VgaInitialize(ConsoleOutput)) return FALSE;
     VgaInitialize(ConsoleOutput);
 
-    /* Register the emulator BOPs */
+    /* Initialize the software callback system and register the emulator BOPs */
+    InitializeCallbacks();
     RegisterBop(BOP_DEBUGGER  , EmulatorDebugBreakBop);
     RegisterBop(BOP_UNSIMULATE, EmulatorUnsimulateBop);
 
@@ -375,7 +409,7 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
 
 VOID EmulatorCleanup(VOID)
 {
-    // VgaCleanup();
+    VgaCleanup();
 
     /* Close the input thread handle */
     if (InputThread != NULL) CloseHandle(InputThread);