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"
47 #include "targetarch/ev5.hh"
51 Uart::IntrEvent::IntrEvent(Uart
*u
, int bit
)
52 : Event(&mainEventQueue
), uart(u
)
54 DPRINTF(Uart
, "UART Interrupt Event Initilizing\n");
59 Uart::IntrEvent::description()
61 return "uart interrupt delay event";
65 Uart::IntrEvent::process()
67 if (intrBit
& uart
->IER
) {
68 DPRINTF(Uart
, "UART InterEvent, interrupting\n");
69 uart
->platform
->postConsoleInt();
70 uart
->status
|= intrBit
;
73 DPRINTF(Uart
, "UART InterEvent, not interrupting\n");
78 Uart::IntrEvent::scheduleIntr()
80 DPRINTF(Uart
, "Scheduling IER interrupt for %#x, at cycle %lld\n", intrBit
,
81 curTick
+ (ticksPerSecond
/2000) * 350);
83 /* @todo Make this cleaner, will be much easier with
84 * nanosecond time everywhere. Hint hint Nate. */
85 schedule(curTick
+ (ticksPerSecond
/2000000000) * 450);
87 reschedule(curTick
+ (ticksPerSecond
/2000000000) * 450);
90 Uart::Uart(const string
&name
, SimConsole
*c
, MemoryController
*mmu
, Addr a
,
91 Addr s
, HierParams
*hier
, Bus
*bus
, Tick pio_latency
, Platform
*p
)
92 : PioDevice(name
), addr(a
), size(s
), cons(c
), txIntrEvent(this, TX_INT
),
93 rxIntrEvent(this, RX_INT
), platform(p
)
95 mmu
->add_child(this, Range
<Addr
>(addr
, addr
+ size
));
99 pioInterface
= newPioInterface(name
, hier
, bus
, this,
101 pioInterface
->addAddrRange(addr
, addr
+ size
- 1);
102 pioLatency
= pio_latency
* bus
->clockRatio
;
114 platform
->uart
= this;
119 Uart::read(MemReqPtr
&req
, uint8_t *data
)
121 Addr daddr
= req
->paddr
- (addr
& PA_IMPL_MASK
);
122 DPRINTF(Uart
, " read register %#x\n", daddr
);
129 case sizeof(uint64_t):
130 *(uint64_t *)data
= 0;
132 case sizeof(uint32_t):
133 *(uint32_t *)data
= 0;
135 case sizeof(uint16_t):
136 *(uint16_t *)data
= 0;
138 case sizeof(uint8_t):
139 *(uint8_t *)data
= 0;
144 case 0x80: // Status Register
149 else if (status
& RX_INT
)
152 DPRINTF(Uart
, "spurious read\n");
161 case 0xc0: // Data register (RX)
162 if (!cons
->dataAvailable())
163 panic("No data to read");
167 if (!cons
->dataAvailable()) {
168 platform
->clearConsoleInt();
172 DPRINTF(Uart
, "read data register \'%c\' %2x\n",
173 isprint(*data
) ? *data
: ' ', *data
);
181 assert(req
->size
== 1);
185 if (!(LCR
& 0x80)) { // read byte
186 if (cons
->dataAvailable())
190 // A limited amount of these are ok.
191 DPRINTF(Uart
, "empty read of RX register\n");
194 platform
->clearConsoleInt();
196 if (cons
->dataAvailable() && (IER
& UART_IER_RDI
))
197 rxIntrEvent
.scheduleIntr();
198 } else { // dll divisor latch
203 if (!(LCR
& 0x80)) { // Intr Enable Register(IER)
204 *(uint8_t*)data
= IER
;
205 } else { // DLM divisor latch MSB
209 case 0x2: // Intr Identification Register (IIR)
210 DPRINTF(Uart
, "IIR Read, status = %#x\n", (uint32_t)status
);
216 case 0x3: // Line Control Register (LCR)
217 *(uint8_t*)data
= LCR
;
219 case 0x4: // Modem Control Register (MCR)
221 case 0x5: // Line Status Register (LSR)
224 // check if there are any bytes to be read
225 if (cons
->dataAvailable())
227 lsr
|= UART_LSR_TEMT
| UART_LSR_THRE
;
228 *(uint8_t*)data
= lsr
;
230 case 0x6: // Modem Status Register (MSR)
233 case 0x7: // Scratch Register (SCR)
234 *(uint8_t*)data
= 0; // doesn't exist with at 8250.
237 panic("Tried to access a UART port that doesn't exist\n");
247 Uart::write(MemReqPtr
&req
, const uint8_t *data
)
249 Addr daddr
= req
->paddr
- (addr
& PA_IMPL_MASK
);
251 DPRINTF(Uart
, " write register %#x value %#x\n", daddr
, *(uint8_t*)data
);
259 case 0x28: // Ack of TX
260 if ((status
& TX_INT
) == 0)
261 panic("Ack of transmit, though there was no interrupt");
264 platform
->clearConsoleInt();
268 case 0x03: // going to read RR3
272 DPRINTF(Uart
, "writing status register %#x \n",
278 case 0xc0: // Data register (TX)
279 cons
->out(*(uint64_t *)data
);
280 platform
->postConsoleInt();
289 if (!(LCR
& 0x80)) { // write byte
290 cons
->out(*(uint64_t *)data
);
291 platform
->clearConsoleInt();
293 if (UART_IER_THRI
& IER
)
294 txIntrEvent
.scheduleIntr();
295 } else { // dll divisor latch
300 if (!(LCR
& 0x80)) { // Intr Enable Register(IER)
301 IER
= *(uint8_t*)data
;
302 if (UART_IER_THRI
& IER
)
304 DPRINTF(Uart
, "IER: IER_THRI set, scheduling TX intrrupt\n");
305 txIntrEvent
.scheduleIntr();
309 DPRINTF(Uart
, "IER: IER_THRI cleared, descheduling TX intrrupt\n");
310 if (txIntrEvent
.scheduled())
311 txIntrEvent
.deschedule();
313 platform
->clearConsoleInt();
317 if ((UART_IER_RDI
& IER
) && cons
->dataAvailable()) {
318 DPRINTF(Uart
, "IER: IER_RDI set, scheduling RX intrrupt\n");
319 rxIntrEvent
.scheduleIntr();
321 DPRINTF(Uart
, "IER: IER_RDI cleared, descheduling RX intrrupt\n");
322 if (rxIntrEvent
.scheduled())
323 rxIntrEvent
.deschedule();
325 platform
->clearConsoleInt();
328 } else { // DLM divisor latch MSB
332 case 0x2: // FIFO Control Register (FCR)
334 case 0x3: // Line Control Register (LCR)
335 LCR
= *(uint8_t*)data
;
337 case 0x4: // Modem Control Register (MCR)
338 if (*(uint8_t*)data
== (UART_MCR_LOOP
| 0x0A))
341 case 0x7: // Scratch Register (SCR)
342 // We are emulating a 8250 so we don't have a scratch reg
345 panic("Tried to access a UART port that doesn't exist\n");
354 Uart::dataAvailable()
357 platform
->postConsoleInt();
361 // if the kernel wants an interrupt when we have data
362 if (IER
& UART_IER_RDI
)
364 platform
->postConsoleInt();
372 Uart::cacheAccess(MemReqPtr
&req
)
374 return curTick
+ pioLatency
;
378 Uart::serialize(ostream
&os
)
381 SERIALIZE_SCALAR(readAddr
);
382 SERIALIZE_SCALAR(status
);
384 SERIALIZE_SCALAR(status
);
385 SERIALIZE_SCALAR(IER
);
386 SERIALIZE_SCALAR(DLAB
);
387 SERIALIZE_SCALAR(LCR
);
388 SERIALIZE_SCALAR(MCR
);
390 if (rxIntrEvent
.scheduled())
391 rxintrwhen
= rxIntrEvent
.when();
395 if (txIntrEvent
.scheduled())
396 txintrwhen
= txIntrEvent
.when();
399 SERIALIZE_SCALAR(rxintrwhen
);
400 SERIALIZE_SCALAR(txintrwhen
);
405 Uart::unserialize(Checkpoint
*cp
, const std::string
§ion
)
408 UNSERIALIZE_SCALAR(readAddr
);
409 UNSERIALIZE_SCALAR(status
);
411 UNSERIALIZE_SCALAR(status
);
412 UNSERIALIZE_SCALAR(IER
);
413 UNSERIALIZE_SCALAR(DLAB
);
414 UNSERIALIZE_SCALAR(LCR
);
415 UNSERIALIZE_SCALAR(MCR
);
418 UNSERIALIZE_SCALAR(rxintrwhen
);
419 UNSERIALIZE_SCALAR(txintrwhen
);
421 rxIntrEvent
.schedule(rxintrwhen
);
423 txIntrEvent
.schedule(txintrwhen
);
428 BEGIN_DECLARE_SIM_OBJECT_PARAMS(Uart
)
430 SimObjectParam
<SimConsole
*> console
;
431 SimObjectParam
<MemoryController
*> mmu
;
432 SimObjectParam
<Platform
*> platform
;
435 SimObjectParam
<Bus
*> io_bus
;
436 Param
<Tick
> pio_latency
;
437 SimObjectParam
<HierParams
*> hier
;
440 END_DECLARE_SIM_OBJECT_PARAMS(Uart
)
442 BEGIN_INIT_SIM_OBJECT_PARAMS(Uart
)
444 INIT_PARAM(console
, "The console"),
445 INIT_PARAM(mmu
, "Memory Controller"),
446 INIT_PARAM(platform
, "Pointer to platfrom"),
447 INIT_PARAM(addr
, "Device Address"),
448 INIT_PARAM_DFLT(size
, "Device size", 0x8),
449 INIT_PARAM_DFLT(io_bus
, "The IO Bus to attach to", NULL
),
450 INIT_PARAM_DFLT(pio_latency
, "Programmed IO latency in bus cycles", 1),
451 INIT_PARAM_DFLT(hier
, "Hierarchy global variables", &defaultHierParams
)
453 END_INIT_SIM_OBJECT_PARAMS(Uart
)
455 CREATE_SIM_OBJECT(Uart
)
457 return new Uart(getInstanceName(), console
, mmu
, addr
, size
, hier
, io_bus
,
458 pio_latency
, platform
);
461 REGISTER_SIM_OBJECT("Uart", Uart
)