Author: aandrejevic Date: Sun Oct 27 00:37:01 2013 New Revision: 60761
URL: http://svn.reactos.org/svn/reactos?rev=60761&view=rev Log: [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.
Modified: branches/ntvdm/include/reactos/libs/fast486/fast486.h branches/ntvdm/lib/fast486/fast486.c branches/ntvdm/lib/fast486/opcodes.c branches/ntvdm/subsystems/ntvdm/bios.c branches/ntvdm/subsystems/ntvdm/emulator.c branches/ntvdm/subsystems/ntvdm/emulator.h branches/ntvdm/subsystems/ntvdm/ntvdm.c branches/ntvdm/subsystems/ntvdm/pic.c branches/ntvdm/subsystems/ntvdm/pic.h branches/ntvdm/subsystems/ntvdm/ps2.c branches/ntvdm/subsystems/ntvdm/ps2.h
Modified: branches/ntvdm/include/reactos/libs/fast486/fast486.h URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/include/reactos/libs/fast4... ============================================================================== --- branches/ntvdm/include/reactos/libs/fast486/fast486.h [iso-8859-1] (original) +++ branches/ntvdm/include/reactos/libs/fast486/fast486.h [iso-8859-1] Sun Oct 27 00:37:01 2013 @@ -145,6 +145,13 @@ FAST486_EXCEPTION_MC = 0x12 } 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 BOOLEAN (NTAPI *FAST486_MEM_READ_PROC) @@ -198,6 +205,13 @@ ( PFAST486_STATE State, USHORT BopCode +); + +typedef +UCHAR +(NTAPI *FAST486_INT_ACK_PROC) +( + PFAST486_STATE State );
typedef union _FAST486_REG @@ -352,6 +366,7 @@ FAST486_IO_WRITE_PROC IoWriteCallback; FAST486_IDLE_PROC IdleCallback; FAST486_BOP_PROC BopCallback; + FAST486_INT_ACK_PROC IntAckCallback; FAST486_REG GeneralRegs[FAST486_NUM_GEN_REGS]; FAST486_SEG_REG SegmentRegs[FAST486_NUM_SEG_REGS]; FAST486_REG InstPtr, SavedInstPtr; @@ -362,7 +377,7 @@ ULONG ExceptionCount; ULONG PrefixFlags; FAST486_SEG_REGS SegmentOverride; - BOOLEAN HardwareInt; + FAST486_INT_STATUS IntStatus; UCHAR PendingIntNum; };
@@ -398,6 +413,10 @@
VOID NTAPI +Fast486InterruptSignal(PFAST486_STATE State); + +VOID +NTAPI Fast486ExecuteAt(PFAST486_STATE State, USHORT Segment, ULONG Offset);
VOID
Modified: branches/ntvdm/lib/fast486/fast486.c URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/lib/fast486/fast486.c?rev=... ============================================================================== --- branches/ntvdm/lib/fast486/fast486.c [iso-8859-1] (original) +++ branches/ntvdm/lib/fast486/fast486.c [iso-8859-1] Sun Oct 27 00:37:01 2013 @@ -61,10 +61,22 @@ { 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; + + if (State->IntStatus == FAST486_INT_SIGNAL) + { + /* Acknowledge the interrupt to get the number */ + State->PendingIntNum = State->IntAckCallback(State); + }
/* Get the interrupt vector */ if (Fast486GetIntVector(State, State->PendingIntNum, &IdtEntry)) @@ -76,8 +88,8 @@ IdtEntry.Type); }
- /* Clear the interrupt pending flag */ - State->HardwareInt = FALSE; + /* Clear the interrupt status */ + State->IntStatus = FAST486_INT_NONE; } }
@@ -243,6 +255,7 @@ FAST486_IO_WRITE_PROC IoWriteCallback = State->IoWriteCallback; FAST486_IDLE_PROC IdleCallback = State->IdleCallback; FAST486_BOP_PROC BopCallback = State->BopCallback; + FAST486_INT_ACK_PROC IntAckCallback = State->IntAckCallback;
/* Clear the entire structure */ RtlZeroMemory(State, sizeof(*State)); @@ -278,15 +291,24 @@ State->IoWriteCallback = IoWriteCallback; State->IdleCallback = IdleCallback; State->BopCallback = BopCallback; + State->IntAckCallback = IntAckCallback; }
VOID NTAPI Fast486Interrupt(PFAST486_STATE State, UCHAR Number) { - /* Set the hardware interrupt flag */ - State->HardwareInt = TRUE; + /* Set the interrupt status and the number */ + State->IntStatus = FAST486_INT_EXECUTE; State->PendingIntNum = Number; +} + +VOID +NTAPI +Fast486InterruptSignal(PFAST486_STATE State) +{ + /* Set the interrupt status */ + State->IntStatus = FAST486_INT_SIGNAL; }
VOID
Modified: branches/ntvdm/lib/fast486/opcodes.c URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/lib/fast486/opcodes.c?rev=... ============================================================================== --- branches/ntvdm/lib/fast486/opcodes.c [iso-8859-1] (original) +++ branches/ntvdm/lib/fast486/opcodes.c [iso-8859-1] Sun Oct 27 00:37:01 2013 @@ -876,7 +876,7 @@ }
/* Halt */ - while (!State->HardwareInt) State->IdleCallback(State); + while (State->IntStatus != FAST486_INT_SIGNAL) State->IdleCallback(State);
/* Return success */ return TRUE;
Modified: branches/ntvdm/subsystems/ntvdm/bios.c URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/bios.c?re... ============================================================================== --- branches/ntvdm/subsystems/ntvdm/bios.c [iso-8859-1] (original) +++ branches/ntvdm/subsystems/ntvdm/bios.c [iso-8859-1] Sun Oct 27 00:37:01 2013 @@ -1092,39 +1092,40 @@ BYTE ScanCode, VirtualKey; WORD Character;
- /* Check if there is a scancode available */ - if (!(KeyboardReadStatus() & 1)) break; - - /* 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))) + /* Loop while there is a scancode available */ + while (KeyboardReadStatus() & 1) { - /* Key press */ - if (VirtualKey == VK_NUMLOCK - || VirtualKey == VK_CAPITAL - || VirtualKey == VK_SCROLL) + /* 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))) { - /* For toggle keys, toggle the lowest bit in the keyboard map */ - BiosKeyboardMap[VirtualKey] ^= ~(1 << 0); + /* Key press */ + 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)); + } } - - /* Set the highest bit */ - BiosKeyboardMap[VirtualKey] |= (1 << 7); - - /* Find out which character this is */ - if (ToAscii(VirtualKey, ScanCode, BiosKeyboardMap, &Character, 0) > 0) + else { - /* Push it onto the BIOS keyboard queue */ - BiosKbdBufferPush((ScanCode << 8) | (Character & 0xFF)); + /* Key release, unset the highest bit */ + BiosKeyboardMap[VirtualKey] &= ~(1 << 7); } - } - else - { - /* Key release, unset the highest bit */ - BiosKeyboardMap[VirtualKey] &= ~(1 << 7); }
break;
Modified: branches/ntvdm/subsystems/ntvdm/emulator.c URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/emulator.... ============================================================================== --- branches/ntvdm/subsystems/ntvdm/emulator.c [iso-8859-1] (original) +++ branches/ntvdm/subsystems/ntvdm/emulator.c [iso-8859-1] Sun Oct 27 00:37:01 2013 @@ -329,6 +329,14 @@ } }
+static BYTE WINAPI EmulatorIntAcknowledge(PFAST486_STATE State) +{ + UNREFERENCED_PARAMETER(State); + + /* Get the interrupt number from the PIC */ + return PicGetInterrupt(); +} + /* PUBLIC FUNCTIONS ***********************************************************/
BOOLEAN EmulatorInitialize() @@ -342,7 +350,8 @@ EmulatorContext.MemWriteCallback = (FAST486_MEM_WRITE_PROC)EmulatorWriteMemory; EmulatorContext.IoReadCallback = (FAST486_IO_READ_PROC)EmulatorReadIo; EmulatorContext.IoWriteCallback = (FAST486_IO_WRITE_PROC)EmulatorWriteIo; - EmulatorContext.BopCallback = (FAST486_BOP_PROC)EmulatorBiosOperation; + EmulatorContext.BopCallback = EmulatorBiosOperation; + EmulatorContext.IntAckCallback = EmulatorIntAcknowledge;
/* Reset the CPU */ Fast486Reset(&EmulatorContext); @@ -371,10 +380,10 @@ Fast486Interrupt(&EmulatorContext, Number); }
-VOID EmulatorExternalInterrupt(BYTE Number) +VOID EmulatorInterruptSignal(VOID) { /* Call the Fast486 API */ - Fast486Interrupt(&EmulatorContext, Number); + Fast486InterruptSignal(&EmulatorContext); }
ULONG EmulatorGetRegister(ULONG Register)
Modified: branches/ntvdm/subsystems/ntvdm/emulator.h URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/emulator.... ============================================================================== --- branches/ntvdm/subsystems/ntvdm/emulator.h [iso-8859-1] (original) +++ branches/ntvdm/subsystems/ntvdm/emulator.h [iso-8859-1] Sun Oct 27 00:37:01 2013 @@ -88,7 +88,7 @@ VOID EmulatorSetStack(WORD Segment, DWORD Offset); VOID EmulatorExecute(WORD Segment, WORD Offset); VOID EmulatorInterrupt(BYTE Number); -VOID EmulatorExternalInterrupt(BYTE Number); +VOID EmulatorInterruptSignal(VOID); ULONG EmulatorGetRegister(ULONG Register); ULONG EmulatorGetProgramCounter(VOID); VOID EmulatorSetRegister(ULONG Register, ULONG Value);
Modified: branches/ntvdm/subsystems/ntvdm/ntvdm.c URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/ntvdm.c?r... ============================================================================== --- branches/ntvdm/subsystems/ntvdm/ntvdm.c [iso-8859-1] (original) +++ branches/ntvdm/subsystems/ntvdm/ntvdm.c [iso-8859-1] Sun Oct 27 00:37:01 2013 @@ -79,12 +79,12 @@ INT i; CHAR CommandLine[DOS_CMDLINE_LENGTH]; DWORD CurrentTickCount; - DWORD LastTickCount = GetTickCount(); DWORD Cycles = 0; DWORD LastCyclePrintout = GetTickCount(); DWORD LastVerticalRefresh = GetTickCount(); LARGE_INTEGER Frequency, LastTimerTick, Counter; LONGLONG TimerTicks; + HANDLE InputThread = NULL;
/* Set the handler routine */ SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE); @@ -141,6 +141,9 @@ DisplayMessage(L"Could not start program: %S", CommandLine); return -1; } + + /* Start the input thread */ + InputThread = CreateThread(NULL, 0, &InputThreadProc, NULL, 0, NULL);
/* Set the last timer tick to the current time */ QueryPerformanceCounter(&LastTimerTick); @@ -162,13 +165,6 @@ for (i = 0; i < TimerTicks; i++) PitDecrementCount(); LastTimerTick = Counter;
- /* Check for console input events every millisecond */ - if (CurrentTickCount != LastTickCount) - { - CheckForInputEvents(); - LastTickCount = CurrentTickCount; - } - /* Check for vertical retrace */ if ((CurrentTickCount - LastVerticalRefresh) >= 16) { @@ -198,6 +194,7 @@ VgaRefreshDisplay();
Cleanup: + if (InputThread != NULL) CloseHandle(InputThread); BiosCleanup(); EmulatorCleanup();
Modified: branches/ntvdm/subsystems/ntvdm/pic.c URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/pic.c?rev... ============================================================================== --- branches/ntvdm/subsystems/ntvdm/pic.c [iso-8859-1] (original) +++ branches/ntvdm/subsystems/ntvdm/pic.c [iso-8859-1] Sun Oct 27 00:37:01 2013 @@ -35,8 +35,8 @@ } else { - /* The IRR is always 0, as the emulated CPU receives the interrupt instantly */ - return 0; + /* Read the interrupt request register */ + return Pic->IntRequestRegister; } }
@@ -167,9 +167,9 @@ /* Check if the interrupt is masked */ if (MasterPic.MaskRegister & (1 << Number)) return;
- /* Set the appropriate bit in the ISR and interrupt the CPU */ - if (!MasterPic.AutoEoi) MasterPic.InServiceRegister |= 1 << Number; - EmulatorExternalInterrupt(MasterPic.IntOffset + Number); + /* Set the appropriate bit in the IRR and interrupt the CPU */ + MasterPic.IntRequestRegister |= 1 << Number; + EmulatorInterruptSignal(); } else if (Number >= 8 && Number < 16) { @@ -187,7 +187,7 @@
/* Check if any of the higher-priorirty interrupts are busy */ if (MasterPic.InServiceRegister != 0) return; - for (i = 0; i <= Number ; i++) + for (i = 0; i <= Number; i++) { if (SlavePic.InServiceRegister & (1 << Number)) return; } @@ -196,12 +196,57 @@ if (SlavePic.MaskRegister & (1 << Number)) return;
/* Set the IRQ 2 bit in the master ISR */ - if (!MasterPic.AutoEoi) MasterPic.InServiceRegister |= 1 << 2; - - /* Set the appropriate bit in the ISR and interrupt the CPU */ - if (!SlavePic.AutoEoi) SlavePic.InServiceRegister |= 1 << Number; - EmulatorExternalInterrupt(SlavePic.IntOffset + Number); - } + if (!MasterPic.AutoEoi) MasterPic.InServiceRegister |= (1 << 2); + + /* Set the appropriate bit in the IRR and interrupt the CPU */ + SlavePic.IntRequestRegister |= 1 << 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 */
Modified: branches/ntvdm/subsystems/ntvdm/pic.h URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/pic.h?rev... ============================================================================== --- branches/ntvdm/subsystems/ntvdm/pic.h [iso-8859-1] (original) +++ branches/ntvdm/subsystems/ntvdm/pic.h [iso-8859-1] Sun Oct 27 00:37:01 2013 @@ -34,6 +34,7 @@ { BOOLEAN Initialization; BYTE MaskRegister; + BYTE IntRequestRegister; BYTE InServiceRegister; BYTE IntOffset; BYTE ConfigRegister; @@ -51,6 +52,7 @@ BYTE PicReadData(BYTE Port); VOID PicWriteData(BYTE Port, BYTE Value); VOID PicInterruptRequest(BYTE Number); +BYTE PicGetInterrupt(VOID);
#endif // _PIC_H_
Modified: branches/ntvdm/subsystems/ntvdm/ps2.c URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/ps2.c?rev... ============================================================================== --- branches/ntvdm/subsystems/ntvdm/ps2.c [iso-8859-1] (original) +++ branches/ntvdm/subsystems/ntvdm/ps2.c [iso-8859-1] Sun Oct 27 00:37:01 2013 @@ -265,49 +265,64 @@ // TODO: Implement PS/2 device commands }
-VOID CheckForInputEvents() -{ - PINPUT_RECORD Buffer; +DWORD WINAPI InputThreadProc(LPVOID Parameter) +{ + INT i; HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE); - DWORD i, j, Count, TotalEvents; - BYTE ScanCode; - BOOLEAN Interrupt = FALSE; - - /* Get the number of input events */ - 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 */ - if (Buffer[i].EventType != KEY_EVENT) continue; - - /* 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); - } - - Interrupt = TRUE; - } - - if (Interrupt) PicInterruptRequest(1); - -Cleanup: - HeapFree(GetProcessHeap(), 0, Buffer); + INPUT_RECORD InputRecord; + DWORD Count; + + while (VdmRunning) + { + /* Wait for an input record */ + if (!ReadConsoleInput(ConsoleInput, &InputRecord, 1, &Count)) + { + DPRINT1("Error reading console input\n"); + return GetLastError(); + + } + + 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; + } + } + } + + return 0; }
/* EOF */
Modified: branches/ntvdm/subsystems/ntvdm/ps2.h URL: http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/ps2.h?rev... ============================================================================== --- branches/ntvdm/subsystems/ntvdm/ps2.h [iso-8859-1] (original) +++ branches/ntvdm/subsystems/ntvdm/ps2.h [iso-8859-1] Sun Oct 27 00:37:01 2013 @@ -28,7 +28,7 @@ VOID KeyboardWriteCommand(BYTE Command); BYTE KeyboardReadData(); VOID KeyboardWriteData(BYTE Data); -VOID CheckForInputEvents(); +DWORD WINAPI InputThreadProc(LPVOID Parameter);
#endif // _PS2_H_