summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/SConscript1
-rw-r--r--src/cpu/base.cc2
-rw-r--r--src/cpu/base.hh2
-rw-r--r--src/cpu/ozone/cpu.hh3
-rw-r--r--src/cpu/ozone/cpu_impl.hh30
-rw-r--r--src/cpu/ozone/front_end.hh9
-rw-r--r--src/cpu/ozone/front_end_impl.hh26
-rw-r--r--src/cpu/ozone/lw_back_end_impl.hh3
-rw-r--r--src/cpu/ozone/lw_lsq.hh4
-rw-r--r--src/cpu/ozone/lw_lsq_impl.hh6
-rw-r--r--src/cpu/simple/atomic.cc15
-rw-r--r--src/cpu/simple/atomic.hh2
-rw-r--r--src/cpu/simple/timing.cc67
-rw-r--r--src/cpu/simple/timing.hh10
-rw-r--r--src/mem/port.hh9
-rw-r--r--src/python/m5/__init__.py84
-rw-r--r--src/python/m5/config.py27
-rw-r--r--src/python/m5/objects/OzoneCPU.py3
-rw-r--r--src/sim/main.cc42
-rw-r--r--src/sim/pseudo_inst.cc6
-rw-r--r--src/sim/serialize.cc117
-rw-r--r--src/sim/serialize.hh7
-rw-r--r--src/sim/sim_events.cc8
-rw-r--r--src/sim/sim_events.hh21
-rw-r--r--src/sim/sim_object.cc64
-rw-r--r--src/sim/sim_object.hh29
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 &section)
{
- 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 &section);
- 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 &section)
{
- 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 &section);
- 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 &section);
- ~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 &section)
- : 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: