mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 04:43:51 +00:00
[FAST486]
Separate external interrupts from interrupt signals (which are interrupts whose number is not known until they can be serviced, just like hardware interrupts on a real CPU). [NTVDM] Improve the PIC emulation code (IRQ priorities, etc...). Instead of checking for interrupts in the main loop, move the PS/2 input parsing to a different thread. Improve BIOS keyboard IRQ handling. svn path=/branches/ntvdm/; revision=60761
This commit is contained in:
parent
fcbe98e6b6
commit
f5d3c9254c
11 changed files with 204 additions and 94 deletions
|
@ -145,6 +145,13 @@ typedef enum _FAST486_EXCEPTIONS
|
||||||
FAST486_EXCEPTION_MC = 0x12
|
FAST486_EXCEPTION_MC = 0x12
|
||||||
} FAST486_EXCEPTIONS, *PFAST486_EXCEPTIONS;
|
} FAST486_EXCEPTIONS, *PFAST486_EXCEPTIONS;
|
||||||
|
|
||||||
|
typedef enum _FAST486_INT_STATUS
|
||||||
|
{
|
||||||
|
FAST486_INT_NONE = 0,
|
||||||
|
FAST486_INT_EXECUTE = 1,
|
||||||
|
FAST486_INT_SIGNAL = 2
|
||||||
|
} FAST486_INT_STATUS, *PFAST486_INT_STATUS;
|
||||||
|
|
||||||
typedef
|
typedef
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
(NTAPI *FAST486_MEM_READ_PROC)
|
(NTAPI *FAST486_MEM_READ_PROC)
|
||||||
|
@ -200,6 +207,13 @@ VOID
|
||||||
USHORT BopCode
|
USHORT BopCode
|
||||||
);
|
);
|
||||||
|
|
||||||
|
typedef
|
||||||
|
UCHAR
|
||||||
|
(NTAPI *FAST486_INT_ACK_PROC)
|
||||||
|
(
|
||||||
|
PFAST486_STATE State
|
||||||
|
);
|
||||||
|
|
||||||
typedef union _FAST486_REG
|
typedef union _FAST486_REG
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
|
@ -352,6 +366,7 @@ struct _FAST486_STATE
|
||||||
FAST486_IO_WRITE_PROC IoWriteCallback;
|
FAST486_IO_WRITE_PROC IoWriteCallback;
|
||||||
FAST486_IDLE_PROC IdleCallback;
|
FAST486_IDLE_PROC IdleCallback;
|
||||||
FAST486_BOP_PROC BopCallback;
|
FAST486_BOP_PROC BopCallback;
|
||||||
|
FAST486_INT_ACK_PROC IntAckCallback;
|
||||||
FAST486_REG GeneralRegs[FAST486_NUM_GEN_REGS];
|
FAST486_REG GeneralRegs[FAST486_NUM_GEN_REGS];
|
||||||
FAST486_SEG_REG SegmentRegs[FAST486_NUM_SEG_REGS];
|
FAST486_SEG_REG SegmentRegs[FAST486_NUM_SEG_REGS];
|
||||||
FAST486_REG InstPtr, SavedInstPtr;
|
FAST486_REG InstPtr, SavedInstPtr;
|
||||||
|
@ -362,7 +377,7 @@ struct _FAST486_STATE
|
||||||
ULONG ExceptionCount;
|
ULONG ExceptionCount;
|
||||||
ULONG PrefixFlags;
|
ULONG PrefixFlags;
|
||||||
FAST486_SEG_REGS SegmentOverride;
|
FAST486_SEG_REGS SegmentOverride;
|
||||||
BOOLEAN HardwareInt;
|
FAST486_INT_STATUS IntStatus;
|
||||||
UCHAR PendingIntNum;
|
UCHAR PendingIntNum;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -396,6 +411,10 @@ VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
Fast486Interrupt(PFAST486_STATE State, UCHAR Number);
|
Fast486Interrupt(PFAST486_STATE State, UCHAR Number);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
Fast486InterruptSignal(PFAST486_STATE State);
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
Fast486ExecuteAt(PFAST486_STATE State, USHORT Segment, ULONG Offset);
|
Fast486ExecuteAt(PFAST486_STATE State, USHORT Segment, ULONG Offset);
|
||||||
|
|
|
@ -61,11 +61,23 @@ Fast486ExecutionControl(PFAST486_STATE State, INT Command)
|
||||||
{
|
{
|
||||||
State->SavedInstPtr = State->InstPtr;
|
State->SavedInstPtr = State->InstPtr;
|
||||||
|
|
||||||
/* Check if interrupts are enabled and there is an interrupt pending */
|
/*
|
||||||
if (State->Flags.If && State->HardwareInt)
|
* Check if there is an interrupt to execute, or a hardware interrupt signal
|
||||||
|
* while interrupts are enabled.
|
||||||
|
*/
|
||||||
|
if ((State->IntStatus == FAST486_INT_EXECUTE)
|
||||||
|
|| (State->Flags.If
|
||||||
|
&& (State->IntAckCallback != NULL)
|
||||||
|
&& (State->IntStatus == FAST486_INT_SIGNAL)))
|
||||||
{
|
{
|
||||||
FAST486_IDT_ENTRY IdtEntry;
|
FAST486_IDT_ENTRY IdtEntry;
|
||||||
|
|
||||||
|
if (State->IntStatus == FAST486_INT_SIGNAL)
|
||||||
|
{
|
||||||
|
/* Acknowledge the interrupt to get the number */
|
||||||
|
State->PendingIntNum = State->IntAckCallback(State);
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the interrupt vector */
|
/* Get the interrupt vector */
|
||||||
if (Fast486GetIntVector(State, State->PendingIntNum, &IdtEntry))
|
if (Fast486GetIntVector(State, State->PendingIntNum, &IdtEntry))
|
||||||
{
|
{
|
||||||
|
@ -76,8 +88,8 @@ Fast486ExecutionControl(PFAST486_STATE State, INT Command)
|
||||||
IdtEntry.Type);
|
IdtEntry.Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the interrupt pending flag */
|
/* Clear the interrupt status */
|
||||||
State->HardwareInt = FALSE;
|
State->IntStatus = FAST486_INT_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,6 +255,7 @@ Fast486Reset(PFAST486_STATE State)
|
||||||
FAST486_IO_WRITE_PROC IoWriteCallback = State->IoWriteCallback;
|
FAST486_IO_WRITE_PROC IoWriteCallback = State->IoWriteCallback;
|
||||||
FAST486_IDLE_PROC IdleCallback = State->IdleCallback;
|
FAST486_IDLE_PROC IdleCallback = State->IdleCallback;
|
||||||
FAST486_BOP_PROC BopCallback = State->BopCallback;
|
FAST486_BOP_PROC BopCallback = State->BopCallback;
|
||||||
|
FAST486_INT_ACK_PROC IntAckCallback = State->IntAckCallback;
|
||||||
|
|
||||||
/* Clear the entire structure */
|
/* Clear the entire structure */
|
||||||
RtlZeroMemory(State, sizeof(*State));
|
RtlZeroMemory(State, sizeof(*State));
|
||||||
|
@ -278,17 +291,26 @@ Fast486Reset(PFAST486_STATE State)
|
||||||
State->IoWriteCallback = IoWriteCallback;
|
State->IoWriteCallback = IoWriteCallback;
|
||||||
State->IdleCallback = IdleCallback;
|
State->IdleCallback = IdleCallback;
|
||||||
State->BopCallback = BopCallback;
|
State->BopCallback = BopCallback;
|
||||||
|
State->IntAckCallback = IntAckCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
Fast486Interrupt(PFAST486_STATE State, UCHAR Number)
|
Fast486Interrupt(PFAST486_STATE State, UCHAR Number)
|
||||||
{
|
{
|
||||||
/* Set the hardware interrupt flag */
|
/* Set the interrupt status and the number */
|
||||||
State->HardwareInt = TRUE;
|
State->IntStatus = FAST486_INT_EXECUTE;
|
||||||
State->PendingIntNum = Number;
|
State->PendingIntNum = Number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
Fast486InterruptSignal(PFAST486_STATE State)
|
||||||
|
{
|
||||||
|
/* Set the interrupt status */
|
||||||
|
State->IntStatus = FAST486_INT_SIGNAL;
|
||||||
|
}
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
Fast486ExecuteAt(PFAST486_STATE State, USHORT Segment, ULONG Offset)
|
Fast486ExecuteAt(PFAST486_STATE State, USHORT Segment, ULONG Offset)
|
||||||
|
|
|
@ -876,7 +876,7 @@ FAST486_OPCODE_HANDLER(Fast486OpcodeHalt)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Halt */
|
/* Halt */
|
||||||
while (!State->HardwareInt) State->IdleCallback(State);
|
while (State->IntStatus != FAST486_INT_SIGNAL) State->IdleCallback(State);
|
||||||
|
|
||||||
/* Return success */
|
/* Return success */
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
|
@ -1092,39 +1092,40 @@ VOID BiosHandleIrq(BYTE IrqNumber, LPWORD Stack)
|
||||||
BYTE ScanCode, VirtualKey;
|
BYTE ScanCode, VirtualKey;
|
||||||
WORD Character;
|
WORD Character;
|
||||||
|
|
||||||
/* Check if there is a scancode available */
|
/* Loop while there is a scancode available */
|
||||||
if (!(KeyboardReadStatus() & 1)) break;
|
while (KeyboardReadStatus() & 1)
|
||||||
|
|
||||||
/* Get the scan code and virtual key code */
|
|
||||||
ScanCode = KeyboardReadData();
|
|
||||||
VirtualKey = MapVirtualKey(ScanCode & 0x7F, MAPVK_VSC_TO_VK);
|
|
||||||
|
|
||||||
/* Check if this is a key press or release */
|
|
||||||
if (!(ScanCode & (1 << 7)))
|
|
||||||
{
|
{
|
||||||
/* Key press */
|
/* Get the scan code and virtual key code */
|
||||||
if (VirtualKey == VK_NUMLOCK
|
ScanCode = KeyboardReadData();
|
||||||
|| VirtualKey == VK_CAPITAL
|
VirtualKey = MapVirtualKey(ScanCode & 0x7F, MAPVK_VSC_TO_VK);
|
||||||
|| VirtualKey == VK_SCROLL)
|
|
||||||
{
|
|
||||||
/* For toggle keys, toggle the lowest bit in the keyboard map */
|
|
||||||
BiosKeyboardMap[VirtualKey] ^= ~(1 << 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the highest bit */
|
/* Check if this is a key press or release */
|
||||||
BiosKeyboardMap[VirtualKey] |= (1 << 7);
|
if (!(ScanCode & (1 << 7)))
|
||||||
|
|
||||||
/* Find out which character this is */
|
|
||||||
if (ToAscii(VirtualKey, ScanCode, BiosKeyboardMap, &Character, 0) > 0)
|
|
||||||
{
|
{
|
||||||
/* Push it onto the BIOS keyboard queue */
|
/* Key press */
|
||||||
BiosKbdBufferPush((ScanCode << 8) | (Character & 0xFF));
|
if (VirtualKey == VK_NUMLOCK
|
||||||
|
|| VirtualKey == VK_CAPITAL
|
||||||
|
|| VirtualKey == VK_SCROLL)
|
||||||
|
{
|
||||||
|
/* For toggle keys, toggle the lowest bit in the keyboard map */
|
||||||
|
BiosKeyboardMap[VirtualKey] ^= ~(1 << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the highest bit */
|
||||||
|
BiosKeyboardMap[VirtualKey] |= (1 << 7);
|
||||||
|
|
||||||
|
/* Find out which character this is */
|
||||||
|
if (ToAscii(VirtualKey, ScanCode, BiosKeyboardMap, &Character, 0) > 0)
|
||||||
|
{
|
||||||
|
/* Push it onto the BIOS keyboard queue */
|
||||||
|
BiosKbdBufferPush((ScanCode << 8) | (Character & 0xFF));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Key release, unset the highest bit */
|
||||||
|
BiosKeyboardMap[VirtualKey] &= ~(1 << 7);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Key release, unset the highest bit */
|
|
||||||
BiosKeyboardMap[VirtualKey] &= ~(1 << 7);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -329,6 +329,14 @@ static VOID WINAPI EmulatorBiosOperation(PFAST486_STATE State, WORD Code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BYTE WINAPI EmulatorIntAcknowledge(PFAST486_STATE State)
|
||||||
|
{
|
||||||
|
UNREFERENCED_PARAMETER(State);
|
||||||
|
|
||||||
|
/* Get the interrupt number from the PIC */
|
||||||
|
return PicGetInterrupt();
|
||||||
|
}
|
||||||
|
|
||||||
/* PUBLIC FUNCTIONS ***********************************************************/
|
/* PUBLIC FUNCTIONS ***********************************************************/
|
||||||
|
|
||||||
BOOLEAN EmulatorInitialize()
|
BOOLEAN EmulatorInitialize()
|
||||||
|
@ -342,7 +350,8 @@ BOOLEAN EmulatorInitialize()
|
||||||
EmulatorContext.MemWriteCallback = (FAST486_MEM_WRITE_PROC)EmulatorWriteMemory;
|
EmulatorContext.MemWriteCallback = (FAST486_MEM_WRITE_PROC)EmulatorWriteMemory;
|
||||||
EmulatorContext.IoReadCallback = (FAST486_IO_READ_PROC)EmulatorReadIo;
|
EmulatorContext.IoReadCallback = (FAST486_IO_READ_PROC)EmulatorReadIo;
|
||||||
EmulatorContext.IoWriteCallback = (FAST486_IO_WRITE_PROC)EmulatorWriteIo;
|
EmulatorContext.IoWriteCallback = (FAST486_IO_WRITE_PROC)EmulatorWriteIo;
|
||||||
EmulatorContext.BopCallback = (FAST486_BOP_PROC)EmulatorBiosOperation;
|
EmulatorContext.BopCallback = EmulatorBiosOperation;
|
||||||
|
EmulatorContext.IntAckCallback = EmulatorIntAcknowledge;
|
||||||
|
|
||||||
/* Reset the CPU */
|
/* Reset the CPU */
|
||||||
Fast486Reset(&EmulatorContext);
|
Fast486Reset(&EmulatorContext);
|
||||||
|
@ -371,10 +380,10 @@ VOID EmulatorInterrupt(BYTE Number)
|
||||||
Fast486Interrupt(&EmulatorContext, Number);
|
Fast486Interrupt(&EmulatorContext, Number);
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID EmulatorExternalInterrupt(BYTE Number)
|
VOID EmulatorInterruptSignal(VOID)
|
||||||
{
|
{
|
||||||
/* Call the Fast486 API */
|
/* Call the Fast486 API */
|
||||||
Fast486Interrupt(&EmulatorContext, Number);
|
Fast486InterruptSignal(&EmulatorContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
ULONG EmulatorGetRegister(ULONG Register)
|
ULONG EmulatorGetRegister(ULONG Register)
|
||||||
|
|
|
@ -88,7 +88,7 @@ BOOLEAN EmulatorInitialize();
|
||||||
VOID EmulatorSetStack(WORD Segment, DWORD Offset);
|
VOID EmulatorSetStack(WORD Segment, DWORD Offset);
|
||||||
VOID EmulatorExecute(WORD Segment, WORD Offset);
|
VOID EmulatorExecute(WORD Segment, WORD Offset);
|
||||||
VOID EmulatorInterrupt(BYTE Number);
|
VOID EmulatorInterrupt(BYTE Number);
|
||||||
VOID EmulatorExternalInterrupt(BYTE Number);
|
VOID EmulatorInterruptSignal(VOID);
|
||||||
ULONG EmulatorGetRegister(ULONG Register);
|
ULONG EmulatorGetRegister(ULONG Register);
|
||||||
ULONG EmulatorGetProgramCounter(VOID);
|
ULONG EmulatorGetProgramCounter(VOID);
|
||||||
VOID EmulatorSetRegister(ULONG Register, ULONG Value);
|
VOID EmulatorSetRegister(ULONG Register, ULONG Value);
|
||||||
|
|
|
@ -79,12 +79,12 @@ INT wmain(INT argc, WCHAR *argv[])
|
||||||
INT i;
|
INT i;
|
||||||
CHAR CommandLine[DOS_CMDLINE_LENGTH];
|
CHAR CommandLine[DOS_CMDLINE_LENGTH];
|
||||||
DWORD CurrentTickCount;
|
DWORD CurrentTickCount;
|
||||||
DWORD LastTickCount = GetTickCount();
|
|
||||||
DWORD Cycles = 0;
|
DWORD Cycles = 0;
|
||||||
DWORD LastCyclePrintout = GetTickCount();
|
DWORD LastCyclePrintout = GetTickCount();
|
||||||
DWORD LastVerticalRefresh = GetTickCount();
|
DWORD LastVerticalRefresh = GetTickCount();
|
||||||
LARGE_INTEGER Frequency, LastTimerTick, Counter;
|
LARGE_INTEGER Frequency, LastTimerTick, Counter;
|
||||||
LONGLONG TimerTicks;
|
LONGLONG TimerTicks;
|
||||||
|
HANDLE InputThread = NULL;
|
||||||
|
|
||||||
/* Set the handler routine */
|
/* Set the handler routine */
|
||||||
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
|
SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
|
||||||
|
@ -142,6 +142,9 @@ INT wmain(INT argc, WCHAR *argv[])
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Start the input thread */
|
||||||
|
InputThread = CreateThread(NULL, 0, &InputThreadProc, NULL, 0, NULL);
|
||||||
|
|
||||||
/* Set the last timer tick to the current time */
|
/* Set the last timer tick to the current time */
|
||||||
QueryPerformanceCounter(&LastTimerTick);
|
QueryPerformanceCounter(&LastTimerTick);
|
||||||
|
|
||||||
|
@ -162,13 +165,6 @@ INT wmain(INT argc, WCHAR *argv[])
|
||||||
for (i = 0; i < TimerTicks; i++) PitDecrementCount();
|
for (i = 0; i < TimerTicks; i++) PitDecrementCount();
|
||||||
LastTimerTick = Counter;
|
LastTimerTick = Counter;
|
||||||
|
|
||||||
/* Check for console input events every millisecond */
|
|
||||||
if (CurrentTickCount != LastTickCount)
|
|
||||||
{
|
|
||||||
CheckForInputEvents();
|
|
||||||
LastTickCount = CurrentTickCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for vertical retrace */
|
/* Check for vertical retrace */
|
||||||
if ((CurrentTickCount - LastVerticalRefresh) >= 16)
|
if ((CurrentTickCount - LastVerticalRefresh) >= 16)
|
||||||
{
|
{
|
||||||
|
@ -198,6 +194,7 @@ INT wmain(INT argc, WCHAR *argv[])
|
||||||
VgaRefreshDisplay();
|
VgaRefreshDisplay();
|
||||||
|
|
||||||
Cleanup:
|
Cleanup:
|
||||||
|
if (InputThread != NULL) CloseHandle(InputThread);
|
||||||
BiosCleanup();
|
BiosCleanup();
|
||||||
EmulatorCleanup();
|
EmulatorCleanup();
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,8 @@ BYTE PicReadCommand(BYTE Port)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* The IRR is always 0, as the emulated CPU receives the interrupt instantly */
|
/* Read the interrupt request register */
|
||||||
return 0;
|
return Pic->IntRequestRegister;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,9 +167,9 @@ VOID PicInterruptRequest(BYTE Number)
|
||||||
/* Check if the interrupt is masked */
|
/* Check if the interrupt is masked */
|
||||||
if (MasterPic.MaskRegister & (1 << Number)) return;
|
if (MasterPic.MaskRegister & (1 << Number)) return;
|
||||||
|
|
||||||
/* Set the appropriate bit in the ISR and interrupt the CPU */
|
/* Set the appropriate bit in the IRR and interrupt the CPU */
|
||||||
if (!MasterPic.AutoEoi) MasterPic.InServiceRegister |= 1 << Number;
|
MasterPic.IntRequestRegister |= 1 << Number;
|
||||||
EmulatorExternalInterrupt(MasterPic.IntOffset + Number);
|
EmulatorInterruptSignal();
|
||||||
}
|
}
|
||||||
else if (Number >= 8 && Number < 16)
|
else if (Number >= 8 && Number < 16)
|
||||||
{
|
{
|
||||||
|
@ -187,7 +187,7 @@ VOID PicInterruptRequest(BYTE Number)
|
||||||
|
|
||||||
/* Check if any of the higher-priorirty interrupts are busy */
|
/* Check if any of the higher-priorirty interrupts are busy */
|
||||||
if (MasterPic.InServiceRegister != 0) return;
|
if (MasterPic.InServiceRegister != 0) return;
|
||||||
for (i = 0; i <= Number ; i++)
|
for (i = 0; i <= Number; i++)
|
||||||
{
|
{
|
||||||
if (SlavePic.InServiceRegister & (1 << Number)) return;
|
if (SlavePic.InServiceRegister & (1 << Number)) return;
|
||||||
}
|
}
|
||||||
|
@ -196,12 +196,57 @@ VOID PicInterruptRequest(BYTE Number)
|
||||||
if (SlavePic.MaskRegister & (1 << Number)) return;
|
if (SlavePic.MaskRegister & (1 << Number)) return;
|
||||||
|
|
||||||
/* Set the IRQ 2 bit in the master ISR */
|
/* Set the IRQ 2 bit in the master ISR */
|
||||||
if (!MasterPic.AutoEoi) MasterPic.InServiceRegister |= 1 << 2;
|
if (!MasterPic.AutoEoi) MasterPic.InServiceRegister |= (1 << 2);
|
||||||
|
|
||||||
/* Set the appropriate bit in the ISR and interrupt the CPU */
|
/* Set the appropriate bit in the IRR and interrupt the CPU */
|
||||||
if (!SlavePic.AutoEoi) SlavePic.InServiceRegister |= 1 << Number;
|
SlavePic.IntRequestRegister |= 1 << Number;
|
||||||
EmulatorExternalInterrupt(SlavePic.IntOffset + Number);
|
EmulatorInterruptSignal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BYTE PicGetInterrupt(VOID)
|
||||||
|
{
|
||||||
|
INT i, j;
|
||||||
|
|
||||||
|
/* Search interrupts by priority */
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
/* Check if this line is cascaded to the slave PIC */
|
||||||
|
if ((i == 2)
|
||||||
|
&& MasterPic.CascadeRegister & (1 << 2)
|
||||||
|
&& SlavePic.Slave
|
||||||
|
&& (SlavePic.CascadeRegister == 2))
|
||||||
|
{
|
||||||
|
/* Search the slave PIC interrupts by priority */
|
||||||
|
for (j = 0; j < 8; j++) if ((j != 1) && SlavePic.IntRequestRegister & (1 << j))
|
||||||
|
{
|
||||||
|
/* Clear the IRR flag */
|
||||||
|
SlavePic.IntRequestRegister &= ~(1 << j);
|
||||||
|
|
||||||
|
/* Set the ISR flag, unless AEOI is enabled */
|
||||||
|
if (!SlavePic.AutoEoi) SlavePic.InServiceRegister |= (1 << j);
|
||||||
|
|
||||||
|
/* Return the interrupt number */
|
||||||
|
return SlavePic.IntOffset + j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MasterPic.IntRequestRegister & (1 << i))
|
||||||
|
{
|
||||||
|
/* Clear the IRR flag */
|
||||||
|
MasterPic.IntRequestRegister &= ~(1 << i);
|
||||||
|
|
||||||
|
/* Set the ISR flag, unless AEOI is enabled */
|
||||||
|
if (!MasterPic.AutoEoi) MasterPic.InServiceRegister |= (1 << i);
|
||||||
|
|
||||||
|
/* Return the interrupt number */
|
||||||
|
return MasterPic.IntOffset + i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Spurious interrupt */
|
||||||
|
if (MasterPic.InServiceRegister & (1 << 2)) return SlavePic.IntOffset + 7;
|
||||||
|
else return MasterPic.IntOffset + 7;
|
||||||
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -34,6 +34,7 @@ typedef struct _PIC
|
||||||
{
|
{
|
||||||
BOOLEAN Initialization;
|
BOOLEAN Initialization;
|
||||||
BYTE MaskRegister;
|
BYTE MaskRegister;
|
||||||
|
BYTE IntRequestRegister;
|
||||||
BYTE InServiceRegister;
|
BYTE InServiceRegister;
|
||||||
BYTE IntOffset;
|
BYTE IntOffset;
|
||||||
BYTE ConfigRegister;
|
BYTE ConfigRegister;
|
||||||
|
@ -51,6 +52,7 @@ VOID PicWriteCommand(BYTE Port, BYTE Value);
|
||||||
BYTE PicReadData(BYTE Port);
|
BYTE PicReadData(BYTE Port);
|
||||||
VOID PicWriteData(BYTE Port, BYTE Value);
|
VOID PicWriteData(BYTE Port, BYTE Value);
|
||||||
VOID PicInterruptRequest(BYTE Number);
|
VOID PicInterruptRequest(BYTE Number);
|
||||||
|
BYTE PicGetInterrupt(VOID);
|
||||||
|
|
||||||
#endif // _PIC_H_
|
#endif // _PIC_H_
|
||||||
|
|
||||||
|
|
|
@ -265,49 +265,64 @@ VOID KeyboardWriteData(BYTE Data)
|
||||||
// TODO: Implement PS/2 device commands
|
// TODO: Implement PS/2 device commands
|
||||||
}
|
}
|
||||||
|
|
||||||
VOID CheckForInputEvents()
|
DWORD WINAPI InputThreadProc(LPVOID Parameter)
|
||||||
{
|
{
|
||||||
PINPUT_RECORD Buffer;
|
INT i;
|
||||||
HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
|
HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
DWORD i, j, Count, TotalEvents;
|
INPUT_RECORD InputRecord;
|
||||||
BYTE ScanCode;
|
DWORD Count;
|
||||||
BOOLEAN Interrupt = FALSE;
|
|
||||||
|
|
||||||
/* Get the number of input events */
|
while (VdmRunning)
|
||||||
if (!GetNumberOfConsoleInputEvents(ConsoleInput, &Count)) return;
|
|
||||||
if (Count == 0) return;
|
|
||||||
|
|
||||||
/* Allocate the buffer */
|
|
||||||
Buffer = (PINPUT_RECORD)HeapAlloc(GetProcessHeap(), 0, Count * sizeof(INPUT_RECORD));
|
|
||||||
if (Buffer == NULL) return;
|
|
||||||
|
|
||||||
/* Peek the input events */
|
|
||||||
if (!ReadConsoleInput(ConsoleInput, Buffer, Count, &TotalEvents)) goto Cleanup;
|
|
||||||
|
|
||||||
for (i = 0; i < TotalEvents; i++)
|
|
||||||
{
|
{
|
||||||
/* Check if this is a key event */
|
/* Wait for an input record */
|
||||||
if (Buffer[i].EventType != KEY_EVENT) continue;
|
if (!ReadConsoleInput(ConsoleInput, &InputRecord, 1, &Count))
|
||||||
|
|
||||||
/* Get the scan code */
|
|
||||||
ScanCode = (BYTE)Buffer[i].Event.KeyEvent.wVirtualScanCode;
|
|
||||||
|
|
||||||
/* If this is a key release, set the highest bit in the scan code */
|
|
||||||
if (!Buffer[i].Event.KeyEvent.bKeyDown) ScanCode |= 0x80;
|
|
||||||
|
|
||||||
/* Push the scan code onto the keyboard queue */
|
|
||||||
for (j = 0; j < Buffer[i].Event.KeyEvent.wRepeatCount; j++)
|
|
||||||
{
|
{
|
||||||
KeyboardQueuePush(ScanCode);
|
DPRINT1("Error reading console input\n");
|
||||||
|
return GetLastError();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Interrupt = TRUE;
|
ASSERT(Count != 0);
|
||||||
|
|
||||||
|
/* Check the event type */
|
||||||
|
switch (InputRecord.EventType)
|
||||||
|
{
|
||||||
|
case KEY_EVENT:
|
||||||
|
{
|
||||||
|
BYTE ScanCode = (BYTE)InputRecord.Event.KeyEvent.wVirtualScanCode;
|
||||||
|
|
||||||
|
/* If this is a key release, set the highest bit in the scan code */
|
||||||
|
if (!InputRecord.Event.KeyEvent.bKeyDown) ScanCode |= 0x80;
|
||||||
|
|
||||||
|
/* Push the scan code onto the keyboard queue */
|
||||||
|
for (i = 0; i < InputRecord.Event.KeyEvent.wRepeatCount; i++)
|
||||||
|
{
|
||||||
|
KeyboardQueuePush(ScanCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Keyboard IRQ */
|
||||||
|
PicInterruptRequest(1);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MOUSE_EVENT:
|
||||||
|
{
|
||||||
|
// TODO: NOT IMPLEMENTED
|
||||||
|
UNIMPLEMENTED;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
/* Ignored */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Interrupt) PicInterruptRequest(1);
|
return 0;
|
||||||
|
|
||||||
Cleanup:
|
|
||||||
HeapFree(GetProcessHeap(), 0, Buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -28,7 +28,7 @@ BYTE KeyboardReadStatus();
|
||||||
VOID KeyboardWriteCommand(BYTE Command);
|
VOID KeyboardWriteCommand(BYTE Command);
|
||||||
BYTE KeyboardReadData();
|
BYTE KeyboardReadData();
|
||||||
VOID KeyboardWriteData(BYTE Data);
|
VOID KeyboardWriteData(BYTE Data);
|
||||||
VOID CheckForInputEvents();
|
DWORD WINAPI InputThreadProc(LPVOID Parameter);
|
||||||
|
|
||||||
#endif // _PS2_H_
|
#endif // _PS2_H_
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue