2 * Copyright (c) 2005 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/uart8250.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/memory_control.hh"
46 #include "sim/builder.hh"
50 Uart8250::IntrEvent::IntrEvent(Uart8250
*u
, int bit
)
51 : Event(&mainEventQueue
), uart(u
)
53 DPRINTF(Uart
, "UART Interrupt Event Initilizing\n");
58 Uart8250::IntrEvent::description()
60 return "uart interrupt delay event";
64 Uart8250::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 Uart8250::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
);
101 Uart8250::Uart8250(const string
&name
, SimConsole
*c
, MemoryController
*mmu
,
102 Addr a
, Addr s
, HierParams
*hier
, Bus
*pio_bus
,
103 Tick pio_latency
, Platform
*p
)
104 : Uart(name
, c
, mmu
, a
, s
, hier
, pio_bus
, pio_latency
, p
),
105 txIntrEvent(this, TX_INT
), rxIntrEvent(this, RX_INT
)
115 Uart8250::read(MemReqPtr
&req
, uint8_t *data
)
117 Addr daddr
= req
->paddr
- (addr
& EV5::PAddrImplMask
);
118 DPRINTF(Uart
, " read register %#x\n", daddr
);
120 assert(req
->size
== 1);
124 if (!(LCR
& 0x80)) { // read byte
125 if (cons
->dataAvailable())
129 // A limited amount of these are ok.
130 DPRINTF(Uart
, "empty read of RX register\n");
133 platform
->clearConsoleInt();
135 if (cons
->dataAvailable() && (IER
& UART_IER_RDI
))
136 rxIntrEvent
.scheduleIntr();
137 } else { // dll divisor latch
142 if (!(LCR
& 0x80)) { // Intr Enable Register(IER)
143 *(uint8_t*)data
= IER
;
144 } else { // DLM divisor latch MSB
148 case 0x2: // Intr Identification Register (IIR)
149 DPRINTF(Uart
, "IIR Read, status = %#x\n", (uint32_t)status
);
151 if (status
& RX_INT
) /* Rx data interrupt has a higher priority */
152 *(uint8_t*)data
= IIR_RXID
;
153 else if (status
& TX_INT
)
154 *(uint8_t*)data
= IIR_TXID
;
156 *(uint8_t*)data
= IIR_NOPEND
;
158 //Tx interrupts are cleared on IIR reads
161 case 0x3: // Line Control Register (LCR)
162 *(uint8_t*)data
= LCR
;
164 case 0x4: // Modem Control Register (MCR)
166 case 0x5: // Line Status Register (LSR)
169 // check if there are any bytes to be read
170 if (cons
->dataAvailable())
172 lsr
|= UART_LSR_TEMT
| UART_LSR_THRE
;
173 *(uint8_t*)data
= lsr
;
175 case 0x6: // Modem Status Register (MSR)
178 case 0x7: // Scratch Register (SCR)
179 *(uint8_t*)data
= 0; // doesn't exist with at 8250.
182 panic("Tried to access a UART port that doesn't exist\n");
191 Uart8250::write(MemReqPtr
&req
, const uint8_t *data
)
193 Addr daddr
= req
->paddr
- (addr
& EV5::PAddrImplMask
);
195 DPRINTF(Uart
, " write register %#x value %#x\n", daddr
, *(uint8_t*)data
);
199 if (!(LCR
& 0x80)) { // write byte
200 cons
->out(*(uint8_t *)data
);
201 platform
->clearConsoleInt();
203 if (UART_IER_THRI
& IER
)
204 txIntrEvent
.scheduleIntr();
205 } else { // dll divisor latch
210 if (!(LCR
& 0x80)) { // Intr Enable Register(IER)
211 IER
= *(uint8_t*)data
;
212 if (UART_IER_THRI
& IER
)
214 DPRINTF(Uart
, "IER: IER_THRI set, scheduling TX intrrupt\n");
215 txIntrEvent
.scheduleIntr();
219 DPRINTF(Uart
, "IER: IER_THRI cleared, descheduling TX intrrupt\n");
220 if (txIntrEvent
.scheduled())
221 txIntrEvent
.deschedule();
223 platform
->clearConsoleInt();
227 if ((UART_IER_RDI
& IER
) && cons
->dataAvailable()) {
228 DPRINTF(Uart
, "IER: IER_RDI set, scheduling RX intrrupt\n");
229 rxIntrEvent
.scheduleIntr();
231 DPRINTF(Uart
, "IER: IER_RDI cleared, descheduling RX intrrupt\n");
232 if (rxIntrEvent
.scheduled())
233 rxIntrEvent
.deschedule();
235 platform
->clearConsoleInt();
238 } else { // DLM divisor latch MSB
242 case 0x2: // FIFO Control Register (FCR)
244 case 0x3: // Line Control Register (LCR)
245 LCR
= *(uint8_t*)data
;
247 case 0x4: // Modem Control Register (MCR)
248 if (*(uint8_t*)data
== (UART_MCR_LOOP
| 0x0A))
251 case 0x7: // Scratch Register (SCR)
252 // We are emulating a 8250 so we don't have a scratch reg
255 panic("Tried to access a UART port that doesn't exist\n");
262 Uart8250::dataAvailable()
264 // if the kernel wants an interrupt when we have data
265 if (IER
& UART_IER_RDI
)
267 platform
->postConsoleInt();
276 Uart8250::serialize(ostream
&os
)
278 SERIALIZE_SCALAR(status
);
279 SERIALIZE_SCALAR(IER
);
280 SERIALIZE_SCALAR(DLAB
);
281 SERIALIZE_SCALAR(LCR
);
282 SERIALIZE_SCALAR(MCR
);
284 if (rxIntrEvent
.scheduled())
285 rxintrwhen
= rxIntrEvent
.when();
289 if (txIntrEvent
.scheduled())
290 txintrwhen
= txIntrEvent
.when();
293 SERIALIZE_SCALAR(rxintrwhen
);
294 SERIALIZE_SCALAR(txintrwhen
);
298 Uart8250::unserialize(Checkpoint
*cp
, const std::string
§ion
)
300 UNSERIALIZE_SCALAR(status
);
301 UNSERIALIZE_SCALAR(IER
);
302 UNSERIALIZE_SCALAR(DLAB
);
303 UNSERIALIZE_SCALAR(LCR
);
304 UNSERIALIZE_SCALAR(MCR
);
307 UNSERIALIZE_SCALAR(rxintrwhen
);
308 UNSERIALIZE_SCALAR(txintrwhen
);
310 rxIntrEvent
.schedule(rxintrwhen
);
312 txIntrEvent
.schedule(txintrwhen
);
315 BEGIN_DECLARE_SIM_OBJECT_PARAMS(Uart8250
)
317 SimObjectParam
<SimConsole
*> console
;
318 SimObjectParam
<MemoryController
*> mmu
;
319 SimObjectParam
<Platform
*> platform
;
322 SimObjectParam
<Bus
*> pio_bus
;
323 Param
<Tick
> pio_latency
;
324 SimObjectParam
<HierParams
*> hier
;
327 END_DECLARE_SIM_OBJECT_PARAMS(Uart8250
)
329 BEGIN_INIT_SIM_OBJECT_PARAMS(Uart8250
)
331 INIT_PARAM(console
, "The console"),
332 INIT_PARAM(mmu
, "Memory Controller"),
333 INIT_PARAM(platform
, "Pointer to platfrom"),
334 INIT_PARAM(addr
, "Device Address"),
335 INIT_PARAM_DFLT(size
, "Device size", 0x8),
336 INIT_PARAM(pio_bus
, ""),
337 INIT_PARAM_DFLT(pio_latency
, "Programmed IO latency in bus cycles", 1),
338 INIT_PARAM_DFLT(hier
, "Hierarchy global variables", &defaultHierParams
)
340 END_INIT_SIM_OBJECT_PARAMS(Uart8250
)
342 CREATE_SIM_OBJECT(Uart8250
)
344 return new Uart8250(getInstanceName(), console
, mmu
, addr
, size
, hier
,
345 pio_bus
, pio_latency
, platform
);
348 REGISTER_SIM_OBJECT("Uart8250", Uart8250
)