gem5  v20.1.0.0
uart8250.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 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 
33 #include "dev/serial/uart8250.hh"
34 
35 #include <string>
36 #include <vector>
37 
38 #include "base/inifile.hh"
39 #include "base/trace.hh"
40 #include "debug/Uart.hh"
41 #include "dev/platform.hh"
42 #include "mem/packet.hh"
43 #include "mem/packet_access.hh"
44 
45 using namespace std;
46 
47 void
49 {
50  if (intrBit & IER) {
51  DPRINTF(Uart, "UART InterEvent, interrupting\n");
52  platform->postConsoleInt();
53  status |= intrBit;
54  lastTxInt = curTick();
55  }
56  else
57  DPRINTF(Uart, "UART InterEvent, not interrupting\n");
58 
59 }
60 
61 /* The linux serial driver (8250.c about line 1182) loops reading from
62  * the device until the device reports it has no more data to
63  * read. After a maximum of 255 iterations the code prints "serial8250
64  * too much work for irq X," and breaks out of the loop. Since the
65  * simulated system is so much slower than the actual system, if a
66  * user is typing on the keyboard it is very easy for them to provide
67  * input at a fast enough rate to not allow the loop to exit and thus
68  * the error to be printed. This magic number provides a delay between
69  * the time the UART receives a character to send to the simulated
70  * system and the time it actually notifies the system it has a
71  * character to send to alleviate this problem. --Ali
72  */
73 void
75 {
76  static const Tick interval = 225 * SimClock::Int::ns;
77  DPRINTF(Uart, "Scheduling IER interrupt for %s, at cycle %lld\n",
78  event->name(), curTick() + interval);
79  if (!event->scheduled())
80  schedule(event, curTick() + interval);
81  else
82  reschedule(event, curTick() + interval);
83 }
84 
85 
87  : Uart(p, 8), IER(0), DLAB(0), LCR(0), MCR(0), lastTxInt(0),
88  txIntrEvent([this]{ processIntrEvent(TX_INT); }, "TX"),
89  rxIntrEvent([this]{ processIntrEvent(RX_INT); }, "RX")
90 {
91 }
92 
93 Tick
95 {
96  assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
97  assert(pkt->getSize() == 1);
98 
99  Addr daddr = pkt->getAddr() - pioAddr;
100 
101  DPRINTF(Uart, " read register %#x\n", daddr);
102 
103  switch (daddr) {
104  case 0x0:
105  if (!(LCR & 0x80)) { // read byte
106  if (device->dataAvailable())
107  pkt->setRaw(device->readData());
108  else {
109  pkt->setRaw((uint8_t)0);
110  // A limited amount of these are ok.
111  DPRINTF(Uart, "empty read of RX register\n");
112  }
113  status &= ~RX_INT;
115 
116  if (device->dataAvailable() && (IER & UART_IER_RDI))
118  } else { // dll divisor latch
119  ;
120  }
121  break;
122  case 0x1:
123  if (!(LCR & 0x80)) { // Intr Enable Register(IER)
124  pkt->setRaw(IER);
125  } else { // DLM divisor latch MSB
126  ;
127  }
128  break;
129  case 0x2: // Intr Identification Register (IIR)
130  DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status);
131 
132  if (status & RX_INT) /* Rx data interrupt has a higher priority */
133  pkt->setRaw(IIR_RXID);
134  else if (status & TX_INT) {
135  pkt->setRaw(IIR_TXID);
136  //Tx interrupts are cleared on IIR reads
137  status &= ~TX_INT;
138  } else
139  pkt->setRaw(IIR_NOPEND);
140 
141  break;
142  case 0x3: // Line Control Register (LCR)
143  pkt->setRaw(LCR);
144  break;
145  case 0x4: // Modem Control Register (MCR)
146  pkt->setRaw(MCR);
147  break;
148  case 0x5: // Line Status Register (LSR)
149  uint8_t lsr;
150  lsr = 0;
151  // check if there are any bytes to be read
152  if (device->dataAvailable())
153  lsr = UART_LSR_DR;
154  lsr |= UART_LSR_TEMT | UART_LSR_THRE;
155  pkt->setRaw(lsr);
156  break;
157  case 0x6: // Modem Status Register (MSR)
158  pkt->setRaw((uint8_t)0);
159  break;
160  case 0x7: // Scratch Register (SCR)
161  pkt->setRaw((uint8_t)0); // doesn't exist with at 8250.
162  break;
163  default:
164  panic("Tried to access a UART port that doesn't exist\n");
165  break;
166  }
167 /* uint32_t d32 = *data;
168  DPRINTF(Uart, "Register read to register %#x returned %#x\n", daddr, d32);
169 */
170  pkt->makeAtomicResponse();
171  return pioDelay;
172 }
173 
174 Tick
176 {
177 
178  assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
179  assert(pkt->getSize() == 1);
180 
181  Addr daddr = pkt->getAddr() - pioAddr;
182 
183  DPRINTF(Uart, " write register %#x value %#x\n", daddr,
184  pkt->getRaw<uint8_t>());
185 
186  switch (daddr) {
187  case 0x0:
188  if (!(LCR & 0x80)) { // write byte
189  device->writeData(pkt->getRaw<uint8_t>());
191  status &= ~TX_INT;
192  if (UART_IER_THRI & IER)
194  } else { // dll divisor latch
195  ;
196  }
197  break;
198  case 0x1:
199  if (!(LCR & 0x80)) { // Intr Enable Register(IER)
200  IER = pkt->getRaw<uint8_t>();
201  if (UART_IER_THRI & IER)
202  {
203  DPRINTF(Uart,
204  "IER: IER_THRI set, scheduling TX intrrupt\n");
205  if (curTick() - lastTxInt > 225 * SimClock::Int::ns) {
206  DPRINTF(Uart, "-- Interrupting Immediately... %d,%d\n",
207  curTick(), lastTxInt);
209  } else {
210  DPRINTF(Uart, "-- Delaying interrupt... %d,%d\n",
211  curTick(), lastTxInt);
213  }
214  }
215  else
216  {
217  DPRINTF(Uart, "IER: IER_THRI cleared, "
218  "descheduling TX intrrupt\n");
219  if (txIntrEvent.scheduled())
221  if (status & TX_INT)
223  status &= ~TX_INT;
224  }
225 
226  if ((UART_IER_RDI & IER) && device->dataAvailable()) {
227  DPRINTF(Uart,
228  "IER: IER_RDI set, scheduling RX intrrupt\n");
230  } else {
231  DPRINTF(Uart, "IER: IER_RDI cleared, "
232  "descheduling RX intrrupt\n");
233  if (rxIntrEvent.scheduled())
235  if (status & RX_INT)
237  status &= ~RX_INT;
238  }
239  } else { // DLM divisor latch MSB
240  ;
241  }
242  break;
243  case 0x2: // FIFO Control Register (FCR)
244  break;
245  case 0x3: // Line Control Register (LCR)
246  LCR = pkt->getRaw<uint8_t>();
247  break;
248  case 0x4: // Modem Control Register (MCR)
249  if (pkt->getRaw<uint8_t>() == (UART_MCR_LOOP | 0x0A))
250  MCR = 0x9A;
251  break;
252  case 0x7: // Scratch Register (SCR)
253  // We are emulating a 8250 so we don't have a scratch reg
254  break;
255  default:
256  panic("Tried to access a UART port that doesn't exist\n");
257  break;
258  }
259  pkt->makeAtomicResponse();
260  return pioDelay;
261 }
262 
263 void
265 {
266  // if the kernel wants an interrupt when we have data
267  if (IER & UART_IER_RDI)
268  {
270  status |= RX_INT;
271  }
272 
273 }
274 
277 {
278  AddrRangeList ranges;
279  ranges.push_back(RangeSize(pioAddr, pioSize));
280  return ranges;
281 }
282 
283 void
285 {
291  Tick rxintrwhen;
292  if (rxIntrEvent.scheduled())
293  rxintrwhen = rxIntrEvent.when();
294  else
295  rxintrwhen = 0;
296  Tick txintrwhen;
297  if (txIntrEvent.scheduled())
298  txintrwhen = txIntrEvent.when();
299  else
300  txintrwhen = 0;
301  SERIALIZE_SCALAR(rxintrwhen);
302  SERIALIZE_SCALAR(txintrwhen);
303 }
304 
305 void
307 {
313  Tick rxintrwhen;
314  Tick txintrwhen;
315  UNSERIALIZE_SCALAR(rxintrwhen);
316  UNSERIALIZE_SCALAR(txintrwhen);
317  if (rxintrwhen != 0)
318  schedule(rxIntrEvent, rxintrwhen);
319  if (txintrwhen != 0)
320  schedule(txIntrEvent, txintrwhen);
321 }
322 
323 Uart8250 *
324 Uart8250Params::create()
325 {
326  return new Uart8250(this);
327 }
ArmISA::status
Bitfield< 5, 0 > status
Definition: miscregs_types.hh:417
Event::scheduled
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:460
Packet::makeAtomicResponse
void makeAtomicResponse()
Definition: packet.hh:1016
BasicPioDevice::pioAddr
Addr pioAddr
Address that the device listens to.
Definition: io_device.hh:154
SimClock::Int::ns
Tick ns
nanosecond
Definition: core.cc:65
Uart8250::DLAB
uint8_t DLAB
Definition: uart8250.hh:71
UNSERIALIZE_SCALAR
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:797
Packet::getAddr
Addr getAddr() const
Definition: packet.hh:754
IER
@ IER
Definition: ns_gige_reg.h:45
Packet::setRaw
void setRaw(T v)
Set the value in the data pointer to v without byte swapping.
Definition: packet_access.hh:58
uart8250.hh
Tick
uint64_t Tick
Tick count type.
Definition: types.hh:63
Uart8250::processIntrEvent
void processIntrEvent(int intrBit)
Definition: uart8250.cc:48
EventManager::deschedule
void deschedule(Event &event)
Definition: eventq.hh:1014
Packet::getSize
unsigned getSize() const
Definition: packet.hh:764
Event::when
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:503
IIR_RXID
const uint8_t IIR_RXID
Definition: uart8250.hh:50
Platform::clearConsoleInt
virtual void clearConsoleInt()=0
Clear a posted CPU interrupt.
packet.hh
Uart8250::txIntrEvent
EventFunctionWrapper txIntrEvent
Definition: uart8250.hh:77
Uart8250::getAddrRanges
AddrRangeList getAddrRanges() const override
Determine the address ranges that this device responds to.
Definition: uart8250.cc:276
Uart8250::MCR
uint8_t MCR
Definition: uart8250.hh:71
Uart8250::Uart8250
Uart8250(const Params *p)
Definition: uart8250.cc:86
Uart8250::write
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: uart8250.cc:175
cp
Definition: cprintf.cc:40
EventManager::schedule
void schedule(Event &event, Tick when)
Definition: eventq.hh:1005
Uart
Definition: uart.hh:46
Event
Definition: eventq.hh:246
SerialDevice::dataAvailable
virtual bool dataAvailable() const =0
Check if there is pending data from the serial device.
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:234
Uart8250
Definition: uart8250.hh:68
Uart::device
SerialDevice * device
Definition: uart.hh:51
MipsISA::event
Bitfield< 10, 5 > event
Definition: pra_constants.hh:297
RangeSize
AddrRange RangeSize(Addr start, Addr size)
Definition: addr_range.hh:638
PioDevice::Params
PioDeviceParams Params
Definition: io_device.hh:131
UART_LSR_TEMT
const uint8_t UART_LSR_TEMT
Definition: uart8250.hh:58
BasicPioDevice::pioSize
Addr pioSize
Size that the device's address range.
Definition: io_device.hh:157
Platform::postConsoleInt
virtual void postConsoleInt()=0
Cause the cpu to post a serial interrupt to the CPU.
inifile.hh
Uart::status
int status
Definition: uart.hh:49
IIR_NOPEND
const uint8_t IIR_NOPEND
Definition: uart8250.hh:45
TX_INT
const int TX_INT
Definition: uart.hh:44
SerialDevice::readData
virtual uint8_t readData()=0
Read a character from the device.
Uart8250::read
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: uart8250.cc:94
platform.hh
Uart8250::scheduleIntr
void scheduleIntr(Event *event)
Definition: uart8250.cc:74
Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
IIR_TXID
const uint8_t IIR_TXID
Definition: uart8250.hh:49
Uart8250::lastTxInt
Tick lastTxInt
Definition: uart8250.hh:72
SERIALIZE_SCALAR
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:790
Uart8250::rxIntrEvent
EventFunctionWrapper rxIntrEvent
Definition: uart8250.hh:78
packet_access.hh
EventFunctionWrapper::process
void process()
Definition: eventq.hh:1127
UART_IER_RDI
const uint8_t UART_IER_RDI
Definition: uart8250.hh:53
Packet::getRaw
T getRaw() const
Get the data in the packet without byte swapping.
Definition: packet_access.hh:49
Uart8250::serialize
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: uart8250.cc:284
RX_INT
const int RX_INT
Definition: uart.hh:43
Uart8250::IER
uint8_t IER
Definition: uart8250.hh:71
std
Overload hash function for BasicBlockRange type.
Definition: vec_reg.hh:587
UART_MCR_LOOP
const uint8_t UART_MCR_LOOP
Definition: uart8250.hh:62
UART_IER_THRI
const uint8_t UART_IER_THRI
Definition: uart8250.hh:54
Packet
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:257
Uart8250::dataAvailable
void dataAvailable() override
Inform the uart that there is data available.
Definition: uart8250.cc:264
BasicPioDevice::pioDelay
Tick pioDelay
Delay that the device experinces on an access.
Definition: io_device.hh:160
CheckpointOut
std::ostream CheckpointOut
Definition: serialize.hh:63
SerialDevice::writeData
virtual void writeData(uint8_t c)=0
Transmit a character from the host interface to the device.
trace.hh
MipsISA::p
Bitfield< 0 > p
Definition: pra_constants.hh:323
std::list< AddrRange >
CheckpointIn
Definition: serialize.hh:67
UART_LSR_DR
const uint8_t UART_LSR_DR
Definition: uart8250.hh:60
Uart8250::unserialize
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: uart8250.cc:306
Uart8250::LCR
uint8_t LCR
Definition: uart8250.hh:71
UART_LSR_THRE
const uint8_t UART_LSR_THRE
Definition: uart8250.hh:59
panic
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:171
Uart::platform
Platform * platform
Definition: uart.hh:50
curTick
Tick curTick()
The current simulated tick.
Definition: core.hh:45

Generated on Wed Sep 30 2020 14:02:11 for gem5 by doxygen 1.8.17