gem5  v22.1.0.0
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 
31 #include "arch/x86/x86_traits.hh"
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 
39 namespace 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 
70 void
72 {
74 
75  for (auto *input: inputs)
76  pinStates[input->getId()] = input->state();
77 }
78 
79 Tick
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 
106 Tick
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:
132  DPRINTF(I8259,
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 
253 void
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 
263 void
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 
281 void
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 
296 void
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 
308 void
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 
318 int
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 
343 void
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 
361 void
363 {
364  UNSERIALIZE_ARRAY(pinStates, NumLines);
366  UNSERIALIZE_SCALAR(IRR);
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:186
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:294
Addr getAddr() const
Definition: packet.hh:805
void setLE(T v)
Set the value in the data pointer to v as little endian.
unsigned getSize() const
Definition: packet.hh:815
void makeAtomicResponse()
Definition: packet.hh:1071
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
PioDeviceParams Params
Definition: io_device.hh:134
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
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)
Definition: addr_range.hh:815
constexpr int findMsbSet(uint64_t val)
Returns the bit position of the MSB that is set in the input.
Definition: bitfield.hh:260
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:76
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:204
#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:246
Bitfield< 4, 0 > mode
Definition: misc_types.hh:74
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 54 > p
Definition: pagetable.hh:70
Bitfield< 63 > val
Definition: misc.hh:776
Bitfield< 3 > mode
Definition: types.hh:192
Bitfield< 0 > p
Definition: pagetable.hh:151
const Addr PhysAddrIntA
Definition: x86_traits.hh:76
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
std::ostream CheckpointOut
Definition: serialize.hh:66
@ ISR
Definition: ns_gige_reg.h:47
@ IMR
Definition: ns_gige_reg.h:48
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 Wed Dec 21 2022 10:22:35 for gem5 by doxygen 1.9.1