mirror of
https://github.com/reactos/reactos.git
synced 2024-08-04 10:30:59 +00:00
[NTVDM]
Implement 8259 Programmable Interrupt Controller emulation. svn path=/branches/ntvdm/; revision=59268
This commit is contained in:
parent
c1bb00076e
commit
b44c5d3a6f
|
@ -5,6 +5,7 @@ list(APPEND SOURCE
|
|||
bios.c
|
||||
dos.c
|
||||
emulator.c
|
||||
hardware.c
|
||||
ntvdm.c
|
||||
ntvdm.rc)
|
||||
|
||||
|
|
|
@ -55,6 +55,22 @@ BOOLEAN BiosInitialize()
|
|||
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;
|
||||
}
|
||||
|
|
202
subsystems/ntvdm/hardware.c
Normal file
202
subsystems/ntvdm/hardware.c
Normal file
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
@ -43,6 +45,28 @@
|
|||
#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)
|
||||
#define EMULATOR_FLAG_AF (1 << 4)
|
||||
|
@ -184,6 +208,11 @@ VOID DosInt20h(WORD CodeSegment);
|
|||
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);
|
||||
|
|
Loading…
Reference in a new issue