From adce616cfef6f9476d0fbb1bf03fb65734bf3bdf Mon Sep 17 00:00:00 2001 From: Ali Saidi Date: Sun, 5 Jun 2005 01:22:21 -0400 Subject: [PATCH] split uart into urt8250 and uart8530 fix some doxygen comments SConscript: Added split uart files dev/ns_gige.cc: dev/ns_gige.hh: dev/ns_gige_reg.h: dev/tsunami.cc: dev/tsunami_cchip.cc: dev/tsunami_io.cc: dev/tsunami_pchip.cc: dev/tsunamireg.h: fix doxgyen file comment dev/uart.cc: dev/uart.hh: python/m5/objects/Uart.py: split uart into urt8250 and uart8530 --HG-- extra : convert_revision : 2e70aad892a37620d7909017648bca6d7d69d678 --- SConscript | 2 + dev/ns_gige.cc | 2 +- dev/ns_gige.hh | 2 +- dev/ns_gige_reg.h | 2 +- dev/tsunami.cc | 3 + dev/tsunami_cchip.cc | 2 +- dev/tsunami_io.cc | 2 +- dev/tsunami_pchip.cc | 2 +- dev/tsunamireg.h | 4 + dev/uart.cc | 399 +------------------------------------- dev/uart.hh | 44 +---- dev/uart8250.cc | 341 ++++++++++++++++++++++++++++++++ dev/uart8250.hh | 92 +++++++++ python/m5/objects/Uart.py | 8 + 14 files changed, 469 insertions(+), 436 deletions(-) create mode 100644 dev/uart8250.cc create mode 100644 dev/uart8250.hh diff --git a/SConscript b/SConscript index 059ce0ca1..0efb3e1e5 100644 --- a/SConscript +++ b/SConscript @@ -293,6 +293,8 @@ full_system_sources = Split(''' dev/tsunami_io.cc dev/tsunami_pchip.cc dev/uart.cc + dev/uart8530.cc + dev/uart8250.cc kern/kernel_binning.cc kern/kernel_stats.cc diff --git a/dev/ns_gige.cc b/dev/ns_gige.cc index 637cd7825..46ad1325f 100644 --- a/dev/ns_gige.cc +++ b/dev/ns_gige.cc @@ -26,7 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* @file +/** @file * Device module for modelling the National Semiconductor * DP83820 ethernet controller. Does not support priority queueing */ diff --git a/dev/ns_gige.hh b/dev/ns_gige.hh index 302aa5a89..a1e90a375 100644 --- a/dev/ns_gige.hh +++ b/dev/ns_gige.hh @@ -26,7 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* @file +/** @file * Device module for modelling the National Semiconductor * DP83820 ethernet controller */ diff --git a/dev/ns_gige_reg.h b/dev/ns_gige_reg.h index d73a6c6b2..be53149e7 100644 --- a/dev/ns_gige_reg.h +++ b/dev/ns_gige_reg.h @@ -26,7 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* @file +/** @file * Ethernet device register definitions for the National * Semiconductor DP83820 Ethernet controller */ diff --git a/dev/tsunami.cc b/dev/tsunami.cc index 55a2c5ea6..584c8a346 100644 --- a/dev/tsunami.cc +++ b/dev/tsunami.cc @@ -26,6 +26,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** @file Implementation of Tsunami platform. + */ + #include #include #include diff --git a/dev/tsunami_cchip.cc b/dev/tsunami_cchip.cc index a10dba082..125dce325 100644 --- a/dev/tsunami_cchip.cc +++ b/dev/tsunami_cchip.cc @@ -26,7 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* @file +/** @file * Emulation of the Tsunami CChip CSRs */ diff --git a/dev/tsunami_io.cc b/dev/tsunami_io.cc index 2e12b41ea..1d1266db0 100644 --- a/dev/tsunami_io.cc +++ b/dev/tsunami_io.cc @@ -26,7 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* @file +/** @file * Tsunami I/O including PIC, PIT, RTC, DMA */ diff --git a/dev/tsunami_pchip.cc b/dev/tsunami_pchip.cc index f8bec77c0..638a2d427 100644 --- a/dev/tsunami_pchip.cc +++ b/dev/tsunami_pchip.cc @@ -26,7 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* @file +/** @file * Tsunami PChip (pci) */ diff --git a/dev/tsunamireg.h b/dev/tsunamireg.h index 290f21a5b..df10ce29d 100644 --- a/dev/tsunamireg.h +++ b/dev/tsunamireg.h @@ -26,6 +26,10 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/** @file + * List of Tsunami CSRs + */ + #ifndef __TSUNAMIREG_H__ #define __TSUNAMIREG_H__ diff --git a/dev/uart.cc b/dev/uart.cc index c04a5d066..cf58b7fdd 100644 --- a/dev/uart.cc +++ b/dev/uart.cc @@ -26,7 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* @file +/** @file * Implements a 8250 UART */ @@ -47,60 +47,9 @@ using namespace std; -Uart::IntrEvent::IntrEvent(Uart *u, int bit) - : Event(&mainEventQueue), uart(u) -{ - DPRINTF(Uart, "UART Interrupt Event Initilizing\n"); - intrBit = bit; -} - -const char * -Uart::IntrEvent::description() -{ - return "uart interrupt delay event"; -} - -void -Uart::IntrEvent::process() -{ - if (intrBit & uart->IER) { - DPRINTF(Uart, "UART InterEvent, interrupting\n"); - uart->platform->postConsoleInt(); - uart->status |= intrBit; - } - else - DPRINTF(Uart, "UART InterEvent, not interrupting\n"); - -} - -/* The linux serial driver (8250.c about line 1182) loops reading from - * the device until the device reports it has no more data to - * read. After a maximum of 255 iterations the code prints "serial8250 - * too much work for irq X," and breaks out of the loop. Since the - * simulated system is so much slower than the actual system, if a - * user is typing on the keyboard it is very easy for them to provide - * input at a fast enough rate to not allow the loop to exit and thus - * the error to be printed. This magic number provides a delay between - * the time the UART receives a character to send to the simulated - * system and the time it actually notifies the system it has a - * character to send to alleviate this problem. --Ali - */ -void -Uart::IntrEvent::scheduleIntr() -{ - static const Tick interval = (Tick)((Clock::Float::s / 2e9) * 450); - DPRINTF(Uart, "Scheduling IER interrupt for %#x, at cycle %lld\n", intrBit, - curTick + interval); - if (!scheduled()) - schedule(curTick + interval); - else - reschedule(curTick + interval); -} - Uart::Uart(const string &name, SimConsole *c, MemoryController *mmu, Addr a, Addr s, HierParams *hier, Bus *bus, Tick pio_latency, Platform *p) - : PioDevice(name, p), addr(a), size(s), cons(c), - txIntrEvent(this, TX_INT), rxIntrEvent(this, RX_INT) + : PioDevice(name, p), addr(a), size(s), cons(c) { mmu->add_child(this, RangeSize(addr, size)); @@ -112,270 +61,11 @@ Uart::Uart(const string &name, SimConsole *c, MemoryController *mmu, Addr a, pioLatency = pio_latency * bus->clockRate; } - readAddr = 0; - IER = 0; - DLAB = 0; - LCR = 0; - MCR = 0; status = 0; // set back pointers cons->uart = this; platform->uart = this; - -} - -Fault -Uart::read(MemReqPtr &req, uint8_t *data) -{ - Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); - DPRINTF(Uart, " read register %#x\n", daddr); - - - -#ifdef ALPHA_TLASER - - switch (req->size) { - case sizeof(uint64_t): - *(uint64_t *)data = 0; - break; - case sizeof(uint32_t): - *(uint32_t *)data = 0; - break; - case sizeof(uint16_t): - *(uint16_t *)data = 0; - break; - case sizeof(uint8_t): - *(uint8_t *)data = 0; - break; - } - - switch (daddr) { - case 0x80: // Status Register - if (readAddr == 3) { - readAddr = 0; - if (status & TX_INT) - *data = (1 << 4); - else if (status & RX_INT) - *data = (1 << 5); - else - DPRINTF(Uart, "spurious read\n"); - - } else { - *data = (1 << 2); - if (status & RX_INT) - *data |= (1 << 0); - } - break; - - case 0xc0: // Data register (RX) - if (!cons->dataAvailable()) - panic("No data to read"); - - cons->in(*data); - - if (!cons->dataAvailable()) { - platform->clearConsoleInt(); - status &= ~RX_INT; - } - - DPRINTF(Uart, "read data register \'%c\' %2x\n", - isprint(*data) ? *data : ' ', *data); - break; - } - - -#else - - - assert(req->size == 1); - - switch (daddr) { - case 0x0: - if (!(LCR & 0x80)) { // read byte - if (cons->dataAvailable()) - cons->in(*data); - else { - *(uint8_t*)data = 0; - // A limited amount of these are ok. - DPRINTF(Uart, "empty read of RX register\n"); - } - status &= ~RX_INT; - platform->clearConsoleInt(); - - if (cons->dataAvailable() && (IER & UART_IER_RDI)) - rxIntrEvent.scheduleIntr(); - } else { // dll divisor latch - ; - } - break; - case 0x1: - if (!(LCR & 0x80)) { // Intr Enable Register(IER) - *(uint8_t*)data = IER; - } else { // DLM divisor latch MSB - ; - } - break; - case 0x2: // Intr Identification Register (IIR) - DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status); - if (status) - *(uint8_t*)data = 0; - else - *(uint8_t*)data = 1; - break; - case 0x3: // Line Control Register (LCR) - *(uint8_t*)data = LCR; - break; - case 0x4: // Modem Control Register (MCR) - break; - case 0x5: // Line Status Register (LSR) - uint8_t lsr; - lsr = 0; - // check if there are any bytes to be read - if (cons->dataAvailable()) - lsr = UART_LSR_DR; - lsr |= UART_LSR_TEMT | UART_LSR_THRE; - *(uint8_t*)data = lsr; - break; - case 0x6: // Modem Status Register (MSR) - *(uint8_t*)data = 0; - break; - case 0x7: // Scratch Register (SCR) - *(uint8_t*)data = 0; // doesn't exist with at 8250. - break; - default: - panic("Tried to access a UART port that doesn't exist\n"); - break; - } - -#endif - return No_Fault; - -} - -Fault -Uart::write(MemReqPtr &req, const uint8_t *data) -{ - Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); - - DPRINTF(Uart, " write register %#x value %#x\n", daddr, *(uint8_t*)data); - -#ifdef ALPHA_TLASER - - switch (daddr) { - case 0x80: - readAddr = *data; - switch (*data) { - case 0x28: // Ack of TX - if ((status & TX_INT) == 0) - panic("Ack of transmit, though there was no interrupt"); - - status &= ~TX_INT; - platform->clearConsoleInt(); - break; - case 0x00: - case 0x01: - case 0x03: // going to read RR3 - case 0x12: - break; - default: - DPRINTF(Uart, "writing status register %#x \n", - *(uint64_t *)data); - break; - } - break; - - case 0xc0: // Data register (TX) - cons->out(*(uint64_t *)data); - platform->postConsoleInt(); - status |= TX_INT; - break; - } - - -#else - switch (daddr) { - case 0x0: - if (!(LCR & 0x80)) { // write byte - cons->out(*(uint8_t *)data); - platform->clearConsoleInt(); - status &= ~TX_INT; - if (UART_IER_THRI & IER) - txIntrEvent.scheduleIntr(); - } else { // dll divisor latch - ; - } - break; - case 0x1: - if (!(LCR & 0x80)) { // Intr Enable Register(IER) - IER = *(uint8_t*)data; - if (UART_IER_THRI & IER) - { - DPRINTF(Uart, "IER: IER_THRI set, scheduling TX intrrupt\n"); - txIntrEvent.scheduleIntr(); - } - else - { - DPRINTF(Uart, "IER: IER_THRI cleared, descheduling TX intrrupt\n"); - if (txIntrEvent.scheduled()) - txIntrEvent.deschedule(); - if (status & TX_INT) - platform->clearConsoleInt(); - status &= ~TX_INT; - } - - if ((UART_IER_RDI & IER) && cons->dataAvailable()) { - DPRINTF(Uart, "IER: IER_RDI set, scheduling RX intrrupt\n"); - rxIntrEvent.scheduleIntr(); - } else { - DPRINTF(Uart, "IER: IER_RDI cleared, descheduling RX intrrupt\n"); - if (rxIntrEvent.scheduled()) - rxIntrEvent.deschedule(); - if (status & RX_INT) - platform->clearConsoleInt(); - status &= ~RX_INT; - } - } else { // DLM divisor latch MSB - ; - } - break; - case 0x2: // FIFO Control Register (FCR) - break; - case 0x3: // Line Control Register (LCR) - LCR = *(uint8_t*)data; - break; - case 0x4: // Modem Control Register (MCR) - if (*(uint8_t*)data == (UART_MCR_LOOP | 0x0A)) - MCR = 0x9A; - break; - case 0x7: // Scratch Register (SCR) - // We are emulating a 8250 so we don't have a scratch reg - break; - default: - panic("Tried to access a UART port that doesn't exist\n"); - break; - } -#endif - - return No_Fault; -} - -void -Uart::dataAvailable() -{ -#ifdef ALPHA_TLASER - platform->postConsoleInt(); - status |= RX_INT; -#else - - // if the kernel wants an interrupt when we have data - if (IER & UART_IER_RDI) - { - platform->postConsoleInt(); - status |= RX_INT; - } - -#endif } Tick @@ -384,88 +74,5 @@ Uart::cacheAccess(MemReqPtr &req) return curTick + pioLatency; } -void -Uart::serialize(ostream &os) -{ -#ifdef ALPHA_TLASER - SERIALIZE_SCALAR(readAddr); - SERIALIZE_SCALAR(status); -#else - SERIALIZE_SCALAR(status); - SERIALIZE_SCALAR(IER); - SERIALIZE_SCALAR(DLAB); - SERIALIZE_SCALAR(LCR); - SERIALIZE_SCALAR(MCR); - Tick rxintrwhen; - if (rxIntrEvent.scheduled()) - rxintrwhen = rxIntrEvent.when(); - else - rxintrwhen = 0; - Tick txintrwhen; - if (txIntrEvent.scheduled()) - txintrwhen = txIntrEvent.when(); - else - txintrwhen = 0; - SERIALIZE_SCALAR(rxintrwhen); - SERIALIZE_SCALAR(txintrwhen); -#endif -} +DEFINE_SIM_OBJECT_CLASS_NAME("Uart", Uart) -void -Uart::unserialize(Checkpoint *cp, const std::string §ion) -{ -#ifdef ALPHA_TLASER - UNSERIALIZE_SCALAR(readAddr); - UNSERIALIZE_SCALAR(status); -#else - UNSERIALIZE_SCALAR(status); - UNSERIALIZE_SCALAR(IER); - UNSERIALIZE_SCALAR(DLAB); - UNSERIALIZE_SCALAR(LCR); - UNSERIALIZE_SCALAR(MCR); - Tick rxintrwhen; - Tick txintrwhen; - UNSERIALIZE_SCALAR(rxintrwhen); - UNSERIALIZE_SCALAR(txintrwhen); - if (rxintrwhen != 0) - rxIntrEvent.schedule(rxintrwhen); - if (txintrwhen != 0) - txIntrEvent.schedule(txintrwhen); -#endif - -} - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(Uart) - - SimObjectParam console; - SimObjectParam mmu; - SimObjectParam platform; - Param addr; - Param size; - SimObjectParam io_bus; - Param pio_latency; - SimObjectParam hier; - - -END_DECLARE_SIM_OBJECT_PARAMS(Uart) - -BEGIN_INIT_SIM_OBJECT_PARAMS(Uart) - - INIT_PARAM(console, "The console"), - INIT_PARAM(mmu, "Memory Controller"), - INIT_PARAM(platform, "Pointer to platfrom"), - INIT_PARAM(addr, "Device Address"), - INIT_PARAM_DFLT(size, "Device size", 0x8), - INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), - INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) - -END_INIT_SIM_OBJECT_PARAMS(Uart) - -CREATE_SIM_OBJECT(Uart) -{ - return new Uart(getInstanceName(), console, mmu, addr, size, hier, io_bus, - pio_latency, platform); -} - -REGISTER_SIM_OBJECT("Uart", Uart) diff --git a/dev/uart.hh b/dev/uart.hh index d1f167526..a2be3fb8e 100644 --- a/dev/uart.hh +++ b/dev/uart.hh @@ -26,14 +26,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* @file - * Defines a 8250 UART +/** @file + * Base class for UART */ -#ifndef __TSUNAMI_UART_HH__ -#define __TSUNAMI_UART_HH__ +#ifndef __UART_HH__ +#define __UART_HH__ -#include "dev/tsunamireg.h" #include "base/range.hh" #include "dev/io_device.hh" @@ -47,45 +46,25 @@ const int TX_INT = 0x2; class Uart : public PioDevice { - private: + protected: + int status; Addr addr; Addr size; SimConsole *cons; - - protected: - int readAddr; // tlaser only - uint8_t IER, DLAB, LCR, MCR; - int status; - - class IntrEvent : public Event - { - protected: - Uart *uart; - int intrBit; - public: - IntrEvent(Uart *u, int bit); - virtual void process(); - virtual const char *description(); - void scheduleIntr(); - }; - - IntrEvent txIntrEvent; - IntrEvent rxIntrEvent; - public: Uart(const std::string &name, SimConsole *c, MemoryController *mmu, Addr a, Addr s, HierParams *hier, Bus *bus, Tick pio_latency, Platform *p); - Fault read(MemReqPtr &req, uint8_t *data); - Fault write(MemReqPtr &req, const uint8_t *data); + virtual Fault read(MemReqPtr &req, uint8_t *data) = 0; + virtual Fault write(MemReqPtr &req, const uint8_t *data) = 0; /** * Inform the uart that there is data available. */ - void dataAvailable(); + virtual void dataAvailable() = 0; /** @@ -94,9 +73,6 @@ class Uart : public PioDevice */ bool intStatus() { return status ? true : false; } - virtual void serialize(std::ostream &os); - virtual void unserialize(Checkpoint *cp, const std::string §ion); - /** * Return how long this access will take. * @param req the memory request to calcuate @@ -105,4 +81,4 @@ class Uart : public PioDevice Tick cacheAccess(MemReqPtr &req); }; -#endif // __TSUNAMI_UART_HH__ +#endif // __UART_HH__ diff --git a/dev/uart8250.cc b/dev/uart8250.cc new file mode 100644 index 000000000..93e153319 --- /dev/null +++ b/dev/uart8250.cc @@ -0,0 +1,341 @@ +/* + * Copyright (c) 2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Implements a 8250 UART + */ + +#include +#include + +#include "base/inifile.hh" +#include "base/str.hh" // for to_number +#include "base/trace.hh" +#include "dev/simconsole.hh" +#include "dev/uart8250.hh" +#include "dev/platform.hh" +#include "mem/bus/bus.hh" +#include "mem/bus/pio_interface.hh" +#include "mem/bus/pio_interface_impl.hh" +#include "mem/functional_mem/memory_control.hh" +#include "sim/builder.hh" + +using namespace std; + +Uart8250::IntrEvent::IntrEvent(Uart8250 *u, int bit) + : Event(&mainEventQueue), uart(u) +{ + DPRINTF(Uart, "UART Interrupt Event Initilizing\n"); + intrBit = bit; +} + +const char * +Uart8250::IntrEvent::description() +{ + return "uart interrupt delay event"; +} + +void +Uart8250::IntrEvent::process() +{ + if (intrBit & uart->IER) { + DPRINTF(Uart, "UART InterEvent, interrupting\n"); + uart->platform->postConsoleInt(); + uart->status |= intrBit; + } + else + DPRINTF(Uart, "UART InterEvent, not interrupting\n"); + +} + +/* The linux serial driver (8250.c about line 1182) loops reading from + * the device until the device reports it has no more data to + * read. After a maximum of 255 iterations the code prints "serial8250 + * too much work for irq X," and breaks out of the loop. Since the + * simulated system is so much slower than the actual system, if a + * user is typing on the keyboard it is very easy for them to provide + * input at a fast enough rate to not allow the loop to exit and thus + * the error to be printed. This magic number provides a delay between + * the time the UART receives a character to send to the simulated + * system and the time it actually notifies the system it has a + * character to send to alleviate this problem. --Ali + */ +void +Uart8250::IntrEvent::scheduleIntr() +{ + static const Tick interval = (Tick)((Clock::Float::s / 2e9) * 450); + DPRINTF(Uart, "Scheduling IER interrupt for %#x, at cycle %lld\n", intrBit, + curTick + interval); + if (!scheduled()) + schedule(curTick + interval); + else + reschedule(curTick + interval); +} + + +Uart8250::Uart8250(const string &name, SimConsole *c, MemoryController *mmu, Addr a, + Addr s, HierParams *hier, Bus *bus, Tick pio_latency, Platform *p) + : Uart(name, c, mmu, a, s, hier, bus, pio_latency, p), + txIntrEvent(this, TX_INT), rxIntrEvent(this, RX_INT) +{ + IER = 0; + DLAB = 0; + LCR = 0; + MCR = 0; + +} + +Fault +Uart8250::read(MemReqPtr &req, uint8_t *data) +{ + Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); + DPRINTF(Uart, " read register %#x\n", daddr); + + assert(req->size == 1); + + switch (daddr) { + case 0x0: + if (!(LCR & 0x80)) { // read byte + if (cons->dataAvailable()) + cons->in(*data); + else { + *(uint8_t*)data = 0; + // A limited amount of these are ok. + DPRINTF(Uart, "empty read of RX register\n"); + } + status &= ~RX_INT; + platform->clearConsoleInt(); + + if (cons->dataAvailable() && (IER & UART_IER_RDI)) + rxIntrEvent.scheduleIntr(); + } else { // dll divisor latch + ; + } + break; + case 0x1: + if (!(LCR & 0x80)) { // Intr Enable Register(IER) + *(uint8_t*)data = IER; + } else { // DLM divisor latch MSB + ; + } + break; + case 0x2: // Intr Identification Register (IIR) + DPRINTF(Uart, "IIR Read, status = %#x\n", (uint32_t)status); + if (status) + *(uint8_t*)data = 0; + else + *(uint8_t*)data = 1; + break; + case 0x3: // Line Control Register (LCR) + *(uint8_t*)data = LCR; + break; + case 0x4: // Modem Control Register (MCR) + break; + case 0x5: // Line Status Register (LSR) + uint8_t lsr; + lsr = 0; + // check if there are any bytes to be read + if (cons->dataAvailable()) + lsr = UART_LSR_DR; + lsr |= UART_LSR_TEMT | UART_LSR_THRE; + *(uint8_t*)data = lsr; + break; + case 0x6: // Modem Status Register (MSR) + *(uint8_t*)data = 0; + break; + case 0x7: // Scratch Register (SCR) + *(uint8_t*)data = 0; // doesn't exist with at 8250. + break; + default: + panic("Tried to access a UART port that doesn't exist\n"); + break; + } + + return No_Fault; + +} + +Fault +Uart8250::write(MemReqPtr &req, const uint8_t *data) +{ + Addr daddr = req->paddr - (addr & EV5::PAddrImplMask); + + DPRINTF(Uart, " write register %#x value %#x\n", daddr, *(uint8_t*)data); + + switch (daddr) { + case 0x0: + if (!(LCR & 0x80)) { // write byte + cons->out(*(uint8_t *)data); + platform->clearConsoleInt(); + status &= ~TX_INT; + if (UART_IER_THRI & IER) + txIntrEvent.scheduleIntr(); + } else { // dll divisor latch + ; + } + break; + case 0x1: + if (!(LCR & 0x80)) { // Intr Enable Register(IER) + IER = *(uint8_t*)data; + if (UART_IER_THRI & IER) + { + DPRINTF(Uart, "IER: IER_THRI set, scheduling TX intrrupt\n"); + txIntrEvent.scheduleIntr(); + } + else + { + DPRINTF(Uart, "IER: IER_THRI cleared, descheduling TX intrrupt\n"); + if (txIntrEvent.scheduled()) + txIntrEvent.deschedule(); + if (status & TX_INT) + platform->clearConsoleInt(); + status &= ~TX_INT; + } + + if ((UART_IER_RDI & IER) && cons->dataAvailable()) { + DPRINTF(Uart, "IER: IER_RDI set, scheduling RX intrrupt\n"); + rxIntrEvent.scheduleIntr(); + } else { + DPRINTF(Uart, "IER: IER_RDI cleared, descheduling RX intrrupt\n"); + if (rxIntrEvent.scheduled()) + rxIntrEvent.deschedule(); + if (status & RX_INT) + platform->clearConsoleInt(); + status &= ~RX_INT; + } + } else { // DLM divisor latch MSB + ; + } + break; + case 0x2: // FIFO Control Register (FCR) + break; + case 0x3: // Line Control Register (LCR) + LCR = *(uint8_t*)data; + break; + case 0x4: // Modem Control Register (MCR) + if (*(uint8_t*)data == (UART_MCR_LOOP | 0x0A)) + MCR = 0x9A; + break; + case 0x7: // Scratch Register (SCR) + // We are emulating a 8250 so we don't have a scratch reg + break; + default: + panic("Tried to access a UART port that doesn't exist\n"); + break; + } + return No_Fault; +} + +void +Uart8250::dataAvailable() +{ + // if the kernel wants an interrupt when we have data + if (IER & UART_IER_RDI) + { + platform->postConsoleInt(); + status |= RX_INT; + } + +} + + + +void +Uart8250::serialize(ostream &os) +{ + SERIALIZE_SCALAR(status); + SERIALIZE_SCALAR(IER); + SERIALIZE_SCALAR(DLAB); + SERIALIZE_SCALAR(LCR); + SERIALIZE_SCALAR(MCR); + Tick rxintrwhen; + if (rxIntrEvent.scheduled()) + rxintrwhen = rxIntrEvent.when(); + else + rxintrwhen = 0; + Tick txintrwhen; + if (txIntrEvent.scheduled()) + txintrwhen = txIntrEvent.when(); + else + txintrwhen = 0; + SERIALIZE_SCALAR(rxintrwhen); + SERIALIZE_SCALAR(txintrwhen); +} + +void +Uart8250::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(status); + UNSERIALIZE_SCALAR(IER); + UNSERIALIZE_SCALAR(DLAB); + UNSERIALIZE_SCALAR(LCR); + UNSERIALIZE_SCALAR(MCR); + Tick rxintrwhen; + Tick txintrwhen; + UNSERIALIZE_SCALAR(rxintrwhen); + UNSERIALIZE_SCALAR(txintrwhen); + if (rxintrwhen != 0) + rxIntrEvent.schedule(rxintrwhen); + if (txintrwhen != 0) + txIntrEvent.schedule(txintrwhen); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Uart8250) + + SimObjectParam console; + SimObjectParam mmu; + SimObjectParam platform; + Param addr; + Param size; + SimObjectParam io_bus; + Param pio_latency; + SimObjectParam hier; + + +END_DECLARE_SIM_OBJECT_PARAMS(Uart8250) + +BEGIN_INIT_SIM_OBJECT_PARAMS(Uart8250) + + INIT_PARAM(console, "The console"), + INIT_PARAM(mmu, "Memory Controller"), + INIT_PARAM(platform, "Pointer to platfrom"), + INIT_PARAM(addr, "Device Address"), + INIT_PARAM_DFLT(size, "Device size", 0x8), + INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to", NULL), + INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), + INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams) + +END_INIT_SIM_OBJECT_PARAMS(Uart8250) + +CREATE_SIM_OBJECT(Uart8250) +{ + return new Uart8250(getInstanceName(), console, mmu, addr, size, hier, io_bus, + pio_latency, platform); +} + +REGISTER_SIM_OBJECT("Uart8250", Uart8250) diff --git a/dev/uart8250.hh b/dev/uart8250.hh new file mode 100644 index 000000000..046388fb5 --- /dev/null +++ b/dev/uart8250.hh @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2004 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** @file + * Defines a 8250 UART + */ + +#ifndef __TSUNAMI_UART_HH__ +#define __TSUNAMI_UART_HH__ + +#include "dev/tsunamireg.h" +#include "base/range.hh" +#include "dev/io_device.hh" +#include "dev/uart.hh" + +class SimConsole; +class Platform; + +class Uart8250 : public Uart +{ + + + protected: + uint8_t IER, DLAB, LCR, MCR; + + class IntrEvent : public Event + { + protected: + Uart8250 *uart; + int intrBit; + public: + IntrEvent(Uart8250 *u, int bit); + virtual void process(); + virtual const char *description(); + void scheduleIntr(); + }; + + IntrEvent txIntrEvent; + IntrEvent rxIntrEvent; + + public: + Uart8250(const std::string &name, SimConsole *c, MemoryController *mmu, + Addr a, Addr s, HierParams *hier, Bus *bus, Tick pio_latency, + Platform *p); + + virtual Fault read(MemReqPtr &req, uint8_t *data); + virtual Fault write(MemReqPtr &req, const uint8_t *data); + + + /** + * Inform the uart that there is data available. + */ + virtual void dataAvailable(); + + + /** + * Return if we have an interrupt pending + * @return interrupt status + */ + virtual bool intStatus() { return status ? true : false; } + + virtual void serialize(std::ostream &os); + virtual void unserialize(Checkpoint *cp, const std::string §ion); + +}; + +#endif // __TSUNAMI_UART_HH__ diff --git a/python/m5/objects/Uart.py b/python/m5/objects/Uart.py index cfb09acad..57b8b44af 100644 --- a/python/m5/objects/Uart.py +++ b/python/m5/objects/Uart.py @@ -3,5 +3,13 @@ from Device import PioDevice class Uart(PioDevice): type = 'Uart' + abstract = True console = Param.SimConsole(Parent.any, "The console") size = Param.Addr(0x8, "Device size") + +class Uart8250(Uart): + type = 'Uart8250' + +class Uart8530(Uart): + type = 'Uart8530' +