better debugging of DMA operations
[gem5.git] / dev / tsunami_cchip.cc
index cdef6202ed8bc5e67425fbddd35021f990341f10..870924a2fff133ab5307c6bdd8fe21ceef2262fd 100644 (file)
@@ -1,4 +1,30 @@
-/* $Id$ */
+/*
+ * 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
  * Emulation of the Tsunami CChip CSRs
 #include <vector>
 
 #include "base/trace.hh"
-#include "cpu/exec_context.hh"
-#include "dev/console.hh"
 #include "dev/tsunami_cchip.hh"
 #include "dev/tsunamireg.h"
 #include "dev/tsunami.hh"
-#include "cpu/intr_control.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 "cpu/intr_control.hh"
 #include "sim/builder.hh"
 #include "sim/system.hh"
 
 using namespace std;
 
 TsunamiCChip::TsunamiCChip(const string &name, Tsunami *t, Addr a,
-                           MemoryController *mmu)
-    : FunctionalMemory(name), addr(a), tsunami(t)
+                           MemoryController *mmu, HierParams *hier, Bus* bus,
+                           Tick pio_latency)
+    : PioDevice(name), addr(a), tsunami(t)
 {
     mmu->add_child(this, Range<Addr>(addr, addr + size));
 
@@ -31,11 +59,19 @@ TsunamiCChip::TsunamiCChip(const string &name, Tsunami *t, Addr a,
         dim[i] = 0;
         dir[i] = 0;
         dirInterrupting[i] = false;
+        ipiInterrupting[i] = false;
+        RTCInterrupting[i] = false;
+    }
+
+    if (bus) {
+        pioInterface = newPioInterface(name, hier, bus, this,
+                                      &TsunamiCChip::cacheAccess);
+        pioInterface->addAddrRange(addr, addr + size - 1);
+        pioLatency = pio_latency * bus->clockRatio;
     }
 
     drir = 0;
     misc = 0;
-    RTCInterrupting = false;
 
     //Put back pointer in tsunami
     tsunami->cchip = this;
@@ -47,7 +83,7 @@ TsunamiCChip::read(MemReqPtr &req, uint8_t *data)
     DPRINTF(Tsunami, "read  va=%#x size=%d\n",
             req->vaddr, req->size);
 
-    Addr daddr = (req->paddr & size) >> 6;
+    Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
     ExecContext *xc = req->xc;
 
     switch (req->size) {
@@ -67,7 +103,7 @@ TsunamiCChip::read(MemReqPtr &req, uint8_t *data)
               case TSDEV_CC_AAR1:
               case TSDEV_CC_AAR2:
               case TSDEV_CC_AAR3:
-                  panic("TSDEV_CC_AARx not implemeted\n");
+                  *(uint64_t*)data = 0;
                   return No_Fault;
               case TSDEV_CC_DIM0:
                   *(uint64_t*)data = dim[0];
@@ -130,30 +166,77 @@ TsunamiCChip::read(MemReqPtr &req, uint8_t *data)
 Fault
 TsunamiCChip::write(MemReqPtr &req, const uint8_t *data)
 {
-    DPRINTF(Tsunami, "write - va=%#x size=%d \n",
-            req->vaddr, req->size);
+    DPRINTF(Tsunami, "write - va=%#x value=%#x size=%d \n",
+            req->vaddr, *(uint64_t*)data, req->size);
+
+    Addr daddr = (req->paddr - (addr & PA_IMPL_MASK)) >> 6;
 
-    Addr daddr = (req->paddr & size) >> 6;
+    bool supportedWrite = false;
+    uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
 
     switch (req->size) {
 
       case sizeof(uint64_t):
           switch(daddr) {
-              case TSDEV_CC_CSR:
+            case TSDEV_CC_CSR:
                   panic("TSDEV_CC_CSR write\n");
                   return No_Fault;
               case TSDEV_CC_MTR:
                   panic("TSDEV_CC_MTR write not implemented\n");
                    return No_Fault;
               case TSDEV_CC_MISC:
-                //If it is the seventh bit, clear the RTC interrupt
-                if ((*(uint64_t*) data) & (1<<4)) {
-                    RTCInterrupting = false;
-                    tsunami->intrctrl->clear(0, TheISA::INTLEVEL_IRQ2, 0);
-                    DPRINTF(Tsunami, "clearing rtc interrupt\n");
-                    misc &= ~(1<<4);
-                } else panic("TSDEV_CC_MISC write not implemented\n");
-                  return No_Fault;
+                //If it is the 4-7th bit, clear the RTC interrupt
+                uint64_t itintr;
+                if ((itintr = (*(uint64_t*) data) & (0xf<<4))) {
+                    //Clear the bits in ITINTR
+                    misc &= ~(itintr);
+                    for (int i=0; i < size; i++) {
+                        if ((itintr & (1 << (i+4))) && RTCInterrupting[i]) {
+                            tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ2, 0);
+                            RTCInterrupting[i] = false;
+                            DPRINTF(Tsunami, "clearing rtc interrupt to cpu=%d\n", i);
+                        }
+                    }
+                    supportedWrite = true;
+                }
+                //If it is 12th-15th bit, IPI sent to Processor 1
+                uint64_t ipreq;
+                if ((ipreq = (*(uint64_t*) data) & (0xf << 12))) {
+                    //Set the bits in IPINTR
+                    misc |= (ipreq >> 4);
+                    for (int i=0; i < size; i++) {
+                        if ((ipreq & (1 << (i + 12)))) {
+                            if (!ipiInterrupting[i])
+                                tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ3, 0);
+                            ipiInterrupting[i]++;
+                            DPRINTF(IPI, "send cpu=%d pending=%d from=%d\n", i,
+                                    ipiInterrupting[i], req->cpu_num);
+                        }
+                    }
+                    supportedWrite = true;
+                }
+                //If it is bits 8-11, then clearing IPI's
+                uint64_t ipintr;
+                if ((ipintr = (*(uint64_t*) data) & (0xf << 8))) {
+                    //Clear the bits in IPINTR
+                    misc &= ~(ipintr);
+                    for (int i=0; i < size; i++) {
+                        if ((ipintr & (1 << (i + 8))) && ipiInterrupting[i]) {
+                            if (!(--ipiInterrupting[i]))
+                                tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ3, 0);
+                            DPRINTF(IPI, "clearing cpu=%d pending=%d from=%d\n", i,
+                                    ipiInterrupting[i] + 1, req->cpu_num);
+                        }
+                    }
+                    supportedWrite = true;
+                }
+
+        // ignore NXMs
+        if (*(uint64_t*)data & 0x10000000)
+            supportedWrite = true;
+
+                if(!supportedWrite) panic("TSDEV_CC_MISC write not implemented\n");
+                return No_Fault;
               case TSDEV_CC_AAR0:
               case TSDEV_CC_AAR1:
               case TSDEV_CC_AAR2:
@@ -161,47 +244,52 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data)
                   panic("TSDEV_CC_AARx write not implemeted\n");
                   return No_Fault;
               case TSDEV_CC_DIM0:
-                   dim[0] = *(uint64_t*)data;
-                   if (dim[0] & drir) {
-                       dir[0] = dim[0] & drir;
-                       if (!dirInterrupting[0]) {
-                           dirInterrupting[0] = true;
-                           tsunami->intrctrl->post(0, TheISA::INTLEVEL_IRQ1, 0);
-                           DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n");
-                       }
-                   }
-                  return No_Fault;
               case TSDEV_CC_DIM1:
-                  dim[1] = *(uint64_t*)data;
-                  if (dim[1] & drir) {
-                       dir[1] = dim[1] & drir;
-                       if (!dirInterrupting[1]) {
-                           dirInterrupting[1] = true;
-                           tsunami->intrctrl->post(1, TheISA::INTLEVEL_IRQ1, 0);
-                           DPRINTF(Tsunami, "posting dir interrupt to cpu 1\n");
-                       }
-                  }
-                  return No_Fault;
               case TSDEV_CC_DIM2:
-                  dim[2] = *(uint64_t*)data;
-                  if (dim[2] & drir) {
-                       dir[2] = dim[2] & drir;
-                       if (!dirInterrupting[2]) {
-                           dirInterrupting[2] = true;
-                           tsunami->intrctrl->post(2, TheISA::INTLEVEL_IRQ1, 0);
-                           DPRINTF(Tsunami, "posting dir interrupt to cpu 2\n");
-                       }
-                  }
-                  return No_Fault;
               case TSDEV_CC_DIM3:
-                  dim[3] = *(uint64_t*)data;
-                  if ((dim[3] & drir) /*And Not Already Int*/) {
-                       dir[3] = dim[3] & drir;
-                       if (!dirInterrupting[3]) {
-                           dirInterrupting[3] = true;
-                           tsunami->intrctrl->post(3, TheISA::INTLEVEL_IRQ1, 0);
-                           DPRINTF(Tsunami, "posting dir interrupt to cpu 3\n");
-                       }
+                  int number;
+                  if(daddr == TSDEV_CC_DIM0)
+                      number = 0;
+                  else if(daddr == TSDEV_CC_DIM1)
+                      number = 1;
+                  else if(daddr == TSDEV_CC_DIM2)
+                      number = 2;
+                  else
+                      number = 3;
+
+                  uint64_t bitvector;
+                  uint64_t olddim;
+                  uint64_t olddir;
+
+                  olddim = dim[number];
+                  olddir = dir[number];
+                  dim[number] = *(uint64_t*)data;
+                  dir[number] = dim[number] & drir;
+                  for(int x = 0; x < 64; x++)
+                  {
+                      bitvector = (uint64_t)1 << x;
+                      // Figure out which bits have changed
+                      if ((dim[number] & bitvector) != (olddim & bitvector))
+                      {
+                          // The bit is now set and it wasn't before (set)
+                          if((dim[number] & bitvector) && (dir[number] & bitvector))
+                          {
+                              tsunami->intrctrl->post(number, TheISA::INTLEVEL_IRQ1, x);
+                              DPRINTF(Tsunami, "posting dir interrupt to cpu 0\n");
+                          }
+                          else if ((olddir & bitvector) &&
+                                  !(dir[number] & bitvector))
+                          {
+                              // The bit was set and now its now clear and
+                              // we were interrupting on that bit before
+                              tsunami->intrctrl->clear(number, TheISA::INTLEVEL_IRQ1, x);
+                              DPRINTF(Tsunami, "dim write resulting in clear"
+                                      "dir interrupt to cpu 0\n");
+
+                          }
+
+
+                      }
                   }
                   return No_Fault;
               case TSDEV_CC_DIR0:
@@ -209,25 +297,20 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data)
               case TSDEV_CC_DIR2:
               case TSDEV_CC_DIR3:
                   panic("TSDEV_CC_DIR write not implemented\n");
-                  return No_Fault;
               case TSDEV_CC_DRIR:
                   panic("TSDEV_CC_DRIR write not implemented\n");
-                  return No_Fault;
               case TSDEV_CC_PRBEN:
                   panic("TSDEV_CC_PRBEN write not implemented\n");
-                  return No_Fault;
               case TSDEV_CC_IIC0:
               case TSDEV_CC_IIC1:
               case TSDEV_CC_IIC2:
               case TSDEV_CC_IIC3:
                   panic("TSDEV_CC_IICx write not implemented\n");
-                  return No_Fault;
               case TSDEV_CC_MPR0:
               case TSDEV_CC_MPR1:
               case TSDEV_CC_MPR2:
               case TSDEV_CC_MPR3:
                   panic("TSDEV_CC_MPRx write not implemented\n");
-                  return No_Fault;
               default:
                   panic("default in cchip read reached, accessing 0x%x\n");
           }
@@ -246,45 +329,76 @@ TsunamiCChip::write(MemReqPtr &req, const uint8_t *data)
 }
 
 void
-TsunamiCChip::postDRIR(uint64_t bitvector)
+TsunamiCChip::postRTC()
+{
+    int size = tsunami->intrctrl->cpu->system->execContexts.size();
+
+    for (int i = 0; i < size; i++) {
+        if (!RTCInterrupting[i]) {
+            misc |= 16 << i;
+            RTCInterrupting[i] = true;
+            tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ2, 0);
+            DPRINTF(Tsunami, "Posting RTC interrupt to cpu=%d", i);
+        }
+    }
+
+}
+
+void
+TsunamiCChip::postDRIR(uint32_t interrupt)
 {
+    uint64_t bitvector = (uint64_t)0x1 << interrupt;
     drir |= bitvector;
-    for(int i=0; i < Tsunami::Max_CPUs; i++) {
-        if (bitvector & dim[i]) {
-            dir[i] |= bitvector;
-            if (!dirInterrupting[i]) {
-                dirInterrupting[i] = true;
-                tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, 0);
-                DPRINTF(Tsunami, "posting dir interrupt to cpu %d\n",i);
-            }
+    uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
+    for(int i=0; i < size; i++) {
+        dir[i] = dim[i] & drir;
+        if (dim[i] & bitvector) {
+                tsunami->intrctrl->post(i, TheISA::INTLEVEL_IRQ1, interrupt);
+                DPRINTF(Tsunami, "posting dir interrupt to cpu %d,"
+                        "interrupt %d\n",i, interrupt);
         }
     }
 }
 
 void
-TsunamiCChip::clearDRIR(uint64_t bitvector)
+TsunamiCChip::clearDRIR(uint32_t interrupt)
 {
-    drir &= ~bitvector;
-    for(int i=0; i < Tsunami::Max_CPUs; i++) {
-        dir[i] &= ~bitvector;
-        if (!dir[i]) {
-            dirInterrupting[i] = false;
-            tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, 0);
-            DPRINTF(Tsunami, "clearing dir interrupt to cpu %d\n", i);
+    uint64_t bitvector = (uint64_t)0x1 << interrupt;
+    uint64_t size = tsunami->intrctrl->cpu->system->execContexts.size();
+    if (drir & bitvector)
+    {
+        drir &= ~bitvector;
+        for(int i=0; i < size; i++) {
+            if (dir[i] & bitvector) {
+                tsunami->intrctrl->clear(i, TheISA::INTLEVEL_IRQ1, interrupt);
+                DPRINTF(Tsunami, "clearing dir interrupt to cpu %d,"
+                    "interrupt %d\n",i, interrupt);
 
+            }
+            dir[i] = dim[i] & drir;
         }
     }
+    else
+        DPRINTF(Tsunami, "Spurrious clear? interrupt %d\n", interrupt);
 }
 
+Tick
+TsunamiCChip::cacheAccess(MemReqPtr &req)
+{
+    return curTick + pioLatency;
+}
+
+
 void
 TsunamiCChip::serialize(std::ostream &os)
 {
     SERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
     SERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
     SERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs);
+    SERIALIZE_ARRAY(ipiInterrupting, Tsunami::Max_CPUs);
     SERIALIZE_SCALAR(drir);
     SERIALIZE_SCALAR(misc);
-    SERIALIZE_SCALAR(RTCInterrupting);
+    SERIALIZE_ARRAY(RTCInterrupting, Tsunami::Max_CPUs);
 }
 
 void
@@ -293,9 +407,10 @@ TsunamiCChip::unserialize(Checkpoint *cp, const std::string &section)
     UNSERIALIZE_ARRAY(dim, Tsunami::Max_CPUs);
     UNSERIALIZE_ARRAY(dir, Tsunami::Max_CPUs);
     UNSERIALIZE_ARRAY(dirInterrupting, Tsunami::Max_CPUs);
+    UNSERIALIZE_ARRAY(ipiInterrupting, Tsunami::Max_CPUs);
     UNSERIALIZE_SCALAR(drir);
     UNSERIALIZE_SCALAR(misc);
-    UNSERIALIZE_SCALAR(RTCInterrupting);
+    UNSERIALIZE_ARRAY(RTCInterrupting, Tsunami::Max_CPUs);
 }
 
 BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
@@ -303,6 +418,9 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
     SimObjectParam<Tsunami *> tsunami;
     SimObjectParam<MemoryController *> mmu;
     Param<Addr> addr;
+    SimObjectParam<Bus*> io_bus;
+    Param<Tick> pio_latency;
+    SimObjectParam<HierParams *> hier;
 
 END_DECLARE_SIM_OBJECT_PARAMS(TsunamiCChip)
 
@@ -310,13 +428,17 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(TsunamiCChip)
 
     INIT_PARAM(tsunami, "Tsunami"),
     INIT_PARAM(mmu, "Memory Controller"),
-    INIT_PARAM(addr, "Device Address")
+    INIT_PARAM(addr, "Device Address"),
+    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(TsunamiCChip)
 
 CREATE_SIM_OBJECT(TsunamiCChip)
 {
-    return new TsunamiCChip(getInstanceName(), tsunami, addr, mmu);
+    return new TsunamiCChip(getInstanceName(), tsunami, addr, mmu, hier,
+                            io_bus, pio_latency);
 }
 
 REGISTER_SIM_OBJECT("TsunamiCChip", TsunamiCChip)