gem5  v22.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 #include "sim/serialize.hh"
45 
46 namespace gem5
47 {
48 
49 void
51 {
52  if (intrBit & registers.ier.get()) {
53  DPRINTF(Uart, "UART InterEvent, interrupting\n");
54  platform->postConsoleInt();
55  status |= intrBit;
56  lastTxInt = curTick();
57  } else {
58  DPRINTF(Uart, "UART InterEvent, not interrupting\n");
59  }
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 * sim_clock::as_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, p.pio_size), registers(this, name() + ".registers"),
90  lastTxInt(0),
91  txIntrEvent([this]{ processIntrEvent(TX_INT); }, "TX"),
92  rxIntrEvent([this]{ processIntrEvent(RX_INT); }, "RX")
93 {
94 }
95 
96 Uart8250::Registers::Registers(Uart8250 *uart, const std::string &new_name) :
97  RegisterBankLE(new_name, 0), rbrThr(rbr, thr), rbrThrDll(rbrThr, dll),
98  ierDlh(ier, dlh), iirFcr(iir, fcr)
99 {
100  rbr.reader(uart, &Uart8250::readRbr);
101  thr.writer(uart, &Uart8250::writeThr);
102  ier.writer(uart, &Uart8250::writeIer);
103  iir.reader(uart, &Uart8250::readIir);
104 
105  lcr.writer([this](auto &reg, const auto &value) {
106  reg.update(value);
107  rbrThrDll.select(value.dlab);
108  ierDlh.select(value.dlab);
109  });
110 
111  mcr.writer([](auto &reg, const auto &value) {
112  if (value == (UART_MCR_LOOP | 0x0A))
113  reg.update(0x9A);
114  });
115 
116  lsr.readonly().
117  reader([device = uart->device](auto &reg) {
118  Lsr lsr = 0;
119  if (device->dataAvailable())
120  lsr.rdr = 1;
121  lsr.tbe = 1;
122  lsr.txEmpty = 1;
123  return lsr;
124  });
125 
126  msr.readonly();
127 
129 }
130 
131 uint8_t
133 {
134  uint8_t data = 0;
135  if (device->dataAvailable())
136  data = device->readData();
137  else
138  DPRINTF(Uart, "empty read of RX register\n");
139 
140  status &= ~RX_INT;
141  platform->clearConsoleInt();
142 
143  if (device->dataAvailable() && registers.ier.get().rdi)
145 
146  return data;
147 }
148 
149 void
151 {
153  platform->clearConsoleInt();
154  status &= ~TX_INT;
155  if (registers.ier.get().thri)
157 }
158 
159 Uart8250::Iir
161 {
162  DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status);
163 
164  Iir iir = 0;
165  if (status & RX_INT) {
166  // Rx data interrupt has a higher priority.
167  iir.id = (uint8_t)InterruptIds::Rx;
168  } else if (status & TX_INT) {
169  iir.id = (uint8_t)InterruptIds::Tx;
170  // Tx interrupts are cleared on IIR reads.
171  status &= ~TX_INT;
172  } else {
173  iir.pending = 1;
174  }
175  return iir;
176 }
177 
178 void
180 {
181  reg.update(ier);
182 
183  if (ier.thri) {
184  DPRINTF(Uart, "IER: IER_THRI set, scheduling TX intrrupt\n");
185  if (curTick() - lastTxInt > 225 * sim_clock::as_int::ns) {
186  DPRINTF(Uart, "-- Interrupting Immediately... %d,%d\n",
187  curTick(), lastTxInt);
189  } else {
190  DPRINTF(Uart, "-- Delaying interrupt... %d,%d\n",
191  curTick(), lastTxInt);
193  }
194  } else {
195  DPRINTF(Uart, "IER: IER_THRI cleared, descheduling TX intrrupt\n");
196  if (txIntrEvent.scheduled())
198  if (status & TX_INT)
199  platform->clearConsoleInt();
200  status &= ~TX_INT;
201  }
202 
203  if (ier.rdi && device->dataAvailable()) {
204  DPRINTF(Uart, "IER: IER_RDI set, scheduling RX intrrupt\n");
206  } else {
207  DPRINTF(Uart, "IER: IER_RDI cleared, descheduling RX intrrupt\n");
208  if (rxIntrEvent.scheduled())
210  if (status & RX_INT)
211  platform->clearConsoleInt();
212  status &= ~RX_INT;
213  }
214 }
215 
216 Tick
218 {
219  Addr daddr = pkt->getAddr() - pioAddr;
220 
221  DPRINTF(Uart, "Read register %#x\n", daddr);
222 
223  registers.read(daddr, pkt->getPtr<void>(), pkt->getSize());
224 
225  pkt->makeAtomicResponse();
226  return pioDelay;
227 }
228 
229 Tick
231 {
232  Addr daddr = pkt->getAddr() - pioAddr;
233 
234  DPRINTF(Uart, "Write register %#x value %#x\n", daddr,
235  pkt->getRaw<uint8_t>());
236 
237  registers.write(daddr, pkt->getPtr<void>(), pkt->getSize());
238 
239  pkt->makeAtomicResponse();
240  return pioDelay;
241 }
242 
243 void
245 {
246  // If the kernel wants an interrupt when we have data.
247  if (registers.ier.get().rdi) {
248  platform->postConsoleInt();
249  status |= RX_INT;
250  }
251 
252 }
253 
256 {
257  AddrRangeList ranges;
258  ranges.push_back(RangeSize(pioAddr, pioSize));
259  return ranges;
260 }
261 
262 void
264 {
266  paramOut(cp, "IER", registers.ier);
267  paramOut(cp, "LCR", registers.lcr);
268  paramOut(cp, "MCR", registers.mcr);
269  Tick rxintrwhen;
270  if (rxIntrEvent.scheduled())
271  rxintrwhen = rxIntrEvent.when();
272  else
273  rxintrwhen = 0;
274  Tick txintrwhen;
275  if (txIntrEvent.scheduled())
276  txintrwhen = txIntrEvent.when();
277  else
278  txintrwhen = 0;
279  SERIALIZE_SCALAR(rxintrwhen);
280  SERIALIZE_SCALAR(txintrwhen);
281 }
282 
283 void
285 {
287  paramIn(cp, "IER", registers.ier);
288  paramIn(cp, "LCR", registers.lcr);
289  paramIn(cp, "MCR", registers.mcr);
290  Tick rxintrwhen;
291  Tick txintrwhen;
292  UNSERIALIZE_SCALAR(rxintrwhen);
293  UNSERIALIZE_SCALAR(txintrwhen);
294  if (rxintrwhen != 0)
295  schedule(rxIntrEvent, rxintrwhen);
296  if (txintrwhen != 0)
297  schedule(txIntrEvent, txintrwhen);
298 }
299 
300 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
const char data[]
Addr pioAddr
Address that the device listens to.
Definition: io_device.hh:151
Tick pioDelay
Delay that the device experinces on an access.
Definition: io_device.hh:157
Addr pioSize
Size that the device's address range.
Definition: io_device.hh:154
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:294
T * getPtr()
get a pointer to the data ptr.
Definition: packet.hh:1212
Addr getAddr() const
Definition: packet.hh:805
unsigned getSize() const
Definition: packet.hh:815
T getRaw() const
Get the data in the packet without byte swapping.
void makeAtomicResponse()
Definition: packet.hh:1071
PioDeviceParams Params
Definition: io_device.hh:134
void addRegisters(std::initializer_list< std::reference_wrapper< RegisterBase >> regs)
Definition: reg_bank.hh:809
virtual void read(Addr addr, void *buf, Addr bytes)
Definition: reg_bank.hh:827
virtual void write(Addr addr, const void *buf, Addr bytes)
Definition: reg_bank.hh:884
virtual uint8_t readData()=0
Read a character from the device.
virtual void writeData(uint8_t c)=0
Transmit a character from the host interface to the device.
virtual bool dataAvailable() const =0
Check if there is pending data from the serial device.
Register< Lcr > lcr
Definition: uart8250.hh:188
Register< Ier > ier
Definition: uart8250.hh:178
Register< Lsr > lsr
Definition: uart8250.hh:190
BankedRegister ierDlh
Definition: uart8250.hh:180
BankedRegister rbrThrDll
Definition: uart8250.hh:175
Registers(Uart8250 *uart, const std::string &new_name)
Definition: uart8250.cc:96
RWSwitchedRegister iirFcr
Definition: uart8250.hh:185
Register< Iir > iir
Definition: uart8250.hh:183
Iir readIir(Register< Iir > &reg)
Definition: uart8250.cc:160
EventFunctionWrapper txIntrEvent
Definition: uart8250.hh:212
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: uart8250.cc:263
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: uart8250.cc:284
void writeThr(Register8 &reg, const uint8_t &data)
Definition: uart8250.cc:150
Registers registers
Definition: uart8250.hh:200
EventFunctionWrapper rxIntrEvent
Definition: uart8250.hh:213
void dataAvailable() override
Inform the uart that there is data available.
Definition: uart8250.cc:244
Uart8250(const Params &p)
Definition: uart8250.cc:88
AddrRangeList getAddrRanges() const override
Determine the address ranges that this device responds to.
Definition: uart8250.cc:255
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: uart8250.cc:230
void scheduleIntr(Event *event)
Definition: uart8250.cc:76
Registers::Register< T > Register
Definition: uart8250.hh:198
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: uart8250.cc:217
Registers::Register8 Register8
Definition: uart8250.hh:196
uint8_t readRbr(Register8 &reg)
Definition: uart8250.cc:132
void processIntrEvent(int intrBit)
Definition: uart8250.cc:50
void writeIer(Register< Ier > &reg, const Ier &ier)
Definition: uart8250.cc:179
SerialDevice * device
Definition: uart.hh:54
Platform * platform
Definition: uart.hh:53
int status
Definition: uart.hh:52
AddrRange RangeSize(Addr start, Addr size)
Definition: addr_range.hh:815
void deschedule(Event &event)
Definition: eventq.hh:1028
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:465
void schedule(Event &event, Tick when)
Definition: eventq.hh:1019
void reschedule(Event &event, Tick when, bool always=false)
Definition: eventq.hh:1037
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:508
Declaration of IniFile object.
Bitfield< 10, 5 > event
Bitfield< 54 > p
Definition: pagetable.hh:70
Bitfield< 5, 3 > reg
Definition: types.hh:92
Tick ns
nanosecond
Definition: core.cc:71
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
const int RX_INT
Definition: uart.hh:46
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
std::ostream CheckpointOut
Definition: serialize.hh:66
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
void paramOut(CheckpointOut &cp, const std::string &name, ExtMachInst const &machInst)
Definition: types.cc:40
void paramIn(CheckpointIn &cp, const std::string &name, ExtMachInst &machInst)
Definition: types.cc:72
uint64_t Tick
Tick count type.
Definition: types.hh:58
const uint8_t UART_MCR_LOOP
Definition: uart8250.hh:46
const int TX_INT
Definition: uart.hh:47
Declaration of the Packet class.
Generic interface for platforms.
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:568
const std::string & name()
Definition: trace.cc:49
Defines a 8250 UART.

Generated on Wed Dec 21 2022 10:22:35 for gem5 by doxygen 1.9.1