ReactOS  0.4.13-dev-99-g7e18b6d
pic.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: GPL - See COPYING in the top level directory
3  * PROJECT: ReactOS Virtual DOS Machine
4  * FILE: subsystems/mvdm/ntvdm/hardware/pic.c
5  * PURPOSE: Programmable Interrupt Controller emulation
6  * (Interrupt Controller Adapter (ICA) in Windows terminology)
7  * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
8  */
9 
10 /* INCLUDES *******************************************************************/
11 
12 #include "ntvdm.h"
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 #include "emulator.h"
18 #include "pic.h"
19 
20 #include "io.h"
21 
22 /* PRIVATE VARIABLES **********************************************************/
23 
24 typedef struct _PIC
25 {
37 } PIC, *PPIC;
38 
40 
41 /* PRIVATE FUNCTIONS **********************************************************/
42 
44 {
45  PPIC Pic;
46 
47  /* Which PIC are we accessing? */
48  if (Port == PIC_MASTER_CMD)
49  Pic = &MasterPic;
50  else // if (Port == PIC_SLAVE_CMD)
51  Pic = &SlavePic;
52 
53  if (Pic->ReadIsr)
54  {
55  /* Read the in-service register */
56  Pic->ReadIsr = FALSE;
57  return Pic->InServiceRegister;
58  }
59  else
60  {
61  /* Read the interrupt request register */
62  return Pic->IntRequestRegister;
63  }
64 }
65 
67 {
68  PPIC Pic;
69 
70  /* Which PIC are we accessing? */
71  if (Port == PIC_MASTER_CMD)
72  Pic = &MasterPic;
73  else // if (Port == PIC_SLAVE_CMD)
74  Pic = &SlavePic;
75 
76  if (Data & PIC_ICW1)
77  {
78  /* Start initialization */
79  Pic->Initialization = TRUE;
80  Pic->IntOffset = 0xFF;
82  Pic->ConfigRegister = Data;
83  return;
84  }
85 
86  if (Data & PIC_OCW3)
87  {
88  /* This is an OCR3 */
89  if (Data == PIC_OCW3_READ_ISR)
90  {
91  /* Return the ISR on next read from command port */
92  Pic->ReadIsr = TRUE;
93  }
94 
95  return;
96  }
97 
98  /* This is an OCW2 */
99  if (Data & PIC_OCW2_EOI)
100  {
101  if (Data & PIC_OCW2_SL)
102  {
103  /* If the SL bit is set, clear a specific IRQ */
104  Pic->InServiceRegister &= ~(1 << (Data & PIC_OCW2_NUM_MASK));
105  }
106  else
107  {
108  /* Otherwise, clear all of them */
109  Pic->InServiceRegister = 0;
110  }
111 
113  {
114  /* Signal the next IRQ */
116  }
117  }
118 }
119 
121 {
122  /* Read the mask register */
123  if (Port == PIC_MASTER_DATA)
124  return MasterPic.MaskRegister;
125  else // if (Port == PIC_SLAVE_DATA)
126  return SlavePic.MaskRegister;
127 }
128 
130 {
131  PPIC Pic;
132 
133  /* Which PIC are we accessing? */
134  if (Port == PIC_MASTER_DATA)
135  Pic = &MasterPic;
136  else // if (Port == PIC_SLAVE_DATA)
137  Pic = &SlavePic;
138 
139  /* Is the PIC ready? */
140  if (!Pic->Initialization)
141  {
142  /* Yes, this is an OCW1 */
143  Pic->MaskRegister = Data;
144  return;
145  }
146 
147  /* Has the interrupt offset been set? */
148  if (Pic->IntOffset == 0xFF)
149  {
150  /* This is an ICW2, set the offset (last three bits always zero) */
151  Pic->IntOffset = Data & 0xF8;
152 
153  /* Check if we are in single mode and don't need an ICW4 */
154  if ((Pic->ConfigRegister & PIC_ICW1_SINGLE)
155  && !(Pic->ConfigRegister & PIC_ICW1_ICW4))
156  {
157  /* Yes, done initializing */
158  Pic->Initialization = FALSE;
159  }
160  return;
161  }
162 
163  /* Check if we are in cascade mode and the cascade register was not set */
164  if (!(Pic->ConfigRegister & PIC_ICW1_SINGLE) && !Pic->CascadeRegisterSet)
165  {
166  /* This is an ICW3 */
167  Pic->CascadeRegister = Data;
168  Pic->CascadeRegisterSet = TRUE;
169 
170  /* Check if we need an ICW4 */
171  if (!(Pic->ConfigRegister & PIC_ICW1_ICW4))
172  {
173  /* No, done initializing */
174  Pic->Initialization = FALSE;
175  }
176  return;
177  }
178 
179  /* This must be an ICW4, we will ignore the 8086 bit (assume always set) */
180  if (Data & PIC_ICW4_AEOI)
181  {
182  /* Use automatic end-of-interrupt */
183  Pic->AutoEoi = TRUE;
184  }
185 
186  /* Done initializing */
187  Pic->Initialization = FALSE;
188 }
189 
190 /* PUBLIC FUNCTIONS ***********************************************************/
191 
193 {
194  BYTE i;
195 
196  if (/* Number >= 0 && */ Number < 8)
197  {
198  /* Check if any of the higher-priority interrupts are busy */
199  for (i = 0; i <= Number; i++)
200  {
201  if (MasterPic.InServiceRegister & (1 << Number)) return;
202  }
203 
204  /* Check if the interrupt is masked */
205  if (MasterPic.MaskRegister & (1 << Number)) return;
206 
207  /* Set the appropriate bit in the IRR and interrupt the CPU */
210  }
211  else if (Number >= 8 && Number < 16)
212  {
213  Number -= 8;
214 
215  /*
216  * The slave PIC is connected to IRQ 2, always! If the master PIC
217  * was misconfigured, don't do anything.
218  */
219  if (!(MasterPic.CascadeRegister & (1 << 2))
220  || SlavePic.CascadeRegister != 2)
221  {
222  return;
223  }
224 
225  /* Check if any of the higher-priority interrupts are busy */
226  if (MasterPic.InServiceRegister != 0) return;
227  for (i = 0; i <= Number; i++)
228  {
229  if (SlavePic.InServiceRegister & (1 << Number)) return;
230  }
231 
232  /* Check if the interrupt is masked */
233  if (SlavePic.MaskRegister & (1 << Number)) return;
234 
235  /* Set the IRQ 2 bit in the master ISR */
236  if (!MasterPic.AutoEoi) MasterPic.InServiceRegister |= (1 << 2);
237 
238  /* Set the appropriate bit in the IRR and interrupt the CPU */
241  }
242 }
243 
245 {
246  UINT i;
247 
248  /* Search the master PIC interrupts by priority */
249  for (i = 0; i < 8; i++)
250  {
251  if (MasterPic.IntRequestRegister & (1 << i))
252  {
253  /* Clear the IRR flag */
254  MasterPic.IntRequestRegister &= ~(1 << i);
255 
256  /* Set the ISR flag, unless AEOI is enabled */
258 
259  /* Return the interrupt number */
260  return MasterPic.IntOffset + i;
261  }
262  }
263 
264  /* Search the slave PIC interrupts by priority */
265  for (i = 0; i < 8; i++)
266  {
267  if (SlavePic.IntRequestRegister & (1 << i))
268  {
269  /* Clear the IRR flag */
270  SlavePic.IntRequestRegister &= ~(1 << i);
271 
272  if ((i == 1) && SlavePic.CascadeRegisterSet)
273  {
274  /* This interrupt is routed to the master PIC */
276  }
277  else
278  {
279  /* Set the ISR flag, unless AEOI is enabled */
280  if (!SlavePic.AutoEoi) SlavePic.InServiceRegister |= (1 << i);
281 
282  /* Return the interrupt number */
283  return SlavePic.IntOffset + i;
284  }
285  }
286  }
287 
288  /* Spurious interrupt */
289  if (MasterPic.InServiceRegister & (1 << 2))
290  return SlavePic.IntOffset + 7;
291  else
292  return MasterPic.IntOffset + 7;
293 }
294 
296 {
297  /* Register the I/O Ports */
302 }
303 
304 
305 
306 VOID
307 WINAPI
309  BYTE line,
310  INT count)
311 {
312  BYTE InterruptNumber = line;
313 
314  /* Check for PIC validity */
315  if (ms != ICA_MASTER && ms != ICA_SLAVE) return;
316 
317  /*
318  * Adjust the interrupt request number according to the parameters,
319  * by adding an offset == 8 to the interrupt number.
320  *
321  * Indeed VDDs calling this function usually subtracts 8 so that they give:
322  *
323  * ms | line | corresponding interrupt number
324  * ------------+--------+--------------------------------
325  * ICA_MASTER | 0 -- 7 | 0 -- 7
326  * ICA_SLAVE | 0 -- 7 | 8 -- 15
327  *
328  * and PicInterruptRequest subtracts again 8 to the interrupt number
329  * if it is greater or equal than 8 (so that it determines which PIC
330  * to use via the interrupt number).
331  */
332  if (ms == ICA_SLAVE) InterruptNumber += 8;
333 
334  /* Send the specified number of interrupt requests */
335  while (count-- > 0)
336  {
337  PicInterruptRequest(InterruptNumber);
338  /*
339  * FIXME: We should now restart 16-bit emulation and wait for its termination:
340  *
341  * "When the VDD calls VDDSimulateInterrupt, the address pointed to by
342  * the interrupt vector starts running in 16-bit mode. For an asynchronous
343  * interrupt, the VDD should create another thread and call VDDSimulateInterrupt
344  * from that thread."
345  */
346  }
347 }
348 
349 WORD
350 WINAPI
352  IN WORD IrqLine)
353 {
356  return 0xFFFF;
357 }
358 
359 BOOL
360 WINAPI
362  IN WORD IrqLine)
363 {
366  return FALSE;
367 }
368 
369 /* EOF */
#define PIC_MASTER_DATA
Definition: pic.h:16
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
CPPORT Port[4]
Definition: headless.c:34
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
static VOID WINAPI PicWriteData(USHORT Port, BYTE Data)
Definition: pic.c:129
#define PIC_OCW2_NUM_MASK
Definition: pic.h:26
GLuint GLuint GLsizei count
Definition: gl.h:1545
BOOLEAN Slave
Definition: pic.c:35
#define PIC_ICW1_SINGLE
Definition: pic.h:22
VOID PicInitialize(VOID)
Definition: pic.c:295
static BYTE WINAPI PicReadData(USHORT Port)
Definition: pic.c:120
BYTE IntOffset
Definition: pic.c:30
BOOLEAN Initialization
Definition: pic.c:26
int32_t INT
Definition: typedefs.h:56
Definition: pic.c:24
VOID RegisterIoPort(USHORT Port, EMULATOR_INB_PROC InHandler, EMULATOR_OUTB_PROC OutHandler)
Definition: io.c:320
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
WORD WINAPI VDDReserveIrqLine(IN HANDLE hVdd, IN WORD IrqLine)
Definition: pic.c:351
unsigned int BOOL
Definition: ntddk_ex.h:94
#define PIC_OCW3
Definition: pic.h:30
BOOLEAN CascadeRegisterSet
Definition: pic.c:33
#define ICA_MASTER
Definition: vddsvc.h:32
unsigned char BOOLEAN
#define PIC_SLAVE_DATA
Definition: pic.h:18
BOOL WINAPI VDDReleaseIrqLine(IN HANDLE hVdd, IN WORD IrqLine)
Definition: pic.c:361
_In_ LPGUID _In_ PVOID Data
Definition: classpnp.h:778
Definition: parser.c:48
BYTE ConfigRegister
Definition: pic.c:31
#define PIC_MASTER_CMD
Definition: pic.h:15
BYTE PicGetInterrupt(VOID)
Definition: pic.c:244
#define PIC_ICW1_ICW4
Definition: pic.h:21
BOOLEAN ReadIsr
Definition: pic.c:36
#define PIC_ICW4_AEOI
Definition: pic.h:24
#define PIC_OCW3_READ_ISR
Definition: pic.h:31
#define WINAPI
Definition: msvc.h:8
unsigned short WORD
Definition: ntddk_ex.h:93
#define SetLastError(x)
Definition: compat.h:409
static BYTE WINAPI PicReadCommand(USHORT Port)
Definition: pic.c:43
char line[200]
Definition: main.c:97
#define ICA_SLAVE
Definition: vddsvc.h:33
unsigned char BYTE
Definition: mem.h:68
_In_opt_ PENTER_STATE_SYSTEM_HANDLER _In_opt_ PVOID _In_ LONG _In_opt_ LONG volatile * Number
Definition: ntpoapi.h:204
#define PIC_ICW1
Definition: pic.h:20
#define PIC_OCW2_EOI
Definition: pic.h:27
#define PIC_OCW2_SL
Definition: pic.h:28
VOID EmulatorInterruptSignal(VOID)
Definition: emulator.c:120
unsigned short USHORT
Definition: pedump.c:61
BOOLEAN AutoEoi
Definition: pic.c:34
BYTE CascadeRegister
Definition: pic.c:32
static VOID WINAPI PicWriteCommand(USHORT Port, BYTE Data)
Definition: pic.c:66
unsigned int UINT
Definition: ndis.h:50
BYTE IntRequestRegister
Definition: pic.c:28
#define PIC_SLAVE_CMD
Definition: pic.h:17
BYTE MaskRegister
Definition: pic.c:27
VOID PicInterruptRequest(BYTE Number)
Definition: pic.c:192
BYTE InServiceRegister
Definition: pic.c:29
#define UNIMPLEMENTED
Definition: debug.h:114
struct _PIC * PPIC
struct _PIC PIC
static PIC MasterPic
Definition: pic.c:39
VOID WINAPI call_ica_hw_interrupt(INT ms, BYTE line, INT count)
Definition: pic.c:308
static PIC SlavePic
Definition: pic.c:39
HANDLE hVdd
Definition: testvdd.c:87