split uart into urt8250 and uart8530
authorAli Saidi <saidi@eecs.umich.edu>
Sun, 5 Jun 2005 05:22:21 +0000 (01:22 -0400)
committerAli Saidi <saidi@eecs.umich.edu>
Sun, 5 Jun 2005 05:22:21 +0000 (01:22 -0400)
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

14 files changed:
SConscript
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
dev/uart.cc
dev/uart.hh
dev/uart8250.cc [new file with mode: 0644]
dev/uart8250.hh [new file with mode: 0644]
python/m5/objects/Uart.py

index 059ce0ca1cf315afca8c389f7096eaa93120126c..0efb3e1e567ab71fe0c13c3208bf841eb36f237c 100644 (file)
@@ -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
index 637cd7825f31a481db4f72ac01248b8019e2dca7..46ad1325f05ea40906f82e622472f3694cee46b3 100644 (file)
@@ -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
  */
index 302aa5a899271544d08d422c657e3a21cf051b3f..a1e90a375bb59c342d2181aceb3332f225462171 100644 (file)
@@ -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
  */
index d73a6c6b263c559ffa5459730852b6431263f72e..be53149e7d7bf598f0533da8e1699be2161d09b9 100644 (file)
@@ -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
  */
index 55a2c5ea611ec77b9d12b1d0f29d75874dd99086..584c8a3469d481062f7380c3ca76de6c68c7865f 100644 (file)
@@ -26,6 +26,9 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+/** @file Implementation of Tsunami platform.
+ */
+
 #include <deque>
 #include <string>
 #include <vector>
index a10dba082c71780566f8c23ce7252d308166dd1c..125dce32508546209490b1ae4df19998be887f08 100644 (file)
@@ -26,7 +26,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* @file
+/** @file
  * Emulation of the Tsunami CChip CSRs
  */
 
index 2e12b41ea2b402b894adf9129c93c79edce728c2..1d1266db023a4bfc29393c8f26240aae9755081b 100644 (file)
@@ -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
  */
 
index f8bec77c0c45b1a9c0e66144bb1231edb804e55d..638a2d4278920bf8fb0a3c994f6deb546b689257 100644 (file)
@@ -26,7 +26,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* @file
+/** @file
  * Tsunami PChip (pci)
  */
 
index 290f21a5bc7bc5b2b393e3c4b7407732c9d2aa72..df10ce29d089d4ed3d61f9a4dfbd8ab9441eb1a1 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+/** @file
+ * List of Tsunami CSRs
+ */
+
 #ifndef __TSUNAMIREG_H__
 #define __TSUNAMIREG_H__
 
index c04a5d06600e1766c294679b54deb1877604966b..cf58b7fdd579f729e413fefda57414ac4f96157f 100644 (file)
@@ -26,7 +26,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* @file
+/** @file
  * Implements a 8250 UART
  */
 
 
 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
-}
-
-void
-Uart::unserialize(Checkpoint *cp, const std::string &section)
-{
-#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<SimConsole *> console;
-    SimObjectParam<MemoryController *> mmu;
-    SimObjectParam<Platform *> platform;
-    Param<Addr> addr;
-    Param<Addr> size;
-    SimObjectParam<Bus*> io_bus;
-    Param<Tick> pio_latency;
-    SimObjectParam<HierParams *> 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);
-}
+DEFINE_SIM_OBJECT_CLASS_NAME("Uart", Uart)
 
-REGISTER_SIM_OBJECT("Uart", Uart)
index d1f167526943dc2973dc9d4f0c79f7ce730a52b0..a2be3fb8e00c53f0beaa4dae26276f0a670e867c 100644 (file)
  * 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 &section);
-
     /**
      * 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 (file)
index 0000000..93e1533
--- /dev/null
@@ -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 <string>
+#include <vector>
+
+#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 &section)
+{
+    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<SimConsole *> console;
+    SimObjectParam<MemoryController *> mmu;
+    SimObjectParam<Platform *> platform;
+    Param<Addr> addr;
+    Param<Addr> size;
+    SimObjectParam<Bus*> io_bus;
+    Param<Tick> pio_latency;
+    SimObjectParam<HierParams *> 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 (file)
index 0000000..046388f
--- /dev/null
@@ -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 &section);
+
+};
+
+#endif // __TSUNAMI_UART_HH__
index cfb09acadae5a8f6378095496aa8100c2fc378ad..57b8b44af79dfaba52e8d8e90546dda402396607 100644 (file)
@@ -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'
+