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/fast…
==============================================================================
--- 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?r…
==============================================================================
--- 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?…
==============================================================================
--- 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?re…
==============================================================================
--- 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?re…
==============================================================================
--- 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?re…
==============================================================================
--- 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?re…
==============================================================================
--- 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_