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

Generated on Fri Feb 28 2020 16:27:01 for gem5 by doxygen 1.8.13