51d2febbb735b519354614ec964e49aae735c184
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 *******************************************************************/
16 /* PRIVATE VARIABLES **********************************************************/
18 static PIC MasterPic
, SlavePic
;
20 /* PUBLIC FUNCTIONS ***********************************************************/
22 BYTE
PicReadCommand(BYTE Port
)
26 /* Which PIC are we accessing? */
27 if (Port
== PIC_MASTER_CMD
) Pic
= &MasterPic
;
32 /* Read the in-service register */
34 return Pic
->InServiceRegister
;
38 /* The IRR is always 0, as the emulated CPU receives the interrupt instantly */
43 VOID
PicWriteCommand(BYTE Port
, BYTE Value
)
47 /* Which PIC are we accessing? */
48 if (Port
== PIC_MASTER_CMD
) Pic
= &MasterPic
;
53 /* Start initialization */
54 Pic
->Initialization
= TRUE
;
55 Pic
->IntOffset
= 0xFF;
56 Pic
->CascadeRegisterSet
= FALSE
;
57 Pic
->ConfigRegister
= Value
;
64 if (Value
== PIC_OCW3_READ_ISR
)
66 /* Return the ISR on next read from command port */
74 if (Value
& PIC_OCW2_EOI
)
76 if (Value
& PIC_OCW2_SL
)
78 /* If the SL bit is set, clear a specific IRQ */
79 Pic
->InServiceRegister
&= ~(1 << (Value
& PIC_OCW2_NUM_MASK
));
83 /* Otherwise, clear all of them */
84 Pic
->InServiceRegister
= 0;
89 BYTE
PicReadData(BYTE Port
)
91 /* Read the mask register */
92 if (Port
== PIC_MASTER_DATA
) return MasterPic
.MaskRegister
;
93 else return SlavePic
.MaskRegister
;
96 VOID
PicWriteData(BYTE Port
, BYTE Value
)
100 /* Which PIC are we accessing? */
101 if (Port
== PIC_MASTER_DATA
) Pic
= &MasterPic
;
102 else Pic
= &SlavePic
;
104 /* Is the PIC ready? */
105 if (!Pic
->Initialization
)
107 /* Yes, this is an OCW1 */
108 Pic
->MaskRegister
= Value
;
112 /* Has the interrupt offset been set? */
113 if (Pic
->IntOffset
== 0xFF)
115 /* This is an ICW2, set the offset (last three bits always zero) */
116 Pic
->IntOffset
= Value
& 0xF8;
118 /* Check if we are in single mode and don't need an ICW4 */
119 if ((Pic
->ConfigRegister
& PIC_ICW1_SINGLE
)
120 && !(Pic
->ConfigRegister
& PIC_ICW1_ICW4
))
122 /* Yes, done initializing */
123 Pic
->Initialization
= FALSE
;
128 /* Check if we are in cascade mode and the cascade register was not set */
129 if (!(Pic
->ConfigRegister
& PIC_ICW1_SINGLE
) && !Pic
->CascadeRegisterSet
)
131 /* This is an ICW3 */
132 Pic
->CascadeRegister
= Value
;
133 Pic
->CascadeRegisterSet
= TRUE
;
135 /* Check if we need an ICW4 */
136 if (!(Pic
->ConfigRegister
& PIC_ICW1_ICW4
))
138 /* No, done initializing */
139 Pic
->Initialization
= FALSE
;
144 /* This must be an ICW4, we will ignore the 8086 bit (assume always set) */
145 if (Value
& PIC_ICW4_AEOI
)
147 /* Use automatic end-of-interrupt */
151 /* Done initializing */
152 Pic
->Initialization
= FALSE
;
155 VOID
PicInterruptRequest(BYTE Number
)
159 if (Number
>= 0 && Number
< 8)
161 /* Check if any of the higher-priorirty interrupts are busy */
162 for (i
= 0; i
<= Number
; i
++)
164 if (MasterPic
.InServiceRegister
& (1 << Number
)) return;
167 /* Check if the interrupt is masked */
168 if (MasterPic
.MaskRegister
& (1 << Number
)) return;
170 /* Set the appropriate bit in the ISR and interrupt the CPU */
171 if (!MasterPic
.AutoEoi
) MasterPic
.InServiceRegister
|= 1 << Number
;
172 EmulatorExternalInterrupt(MasterPic
.IntOffset
+ Number
);
174 else if (Number
>= 8 && Number
< 16)
179 * The slave PIC is connected to IRQ 2, always! If the master PIC
180 * was misconfigured, don't do anything.
182 if (!(MasterPic
.CascadeRegister
& (1 << 2))
183 || SlavePic
.CascadeRegister
!= 2)
188 /* Check if any of the higher-priorirty interrupts are busy */
189 if (MasterPic
.InServiceRegister
!= 0) return;
190 for (i
= 0; i
<= Number
; i
++)
192 if (SlavePic
.InServiceRegister
& (1 << Number
)) return;
195 /* Check if the interrupt is masked */
196 if (SlavePic
.MaskRegister
& (1 << Number
)) return;
198 /* Set the IRQ 2 bit in the master ISR */
199 if (!MasterPic
.AutoEoi
) MasterPic
.InServiceRegister
|= 1 << 2;
201 /* Set the appropriate bit in the ISR and interrupt the CPU */
202 if (!SlavePic
.AutoEoi
) SlavePic
.InServiceRegister
|= 1 << Number
;
203 EmulatorExternalInterrupt(SlavePic
.IntOffset
+ Number
);