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/CMakeList... ============================================================================== --- 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?re... ============================================================================== --- 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?r... ============================================================================== --- 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);