gem5 v24.0.0.0
Loading...
Searching...
No Matches
i8259.cc
Go to the documentation of this file.
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
32#include "base/bitfield.hh"
33#include "base/trace.hh"
34#include "debug/I8259.hh"
35#include "dev/x86/i82094aa.hh"
36#include "mem/packet.hh"
37#include "mem/packet_access.hh"
38
39namespace gem5
40{
41
43 latency(p.pio_latency), mode(p.mode), slave(p.slave)
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
61{
63 if (mode == enums::I8259Master || mode == enums::I8259Single) {
64 // Listen for INTA messages.
65 ranges.push_back(RangeSize(PhysAddrIntA, 1));
66 }
67 return ranges;
68}
69
70void
72{
74
75 for (auto *input: inputs)
76 pinStates[input->getId()] = input->state();
77}
78
79Tick
81{
82 assert(pkt->getSize() == 1);
83 if (pkt->getAddr() == PhysAddrIntA) {
84 assert(mode == enums::I8259Master || mode == enums::I8259Single);
85 pkt->setLE<uint8_t>(getVector());
86 }
87 switch(pkt->getAddr() - pioAddr) {
88 case 0x0:
89 if (readIRR) {
90 DPRINTF(I8259, "Reading IRR as %#x.\n", IRR);
91 pkt->setLE(IRR);
92 } else {
93 DPRINTF(I8259, "Reading ISR as %#x.\n", ISR);
94 pkt->setLE(ISR);
95 }
96 break;
97 case 0x1:
98 DPRINTF(I8259, "Reading IMR as %#x.\n", IMR);
99 pkt->setLE(IMR);
100 break;
101 }
102 pkt->makeAtomicResponse();
103 return latency;
104}
105
106Tick
108{
109 assert(pkt->getSize() == 1);
110 uint8_t val = pkt->getLE<uint8_t>();
111 switch (pkt->getAddr() - pioAddr) {
112 case 0x0:
113 if (bits(val, 4)) {
114 DPRINTF(I8259, "Received initialization command word 1.\n");
115 IMR = 0;
116 edgeTriggered = bits(val, 3);
117 DPRINTF(I8259, "%s triggered mode.\n",
118 edgeTriggered ? "Edge" : "Level");
119 cascadeMode = !bits(val, 1);
120 DPRINTF(I8259, "%s mode.\n",
121 cascadeMode ? "Cascade" : "Single");
122 expectICW4 = bits(val, 0);
123 if (!expectICW4) {
124 autoEOI = false;
125 }
126 initControlWord = 1;
127 DPRINTF(I8259, "Expecting %d more bytes.\n", expectICW4 ? 3 : 2);
128 } else if (bits(val, 4, 3) == 0) {
129 DPRINTF(I8259, "Received operation command word 2.\n");
130 switch (bits(val, 7, 5)) {
131 case 0x0:
133 "Subcommand: Rotate in auto-EOI mode (clear).\n");
134 break;
135 case 0x1:
136 {
137 int line = findMsbSet(ISR);
138 DPRINTF(I8259, "Subcommand: Nonspecific EOI on line %d.\n",
139 line);
140 handleEOI(line);
141 }
142 break;
143 case 0x2:
144 DPRINTF(I8259, "Subcommand: No operation.\n");
145 break;
146 case 0x3:
147 {
148 int line = bits(val, 2, 0);
149 DPRINTF(I8259, "Subcommand: Specific EIO on line %d.\n",
150 line);
151 handleEOI(line);
152 }
153 break;
154 case 0x4:
155 DPRINTF(I8259, "Subcommand: Rotate in auto-EOI mode (set).\n");
156 break;
157 case 0x5:
158 DPRINTF(I8259, "Subcommand: Rotate on nonspecific EOI.\n");
159 break;
160 case 0x6:
161 DPRINTF(I8259, "Subcommand: Set priority command.\n");
162 DPRINTF(I8259, "Lowest: IRQ%d Highest IRQ%d.\n",
163 bits(val, 2, 0), (bits(val, 2, 0) + 1) % 8);
164 break;
165 case 0x7:
166 DPRINTF(I8259, "Subcommand: Rotate on specific EOI.\n");
167 DPRINTF(I8259, "Lowest: IRQ%d Highest IRQ%d.\n",
168 bits(val, 2, 0), (bits(val, 2, 0) + 1) % 8);
169 break;
170 }
171 } else if (bits(val, 4, 3) == 1) {
172 DPRINTF(I8259, "Received operation command word 3.\n");
173 if (bits(val, 7)) {
174 DPRINTF(I8259, "%s special mask mode.\n",
175 bits(val, 6) ? "Set" : "Clear");
176 }
177 if (bits(val, 1)) {
178 readIRR = bits(val, 0);
179 DPRINTF(I8259, "Read %s.\n", readIRR ? "IRR" : "ISR");
180 }
181 }
182 break;
183 case 0x1:
184 switch (initControlWord) {
185 case 0x0:
186 DPRINTF(I8259, "Received operation command word 1.\n");
187 DPRINTF(I8259, "Wrote IMR value %#x.\n", val);
188 IMR = val;
189 break;
190 case 0x1:
191 DPRINTF(I8259, "Received initialization command word 2.\n");
192 vectorOffset = val & ~mask(3);
193 DPRINTF(I8259, "Responsible for vectors %#x-%#x.\n",
194 vectorOffset, vectorOffset | mask(3));
195 if (cascadeMode) {
196 initControlWord++;
197 } else {
198 cascadeBits = 0;
199 initControlWord = 0;
200 }
201 break;
202 case 0x2:
203 DPRINTF(I8259, "Received initialization command word 3.\n");
204 if (mode == enums::I8259Master) {
205 DPRINTF(I8259, "Responders attached to "
206 "IRQs:%s%s%s%s%s%s%s%s\n",
207 bits(val, 0) ? " 0" : "",
208 bits(val, 1) ? " 1" : "",
209 bits(val, 2) ? " 2" : "",
210 bits(val, 3) ? " 3" : "",
211 bits(val, 4) ? " 4" : "",
212 bits(val, 5) ? " 5" : "",
213 bits(val, 6) ? " 6" : "",
214 bits(val, 7) ? " 7" : "");
215 cascadeBits = val;
216 } else {
217 DPRINTF(I8259, "Responder ID is %d.\n", val & mask(3));
218 cascadeBits = val & mask(3);
219 }
220 if (expectICW4)
221 initControlWord++;
222 else
223 initControlWord = 0;
224 break;
225 case 0x3:
226 DPRINTF(I8259, "Received initialization command word 4.\n");
227 if (bits(val, 4)) {
228 DPRINTF(I8259, "Special fully nested mode.\n");
229 } else {
230 DPRINTF(I8259, "Not special fully nested mode.\n");
231 }
232 if (bits(val, 3) == 0) {
233 DPRINTF(I8259, "Nonbuffered.\n");
234 } else if (bits(val, 2) == 0) {
235 DPRINTF(I8259, "Buffered.\n");
236 } else {
237 DPRINTF(I8259, "Unrecognized buffer mode.\n");
238 }
239 autoEOI = bits(val, 1);
240 DPRINTF(I8259, "%s End Of Interrupt.\n",
241 autoEOI ? "Automatic" : "Normal");
242
243 DPRINTF(I8259, "%s mode.\n", bits(val, 0) ? "80x86" : "MCX-80/85");
244 initControlWord = 0;
245 break;
246 }
247 break;
248 }
249 pkt->makeAtomicResponse();
250 return latency;
251}
252
253void
255{
256 ISR &= ~(1 << line);
257 // There may be an interrupt that was waiting which can
258 // now be sent.
259 if (IRR)
260 requestInterrupt(findMsbSet(IRR));
261}
262
263void
265{
266 if (bits(ISR, 7, line) == 0) {
267 if (!output.empty()) {
268 DPRINTF(I8259, "Propogating interrupt.\n");
269 for (auto *wire: output) {
270 wire->raise();
271 //XXX This is a hack.
272 wire->lower();
273 }
274 } else {
275 warn("Received interrupt but didn't have "
276 "anyone to tell about it.\n");
277 }
278 }
279}
280
281void
283{
284 DPRINTF(I8259, "Interrupt requested for line %d.\n", line);
285 if (line >= NumLines)
286 fatal("Line number %d doesn't exist. The max is %d.\n",
287 line, NumLines - 1);
288 if (bits(IMR, line)) {
289 DPRINTF(I8259, "Interrupt %d was masked.\n", line);
290 } else {
291 IRR |= 1 << line;
292 requestInterrupt(line);
293 }
294}
295
296void
298{
299 DPRINTF(I8259, "Interrupt signal raised 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 if (!pinStates[number])
304 signalInterrupt(number);
305 pinStates[number] = true;
306}
307
308void
310{
311 DPRINTF(I8259, "Interrupt signal lowered for pin %d.\n", number);
312 if (number >= NumLines)
313 fatal("Line number %d doesn't exist. The max is %d.\n",
314 number, NumLines - 1);
315 pinStates[number] = false;
316}
317
318int
320{
321 /*
322 * This code only handles one responder. Since that's how the PC platform
323 * always uses the 8259 PIC, there shouldn't be any need for more. If
324 * there -is- a need for more for some reason, "responder" can become a
325 * vector of responders.
326 */
327 int line = findMsbSet(IRR);
328 IRR &= ~(1 << line);
329 DPRINTF(I8259, "Interrupt %d was accepted.\n", line);
330 if (autoEOI) {
331 handleEOI(line);
332 } else {
333 ISR |= 1 << line;
334 }
335 if (slave && bits(cascadeBits, line)) {
336 DPRINTF(I8259, "Interrupt was from responder who will "
337 "provide the vector.\n");
338 return slave->getVector();
339 }
340 return line | vectorOffset;
341}
342
343void
345{
346 SERIALIZE_ARRAY(pinStates, NumLines);
348 SERIALIZE_SCALAR(IRR);
351 SERIALIZE_SCALAR(vectorOffset);
352 SERIALIZE_SCALAR(cascadeMode);
353 SERIALIZE_SCALAR(cascadeBits);
354 SERIALIZE_SCALAR(edgeTriggered);
355 SERIALIZE_SCALAR(readIRR);
356 SERIALIZE_SCALAR(expectICW4);
357 SERIALIZE_SCALAR(initControlWord);
358 SERIALIZE_SCALAR(autoEOI);
359}
360
361void
363{
364 UNSERIALIZE_ARRAY(pinStates, NumLines);
369 UNSERIALIZE_SCALAR(vectorOffset);
370 UNSERIALIZE_SCALAR(cascadeMode);
371 UNSERIALIZE_SCALAR(cascadeBits);
372 UNSERIALIZE_SCALAR(edgeTriggered);
373 UNSERIALIZE_SCALAR(readIRR);
374 UNSERIALIZE_SCALAR(expectICW4);
375 UNSERIALIZE_SCALAR(initControlWord);
376 UNSERIALIZE_SCALAR(autoEOI);
377}
378
379} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
AddrRangeList getAddrRanges() const override
Determine the address ranges that this device responds to.
Definition io_device.cc:81
virtual std::string name() const
Definition named.hh:47
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition packet.hh:295
Addr getAddr() const
Definition packet.hh:807
void setLE(T v)
Set the value in the data pointer to v as little endian.
unsigned getSize() const
Definition packet.hh:817
void makeAtomicResponse()
Definition packet.hh:1074
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition io_device.cc:59
void signalInterrupt(int line)
Definition i8259.cc:282
void handleEOI(int line)
Definition i8259.cc:254
std::vector< IntSinkPin< I8259 > * > inputs
Definition i8259.hh:53
void raiseInterruptPin(int number)
Definition i8259.cc:297
void lowerInterruptPin(int number)
Definition i8259.cc:309
I8259Params Params
Definition i8259.hh:89
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition i8259.cc:107
std::vector< IntSourcePin< I8259 > * > output
Definition i8259.hh:52
static const int NumLines
Definition i8259.hh:46
I8259(const Params &p)
Definition i8259.cc:42
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition i8259.cc:362
AddrRangeList getAddrRanges() const override
Determine the address ranges that this device responds to.
Definition i8259.cc:60
void requestInterrupt(int line)
Definition i8259.cc:264
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition i8259.cc:71
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition i8259.cc:80
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition i8259.cc:344
AddrRange RangeSize(Addr start, Addr size)
constexpr int findMsbSet(uint64_t val)
Returns the bit position of the MSB that is set in the input.
Definition bitfield.hh:279
constexpr T bits(T val, unsigned first, unsigned last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
Definition bitfield.hh:79
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:200
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:214
#define SERIALIZE_ENUM(scalar)
Definition serialize.hh:591
#define UNSERIALIZE_ARRAY(member, size)
Definition serialize.hh:618
#define SERIALIZE_ARRAY(member, size)
Definition serialize.hh:610
#define UNSERIALIZE_ENUM(scalar)
Definition serialize.hh:598
#define warn(...)
Definition logging.hh:256
Bitfield< 4, 0 > mode
Definition misc_types.hh:74
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 0 > p
Bitfield< 63 > val
Definition misc.hh:804
Bitfield< 3 > mode
Definition types.hh:192
Bitfield< 0 > p
Definition pagetable.hh:151
const Addr PhysAddrIntA
Definition x86_traits.hh:77
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
std::ostream CheckpointOut
Definition serialize.hh:66
uint64_t Tick
Tick count type.
Definition types.hh:58
static void output(const char *filename)
Definition debug.cc:60
std::string csprintf(const char *format, const Args &...args)
Definition cprintf.hh:161
Declaration of the Packet class.
#define UNSERIALIZE_SCALAR(scalar)
Definition serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition serialize.hh:568

Generated on Tue Jun 18 2024 16:24:04 for gem5 by doxygen 1.11.0