2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: Programmable Interrupt Controller emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
14 /* PRIVATE VARIABLES **********************************************************/
16 static PIC MasterPic
, SlavePic
;
18 /* PUBLIC FUNCTIONS ***********************************************************/
20 BYTE
PicReadCommand(BYTE Port
)
24 /* Which PIC are we accessing? */
25 if (Port
== PIC_MASTER_CMD
) Pic
= &MasterPic
;
30 /* Read the in-service register */
32 return Pic
->InServiceRegister
;
36 /* The IRR is always 0, as the emulated CPU receives the interrupt instantly */
41 VOID
PicWriteCommand(BYTE Port
, BYTE Value
)
45 /* Which PIC are we accessing? */
46 if (Port
== PIC_MASTER_CMD
) Pic
= &MasterPic
;
51 /* Start initialization */
52 Pic
->Initialization
= TRUE
;
53 Pic
->IntOffset
= 0xFF;
54 Pic
->CascadeRegisterSet
= FALSE
;
55 Pic
->ConfigRegister
= Value
;
62 if (Value
== PIC_OCW3_READ_ISR
)
64 /* Return the ISR on next read from command port */
72 if (Value
& PIC_OCW2_EOI
)
74 if (Value
& PIC_OCW2_SL
)
76 /* If the SL bit is set, clear a specific IRQ */
77 Pic
->InServiceRegister
&= ~(1 << (Value
& PIC_OCW2_NUM_MASK
));
81 /* Otherwise, clear all of them */
82 Pic
->InServiceRegister
= 0;
87 BYTE
PicReadData(BYTE Port
)
89 /* Read the mask register */
90 if (Port
== PIC_MASTER_DATA
) return MasterPic
.MaskRegister
;
91 else return SlavePic
.MaskRegister
;
94 VOID
PicWriteData(BYTE Port
, BYTE Value
)
98 /* Which PIC are we accessing? */
99 if (Port
== PIC_MASTER_DATA
) Pic
= &MasterPic
;
100 else Pic
= &SlavePic
;
102 /* Is the PIC ready? */
103 if (!Pic
->Initialization
)
105 /* Yes, this is an OCW1 */
106 Pic
->MaskRegister
= Value
;
110 /* Has the interrupt offset been set? */
111 if (Pic
->IntOffset
== 0xFF)
113 /* This is an ICW2, set the offset (last three bits always zero) */
114 Pic
->IntOffset
= Value
& 0xF8;
116 /* Check if we are in single mode and don't need an ICW4 */
117 if ((Pic
->ConfigRegister
& PIC_ICW1_SINGLE
)
118 && !(Pic
->ConfigRegister
& PIC_ICW1_ICW4
))
120 /* Yes, done initializing */
121 Pic
->Initialization
= FALSE
;
126 /* Check if we are in cascade mode and the cascade register was not set */
127 if (!(Pic
->ConfigRegister
& PIC_ICW1_SINGLE
) && !Pic
->CascadeRegisterSet
)
129 /* This is an ICW3 */
130 Pic
->CascadeRegister
= Value
;
131 Pic
->CascadeRegisterSet
= TRUE
;
133 /* Check if we need an ICW4 */
134 if (!(Pic
->ConfigRegister
& PIC_ICW1_ICW4
))
136 /* No, done initializing */
137 Pic
->Initialization
= FALSE
;
142 /* This must be an ICW4, we will ignore the 8086 bit (assume always set) */
143 if (Value
& PIC_ICW4_AEOI
)
145 /* Use automatic end-of-interrupt */
149 /* Done initializing */
150 Pic
->Initialization
= FALSE
;
153 VOID
PicInterruptRequest(BYTE Number
)
157 if (Number
>= 0 && Number
< 8)
159 /* Check if any of the higher-priorirty interrupts are busy */
160 for (i
= 0; i
<= Number
; i
++)
162 if (MasterPic
.InServiceRegister
& (1 << Number
)) return;
165 /* Check if the interrupt is masked */
166 if (MasterPic
.MaskRegister
& (1 << Number
)) return;
168 /* Set the appropriate bit in the ISR and interrupt the CPU */
169 if (!MasterPic
.AutoEoi
) MasterPic
.InServiceRegister
|= 1 << Number
;
170 EmulatorExternalInterrupt(MasterPic
.IntOffset
+ Number
);
172 else if (Number
>= 8 && Number
< 16)
177 * The slave PIC is connected to IRQ 2, always! If the master PIC
178 * was misconfigured, don't do anything.
180 if (!(MasterPic
.CascadeRegister
& (1 << 2))
181 || SlavePic
.CascadeRegister
!= 2)
186 /* Check if any of the higher-priorirty interrupts are busy */
187 if (MasterPic
.InServiceRegister
!= 0) return;
188 for (i
= 0; i
<= Number
; i
++)
190 if (SlavePic
.InServiceRegister
& (1 << Number
)) return;
193 /* Check if the interrupt is masked */
194 if (SlavePic
.MaskRegister
& (1 << Number
)) return;
196 /* Set the IRQ 2 bit in the master ISR */
197 if (!MasterPic
.AutoEoi
) MasterPic
.InServiceRegister
|= 1 << 2;
199 /* Set the appropriate bit in the ISR and interrupt the CPU */
200 if (!SlavePic
.AutoEoi
) SlavePic
.InServiceRegister
|= 1 << Number
;
201 EmulatorExternalInterrupt(SlavePic
.IntOffset
+ Number
);