Author: aandrejevic
Date: Thu Jun 20 19:00:07 2013
New Revision: 59268
URL:
http://svn.reactos.org/svn/reactos?rev=59268&view=rev
Log:
[NTVDM]
Implement 8259 Programmable Interrupt Controller emulation.
Added:
branches/ntvdm/subsystems/ntvdm/hardware.c (with props)
Modified:
branches/ntvdm/subsystems/ntvdm/CMakeLists.txt
branches/ntvdm/subsystems/ntvdm/bios.c
branches/ntvdm/subsystems/ntvdm/ntvdm.h
Modified: branches/ntvdm/subsystems/ntvdm/CMakeLists.txt
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/CMakeLis…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/CMakeLists.txt [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/CMakeLists.txt [iso-8859-1] Thu Jun 20 19:00:07 2013
@@ -5,6 +5,7 @@
bios.c
dos.c
emulator.c
+ hardware.c
ntvdm.c
ntvdm.rc)
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] Thu Jun 20 19:00:07 2013
@@ -55,6 +55,22 @@
CursorRow = ConsoleInfo.dwCursorPosition.Y;
ConsoleWidth = ConsoleInfo.dwSize.X;
ConsoleHeight = ConsoleInfo.dwSize.Y;
+
+ /* Initialize the PIC */
+ PicWriteCommand(PIC_MASTER_CMD, PIC_ICW1 | PIC_ICW1_ICW4);
+ PicWriteCommand(PIC_SLAVE_CMD, PIC_ICW1 | PIC_ICW1_ICW4);
+
+ /* Set the interrupt offsets */
+ PicWriteData(PIC_MASTER_DATA, BIOS_PIC_MASTER_INT);
+ PicWriteData(PIC_SLAVE_DATA, BIOS_PIC_SLAVE_INT);
+
+ /* Tell the master PIC there is a slave at IRQ 2 */
+ PicWriteData(PIC_MASTER_DATA, 1 << 2);
+ PicWriteData(PIC_SLAVE_DATA, 2);
+
+ /* Make sure the PIC is in 8086 mode */
+ PicWriteData(PIC_MASTER_DATA, PIC_ICW4_8086);
+ PicWriteData(PIC_SLAVE_DATA, PIC_ICW4_8086);
return TRUE;
}
Added: branches/ntvdm/subsystems/ntvdm/hardware.c
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/hardware…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/hardware.c (added)
+++ branches/ntvdm/subsystems/ntvdm/hardware.c [iso-8859-1] Thu Jun 20 19:00:07 2013
@@ -0,0 +1,202 @@
+/*
+ * COPYRIGHT: GPL - See COPYING in the top level directory
+ * PROJECT: ReactOS Virtual DOS Machine
+ * FILE: hardware.c
+ * PURPOSE: Minimal hardware emulation
+ * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include "ntvdm.h"
+
+typedef struct _PIC
+{
+ BOOLEAN Initialization;
+ BYTE MaskRegister;
+ BYTE InServiceRegister;
+ BYTE IntOffset;
+ BYTE ConfigRegister;
+ BYTE CascadeRegister;
+ BOOLEAN CascadeRegisterSet;
+ BOOLEAN AutoEoi;
+ BOOLEAN Slave;
+ BOOLEAN ReadIsr;
+} PIC, *PPIC;
+
+static PIC MasterPic, SlavePic;
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+
+BYTE PicReadCommand(BYTE Port)
+{
+ PPIC Pic;
+
+ /* Which PIC are we accessing? */
+ if (Port == PIC_MASTER_CMD) Pic = &MasterPic;
+ else Pic = &SlavePic;
+
+ if (Pic->ReadIsr)
+ {
+ /* Read the in-service register */
+ Pic->ReadIsr = FALSE;
+ return Pic->InServiceRegister;
+ }
+ else
+ {
+ /* The IRR is always 0, as the emulated CPU receives the interrupt instantly */
+ return 0;
+ }
+}
+
+VOID PicWriteCommand(BYTE Port, BYTE Value)
+{
+ PPIC Pic;
+
+ /* Which PIC are we accessing? */
+ if (Port == PIC_MASTER_CMD) Pic = &MasterPic;
+ else Pic = &SlavePic;
+
+ if (Value & PIC_ICW1)
+ {
+ /* Start initialization */
+ Pic->Initialization = TRUE;
+ Pic->IntOffset = 0xFF;
+ Pic->CascadeRegisterSet = FALSE;
+ Pic->ConfigRegister = Value;
+ return;
+ }
+
+ if (Value & PIC_OCW3)
+ {
+ /* This is an OCR3 */
+ if (Value == PIC_OCW3_READ_ISR)
+ {
+ /* Return the ISR on next read from command port */
+ Pic->ReadIsr = TRUE;
+ }
+
+ return;
+ }
+
+ /* This is an OCW2 */
+ if (Value & PIC_OCW2_EOI)
+ {
+ if (Value & PIC_OCW2_SL)
+ {
+ /* If the SL bit is set, clear a specific IRQ */
+ Pic->InServiceRegister &= ~(1 << (Value &
PIC_OCW2_NUM_MASK));
+ }
+ else
+ {
+ /* Otherwise, clear all of them */
+ Pic->InServiceRegister = 0;
+ }
+ }
+}
+
+BYTE PicReadData(BYTE Port)
+{
+ /* Read the mask register */
+ if (Port == PIC_MASTER_DATA) return MasterPic.MaskRegister;
+ else return SlavePic.MaskRegister;
+}
+
+VOID PicWriteData(BYTE Port, BYTE Value)
+{
+ PPIC Pic;
+
+ /* Which PIC are we accessing? */
+ if (Port == PIC_MASTER_DATA) Pic = &MasterPic;
+ else Pic = &SlavePic;
+
+ /* Is the PIC ready? */
+ if (!Pic->Initialization)
+ {
+ /* Yes, this is an OCW1 */
+ Pic->MaskRegister = Value;
+ return;
+ }
+
+ /* Has the interrupt offset been set? */
+ if (Pic->IntOffset == 0xFF)
+ {
+ /* This is an ICW2, set the offset (last three bits always zero) */
+ Pic->IntOffset = Value & 0xF8;
+
+ /* Check if we are in single mode and don't need an ICW4 */
+ if ((Pic->ConfigRegister & PIC_ICW1_SINGLE)
+ && !(Pic->ConfigRegister & PIC_ICW1_ICW4))
+ {
+ /* Yes, done initializing */
+ Pic->Initialization = FALSE;
+ }
+ return;
+ }
+
+ /* Check if we are in cascade mode and the cascade register was not set */
+ if (!(Pic->ConfigRegister & PIC_ICW1_SINGLE) &&
!Pic->CascadeRegisterSet)
+ {
+ /* This is an ICW3 */
+ Pic->CascadeRegister = Value;
+ Pic->CascadeRegisterSet = TRUE;
+
+ /* Check if we need an ICW4 */
+ if (!(Pic->ConfigRegister & PIC_ICW1_ICW4))
+ {
+ /* No, done initializing */
+ Pic->Initialization = FALSE;
+ }
+ return;
+ }
+
+ /* This must be an ICW4, we will ignore the 8086 bit (assume always set) */
+ if (Value & PIC_ICW4_AEOI)
+ {
+ /* Use automatic end-of-interrupt */
+ Pic->AutoEoi = TRUE;
+ }
+
+ /* Done initializing */
+ Pic->Initialization = FALSE;
+}
+
+VOID PicInterruptRequest(BYTE Number)
+{
+ if (Number >= 0 && Number < 8)
+ {
+ /* Check if the interrupt is busy or in a cascade */
+ if (MasterPic.CascadeRegister & (1 << Number)
+ || MasterPic.InServiceRegister & (1 << Number))
+ {
+ return;
+ }
+
+ MasterPic.InServiceRegister |= 1 << Number;
+ EmulatorInterrupt(MasterPic.IntOffset + Number);
+ }
+ else if (Number >= 8 && Number < 16)
+ {
+ Number -= 8;
+
+ /*
+ * The slave PIC is connected to IRQ 2, always! If the master PIC
+ * was misconfigured, don't do anything.
+ */
+ if (!(MasterPic.CascadeRegister & (1 << 2))
+ || SlavePic.CascadeRegister != 2)
+ {
+ return;
+ }
+
+ /* Check if the interrupt is busy or in a cascade */
+ if (SlavePic.CascadeRegister & (1 << Number)
+ || SlavePic.InServiceRegister & (1 << Number))
+ {
+ return;
+ }
+
+ SlavePic.InServiceRegister |= 1 << Number;
+ EmulatorInterrupt(SlavePic.IntOffset + Number);
+ }
+}
Propchange: branches/ntvdm/subsystems/ntvdm/hardware.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: branches/ntvdm/subsystems/ntvdm/ntvdm.h
URL:
http://svn.reactos.org/svn/reactos/branches/ntvdm/subsystems/ntvdm/ntvdm.h?…
==============================================================================
--- branches/ntvdm/subsystems/ntvdm/ntvdm.h [iso-8859-1] (original)
+++ branches/ntvdm/subsystems/ntvdm/ntvdm.h [iso-8859-1] Thu Jun 20 19:00:07 2013
@@ -23,6 +23,8 @@
#define MAX_ADDRESS TO_LINEAR(MAX_SEGMENT, MAX_OFFSET)
#define ROM_AREA_START 0xC0000
#define ROM_AREA_END 0xFFFFF
+#define BIOS_PIC_MASTER_INT 0x08
+#define BIOS_PIC_SLAVE_INT 0x70
#define BIOS_SEGMENT 0xF000
#define VIDEO_BIOS_INTERRUPT 0x10
#define SPECIAL_INT_NUM 0xFF
@@ -42,6 +44,28 @@
#define CONSOLE_FONT_HEIGHT 8
#define CONSOLE_VIDEO_MEM_START 0xB8000
#define CONSOLE_VIDEO_MEM_END 0xBFFFF
+
+/* Programmable interval timer (PIT) */
+#define PIT_CHANNELS 3
+#define PIT_BASE_FREQUENCY 1193182LL
+#define PIT_DATA_PORT(x) (0x40 + (x))
+#define PIT_COMMAND_PORT 0x43
+
+/* Programmable interrupt controller (PIC) */
+#define PIC_MASTER_CMD 0x20
+#define PIC_MASTER_DATA 0x21
+#define PIC_SLAVE_CMD 0xA0
+#define PIC_SLAVE_DATA 0xA1
+#define PIC_ICW1 0x10
+#define PIC_ICW1_ICW4 (1 << 0)
+#define PIC_ICW1_SINGLE (1 << 1)
+#define PIC_ICW4_8086 (1 << 0)
+#define PIC_ICW4_AEOI (1 << 1)
+#define PIC_OCW2_NUM_MASK 0x07
+#define PIC_OCW2_EOI (1 << 5)
+#define PIC_OCW2_SL (1 << 6)
+#define PIC_OCW3 (1 << 3)
+#define PIC_OCW3_READ_ISR 0x0B
#define EMULATOR_FLAG_CF (1 << 0)
#define EMULATOR_FLAG_PF (1 << 2)
@@ -184,6 +208,11 @@
VOID DosInt21h(WORD CodeSegment);
VOID DosBreakInterrupt();
VOID BiosVideoService();
+BYTE PicReadCommand(BYTE Port);
+VOID PicWriteCommand(BYTE Port, BYTE Value);
+BYTE PicReadData(BYTE Port);
+VOID PicWriteData(BYTE Port, BYTE Value);
+VOID PicInterruptRequest(BYTE Number);
VOID EmulatorSetStack(WORD Segment, WORD Offset);
VOID EmulatorExecute(WORD Segment, WORD Offset);
VOID EmulatorInterrupt(BYTE Number);