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");
77 Uart::IntrEvent::scheduleIntr()
79 DPRINTF(Uart
, "Scheduling IER interrupt for %#x, at cycle %lld\n", intrBit
,
80 curTick
+ (ticksPerSecond
/2000) * 350);
82 /* @todo Make this cleaner, will be much easier with
83 * nanosecond time everywhere. Hint hint Nate. */
84 schedule(curTick
+ (ticksPerSecond
/2000000000) * 450);
86 reschedule(curTick
+ (ticksPerSecond
/2000000000) * 450);
89 Uart::Uart(const string
&name
, SimConsole
*c
, MemoryController
*mmu
, Addr a
,
90 Addr s
, HierParams
*hier
, Bus
*bus
, Tick pio_latency
, Platform
*p
)
91 : PioDevice(name
), addr(a
), size(s
), cons(c
), txIntrEvent(this, TX_INT
),
92 rxIntrEvent(this, RX_INT
), platform(p
)
94 mmu
->add_child(this, RangeSize(addr
, size
));
98 pioInterface
= newPioInterface(name
, hier
, bus
, this,
100 pioInterface
->addAddrRange(RangeSize(addr
, size
));
101 pioLatency
= pio_latency
* bus
->clockRatio
;
113 platform
->uart
= this;
118 Uart::read(MemReqPtr
&req
, uint8_t *data
)
120 Addr daddr
= req
->paddr
- (addr
& EV5::PAddrImplMask
);
121 DPRINTF(Uart
, " read register %#x\n", daddr
);
128 case sizeof(uint64_t):
129 *(uint64_t *)data
= 0;
131 case sizeof(uint32_t):
132 *(uint32_t *)data
= 0;
134 case sizeof(uint16_t):
135 *(uint16_t *)data
= 0;
137 case sizeof(uint8_t):
138 *(uint8_t *)data
= 0;
143 case 0x80: // Status Register
148 else if (status
& RX_INT
)
151 DPRINTF(Uart
, "spurious read\n");
160 case 0xc0: // Data register (RX)
161 if (!cons
->dataAvailable())
162 panic("No data to read");
166 if (!cons
->dataAvailable()) {
167 platform
->clearConsoleInt();
171 DPRINTF(Uart
, "read data register \'%c\' %2x\n",
172 isprint(*data
) ? *data
: ' ', *data
);
180 assert(req
->size
== 1);
184 if (!(LCR
& 0x80)) { // read byte
185 if (cons
->dataAvailable())
189 // A limited amount of these are ok.
190 DPRINTF(Uart
, "empty read of RX register\n");
193 platform
->clearConsoleInt();
195 if (cons
->dataAvailable() && (IER
& UART_IER_RDI
))
196 rxIntrEvent
.scheduleIntr();
197 } else { // dll divisor latch
202 if (!(LCR
& 0x80)) { // Intr Enable Register(IER)
203 *(uint8_t*)data
= IER
;
204 } else { // DLM divisor latch MSB
208 case 0x2: // Intr Identification Register (IIR)
209 DPRINTF(Uart
, "IIR Read, status = %#x\n", (uint32_t)status
);
215 case 0x3: // Line Control Register (LCR)
216 *(uint8_t*)data
= LCR
;
218 case 0x4: // Modem Control Register (MCR)
220 case 0x5: // Line Status Register (LSR)
223 // check if there are any bytes to be read
224 if (cons
->dataAvailable())
226 lsr
|= UART_LSR_TEMT
| UART_LSR_THRE
;
227 *(uint8_t*)data
= lsr
;
229 case 0x6: // Modem Status Register (MSR)
232 case 0x7: // Scratch Register (SCR)
233 *(uint8_t*)data
= 0; // doesn't exist with at 8250.
236 panic("Tried to access a UART port that doesn't exist\n");
246 Uart::write(MemReqPtr
&req
, const uint8_t *data
)
248 Addr daddr
= req
->paddr
- (addr
& EV5::PAddrImplMask
);
250 DPRINTF(Uart
, " write register %#x value %#x\n", daddr
, *(uint8_t*)data
);
258 case 0x28: // Ack of TX
259 if ((status
& TX_INT
) == 0)
260 panic("Ack of transmit, though there was no interrupt");
263 platform
->clearConsoleInt();
267 case 0x03: // going to read RR3
271 DPRINTF(Uart
, "writing status register %#x \n",
277 case 0xc0: // Data register (TX)
278 cons
->out(*(uint64_t *)data
);
279 platform
->postConsoleInt();
288 if (!(LCR
& 0x80)) { // write byte
289 cons
->out(*(uint8_t *)data
);
290 platform
->clearConsoleInt();
292 if (UART_IER_THRI
& IER
)
293 txIntrEvent
.scheduleIntr();
294 } else { // dll divisor latch
299 if (!(LCR
& 0x80)) { // Intr Enable Register(IER)
300 IER
= *(uint8_t*)data
;
301 if (UART_IER_THRI
& IER
)
303 DPRINTF(Uart
, "IER: IER_THRI set, scheduling TX intrrupt\n");
304 txIntrEvent
.scheduleIntr();
308 DPRINTF(Uart
, "IER: IER_THRI cleared, descheduling TX intrrupt\n");
309 if (txIntrEvent
.scheduled())
310 txIntrEvent
.deschedule();
312 platform
->clearConsoleInt();
316 if ((UART_IER_RDI
& IER
) && cons
->dataAvailable()) {
317 DPRINTF(Uart
, "IER: IER_RDI set, scheduling RX intrrupt\n");
318 rxIntrEvent
.scheduleIntr();
320 DPRINTF(Uart
, "IER: IER_RDI cleared, descheduling RX intrrupt\n");
321 if (rxIntrEvent
.scheduled())
322 rxIntrEvent
.deschedule();
324 platform
->clearConsoleInt();
327 } else { // DLM divisor latch MSB
331 case 0x2: // FIFO Control Register (FCR)
333 case 0x3: // Line Control Register (LCR)
334 LCR
= *(uint8_t*)data
;
336 case 0x4: // Modem Control Register (MCR)
337 if (*(uint8_t*)data
== (UART_MCR_LOOP
| 0x0A))
340 case 0x7: // Scratch Register (SCR)
341 // We are emulating a 8250 so we don't have a scratch reg
344 panic("Tried to access a UART port that doesn't exist\n");
353 Uart::dataAvailable()
356 platform
->postConsoleInt();
360 // if the kernel wants an interrupt when we have data
361 if (IER
& UART_IER_RDI
)
363 platform
->postConsoleInt();
371 Uart::cacheAccess(MemReqPtr
&req
)
373 return curTick
+ pioLatency
;
377 Uart::serialize(ostream
&os
)
380 SERIALIZE_SCALAR(readAddr
);
381 SERIALIZE_SCALAR(status
);
383 SERIALIZE_SCALAR(status
);
384 SERIALIZE_SCALAR(IER
);
385 SERIALIZE_SCALAR(DLAB
);
386 SERIALIZE_SCALAR(LCR
);
387 SERIALIZE_SCALAR(MCR
);
389 if (rxIntrEvent
.scheduled())
390 rxintrwhen
= rxIntrEvent
.when();
394 if (txIntrEvent
.scheduled())
395 txintrwhen
= txIntrEvent
.when();
398 SERIALIZE_SCALAR(rxintrwhen
);
399 SERIALIZE_SCALAR(txintrwhen
);
404 Uart::unserialize(Checkpoint
*cp
, const std::string
§ion
)
407 UNSERIALIZE_SCALAR(readAddr
);
408 UNSERIALIZE_SCALAR(status
);
410 UNSERIALIZE_SCALAR(status
);
411 UNSERIALIZE_SCALAR(IER
);
412 UNSERIALIZE_SCALAR(DLAB
);
413 UNSERIALIZE_SCALAR(LCR
);
414 UNSERIALIZE_SCALAR(MCR
);
417 UNSERIALIZE_SCALAR(rxintrwhen
);
418 UNSERIALIZE_SCALAR(txintrwhen
);
420 rxIntrEvent
.schedule(rxintrwhen
);
422 txIntrEvent
.schedule(txintrwhen
);
427 BEGIN_DECLARE_SIM_OBJECT_PARAMS(Uart
)
429 SimObjectParam
<SimConsole
*> console
;
430 SimObjectParam
<MemoryController
*> mmu
;
431 SimObjectParam
<Platform
*> platform
;
434 SimObjectParam
<Bus
*> io_bus
;
435 Param
<Tick
> pio_latency
;
436 SimObjectParam
<HierParams
*> hier
;
439 END_DECLARE_SIM_OBJECT_PARAMS(Uart
)
441 BEGIN_INIT_SIM_OBJECT_PARAMS(Uart
)
443 INIT_PARAM(console
, "The console"),
444 INIT_PARAM(mmu
, "Memory Controller"),
445 INIT_PARAM(platform
, "Pointer to platfrom"),
446 INIT_PARAM(addr
, "Device Address"),
447 INIT_PARAM_DFLT(size
, "Device size", 0x8),
448 INIT_PARAM_DFLT(io_bus
, "The IO Bus to attach to", NULL
),
449 INIT_PARAM_DFLT(pio_latency
, "Programmed IO latency in bus cycles", 1),
450 INIT_PARAM_DFLT(hier
, "Hierarchy global variables", &defaultHierParams
)
452 END_INIT_SIM_OBJECT_PARAMS(Uart
)
454 CREATE_SIM_OBJECT(Uart
)
456 return new Uart(getInstanceName(), console
, mmu
, addr
, size
, hier
, io_bus
,
457 pio_latency
, platform
);
460 REGISTER_SIM_OBJECT("Uart", Uart
)