sim: Move the draining interface into a separate base class
authorAndreas Sandberg <Andreas.Sandberg@arm.com>
Fri, 2 Nov 2012 16:32:01 +0000 (11:32 -0500)
committerAndreas Sandberg <Andreas.Sandberg@arm.com>
Fri, 2 Nov 2012 16:32:01 +0000 (11:32 -0500)
This patch moves the draining interface from SimObject to a separate
class that can be used by any object needing draining. However,
objects not visible to the Python code (i.e., objects not deriving
from SimObject) still depend on their parents informing them when to
drain. This patch also gets rid of the CountedDrainEvent (which isn't
really an event) and replaces it with a DrainManager.

64 files changed:
src/arch/arm/table_walker.cc
src/arch/arm/table_walker.hh
src/cpu/o3/cpu.cc
src/cpu/o3/cpu.hh
src/cpu/simple/atomic.cc
src/cpu/simple/atomic.hh
src/cpu/simple/timing.cc
src/cpu/simple/timing.hh
src/cpu/testers/traffic_gen/traffic_gen.cc
src/cpu/testers/traffic_gen/traffic_gen.hh
src/dev/copy_engine.cc
src/dev/copy_engine.hh
src/dev/dma_device.cc
src/dev/dma_device.hh
src/dev/i8254xGBe.cc
src/dev/i8254xGBe.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/mem/bus.cc
src/mem/bus.hh
src/mem/cache/base.cc
src/mem/cache/base.hh
src/mem/coherent_bus.cc
src/mem/coherent_bus.hh
src/mem/noncoherent_bus.cc
src/mem/noncoherent_bus.hh
src/mem/packet_queue.cc
src/mem/packet_queue.hh
src/mem/qport.hh
src/mem/ruby/system/MemoryControl.hh
src/mem/ruby/system/RubyMemoryControl.cc
src/mem/ruby/system/RubyMemoryControl.hh
src/mem/ruby/system/RubyPort.cc
src/mem/ruby/system/RubyPort.hh
src/mem/ruby/system/Sequencer.cc
src/mem/simple_dram.cc
src/mem/simple_dram.hh
src/mem/simple_mem.cc
src/mem/simple_mem.hh
src/python/SConscript
src/python/m5/SimObject.py
src/python/m5/__init__.py
src/python/m5/internal/__init__.py
src/python/m5/simulate.py
src/python/swig/drain.i [new file with mode: 0644]
src/python/swig/event.i
src/python/swig/pyevent.cc
src/python/swig/pyevent.hh
src/sim/SConscript
src/sim/drain.cc [new file with mode: 0644]
src/sim/drain.hh [new file with mode: 0644]
src/sim/serialize.hh
src/sim/sim_events.cc
src/sim/sim_object.cc
src/sim/sim_object.hh
src/sim/system.cc
src/sim/system.hh

index a10eb4a20130eb68729afb5732a00e4e5960ed43..e4c6209d6eabe1a0c879a5f3da198c6769d47cce 100644 (file)
@@ -51,7 +51,7 @@
 using namespace ArmISA;
 
 TableWalker::TableWalker(const Params *p)
-    : MemObject(p), port(this, params()->sys), drainEvent(NULL),
+    : MemObject(p), port(this, params()->sys), drainManager(NULL),
       tlb(NULL), currState(NULL), pending(false),
       masterId(p->sys->getMasterId(name())),
       numSquashable(p->num_squash_per_cycle),
@@ -68,30 +68,30 @@ TableWalker::~TableWalker()
 void
 TableWalker::completeDrain()
 {
-    if (drainEvent && stateQueueL1.empty() && stateQueueL2.empty() &&
+    if (drainManager && stateQueueL1.empty() && stateQueueL2.empty() &&
         pendingQueue.empty()) {
-        changeState(Drained);
+        setDrainState(Drainable::Drained);
         DPRINTF(Drain, "TableWalker done draining, processing drain event\n");
-        drainEvent->process();
-        drainEvent = NULL;
+        drainManager->signalDrainDone();
+        drainManager = NULL;
     }
 }
 
 unsigned int
-TableWalker::drain(Event *de)
+TableWalker::drain(DrainManager *dm)
 {
-    unsigned int count = port.drain(de);
+    unsigned int count = port.drain(dm);
 
     if (stateQueueL1.empty() && stateQueueL2.empty() &&
         pendingQueue.empty()) {
-        changeState(Drained);
+        setDrainState(Drainable::Drained);
         DPRINTF(Drain, "TableWalker free, no need to drain\n");
 
         // table walker is drained, but its ports may still need to be drained
         return count;
     } else {
-        drainEvent = de;
-        changeState(Draining);
+        drainManager = dm;
+        setDrainState(Drainable::Draining);
         DPRINTF(Drain, "TableWalker not drained\n");
 
         // return port drain count plus the table walker itself needs to drain
@@ -101,9 +101,9 @@ TableWalker::drain(Event *de)
 }
 
 void
-TableWalker::resume()
+TableWalker::drainResume()
 {
-    MemObject::resume();
+    Drainable::drainResume();
     if ((params()->sys->getMemoryMode() == Enums::timing) && currState) {
         delete currState;
         currState = NULL;
index 22c5d03b425ff49abef3ea70bf07cf7f4eb61850..23464f56d7926f70d4c330e58f3a1b0025933c72 100644 (file)
@@ -364,7 +364,7 @@ class TableWalker : public MemObject
     SnoopingDmaPort port;
 
     /** If we're draining keep the drain event around until we're drained */
-    Event *drainEvent;
+    DrainManager *drainManager;
 
     /** TLB that is initiating these table walks */
     TLB *tlb;
@@ -397,8 +397,8 @@ class TableWalker : public MemObject
 
     /** Checks if all state is cleared and if so, completes drain */
     void completeDrain();
-    virtual unsigned int drain(Event *de);
-    virtual void resume();
+    unsigned int drain(DrainManager *dm);
+    void drainResume();
     virtual BaseMasterPort& getMasterPort(const std::string &if_name,
                                           PortID idx = InvalidPortID);
 
index fdd45fddae71ab76be8ade49b98a1de718c1acd1..bc5f096e690bb3b78968d57752fa89e406dc87bc 100644 (file)
@@ -619,7 +619,7 @@ FullO3CPU<Impl>::tick()
 
     if (!tickEvent.scheduled()) {
         if (_status == SwitchedOut ||
-            getState() == SimObject::Drained) {
+            getDrainState() == Drainable::Drained) {
             DPRINTF(O3CPU, "Switched out!\n");
             // increment stat
             lastRunningCycle = curCycle();
@@ -1077,7 +1077,7 @@ template <class Impl>
 void
 FullO3CPU<Impl>::serialize(std::ostream &os)
 {
-    SimObject::State so_state = SimObject::getState();
+    Drainable::State so_state(getDrainState());
     SERIALIZE_ENUM(so_state);
     BaseCPU::serialize(os);
     nameOut(os, csprintf("%s.tickEvent", name()));
@@ -1100,7 +1100,7 @@ template <class Impl>
 void
 FullO3CPU<Impl>::unserialize(Checkpoint *cp, const std::string &section)
 {
-    SimObject::State so_state;
+    Drainable::State so_state;
     UNSERIALIZE_ENUM(so_state);
     BaseCPU::unserialize(cp, section);
     tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
@@ -1120,7 +1120,7 @@ FullO3CPU<Impl>::unserialize(Checkpoint *cp, const std::string &section)
 
 template <class Impl>
 unsigned int
-FullO3CPU<Impl>::drain(Event *drain_event)
+FullO3CPU<Impl>::drain(DrainManager *drain_manager)
 {
     DPRINTF(O3CPU, "Switching out\n");
 
@@ -1137,12 +1137,12 @@ FullO3CPU<Impl>::drain(Event *drain_event)
 
     // Wake the CPU and record activity so everything can drain out if
     // the CPU was not able to immediately drain.
-    if (getState() != SimObject::Drained) {
-        // A bit of a hack...set the drainEvent after all the drain()
+    if (getDrainState() != Drainable::Drained) {
+        // A bit of a hack...set the drainManager after all the drain()
         // calls have been made, that way if all of the stages drain
         // immediately, the signalDrained() function knows not to call
         // process on the drain event.
-        drainEvent = drain_event;
+        drainManager = drain_manager;
 
         wakeCPU();
         activityRec.activity();
@@ -1157,7 +1157,7 @@ FullO3CPU<Impl>::drain(Event *drain_event)
 
 template <class Impl>
 void
-FullO3CPU<Impl>::resume()
+FullO3CPU<Impl>::drainResume()
 {
     fetch.resume();
     decode.resume();
@@ -1165,7 +1165,7 @@ FullO3CPU<Impl>::resume()
     iew.resume();
     commit.resume();
 
-    changeState(SimObject::Running);
+    setDrainState(Drainable::Running);
 
     if (_status == SwitchedOut)
         return;
@@ -1185,14 +1185,14 @@ FullO3CPU<Impl>::signalDrained()
         if (tickEvent.scheduled())
             tickEvent.squash();
 
-        changeState(SimObject::Drained);
+        setDrainState(Drainable::Drained);
 
         BaseCPU::switchOut();
 
-        if (drainEvent) {
+        if (drainManager) {
             DPRINTF(Drain, "CPU done draining, processing drain event\n");
-            drainEvent->process();
-            drainEvent = NULL;
+            drainManager->signalDrainDone();
+            drainManager = NULL;
         }
     }
     assert(drainCount <= 5);
index 076cce0fb882c0f7d0335bfbf2535c70f9a364ae..1f9a8da6ccbc9c53d4bea40ee0ae6b06a4c2d8c5 100644 (file)
@@ -431,10 +431,10 @@ class FullO3CPU : public BaseO3CPU
 
     /** Starts draining the CPU's pipeline of all instructions in
      * order to stop all memory accesses. */
-    virtual unsigned int drain(Event *drain_event);
+    unsigned int drain(DrainManager *drain_manager);
 
     /** Resumes execution after a drain. */
-    virtual void resume();
+    void drainResume();
 
     /** Signals to this CPU that a stage has completed switching out. */
     void signalDrained();
@@ -730,8 +730,8 @@ class FullO3CPU : public BaseO3CPU
     /** Pointer to the system. */
     System *system;
 
-    /** Event to call process() on once draining has completed. */
-    Event *drainEvent;
+    /** DrainManager to notify when draining has completed. */
+    DrainManager *drainManager;
 
     /** Counter of how many stages have completed draining. */
     int drainCount;
index 2d7afd2219fd33401a4e51aa9e79b186e42427e0..e63d998a7549c491da5c637605b4bed0b64c85c2 100644 (file)
@@ -123,7 +123,7 @@ AtomicSimpleCPU::~AtomicSimpleCPU()
 void
 AtomicSimpleCPU::serialize(ostream &os)
 {
-    SimObject::State so_state = SimObject::getState();
+    Drainable::State so_state(getDrainState());
     SERIALIZE_ENUM(so_state);
     SERIALIZE_SCALAR(locked);
     BaseSimpleCPU::serialize(os);
@@ -134,15 +134,22 @@ AtomicSimpleCPU::serialize(ostream &os)
 void
 AtomicSimpleCPU::unserialize(Checkpoint *cp, const string &section)
 {
-    SimObject::State so_state;
+    Drainable::State so_state;
     UNSERIALIZE_ENUM(so_state);
     UNSERIALIZE_SCALAR(locked);
     BaseSimpleCPU::unserialize(cp, section);
     tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
 }
 
+unsigned int
+AtomicSimpleCPU::drain(DrainManager *drain_manager)
+{
+    setDrainState(Drainable::Drained);
+    return 0;
+}
+
 void
-AtomicSimpleCPU::resume()
+AtomicSimpleCPU::drainResume()
 {
     if (_status == Idle || _status == SwitchedOut)
         return;
@@ -150,7 +157,7 @@ AtomicSimpleCPU::resume()
     DPRINTF(SimpleCPU, "Resume\n");
     assert(system->getMemoryMode() == Enums::atomic);
 
-    changeState(SimObject::Running);
+    setDrainState(Drainable::Running);
     if (thread->status() == ThreadContext::Active) {
         if (!tickEvent.scheduled())
             schedule(tickEvent, nextCycle());
@@ -161,7 +168,7 @@ AtomicSimpleCPU::resume()
 void
 AtomicSimpleCPU::switchOut()
 {
-    assert(_status == Running || _status == Idle);
+    assert(_status == BaseSimpleCPU::Running || _status == Idle);
     _status = SwitchedOut;
 
     tickEvent.squash();
@@ -180,13 +187,14 @@ AtomicSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
     ThreadID size = threadContexts.size();
     for (ThreadID i = 0; i < size; ++i) {
         ThreadContext *tc = threadContexts[i];
-        if (tc->status() == ThreadContext::Active && _status != Running) {
-            _status = Running;
+        if (tc->status() == ThreadContext::Active &&
+            _status != BaseSimpleCPU::Running) {
+            _status = BaseSimpleCPU::Running;
             schedule(tickEvent, nextCycle());
             break;
         }
     }
-    if (_status != Running) {
+    if (_status != BaseSimpleCPU::Running) {
         _status = Idle;
     }
     assert(threadContexts.size() == 1);
@@ -212,7 +220,7 @@ AtomicSimpleCPU::activateContext(ThreadID thread_num, Cycles delay)
 
     //Make sure ticks are still on multiples of cycles
     schedule(tickEvent, clockEdge(delay));
-    _status = Running;
+    _status = BaseSimpleCPU::Running;
 }
 
 
@@ -227,7 +235,7 @@ AtomicSimpleCPU::suspendContext(ThreadID thread_num)
     if (_status == Idle)
         return;
 
-    assert(_status == Running);
+    assert(_status == BaseSimpleCPU::Running);
 
     // tick event may not be scheduled if this gets called from inside
     // an instruction's execution, e.g. "quiesce"
index d67ab67a5af11e08f0b8919a9b4c89ce9ae8f1a6..94d2de081c17965506ce9b2839b75565627db7c9 100644 (file)
@@ -122,7 +122,9 @@ class AtomicSimpleCPU : public BaseSimpleCPU
 
     virtual void serialize(std::ostream &os);
     virtual void unserialize(Checkpoint *cp, const std::string &section);
-    virtual void resume();
+
+    unsigned int drain(DrainManager *drain_manager);
+    void drainResume();
 
     void switchOut();
     void takeOverFrom(BaseCPU *oldCPU);
index 15b277d5329b6c89346db595a2b75aad86add4b2..41764302d8b497cfc0fb549c4307bf9141b08ff8 100644 (file)
@@ -92,7 +92,7 @@ TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
 {
     _status = Idle;
 
-    changeState(SimObject::Running);
+    setDrainState(Drainable::Running);
     system->totalNumInsts = 0;
 }
 
@@ -104,7 +104,7 @@ TimingSimpleCPU::~TimingSimpleCPU()
 void
 TimingSimpleCPU::serialize(ostream &os)
 {
-    SimObject::State so_state = SimObject::getState();
+    Drainable::State so_state(getDrainState());
     SERIALIZE_ENUM(so_state);
     BaseSimpleCPU::serialize(os);
 }
@@ -112,29 +112,31 @@ TimingSimpleCPU::serialize(ostream &os)
 void
 TimingSimpleCPU::unserialize(Checkpoint *cp, const string &section)
 {
-    SimObject::State so_state;
+    Drainable::State so_state;
     UNSERIALIZE_ENUM(so_state);
     BaseSimpleCPU::unserialize(cp, section);
 }
 
 unsigned int
-TimingSimpleCPU::drain(Event *drain_event)
+TimingSimpleCPU::drain(DrainManager *drain_manager)
 {
     // TimingSimpleCPU is ready to drain if it's not waiting for
     // an access to complete.
-    if (_status == Idle || _status == Running || _status == SwitchedOut) {
-        changeState(SimObject::Drained);
+    if (_status == Idle ||
+        _status == BaseSimpleCPU::Running ||
+        _status == SwitchedOut) {
+        setDrainState(Drainable::Drained);
         return 0;
     } else {
-        changeState(SimObject::Draining);
-        drainEvent = drain_event;
+        setDrainState(Drainable::Draining);
+        drainManager = drain_manager;
         DPRINTF(Drain, "CPU not drained\n");
         return 1;
     }
 }
 
 void
-TimingSimpleCPU::resume()
+TimingSimpleCPU::drainResume()
 {
     DPRINTF(SimpleCPU, "Resume\n");
     if (_status != SwitchedOut && _status != Idle) {
@@ -146,13 +148,13 @@ TimingSimpleCPU::resume()
         schedule(fetchEvent, nextCycle());
     }
 
-    changeState(SimObject::Running);
+    setDrainState(Drainable::Running);
 }
 
 void
 TimingSimpleCPU::switchOut()
 {
-    assert(_status == Running || _status == Idle);
+    assert(_status == BaseSimpleCPU::Running || _status == Idle);
     _status = SwitchedOut;
     numCycles += curCycle() - previousCycle;
 
@@ -172,13 +174,14 @@ TimingSimpleCPU::takeOverFrom(BaseCPU *oldCPU)
     // running and schedule its tick event.
     for (int i = 0; i < threadContexts.size(); ++i) {
         ThreadContext *tc = threadContexts[i];
-        if (tc->status() == ThreadContext::Active && _status != Running) {
-            _status = Running;
+        if (tc->status() == ThreadContext::Active &&
+            _status != BaseSimpleCPU::Running) {
+            _status = BaseSimpleCPU::Running;
             break;
         }
     }
 
-    if (_status != Running) {
+    if (_status != BaseSimpleCPU::Running) {
         _status = Idle;
     }
     assert(threadContexts.size() == 1);
@@ -197,7 +200,7 @@ TimingSimpleCPU::activateContext(ThreadID thread_num, Cycles delay)
     assert(_status == Idle);
 
     notIdleFraction++;
-    _status = Running;
+    _status = BaseSimpleCPU::Running;
 
     // kick things off by initiating the fetch of the next instruction
     schedule(fetchEvent, clockEdge(delay));
@@ -215,7 +218,7 @@ TimingSimpleCPU::suspendContext(ThreadID thread_num)
     if (_status == Idle)
         return;
 
-    assert(_status == Running);
+    assert(_status == BaseSimpleCPU::Running);
 
     // just change status to Idle... if status != Running,
     // completeInst() will not initiate fetch of next instruction.
@@ -330,7 +333,7 @@ TimingSimpleCPU::translationFault(Fault fault)
 
     postExecute();
 
-    if (getState() == SimObject::Draining) {
+    if (getDrainState() == Drainable::Draining) {
         advancePC(fault);
         completeDrain();
     } else {
@@ -511,7 +514,7 @@ TimingSimpleCPU::writeMem(uint8_t *data, unsigned size,
 void
 TimingSimpleCPU::finishTranslation(WholeTranslationState *state)
 {
-    _status = Running;
+    _status = BaseSimpleCPU::Running;
 
     if (state->getFault() != NoFault) {
         if (state->isPrefetch()) {
@@ -552,7 +555,7 @@ TimingSimpleCPU::fetch()
     bool needToFetch = !isRomMicroPC(pcState.microPC()) && !curMacroStaticInst;
 
     if (needToFetch) {
-        _status = Running;
+        _status = BaseSimpleCPU::Running;
         Request *ifetch_req = new Request();
         ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0);
         setupFetchRequest(ifetch_req);
@@ -592,7 +595,7 @@ TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc)
         DPRINTF(SimpleCPU, "Translation of addr %#x faulted\n", req->getVaddr());
         delete req;
         // fetch fault: advance directly to next instruction (fault handler)
-        _status = Running;
+        _status = BaseSimpleCPU::Running;
         advanceInst(fault);
     }
 
@@ -620,7 +623,7 @@ TimingSimpleCPU::advanceInst(Fault fault)
     if (!stayAtPC)
         advancePC(fault);
 
-    if (_status == Running) {
+    if (_status == BaseSimpleCPU::Running) {
         // kick off fetch of next instruction... callback from icache
         // response will cause that instruction to be executed,
         // keeping the CPU running.
@@ -641,12 +644,12 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
     assert(!pkt || !pkt->isError());
     assert(_status == IcacheWaitResponse);
 
-    _status = Running;
+    _status = BaseSimpleCPU::Running;
 
     numCycles += curCycle() - previousCycle;
     previousCycle = curCycle();
 
-    if (getState() == SimObject::Draining) {
+    if (getDrainState() == Drainable::Draining) {
         if (pkt) {
             delete pkt->req;
             delete pkt;
@@ -664,7 +667,7 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
         // If we're not running now the instruction will complete in a dcache
         // response callback or the instruction faulted and has started an
         // ifetch
-        if (_status == Running) {
+        if (_status == BaseSimpleCPU::Running) {
             if (fault != NoFault && traceData) {
                 // If there was a fault, we shouldn't trace this instruction.
                 delete traceData;
@@ -778,7 +781,7 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
         }
     }
 
-    _status = Running;
+    _status = BaseSimpleCPU::Running;
 
     Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
 
@@ -802,7 +805,7 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
 
     postExecute();
 
-    if (getState() == SimObject::Draining) {
+    if (getDrainState() == Drainable::Draining) {
         advancePC(fault);
         completeDrain();
 
@@ -817,8 +820,8 @@ void
 TimingSimpleCPU::completeDrain()
 {
     DPRINTF(Drain, "CPU done draining, processing drain event\n");
-    changeState(SimObject::Drained);
-    drainEvent->process();
+    setDrainState(Drainable::Drained);
+    drainManager->signalDrainDone();
 }
 
 bool
index a2570abe696df6b7d28d7ce51ee15076744ce008..e7f5122d0a087bbc460e350facc47f1f17f027ef 100644 (file)
@@ -45,7 +45,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
     virtual void init();
 
   public:
-    Event *drainEvent;
+    DrainManager *drainManager;
 
   private:
 
@@ -109,7 +109,7 @@ class TimingSimpleCPU : public BaseSimpleCPU
         void
         markDelayed()
         {
-            assert(cpu->_status == Running);
+            assert(cpu->_status == BaseSimpleCPU::Running);
             cpu->_status = ITBWaitResponse;
         }
 
@@ -249,8 +249,8 @@ class TimingSimpleCPU : public BaseSimpleCPU
     virtual void serialize(std::ostream &os);
     virtual void unserialize(Checkpoint *cp, const std::string &section);
 
-    virtual unsigned int drain(Event *drain_event);
-    virtual void resume();
+    unsigned int drain(DrainManager *drain_manager);
+    void drainResume();
 
     void switchOut();
     void takeOverFrom(BaseCPU *oldCPU);
index af7ff89f4add63ee7210899f4f4b476e04d4a03f..e0657822cfea2b014507a81f0da42834d0bcc44a 100644 (file)
@@ -110,11 +110,11 @@ TrafficGen::initState()
 }
 
 unsigned int
-TrafficGen::drain(Event* drain_event)
+TrafficGen::drain(DrainManager *dm)
 {
     // @todo we should also stop putting new requests in the queue and
     // either interrupt the current state or wait for a transition
-    return port.drain(drain_event);
+    return port.drain(dm);
 }
 
 void
index 5f59be82c76550a53061d7e52968be493665bf81..4e94df548a11f8d3907074fc9e52001f8913906a 100644 (file)
@@ -604,7 +604,7 @@ class TrafficGen : public MemObject
 
     void initState();
 
-    unsigned int drain(Event *drain_event);
+    unsigned int drain(DrainManager *dm);
 
     void serialize(std::ostream &os);
 
index 799e9f96a274ab5377d1734f26a0ec28aa846a6a..d6162b689991376e7ec5a610682933f6782d5c29 100644 (file)
@@ -82,7 +82,7 @@ CopyEngine::CopyEngineChannel::CopyEngineChannel(CopyEngine *_ce, int cid)
       ce(_ce), channelId(cid), busy(false), underReset(false),
     refreshNext(false), latBeforeBegin(ce->params()->latBeforeBegin),
     latAfterCompletion(ce->params()->latAfterCompletion),
-    completionDataReg(0), nextState(Idle), drainEvent(NULL),
+    completionDataReg(0), nextState(Idle), drainManager(NULL),
     fetchCompleteEvent(this), addrCompleteEvent(this),
     readCompleteEvent(this), writeCompleteEvent(this),
     statusCompleteEvent(this)
@@ -140,12 +140,12 @@ CopyEngine::CopyEngineChannel::recvCommand()
         cr.status.dma_transfer_status(0);
         nextState = DescriptorFetch;
         fetchAddress = cr.descChainAddr;
-        if (ce->getState() == SimObject::Running)
+        if (ce->getDrainState() == Drainable::Running)
             fetchDescriptor(cr.descChainAddr);
     } else if (cr.command.append_dma()) {
         if (!busy) {
             nextState = AddressFetch;
-            if (ce->getState() == SimObject::Running)
+            if (ce->getDrainState() == Drainable::Running)
                 fetchNextAddr(lastDescriptorAddr);
         } else
             refreshNext = true;
@@ -637,41 +637,41 @@ CopyEngine::CopyEngineChannel::fetchAddrComplete()
 bool
 CopyEngine::CopyEngineChannel::inDrain()
 {
-    if (ce->getState() == SimObject::Draining) {
+    if (ce->getDrainState() == Drainable::Draining) {
         DPRINTF(Drain, "CopyEngine done draining, processing drain event\n");
-        assert(drainEvent);
-        drainEvent->process();
-        drainEvent = NULL;
+        assert(drainManager);
+        drainManager->signalDrainDone();
+        drainManager = NULL;
     }
 
-    return ce->getState() != SimObject::Running;
+    return ce->getDrainState() != Drainable::Running;
 }
 
 unsigned int
-CopyEngine::CopyEngineChannel::drain(Event *de)
+CopyEngine::CopyEngineChannel::drain(DrainManager *dm)
 {
-    if (nextState == Idle || ce->getState() != SimObject::Running)
+    if (nextState == Idle || ce->getDrainState() != Drainable::Running)
         return 0;
     unsigned int count = 1;
-    count += cePort.drain(de);
+    count += cePort.drain(dm);
 
     DPRINTF(Drain, "CopyEngineChannel not drained\n");
-    drainEvent = de;
+    this->drainManager = dm;
     return count;
 }
 
 unsigned int
-CopyEngine::drain(Event *de)
+CopyEngine::drain(DrainManager *dm)
 {
     unsigned int count;
-    count = pioPort.drain(de) + dmaPort.drain(de) + configPort.drain(de);
+    count = pioPort.drain(dm) + dmaPort.drain(dm) + configPort.drain(dm);
     for (int x = 0;x < chan.size(); x++)
-        count += chan[x]->drain(de);
+        count += chan[x]->drain(dm);
 
     if (count)
-        changeState(Draining);
+        setDrainState(Draining);
     else
-        changeState(Drained);
+        setDrainState(Drained);
 
     DPRINTF(Drain, "CopyEngine not drained\n");
     return count;
@@ -760,16 +760,16 @@ CopyEngine::CopyEngineChannel::restartStateMachine()
 }
 
 void
-CopyEngine::resume()
+CopyEngine::drainResume()
 {
-    SimObject::resume();
+    Drainable::drainResume();
     for (int x = 0;x < chan.size(); x++)
-        chan[x]->resume();
+        chan[x]->drainResume();
 }
 
 
 void
-CopyEngine::CopyEngineChannel::resume()
+CopyEngine::CopyEngineChannel::drainResume()
 {
     DPRINTF(DMACopyEngine, "Restarting state machine at state %d\n", nextState);
     restartStateMachine();
index 9a0cb062814cb8ce811b96fdf76bc8a8946df1c7..c4b07c79d199e30cc79ea24c4e1a69f6c5f5f290 100644 (file)
 #include "dev/copy_engine_defs.hh"
 #include "dev/pcidev.hh"
 #include "params/CopyEngine.hh"
+#include "sim/drain.hh"
 #include "sim/eventq.hh"
 
 class CopyEngine : public PciDev
 {
-    class CopyEngineChannel
+    class CopyEngineChannel : public Drainable
     {
       private:
         DmaPort cePort;
@@ -91,7 +92,7 @@ class CopyEngine : public PciDev
 
         ChannelState nextState;
 
-        Event *drainEvent;
+        DrainManager *drainManager;
       public:
         CopyEngineChannel(CopyEngine *_ce, int cid);
         virtual ~CopyEngineChannel();
@@ -106,8 +107,9 @@ class CopyEngine : public PciDev
         void channelRead(PacketPtr pkt, Addr daddr, int size);
         void channelWrite(PacketPtr pkt, Addr daddr, int size);
 
-        unsigned int drain(Event *de);
-        void resume();
+        unsigned int drain(DrainManager *drainManger);
+        void drainResume();
+
         void serialize(std::ostream &os);
         void unserialize(Checkpoint *cp, const std::string &section);
 
@@ -205,8 +207,9 @@ class CopyEngine : public PciDev
 
     virtual void serialize(std::ostream &os);
     virtual void unserialize(Checkpoint *cp, const std::string &section);
-    virtual unsigned int drain(Event *de);
-    virtual void resume();
+
+    unsigned int drain(DrainManager *drainManger);
+    void drainResume();
 };
 
 #endif //__DEV_COPY_ENGINE_HH__
index 1aa4a8647abca568224b828bdc5cb930b4fb47a3..952d6f622c811003ff50e467ad916089e491fbf5 100644 (file)
@@ -51,7 +51,7 @@
 DmaPort::DmaPort(MemObject *dev, System *s)
     : MasterPort(dev->name() + ".dma", dev), device(dev), sendEvent(this),
       sys(s), masterId(s->getMasterId(dev->name())),
-      pendingCount(0), drainEvent(NULL),
+      pendingCount(0), drainManager(NULL),
       inRetry(false)
 { }
 
@@ -98,9 +98,9 @@ DmaPort::handleResp(PacketPtr pkt, Tick delay)
     delete pkt;
 
     // we might be drained at this point, if so signal the drain event
-    if (pendingCount == 0 && drainEvent) {
-        drainEvent->process();
-        drainEvent = NULL;
+    if (pendingCount == 0 && drainManager) {
+        drainManager->signalDrainDone();
+        drainManager = NULL;
     }
 }
 
@@ -128,22 +128,22 @@ DmaDevice::init()
 }
 
 unsigned int
-DmaDevice::drain(Event *de)
+DmaDevice::drain(DrainManager *dm)
 {
-    unsigned int count = pioPort.drain(de) + dmaPort.drain(de);
+    unsigned int count = pioPort.drain(dm) + dmaPort.drain(dm);
     if (count)
-        changeState(Draining);
+        setDrainState(Drainable::Draining);
     else
-        changeState(Drained);
+        setDrainState(Drainable::Drained);
     return count;
 }
 
 unsigned int
-DmaPort::drain(Event *de)
+DmaPort::drain(DrainManager *dm)
 {
     if (pendingCount == 0)
         return 0;
-    drainEvent = de;
+    drainManager = dm;
     DPRINTF(Drain, "DmaPort not drained\n");
     return 1;
 }
index cd328f3d682a0748255c093c1df0cab15e6a80f9..3b4bb522d88fbca5219ca4cf207c674787d97523 100644 (file)
@@ -48,6 +48,7 @@
 
 #include "dev/io_device.hh"
 #include "params/DmaDevice.hh"
+#include "sim/drain.hh"
 
 class DmaPort : public MasterPort
 {
@@ -123,7 +124,7 @@ class DmaPort : public MasterPort
 
     /** If we need to drain, keep the drain event around until we're done
      * here.*/
-    Event *drainEvent;
+    DrainManager *drainManager;
 
     /** If the port is currently waiting for a retry before it can
      * send whatever it is that it's sending. */
@@ -146,7 +147,7 @@ class DmaPort : public MasterPort
     bool dmaPending() const { return pendingCount > 0; }
 
     unsigned cacheBlockSize() const { return peerBlockSize(); }
-    unsigned int drain(Event *de);
+    unsigned int drain(DrainManager *drainManger);
 };
 
 class DmaDevice : public PioDevice
@@ -175,7 +176,7 @@ class DmaDevice : public PioDevice
 
     virtual void init();
 
-    virtual unsigned int drain(Event *de);
+    unsigned int drain(DrainManager *drainManger);
 
     unsigned cacheBlockSize() const { return dmaPort.cacheBlockSize(); }
 
index 159cc47267c17a848fe9f88b123c41e18dcc7b8b..9a3ddaeb7b7f4ca01cb81ea8d1bbd34d3f738fdd 100644 (file)
@@ -57,7 +57,7 @@ using namespace iGbReg;
 using namespace Net;
 
 IGbE::IGbE(const Params *p)
-    : EtherDevice(p), etherInt(NULL),  drainEvent(NULL),
+    : EtherDevice(p), etherInt(NULL),  drainManager(NULL),
       useFlowControl(p->use_flow_control),
       rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false),
       txTick(false), txFifoTick(false), rxDmaPacket(false), pktOffset(0),
@@ -588,7 +588,7 @@ IGbE::write(PacketPtr pkt)
       case REG_RDT:
         regs.rdt = val;
         DPRINTF(EthernetSM, "RXS: RDT Updated.\n");
-        if (getState() == SimObject::Running) {
+        if (getDrainState() == Drainable::Running) {
             DPRINTF(EthernetSM, "RXS: RDT Fetching Descriptors!\n");
             rxDescCache.fetchDescriptors();
         } else {
@@ -628,7 +628,7 @@ IGbE::write(PacketPtr pkt)
       case REG_TDT:
         regs.tdt = val;
         DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n");
-        if (getState() == SimObject::Running) {
+        if (getDrainState() == Drainable::Running) {
             DPRINTF(EthernetSM, "TXS: TDT Fetching Descriptors!\n");
             txDescCache.fetchDescriptors();
         } else {
@@ -906,7 +906,7 @@ void
 IGbE::DescCache<T>::writeback1()
 {
     // If we're draining delay issuing this DMA
-    if (igbe->getState() != SimObject::Running) {
+    if (igbe->getDrainState() != Drainable::Running) {
         igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
         return;
     }
@@ -987,7 +987,7 @@ void
 IGbE::DescCache<T>::fetchDescriptors1()
 {
     // If we're draining delay issuing this DMA
-    if (igbe->getState() != SimObject::Running) {
+    if (igbe->getDrainState() != Drainable::Running) {
         igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
         return;
     }
@@ -1493,7 +1493,7 @@ IGbE::RxDescCache::pktComplete()
 void
 IGbE::RxDescCache::enableSm()
 {
-    if (!igbe->drainEvent) {
+    if (!igbe->drainManager) {
         igbe->rxTick = true;
         igbe->restartClock();
     }
@@ -2029,7 +2029,7 @@ IGbE::TxDescCache::packetAvailable()
 void
 IGbE::TxDescCache::enableSm()
 {
-    if (!igbe->drainEvent) {
+    if (!igbe->drainManager) {
         igbe->txTick = true;
         igbe->restartClock();
     }
@@ -2049,19 +2049,19 @@ void
 IGbE::restartClock()
 {
     if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) &&
-        getState() == SimObject::Running)
+        getDrainState() == Drainable::Running)
         schedule(tickEvent, clockEdge(Cycles(1)));
 }
 
 unsigned int
-IGbE::drain(Event *de)
+IGbE::drain(DrainManager *dm)
 {
     unsigned int count;
-    count = pioPort.drain(de) + dmaPort.drain(de);
+    count = pioPort.drain(dm) + dmaPort.drain(dm);
     if (rxDescCache.hasOutstandingEvents() ||
         txDescCache.hasOutstandingEvents()) {
         count++;
-        drainEvent = de;
+        drainManager = dm;
     }
 
     txFifoTick = false;
@@ -2073,17 +2073,17 @@ IGbE::drain(Event *de)
 
     if (count) {
         DPRINTF(Drain, "IGbE not drained\n");
-        changeState(Draining);
+        setDrainState(Drainable::Draining);
     } else
-        changeState(Drained);
+        setDrainState(Drainable::Drained);
 
     return count;
 }
 
 void
-IGbE::resume()
+IGbE::drainResume()
 {
-    SimObject::resume();
+    Drainable::drainResume();
 
     txFifoTick = true;
     txTick = true;
@@ -2096,7 +2096,7 @@ IGbE::resume()
 void
 IGbE::checkDrain()
 {
-    if (!drainEvent)
+    if (!drainManager)
         return;
 
     txFifoTick = false;
@@ -2105,8 +2105,8 @@ IGbE::checkDrain()
     if (!rxDescCache.hasOutstandingEvents() &&
         !txDescCache.hasOutstandingEvents()) {
         DPRINTF(Drain, "IGbE done draining, processing drain event\n");
-        drainEvent->process();
-        drainEvent = NULL;
+        drainManager->signalDrainDone();
+        drainManager = NULL;
     }
 }
 
@@ -2130,7 +2130,7 @@ IGbE::txStateMachine()
         bool success =
 #endif
             txFifo.push(txPacket);
-        txFifoTick = true && !drainEvent;
+        txFifoTick = true && !drainManager;
         assert(success);
         txPacket = NULL;
         anBegin("TXS", "Desc Writeback");
@@ -2229,7 +2229,7 @@ IGbE::ethRxPkt(EthPacketPtr pkt)
     }
 
     // restart the state machines if they are stopped
-    rxTick = true && !drainEvent;
+    rxTick = true && !drainManager;
     if ((rxTick || txTick) && !tickEvent.scheduled()) {
         DPRINTF(EthernetSM,
                 "RXS: received packet into fifo, starting ticking\n");
@@ -2442,8 +2442,8 @@ IGbE::ethTxDone()
     // restart the tx state machines if they are stopped
     // fifo to send another packet
     // tx sm to put more data into the fifo
-    txFifoTick = true && !drainEvent;
-    if (txDescCache.descLeft() != 0 && !drainEvent)
+    txFifoTick = true && !drainManager;
+    if (txDescCache.descLeft() != 0 && !drainManager)
         txTick = true;
 
     restartClock();
index 099cd0d1190f2d4f5565c727137b1be001c73a59..b8099fb1c92a6abb90bc6d13c09f22b9c102fb5f 100644 (file)
@@ -68,7 +68,7 @@ class IGbE : public EtherDevice
     uint16_t flash[iGbReg::EEPROM_SIZE];
 
     // The drain event if we have one
-    Event *drainEvent;
+    DrainManager *drainManager;
 
     // cached parameters from params struct
     bool useFlowControl;
@@ -347,7 +347,7 @@ class IGbE : public EtherDevice
         virtual void updateHead(long h) { igbe->regs.rdh(h); }
         virtual void enableSm();
         virtual void fetchAfterWb() {
-            if (!igbe->rxTick && igbe->getState() == SimObject::Running)
+            if (!igbe->rxTick && igbe->getDrainState() == Drainable::Running)
                 fetchDescriptors();
         }
 
@@ -409,7 +409,7 @@ class IGbE : public EtherDevice
         virtual void enableSm();
         virtual void actionAfterWb();
         virtual void fetchAfterWb() {
-            if (!igbe->txTick && igbe->getState() == SimObject::Running)
+            if (!igbe->txTick && igbe->getDrainState() == Drainable::Running)
                 fetchDescriptors();
         }
         
@@ -535,8 +535,9 @@ class IGbE : public EtherDevice
 
     virtual void serialize(std::ostream &os);
     virtual void unserialize(Checkpoint *cp, const std::string &section);
-    virtual unsigned int drain(Event *de);
-    virtual void resume();
+
+    unsigned int drain(DrainManager *dm);
+    void drainResume();
 
 };
 
index f0c8c8668e3c1c8c8e71c110238a3bd9fe71a6a4..6c5ccdd869529d9673a2e4d400c91ad8bd684af1 100644 (file)
@@ -323,7 +323,7 @@ IdeDisk::doDmaTransfer()
         panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
               dmaState, devState);
 
-    if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
+    if (ctrl->dmaPending() || ctrl->getDrainState() != Drainable::Running) {
         schedule(dmaTransferEvent, curTick() + DMA_BACKOFF_PERIOD);
         return;
     } else
@@ -404,7 +404,7 @@ IdeDisk::doDmaRead()
                 curPrd.getByteCount(), TheISA::PageBytes);
 
     }
-    if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
+    if (ctrl->dmaPending() || ctrl->getDrainState() != Drainable::Running) {
         schedule(dmaReadWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
         return;
     } else if (!dmaReadCG->done()) {
@@ -481,7 +481,7 @@ IdeDisk::doDmaWrite()
         dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
                 curPrd.getByteCount(), TheISA::PageBytes);
     }
-    if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {
+    if (ctrl->dmaPending() || ctrl->getDrainState() != Drainable::Running) {
         schedule(dmaWriteWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
         DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n");
         return;
index 0cc1324f5983fdec40e18f6dc868539753e8df82..988f8344aafddfa458f7d2e7d20500b2fe09f204 100644 (file)
@@ -89,14 +89,14 @@ PioDevice::getSlavePort(const std::string &if_name, PortID idx)
 }
 
 unsigned int
-PioDevice::drain(Event *de)
+PioDevice::drain(DrainManager *dm)
 {
     unsigned int count;
-    count = pioPort.drain(de);
+    count = pioPort.drain(dm);
     if (count)
-        changeState(Draining);
+        setDrainState(Drainable::Draining);
     else
-        changeState(Drained);
+        setDrainState(Drainable::Drained);
     return count;
 }
 
index bd6a26d141d24562c3574b2432061232c23b93b4..848b8f0ba7f1136fa9d597f5ea0fb199481a96be 100644 (file)
@@ -125,7 +125,7 @@ class PioDevice : public MemObject
 
     virtual void init();
 
-    virtual unsigned int drain(Event *de);
+    unsigned int drain(DrainManager *drainManger);
 
     virtual BaseSlavePort &getSlavePort(const std::string &if_name,
                                         PortID idx = InvalidPortID);
index 0af9fbfc59564780be2f47f1d06f579653593768..90eb14acd0cf9f5f783fa9d471a660fab16a0fd2 100644 (file)
@@ -1069,7 +1069,7 @@ NSGigE::doRxDmaRead()
     assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
     rxDmaState = dmaReading;
 
-    if (dmaPending() || getState() != Running)
+    if (dmaPending() || getDrainState() != Drainable::Running)
         rxDmaState = dmaReadWaiting;
     else
         dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
@@ -1100,7 +1100,7 @@ NSGigE::doRxDmaWrite()
     assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
     rxDmaState = dmaWriting;
 
-    if (dmaPending() || getState() != Running)
+    if (dmaPending() || getDrainState() != Running)
         rxDmaState = dmaWriteWaiting;
     else
         dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
@@ -1518,7 +1518,7 @@ NSGigE::doTxDmaRead()
     assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
     txDmaState = dmaReading;
 
-    if (dmaPending() || getState() != Running)
+    if (dmaPending() || getDrainState() != Running)
         txDmaState = dmaReadWaiting;
     else
         dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
@@ -1549,7 +1549,7 @@ NSGigE::doTxDmaWrite()
     assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
     txDmaState = dmaWriting;
 
-    if (dmaPending() || getState() != Running)
+    if (dmaPending() || getDrainState() != Running)
         txDmaState = dmaWriteWaiting;
     else
         dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
@@ -2112,9 +2112,9 @@ NSGigE::recvPacket(EthPacketPtr packet)
 
 
 void
-NSGigE::resume()
+NSGigE::drainResume()
 {
-    SimObject::resume();
+    Drainable::drainResume();
 
     // 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.
index f4d0171d6a8c19069ead2087e44c3eeee93d51b2..6d5068a2b8a3f93d2d04c27213c897559cb02bea 100644 (file)
@@ -369,7 +369,7 @@ class NSGigE : public EtherDevBase
     virtual void serialize(std::ostream &os);
     virtual void unserialize(Checkpoint *cp, const std::string &section);
 
-    virtual void resume();
+    void drainResume();
 };
 
 /*
index fb4aaa799c280600ed0c81d2ec07707a62e11978..592852e293ebac273e84c1b34fdd5ee01e4d8bf9 100644 (file)
@@ -157,14 +157,14 @@ PciDev::init()
 }
 
 unsigned int
-PciDev::drain(Event *de)
+PciDev::drain(DrainManager *dm)
 {
     unsigned int count;
-    count = pioPort.drain(de) + dmaPort.drain(de) + configPort.drain(de);
+    count = pioPort.drain(dm) + dmaPort.drain(dm) + configPort.drain(dm);
     if (count)
-        changeState(Draining);
+        setDrainState(Drainable::Draining);
     else
-        changeState(Drained);
+        setDrainState(Drainable::Drained);
     return count;
 }
 
index 9994d2a2de645bdbf54f368bd82ec8891af4268a..df468d4c62d18e25904b1a5737d55f4744251d54 100644 (file)
@@ -216,7 +216,7 @@ class PciDev : public DmaDevice
     virtual void unserialize(Checkpoint *cp, const std::string &section);
 
 
-    virtual unsigned int drain(Event *de);
+    virtual unsigned int drain(DrainManager *dm);
 
     virtual BaseSlavePort &getSlavePort(const std::string &if_name,
                                         PortID idx = InvalidPortID)
index 2d109cbbb9a138111f0349b6555847de48f2bc05..cfb7548eb36858e1ea88ece5ccaf3cf83f1cb896 100644 (file)
@@ -870,7 +870,7 @@ Device::rxKick()
         break;
 
       case rxBeginCopy:
-        if (dmaPending() || getState() != Running)
+        if (dmaPending() || getDrainState() != Drainable::Running)
             goto exit;
 
         rxDmaAddr = params()->platform->pciToDma(
@@ -1070,7 +1070,7 @@ Device::txKick()
         break;
 
       case txBeginCopy:
-        if (dmaPending() || getState() != Running)
+        if (dmaPending() || getDrainState() != Drainable::Running)
             goto exit;
 
         txDmaAddr = params()->platform->pciToDma(
@@ -1246,9 +1246,9 @@ Device::recvPacket(EthPacketPtr packet)
 }
 
 void
-Device::resume()
+Device::drainResume()
 {
-    SimObject::resume();
+    Drainable::drainResume();
 
     // 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.
index 8189ce39a885306787f5a94fb5ed395d32cb5d5a..58f9e7253ab4fbe005a7a71f57cfc5609af68bd2 100644 (file)
@@ -271,7 +271,7 @@ class Device : public Base
   public:
     virtual Tick read(PacketPtr pkt);
     virtual Tick write(PacketPtr pkt);
-    virtual void resume();
+    virtual void drainResume();
 
     void prepareIO(int cpu, int index);
     void prepareRead(int cpu, int index);
index a0db6e52a227c87b8d154d93e583c5fdf55fa86c..ddbdcb136e681c158339fdc8e0c9ec45381d0586 100644 (file)
@@ -161,7 +161,8 @@ BaseBus::calcPacketTiming(PacketPtr pkt)
 template <typename PortClass>
 BaseBus::Layer<PortClass>::Layer(BaseBus& _bus, const std::string& _name,
                                  Tick _clock) :
-    bus(_bus), _name(_name), state(IDLE), clock(_clock), drainEvent(NULL),
+    Drainable(),
+    bus(_bus), _name(_name), state(IDLE), clock(_clock), drainManager(NULL),
     releaseEvent(this)
 {
 }
@@ -266,12 +267,12 @@ BaseBus::Layer<PortClass>::releaseLayer()
         // busy, and in the latter case the bus may be released before
         // we see a retry from the destination
         retryWaiting();
-    } else if (drainEvent) {
-        DPRINTF(Drain, "Bus done draining, processing drain event\n");
+    } else if (drainManager) {
+        DPRINTF(Drain, "Bus done draining, signaling drain manager\n");
         //If we weren't able to drain before, do it now.
-        drainEvent->process();
+        drainManager->signalDrainDone();
         // Clear the drain event once we're done with it.
-        drainEvent = NULL;
+        drainManager = NULL;
     }
 }
 
@@ -522,14 +523,14 @@ BaseBus::deviceBlockSize() const
 
 template <typename PortClass>
 unsigned int
-BaseBus::Layer<PortClass>::drain(Event * de)
+BaseBus::Layer<PortClass>::drain(DrainManager *dm)
 {
     //We should check that we're not "doing" anything, and that noone is
     //waiting. We might be idle but have someone waiting if the device we
     //contacted for a retry didn't actually retry.
     if (!retryList.empty() || state != IDLE) {
         DPRINTF(Drain, "Bus not drained\n");
-        drainEvent = de;
+        drainManager = dm;
         return 1;
     }
     return 0;
index f3cbc9d24e7d13cd7d84669c3014f741f282034a..19ffa020c79fce4a1159995f374c8056a94b8da0 100644 (file)
@@ -94,7 +94,7 @@ class BaseBus : public MemObject
      * whereas a response layer holds master ports.
      */
     template <typename PortClass>
-    class Layer
+    class Layer : public Drainable
     {
 
       public:
@@ -118,7 +118,7 @@ class BaseBus : public MemObject
          *
          * @return 1 if busy or waiting to retry, or 0 if idle
          */
-        unsigned int drain(Event *de);
+        unsigned int drain(DrainManager *dm);
 
         /**
          * Get the bus layer's name
@@ -206,8 +206,8 @@ class BaseBus : public MemObject
         /** the clock speed for the bus layer */
         Tick clock;
 
-        /** event for signalling when drained */
-        Event * drainEvent;
+        /** manager to signal when drained */
+        DrainManager *drainManager;
 
         /**
          * An array of ports that retry should be called
@@ -366,7 +366,7 @@ class BaseBus : public MemObject
     BaseSlavePort& getSlavePort(const std::string& if_name,
                                 PortID idx = InvalidPortID);
 
-    virtual unsigned int drain(Event *de) = 0;
+    virtual unsigned int drain(DrainManager *dm) = 0;
 
 };
 
index a8874962704a0988f1dc5d2e53aa860a1a1adc2a..ad1c751bc78e1e3c94eac8359e8ebadcdb0b5b00 100644 (file)
@@ -77,7 +77,7 @@ BaseCache::BaseCache(const Params *p)
       blocked(0),
       noTargetMSHR(NULL),
       missCount(p->max_miss_count),
-      drainEvent(NULL),
+      drainManager(NULL),
       addrRanges(p->addr_ranges.begin(), p->addr_ranges.end()),
       system(p->system)
 {
@@ -749,19 +749,19 @@ BaseCache::regStats()
 }
 
 unsigned int
-BaseCache::drain(Event *de)
+BaseCache::drain(DrainManager *dm)
 {
-    int count = memSidePort->drain(de) + cpuSidePort->drain(de);
+    int count = memSidePort->drain(dm) + cpuSidePort->drain(dm);
 
     // Set status
     if (count != 0) {
-        drainEvent = de;
+        drainManager = dm;
 
-        changeState(SimObject::Draining);
+        setDrainState(Drainable::Draining);
         DPRINTF(Drain, "Cache not drained\n");
         return count;
     }
 
-    changeState(SimObject::Drained);
+    setDrainState(Drainable::Drained);
     return 0;
 }
index 42ade9b0bf010dc5a799515a06df42edaaa17de0..ab13be77125bd8737cd4fdbf0e5261a31e07d7bd 100644 (file)
@@ -269,7 +269,7 @@ class BaseCache : public MemObject
     Counter missCount;
 
     /** The drain event. */
-    Event *drainEvent;
+    DrainManager *drainManager;
 
     /**
      * The address range to which the cache responds on the CPU side.
@@ -542,7 +542,7 @@ class BaseCache : public MemObject
         // interesting again.
     }
 
-    virtual unsigned int drain(Event *de);
+    virtual unsigned int drain(DrainManager *dm);
 
     virtual bool inCache(Addr addr) = 0;
 
index 98d86f3f0ac328b44a33048231fab4377e2bd811..b1ac6dbcf01f79511753d7630adacc7a41e50acf 100644 (file)
@@ -508,10 +508,10 @@ CoherentBus::forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id)
 }
 
 unsigned int
-CoherentBus::drain(Event *de)
+CoherentBus::drain(DrainManager *dm)
 {
     // sum up the individual layers
-    return reqLayer.drain(de) + respLayer.drain(de) + snoopRespLayer.drain(de);
+    return reqLayer.drain(dm) + respLayer.drain(dm) + snoopRespLayer.drain(dm);
 }
 
 CoherentBus *
index 89a75954648e9c0e8d9ba0f50d14e3a80c1f9a52..61406608b5a39b8d6fcc7eab127806376f1d4b0b 100644 (file)
@@ -299,7 +299,7 @@ class CoherentBus : public BaseBus
 
     CoherentBus(const CoherentBusParams *p);
 
-    unsigned int drain(Event *de);
+    unsigned int drain(DrainManager *dm);
 };
 
 #endif //__MEM_COHERENT_BUS_HH__
index 237e8726b8d7dc6288c43b10a76f01dafad9a53d..f14f6e3d66d024a13eaf4cbaac12423a1e0203b0 100644 (file)
@@ -212,10 +212,10 @@ NoncoherentBus::recvFunctional(PacketPtr pkt, PortID slave_port_id)
 }
 
 unsigned int
-NoncoherentBus::drain(Event *de)
+NoncoherentBus::drain(DrainManager *dm)
 {
     // sum up the individual layers
-    return reqLayer.drain(de) + respLayer.drain(de);
+    return reqLayer.drain(dm) + respLayer.drain(dm);
 }
 
 NoncoherentBus*
index 16cf7deda4c9fc63057b696efe9bbd00efefc454..a42c26b2e989ca1082aca335f9d5fb0d636df39c 100644 (file)
@@ -207,7 +207,7 @@ class NoncoherentBus : public BaseBus
 
     NoncoherentBus(const NoncoherentBusParams *p);
 
-    unsigned int drain(Event *de);
+    unsigned int drain(DrainManager *dm);
 
 };
 
index 4a4543f61e3eecc2838dcd11fe7f21a8aade607a..eb94cc3970e5048727b65cdf54ae3215742b6a1b 100644 (file)
@@ -48,7 +48,7 @@
 using namespace std;
 
 PacketQueue::PacketQueue(EventManager& _em, const std::string& _label)
-    : em(_em), sendEvent(this), drainEvent(NULL), label(_label),
+    : em(_em), sendEvent(this), drainManager(NULL), label(_label),
       waitingOnRetry(false)
 {
 }
@@ -173,11 +173,11 @@ PacketQueue::scheduleSend(Tick time)
             em.schedule(&sendEvent, std::max(nextReady, curTick() + 1));
     } else {
         // no more to send, so if we're draining, we may be done
-        if (drainEvent && transmitList.empty() && !sendEvent.scheduled()) {
+        if (drainManager && transmitList.empty() && !sendEvent.scheduled()) {
             DPRINTF(Drain, "PacketQueue done draining,"
                     "processing drain event\n");
-            drainEvent->process();
-            drainEvent = NULL;
+            drainManager->signalDrainDone();
+            drainManager = NULL;
         }
     }
 }
@@ -204,12 +204,12 @@ PacketQueue::processSendEvent()
 }
 
 unsigned int
-PacketQueue::drain(Event *de)
+PacketQueue::drain(DrainManager *dm)
 {
     if (transmitList.empty() && !sendEvent.scheduled())
         return 0;
     DPRINTF(Drain, "PacketQueue not drained\n");
-    drainEvent = de;
+    drainManager = dm;
     return 1;
 }
 
index 0171eb9a39d8e5738bfcec5bb82ee1f0ff711742..2321ec4f273b6317050cc4849a0f9f319445d002 100644 (file)
 
 #include "mem/port.hh"
 #include "sim/eventq.hh"
+#include "sim/drain.hh"
 
 /**
  * A packet queue is a class that holds deferred packets and later
  * sends them using the associated slave port or master port.
  */
-class PacketQueue
+class PacketQueue : public Drainable
 {
   private:
     /** A deferred packet, buffered to transmit later. */
@@ -95,9 +96,9 @@ class PacketQueue
      **/
     EventWrapper<PacketQueue, &PacketQueue::processSendEvent> sendEvent;
 
-    /** If we need to drain, keep the drain event around until we're done
+    /** If we need to drain, keep the drain manager around until we're done
      * here.*/
-    Event *drainEvent;
+    DrainManager *drainManager;
 
   protected:
 
@@ -207,13 +208,7 @@ class PacketQueue
      */
     void retry();
 
-    /**
-     * Hook for draining the packet queue.
-     *
-     * @param de An event which is used to signal back to the caller
-     * @return A number indicating how many times process will be called
-     */
-    unsigned int drain(Event *de);
+    unsigned int drain(DrainManager *dm);
 };
 
 class MasterPacketQueue : public PacketQueue
index b771f6984d4d30bebb8cbdf1f8273f7cd20570af..dd5caa084d07fb6343a09e566d8c6347aa665bda 100644 (file)
@@ -97,13 +97,7 @@ class QueuedSlavePort : public SlavePort
      * functional request. */
     bool checkFunctional(PacketPtr pkt) { return queue.checkFunctional(pkt); }
 
-    /**
-     * Hook for draining the queued port.
-     *
-     * @param de an event which is used to signal back to the caller
-     * @returns a number indicating how many times process will be called
-     */
-    unsigned int drain(Event *de) { return queue.drain(de); }
+    unsigned int drain(DrainManager *dm) { return queue.drain(dm); }
 };
 
 class QueuedMasterPort : public MasterPort
@@ -156,13 +150,7 @@ class QueuedMasterPort : public MasterPort
      * functional request. */
     bool checkFunctional(PacketPtr pkt) { return queue.checkFunctional(pkt); }
 
-    /**
-     * Hook for draining the queued port.
-     *
-     * @param de an event which is used to signal back to the caller
-     * @returns a number indicating how many times process will be called
-     */
-    unsigned int drain(Event *de) { return queue.drain(de); }
+    unsigned int drain(DrainManager *dm) { return queue.drain(dm); }
 };
 
 #endif // __MEM_QPORT_HH__
index 8d15b8decc1803b1a2b04c9bb575c3174ba2485c..5c6adb0abc7def360d37a51df722caa0de1b75d8 100644 (file)
@@ -56,8 +56,6 @@ class MemoryControl : public ClockedObject, public Consumer
 
     ~MemoryControl();
 
-    unsigned int drain(Event *de) = 0;
-
     virtual void wakeup() = 0;
 
     virtual void setConsumer(Consumer* consumer_ptr) = 0;
index c0e91c28b211e0161269ab3ba352dd8001483bce..6201137198e3ef6bfeca562c958df360cd981174 100644 (file)
@@ -684,7 +684,7 @@ RubyMemoryControl::executeCycle()
 }
 
 unsigned int
-RubyMemoryControl::drain(Event *de)
+RubyMemoryControl::drain(DrainManager *dm)
 {
     DPRINTF(RubyMemory, "MemoryController drain\n");
     if(m_event.scheduled()) {
index 1f3a8acf56b94930179c6fd5648f4b9c69049571..53e8fabef4efa3ea82b50fdc816975cda11bf33c 100644 (file)
@@ -62,7 +62,7 @@ class RubyMemoryControl : public MemoryControl
 
     ~RubyMemoryControl();
 
-    unsigned int drain(Event *de);
+    unsigned int drain(DrainManager *dm);
 
     void wakeup();
 
index 1259f0f15fcb0fb3adc5ec466b629be63a3f9ba7..dd9e9676ebb3a520b1fddb9e9dbfce35f9c77af8 100644 (file)
@@ -53,7 +53,7 @@ RubyPort::RubyPort(const Params *p)
       m_mandatory_q_ptr(NULL),
       pio_port(csprintf("%s-pio-port", name()), this),
       m_usingRubyTester(p->using_ruby_tester), m_request_cnt(0),
-      drainEvent(NULL), ruby_system(p->ruby_system), system(p->system),
+      drainManager(NULL), ruby_system(p->ruby_system), system(p->system),
       waitingOnSequencer(false), access_phys_mem(p->access_phys_mem)
 {
     assert(m_version != -1);
@@ -343,36 +343,36 @@ void
 RubyPort::testDrainComplete()
 {
     //If we weren't able to drain before, we might be able to now.
-    if (drainEvent != NULL) {
+    if (drainManager != NULL) {
         unsigned int drainCount = outstandingCount();
         DPRINTF(Drain, "Drain count: %u\n", drainCount);
         if (drainCount == 0) {
-            DPRINTF(Drain, "RubyPort done draining, processing drain event\n");
-            drainEvent->process();
-            // Clear the drain event once we're done with it.
-            drainEvent = NULL;
+            DPRINTF(Drain, "RubyPort done draining, signaling drain done\n");
+            drainManager->signalDrainDone();
+            // Clear the drain manager once we're done with it.
+            drainManager = NULL;
         }
     }
 }
 
 unsigned int
-RubyPort::getChildDrainCount(Event *de)
+RubyPort::getChildDrainCount(DrainManager *dm)
 {
     int count = 0;
 
     if (pio_port.isConnected()) {
-        count += pio_port.drain(de);
+        count += pio_port.drain(dm);
         DPRINTF(Config, "count after pio check %d\n", count);
     }
 
     for (CpuPortIter p = slave_ports.begin(); p != slave_ports.end(); ++p) {
-        count += (*p)->drain(de);
+        count += (*p)->drain(dm);
         DPRINTF(Config, "count after slave port check %d\n", count);
     }
 
     for (std::vector<PioPort*>::iterator p = master_ports.begin();
          p != master_ports.end(); ++p) {
-        count += (*p)->drain(de);
+        count += (*p)->drain(dm);
         DPRINTF(Config, "count after master port check %d\n", count);
     }
 
@@ -382,7 +382,7 @@ RubyPort::getChildDrainCount(Event *de)
 }
 
 unsigned int
-RubyPort::drain(Event *de)
+RubyPort::drain(DrainManager *dm)
 {
     if (isDeadlockEventScheduled()) {
         descheduleDeadlockEvent();
@@ -390,28 +390,28 @@ RubyPort::drain(Event *de)
 
     //
     // If the RubyPort is not empty, then it needs to clear all outstanding
-    // requests before it should call drainEvent->process()
+    // requests before it should call drainManager->signalDrainDone()
     //
     DPRINTF(Config, "outstanding count %d\n", outstandingCount());
     bool need_drain = outstandingCount() > 0;
 
     //
     // Also, get the number of child ports that will also need to clear
-    // their buffered requests before they call drainEvent->process()
+    // their buffered requests before they call drainManager->signalDrainDone()
     //
-    unsigned int child_drain_count = getChildDrainCount(de);
+    unsigned int child_drain_count = getChildDrainCount(dm);
 
     // Set status
     if (need_drain) {
-        drainEvent = de;
+        drainManager = dm;
 
         DPRINTF(Drain, "RubyPort not drained\n");
-        changeState(SimObject::Draining);
+        setDrainState(Drainable::Draining);
         return child_drain_count + 1;
     }
 
-    drainEvent = NULL;
-    changeState(SimObject::Drained);
+    drainManager = NULL;
+    setDrainState(Drainable::Drained);
     return child_drain_count;
 }
 
index ab09bd90a4df5b3a223de04acbb73cfc07e71ca2..98bcede446c81c6df7e3cddbc1369c58fa57d3e6 100644 (file)
@@ -142,7 +142,7 @@ class RubyPort : public MemObject
     //
     void setController(AbstractController* _cntrl) { m_controller = _cntrl; }
     int getId() { return m_version; }
-    unsigned int drain(Event *de);
+    unsigned int drain(DrainManager *dm);
 
   protected:
     const std::string m_name;
@@ -166,7 +166,7 @@ class RubyPort : public MemObject
         }
     }
 
-    unsigned int getChildDrainCount(Event *de);
+    unsigned int getChildDrainCount(DrainManager *dm);
 
     uint16_t m_port_id;
     uint64_t m_request_cnt;
@@ -176,7 +176,7 @@ class RubyPort : public MemObject
     std::vector<M5Port*> slave_ports;
     std::vector<PioPort*> master_ports;
 
-    Event *drainEvent;
+    DrainManager *drainManager;
 
     RubySystem* ruby_system;
     System* system;
index 9b6ef35cd525102858c64b28f5069385b5f4752a..a45dfc98da78ded055dbe3cd9851c9d58919b2fa 100644 (file)
@@ -85,7 +85,7 @@ Sequencer::~Sequencer()
 void
 Sequencer::wakeup()
 {
-    assert(getState() != SimObject::Draining);
+    assert(getDrainState() != Drainable::Draining);
 
     // Check for deadlock of any of the requests
     Time current_time = g_system_ptr->getTime();
@@ -209,7 +209,8 @@ Sequencer::insertRequest(PacketPtr pkt, RubyRequestType request_type)
         (m_writeRequestTable.size() + m_readRequestTable.size()));
 
     // See if we should schedule a deadlock check
-    if (!deadlockCheckEvent.scheduled() && getState() != SimObject::Draining) {
+    if (!deadlockCheckEvent.scheduled() &&
+        getDrainState() != Drainable::Draining) {
         schedule(deadlockCheckEvent,
             g_system_ptr->clockPeriod() * m_deadlock_threshold + curTick());
     }
index 0f6e9511c5858d448c59d99901d38a25d1cb0e16..42c97977a4704eedc0afb225aa9e566b127d9326 100644 (file)
@@ -51,7 +51,7 @@ SimpleDRAM::SimpleDRAM(const SimpleDRAMParams* p) :
     retryRdReq(false), retryWrReq(false),
     rowHitFlag(false), stopReads(false),
     writeEvent(this), respondEvent(this),
-    refreshEvent(this), nextReqEvent(this), drainEvent(NULL),
+    refreshEvent(this), nextReqEvent(this), drainManager(NULL),
     bytesPerCacheLine(0),
     linesPerRowBuffer(p->lines_per_rowbuffer),
     ranksPerChannel(p->ranks_per_channel),
@@ -346,9 +346,9 @@ SimpleDRAM::processWriteEvent()
 
     // if there is nothing left in any queue, signal a drain
     if (dramWriteQueue.empty() && dramReadQueue.empty() &&
-        dramRespQueue.empty () && drainEvent) {
-        drainEvent->process();
-        drainEvent = NULL;
+        dramRespQueue.empty () && drainManager) {
+        drainManager->signalDrainDone();
+        drainManager = NULL;
     }
 
     // Once you're done emptying the write queue, check if there's
@@ -595,9 +595,9 @@ SimpleDRAM::processRespondEvent()
      } else {
          // if there is nothing left in any queue, signal a drain
          if (dramWriteQueue.empty() && dramReadQueue.empty() &&
-             drainEvent) {
-             drainEvent->process();
-             drainEvent = NULL;
+             drainManager) {
+             drainManager->signalDrainDone();
+             drainManager = NULL;
          }
      }
 }
@@ -1197,22 +1197,22 @@ SimpleDRAM::getSlavePort(const string &if_name, PortID idx)
 }
 
 unsigned int
-SimpleDRAM::drain(Event *de)
+SimpleDRAM::drain(DrainManager *dm)
 {
-    unsigned int count = port.drain(de);
+    unsigned int count = port.drain(dm);
 
     // if there is anything in any of our internal queues, keep track
     // of that as well
     if (!(dramWriteQueue.empty() && dramReadQueue.empty() &&
           dramRespQueue.empty())) {
         ++count;
-        drainEvent = de;
+        drainManager = dm;
     }
 
     if (count)
-        changeState(Draining);
+        setDrainState(Drainable::Draining);
     else
-        changeState(Drained);
+        setDrainState(Drainable::Drained);
     return count;
 }
 
index 74058afaa3eb3cbdad945679648d690afaf5e19a..373408c2a874c76c1a0fda46f38a791c1b14b0c2 100644 (file)
@@ -341,10 +341,10 @@ class SimpleDRAM : public AbstractMemory
      */
     std::list<DRAMPacket*> dramRespQueue;
 
-    /** If we need to drain, keep the drain event around until we're done
+    /** If we need to drain, keep the drain manager around until we're done
      * here.
      */
-    Event *drainEvent;
+    DrainManager *drainManager;
 
     /**
      * Multi-dimensional vector of banks, first dimension is ranks,
@@ -459,7 +459,7 @@ class SimpleDRAM : public AbstractMemory
 
     SimpleDRAM(const SimpleDRAMParams* p);
 
-    unsigned int drain(Event* de);
+    unsigned int drain(DrainManager* dm);
 
     virtual BaseSlavePort& getSlavePort(const std::string& if_name,
                                         PortID idx = InvalidPortID);
index c54e8e5ea734865e41bdd7714ea7c2ccd8623374..e78b5792895d9ddad61129f3f8b651a7144d95d2 100644 (file)
@@ -176,14 +176,14 @@ SimpleMemory::getSlavePort(const std::string &if_name, PortID idx)
 }
 
 unsigned int
-SimpleMemory::drain(Event *de)
+SimpleMemory::drain(DrainManager *dm)
 {
-    int count = port.drain(de);
+    int count = port.drain(dm);
 
     if (count)
-        changeState(Draining);
+        setDrainState(Drainable::Draining);
     else
-        changeState(Drained);
+        setDrainState(Drainable::Drained);
     return count;
 }
 
index 7fd64db47b2fe4d14af927d61f8741ece4d943b7..f1bad7d9f781bfc81f33a5533f6ca140d22c0a4f 100644 (file)
@@ -123,7 +123,7 @@ class SimpleMemory : public AbstractMemory
     SimpleMemory(const SimpleMemoryParams *p);
     virtual ~SimpleMemory() { }
 
-    unsigned int drain(Event* de);
+    unsigned int drain(DrainManager *dm);
 
     virtual BaseSlavePort& getSlavePort(const std::string& if_name,
                                         PortID idx = InvalidPortID);
index 7517106658e80e14e9e04711d5a2374f923e237b..d00432642f77061626db5dd48d6d9cad0e979041 100644 (file)
@@ -66,6 +66,7 @@ PySource('m5.util', 'm5/util/terminal.py')
 
 SwigSource('m5.internal', 'swig/core.i')
 SwigSource('m5.internal', 'swig/debug.i')
+SwigSource('m5.internal', 'swig/drain.i')
 SwigSource('m5.internal', 'swig/event.i')
 SwigSource('m5.internal', 'swig/pyobject.i')
 SwigSource('m5.internal', 'swig/range.i')
index c01db2a8001a4f3ae4465ac3c271bff14548986e..3aea55f5ffb4ca7f439df2eb6d736bfa0047612b 100644 (file)
@@ -123,7 +123,8 @@ class MetaSimObject(type):
                       'cxx_class' : str,
                       'cxx_type' : str,
                       'cxx_header' : str,
-                      'type' : str }
+                      'type' : str,
+                      'cxx_bases' : list }
     # Attributes that can be set any time
     keywords = { 'check' : FunctionType }
 
@@ -148,6 +149,8 @@ class MetaSimObject(type):
                 value_dict[key] = val
         if 'abstract' not in value_dict:
             value_dict['abstract'] = False
+        if 'cxx_bases' not in value_dict:
+            value_dict['cxx_bases'] = []
         cls_dict['_value_dict'] = value_dict
         cls = super(MetaSimObject, mcls).__new__(mcls, name, bases, cls_dict)
         if 'type' in value_dict:
@@ -414,6 +417,7 @@ class MetaSimObject(type):
         code('%module(package="m5.internal") param_$cls')
         code()
         code('%{')
+        code('#include "sim/sim_object.hh"')
         code('#include "params/$cls.hh"')
         for param in params:
             param.cxx_predecls(code)
@@ -458,7 +462,17 @@ using std::ptrdiff_t;
         code('%nodefault $classname;')
         code('class $classname')
         if cls._base:
-            code('    : public ${{cls._base.cxx_class}}')
+            bases = [ cls._base.cxx_class ] + cls.cxx_bases
+        else:
+            bases = cls.cxx_bases
+        base_first = True
+        for base in bases:
+            if base_first:
+                code('    : public ${{base}}')
+                base_first = False
+            else:
+                code('    , public ${{base}}')
+
         code('{')
         code('  public:')
         cls.export_methods(code)
@@ -581,30 +595,25 @@ class SimObject(object):
     abstract = True
     cxx_header = "sim/sim_object.hh"
 
+    cxx_bases = [ "Drainable" ]
+
     @classmethod
     def export_method_swig_predecls(cls, code):
         code('''
 %include <std_string.i>
+
+%import "python/swig/drain.i"
 ''')
 
     @classmethod
     def export_methods(cls, code):
         code('''
-    enum State {
-      Running,
-      Draining,
-      Drained
-    };
-
     void init();
     void loadState(Checkpoint *cp);
     void initState();
     void regStats();
     void resetStats();
     void startup();
-
-    unsigned int drain(Event *drain_event);
-    void resume();
 ''')
 
     # Initialize new instance.  For objects with SimObject-valued
index 930609b6b95abe77ac993b4419b19169d6c7d8df..dc6c5a923bd5572f59b660df9f812070c7932226 100644 (file)
@@ -51,3 +51,4 @@ if internal:
     from event import *
     from main import main
     from simulate import *
+
index ca09ab46826a7f09e4a3eca18c1a4c8b59ba0c03..30090549a1f3d6005e3430967cc63d75679e12c8 100644 (file)
@@ -31,3 +31,4 @@ import debug
 import event
 import stats
 import trace
+from drain import DrainManager, Drainable
index 89b6b1e9dea5b06c341f053e401ff5917dbc789a..df30f654ab8bda2d6f48932a4cf9911548b0d938 100644 (file)
@@ -169,19 +169,19 @@ def doDrain(root):
 # be drained.
 def drain(root):
     all_drained = False
-    drain_event = internal.event.createCountedDrain()
-    unready_objs = sum(obj.drain(drain_event) for obj in root.descendants())
+    dm = internal.drain.createDrainManager()
+    unready_objs = sum(obj.drain(dm) for obj in root.descendants())
     # If we've got some objects that can't drain immediately, then simulate
     if unready_objs > 0:
-        drain_event.setCount(unready_objs)
+        dm.setCount(unready_objs)
         simulate()
     else:
         all_drained = True
-    internal.event.cleanupCountedDrain(drain_event)
+    internal.drain.cleanupDrainManager(dm)
     return all_drained
 
 def resume(root):
-    for obj in root.descendants(): obj.resume()
+    for obj in root.descendants(): obj.drainResume()
 
 def checkpoint(dir):
     root = objects.Root.getInstance()
diff --git a/src/python/swig/drain.i b/src/python/swig/drain.i
new file mode 100644 (file)
index 0000000..4442db2
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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.
+ *
+ * Authors: Andreas Sandberg
+ */
+
+%module(package="m5.internal") drain
+
+%{
+#include "sim/drain.hh"
+%}
+
+%nodefaultctor Drainable;
+
+%include "sim/drain.hh"
+
+%inline %{
+
+DrainManager *
+createDrainManager()
+{
+    return new DrainManager();
+}
+
+void
+cleanupDrainManager(DrainManager *drain_manager)
+{
+    assert(drain_manager);
+    assert(drain_manager->getCount() == 0);
+    delete drain_manager;
+}
+
+%}
index 0af29e44935043b2b502f245fbff3a6f71b3a1a6..766dc2769ef30513a74f8bff768ccb2842e947d5 100644 (file)
 // This must follow eventq.hh
 %include "python/swig/pyevent.hh"
 
-struct CountedDrainEvent : public Event
-{
-    void setCount(int _count);
-};
-
 // minimal definition of SimExitEvent interface to wrap
 class SimLoopExitEvent : public Event
 {
index 0695ed2d36cb313623d31c48844533d92bdf51e9..4651d252b82339b48334c73854e5629999b0d631 100644 (file)
@@ -65,22 +65,3 @@ PythonEvent::process()
     // reference count must be decremented.
     Py_DECREF(object);
 }
-
-CountedDrainEvent *
-createCountedDrain()
-{
-    return new CountedDrainEvent();
-}
-
-void
-cleanupCountedDrain(Event *counted_drain)
-{
-    CountedDrainEvent *event =
-        dynamic_cast<CountedDrainEvent *>(counted_drain);
-    if (event == NULL) {
-        fatal("Called cleanupCountedDrain() on an event that was not "
-              "a CountedDrainEvent.");
-    }
-    assert(event->getCount() == 0);
-    delete event;
-}
index 9006a0404042c6e98919699fabc06585aa17b89e..f34fbd99698661c177da9cfa6e9a0faa5e97cc4f 100644 (file)
@@ -49,7 +49,4 @@ class PythonEvent : public Event
     virtual void process();
 };
 
-CountedDrainEvent *createCountedDrain();
-void cleanupCountedDrain(Event *counted_drain);
-
 #endif // __PYTHON_SWIG_PYEVENT_HH__
index 16eeb36d39acaa5320ef9d3d2211c5376643311e..42993b90f4e220737bd8161d58ada884856609b5 100644 (file)
@@ -44,6 +44,7 @@ Source('init.cc')
 Source('main.cc', main=True, skip_lib=True)
 Source('root.cc')
 Source('serialize.cc')
+Source('drain.cc')
 Source('sim_events.cc')
 Source('sim_object.cc')
 Source('simulate.cc')
diff --git a/src/sim/drain.cc b/src/sim/drain.cc
new file mode 100644 (file)
index 0000000..3daf762
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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.
+ *
+ * Authors: Andreas Sandberg
+ */
+
+#include "sim/drain.hh"
+#include "sim/sim_exit.hh"
+
+DrainManager::DrainManager()
+    : _count(0)
+{
+}
+
+DrainManager::~DrainManager()
+{
+}
+
+void
+DrainManager::drainCycleDone()
+{
+    exitSimLoop("Finished drain", 0);
+}
+
+
+
+Drainable::Drainable()
+    : _drainState(Running)
+{
+}
+
+Drainable::~Drainable()
+{
+}
+
+void
+Drainable::drainResume()
+{
+    _drainState = Running;
+}
diff --git a/src/sim/drain.hh b/src/sim/drain.hh
new file mode 100644 (file)
index 0000000..252022b
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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.
+ *
+ * Authors: Andreas Sandberg
+ */
+
+#ifndef __SIM_DRAIN_HH__
+#define __SIM_DRAIN_HH__
+
+#include <cassert>
+#include <vector>
+
+#include "base/flags.hh"
+
+class Event;
+
+/**
+ * This class coordinates draining of a System.
+ *
+ * When draining a System, we need to make sure that all SimObjects in
+ * that system have drained their state before declaring the operation
+ * to be successful. This class keeps track of how many objects are
+ * still in the process of draining their state. Once it determines
+ * that all objects have drained their state, it exits the simulation
+ * loop.
+ *
+ * @note A System might not be completely drained even though the
+ * DrainManager has caused the simulation loop to exit. Draining needs
+ * to be restarted until all Drainable objects declare that they don't
+ * need further simulation to be completely drained. See Drainable for
+ * more information.
+ */
+class DrainManager
+{
+  public:
+    DrainManager();
+    virtual ~DrainManager();
+
+    /**
+     * Get the number of objects registered with this DrainManager
+     * that are currently draining their state.
+     *
+     * @return Number of objects currently draining.
+     */
+    unsigned int getCount() const { return _count; }
+
+    void setCount(int count) { _count = count; }
+
+    /**
+     * Notify the DrainManager that a Drainable object has finished
+     * draining.
+     */
+    void signalDrainDone() {
+        assert(_count > 0);
+        if (--_count == 0)
+            drainCycleDone();
+    }
+
+  protected:
+    /**
+     * Callback when all registered Drainable objects have completed a
+     * drain cycle.
+     */
+    virtual void drainCycleDone();
+
+    /** Number of objects still draining. */
+    unsigned int _count;
+};
+
+/**
+ * Interface for objects that might require draining before
+ * checkpointing.
+ *
+ * An object's internal state needs to be drained when creating a
+ * checkpoint, switching between CPU models, or switching between
+ * timing models. Once the internal state has been drained from
+ * <i>all</i> objects in the system, the objects are serialized to
+ * disc or the configuration change takes place. The process works as
+ * follows (see simulate.py for details):
+ *
+ * <ol>
+ * <li>An instance of a DrainManager is created to keep track of how
+ *     many objects need to be drained. The object maintains an
+ *     internal counter that is decreased every time its
+ *     CountedDrainEvent::signalDrainDone() method is called. When the
+ *     counter reaches zero, the simulation is stopped.
+ *
+ * <li>Call Drainable::drain() for every object in the
+ *     system. Draining has completed if all of them return
+ *     zero. Otherwise, the sum of the return values is loaded into
+ *     the counter of the DrainManager. A pointer to the drain
+ *     manager is passed as an argument to the drain() method.
+ *
+ * <li>Continue simulation. When an object has finished draining its
+ *     internal state, it calls CountedDrainEvent::signalDrainDone()
+ *     on the manager. When the counter in the manager reaches zero,
+ *     the simulation stops.
+ *
+ * <li>Check if any object still needs draining, if so repeat the
+ *     process above.
+ *
+ * <li>Serialize objects, switch CPU model, or change timing model.
+ *
+ * <li>Call Drainable::drainResume() and continue the simulation.
+ * </ol>
+ *
+ */
+class Drainable
+{
+  public:
+    /**
+     * Object drain/handover states
+     *
+     * An object starts out in the Running state. When the simulator
+     * prepares to take a snapshot or prepares a CPU for handover, it
+     * calls the drain() method to transfer the object into the
+     * Draining or Drained state. If any object enters the Draining
+     * state (drain() returning >0), simulation continues until it all
+     * objects have entered the Drained state.
+     *
+     * Before resuming simulation, the simulator calls resume() to
+     * transfer the object to the Running state.
+     *
+     * \note Even though the state of an object (visible to the rest
+     * of the world through getState()) could be used to determine if
+     * all objects have entered the Drained state, the protocol is
+     * actually a bit more elaborate. See drain() for details.
+     */
+    enum State {
+        Running,  /** Running normally */
+        Draining, /** Draining buffers pending serialization/handover */
+        Drained   /** Buffers drained, ready for serialization/handover */
+    };
+
+    Drainable();
+    virtual ~Drainable();
+
+    /**
+     * Determine if an object needs draining and register a
+     * DrainManager.
+     *
+     * When draining the state of an object, the simulator calls drain
+     * with a pointer to a drain manager. If the object does not need
+     * further simulation to drain internal buffers, it switched to
+     * the Drained state and returns 0, otherwise it switches to the
+     * Draining state and returns the number of times that it will
+     * call Event::process() on the drain event. Most objects are
+     * expected to return either 0 or 1.
+     *
+     * @note An object that has entered the Drained state can be
+     * disturbed by other objects in the system and consequently be
+     * forced to enter the Draining state again. The simulator
+     * therefore repeats the draining process until all objects return
+     * 0 on the first call to drain().
+     *
+     * @param drainManager DrainManager to use to inform the simulator
+     * when draining has completed.
+     *
+     * @return 0 if the object is ready for serialization now, >0 if
+     * it needs further simulation.
+     */
+    virtual unsigned int drain(DrainManager *drainManager) = 0;
+
+    /**
+     * Resume execution after a successful drain.
+     *
+     * @note This method is normally only called from the simulation
+     * scripts.
+     */
+    virtual void drainResume();
+
+    State getDrainState() const { return _drainState; }
+
+  protected:
+    void setDrainState(State new_state) { _drainState = new_state; }
+
+
+  private:
+    State _drainState;
+
+};
+
+#endif
index 531b2e1cd869eafcf2fe32beffb7eaaec6a768f1..9ee34fe80b112fa63921c1fc75cd35fdba242f2b 100644 (file)
@@ -144,8 +144,14 @@ void fromSimObject(T &t, SimObject *s)
     fromSimObject(objptr, sptr);                        \
   } while (0)
 
-/*
+/**
  * Basic support for object serialization.
+ *
+ * @note Many objects that support serialization need to be put in a
+ * consistent state when serialization takes place. We refer to the
+ * action of forcing an object into a consistent state as
+ * 'draining'. Objects that need draining inherit from Drainable. See
+ * Drainable for more information.
  */
 class Serializable
 {
index a77e8b103be0b89564474fe259ce92a4ffc61e06..2354e89f71d2269e64fbe0a4f22881a384a0b7aa 100644 (file)
@@ -83,17 +83,6 @@ exitSimLoop(const std::string &message, int exit_code, Tick when, Tick repeat)
     mainEventQueue.schedule(event, when);
 }
 
-CountedDrainEvent::CountedDrainEvent()
-    : count(0)
-{ }
-
-void
-CountedDrainEvent::process()
-{
-    if (--count == 0)
-        exitSimLoop("Finished drain", 0);
-}
-
 //
 // constructor: automatically schedules at specified time
 //
index 32e936ff227319d268e2581a9b40954b29d01ed6..345fb85cb393cd1393c14ae9869e801cdcab18b7 100644 (file)
@@ -67,7 +67,6 @@ SimObject::SimObject(const Params *p)
 #endif
 
     simObjectList.push_back(this);
-    state = Running;
 }
 
 void
@@ -151,17 +150,12 @@ debugObjectBreak(const char *objs)
 #endif
 
 unsigned int
-SimObject::drain(Event *drain_event)
+SimObject::drain(DrainManager *drain_manager)
 {
-    state = Drained;
+    setDrainState(Drained);
     return 0;
 }
 
-void
-SimObject::resume()
-{
-    state = Running;
-}
 
 SimObject *
 SimObject::find(const char *name)
index c1238e23fd74528df4f34ef08c43f809f563c8c3..f04289e2f50ee3c5e9e2a8b78afef94210a8a1c9 100644 (file)
@@ -45,6 +45,7 @@
 
 #include "enums/MemoryMode.hh"
 #include "params/SimObject.hh"
+#include "sim/drain.hh"
 #include "sim/eventq.hh"
 #include "sim/serialize.hh"
 
@@ -72,40 +73,7 @@ class Event;
  *     </ul>
  * <li>SimObject::resetStats()
  * <li>SimObject::startup()
- * <li>SimObject::resume() if resuming from a checkpoint.
- * </ol>
- *
- * An object's internal state needs to be drained when creating a
- * checkpoint, switching between CPU models, or switching between
- * timing models. Once the internal state has been drained from
- * <i>all</i> objects in the system, the objects are serialized to
- * disc or the configuration change takes place. The process works as
- * follows (see simulate.py for details):
- *
- * <ol>
- * <li>An instance of a CountedDrainEvent is created to keep track of
- *     how many objects need to be drained. The object maintains an
- *     internal counter that is decreased every time its
- *     CountedDrainEvent::process() method is called. When the counter
- *     reaches zero, the simulation is stopped.
- *
- * <li>Call SimObject::drain() for every object in the
- *     system. Draining has completed if all of them return
- *     zero. Otherwise, the sum of the return values is loaded into
- *     the counter of the CountedDrainEvent. A pointer of the drain
- *     event is passed as an argument to the drain() method.
- *
- * <li>Continue simulation. When an object has finished draining its
- *     internal state, it calls CountedDrainEvent::process() on the
- *     CountedDrainEvent. When counter in the CountedDrainEvent reaches
- *     zero, the simulation stops.
- *
- * <li>Check if any object still needs draining, if so repeat the
- *     process above.
- *
- * <li>Serialize objects, switch CPU model, or change timing model.
- *
- * <li>Call SimObject::resume() and continue the simulation.
+ * <li>Drainable::drainResume() if resuming from a checkpoint.
  * </ol>
  *
  * @note Whenever a method is called on all objects in the simulator's
@@ -114,42 +82,8 @@ class Event;
  * SimObject.py). This has the effect of calling the method on the
  * parent node <i>before</i> its children.
  */
-class SimObject : public EventManager, public Serializable
+class SimObject : public EventManager, public Serializable, public Drainable
 {
-  public:
-    /**
-     * Object drain/handover states
-     *
-     * An object starts out in the Running state. When the simulator
-     * prepares to take a snapshot or prepares a CPU for handover, it
-     * calls the drain() method to transfer the object into the
-     * Draining or Drained state. If any object enters the Draining
-     * state (drain() returning >0), simulation continues until it all
-     * objects have entered the Drained.
-     *
-     * The before resuming simulation, the simulator calls resume() to
-     * transfer the object to the Running state.
-     *
-     * \note Even though the state of an object (visible to the rest
-     * of the world through getState()) could be used to determine if
-     * all objects have entered the Drained state, the protocol is
-     * actually a bit more elaborate. See drain() for details.
-     */
-    enum State {
-        Running,  /** Running normally */
-        Draining, /** Draining buffers pending serialization/handover */
-        Drained   /** Buffers drained, ready for serialization/handover */
-    };
-
-  private:
-    State state;
-
-  protected:
-    void changeState(State new_state) { state = new_state; }
-
-  public:
-    State getState() { return state; }
-
   private:
     typedef std::vector<SimObject *> SimObjectList;
 
@@ -217,43 +151,16 @@ class SimObject : public EventManager, public Serializable
     virtual void startup();
 
     /**
-     * Serialize all SimObjects in the system.
+     * Provide a default implementation of the drain interface that
+     * simply returns 0 (draining completed) and sets the drain state
+     * to Drained.
      */
-    static void serializeAll(std::ostream &os);
+    unsigned int drain(DrainManager *drainManger);
 
     /**
-     * Determine if an object needs draining and register a drain
-     * event.
-     *
-     * When draining the state of an object, the simulator calls drain
-     * with a pointer to a drain event. If the object does not need
-     * further simulation to drain internal buffers, it switched to
-     * the Drained state and returns 0, otherwise it switches to the
-     * Draining state and returns the number of times that it will
-     * call Event::process() on the drain event. Most objects are
-     * expected to return either 0 or 1.
-     *
-     * The default implementation simply switches to the Drained state
-     * and returns 0.
-     *
-     * @note An object that has entered the Drained state can be
-     * disturbed by other objects in the system and consequently be
-     * forced to enter the Draining state again. The simulator
-     * therefore repeats the draining process until all objects return
-     * 0 on the first call to drain().
-     *
-     * @param drain_event Event to use to inform the simulator when
-     * the draining has completed.
-     *
-     * @return 0 if the object is ready for serialization now, >0 if
-     * it needs further simulation.
-     */
-    virtual unsigned int drain(Event *drain_event);
-
-    /**
-     * Switch an object in the Drained stated into the Running state.
+     * Serialize all SimObjects in the system.
      */
-    virtual void resume();
+    static void serializeAll(std::ostream &os);
 
 #ifdef DEBUG
   public:
index 5ec7f4b3037db8edb172acbecce058036354a336..259ed3e884c09be7c67ad5bc9bd0edc15ce8a398 100644 (file)
@@ -181,7 +181,7 @@ System::getMasterPort(const std::string &if_name, PortID idx)
 void
 System::setMemoryMode(Enums::MemoryMode mode)
 {
-    assert(getState() == Drained);
+    assert(getDrainState() == Drainable::Drained);
     memoryMode = mode;
 }
 
@@ -328,10 +328,17 @@ System::isMemAddr(Addr addr) const
     return physmem.isMemAddr(addr);
 }
 
+unsigned int
+System::drain(DrainManager *dm)
+{
+    setDrainState(Drainable::Drained);
+    return 0;
+}
+
 void
-System::resume()
+System::drainResume()
 {
-    SimObject::resume();
+    Drainable::drainResume();
     totalNumInsts = 0;
 }
 
index 645ef8af2a7d760b9d636719a225380d8043456b..d1b79bbf4dfa5f5e2a3eb3dc80eeebd31e3fb590 100644 (file)
@@ -382,7 +382,9 @@ class System : public MemObject
 
     void serialize(std::ostream &os);
     void unserialize(Checkpoint *cp, const std::string &section);
-    virtual void resume();
+
+    unsigned int drain(DrainManager *dm);
+    void drainResume();
 
   public:
     Counter totalNumInsts;