2 * Copyright (c) 2004 The Regents of The University of Michigan
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.
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.
30 * Implements a 8250 UART
36 #include "base/inifile.hh"
37 #include "base/str.hh" // for to_number
38 #include "base/trace.hh"
39 #include "dev/simconsole.hh"
40 #include "dev/uart.hh"
41 #include "dev/platform.hh"
42 #include "mem/bus/bus.hh"
43 #include "mem/bus/pio_interface.hh"
44 #include "mem/bus/pio_interface_impl.hh"
45 #include "mem/functional_mem/memory_control.hh"
46 #include "sim/builder.hh"
50 Uart::IntrEvent::IntrEvent(Uart
*u
, int bit
)
51 : Event(&mainEventQueue
), uart(u
)
53 DPRINTF(Uart
, "UART Interrupt Event Initilizing\n");
58 Uart::IntrEvent::description()
60 return "uart interrupt delay event";
64 Uart::IntrEvent::process()
66 if (intrBit
& uart
->IER
) {
67 DPRINTF(Uart
, "UART InterEvent, interrupting\n");
68 uart
->platform
->postConsoleInt();
69 uart
->status
|= intrBit
;
72 DPRINTF(Uart
, "UART InterEvent, not interrupting\n");
76 /* The linux serial driver (8250.c about line 1182) loops reading from
77 * the device until the device reports it has no more data to
78 * read. After a maximum of 255 iterations the code prints "serial8250
79 * too much work for irq X," and breaks out of the loop. Since the
80 * simulated system is so much slower than the actual system, if a
81 * user is typing on the keyboard it is very easy for them to provide
82 * input at a fast enough rate to not allow the loop to exit and thus
83 * the error to be printed. This magic number provides a delay between
84 * the time the UART receives a character to send to the simulated
85 * system and the time it actually notifies the system it has a
86 * character to send to alleviate this problem. --Ali
89 Uart::IntrEvent::scheduleIntr()
91 static const Tick interval
= (Tick
)((Clock::Float::s
/ 2e9
) * 450);
92 DPRINTF(Uart
, "Scheduling IER interrupt for %#x, at cycle %lld\n", intrBit
,
95 schedule(curTick
+ interval
);
97 reschedule(curTick
+ interval
);
100 Uart::Uart(const string
&name
, SimConsole
*c
, MemoryController
*mmu
, Addr a
,
101 Addr s
, HierParams
*hier
, Bus
*bus
, Tick pio_latency
, Platform
*p
)
102 : PioDevice(name
, p
), addr(a
), size(s
), cons(c
),
103 txIntrEvent(this, TX_INT
), rxIntrEvent(this, RX_INT
)
105 mmu
->add_child(this, RangeSize(addr
, size
));
109 pioInterface
= newPioInterface(name
, hier
, bus
, this,
111 pioInterface
->addAddrRange(RangeSize(addr
, size
));
112 pioLatency
= pio_latency
* bus
->clockRatio
;
124 platform
->uart
= this;
129 Uart::read(MemReqPtr
&req
, uint8_t *data
)
131 Addr daddr
= req
->paddr
- (addr
& EV5::PAddrImplMask
);
132 DPRINTF(Uart
, " read register %#x\n", daddr
);
139 case sizeof(uint64_t):
140 *(uint64_t *)data
= 0;
142 case sizeof(uint32_t):
143 *(uint32_t *)data
= 0;
145 case sizeof(uint16_t):
146 *(uint16_t *)data
= 0;
148 case sizeof(uint8_t):
149 *(uint8_t *)data
= 0;
154 case 0x80: // Status Register
159 else if (status
& RX_INT
)
162 DPRINTF(Uart
, "spurious read\n");
171 case 0xc0: // Data register (RX)
172 if (!cons
->dataAvailable())
173 panic("No data to read");
177 if (!cons
->dataAvailable()) {
178 platform
->clearConsoleInt();
182 DPRINTF(Uart
, "read data register \'%c\' %2x\n",
183 isprint(*data
) ? *data
: ' ', *data
);
191 assert(req
->size
== 1);
195 if (!(LCR
& 0x80)) { // read byte
196 if (cons
->dataAvailable())
200 // A limited amount of these are ok.
201 DPRINTF(Uart
, "empty read of RX register\n");
204 platform
->clearConsoleInt();
206 if (cons
->dataAvailable() && (IER
& UART_IER_RDI
))
207 rxIntrEvent
.scheduleIntr();
208 } else { // dll divisor latch
213 if (!(LCR
& 0x80)) { // Intr Enable Register(IER)
214 *(uint8_t*)data
= IER
;
215 } else { // DLM divisor latch MSB
219 case 0x2: // Intr Identification Register (IIR)
220 DPRINTF(Uart
, "IIR Read, status = %#x\n", (uint32_t)status
);
226 case 0x3: // Line Control Register (LCR)
227 *(uint8_t*)data
= LCR
;
229 case 0x4: // Modem Control Register (MCR)
231 case 0x5: // Line Status Register (LSR)
234 // check if there are any bytes to be read
235 if (cons
->dataAvailable())
237 lsr
|= UART_LSR_TEMT
| UART_LSR_THRE
;
238 *(uint8_t*)data
= lsr
;
240 case 0x6: // Modem Status Register (MSR)
243 case 0x7: // Scratch Register (SCR)
244 *(uint8_t*)data
= 0; // doesn't exist with at 8250.
247 panic("Tried to access a UART port that doesn't exist\n");
257 Uart::write(MemReqPtr
&req
, const uint8_t *data
)
259 Addr daddr
= req
->paddr
- (addr
& EV5::PAddrImplMask
);
261 DPRINTF(Uart
, " write register %#x value %#x\n", daddr
, *(uint8_t*)data
);
269 case 0x28: // Ack of TX
270 if ((status
& TX_INT
) == 0)
271 panic("Ack of transmit, though there was no interrupt");
274 platform
->clearConsoleInt();
278 case 0x03: // going to read RR3
282 DPRINTF(Uart
, "writing status register %#x \n",
288 case 0xc0: // Data register (TX)
289 cons
->out(*(uint64_t *)data
);
290 platform
->postConsoleInt();
299 if (!(LCR
& 0x80)) { // write byte
300 cons
->out(*(uint8_t *)data
);
301 platform
->clearConsoleInt();
303 if (UART_IER_THRI
& IER
)
304 txIntrEvent
.scheduleIntr();
305 } else { // dll divisor latch
310 if (!(LCR
& 0x80)) { // Intr Enable Register(IER)
311 IER
= *(uint8_t*)data
;
312 if (UART_IER_THRI
& IER
)
314 DPRINTF(Uart
, "IER: IER_THRI set, scheduling TX intrrupt\n");
315 txIntrEvent
.scheduleIntr();
319 DPRINTF(Uart
, "IER: IER_THRI cleared, descheduling TX intrrupt\n");
320 if (txIntrEvent
.scheduled())
321 txIntrEvent
.deschedule();
323 platform
->clearConsoleInt();
327 if ((UART_IER_RDI
& IER
) && cons
->dataAvailable()) {
328 DPRINTF(Uart
, "IER: IER_RDI set, scheduling RX intrrupt\n");
329 rxIntrEvent
.scheduleIntr();
331 DPRINTF(Uart
, "IER: IER_RDI cleared, descheduling RX intrrupt\n");
332 if (rxIntrEvent
.scheduled())
333 rxIntrEvent
.deschedule();
335 platform
->clearConsoleInt();
338 } else { // DLM divisor latch MSB
342 case 0x2: // FIFO Control Register (FCR)
344 case 0x3: // Line Control Register (LCR)
345 LCR
= *(uint8_t*)data
;
347 case 0x4: // Modem Control Register (MCR)
348 if (*(uint8_t*)data
== (UART_MCR_LOOP
| 0x0A))
351 case 0x7: // Scratch Register (SCR)
352 // We are emulating a 8250 so we don't have a scratch reg
355 panic("Tried to access a UART port that doesn't exist\n");
364 Uart::dataAvailable()
367 platform
->postConsoleInt();
371 // if the kernel wants an interrupt when we have data
372 if (IER
& UART_IER_RDI
)
374 platform
->postConsoleInt();
382 Uart::cacheAccess(MemReqPtr
&req
)
384 return curTick
+ pioLatency
;
388 Uart::serialize(ostream
&os
)
391 SERIALIZE_SCALAR(readAddr
);
392 SERIALIZE_SCALAR(status
);
394 SERIALIZE_SCALAR(status
);
395 SERIALIZE_SCALAR(IER
);
396 SERIALIZE_SCALAR(DLAB
);
397 SERIALIZE_SCALAR(LCR
);
398 SERIALIZE_SCALAR(MCR
);
400 if (rxIntrEvent
.scheduled())
401 rxintrwhen
= rxIntrEvent
.when();
405 if (txIntrEvent
.scheduled())
406 txintrwhen
= txIntrEvent
.when();
409 SERIALIZE_SCALAR(rxintrwhen
);
410 SERIALIZE_SCALAR(txintrwhen
);
415 Uart::unserialize(Checkpoint
*cp
, const std::string
§ion
)
418 UNSERIALIZE_SCALAR(readAddr
);
419 UNSERIALIZE_SCALAR(status
);
421 UNSERIALIZE_SCALAR(status
);
422 UNSERIALIZE_SCALAR(IER
);
423 UNSERIALIZE_SCALAR(DLAB
);
424 UNSERIALIZE_SCALAR(LCR
);
425 UNSERIALIZE_SCALAR(MCR
);
428 UNSERIALIZE_SCALAR(rxintrwhen
);
429 UNSERIALIZE_SCALAR(txintrwhen
);
431 rxIntrEvent
.schedule(rxintrwhen
);
433 txIntrEvent
.schedule(txintrwhen
);
438 BEGIN_DECLARE_SIM_OBJECT_PARAMS(Uart
)
440 SimObjectParam
<SimConsole
*> console
;
441 SimObjectParam
<MemoryController
*> mmu
;
442 SimObjectParam
<Platform
*> platform
;
445 SimObjectParam
<Bus
*> io_bus
;
446 Param
<Tick
> pio_latency
;
447 SimObjectParam
<HierParams
*> hier
;
450 END_DECLARE_SIM_OBJECT_PARAMS(Uart
)
452 BEGIN_INIT_SIM_OBJECT_PARAMS(Uart
)
454 INIT_PARAM(console
, "The console"),
455 INIT_PARAM(mmu
, "Memory Controller"),
456 INIT_PARAM(platform
, "Pointer to platfrom"),
457 INIT_PARAM(addr
, "Device Address"),
458 INIT_PARAM_DFLT(size
, "Device size", 0x8),
459 INIT_PARAM_DFLT(io_bus
, "The IO Bus to attach to", NULL
),
460 INIT_PARAM_DFLT(pio_latency
, "Programmed IO latency in bus cycles", 1),
461 INIT_PARAM_DFLT(hier
, "Hierarchy global variables", &defaultHierParams
)
463 END_INIT_SIM_OBJECT_PARAMS(Uart
)
465 CREATE_SIM_OBJECT(Uart
)
467 return new Uart(getInstanceName(), console
, mmu
, addr
, size
, hier
, io_bus
,
468 pio_latency
, platform
);
471 REGISTER_SIM_OBJECT("Uart", Uart
)