[NTVDM]
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Tue, 28 Jan 2014 20:24:24 +0000 (20:24 +0000)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Tue, 28 Jan 2014 20:24:24 +0000 (20:24 +0000)
Part 2 of PIT + sound fix.
- Move port 61h management from speaker.c to the emulator.c module;
- Add PIT OUT callbacks support;
- Add (unimplemented) PitSetGate function (will be used later on).
Still WIP.

svn path=/branches/ntvdm/; revision=61866

subsystems/ntvdm/emulator.c
subsystems/ntvdm/emulator.h
subsystems/ntvdm/hardware/speaker.c
subsystems/ntvdm/hardware/speaker.h
subsystems/ntvdm/hardware/timer.c
subsystems/ntvdm/hardware/timer.h

index c8b2c13..bc3f101 100644 (file)
@@ -31,6 +31,7 @@ LPVOID  BaseAddress = NULL;
 BOOLEAN VdmRunning  = TRUE;
 
 static BOOLEAN A20Line = FALSE;
+static BYTE Port61hState = 0x00;
 
 LPCWSTR ExceptionName[] =
 {
@@ -125,6 +126,79 @@ VOID WINAPI EmulatorDebugBreak(LPWORD Stack)
     DebugBreak();
 }
 
+
+static BYTE WINAPI Port61hRead(ULONG Port)
+{
+    return Port61hState;
+}
+
+static VOID WINAPI Port61hWrite(ULONG Port, BYTE Data)
+{
+    BYTE OldPort61hState = Port61hState;
+
+    /* Only the four lowest bytes can be written */
+    Port61hState = (Port61hState & 0xF0) | (Data & 0x0F);
+
+    if ((OldPort61hState ^ Port61hState) & 0x01)
+    {
+        DPRINT1("PIT 2 Gate %s\n", Port61hState & 0x01 ? "on" : "off");
+    }
+
+    PitSetGate(2, !!(Port61hState & 0x01));
+
+    if ((OldPort61hState ^ Port61hState) & 0x02)
+    {
+        /* There were some change for the speaker... */
+        DPRINT1("Speaker %s\n", Port61hState & 0x02 ? "on" : "off");
+    }
+}
+
+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)
+{
+#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
+}
+
 /* PUBLIC FUNCTIONS ***********************************************************/
 
 BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
@@ -160,6 +234,14 @@ BOOLEAN EmulatorInitialize(HANDLE ConsoleInput, HANDLE ConsoleOutput)
     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);
 
index 2474968..49aff1e 100644 (file)
 #define BCD_TO_BINARY(x) (((x) >> 12) * 1000 + ((x) >> 8) * 100 + ((x) >> 4) * 10 + ((x) & 0x0F))
 
 
+/* System I/O ports */
+#define CONTROL_SYSTEM_PORT61H  0x61
+
+
 enum
 {
     EMULATOR_EXCEPTION_DIVISION_BY_ZERO,
index 4bd9af8..26af44d 100644 (file)
 
 /* PRIVATE VARIABLES **********************************************************/
 
-static BYTE Port61hState = 0x00;
-HANDLE hBeep = NULL;
+static HANDLE hBeep = NULL;
 
 /* PRIVATE FUNCTIONS **********************************************************/
 
-static BYTE SpeakerReadStatus(VOID)
-{
-    return Port61hState;
-}
+/* PUBLIC FUNCTIONS ***********************************************************/
 
-static VOID SpeakerWriteCommand(BYTE Value)
+VOID SpeakerPool(VOID)
 {
-    BOOLEAN IsConnectedToPITChannel2;
-    UCHAR   SpeakerData;
-
-    Port61hState = Value;
-    IsConnectedToPITChannel2 = ((Port61hState & 0x01) != 0);
-    SpeakerData = (Port61hState & 0x02);
-
-    if (PitChannel2 && IsConnectedToPITChannel2)
-    {
-        /* Set bit 5 of Port 61h */
-        Port61hState |= 1 << 5;
-    }
-    else
-    {
-        /* Clear bit 5 of Port 61h */
-        Port61hState &= ~(1 << 5);
-    }
+    BYTE    Port61hState = IOReadB(CONTROL_SYSTEM_PORT61H);
+    BOOLEAN IsConnectedToPITChannel2 = !!(Port61hState & 0x01);
+    BOOLEAN SpeakerDataOn = !!(Port61hState & 0x02);
 
-    if (PitChannel2 && IsConnectedToPITChannel2 && (SpeakerData != 0))
+    if (PitChannel2 && IsConnectedToPITChannel2 && SpeakerDataOn)
     {
         /* Start beeping - Adapted from kernel32:Beep() */
         NTSTATUS Status;
@@ -121,18 +103,6 @@ static VOID SpeakerWriteCommand(BYTE Value)
     }
 }
 
-static BYTE WINAPI SpeakerReadPort(ULONG Port)
-{
-    return SpeakerReadStatus();
-}
-
-static VOID WINAPI SpeakerWritePort(ULONG Port, BYTE Data)
-{
-    SpeakerWriteCommand(Data);
-}
-
-/* PUBLIC FUNCTIONS ***********************************************************/
-
 VOID SpeakerInitialize(VOID)
 {
     NTSTATUS Status;
@@ -165,9 +135,6 @@ VOID SpeakerInitialize(VOID)
     {
         DPRINT1("Failed to open Beep driver, Status 0x%08lx\n", Status);
     }
-
-    /* Register the I/O Ports */
-    RegisterIoPort(SPEAKER_CONTROL_PORT, SpeakerReadPort, SpeakerWritePort);
 }
 
 VOID SpeakerCleanup(VOID)
index 166c63e..207b501 100644 (file)
 
 /* DEFINES ********************************************************************/
 
-#define SPEAKER_CONTROL_PORT 0x61
-
 /* FUNCTIONS ******************************************************************/
 
+VOID SpeakerPool(VOID);
+
 VOID SpeakerInitialize(VOID);
 VOID SpeakerCleanup(VOID);
 
index 153e744..87f6863 100644 (file)
@@ -37,13 +37,14 @@ static VOID PitLatchChannelStatus(BYTE Channel)
     if (PitChannels[Channel].LatchStatusSet == FALSE)
     {
         BYTE StatusLatch = 0;
-        /* HACK!! */BYTE NullCount = 0;/* HACK!! */
+        /** HACK!! **/BYTE NullCount = 0;/** HACK!! **/
 
-        StatusLatch = PitChannels[Channel].Out << 7 | NullCount << 6;
+        StatusLatch  =  PitChannels[Channel].Out << 7 | NullCount  << 6;
         StatusLatch |= (PitChannels[Channel].ReadWriteMode & 0x03) << 4;
         StatusLatch |= (PitChannels[Channel].Mode & 0x07) << 1;
         StatusLatch |= (PitChannels[Channel].Bcd  & 0x01);
 
+        /* Latch the counter's status */
         PitChannels[Channel].LatchStatusSet = TRUE;
         PitChannels[Channel].StatusLatch    = StatusLatch;
     }
@@ -61,23 +62,24 @@ static VOID PitLatchChannelCount(BYTE Channel)
      */
     if (PitChannels[Channel].ReadStatus == 0x00)
     {
+        /* Latch the counter's value */
         PitChannels[Channel].ReadStatus  = PitChannels[Channel].ReadWriteMode;
 
         /* Convert the current value to BCD if needed */
-        PitChannels[Channel].OutputLatch = READ_PIT_VALUE(PitChannels[Channel],
-                                                          PitChannels[Channel].CurrentValue);
+        PitChannels[Channel].OutputLatch =
+            READ_PIT_VALUE(PitChannels[Channel], PitChannels[Channel].CurrentValue);
     }
 }
 
 static VOID PitSetOut(PPIT_CHANNEL Channel, BOOLEAN State)
 {
-    if (State == Channel->Out) return;
+    /** HACK!! **\ if (State == Channel->Out) return; \** HACK!! **/
 
     /* Set the new state of the OUT pin */
     Channel->Out = State;
 
-    // /* Call the callback */
-    // if (Channel->OutFunction) Channel->OutFunction(Channel->OutParam, State);
+    /* Call the callback */
+    if (Channel->OutFunction) Channel->OutFunction(Channel->OutParam, State);
 }
 
 static VOID PitInitCounter(PPIT_CHANNEL Channel)
@@ -138,20 +140,16 @@ static VOID PitWriteCommand(BYTE Value)
 
     /* ... otherwise, set the modes and reset flip-flops */
     PitChannels[Channel].ReadWriteMode = ReadWriteMode;
+    PitChannels[Channel].ReadStatus    = 0x00;
+    PitChannels[Channel].WriteStatus   = 0x00;
 
     PitChannels[Channel].LatchStatusSet = FALSE;
     PitChannels[Channel].StatusLatch    = 0x00;
 
-    PitChannels[Channel].ReadStatus  = 0x00;
-    PitChannels[Channel].WriteStatus = 0x00;
-
     PitChannels[Channel].CountRegister = 0x00;
     PitChannels[Channel].OutputLatch   = 0x00;
 
-    PitChannels[Channel].Pulsed = FALSE;
-
-
-    // PitChannels[Channel].Out = FALSE; // <-- unneeded, see the PitInitCounter call below.
+    /** HACK!! **/PitChannels[Channel].FlipFlop = FALSE;/** HACK!! **/
 
     /* Fix the current value if we switch to BCD counting */
     PitChannels[Channel].Bcd = IsBcd;
@@ -192,9 +190,8 @@ static BYTE PitReadData(BYTE Channel)
     LPWORD CurrentValue  = NULL;
 
     /*
-     * If the status was latched, the first read operation
-     * will return the latched status, whichever the count
-     * value or the status was latched first.
+     * If the status was latched, the first read operation will return the
+     * latched status, whichever value (count or status) was latched first.
      */
     if (PitChannels[Channel].LatchStatusSet)
     {
@@ -239,6 +236,8 @@ static VOID PitWriteData(BYTE Channel, BYTE Value)
         PitChannels[Channel].WriteStatus = PitChannels[Channel].ReadWriteMode;
     }
 
+    ASSERT(PitChannels[Channel].WriteStatus != 0);
+
     ReadWriteMode = &PitChannels[Channel].WriteStatus;
 
     if (*ReadWriteMode & 1)
@@ -261,6 +260,7 @@ static VOID PitWriteData(BYTE Channel, BYTE Value)
     {
         if (PitChannels[Channel].CountRegister == 0x0000)
         {
+            /* Wrap around to the highest count */
             if (PitChannels[Channel].Bcd)
                 PitChannels[Channel].CountRegister = 9999;
             else
@@ -268,8 +268,8 @@ static VOID PitWriteData(BYTE Channel, BYTE Value)
         }
 
         /* Convert the current value from BCD if needed */
-        PitChannels[Channel].CountRegister = WRITE_PIT_VALUE(PitChannels[Channel],
-                                                             PitChannels[Channel].CountRegister);
+        PitChannels[Channel].CountRegister =
+            WRITE_PIT_VALUE(PitChannels[Channel], PitChannels[Channel].CountRegister);
         PitChannels[Channel].ReloadValue = PitChannels[Channel].CountRegister;
     }
 }
@@ -311,6 +311,8 @@ static VOID WINAPI PitWritePort(ULONG Port, BYTE Data)
 
 static VOID PitDecrementCount(PPIT_CHANNEL Channel, DWORD Count)
 {
+    if (Count == 0) return;
+
     switch (Channel->Mode)
     {
         case PIT_MODE_INT_ON_TERMINAL_COUNT:
@@ -324,11 +326,10 @@ static VOID PitDecrementCount(PPIT_CHANNEL Channel, DWORD Count)
             else Channel->CurrentValue -= Count;
 
             /* Did it fall to the terminal count? */
-            if (Channel->CurrentValue == 0 && !Channel->Pulsed)
+            if (Channel->CurrentValue == 0 && !Channel->Out)
             {
                 /* Yes, raise the output line */
-                if (Channel == &PitChannels[0]) PicInterruptRequest(0);
-                Channel->Pulsed = TRUE;
+                PitSetOut(Channel, TRUE);
             }
             break;
         }
@@ -342,7 +343,7 @@ static VOID PitDecrementCount(PPIT_CHANNEL Channel, DWORD Count)
                 if ((Count > Channel->CurrentValue)
                     && (Channel->CurrentValue != 0))
                 {
-                    /* Decrease the count */
+                    /* Decrement the count */
                     Count -= Channel->CurrentValue;
 
                     /* Reload the value */
@@ -353,7 +354,7 @@ static VOID PitDecrementCount(PPIT_CHANNEL Channel, DWORD Count)
                 }
                 else
                 {
-                    /* Decrease the value */
+                    /* Decrement the value */
                     Channel->CurrentValue -= Count;
 
                     /* Clear the count */
@@ -368,8 +369,8 @@ static VOID PitDecrementCount(PPIT_CHANNEL Channel, DWORD Count)
                 }
             }
 
-            /* If there was a reload on channel 0, raise IRQ 0 */
-            if ((Channel == &PitChannels[0]) && Reloaded) PicInterruptRequest(0);
+            /* If there was a reload, raise the output line */
+            if (Reloaded) PitSetOut(Channel, TRUE);
 
             break;
         }
@@ -387,7 +388,7 @@ static VOID PitDecrementCount(PPIT_CHANNEL Channel, DWORD Count)
                 if (((Count * 2) > Channel->CurrentValue)
                     && (Channel->CurrentValue != 0))
                 {
-                    /* Decrease the count */
+                    /* Decrement the count */
                     Count -= Channel->CurrentValue / 2;
 
                     /* Reload the value */
@@ -398,7 +399,7 @@ static VOID PitDecrementCount(PPIT_CHANNEL Channel, DWORD Count)
                 }
                 else
                 {
-                    /* Decrease the value */
+                    /* Decrement the value */
                     Channel->CurrentValue -= Count * 2;
 
                     /* Clear the count */
@@ -421,16 +422,15 @@ static VOID PitDecrementCount(PPIT_CHANNEL Channel, DWORD Count)
             /* Toggle the flip-flop if the number of reloads was odd */
             if (ReloadCount & 1)
             {
-                Channel->Out = !Channel->Out;
+                Channel->FlipFlop = !Channel->FlipFlop;
+                // PitSetOut(Channel, !Channel->Out);
             }
 
-            /* Was there any rising edge on channel 0 ? */
-            if (((Channel->Out && (ReloadCount == 1))
-                || (ReloadCount > 1))
-                && (Channel == &PitChannels[0]))
+            /* Was there any rising edge? */
+            if ((Channel->FlipFlop && (ReloadCount == 1)) || (ReloadCount > 1))
             {
-                /* Yes, IRQ 0 */
-                PicInterruptRequest(0);
+                /* Yes, raise the output line */
+                PitSetOut(Channel, TRUE);
             }
 
             break;
@@ -453,6 +453,23 @@ static VOID PitDecrementCount(PPIT_CHANNEL Channel, DWORD Count)
 
 /* PUBLIC FUNCTIONS ***********************************************************/
 
+VOID PitSetOutFunction(BYTE Channel, LPVOID Param, PIT_OUT_FUNCTION OutFunction)
+{
+    if (Channel >= PIT_CHANNELS) return;
+
+    PitChannels[Channel].OutParam    = Param;
+    PitChannels[Channel].OutFunction = OutFunction;
+}
+
+VOID PitSetGate(BYTE Channel, BOOLEAN State)
+{
+    if (Channel >= PIT_CHANNELS) return;
+    if (State == PitChannels[Channel].Gate) return;
+
+    /* UNIMPLEMENTED */
+    PitChannels[Channel].Gate = State;
+}
+
 VOID PitClock(DWORD Count)
 {
     UINT i;
@@ -461,7 +478,7 @@ VOID PitClock(DWORD Count)
 
     for (i = 0; i < PIT_CHANNELS; i++)
     {
-        // if (!PitChannels[i].Couting) continue;
+        // if (!PitChannels[i].Counting) continue;
         PitDecrementCount(&PitChannels[i], Count);
     }
 }
@@ -487,6 +504,14 @@ DWORD PitGetResolution(VOID)
 
 VOID PitInitialize(VOID)
 {
+    /* Set up the timers to their default value */
+    PitSetOutFunction(0, NULL, NULL);
+    PitSetGate(0, TRUE);
+    PitSetOutFunction(1, NULL, NULL);
+    PitSetGate(1, TRUE);
+    PitSetOutFunction(2, NULL, NULL);
+    PitSetGate(2, FALSE);
+
     /* Register the I/O Ports */
     RegisterIoPort(PIT_COMMAND_PORT, NULL       , PitWritePort);
     RegisterIoPort(PIT_DATA_PORT(0), PitReadPort, PitWritePort);
index fcd0fcf..21f7f8e 100644 (file)
@@ -38,23 +38,25 @@ typedef enum _PIT_MODE
     PIT_MODE_HARDWARE_STROBE
 } PIT_MODE, *PPIT_MODE;
 
+typedef VOID (WINAPI *PIT_OUT_FUNCTION)(LPVOID Param, BOOLEAN State);
+
 typedef struct _PIT_CHANNEL
 {
-    BOOLEAN Pulsed;
-
-
-    /* PIT Status members */
+    /* PIT Status fields */
     PIT_MODE Mode;
     BOOLEAN  Bcd;
     BYTE     ReadWriteMode; // 0 --> Counter Latch ; 1 --> LSB R/W ; 2 --> MSB R/W ; 3 --> LSB then MSB R/W
 
-    /* Reading the PIT status byte */
+    /* For interleaved reading and writing in 2-byte RW mode */
+    BYTE    ReadStatus;     // Same convention as ReadWriteMode
+    BYTE    WriteStatus;    // Same convention as ReadWriteMode
+
+    /* For reading the PIT status byte */
     BOOLEAN LatchStatusSet;
     BYTE    StatusLatch;
 
-    /* For interleaving reading and writing in 2-byte RW mode */
-    BYTE    ReadStatus;     // Same convention as ReadWriteMode
-    BYTE    WriteStatus;    // Same convention as ReadWriteMode
+    /* Counting */
+    BOOLEAN Gate;
 
     /**/WORD    CountRegister;/**/  // Our ReloadValue ???
     WORD OutputLatch;
@@ -65,6 +67,9 @@ typedef struct _PIT_CHANNEL
 
     /* PIT Output */
     BOOLEAN Out;    // 0: Low ; 1: High
+    /** HACK!! **/BOOLEAN FlipFlop;/** HACK!! **/
+    LPVOID           OutParam;
+    PIT_OUT_FUNCTION OutFunction;
 
 } PIT_CHANNEL, *PPIT_CHANNEL;
 
@@ -72,6 +77,9 @@ extern PPIT_CHANNEL PitChannel2;    // Needed for PC Speaker
 
 /* FUNCTIONS ******************************************************************/
 
+VOID PitSetOutFunction(BYTE Channel, LPVOID Param, PIT_OUT_FUNCTION OutFunction);
+VOID PitSetGate(BYTE Channel, BOOLEAN State);
+
 VOID PitClock(DWORD Count);
 DWORD PitGetResolution(VOID);