arm: Wire up the GIC with the platform in the base class
[gem5.git] / src / dev / uart8250.cc
index 8e6843841f14d340d68c0cb68e9a9ff104809875..e840d2a56a52cbb0e633abb49b5fcf870ec9cd69 100644 (file)
@@ -24,6 +24,8 @@
  * 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.
+ *
+ * Authors: Ali Saidi
  */
 
 /** @file
 #include <string>
 #include <vector>
 
-#include "arch/alpha/ev5.hh"
 #include "base/inifile.hh"
-#include "base/str.hh"        // for to_number
 #include "base/trace.hh"
-#include "dev/simconsole.hh"
-#include "dev/uart8250.hh"
+#include "config/the_isa.hh"
+#include "debug/Uart.hh"
 #include "dev/platform.hh"
-#include "sim/builder.hh"
+#include "dev/terminal.hh"
+#include "dev/uart8250.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
 
 using namespace std;
 using namespace TheISA;
 
 Uart8250::IntrEvent::IntrEvent(Uart8250 *u, int bit)
-    : Event(&mainEventQueue), uart(u)
+    : uart(u)
 {
     DPRINTF(Uart, "UART Interrupt Event Initilizing\n");
     intrBit = bit;
 }
 
 const char *
-Uart8250::IntrEvent::description()
+Uart8250::IntrEvent::description() const
 {
-    return "uart interrupt delay event";
+    return "uart interrupt delay";
 }
 
 void
@@ -65,6 +68,7 @@ Uart8250::IntrEvent::process()
        DPRINTF(Uart, "UART InterEvent, interrupting\n");
        uart->platform->postConsoleInt();
        uart->status |= intrBit;
+       uart->lastTxInt = curTick();
     }
     else
        DPRINTF(Uart, "UART InterEvent, not interrupting\n");
@@ -86,45 +90,37 @@ Uart8250::IntrEvent::process()
 void
 Uart8250::IntrEvent::scheduleIntr()
 {
-    static const Tick interval = (Tick)((Clock::Float::s / 2e9) * 450);
+    static const Tick interval = 225 * SimClock::Int::ns;
     DPRINTF(Uart, "Scheduling IER interrupt for %#x, at cycle %lld\n", intrBit,
-            curTick + interval);
+            curTick() + interval);
     if (!scheduled())
-        schedule(curTick + interval);
+        uart->schedule(this, curTick() + interval);
     else
-        reschedule(curTick + interval);
+        uart->reschedule(this, curTick() + interval);
 }
 
 
-Uart8250::Uart8250(Params *p)
-    : Uart(p), txIntrEvent(this, TX_INT), rxIntrEvent(this, RX_INT)
+Uart8250::Uart8250(const Params *p)
+    : Uart(p, 8), IER(0), DLAB(0), LCR(0), MCR(0), lastTxInt(0),
+      txIntrEvent(this, TX_INT), rxIntrEvent(this, RX_INT)
 {
-    pioSize = 8;
-
-    IER = 0;
-    DLAB = 0;
-    LCR = 0;
-    MCR = 0;
 }
 
 Tick
-Uart8250::read(Packet *pkt)
+Uart8250::read(PacketPtr pkt)
 {
-    assert(pkt->result == Packet::Unknown);
     assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
     assert(pkt->getSize() == 1);
 
-    pkt->time += pioDelay;
     Addr daddr = pkt->getAddr() - pioAddr;
-    pkt->allocate();
 
     DPRINTF(Uart, " read register %#x\n", daddr);
 
     switch (daddr) {
         case 0x0:
             if (!(LCR & 0x80)) { // read byte
-                if (cons->dataAvailable())
-                    cons->in(*pkt->getPtr<uint8_t>());
+                if (term->dataAvailable())
+                    pkt->set(term->in());
                 else {
                     pkt->set((uint8_t)0);
                     // A limited amount of these are ok.
@@ -133,7 +129,7 @@ Uart8250::read(Packet *pkt)
                 status &= ~RX_INT;
                 platform->clearConsoleInt();
 
-                if (cons->dataAvailable() && (IER & UART_IER_RDI))
+                if (term->dataAvailable() && (IER & UART_IER_RDI))
                     rxIntrEvent.scheduleIntr();
             } else { // dll divisor latch
                ;
@@ -151,24 +147,25 @@ Uart8250::read(Packet *pkt)
 
             if (status & RX_INT) /* Rx data interrupt has a higher priority */
                 pkt->set(IIR_RXID);
-            else if (status & TX_INT)
+            else if (status & TX_INT) {
                 pkt->set(IIR_TXID);
-            else
+                //Tx interrupts are cleared on IIR reads
+                status &= ~TX_INT;
+            } else
                 pkt->set(IIR_NOPEND);
 
-            //Tx interrupts are cleared on IIR reads
-            status &= ~TX_INT;
             break;
         case 0x3: // Line Control Register (LCR)
             pkt->set(LCR);
             break;
         case 0x4: // Modem Control Register (MCR)
+            pkt->set(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())
+            if (term->dataAvailable())
                 lsr = UART_LSR_DR;
             lsr |= UART_LSR_TEMT | UART_LSR_THRE;
             pkt->set(lsr);
@@ -186,19 +183,17 @@ Uart8250::read(Packet *pkt)
 /*    uint32_t d32 = *data;
     DPRINTF(Uart, "Register read to register %#x returned %#x\n", daddr, d32);
 */
-    pkt->result = Packet::Success;
+    pkt->makeAtomicResponse();
     return pioDelay;
 }
 
 Tick
-Uart8250::write(Packet *pkt)
+Uart8250::write(PacketPtr pkt)
 {
 
-    assert(pkt->result == Packet::Unknown);
     assert(pkt->getAddr() >= pioAddr && pkt->getAddr() < pioAddr + pioSize);
     assert(pkt->getSize() == 1);
 
-    pkt->time += pioDelay;
     Addr daddr = pkt->getAddr() - pioAddr;
 
     DPRINTF(Uart, " write register %#x value %#x\n", daddr, pkt->get<uint8_t>());
@@ -206,7 +201,7 @@ Uart8250::write(Packet *pkt)
     switch (daddr) {
         case 0x0:
             if (!(LCR & 0x80)) { // write byte
-                cons->out(pkt->get<uint8_t>());
+                term->out(pkt->get<uint8_t>());
                 platform->clearConsoleInt();
                 status &= ~TX_INT;
                 if (UART_IER_THRI & IER)
@@ -221,25 +216,33 @@ Uart8250::write(Packet *pkt)
                 if (UART_IER_THRI & IER)
                 {
                     DPRINTF(Uart, "IER: IER_THRI set, scheduling TX intrrupt\n");
-                    txIntrEvent.scheduleIntr();
+                    if (curTick() - lastTxInt > 225 * SimClock::Int::ns) {
+                        DPRINTF(Uart, "-- Interrupting Immediately... %d,%d\n",
+                                curTick(), lastTxInt);
+                        txIntrEvent.process();
+                    } else {
+                        DPRINTF(Uart, "-- Delaying interrupt... %d,%d\n",
+                                curTick(), lastTxInt);
+                        txIntrEvent.scheduleIntr();
+                    }
                 }
                 else
                 {
                     DPRINTF(Uart, "IER: IER_THRI cleared, descheduling TX intrrupt\n");
                     if (txIntrEvent.scheduled())
-                        txIntrEvent.deschedule();
+                        deschedule(txIntrEvent);
                     if (status & TX_INT)
                         platform->clearConsoleInt();
                     status &= ~TX_INT;
                 }
 
-                if ((UART_IER_RDI & IER) && cons->dataAvailable()) {
+                if ((UART_IER_RDI & IER) && term->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();
+                        deschedule(rxIntrEvent);
                     if (status & RX_INT)
                         platform->clearConsoleInt();
                     status &= ~RX_INT;
@@ -264,7 +267,7 @@ Uart8250::write(Packet *pkt)
             panic("Tried to access a UART port that doesn't exist\n");
             break;
     }
-    pkt->result = Packet::Success;
+    pkt->makeAtomicResponse();
     return pioDelay;
 }
 
@@ -280,16 +283,14 @@ Uart8250::dataAvailable()
 
 }
 
-void
-Uart8250::addressRanges(AddrRangeList &range_list)
+AddrRangeList
+Uart8250::getAddrRanges() const
 {
-    assert(pioSize != 0);
-    range_list.clear();
-    range_list.push_back(RangeSize(pioAddr, pioSize));
+    AddrRangeList ranges;
+    ranges.push_back(RangeSize(pioAddr, pioSize));
+    return ranges;
 }
 
-
-
 void
 Uart8250::serialize(ostream &os)
 {
@@ -325,42 +326,13 @@ Uart8250::unserialize(Checkpoint *cp, const std::string &section)
     UNSERIALIZE_SCALAR(rxintrwhen);
     UNSERIALIZE_SCALAR(txintrwhen);
     if (rxintrwhen != 0)
-        rxIntrEvent.schedule(rxintrwhen);
+        schedule(rxIntrEvent, rxintrwhen);
     if (txintrwhen != 0)
-        txIntrEvent.schedule(txintrwhen);
+        schedule(txIntrEvent, txintrwhen);
 }
 
-BEGIN_DECLARE_SIM_OBJECT_PARAMS(Uart8250)
-
-    Param<Addr> pio_addr;
-    Param<Tick> pio_latency;
-    SimObjectParam<Platform *> platform;
-    SimObjectParam<SimConsole *> sim_console;
-    SimObjectParam<System *> system;
-
-END_DECLARE_SIM_OBJECT_PARAMS(Uart8250)
-
-BEGIN_INIT_SIM_OBJECT_PARAMS(Uart8250)
-
-    INIT_PARAM(pio_addr, "Device Address"),
-    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000),
-    INIT_PARAM(platform, "platform"),
-    INIT_PARAM(sim_console, "The Simulator Console"),
-    INIT_PARAM(system, "system object")
-
-END_INIT_SIM_OBJECT_PARAMS(Uart8250)
-
-CREATE_SIM_OBJECT(Uart8250)
+Uart8250 *
+Uart8250Params::create()
 {
-    Uart8250::Params *p = new Uart8250::Params;
-    p->name = getInstanceName();
-    p->pio_addr = pio_addr;
-    p->pio_delay = pio_latency;
-    p->platform = platform;
-    p->cons = sim_console;
-    p->system = system;
-    return new Uart8250(p);
+    return new Uart8250(this);
 }
-
-REGISTER_SIM_OBJECT("Uart8250", Uart8250)
-