memory mode information now contained in system object
authorAli Saidi <saidi@eecs.umich.edu>
Thu, 13 Jul 2006 00:22:07 +0000 (20:22 -0400)
committerAli Saidi <saidi@eecs.umich.edu>
Thu, 13 Jul 2006 00:22:07 +0000 (20:22 -0400)
States are now running, draining, or drained. memory state information moved into system object
system parameter is not fs only for cpus
Implement drain() support in devices
Update for drain() call that returns number of times drain_event->process() will be called

Break O3 CPU! No sense in putting in a hack change that kevin is going to remove in a few minutes i imagine

src/cpu/simple/atomic.cc:
src/cpu/simple/atomic.hh:
    Since se mode has a system, allow access to it
    Verify that the atomic cpu is connected to an atomic system on resume
src/cpu/simple/base.cc:
    Since se mode has a system, allow access to it
src/cpu/simple/timing.cc:
src/cpu/simple/timing.hh:
    Update for new drain() call that returns number of times drain_event->process() will be called and memory state being moved into the system
    Since se mode has a system, allow access to it
    Verify that the timing cpu is connected to an timing system on resume
src/dev/ide_disk.cc:
src/dev/io_device.cc:
src/dev/io_device.hh:
src/dev/ns_gige.cc:
src/dev/ns_gige.hh:
src/dev/pcidev.cc:
src/dev/pcidev.hh:
src/dev/sinic.cc:
src/dev/sinic.hh:
    Implement drain() support in devices
src/python/m5/config.py:
    Allow drain to return number of times drain_event->process() will be called. Normally 0 or 1 but things like O3 cpu or devices with multiple ports may want to call it many times
src/python/m5/objects/BaseCPU.py:
    move system parameter out of fs to everyone
src/sim/sim_object.cc:
src/sim/sim_object.hh:
    States are now running, draining, or drained. memory state information moved into system object
src/sim/system.cc:
src/sim/system.hh:
    memory mode information now contained in system object

--HG--
extra : convert_revision : 1389c77e66ee6d9710bf77b4306fb47e107b21cf

20 files changed:
src/cpu/simple/atomic.cc
src/cpu/simple/atomic.hh
src/cpu/simple/base.cc
src/cpu/simple/timing.cc
src/cpu/simple/timing.hh
src/dev/ide_disk.cc
src/dev/io_device.cc
src/dev/io_device.hh
src/dev/ns_gige.cc
src/dev/ns_gige.hh
src/dev/pcidev.cc
src/dev/pcidev.hh
src/dev/sinic.cc
src/dev/sinic.hh
src/python/m5/config.py
src/python/m5/objects/BaseCPU.py
src/sim/sim_object.cc
src/sim/sim_object.hh
src/sim/system.cc
src/sim/system.hh

index 12bfdeb9bfef1b2944724e75807b04b5b171e841..1752b2b5b4fd156c0f21c63c92cd7e2a454ba7de 100644 (file)
@@ -33,6 +33,7 @@
 #include "cpu/simple/atomic.hh"
 #include "mem/packet_impl.hh"
 #include "sim/builder.hh"
+#include "sim/system.hh"
 
 using namespace std;
 using namespace TheISA;
@@ -172,6 +173,13 @@ AtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
     tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
 }
 
+void
+AtomicSimpleCPU::resume()
+{
+    assert(system->getMemoryMode() == System::Atomic);
+    changeState(SimObject::Running);
+}
+
 void
 AtomicSimpleCPU::switchOut()
 {
@@ -451,11 +459,11 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
     Param<Counter> max_loads_any_thread;
     Param<Counter> max_loads_all_threads;
     SimObjectParam<MemObject *> mem;
+    SimObjectParam<System *> system;
 
 #if FULL_SYSTEM
     SimObjectParam<AlphaITB *> itb;
     SimObjectParam<AlphaDTB *> dtb;
-    SimObjectParam<System *> system;
     Param<int> cpu_id;
     Param<Tick> profile;
 #else
@@ -483,11 +491,11 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(AtomicSimpleCPU)
     INIT_PARAM(max_loads_all_threads,
                "terminate when all threads have reached this load count"),
     INIT_PARAM(mem, "memory"),
+    INIT_PARAM(system, "system object"),
 
 #if FULL_SYSTEM
     INIT_PARAM(itb, "Instruction TLB"),
     INIT_PARAM(dtb, "Data TLB"),
-    INIT_PARAM(system, "system object"),
     INIT_PARAM(cpu_id, "processor ID"),
     INIT_PARAM(profile, ""),
 #else
@@ -520,11 +528,11 @@ CREATE_SIM_OBJECT(AtomicSimpleCPU)
     params->width = width;
     params->simulate_stalls = simulate_stalls;
     params->mem = mem;
+    params->system = system;
 
 #if FULL_SYSTEM
     params->itb = itb;
     params->dtb = dtb;
-    params->system = system;
     params->cpu_id = cpu_id;
     params->profile = profile;
 #else
index 179b4a7211d169665af44e42a3f2b3e717ac8a08..d59ca01aa4fb4ee3b9c7880ede6d3ad38afbbd94 100644 (file)
@@ -127,6 +127,7 @@ class AtomicSimpleCPU : public BaseSimpleCPU
     virtual void serialize(std::ostream &os);
     virtual void unserialize(Checkpoint *cp, const std::string &section);
 
+    virtual void resume();
     void switchOut();
     void takeOverFrom(BaseCPU *oldCPU);
 
index a505411896f628900e5b7d95675026433e4130b2..af10e64d7e2f919951e2bf167344741cd932bd9e 100644 (file)
 #include "sim/sim_events.hh"
 #include "sim/sim_object.hh"
 #include "sim/stats.hh"
+#include "sim/system.hh"
 
 #if FULL_SYSTEM
 #include "base/remote_gdb.hh"
-#include "sim/system.hh"
 #include "arch/tlb.hh"
 #include "arch/stacktrace.hh"
 #include "arch/vtophys.hh"
index e55301c6bf0e547d6c7cd4900426b6b26fa6be57..d2c2c7c47a6bf3c06ce2894648d31d0188f91999 100644 (file)
@@ -33,6 +33,7 @@
 #include "cpu/simple/timing.hh"
 #include "mem/packet_impl.hh"
 #include "sim/builder.hh"
+#include "sim/system.hh"
 
 using namespace std;
 using namespace TheISA;
@@ -91,7 +92,7 @@ TimingSimpleCPU::TimingSimpleCPU(Params *p)
     ifetch_pkt = dcache_pkt = NULL;
     drainEvent = NULL;
     fetchEvent = NULL;
-    state = SimObject::Timing;
+    changeState(SimObject::Running);
 }
 
 
@@ -113,18 +114,18 @@ TimingSimpleCPU::unserialize(Checkpoint *cp, const string &section)
     BaseSimpleCPU::unserialize(cp, section);
 }
 
-bool
+unsigned int
 TimingSimpleCPU::drain(Event *drain_event)
 {
     // TimingSimpleCPU is ready to drain if it's not waiting for
     // an access to complete.
     if (status() == Idle || status() == Running || status() == SwitchedOut) {
-        changeState(SimObject::DrainedTiming);
-        return true;
+        changeState(SimObject::Drained);
+        return 0;
     } else {
         changeState(SimObject::Draining);
         drainEvent = drain_event;
-        return false;
+        return 1;
     }
 }
 
@@ -142,12 +143,9 @@ TimingSimpleCPU::resume()
             new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, false);
         fetchEvent->schedule(curTick);
     }
-}
 
-void
-TimingSimpleCPU::setMemoryMode(State new_mode)
-{
-    assert(new_mode == SimObject::Timing);
+    assert(system->getMemoryMode() == System::Timing);
+    changeState(SimObject::Running);
 }
 
 void
@@ -514,7 +512,7 @@ void
 TimingSimpleCPU::completeDrain()
 {
     DPRINTF(Config, "Done draining\n");
-    changeState(SimObject::DrainedTiming);
+    changeState(SimObject::Drained);
     drainEvent->process();
 }
 
@@ -551,11 +549,11 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(TimingSimpleCPU)
     Param<Counter> max_loads_any_thread;
     Param<Counter> max_loads_all_threads;
     SimObjectParam<MemObject *> mem;
+    SimObjectParam<System *> system;
 
 #if FULL_SYSTEM
     SimObjectParam<AlphaITB *> itb;
     SimObjectParam<AlphaDTB *> dtb;
-    SimObjectParam<System *> system;
     Param<int> cpu_id;
     Param<Tick> profile;
 #else
@@ -583,11 +581,11 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(TimingSimpleCPU)
     INIT_PARAM(max_loads_all_threads,
                "terminate when all threads have reached this load count"),
     INIT_PARAM(mem, "memory"),
+    INIT_PARAM(system, "system object"),
 
 #if FULL_SYSTEM
     INIT_PARAM(itb, "Instruction TLB"),
     INIT_PARAM(dtb, "Data TLB"),
-    INIT_PARAM(system, "system object"),
     INIT_PARAM(cpu_id, "processor ID"),
     INIT_PARAM(profile, ""),
 #else
@@ -618,11 +616,11 @@ CREATE_SIM_OBJECT(TimingSimpleCPU)
     params->functionTrace = function_trace;
     params->functionTraceStart = function_trace_start;
     params->mem = mem;
+    params->system = system;
 
 #if FULL_SYSTEM
     params->itb = itb;
     params->dtb = dtb;
-    params->system = system;
     params->cpu_id = cpu_id;
     params->profile = profile;
 #else
index 0a3f91e6c5b2069e1dc04ef9154b70c23d9869c6..ac36e5c994a8becedbf8232d9d80fc0b1a69d175 100644 (file)
@@ -137,9 +137,8 @@ class TimingSimpleCPU : public BaseSimpleCPU
     virtual void serialize(std::ostream &os);
     virtual void unserialize(Checkpoint *cp, const std::string &section);
 
-    virtual bool drain(Event *drain_event);
+    virtual unsigned int drain(Event *drain_event);
     virtual void resume();
-    virtual void setMemoryMode(State new_mode);
 
     void switchOut();
     void takeOverFrom(BaseCPU *oldCPU);
index dc78021f8b97746b071ee612154be230d8a077b2..12564ddd0b70e9d1acd02b785d95dd2d15acfdf0 100644 (file)
@@ -318,7 +318,7 @@ IdeDisk::doDmaTransfer()
         panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
               dmaState, devState);
 
-    if (ctrl->dmaPending()) {
+    if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
         dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
         return;
     } else
@@ -398,8 +398,7 @@ IdeDisk::doDmaRead()
                 curPrd.getByteCount(), TheISA::PageBytes);
 
     }
-    if (ctrl->dmaPending()) {
-        panic("shouldn't be reentant??");
+    if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
         dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
         return;
     } else if (!dmaReadCG->done()) {
@@ -474,8 +473,7 @@ IdeDisk::doDmaWrite()
         dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
                 curPrd.getByteCount(), TheISA::PageBytes);
     }
-    if (ctrl->dmaPending()) {
-        panic("shouldn't be reentant??");
+    if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
         dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
         return;
     } else if (!dmaWriteCG->done()) {
index cb4850108f8cb9dbf2920e9134ace7cbc84eea0d..ed2862065bbc99231e574fe87674ceb5c30e13ac 100644 (file)
 #include "base/trace.hh"
 #include "dev/io_device.hh"
 #include "sim/builder.hh"
+#include "sim/system.hh"
 
 
-PioPort::PioPort(PioDevice *dev, Platform *p, std::string pname)
-    : Port(dev->name() + pname), device(dev), platform(p)
+PioPort::PioPort(PioDevice *dev, System *s, std::string pname)
+    : Port(dev->name() + pname), device(dev), sys(s),
+      outTiming(0), drainEvent(NULL)
 { }
 
 
@@ -68,13 +70,23 @@ PioPort::recvRetry()
         if (result)
             transmitList.pop_front();
     }
+   if (transmitList.size() == 0 && drainEvent) {
+       drainEvent->process();
+       drainEvent = NULL;
+   }
 }
 
 void
 PioPort::SendEvent::process()
 {
+    port->outTiming--;
+    assert(port->outTiming >= 0);
     if (port->Port::sendTiming(packet))
-        return;
+       if (port->transmitList.size() == 0 && port->drainEvent) {
+           port->drainEvent->process();
+           port->drainEvent = NULL;
+       }
+       return;
 
     port->transmitList.push_back(packet);
 }
@@ -105,6 +117,15 @@ PioPort::recvTiming(Packet *pkt)
     return true;
 }
 
+unsigned int
+PioPort::drain(Event *de)
+{
+    if (outTiming == 0 && transmitList.size() == 0)
+        return 0;
+    drainEvent = de;
+    return 1;
+}
+
 PioDevice::~PioDevice()
 {
     if (pioPort)
@@ -119,6 +140,19 @@ PioDevice::init()
     pioPort->sendStatusChange(Port::RangeChange);
 }
 
+
+unsigned int
+PioDevice::drain(Event *de)
+{
+    unsigned int count;
+    count = pioPort->drain(de);
+    if (count)
+        changeState(Draining);
+    else
+        changeState(Drained);
+    return count;
+}
+
 void
 BasicPioDevice::addressRanges(AddrRangeList &range_list)
 {
@@ -128,8 +162,9 @@ BasicPioDevice::addressRanges(AddrRangeList &range_list)
 }
 
 
-DmaPort::DmaPort(DmaDevice *dev, Platform *p)
-    : Port(dev->name() + "-dmaport"), device(dev), platform(p), pendingCount(0)
+DmaPort::DmaPort(DmaDevice *dev, System *s)
+    : Port(dev->name() + "-dmaport"), device(dev), sys(s), pendingCount(0),
+      actionInProgress(0), drainEvent(NULL)
 { }
 
 bool
@@ -159,6 +194,11 @@ DmaPort::recvTiming(Packet *pkt)
         }
         delete pkt->req;
         delete pkt;
+
+        if (pendingCount == 0 && drainEvent) {
+            drainEvent->process();
+            drainEvent = NULL;
+        }
     }  else {
         panic("Got packet without sender state... huh?\n");
     }
@@ -170,6 +210,29 @@ DmaDevice::DmaDevice(Params *p)
     : PioDevice(p), dmaPort(NULL)
 { }
 
+
+unsigned int
+DmaDevice::drain(Event *de)
+{
+    unsigned int count;
+    count = pioPort->drain(de) + dmaPort->drain(de);
+    if (count)
+        changeState(Draining);
+    else
+        changeState(Drained);
+    return count;
+}
+
+unsigned int
+DmaPort::drain(Event *de)
+{
+    if (pendingCount == 0)
+        return 0;
+    drainEvent = de;
+    return 1;
+}
+
+
 void
 DmaPort::recvRetry()
 {
@@ -195,6 +258,8 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
 {
     assert(event);
 
+    assert(device->getState() == SimObject::Running);
+
     DmaReqState *reqState = new DmaReqState(event, this, size);
 
     for (ChunkGenerator gen(addr, size, peerBlockSize());
@@ -212,51 +277,53 @@ DmaPort::dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
             pendingCount++;
             sendDma(pkt);
     }
+
 }
 
 
 void
 DmaPort::sendDma(Packet *pkt, bool front)
 {
-   // some kind of selction between access methods
-   // more work is going to have to be done to make
-   // switching actually work
-  /* MemState state = device->platform->system->memState;
-
-   if (state == Timing) {  */
-       DPRINTF(DMA, "Attempting to send Packet %#x with addr: %#x\n",
-               pkt, pkt->getAddr());
-       if (transmitList.size() || !sendTiming(pkt)) {
-           if (front)
-               transmitList.push_front(pkt);
-           else
-               transmitList.push_back(pkt);
-           DPRINTF(DMA, "-- Failed: queued\n");
-       } else {
-           DPRINTF(DMA, "-- Done\n");
-       }
-  /*  } else if (state == Atomic) {
-       sendAtomic(pkt);
-       if (pkt->senderState) {
-           DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
-           assert(state);
-           state->completionEvent->schedule(curTick + (pkt->time -
-           pkt->req->getTime()) +1);
-           delete state;
-       }
-       pendingCount--;
-       assert(pendingCount >= 0);
-       delete pkt->req;
-       delete pkt;
-
-   } else if (state == Functional) {
-       sendFunctional(pkt);
-       // Is this correct???
-       completionEvent->schedule(pkt->req->responseTime - pkt->req->requestTime);
-       completionEvent == NULL;
+    // some kind of selction between access methods
+    // more work is going to have to be done to make
+    // switching actually work
+    System::MemoryMode state = sys->getMemoryMode();
+    if (state == System::Timing) {
+        DPRINTF(DMA, "Attempting to send Packet %#x with addr: %#x\n",
+                pkt, pkt->getAddr());
+        if (transmitList.size() || !sendTiming(pkt)) {
+            if (front)
+                transmitList.push_front(pkt);
+            else
+                transmitList.push_back(pkt);
+            DPRINTF(DMA, "-- Failed: queued\n");
+        } else {
+            DPRINTF(DMA, "-- Done\n");
+        }
+    } else if (state == System::Atomic) {
+        sendAtomic(pkt);
+        assert(pkt->senderState);
+        DmaReqState *state = dynamic_cast<DmaReqState*>(pkt->senderState);
+        assert(state);
+
+        state->numBytes += pkt->req->getSize();
+        if (state->totBytes == state->numBytes) {
+            state->completionEvent->schedule(curTick +
+                    (pkt->time - pkt->req->getTime()) +1);
+            delete state;
+            delete pkt->req;
+        }
+        pendingCount--;
+        assert(pendingCount >= 0);
+        delete pkt;
+
+        if (pendingCount == 0 && drainEvent) {
+            drainEvent->process();
+            drainEvent = NULL;
+        }
+
    } else
        panic("Unknown memory command state.");
-  */
 }
 
 DmaDevice::~DmaDevice()
index 40edf687574db7fa40626dbb210a7188ad01ce94..fa3f982476b106c6459b88ec450be5ea1af7d68d 100644 (file)
@@ -60,9 +60,9 @@ class PioPort : public Port
     /** The device that this port serves. */
     PioDevice *device;
 
-    /** The platform that device/port are in. This is used to select which mode
+    /** The system that device/port are in. This is used to select which mode
      * we are currently operating in. */
-    Platform *platform;
+    System *sys;
 
     /** A list of outgoing timing response packets that haven't been serviced
      * yet. */
@@ -106,16 +106,27 @@ class PioPort : public Port
         friend class PioPort;
     };
 
+    /** Number of timing requests that are emulating the device timing before
+     * attempting to end up on the bus.
+     */
+    int outTiming;
+
+    /** If we need to drain, keep the drain event around until we're done
+     * here.*/
+    Event *drainEvent;
+
     /** Schedule a sendTiming() event to be called in the future. */
     void sendTiming(Packet *pkt, Tick time)
-    { new PioPort::SendEvent(this, pkt, time); }
+    { outTiming++; new PioPort::SendEvent(this, pkt, time); }
 
     /** This function is notification that the device should attempt to send a
      * packet again. */
     virtual void recvRetry();
 
   public:
-    PioPort(PioDevice *dev, Platform *p, std::string pname = "-pioport");
+    PioPort(PioDevice *dev, System *s, std::string pname = "-pioport");
+
+    unsigned int drain(Event *de);
 
   friend class PioPort::SendEvent;
 };
@@ -147,13 +158,20 @@ class DmaPort : public Port
     DmaDevice *device;
     std::list<Packet*> transmitList;
 
-    /** The platform that device/port are in. This is used to select which mode
+    /** The system that device/port are in. This is used to select which mode
      * we are currently operating in. */
-    Platform *platform;
+    System *sys;
 
     /** Number of outstanding packets the dma port has. */
     int pendingCount;
 
+    /** If a dmaAction is in progress. */
+    int actionInProgress;
+
+    /** If we need to drain, keep the drain event around until we're done
+     * here.*/
+    Event *drainEvent;
+
     virtual bool recvTiming(Packet *pkt);
     virtual Tick recvAtomic(Packet *pkt)
     { panic("dma port shouldn't be used for pio access."); }
@@ -171,13 +189,14 @@ class DmaPort : public Port
     void sendDma(Packet *pkt, bool front = false);
 
   public:
-    DmaPort(DmaDevice *dev, Platform *p);
+    DmaPort(DmaDevice *dev, System *s);
 
     void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event,
                    uint8_t *data = NULL);
 
     bool dmaPending() { return pendingCount > 0; }
 
+    unsigned int drain(Event *de);
 };
 
 /**
@@ -196,6 +215,8 @@ class PioDevice : public MemObject
      * transaction we should perform. */
     Platform *platform;
 
+    System *sys;
+
     /** The pioPort that handles the requests for us and provides us requests
      * that it sees. */
     PioPort *pioPort;
@@ -240,20 +261,22 @@ class PioDevice : public MemObject
     const Params *params() const { return _params; }
 
     PioDevice(Params *p)
-              : MemObject(p->name),  platform(p->platform), pioPort(NULL),
-                _params(p)
+              : MemObject(p->name),  platform(p->platform), sys(p->system),
+              pioPort(NULL), _params(p)
               {}
 
     virtual ~PioDevice();
 
     virtual void init();
 
+    virtual unsigned int drain(Event *de);
+
     virtual Port *getPort(const std::string &if_name, int idx = -1)
     {
         if (if_name == "pio") {
             if (pioPort != NULL)
                 panic("pio port already connected to.");
-            pioPort = new PioPort(this, params()->platform);
+            pioPort = new PioPort(this, sys);
             return pioPort;
         } else
             return NULL;
@@ -310,17 +333,19 @@ class DmaDevice : public PioDevice
 
     bool dmaPending() { return dmaPort->dmaPending(); }
 
+    virtual unsigned int drain(Event *de);
+
     virtual Port *getPort(const std::string &if_name, int idx = -1)
     {
         if (if_name == "pio") {
             if (pioPort != NULL)
                 panic("pio port already connected to.");
-            pioPort = new PioPort(this, params()->platform);
+            pioPort = new PioPort(this, sys);
             return pioPort;
         } else if (if_name == "dma") {
             if (dmaPort != NULL)
                 panic("dma port already connected to.");
-            dmaPort = new DmaPort(this, params()->platform);
+            dmaPort = new DmaPort(this, sys);
             return dmaPort;
         } else
             return NULL;
index 179a2c62ddfe19371cc6b0df9f51f9288c80e01e..bf2279d93a23b070d3e83fb701cdf0f4604a134f 100644 (file)
@@ -1377,7 +1377,7 @@ NSGigE::doRxDmaRead()
     assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
     rxDmaState = dmaReading;
 
-    if (dmaPending())
+    if (dmaPending() || getState() != Running)
         rxDmaState = dmaReadWaiting;
     else
         dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
@@ -1408,7 +1408,7 @@ NSGigE::doRxDmaWrite()
     assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
     rxDmaState = dmaWriting;
 
-    if (dmaPending())
+    if (dmaPending() || getState() != Running)
         rxDmaState = dmaWriteWaiting;
     else
         dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
@@ -1826,7 +1826,7 @@ NSGigE::doTxDmaRead()
     assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
     txDmaState = dmaReading;
 
-    if (dmaPending())
+    if (dmaPending() || getState() != Running)
         txDmaState = dmaReadWaiting;
     else
         dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
@@ -1857,7 +1857,7 @@ NSGigE::doTxDmaWrite()
     assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
     txDmaState = dmaWriting;
 
-    if (dmaPending())
+    if (dmaPending() || getState() != Running)
         txDmaState = dmaWriteWaiting;
     else
         dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
@@ -2406,6 +2406,20 @@ NSGigE::recvPacket(EthPacketPtr packet)
     return true;
 }
 
+
+void
+NSGigE::resume()
+{
+    SimObject::resume();
+
+    // During drain we could have left the state machines in a waiting state and
+    // they wouldn't get out until some other event occured to kick them.
+    // This way they'll get out immediately
+    txKick();
+    rxKick();
+}
+
+
 //=====================================================================
 //
 //
index ea72437770f7c5f903375742170ccb40fcb309f2..080c0b1f32e922cd0c64b7111593661621729792 100644 (file)
@@ -391,6 +391,8 @@ class NSGigE : public PciDev
     virtual void serialize(std::ostream &os);
     virtual void unserialize(Checkpoint *cp, const std::string &section);
 
+    virtual void resume();
+
   public:
     void regStats();
 
index 62a7324ad47eb33476f4f152dee653983e7474ba..e81e0d1ee25d6a38cfc9171285b2351f179bc3a4 100644 (file)
@@ -56,8 +56,8 @@ using namespace std;
 
 PciDev::PciConfigPort::PciConfigPort(PciDev *dev, int busid, int devid,
         int funcid, Platform *p)
-        : PioPort(dev,p,"-pciconf"), device(dev), busId(busid), deviceId(devid),
-        functionId(funcid)
+        : PioPort(dev,p->system,"-pciconf"), device(dev), platform(p),
+          busId(busid), deviceId(devid), functionId(funcid)
 {
     configAddr = platform->calcConfigAddr(busId, deviceId, functionId);
 }
@@ -132,6 +132,18 @@ PciDev::init()
    PioDevice::init();
 }
 
+unsigned int
+PciDev::drain(Event *de)
+{
+    unsigned int count;
+    count = pioPort->drain(de) + dmaPort->drain(de) + configPort->drain(de);
+    if (count)
+        changeState(Draining);
+    else
+        changeState(Drained);
+    return count;
+}
+
 Tick
 PciDev::readConfig(Packet *pkt)
 {
index 20ab9364a8879cd31c213a2b55e61cc5952a9602..847fb07d03ba0d5c6d00c760a3caabae72eb0715 100644 (file)
@@ -95,6 +95,8 @@ class PciDev : public DmaDevice
 
         virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop);
 
+        Platform *platform;
+
         int busId;
         int deviceId;
         int functionId;
@@ -249,6 +251,9 @@ class PciDev : public DmaDevice
      */
     virtual void unserialize(Checkpoint *cp, const std::string &section);
 
+
+    virtual unsigned int drain(Event *de);
+
     virtual Port *getPort(const std::string &if_name, int idx = -1)
     {
         if (if_name == "config") {
index dddda1f1cbc7c398b4dd933bde7dce289d808868..815cecca5a40056c75a5cd19bcb4e98afe6bc61a 100644 (file)
@@ -921,7 +921,7 @@ Device::rxKick()
         break;
 
       case rxBeginCopy:
-        if (dmaPending())
+        if (dmaPending() || getState() != Running)
             goto exit;
 
         rxDmaAddr = params()->platform->pciToDma(
@@ -1109,7 +1109,7 @@ Device::txKick()
         break;
 
       case txBeginCopy:
-        if (dmaPending())
+        if (dmaPending() || getState() != Running)
             goto exit;
 
         txDmaAddr = params()->platform->pciToDma(
@@ -1287,6 +1287,18 @@ Device::recvPacket(EthPacketPtr packet)
     return true;
 }
 
+void
+Device::resume()
+{
+    SimObject::resume();
+
+    // During drain we could have left the state machines in a waiting state and
+    // they wouldn't get out until some other event occured to kick them.
+    // This way they'll get out immediately
+    txKick();
+    rxKick();
+}
+
 //=====================================================================
 //
 //
index f6c229039abfa8a963fb30406f66ce8c348eff9d..eece4ba6b81d257e9f72c0ada51cb8db90587bc1 100644 (file)
@@ -266,6 +266,7 @@ class Device : public Base
   public:
     virtual Tick read(Packet *pkt);
     virtual Tick write(Packet *pkt);
+    virtual void resume();
 
     void prepareIO(int cpu, int index);
     void prepareRead(int cpu, int index);
index 8291e1e1bd91b6a005ec3328887edad0aed5b727..8eed28dccb28a019449eff3b1874e435f8257d4a 100644 (file)
@@ -547,8 +547,7 @@ class SimObject(object):
         count = 0
         # ParamContexts don't serialize
         if isinstance(self, SimObject) and not isinstance(self, ParamContext):
-            if not self._ccObject.drain(drain_event):
-                count = 1
+            count += self._ccObject.drain(drain_event)
         if recursive:
             for child in self._children.itervalues():
                 count += child.startDrain(drain_event, True)
@@ -561,7 +560,7 @@ class SimObject(object):
             child.resume()
 
     def changeTiming(self, mode):
-        if isinstance(self, SimObject) and not isinstance(self, ParamContext):
+        if isinstance(self, System):
             self._ccObject.setMemoryMode(mode)
         for child in self._children.itervalues():
             child.changeTiming(mode)
index 2e78578dfe28254be324e1004afa6e23bb60aa7d..5bf98be9c997200dc03c9cc5bb27f9724f523ed8 100644 (file)
@@ -6,10 +6,10 @@ class BaseCPU(SimObject):
     abstract = True
     mem = Param.MemObject("memory")
 
+    system = Param.System(Parent.any, "system object")
     if build_env['FULL_SYSTEM']:
         dtb = Param.AlphaDTB("Data TLB")
         itb = Param.AlphaITB("Instruction TLB")
-        system = Param.System(Parent.any, "system object")
         cpu_id = Param.Int(-1, "CPU identifier")
     else:
         workload = VectorParam.Process("processes to run")
index a0278dba0f5af5a19ea67c3dd44489982b2a93e0..d12b06b7ad106b4a40fe0b42f8d0eea050d0c81b 100644 (file)
@@ -72,7 +72,7 @@ SimObject::SimObject(Params *p)
 
     doRecordEvent = !Stats::event_ignore.match(name());
     simObjectList.push_back(this);
-    state = Atomic;
+    state = Running;
 }
 
 //
@@ -88,7 +88,7 @@ SimObject::SimObject(const string &_name)
 
     doRecordEvent = !Stats::event_ignore.match(name());
     simObjectList.push_back(this);
-    state = Atomic;
+    state = Running;
 }
 
 void
@@ -269,38 +269,23 @@ SimObject::recordEvent(const std::string &stat)
         Stats::recordEvent(stat);
 }
 
-bool
+unsigned int
 SimObject::drain(Event *drain_event)
 {
-    if (state != DrainedAtomic && state != Atomic) {
-        panic("Must implement your own drain function if it is to be used "
-              "in timing mode!");
-    }
-    state = DrainedAtomic;
-    return true;
+    state = Drained;
+    return 0;
 }
 
 void
 SimObject::resume()
 {
-    if (state == DrainedAtomic) {
-        state = Atomic;
-    } else if (state == DrainedTiming) {
-        state = Timing;
-    }
+    state = Running;
 }
 
 void
 SimObject::setMemoryMode(State new_mode)
 {
-    assert(new_mode == Timing || new_mode == Atomic);
-    if (state == DrainedAtomic && new_mode == Timing) {
-        state = DrainedTiming;
-    } else if (state == DrainedTiming && new_mode == Atomic) {
-        state = DrainedAtomic;
-    } else {
-        state = new_mode;
-    }
+    panic("setMemoryMode() should only be called on systems");
 }
 
 void
index 7ecc0095884479923ee57177de54a9ec25bc53f8..38f2bdd232ef4e82049cabea806a4f42297af6a9 100644 (file)
@@ -60,16 +60,15 @@ class SimObject : public Serializable, protected StartupCallback
     };
 
     enum State {
-        Atomic,
-        Timing,
+        Running,
         Draining,
-        DrainedAtomic,
-        DrainedTiming
+        Drained
     };
+  private:
+    State state;
 
   protected:
     Params *_params;
-    State state;
 
     void changeState(State new_state) { state = new_state; }
 
@@ -116,8 +115,10 @@ class SimObject : public Serializable, protected StartupCallback
 
     // Methods to drain objects in order to take checkpoints
     // Or switch from timing -> atomic memory model
-    // Drain returns false if the SimObject cannot drain immediately.
-    virtual bool drain(Event *drain_event);
+    // Drain returns 0 if the simobject can drain immediately or
+    // the number of times the drain_event's process function will be called
+    // before the object will be done draining. Normally this should be 1
+    virtual unsigned int drain(Event *drain_event);
     virtual void resume();
     virtual void setMemoryMode(State new_mode);
     virtual void switchOut();
index 89e7b8542b2c2d99ba2c638ff1db199bd59f7424..2780d0fdaca0caabcc2657fc6806852b7bc2dbbf 100644 (file)
@@ -143,6 +143,14 @@ int rgdb_wait = -1;
 
 #endif // FULL_SYSTEM
 
+
+void
+System::setMemoryMode(MemoryMode mode)
+{
+    assert(getState() == Drained);
+    memoryMode = mode;
+}
+
 int
 System::registerThreadContext(ThreadContext *tc, int id)
 {
index 059dc92dc7587f8314908e5ea253b1b8cdba6231..77777aed4088df45cea3099eb35681320a5a0c3b 100644 (file)
@@ -61,6 +61,21 @@ class RemoteGDB;
 class System : public SimObject
 {
   public:
+    enum MemoryMode {
+        Invalid=0,
+        Atomic,
+        Timing
+    };
+
+
+    MemoryMode getMemoryMode() { assert(memoryMode); return memoryMode; }
+
+    /** Change the memory mode of the system. This should only be called by the
+     * python!!
+     * @param mode Mode to change to (atomic/timing)
+     */
+    void setMemoryMode(MemoryMode mode);
+
     PhysicalMemory *physmem;
     PCEventQueue pcEventQueue;
 
@@ -108,6 +123,8 @@ class System : public SimObject
 
   protected:
 
+    MemoryMode memoryMode;
+
 #if FULL_SYSTEM
     /**
      * Fix up an address used to match PCs for hooking simulator