mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
[NTVDM]
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
This commit is contained in:
parent
5dafb169e0
commit
03d8479401
6 changed files with 173 additions and 87 deletions
|
@ -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);
|
||||
|
||||
|
|
|
@ -61,6 +61,10 @@
|
|||
#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,
|
||||
|
|
|
@ -25,37 +25,19 @@
|
|||
|
||||
/* 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;
|
||||
BYTE Port61hState = IOReadB(CONTROL_SYSTEM_PORT61H);
|
||||
BOOLEAN IsConnectedToPITChannel2 = !!(Port61hState & 0x01);
|
||||
BOOLEAN SpeakerDataOn = !!(Port61hState & 0x02);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -15,10 +15,10 @@
|
|||
|
||||
/* DEFINES ********************************************************************/
|
||||
|
||||
#define SPEAKER_CONTROL_PORT 0x61
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID SpeakerPool(VOID);
|
||||
|
||||
VOID SpeakerInitialize(VOID);
|
||||
VOID SpeakerCleanup(VOID);
|
||||
|
||||
|
|
|
@ -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].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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue