gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups 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/uart8250.hh"
36 
37 #include <string>
38 #include <vector>
39 
40 #include "base/inifile.hh"
41 #include "base/trace.hh"
42 #include "config/the_isa.hh"
43 #include "debug/Uart.hh"
44 #include "dev/platform.hh"
45 #include "dev/terminal.hh"
46 #include "mem/packet.hh"
47 #include "mem/packet_access.hh"
48 
49 using namespace std;
50 using namespace TheISA;
51 
53  : uart(u)
54 {
55  DPRINTF(Uart, "UART Interrupt Event Initilizing\n");
56  intrBit = bit;
57 }
58 
59 const char *
61 {
62  return "uart interrupt delay";
63 }
64 
65 void
67 {
68  if (intrBit & uart->IER) {
69  DPRINTF(Uart, "UART InterEvent, interrupting\n");
70  uart->platform->postConsoleInt();
71  uart->status |= intrBit;
72  uart->lastTxInt = curTick();
73  }
74  else
75  DPRINTF(Uart, "UART InterEvent, not interrupting\n");
76 
77 }
78 
79 /* The linux serial driver (8250.c about line 1182) loops reading from
80  * the device until the device reports it has no more data to
81  * read. After a maximum of 255 iterations the code prints "serial8250
82  * too much work for irq X," and breaks out of the loop. Since the
83  * simulated system is so much slower than the actual system, if a
84  * user is typing on the keyboard it is very easy for them to provide
85  * input at a fast enough rate to not allow the loop to exit and thus
86  * the error to be printed. This magic number provides a delay between
87  * the time the UART receives a character to send to the simulated
88  * system and the time it actually notifies the system it has a
89  * character to send to alleviate this problem. --Ali
90  */
91 void
93 {
94  static const Tick interval = 225 * SimClock::Int::ns;
95  DPRINTF(Uart, "Scheduling IER interrupt for %#x, at cycle %lld\n", intrBit,
96  curTick() + interval);
97  if (!scheduled())
98  uart->schedule(this, curTick() + interval);
99  else
100  uart->reschedule(this, curTick() + interval);
101 }
102 
103 
105  : Uart(p, 8), IER(0), DLAB(0), LCR(0), MCR(0), lastTxInt(0),
106  txIntrEvent(this, TX_INT), rxIntrEvent(this, RX_INT)
107 {
108 }
109 
110 Tick
112 {
113  assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
114  assert(pkt->getSize() == 1);
115 
116  Addr daddr = pkt->getAddr() - pioAddr;
117 
118  DPRINTF(Uart, " read register %#x\n", daddr);
119 
120  switch (daddr) {
121  case 0x0:
122  if (!(LCR & 0x80)) { // read byte
123  if (term->dataAvailable())
124  pkt->set(term->in());
125  else {
126  pkt->set((uint8_t)0);
127  // A limited amount of these are ok.
128  DPRINTF(Uart, "empty read of RX register\n");
129  }
130  status &= ~RX_INT;
132 
133  if (term->dataAvailable() && (IER & UART_IER_RDI))
135  } else { // dll divisor latch
136  ;
137  }
138  break;
139  case 0x1:
140  if (!(LCR & 0x80)) { // Intr Enable Register(IER)
141  pkt->set(IER);
142  } else { // DLM divisor latch MSB
143  ;
144  }
145  break;
146  case 0x2: // Intr Identification Register (IIR)
147  DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status);
148 
149  if (status & RX_INT) /* Rx data interrupt has a higher priority */
150  pkt->set(IIR_RXID);
151  else if (status & TX_INT) {
152  pkt->set(IIR_TXID);
153  //Tx interrupts are cleared on IIR reads
154  status &= ~TX_INT;
155  } else
156  pkt->set(IIR_NOPEND);
157 
158  break;
159  case 0x3: // Line Control Register (LCR)
160  pkt->set(LCR);
161  break;
162  case 0x4: // Modem Control Register (MCR)
163  pkt->set(MCR);
164  break;
165  case 0x5: // Line Status Register (LSR)
166  uint8_t lsr;
167  lsr = 0;
168  // check if there are any bytes to be read
169  if (term->dataAvailable())
170  lsr = UART_LSR_DR;
171  lsr |= UART_LSR_TEMT | UART_LSR_THRE;
172  pkt->set(lsr);
173  break;
174  case 0x6: // Modem Status Register (MSR)
175  pkt->set((uint8_t)0);
176  break;
177  case 0x7: // Scratch Register (SCR)
178  pkt->set((uint8_t)0); // doesn't exist with at 8250.
179  break;
180  default:
181  panic("Tried to access a UART port that doesn't exist\n");
182  break;
183  }
184 /* uint32_t d32 = *data;
185  DPRINTF(Uart, "Register read to register %#x returned %#x\n", daddr, d32);
186 */
187  pkt->makeAtomicResponse();
188  return pioDelay;
189 }
190 
191 Tick
193 {
194 
195  assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
196  assert(pkt->getSize() == 1);
197 
198  Addr daddr = pkt->getAddr() - pioAddr;
199 
200  DPRINTF(Uart, " write register %#x value %#x\n", daddr, pkt->get<uint8_t>());
201 
202  switch (daddr) {
203  case 0x0:
204  if (!(LCR & 0x80)) { // write byte
205  term->out(pkt->get<uint8_t>());
207  status &= ~TX_INT;
208  if (UART_IER_THRI & IER)
210  } else { // dll divisor latch
211  ;
212  }
213  break;
214  case 0x1:
215  if (!(LCR & 0x80)) { // Intr Enable Register(IER)
216  IER = pkt->get<uint8_t>();
217  if (UART_IER_THRI & IER)
218  {
219  DPRINTF(Uart, "IER: IER_THRI set, scheduling TX intrrupt\n");
220  if (curTick() - lastTxInt > 225 * SimClock::Int::ns) {
221  DPRINTF(Uart, "-- Interrupting Immediately... %d,%d\n",
222  curTick(), lastTxInt);
224  } else {
225  DPRINTF(Uart, "-- Delaying interrupt... %d,%d\n",
226  curTick(), lastTxInt);
228  }
229  }
230  else
231  {
232  DPRINTF(Uart, "IER: IER_THRI cleared, descheduling TX intrrupt\n");
233  if (txIntrEvent.scheduled())
235  if (status & TX_INT)
237  status &= ~TX_INT;
238  }
239 
240  if ((UART_IER_RDI & IER) && term->dataAvailable()) {
241  DPRINTF(Uart, "IER: IER_RDI set, scheduling RX intrrupt\n");
243  } else {
244  DPRINTF(Uart, "IER: IER_RDI cleared, descheduling RX intrrupt\n");
245  if (rxIntrEvent.scheduled())
247  if (status & RX_INT)
249  status &= ~RX_INT;
250  }
251  } else { // DLM divisor latch MSB
252  ;
253  }
254  break;
255  case 0x2: // FIFO Control Register (FCR)
256  break;
257  case 0x3: // Line Control Register (LCR)
258  LCR = pkt->get<uint8_t>();
259  break;
260  case 0x4: // Modem Control Register (MCR)
261  if (pkt->get<uint8_t>() == (UART_MCR_LOOP | 0x0A))
262  MCR = 0x9A;
263  break;
264  case 0x7: // Scratch Register (SCR)
265  // We are emulating a 8250 so we don't have a scratch reg
266  break;
267  default:
268  panic("Tried to access a UART port that doesn't exist\n");
269  break;
270  }
271  pkt->makeAtomicResponse();
272  return pioDelay;
273 }
274 
275 void
277 {
278  // if the kernel wants an interrupt when we have data
279  if (IER & UART_IER_RDI)
280  {
282  status |= RX_INT;
283  }
284 
285 }
286 
289 {
290  AddrRangeList ranges;
291  ranges.push_back(RangeSize(pioAddr, pioSize));
292  return ranges;
293 }
294 
295 void
297 {
303  Tick rxintrwhen;
304  if (rxIntrEvent.scheduled())
305  rxintrwhen = rxIntrEvent.when();
306  else
307  rxintrwhen = 0;
308  Tick txintrwhen;
309  if (txIntrEvent.scheduled())
310  txintrwhen = txIntrEvent.when();
311  else
312  txintrwhen = 0;
313  SERIALIZE_SCALAR(rxintrwhen);
314  SERIALIZE_SCALAR(txintrwhen);
315 }
316 
317 void
319 {
325  Tick rxintrwhen;
326  Tick txintrwhen;
327  UNSERIALIZE_SCALAR(rxintrwhen);
328  UNSERIALIZE_SCALAR(txintrwhen);
329  if (rxintrwhen != 0)
330  schedule(rxIntrEvent, rxintrwhen);
331  if (txintrwhen != 0)
332  schedule(txIntrEvent, txintrwhen);
333 }
334 
335 Uart8250 *
336 Uart8250Params::create()
337 {
338  return new Uart8250(this);
339 }
#define DPRINTF(x,...)
Definition: trace.hh:212
AddrRange RangeSize(Addr start, Addr size)
Definition: addr_range.hh:398
const uint8_t UART_IER_THRI
Definition: uart8250.hh:56
void set(T v, ByteOrder endian)
Set the value in the data pointer to v using the specified endianness.
Terminal * term
Definition: uart.hh:52
Defines a 8250 UART.
uint8_t IER
Definition: uart8250.hh:73
#define panic(...)
Definition: misc.hh:153
IntrEvent rxIntrEvent
Definition: uart8250.hh:89
const uint8_t UART_IER_RDI
Definition: uart8250.hh:55
virtual void process()
Definition: uart8250.cc:66
void dataAvailable() override
Inform the uart that there is data available.
Definition: uart8250.cc:276
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: uart8250.cc:318
const uint8_t UART_LSR_TEMT
Definition: uart8250.hh:60
uint8_t LCR
Definition: uart8250.hh:73
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:381
PioDeviceParams Params
Definition: io_device.hh:116
IntrEvent(Uart8250 *u, int bit)
Definition: uart8250.cc:52
const uint8_t UART_MCR_LOOP
Definition: uart8250.hh:64
void deschedule(Event &event)
Definition: eventq.hh:734
T get(ByteOrder endian) const
Get the data in the packet byte swapped from the specified endianness.
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: uart8250.cc:192
virtual const char * description() const
Return a C string describing the event.
Definition: uart8250.cc:60
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:145
Tick curTick()
The current simulated tick.
Definition: core.hh:47
int status
Definition: uart.hh:50
Addr pioSize
Size that the device's address range.
Definition: io_device.hh:142
Bitfield< 22 > u
Definition: miscregs.hh:1537
virtual void clearConsoleInt()=0
Clear a posted CPU interrupt.
uint8_t MCR
Definition: uart8250.hh:73
Uart8250(const Params *p)
Definition: uart8250.cc:104
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:397
IntrEvent txIntrEvent
Definition: uart8250.hh:88
void makeAtomicResponse()
Definition: packet.hh:857
uint64_t Tick
Tick count type.
Definition: types.hh:63
const uint8_t IIR_TXID
Definition: uart8250.hh:51
uint8_t in()
Definition: terminal.cc:285
void out(char c)
Definition: terminal.cc:317
AddrRangeList getAddrRanges() const override
Determine the address ranges that this device responds to.
Definition: uart8250.cc:288
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: uart8250.cc:111
bool dataAvailable()
Definition: terminal.hh:157
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:245
const int RX_INT
Definition: uart.hh:44
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:143
virtual void postConsoleInt()=0
Cause the cpu to post a serial interrupt to the CPU.
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:67
Tick lastTxInt
Definition: uart8250.hh:74
Tick pioDelay
Delay that the device experinces on an access.
Definition: io_device.hh:145
void schedule(Event &event, Tick when)
Definition: eventq.hh:728
Tick ns
nanosecond
Definition: core.cc:66
unsigned getSize() const
Definition: packet.hh:649
uint8_t DLAB
Definition: uart8250.hh:73
Definition: uart.hh:47
Bitfield< 0 > p
Platform * platform
Definition: uart.hh:51
Addr pioAddr
Address that the device listens to.
Definition: io_device.hh:139
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:296
const int TX_INT
Definition: uart.hh:45
Addr getAddr() const
Definition: packet.hh:639

Generated on Fri Jun 9 2017 13:03:47 for gem5 by doxygen 1.8.6