2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: Minimal hardware emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
15 BOOLEAN Initialization
;
17 BYTE InServiceRegister
;
21 BOOLEAN CascadeRegisterSet
;
27 static PIC MasterPic
, SlavePic
;
29 /* PUBLIC FUNCTIONS ***********************************************************/
31 BYTE
PicReadCommand(BYTE Port
)
35 /* Which PIC are we accessing? */
36 if (Port
== PIC_MASTER_CMD
) Pic
= &MasterPic
;
41 /* Read the in-service register */
43 return Pic
->InServiceRegister
;
47 /* The IRR is always 0, as the emulated CPU receives the interrupt instantly */
52 VOID
PicWriteCommand(BYTE Port
, BYTE Value
)
56 /* Which PIC are we accessing? */
57 if (Port
== PIC_MASTER_CMD
) Pic
= &MasterPic
;
62 /* Start initialization */
63 Pic
->Initialization
= TRUE
;
64 Pic
->IntOffset
= 0xFF;
65 Pic
->CascadeRegisterSet
= FALSE
;
66 Pic
->ConfigRegister
= Value
;
73 if (Value
== PIC_OCW3_READ_ISR
)
75 /* Return the ISR on next read from command port */
83 if (Value
& PIC_OCW2_EOI
)
85 if (Value
& PIC_OCW2_SL
)
87 /* If the SL bit is set, clear a specific IRQ */
88 Pic
->InServiceRegister
&= ~(1 << (Value
& PIC_OCW2_NUM_MASK
));
92 /* Otherwise, clear all of them */
93 Pic
->InServiceRegister
= 0;
98 BYTE
PicReadData(BYTE Port
)
100 /* Read the mask register */
101 if (Port
== PIC_MASTER_DATA
) return MasterPic
.MaskRegister
;
102 else return SlavePic
.MaskRegister
;
105 VOID
PicWriteData(BYTE Port
, BYTE Value
)
109 /* Which PIC are we accessing? */
110 if (Port
== PIC_MASTER_DATA
) Pic
= &MasterPic
;
111 else Pic
= &SlavePic
;
113 /* Is the PIC ready? */
114 if (!Pic
->Initialization
)
116 /* Yes, this is an OCW1 */
117 Pic
->MaskRegister
= Value
;
121 /* Has the interrupt offset been set? */
122 if (Pic
->IntOffset
== 0xFF)
124 /* This is an ICW2, set the offset (last three bits always zero) */
125 Pic
->IntOffset
= Value
& 0xF8;
127 /* Check if we are in single mode and don't need an ICW4 */
128 if ((Pic
->ConfigRegister
& PIC_ICW1_SINGLE
)
129 && !(Pic
->ConfigRegister
& PIC_ICW1_ICW4
))
131 /* Yes, done initializing */
132 Pic
->Initialization
= FALSE
;
137 /* Check if we are in cascade mode and the cascade register was not set */
138 if (!(Pic
->ConfigRegister
& PIC_ICW1_SINGLE
) && !Pic
->CascadeRegisterSet
)
140 /* This is an ICW3 */
141 Pic
->CascadeRegister
= Value
;
142 Pic
->CascadeRegisterSet
= TRUE
;
144 /* Check if we need an ICW4 */
145 if (!(Pic
->ConfigRegister
& PIC_ICW1_ICW4
))
147 /* No, done initializing */
148 Pic
->Initialization
= FALSE
;
153 /* This must be an ICW4, we will ignore the 8086 bit (assume always set) */
154 if (Value
& PIC_ICW4_AEOI
)
156 /* Use automatic end-of-interrupt */
160 /* Done initializing */
161 Pic
->Initialization
= FALSE
;
164 VOID
PicInterruptRequest(BYTE Number
)
166 if (Number
>= 0 && Number
< 8)
168 /* Check if the interrupt is busy or in a cascade */
169 if (MasterPic
.CascadeRegister
& (1 << Number
)
170 || MasterPic
.InServiceRegister
& (1 << Number
))
175 MasterPic
.InServiceRegister
|= 1 << Number
;
176 EmulatorInterrupt(MasterPic
.IntOffset
+ Number
);
178 else if (Number
>= 8 && Number
< 16)
183 * The slave PIC is connected to IRQ 2, always! If the master PIC
184 * was misconfigured, don't do anything.
186 if (!(MasterPic
.CascadeRegister
& (1 << 2))
187 || SlavePic
.CascadeRegister
!= 2)
192 /* Check the if the slave PIC is busy */
193 if (MasterPic
.InServiceRegister
& (1 << 2)) return;
195 /* Set the IRQ 2 bit in the master ISR */
196 MasterPic
.InServiceRegister
|= 1 << 2;
198 /* Check if the interrupt is busy or in a cascade */
199 if (SlavePic
.CascadeRegister
& (1 << Number
)
200 || SlavePic
.InServiceRegister
& (1 << Number
))
205 SlavePic
.InServiceRegister
|= 1 << Number
;
206 EmulatorInterrupt(SlavePic
.IntOffset
+ Number
);