diff options
-rw-r--r-- | src/SConscript | 1 | ||||
-rw-r--r-- | src/cpu/base.cc | 2 | ||||
-rw-r--r-- | src/cpu/base.hh | 2 | ||||
-rw-r--r-- | src/cpu/ozone/cpu.hh | 3 | ||||
-rw-r--r-- | src/cpu/ozone/cpu_impl.hh | 30 | ||||
-rw-r--r-- | src/cpu/ozone/front_end.hh | 9 | ||||
-rw-r--r-- | src/cpu/ozone/front_end_impl.hh | 26 | ||||
-rw-r--r-- | src/cpu/ozone/lw_back_end_impl.hh | 3 | ||||
-rw-r--r-- | src/cpu/ozone/lw_lsq.hh | 4 | ||||
-rw-r--r-- | src/cpu/ozone/lw_lsq_impl.hh | 6 | ||||
-rw-r--r-- | src/cpu/simple/atomic.cc | 15 | ||||
-rw-r--r-- | src/cpu/simple/atomic.hh | 2 | ||||
-rw-r--r-- | src/cpu/simple/timing.cc | 67 | ||||
-rw-r--r-- | src/cpu/simple/timing.hh | 10 | ||||
-rw-r--r-- | src/mem/port.hh | 9 | ||||
-rw-r--r-- | src/python/m5/__init__.py | 84 | ||||
-rw-r--r-- | src/python/m5/config.py | 27 | ||||
-rw-r--r-- | src/python/m5/objects/OzoneCPU.py | 3 | ||||
-rw-r--r-- | src/sim/main.cc | 42 | ||||
-rw-r--r-- | src/sim/pseudo_inst.cc | 6 | ||||
-rw-r--r-- | src/sim/serialize.cc | 117 | ||||
-rw-r--r-- | src/sim/serialize.hh | 7 | ||||
-rw-r--r-- | src/sim/sim_events.cc | 8 | ||||
-rw-r--r-- | src/sim/sim_events.hh | 21 | ||||
-rw-r--r-- | src/sim/sim_object.cc | 64 | ||||
-rw-r--r-- | src/sim/sim_object.hh | 29 |
26 files changed, 441 insertions, 156 deletions
diff --git a/src/SConscript b/src/SConscript index 124f88708..584643535 100644 --- a/src/SConscript +++ b/src/SConscript @@ -62,7 +62,6 @@ base_sources = Split(''' base/range.cc base/random.cc base/sat_counter.cc - base/serializer.cc base/socket.cc base/statistics.cc base/str.cc diff --git a/src/cpu/base.cc b/src/cpu/base.cc index 55c04c498..40cec416b 100644 --- a/src/cpu/base.cc +++ b/src/cpu/base.cc @@ -237,7 +237,7 @@ BaseCPU::registerThreadContexts() void -BaseCPU::switchOut(Sampler *sampler) +BaseCPU::switchOut() { panic("This CPU doesn't support sampling!"); } diff --git a/src/cpu/base.hh b/src/cpu/base.hh index 43122f238..51f3bb905 100644 --- a/src/cpu/base.hh +++ b/src/cpu/base.hh @@ -148,7 +148,7 @@ class BaseCPU : public SimObject /// Prepare for another CPU to take over execution. When it is /// is ready (drained pipe) it signals the sampler. - virtual void switchOut(Sampler *); + virtual void switchOut(); /// Take over execution from the given CPU. Used for warm-up and /// sampling. diff --git a/src/cpu/ozone/cpu.hh b/src/cpu/ozone/cpu.hh index cacc84786..f726ac99b 100644 --- a/src/cpu/ozone/cpu.hh +++ b/src/cpu/ozone/cpu.hh @@ -214,12 +214,11 @@ class OzoneCPU : public BaseCPU uint64_t readNextNPC() { - panic("Alpha has no NextNPC!"); return 0; } void setNextNPC(uint64_t val) - { panic("Alpha has no NextNPC!"); } + { } public: // ISA stuff: diff --git a/src/cpu/ozone/cpu_impl.hh b/src/cpu/ozone/cpu_impl.hh index 2b25ad124..2cdc8a3da 100644 --- a/src/cpu/ozone/cpu_impl.hh +++ b/src/cpu/ozone/cpu_impl.hh @@ -201,7 +201,35 @@ OzoneCPU<Impl>::OzoneCPU(Params *p) backEnd->renameTable.copyFrom(thread.renameTable); #if !FULL_SYSTEM -// pTable = p->pTable; + /* Use this port to for syscall emulation writes to memory. */ + Port *mem_port; + TranslatingPort *trans_port; + trans_port = new TranslatingPort(csprintf("%s-%d-funcport", + name(), 0), + p->workload[0]->pTable, + false); + mem_port = p->mem->getPort("functional"); + mem_port->setPeer(trans_port); + trans_port->setPeer(mem_port); + thread.setMemPort(trans_port); +#else + Port *mem_port; + FunctionalPort *phys_port; + VirtualPort *virt_port; + phys_port = new FunctionalPort(csprintf("%s-%d-funcport", + name(), 0)); + mem_port = system->physmem->getPort("functional"); + mem_port->setPeer(phys_port); + phys_port->setPeer(mem_port); + + virt_port = new VirtualPort(csprintf("%s-%d-vport", + name(), 0)); + mem_port = system->physmem->getPort("functional"); + mem_port->setPeer(virt_port); + virt_port->setPeer(mem_port); + + thread.setPhysPort(phys_port); + thread.setVirtPort(virt_port); #endif lockFlag = 0; diff --git a/src/cpu/ozone/front_end.hh b/src/cpu/ozone/front_end.hh index af310efc3..181609098 100644 --- a/src/cpu/ozone/front_end.hh +++ b/src/cpu/ozone/front_end.hh @@ -43,7 +43,7 @@ #include "sim/stats.hh" class ThreadContext; -class MemInterface; +class MemObject; template <class> class OzoneThreadState; class PageTable; @@ -75,7 +75,7 @@ class FrontEnd public: /** Default constructor. */ IcachePort(FrontEnd<Impl> *_fe) - : Port(_fe->name() + "-iport"), fe(_fe) + : fe(_fe) { } protected: @@ -105,8 +105,7 @@ class FrontEnd std::string name() const; - void setCPU(CPUType *cpu_ptr) - { cpu = cpu_ptr; } + void setCPU(CPUType *cpu_ptr); void setBackEnd(BackEnd *back_end_ptr) { backEnd = back_end_ptr; } @@ -206,6 +205,8 @@ class FrontEnd IcachePort icachePort; + MemObject *mem; + RequestPtr memReq; /** Mask to get a cache block's address. */ diff --git a/src/cpu/ozone/front_end_impl.hh b/src/cpu/ozone/front_end_impl.hh index b1bc325c7..40042489d 100644 --- a/src/cpu/ozone/front_end_impl.hh +++ b/src/cpu/ozone/front_end_impl.hh @@ -28,6 +28,8 @@ * Authors: Kevin Lim */ +#include "config/use_checker.hh" + #include "arch/faults.hh" #include "arch/isa_traits.hh" #include "base/statistics.hh" @@ -37,6 +39,10 @@ #include "mem/packet.hh" #include "mem/request.hh" +#if USE_CHECKER +#include "cpu/checker/cpu.hh" +#endif + using namespace TheISA; template<class Impl> @@ -83,6 +89,7 @@ template <class Impl> FrontEnd<Impl>::FrontEnd(Params *params) : branchPred(params), icachePort(this), + mem(params->mem), instBufferSize(0), maxInstBufferSize(params->maxInstBufferSize), width(params->frontEndWidth), @@ -125,6 +132,25 @@ FrontEnd<Impl>::name() const template <class Impl> void +FrontEnd<Impl>::setCPU(CPUType *cpu_ptr) +{ + cpu = cpu_ptr; + + icachePort.setName(this->name() + "-iport"); + + Port *mem_dport = mem->getPort(""); + icachePort.setPeer(mem_dport); + mem_dport->setPeer(&icachePort); + +#if USE_CHECKER + if (cpu->checker) { + cpu->checker->setIcachePort(&icachePort); + } +#endif +} + +template <class Impl> +void FrontEnd<Impl>::setCommBuffer(TimeBuffer<CommStruct> *_comm) { comm = _comm; diff --git a/src/cpu/ozone/lw_back_end_impl.hh b/src/cpu/ozone/lw_back_end_impl.hh index dcd7a0d7e..a73d3ee6e 100644 --- a/src/cpu/ozone/lw_back_end_impl.hh +++ b/src/cpu/ozone/lw_back_end_impl.hh @@ -142,7 +142,7 @@ LWBackEnd<Impl>::replayMemInst(DynInstPtr &inst) template <class Impl> LWBackEnd<Impl>::LWBackEnd(Params *params) : d2i(5, 5), i2e(5, 5), e2c(5, 5), numInstsToWB(5, 5), - trapSquash(false), tcSquash(false), + trapSquash(false), tcSquash(false), LSQ(params), width(params->backEndWidth), exactFullStall(true) { numROBEntries = params->numROBEntries; @@ -169,6 +169,7 @@ LWBackEnd<Impl>::LWBackEnd(Params *params) LSQ.init(params, params->LQEntries, params->SQEntries, 0); dispatchStatus = Running; + commitStatus = Running; } template <class Impl> diff --git a/src/cpu/ozone/lw_lsq.hh b/src/cpu/ozone/lw_lsq.hh index e0c190134..c749e3aee 100644 --- a/src/cpu/ozone/lw_lsq.hh +++ b/src/cpu/ozone/lw_lsq.hh @@ -654,6 +654,10 @@ OzoneLWLSQ<Impl>::read(RequestPtr req, T &data, int load_idx) return NoFault; } + if (req->getFlags() & LOCKED) { + cpu->lockFlag = true; + } + if (data_pkt->result != Packet::Success) { DPRINTF(OzoneLSQ, "OzoneLSQ: D-cache miss!\n"); DPRINTF(Activity, "Activity: ld accessing mem miss [sn:%lli]\n", diff --git a/src/cpu/ozone/lw_lsq_impl.hh b/src/cpu/ozone/lw_lsq_impl.hh index effb21728..a65a2a4d3 100644 --- a/src/cpu/ozone/lw_lsq_impl.hh +++ b/src/cpu/ozone/lw_lsq_impl.hh @@ -131,8 +131,8 @@ OzoneLWLSQ<Impl>::completeDataAccess(PacketPtr pkt) template <class Impl> OzoneLWLSQ<Impl>::OzoneLWLSQ() - : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false), - loadBlockedHandled(false) + : switchedOut(false), loads(0), stores(0), storesToWB(0), stalled(false), + isStoreBlocked(false), isLoadBlocked(false), loadBlockedHandled(false) { } @@ -153,6 +153,8 @@ OzoneLWLSQ<Impl>::init(Params *params, unsigned maxLQEntries, SQIndices.push(i); } + mem = params->mem; + usedPorts = 0; cachePorts = params->cachePorts; diff --git a/src/cpu/simple/atomic.cc b/src/cpu/simple/atomic.cc index ce28ba9c8..be6f421b3 100644 --- a/src/cpu/simple/atomic.cc +++ b/src/cpu/simple/atomic.cc @@ -145,8 +145,8 @@ AtomicSimpleCPU::~AtomicSimpleCPU() void AtomicSimpleCPU::serialize(ostream &os) { - BaseSimpleCPU::serialize(os); SERIALIZE_ENUM(_status); + BaseSimpleCPU::serialize(os); nameOut(os, csprintf("%s.tickEvent", name())); tickEvent.serialize(os); } @@ -154,21 +154,18 @@ AtomicSimpleCPU::serialize(ostream &os) void AtomicSimpleCPU::unserialize(Checkpoint *cp, const string §ion) { - BaseSimpleCPU::unserialize(cp, section); UNSERIALIZE_ENUM(_status); + BaseSimpleCPU::unserialize(cp, section); tickEvent.unserialize(cp, csprintf("%s.tickEvent", section)); } void -AtomicSimpleCPU::switchOut(Sampler *s) +AtomicSimpleCPU::switchOut() { - sampler = s; - if (status() == Running) { - _status = SwitchedOut; + assert(status() == Running || status() == Idle); + _status = SwitchedOut; - tickEvent.squash(); - } - sampler->signalSwitched(); + tickEvent.squash(); } diff --git a/src/cpu/simple/atomic.hh b/src/cpu/simple/atomic.hh index 7f4956da9..951a8da06 100644 --- a/src/cpu/simple/atomic.hh +++ b/src/cpu/simple/atomic.hh @@ -125,7 +125,7 @@ class AtomicSimpleCPU : public BaseSimpleCPU virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); - void switchOut(Sampler *s); + void switchOut(); void takeOverFrom(BaseCPU *oldCPU); virtual void activateContext(int thread_num, int delay); diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc index c99db8fbf..0729f9489 100644 --- a/src/cpu/simple/timing.cc +++ b/src/cpu/simple/timing.cc @@ -88,6 +88,8 @@ TimingSimpleCPU::TimingSimpleCPU(Params *p) { _status = Idle; ifetch_pkt = dcache_pkt = NULL; + quiesceEvent = NULL; + state = SimObject::Timing; } @@ -98,25 +100,54 @@ TimingSimpleCPU::~TimingSimpleCPU() void TimingSimpleCPU::serialize(ostream &os) { - BaseSimpleCPU::serialize(os); SERIALIZE_ENUM(_status); + BaseSimpleCPU::serialize(os); } void TimingSimpleCPU::unserialize(Checkpoint *cp, const string §ion) { - BaseSimpleCPU::unserialize(cp, section); UNSERIALIZE_ENUM(_status); + BaseSimpleCPU::unserialize(cp, section); +} + +bool +TimingSimpleCPU::quiesce(Event *quiesce_event) +{ + // TimingSimpleCPU is ready to quiesce if it's not waiting for + // an access to complete. + if (status() == Idle || status() == Running || status() == SwitchedOut) { + DPRINTF(Config, "Ready to quiesce\n"); + return false; + } else { + DPRINTF(Config, "Waiting to quiesce\n"); + changeState(SimObject::Quiescing); + quiesceEvent = quiesce_event; + return true; + } } void -TimingSimpleCPU::switchOut(Sampler *s) +TimingSimpleCPU::resume() { - sampler = s; - if (status() == Running) { - _status = SwitchedOut; + if (_status != SwitchedOut && _status != Idle) { + Event *e = + new EventWrapper<TimingSimpleCPU, &TimingSimpleCPU::fetch>(this, true); + e->schedule(curTick); } - sampler->signalSwitched(); +} + +void +TimingSimpleCPU::setMemoryMode(State new_mode) +{ + assert(new_mode == SimObject::Timing); +} + +void +TimingSimpleCPU::switchOut() +{ + assert(status() == Running || status() == Idle); + _status = SwitchedOut; } @@ -383,11 +414,17 @@ TimingSimpleCPU::completeIfetch(Packet *pkt) // instruction assert(pkt->result == Packet::Success); assert(_status == IcacheWaitResponse); + _status = Running; delete pkt->req; delete pkt; + if (getState() == SimObject::Quiescing) { + completeQuiesce(); + return; + } + preExecute(); if (curStaticInst->isMemRef() && !curStaticInst->isDataPrefetch()) { // load or store: just send to dcache @@ -440,6 +477,15 @@ TimingSimpleCPU::completeDataAccess(Packet *pkt) assert(_status == DcacheWaitResponse); _status = Running; + if (getState() == SimObject::Quiescing) { + completeQuiesce(); + + delete pkt->req; + delete pkt; + + return; + } + Fault fault = curStaticInst->completeAcc(pkt, this, traceData); delete pkt->req; @@ -450,6 +496,13 @@ TimingSimpleCPU::completeDataAccess(Packet *pkt) } +void +TimingSimpleCPU::completeQuiesce() +{ + DPRINTF(Config, "Done quiescing\n"); + changeState(SimObject::QuiescedTiming); + quiesceEvent->process(); +} bool TimingSimpleCPU::DcachePort::recvTiming(Packet *pkt) diff --git a/src/cpu/simple/timing.hh b/src/cpu/simple/timing.hh index ab0b2d2ca..d91144e4a 100644 --- a/src/cpu/simple/timing.hh +++ b/src/cpu/simple/timing.hh @@ -64,6 +64,8 @@ class TimingSimpleCPU : public BaseSimpleCPU Status status() const { return _status; } + Event *quiesceEvent; + private: class CpuPort : public Port @@ -131,7 +133,11 @@ class TimingSimpleCPU : public BaseSimpleCPU virtual void serialize(std::ostream &os); virtual void unserialize(Checkpoint *cp, const std::string §ion); - void switchOut(Sampler *s); + virtual bool quiesce(Event *quiesce_event); + virtual void resume(); + virtual void setMemoryMode(State new_mode); + + void switchOut(); void takeOverFrom(BaseCPU *oldCPU); virtual void activateContext(int thread_num, int delay); @@ -147,6 +153,8 @@ class TimingSimpleCPU : public BaseSimpleCPU void completeIfetch(Packet *); void completeDataAccess(Packet *); void advanceInst(Fault fault); + private: + void completeQuiesce(); }; #endif // __CPU_SIMPLE_TIMING_HH__ diff --git a/src/mem/port.hh b/src/mem/port.hh index 2edad095e..17b1f4a00 100644 --- a/src/mem/port.hh +++ b/src/mem/port.hh @@ -74,7 +74,7 @@ class Port private: /** Descriptive name (for DPRINTF output) */ - const std::string portName; + mutable std::string portName; /** A pointer to the peer port. Ports always come in pairs, that way they can use a standardized interface to communicate between different @@ -83,6 +83,10 @@ class Port public: + Port() + : peer(NULL) + { } + /** * Constructor. * @@ -105,6 +109,9 @@ class Port RangeChange }; + void setName(const std::string &name) + { portName = name; } + /** Function to set the pointer for the peer port. @todo should be called by the configuration stuff (python). */ diff --git a/src/python/m5/__init__.py b/src/python/m5/__init__.py index a7e653fc2..828165d15 100644 --- a/src/python/m5/__init__.py +++ b/src/python/m5/__init__.py @@ -34,7 +34,7 @@ import cc_main # import a few SWIG-wrapped items (those that are likely to be used # directly by user scripts) completely into this module for # convenience -from cc_main import simulate, SimLoopExitEvent +from cc_main import simulate, SimLoopExitEvent, setCheckpointDir # import the m5 compile options import defines @@ -117,10 +117,6 @@ def debugBreak(option, opt_str, value, parser): def statsTextFile(option, opt_str, value, parser): objects.Statistics.text_file = value -# Extra list to help for options that are true or false -TrueOrFalse = ['True', 'False'] -TorF = "True | False" - # Standard optparse options. Need to be explicitly included by the # user script when it calls optparse.OptionParser(). standardOptions = [ @@ -216,3 +212,81 @@ atexit.register(cc_main.doExitCleanup) # just doing an 'import m5' (without an 'import m5.objects'). May not # matter since most scripts will probably 'from m5.objects import *'. import objects + +def doQuiesce(root): + quiesce = cc_main.createCountedQuiesce() + unready_objects = root.startQuiesce(quiesce, True) + # If we've got some objects that can't quiesce immediately, then simulate + if unready_objects > 0: + quiesce.setCount(unready_objects) + simulate() + cc_main.cleanupCountedQuiesce(quiesce) + +def resume(root): + root.resume() + +def checkpoint(root): + if not isinstance(root, objects.Root): + raise TypeError, "Object is not a root object. Checkpoint must be called on a root object." + doQuiesce(root) + print "Writing checkpoint" + cc_main.serializeAll() + resume(root) + +def restoreCheckpoint(root): + print "Restoring from checkpoint" + cc_main.unserializeAll() + +def changeToAtomic(system): + if not isinstance(system, objects.Root) and not isinstance(system, System): + raise TypeError, "Object is not a root or system object. Checkpoint must be " + "called on a root object." + doQuiesce(system) + print "Changing memory mode to atomic" + system.changeTiming(cc_main.SimObject.Atomic) + resume(system) + +def changeToTiming(system): + if not isinstance(system, objects.Root) and not isinstance(system, System): + raise TypeError, "Object is not a root or system object. Checkpoint must be " + "called on a root object." + doQuiesce(system) + print "Changing memory mode to timing" + system.changeTiming(cc_main.SimObject.Timing) + resume(system) + +def switchCpus(cpuList): + if not isinstance(cpuList, list): + raise RuntimeError, "Must pass a list to this function" + for i in cpuList: + if not isinstance(i, tuple): + raise RuntimeError, "List must have tuples of (oldCPU,newCPU)" + + [old_cpus, new_cpus] = zip(*cpuList) + + for cpu in old_cpus: + if not isinstance(cpu, objects.BaseCPU): + raise TypeError, "%s is not of type BaseCPU", cpu + for cpu in new_cpus: + if not isinstance(cpu, objects.BaseCPU): + raise TypeError, "%s is not of type BaseCPU", cpu + + # Quiesce all of the individual CPUs + quiesce = cc_main.createCountedQuiesce() + unready_cpus = 0 + for old_cpu in old_cpus: + unready_cpus += old_cpu.startQuiesce(quiesce, False) + # If we've got some objects that can't quiesce immediately, then simulate + if unready_cpus > 0: + quiesce.setCount(unready_cpus) + simulate() + cc_main.cleanupCountedQuiesce(quiesce) + # Now all of the CPUs are ready to be switched out + for old_cpu in old_cpus: + old_cpu._ccObject.switchOut() + index = 0 + print "Switching CPUs" + for new_cpu in new_cpus: + new_cpu.takeOverFrom(old_cpus[index]) + new_cpu._ccObject.resume() + index += 1 diff --git a/src/python/m5/config.py b/src/python/m5/config.py index c29477465..adabe0743 100644 --- a/src/python/m5/config.py +++ b/src/python/m5/config.py @@ -543,6 +543,33 @@ class SimObject(object): for child in self._children.itervalues(): child.connectPorts() + def startQuiesce(self, quiesce_event, recursive): + count = 0 + # ParamContexts don't serialize + if isinstance(self, SimObject) and not isinstance(self, ParamContext): + if self._ccObject.quiesce(quiesce_event): + count = 1 + if recursive: + for child in self._children.itervalues(): + count += child.startQuiesce(quiesce_event, True) + return count + + def resume(self): + if isinstance(self, SimObject) and not isinstance(self, ParamContext): + self._ccObject.resume() + for child in self._children.itervalues(): + child.resume() + + def changeTiming(self, mode): + if isinstance(self, SimObject) and not isinstance(self, ParamContext): + self._ccObject.setMemoryMode(mode) + for child in self._children.itervalues(): + child.changeTiming(mode) + + def takeOverFrom(self, old_cpu): + cpu_ptr = cc_main.convertToBaseCPUPtr(old_cpu._ccObject) + self._ccObject.takeOverFrom(cpu_ptr) + # generate output file for 'dot' to display as a pretty graph. # this code is currently broken. def outputDot(self, dot): diff --git a/src/python/m5/objects/OzoneCPU.py b/src/python/m5/objects/OzoneCPU.py index f2d9aea84..8aff89203 100644 --- a/src/python/m5/objects/OzoneCPU.py +++ b/src/python/m5/objects/OzoneCPU.py @@ -7,9 +7,6 @@ class DerivOzoneCPU(BaseCPU): numThreads = Param.Unsigned("number of HW thread contexts") - if not build_env['FULL_SYSTEM']: - mem = Param.FunctionalMemory(NULL, "memory") - checker = Param.BaseCPU("Checker CPU") width = Param.Unsigned("Width") diff --git a/src/sim/main.cc b/src/sim/main.cc index bf844da7f..3eb7fa95d 100644 --- a/src/sim/main.cc +++ b/src/sim/main.cc @@ -62,6 +62,7 @@ #include "sim/async.hh" #include "sim/builder.hh" #include "sim/host.hh" +#include "sim/serialize.hh" #include "sim/sim_events.hh" #include "sim/sim_exit.hh" #include "sim/sim_object.hh" @@ -521,6 +522,37 @@ simulate(Tick num_cycles = -1) // not reached... only exit is return on SimLoopExitEvent } +Event * +createCountedQuiesce() +{ + return new CountedQuiesceEvent(); +} + +void +cleanupCountedQuiesce(Event *counted_quiesce) +{ + CountedQuiesceEvent *event = + dynamic_cast<CountedQuiesceEvent *>(counted_quiesce); + if (event == NULL) { + fatal("Called cleanupCountedQuiesce() on an event that was not " + "a CountedQuiesceEvent."); + } + assert(event->getCount() == 0); + delete event; +} + +void +serializeAll() +{ + Serializable::serializeAll(); +} + +void +unserializeAll() +{ + Serializable::unserializeAll(); +} + /** * Queue of C++ callbacks to invoke on simulator exit. */ @@ -535,6 +567,16 @@ registerExitCallback(Callback *callback) exitCallbacks.add(callback); } +BaseCPU * +convertToBaseCPUPtr(SimObject *obj) +{ + BaseCPU *ptr = dynamic_cast<BaseCPU *>(obj); + + if (ptr == NULL) + warn("Casting to BaseCPU pointer failed"); + return ptr; +} + /** * Do C++ simulator exit processing. Exported to SWIG to be invoked * when simulator terminates via Python's atexit mechanism. diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc index ae52cdd41..b2854e491 100644 --- a/src/sim/pseudo_inst.cc +++ b/src/sim/pseudo_inst.cc @@ -209,12 +209,6 @@ namespace AlphaPseudo { if (!doCheckpointInsts) return; - - - Tick when = curTick + delay * Clock::Int::ns; - Tick repeat = period * Clock::Int::ns; - - Checkpoint::setup(when, repeat); } uint64_t diff --git a/src/sim/serialize.cc b/src/sim/serialize.cc index 0e3139116..7450d7b7e 100644 --- a/src/sim/serialize.cc +++ b/src/sim/serialize.cc @@ -244,56 +244,41 @@ Serializable::serializeAll() globals.serialize(outstream); SimObject::serializeAll(outstream); - - assert(Serializable::ckptPrevCount + 1 == Serializable::ckptCount); - Serializable::ckptPrevCount++; - if (ckptMaxCount && ++ckptCount >= ckptMaxCount) - exitSimLoop(curTick + 1, "Maximum number of checkpoints dropped"); - } - void -Serializable::unserializeGlobals(Checkpoint *cp) -{ - globals.unserialize(cp); -} - - -class SerializeEvent : public Event +Serializable::unserializeAll() { - protected: - Tick repeat; - - public: - SerializeEvent(Tick _when, Tick _repeat); - virtual void process(); - virtual void serialize(std::ostream &os) - { - panic("Cannot serialize the SerializeEvent"); - } + string dir = Checkpoint::dir(); + string cpt_file = dir + Checkpoint::baseFilename; + string section = ""; -}; + DPRINTFR(Config, "Loading checkpoint dir '%s'\n", + dir); + Checkpoint *cp = new Checkpoint(dir, section); + unserializeGlobals(cp); -SerializeEvent::SerializeEvent(Tick _when, Tick _repeat) - : Event(&mainEventQueue, Serialize_Pri), repeat(_repeat) -{ - setFlags(AutoDelete); - schedule(_when); + SimObject::unserializeAll(cp); } void -SerializeEvent::process() +Serializable::unserializeGlobals(Checkpoint *cp) { - Serializable::serializeAll(); - if (repeat) - schedule(curTick + repeat); + globals.unserialize(cp); } const char *Checkpoint::baseFilename = "m5.cpt"; static string checkpointDirBase; +void +setCheckpointDir(const std::string &name) +{ + checkpointDirBase = name; + if (checkpointDirBase[checkpointDirBase.size() - 1] != '/') + checkpointDirBase += "/"; +} + string Checkpoint::dir() { @@ -304,75 +289,11 @@ Checkpoint::dir() } void -Checkpoint::setup(Tick when, Tick period) -{ - new SerializeEvent(when, period); -} - -class SerializeParamContext : public ParamContext -{ - private: - SerializeEvent *event; - - public: - SerializeParamContext(const string §ion); - ~SerializeParamContext(); - void checkParams(); -}; - -SerializeParamContext serialParams("serialize"); - -Param<string> serialize_dir(&serialParams, "dir", - "dir to stick checkpoint in " - "(sprintf format with cycle #)"); - -Param<Counter> serialize_cycle(&serialParams, - "cycle", - "cycle to serialize", - 0); - -Param<Counter> serialize_period(&serialParams, - "period", - "period to repeat serializations", - 0); - -Param<int> serialize_count(&serialParams, "count", - "maximum number of checkpoints to drop"); - -SerializeParamContext::SerializeParamContext(const string §ion) - : ParamContext(section), event(NULL) -{ } - -SerializeParamContext::~SerializeParamContext() -{ -} - -void -SerializeParamContext::checkParams() -{ - checkpointDirBase = simout.resolve(serialize_dir); - - // guarantee that directory ends with a '/' - if (checkpointDirBase[checkpointDirBase.size() - 1] != '/') - checkpointDirBase += "/"; - - if (serialize_cycle > 0) - Checkpoint::setup(serialize_cycle, serialize_period); - - Serializable::ckptMaxCount = serialize_count; -} - -void debug_serialize() { Serializable::serializeAll(); } -void -debug_serialize(Tick when) -{ - new SerializeEvent(when, 0); -} //////////////////////////////////////////////////////////////////////// // diff --git a/src/sim/serialize.hh b/src/sim/serialize.hh index 64ed6142f..a80dc99e4 100644 --- a/src/sim/serialize.hh +++ b/src/sim/serialize.hh @@ -127,6 +127,7 @@ class Serializable static int ckptMaxCount; static int ckptPrevCount; static void serializeAll(); + static void unserializeAll(); static void unserializeGlobals(Checkpoint *cp); }; @@ -204,6 +205,9 @@ class SerializableClass SerializableClass the##OBJ_CLASS##Class(CLASS_NAME, \ OBJ_CLASS::createForUnserialize); +void +setCheckpointName(const std::string &name); + class Checkpoint { private: @@ -237,9 +241,6 @@ class Checkpoint // Filename for base checkpoint file within directory. static const char *baseFilename; - - // Set up a checkpoint creation event or series of events. - static void setup(Tick when, Tick period = 0); }; #endif // __SERIALIZE_HH__ diff --git a/src/sim/sim_events.cc b/src/sim/sim_events.cc index b7901832d..97f7ae03c 100644 --- a/src/sim/sim_events.cc +++ b/src/sim/sim_events.cc @@ -78,6 +78,14 @@ exitSimLoop(const std::string &message, int exit_code) exitSimLoop(curTick, message, exit_code); } +void +CountedQuiesceEvent::process() +{ + if (--count == 0) { + exitSimLoop("Finished quiesce"); + } +} + // // constructor: automatically schedules at specified time // diff --git a/src/sim/sim_events.hh b/src/sim/sim_events.hh index 4f305ad38..50368f258 100644 --- a/src/sim/sim_events.hh +++ b/src/sim/sim_events.hh @@ -44,6 +44,11 @@ class SimLoopExitEvent : public Event int code; public: + // Default constructor. Only really used for derived classes. + SimLoopExitEvent() + : Event(&mainEventQueue, Sim_Exit_Pri) + { } + SimLoopExitEvent(Tick _when, const std::string &_cause, int c = 0) : Event(&mainEventQueue, Sim_Exit_Pri), cause(_cause), code(c) @@ -62,6 +67,22 @@ class SimLoopExitEvent : public Event virtual const char *description(); }; +class CountedQuiesceEvent : public SimLoopExitEvent +{ + private: + // Count down to quiescing + int count; + public: + CountedQuiesceEvent() + : count(0) + { } + void process(); + + void setCount(int _count) { count = _count; } + + int getCount() { return count; } +}; + // // Event class to terminate simulation after 'n' related events have // occurred using a shared counter: used to terminate when *all* diff --git a/src/sim/sim_object.cc b/src/sim/sim_object.cc index a35c7a88d..551555b25 100644 --- a/src/sim/sim_object.cc +++ b/src/sim/sim_object.cc @@ -73,6 +73,7 @@ SimObject::SimObject(Params *p) doRecordEvent = !Stats::event_ignore.match(name()); simObjectList.push_back(this); + state = Atomic; } // @@ -88,6 +89,7 @@ SimObject::SimObject(const string &_name) doRecordEvent = !Stats::event_ignore.match(name()); simObjectList.push_back(this); + state = Atomic; } void @@ -219,6 +221,24 @@ SimObject::serializeAll(ostream &os) } } +void +SimObject::unserializeAll(Checkpoint *cp) +{ + SimObjectList::reverse_iterator ri = simObjectList.rbegin(); + SimObjectList::reverse_iterator rend = simObjectList.rend(); + + for (; ri != rend; ++ri) { + SimObject *obj = *ri; + DPRINTFR(Config, "Unserializing '%s'\n", + obj->name()); + if(cp->sectionExists(obj->name())) + obj->unserialize(cp, obj->name()); + else + warn("Not unserializing '%s': no section found in checkpoint.\n", + obj->name()); + } +} + #ifdef DEBUG // // static function: flag which objects should have the debugger break @@ -250,10 +270,50 @@ SimObject::recordEvent(const std::string &stat) Stats::recordEvent(stat); } +bool +SimObject::quiesce(Event *quiesce_event) +{ + if (state != QuiescedAtomic && state != Atomic) { + panic("Must implement your own quiesce function if it is to be used " + "in timing mode!"); + } + state = QuiescedAtomic; + return false; +} + +void +SimObject::resume() +{ + if (state == QuiescedAtomic) { + state = Atomic; + } else if (state == QuiescedTiming) { + state = Timing; + } +} + +void +SimObject::setMemoryMode(State new_mode) +{ + assert(new_mode == Timing || new_mode == Atomic); + if (state == QuiescedAtomic && new_mode == Timing) { + state = QuiescedTiming; + } else if (state == QuiescedTiming && new_mode == Atomic) { + state = QuiescedAtomic; + } else { + state = new_mode; + } +} + +void +SimObject::switchOut() +{ + panic("Unimplemented!"); +} + void -SimObject::drain(Serializer *serializer) +SimObject::takeOverFrom(BaseCPU *cpu) { - serializer->signalDrained(); + panic("Unimplemented!"); } DEFINE_SIM_OBJECT_CLASS_NAME("SimObject", SimObject) diff --git a/src/sim/sim_object.hh b/src/sim/sim_object.hh index 84e9376a0..e0b21782f 100644 --- a/src/sim/sim_object.hh +++ b/src/sim/sim_object.hh @@ -44,7 +44,8 @@ #include "sim/serialize.hh" #include "sim/startup.hh" -class Serializer; +class BaseCPU; +class Event; /* * Abstract superclass for simulation objects. Represents things that @@ -58,15 +59,26 @@ class SimObject : public Serializable, protected StartupCallback std::string name; }; + enum State { + Atomic, + Timing, + Quiescing, + QuiescedAtomic, + QuiescedTiming + }; + protected: Params *_params; + State state; + + void changeState(State new_state) { state = new_state; } public: const Params *params() const { return _params; } - private: - friend class Serializer; + State getState() { return state; } + private: typedef std::vector<SimObject *> SimObjectList; // list of all instantiated simulation objects @@ -100,13 +112,16 @@ class SimObject : public Serializable, protected StartupCallback // static: call nameOut() & serialize() on all SimObjects static void serializeAll(std::ostream &); + static void unserializeAll(Checkpoint *cp); // Methods to drain objects in order to take checkpoints // Or switch from timing -> atomic memory model - virtual void drain(Serializer *serializer); - virtual void resume() { return;} ; - virtual void serializationComplete() - { assert(0 && "Unimplemented"); }; + // Quiesce returns true if the SimObject cannot quiesce immediately. + virtual bool quiesce(Event *quiesce_event); + virtual void resume(); + virtual void setMemoryMode(State new_mode); + virtual void switchOut(); + virtual void takeOverFrom(BaseCPU *cpu); #ifdef DEBUG public: |