misc: Make many includes explicit.
[gem5.git] / src / dev / x86 / i8259.cc
1 /*
2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "dev/x86/i8259.hh"
30
31 #include "base/bitfield.hh"
32 #include "base/trace.hh"
33 #include "debug/I8259.hh"
34 #include "dev/x86/i82094aa.hh"
35 #include "mem/packet.hh"
36 #include "mem/packet_access.hh"
37
38 X86ISA::I8259::I8259(Params * p)
39 : BasicPioDevice(p, 2),
40 latency(p->pio_latency),
41 mode(p->mode), slave(p->slave),
42 IRR(0), ISR(0), IMR(0),
43 readIRR(true), initControlWord(0), autoEOI(false)
44 {
45 for (int i = 0; i < p->port_output_connection_count; i++) {
46 output.push_back(new IntSourcePin<I8259>(
47 csprintf("%s.output[%d]", name(), i), i, this));
48 }
49
50 int in_count = p->port_inputs_connection_count;
51 panic_if(in_count >= NumLines,
52 "I8259 only supports 8 inputs, but there are %d.", in_count);
53 for (int i = 0; i < in_count; i++) {
54 inputs.push_back(new IntSinkPin<I8259>(
55 csprintf("%s.inputs[%d]", name(), i), i, this));
56 }
57
58 for (bool &state: pinStates)
59 state = false;
60 }
61
62 void
63 X86ISA::I8259::init()
64 {
65 BasicPioDevice::init();
66
67 for (auto *input: inputs)
68 pinStates[input->getId()] = input->state();
69 }
70
71 Tick
72 X86ISA::I8259::read(PacketPtr pkt)
73 {
74 assert(pkt->getSize() == 1);
75 switch(pkt->getAddr() - pioAddr)
76 {
77 case 0x0:
78 if (readIRR) {
79 DPRINTF(I8259, "Reading IRR as %#x.\n", IRR);
80 pkt->setLE(IRR);
81 } else {
82 DPRINTF(I8259, "Reading ISR as %#x.\n", ISR);
83 pkt->setLE(ISR);
84 }
85 break;
86 case 0x1:
87 DPRINTF(I8259, "Reading IMR as %#x.\n", IMR);
88 pkt->setLE(IMR);
89 break;
90 }
91 pkt->makeAtomicResponse();
92 return latency;
93 }
94
95 Tick
96 X86ISA::I8259::write(PacketPtr pkt)
97 {
98 assert(pkt->getSize() == 1);
99 uint8_t val = pkt->getLE<uint8_t>();
100 switch (pkt->getAddr() - pioAddr) {
101 case 0x0:
102 if (bits(val, 4)) {
103 DPRINTF(I8259, "Received initialization command word 1.\n");
104 IMR = 0;
105 edgeTriggered = bits(val, 3);
106 DPRINTF(I8259, "%s triggered mode.\n",
107 edgeTriggered ? "Edge" : "Level");
108 cascadeMode = !bits(val, 1);
109 DPRINTF(I8259, "%s mode.\n",
110 cascadeMode ? "Cascade" : "Single");
111 expectICW4 = bits(val, 0);
112 if (!expectICW4) {
113 autoEOI = false;
114 }
115 initControlWord = 1;
116 DPRINTF(I8259, "Expecting %d more bytes.\n", expectICW4 ? 3 : 2);
117 } else if (bits(val, 4, 3) == 0) {
118 DPRINTF(I8259, "Received operation command word 2.\n");
119 switch (bits(val, 7, 5)) {
120 case 0x0:
121 DPRINTF(I8259,
122 "Subcommand: Rotate in auto-EOI mode (clear).\n");
123 break;
124 case 0x1:
125 {
126 int line = findMsbSet(ISR);
127 DPRINTF(I8259, "Subcommand: Nonspecific EOI on line %d.\n",
128 line);
129 handleEOI(line);
130 }
131 break;
132 case 0x2:
133 DPRINTF(I8259, "Subcommand: No operation.\n");
134 break;
135 case 0x3:
136 {
137 int line = bits(val, 2, 0);
138 DPRINTF(I8259, "Subcommand: Specific EIO on line %d.\n",
139 line);
140 handleEOI(line);
141 }
142 break;
143 case 0x4:
144 DPRINTF(I8259, "Subcommand: Rotate in auto-EOI mode (set).\n");
145 break;
146 case 0x5:
147 DPRINTF(I8259, "Subcommand: Rotate on nonspecific EOI.\n");
148 break;
149 case 0x6:
150 DPRINTF(I8259, "Subcommand: Set priority command.\n");
151 DPRINTF(I8259, "Lowest: IRQ%d Highest IRQ%d.\n",
152 bits(val, 2, 0), (bits(val, 2, 0) + 1) % 8);
153 break;
154 case 0x7:
155 DPRINTF(I8259, "Subcommand: Rotate on specific EOI.\n");
156 DPRINTF(I8259, "Lowest: IRQ%d Highest IRQ%d.\n",
157 bits(val, 2, 0), (bits(val, 2, 0) + 1) % 8);
158 break;
159 }
160 } else if (bits(val, 4, 3) == 1) {
161 DPRINTF(I8259, "Received operation command word 3.\n");
162 if (bits(val, 7)) {
163 DPRINTF(I8259, "%s special mask mode.\n",
164 bits(val, 6) ? "Set" : "Clear");
165 }
166 if (bits(val, 1)) {
167 readIRR = bits(val, 0);
168 DPRINTF(I8259, "Read %s.\n", readIRR ? "IRR" : "ISR");
169 }
170 }
171 break;
172 case 0x1:
173 switch (initControlWord) {
174 case 0x0:
175 DPRINTF(I8259, "Received operation command word 1.\n");
176 DPRINTF(I8259, "Wrote IMR value %#x.\n", val);
177 IMR = val;
178 break;
179 case 0x1:
180 DPRINTF(I8259, "Received initialization command word 2.\n");
181 vectorOffset = val & ~mask(3);
182 DPRINTF(I8259, "Responsible for vectors %#x-%#x.\n",
183 vectorOffset, vectorOffset | mask(3));
184 if (cascadeMode) {
185 initControlWord++;
186 } else {
187 cascadeBits = 0;
188 initControlWord = 0;
189 }
190 break;
191 case 0x2:
192 DPRINTF(I8259, "Received initialization command word 3.\n");
193 if (mode == Enums::I8259Master) {
194 DPRINTF(I8259, "Slaves attached to IRQs:%s%s%s%s%s%s%s%s\n",
195 bits(val, 0) ? " 0" : "",
196 bits(val, 1) ? " 1" : "",
197 bits(val, 2) ? " 2" : "",
198 bits(val, 3) ? " 3" : "",
199 bits(val, 4) ? " 4" : "",
200 bits(val, 5) ? " 5" : "",
201 bits(val, 6) ? " 6" : "",
202 bits(val, 7) ? " 7" : "");
203 cascadeBits = val;
204 } else {
205 DPRINTF(I8259, "Slave ID is %d.\n", val & mask(3));
206 cascadeBits = val & mask(3);
207 }
208 if (expectICW4)
209 initControlWord++;
210 else
211 initControlWord = 0;
212 break;
213 case 0x3:
214 DPRINTF(I8259, "Received initialization command word 4.\n");
215 if (bits(val, 4)) {
216 DPRINTF(I8259, "Special fully nested mode.\n");
217 } else {
218 DPRINTF(I8259, "Not special fully nested mode.\n");
219 }
220 if (bits(val, 3) == 0) {
221 DPRINTF(I8259, "Nonbuffered.\n");
222 } else if (bits(val, 2) == 0) {
223 DPRINTF(I8259, "Buffered.\n");
224 } else {
225 DPRINTF(I8259, "Unrecognized buffer mode.\n");
226 }
227 autoEOI = bits(val, 1);
228 DPRINTF(I8259, "%s End Of Interrupt.\n",
229 autoEOI ? "Automatic" : "Normal");
230
231 DPRINTF(I8259, "%s mode.\n", bits(val, 0) ? "80x86" : "MCX-80/85");
232 initControlWord = 0;
233 break;
234 }
235 break;
236 }
237 pkt->makeAtomicResponse();
238 return latency;
239 }
240
241 void
242 X86ISA::I8259::handleEOI(int line)
243 {
244 ISR &= ~(1 << line);
245 // There may be an interrupt that was waiting which can
246 // now be sent.
247 if (IRR)
248 requestInterrupt(findMsbSet(IRR));
249 }
250
251 void
252 X86ISA::I8259::requestInterrupt(int line)
253 {
254 if (bits(ISR, 7, line) == 0) {
255 if (!output.empty()) {
256 DPRINTF(I8259, "Propogating interrupt.\n");
257 for (auto *wire: output) {
258 wire->raise();
259 //XXX This is a hack.
260 wire->lower();
261 }
262 } else {
263 warn("Received interrupt but didn't have "
264 "anyone to tell about it.\n");
265 }
266 }
267 }
268
269 void
270 X86ISA::I8259::signalInterrupt(int line)
271 {
272 DPRINTF(I8259, "Interrupt requested for line %d.\n", line);
273 if (line >= NumLines)
274 fatal("Line number %d doesn't exist. The max is %d.\n",
275 line, NumLines - 1);
276 if (bits(IMR, line)) {
277 DPRINTF(I8259, "Interrupt %d was masked.\n", line);
278 } else {
279 IRR |= 1 << line;
280 requestInterrupt(line);
281 }
282 }
283
284 void
285 X86ISA::I8259::raiseInterruptPin(int number)
286 {
287 DPRINTF(I8259, "Interrupt signal raised for pin %d.\n", number);
288 if (number >= NumLines)
289 fatal("Line number %d doesn't exist. The max is %d.\n",
290 number, NumLines - 1);
291 if (!pinStates[number])
292 signalInterrupt(number);
293 pinStates[number] = true;
294 }
295
296 void
297 X86ISA::I8259::lowerInterruptPin(int number)
298 {
299 DPRINTF(I8259, "Interrupt signal lowered for pin %d.\n", number);
300 if (number >= NumLines)
301 fatal("Line number %d doesn't exist. The max is %d.\n",
302 number, NumLines - 1);
303 pinStates[number] = false;
304 }
305
306 int
307 X86ISA::I8259::getVector()
308 {
309 /*
310 * This code only handles one slave. Since that's how the PC platform
311 * always uses the 8259 PIC, there shouldn't be any need for more. If
312 * there -is- a need for more for some reason, "slave" can become a
313 * vector of slaves.
314 */
315 int line = findMsbSet(IRR);
316 IRR &= ~(1 << line);
317 DPRINTF(I8259, "Interrupt %d was accepted.\n", line);
318 if (autoEOI) {
319 handleEOI(line);
320 } else {
321 ISR |= 1 << line;
322 }
323 if (slave && bits(cascadeBits, line)) {
324 DPRINTF(I8259, "Interrupt was from slave who will "
325 "provide the vector.\n");
326 return slave->getVector();
327 }
328 return line | vectorOffset;
329 }
330
331 void
332 X86ISA::I8259::serialize(CheckpointOut &cp) const
333 {
334 SERIALIZE_ARRAY(pinStates, NumLines);
335 SERIALIZE_ENUM(mode);
336 SERIALIZE_SCALAR(IRR);
337 SERIALIZE_SCALAR(ISR);
338 SERIALIZE_SCALAR(IMR);
339 SERIALIZE_SCALAR(vectorOffset);
340 SERIALIZE_SCALAR(cascadeMode);
341 SERIALIZE_SCALAR(cascadeBits);
342 SERIALIZE_SCALAR(edgeTriggered);
343 SERIALIZE_SCALAR(readIRR);
344 SERIALIZE_SCALAR(expectICW4);
345 SERIALIZE_SCALAR(initControlWord);
346 SERIALIZE_SCALAR(autoEOI);
347 }
348
349 void
350 X86ISA::I8259::unserialize(CheckpointIn &cp)
351 {
352 UNSERIALIZE_ARRAY(pinStates, NumLines);
353 UNSERIALIZE_ENUM(mode);
354 UNSERIALIZE_SCALAR(IRR);
355 UNSERIALIZE_SCALAR(ISR);
356 UNSERIALIZE_SCALAR(IMR);
357 UNSERIALIZE_SCALAR(vectorOffset);
358 UNSERIALIZE_SCALAR(cascadeMode);
359 UNSERIALIZE_SCALAR(cascadeBits);
360 UNSERIALIZE_SCALAR(edgeTriggered);
361 UNSERIALIZE_SCALAR(readIRR);
362 UNSERIALIZE_SCALAR(expectICW4);
363 UNSERIALIZE_SCALAR(initControlWord);
364 UNSERIALIZE_SCALAR(autoEOI);
365 }
366
367 X86ISA::I8259 *
368 I8259Params::create()
369 {
370 return new X86ISA::I8259(this);
371 }