summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arch/alpha/regfile.hh4
-rw-r--r--src/cpu/o3/commit.hh2
-rw-r--r--src/cpu/o3/commit_impl.hh11
-rw-r--r--src/cpu/o3/cpu.cc74
-rw-r--r--src/cpu/o3/cpu.hh8
-rw-r--r--src/cpu/o3/decode.hh2
-rw-r--r--src/cpu/o3/decode_impl.hh3
-rw-r--r--src/cpu/o3/fetch.hh2
-rw-r--r--src/cpu/o3/fetch_impl.hh3
-rw-r--r--src/cpu/o3/iew.hh2
-rw-r--r--src/cpu/o3/iew_impl.hh3
-rw-r--r--src/cpu/o3/lsq_impl.hh3
-rw-r--r--src/cpu/o3/regfile.hh4
-rw-r--r--src/cpu/o3/rename.hh2
-rw-r--r--src/cpu/o3/rename_impl.hh3
-rw-r--r--src/cpu/simple/timing.cc4
-rw-r--r--src/cpu/simple_thread.cc78
-rw-r--r--src/cpu/simple_thread.hh10
-rw-r--r--src/cpu/thread_state.cc43
-rw-r--r--src/cpu/thread_state.hh6
-rw-r--r--src/dev/tsunami_pchip.hh2
-rw-r--r--src/python/m5/__init__.py15
-rw-r--r--src/sim/pseudo_inst.cc1
23 files changed, 218 insertions, 67 deletions
diff --git a/src/arch/alpha/regfile.hh b/src/arch/alpha/regfile.hh
index 1025412cd..9ecad6f42 100644
--- a/src/arch/alpha/regfile.hh
+++ b/src/arch/alpha/regfile.hh
@@ -112,6 +112,10 @@ namespace AlphaISA
lock_flag = 0;
lock_addr = 0;
}
+
+ void serialize(std::ostream &os);
+
+ void unserialize(Checkpoint *cp, const std::string &section);
#if FULL_SYSTEM
protected:
typedef uint64_t InternalProcReg;
diff --git a/src/cpu/o3/commit.hh b/src/cpu/o3/commit.hh
index 49ff5cdad..c39bc10f9 100644
--- a/src/cpu/o3/commit.hh
+++ b/src/cpu/o3/commit.hh
@@ -188,7 +188,7 @@ class DefaultCommit
void initStage();
/** Initializes the draining of commit. */
- void drain();
+ bool drain();
/** Resumes execution after draining. */
void resume();
diff --git a/src/cpu/o3/commit_impl.hh b/src/cpu/o3/commit_impl.hh
index 2eb05afac..39e1cf3fe 100644
--- a/src/cpu/o3/commit_impl.hh
+++ b/src/cpu/o3/commit_impl.hh
@@ -350,10 +350,18 @@ DefaultCommit<Impl>::initStage()
}
template <class Impl>
-void
+bool
DefaultCommit<Impl>::drain()
{
drainPending = true;
+
+ // If it's already drained, return true.
+ if (rob->isEmpty() && !iewStage->hasStoresToWB()) {
+ cpu->signalDrained();
+ return true;
+ }
+
+ return false;
}
template <class Impl>
@@ -369,6 +377,7 @@ template <class Impl>
void
DefaultCommit<Impl>::resume()
{
+ drainPending = false;
}
template <class Impl>
diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc
index b182d5ca7..f345fe82d 100644
--- a/src/cpu/o3/cpu.cc
+++ b/src/cpu/o3/cpu.cc
@@ -708,11 +708,51 @@ FullO3CPU<Impl>::haltContext(int tid)
}
template <class Impl>
+void
+FullO3CPU<Impl>::serialize(std::ostream &os)
+{
+ SERIALIZE_ENUM(_status);
+ BaseCPU::serialize(os);
+ nameOut(os, csprintf("%s.tickEvent", name()));
+ tickEvent.serialize(os);
+
+ // Use SimpleThread's ability to checkpoint to make it easier to
+ // write out the registers. Also make this static so it doesn't
+ // get instantiated multiple times (causes a panic in statistics).
+ static SimpleThread temp;
+
+ for (int i = 0; i < thread.size(); i++) {
+ nameOut(os, csprintf("%s.xc.%i", name(), i));
+ temp.copyTC(thread[i]->getTC());
+ temp.serialize(os);
+ }
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::unserialize(Checkpoint *cp, const std::string &section)
+{
+ UNSERIALIZE_ENUM(_status);
+ BaseCPU::unserialize(cp, section);
+ tickEvent.unserialize(cp, csprintf("%s.tickEvent", section));
+
+ // Use SimpleThread's ability to checkpoint to make it easier to
+ // read in the registers. Also make this static so it doesn't
+ // get instantiated multiple times (causes a panic in statistics).
+ static SimpleThread temp;
+
+ for (int i = 0; i < thread.size(); i++) {
+ temp.copyTC(thread[i]->getTC());
+ temp.unserialize(cp, csprintf("%s.xc.%i", section, i));
+ thread[i]->getTC()->copyArchRegs(temp.getTC());
+ }
+}
+
+template <class Impl>
bool
FullO3CPU<Impl>::drain(Event *drain_event)
{
drainCount = 0;
- drainEvent = drain_event;
fetch.drain();
decode.drain();
rename.drain();
@@ -720,25 +760,36 @@ FullO3CPU<Impl>::drain(Event *drain_event)
commit.drain();
// Wake the CPU and record activity so everything can drain out if
- // the CPU is currently idle.
- wakeCPU();
- activityRec.activity();
+ // the CPU was not able to immediately drain.
+ if (getState() != SimObject::DrainedTiming) {
+ // A bit of a hack...set the drainEvent 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;
+
+ wakeCPU();
+ activityRec.activity();
- return false;
+ return false;
+ } else {
+ return true;
+ }
}
template <class Impl>
void
FullO3CPU<Impl>::resume()
{
- if (_status == SwitchedOut)
- return;
fetch.resume();
decode.resume();
rename.resume();
iew.resume();
commit.resume();
+ if (_status == SwitchedOut || _status == Idle)
+ return;
+
if (!tickEvent.scheduled())
tickEvent.schedule(curTick);
_status = Running;
@@ -751,8 +802,13 @@ FullO3CPU<Impl>::signalDrained()
if (++drainCount == NumStages) {
if (tickEvent.scheduled())
tickEvent.squash();
- _status = Drained;
- drainEvent->process();
+
+ changeState(SimObject::DrainedTiming);
+
+ if (drainEvent) {
+ drainEvent->process();
+ drainEvent = NULL;
+ }
}
assert(drainCount <= 5);
}
diff --git a/src/cpu/o3/cpu.hh b/src/cpu/o3/cpu.hh
index cf3747601..5b881e558 100644
--- a/src/cpu/o3/cpu.hh
+++ b/src/cpu/o3/cpu.hh
@@ -111,7 +111,6 @@ class FullO3CPU : public BaseO3CPU
Idle,
Halted,
Blocked,
- Drained,
SwitchedOut
};
@@ -266,6 +265,13 @@ class FullO3CPU : public BaseO3CPU
/** Update The Order In Which We Process Threads. */
void updateThreadPriority();
+ /** Serialize state. */
+ virtual void serialize(std::ostream &os);
+
+ /** Unserialize from a checkpoint. */
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+ public:
/** Executes a syscall on this cycle.
* ---------------------------------------
* Note: this is a virtual function. CPU-Specific
diff --git a/src/cpu/o3/decode.hh b/src/cpu/o3/decode.hh
index 1e96f1884..7f5ecbc26 100644
--- a/src/cpu/o3/decode.hh
+++ b/src/cpu/o3/decode.hh
@@ -110,7 +110,7 @@ class DefaultDecode
void setActiveThreads(std::list<unsigned> *at_ptr);
/** Drains the decode stage. */
- void drain();
+ bool drain();
/** Resumes execution after a drain. */
void resume() { }
diff --git a/src/cpu/o3/decode_impl.hh b/src/cpu/o3/decode_impl.hh
index 71637883b..8b851c032 100644
--- a/src/cpu/o3/decode_impl.hh
+++ b/src/cpu/o3/decode_impl.hh
@@ -165,11 +165,12 @@ DefaultDecode<Impl>::setActiveThreads(list<unsigned> *at_ptr)
}
template <class Impl>
-void
+bool
DefaultDecode<Impl>::drain()
{
// Decode is done draining at any time.
cpu->signalDrained();
+ return true;
}
template <class Impl>
diff --git a/src/cpu/o3/fetch.hh b/src/cpu/o3/fetch.hh
index 9611f0455..a793c7361 100644
--- a/src/cpu/o3/fetch.hh
+++ b/src/cpu/o3/fetch.hh
@@ -181,7 +181,7 @@ class DefaultFetch
void processCacheCompletion(PacketPtr pkt);
/** Begins the drain of the fetch stage. */
- void drain();
+ bool drain();
/** Resumes execution after a drain. */
void resume();
diff --git a/src/cpu/o3/fetch_impl.hh b/src/cpu/o3/fetch_impl.hh
index 500b5304e..c0cc189f2 100644
--- a/src/cpu/o3/fetch_impl.hh
+++ b/src/cpu/o3/fetch_impl.hh
@@ -385,12 +385,13 @@ DefaultFetch<Impl>::processCacheCompletion(PacketPtr pkt)
}
template <class Impl>
-void
+bool
DefaultFetch<Impl>::drain()
{
// Fetch is ready to drain at any time.
cpu->signalDrained();
drainPending = true;
+ return true;
}
template <class Impl>
diff --git a/src/cpu/o3/iew.hh b/src/cpu/o3/iew.hh
index 774b6dcbd..4908a6649 100644
--- a/src/cpu/o3/iew.hh
+++ b/src/cpu/o3/iew.hh
@@ -144,7 +144,7 @@ class DefaultIEW
void setScoreboard(Scoreboard *sb_ptr);
/** Drains IEW stage. */
- void drain();
+ bool drain();
/** Resumes execution after a drain. */
void resume();
diff --git a/src/cpu/o3/iew_impl.hh b/src/cpu/o3/iew_impl.hh
index c3aa748ae..0d82645e3 100644
--- a/src/cpu/o3/iew_impl.hh
+++ b/src/cpu/o3/iew_impl.hh
@@ -354,11 +354,12 @@ DefaultIEW<Impl>::setScoreboard(Scoreboard *sb_ptr)
}
template <class Impl>
-void
+bool
DefaultIEW<Impl>::drain()
{
// IEW is ready to drain at any time.
cpu->signalDrained();
+ return true;
}
template <class Impl>
diff --git a/src/cpu/o3/lsq_impl.hh b/src/cpu/o3/lsq_impl.hh
index 5173f8be1..89fd1a71d 100644
--- a/src/cpu/o3/lsq_impl.hh
+++ b/src/cpu/o3/lsq_impl.hh
@@ -502,6 +502,9 @@ LSQ<Impl>::hasStoresToWB()
{
list<unsigned>::iterator active_threads = (*activeThreads).begin();
+ if ((*activeThreads).empty())
+ return false;
+
while (active_threads != (*activeThreads).end()) {
unsigned tid = *active_threads++;
if (!hasStoresToWB(tid))
diff --git a/src/cpu/o3/regfile.hh b/src/cpu/o3/regfile.hh
index 6972f055f..b6677b4b1 100644
--- a/src/cpu/o3/regfile.hh
+++ b/src/cpu/o3/regfile.hh
@@ -86,10 +86,6 @@ class PhysRegFile
//The duplication is unfortunate but it's better than having
//different ways to access certain registers.
- //Add these in later when everything else is in place
-// void serialize(std::ostream &os);
-// void unserialize(Checkpoint *cp, const std::string &section);
-
/** Reads an integer register. */
uint64_t readIntReg(PhysRegIndex reg_idx)
{
diff --git a/src/cpu/o3/rename.hh b/src/cpu/o3/rename.hh
index 538dd9bb4..034087feb 100644
--- a/src/cpu/o3/rename.hh
+++ b/src/cpu/o3/rename.hh
@@ -158,7 +158,7 @@ class DefaultRename
void setScoreboard(Scoreboard *_scoreboard);
/** Drains the rename stage. */
- void drain();
+ bool drain();
/** Resumes execution after a drain. */
void resume() { }
diff --git a/src/cpu/o3/rename_impl.hh b/src/cpu/o3/rename_impl.hh
index fddbae3db..805a72808 100644
--- a/src/cpu/o3/rename_impl.hh
+++ b/src/cpu/o3/rename_impl.hh
@@ -257,11 +257,12 @@ DefaultRename<Impl>::setScoreboard(Scoreboard *_scoreboard)
}
template <class Impl>
-void
+bool
DefaultRename<Impl>::drain()
{
// Rename is ready to switch out at any time.
cpu->signalDrained();
+ return true;
}
template <class Impl>
diff --git a/src/cpu/simple/timing.cc b/src/cpu/simple/timing.cc
index 036037ba9..6774d79a9 100644
--- a/src/cpu/simple/timing.cc
+++ b/src/cpu/simple/timing.cc
@@ -118,11 +118,11 @@ TimingSimpleCPU::drain(Event *drain_event)
// an access to complete.
if (status() == Idle || status() == Running || status() == SwitchedOut) {
changeState(SimObject::DrainedTiming);
- return false;
+ return true;
} else {
changeState(SimObject::Draining);
drainEvent = drain_event;
- return true;
+ return false;
}
}
diff --git a/src/cpu/simple_thread.cc b/src/cpu/simple_thread.cc
index db28b23e8..af1db2ff2 100644
--- a/src/cpu/simple_thread.cc
+++ b/src/cpu/simple_thread.cc
@@ -123,15 +123,19 @@ SimpleThread::SimpleThread(BaseCPU *_cpu, int _thread_num,
tc = new ProxyThreadContext<SimpleThread>(this);
}
-SimpleThread::SimpleThread(RegFile *regFile)
- : ThreadState(-1, -1, NULL, -1, NULL), cpu(NULL)
+#endif
+
+SimpleThread::SimpleThread()
+#if FULL_SYSTEM
+ : ThreadState(-1, -1)
+#else
+ : ThreadState(-1, -1, NULL, -1, NULL)
+#endif
{
- regs = *regFile;
tc = new ProxyThreadContext<SimpleThread>(this);
+ regs.clear();
}
-#endif
-
SimpleThread::~SimpleThread()
{
delete tc;
@@ -147,13 +151,8 @@ SimpleThread::takeOverFrom(ThreadContext *oldContext)
assert(process == oldContext->getProcessPtr());
#endif
- // copy over functional state
- _status = oldContext->status();
- copyArchRegs(oldContext);
- cpuId = oldContext->readCpuId();
-#if !FULL_SYSTEM
- funcExeInst = oldContext->readFuncExeInst();
-#else
+ copyState(oldContext);
+#if FULL_SYSTEM
EndQuiesceEvent *quiesce = oldContext->getQuiesceEvent();
if (quiesce) {
// Point the quiesce event's TC at this TC so that it wakes up
@@ -171,42 +170,49 @@ SimpleThread::takeOverFrom(ThreadContext *oldContext)
}
void
-SimpleThread::serialize(ostream &os)
+SimpleThread::copyTC(ThreadContext *context)
{
- SERIALIZE_ENUM(_status);
- regs.serialize(os);
- // thread_num and cpu_id are deterministic from the config
- SERIALIZE_SCALAR(funcExeInst);
- SERIALIZE_SCALAR(inst);
+ copyState(context);
#if FULL_SYSTEM
- Tick quiesceEndTick = 0;
- if (quiesceEvent->scheduled())
- quiesceEndTick = quiesceEvent->when();
- SERIALIZE_SCALAR(quiesceEndTick);
- if (kernelStats)
- kernelStats->serialize(os);
+ EndQuiesceEvent *quiesce = context->getQuiesceEvent();
+ if (quiesce) {
+ quiesceEvent = quiesce;
+ }
+ Kernel::Statistics *stats = context->getKernelStats();
+ if (stats) {
+ kernelStats = stats;
+ }
#endif
}
+void
+SimpleThread::copyState(ThreadContext *oldContext)
+{
+ // copy over functional state
+ _status = oldContext->status();
+ copyArchRegs(oldContext);
+ cpuId = oldContext->readCpuId();
+#if !FULL_SYSTEM
+ funcExeInst = oldContext->readFuncExeInst();
+#endif
+}
+
+void
+SimpleThread::serialize(ostream &os)
+{
+ ThreadState::serialize(os);
+ regs.serialize(os);
+ // thread_num and cpu_id are deterministic from the config
+}
+
void
SimpleThread::unserialize(Checkpoint *cp, const std::string &section)
{
- UNSERIALIZE_ENUM(_status);
+ ThreadState::unserialize(cp, section);
regs.unserialize(cp, section);
// thread_num and cpu_id are deterministic from the config
- UNSERIALIZE_SCALAR(funcExeInst);
- UNSERIALIZE_SCALAR(inst);
-
-#if FULL_SYSTEM
- Tick quiesceEndTick;
- UNSERIALIZE_SCALAR(quiesceEndTick);
- if (quiesceEndTick)
- quiesceEvent->schedule(quiesceEndTick);
- if (kernelStats)
- kernelStats->unserialize(cp, section);
-#endif
}
#if FULL_SYSTEM
diff --git a/src/cpu/simple_thread.hh b/src/cpu/simple_thread.hh
index de65e9891..d36853db4 100644
--- a/src/cpu/simple_thread.hh
+++ b/src/cpu/simple_thread.hh
@@ -119,16 +119,20 @@ class SimpleThread : public ThreadState
#else
SimpleThread(BaseCPU *_cpu, int _thread_num, Process *_process, int _asid,
MemObject *memobj);
- // Constructor to use SimpleThread to pass reg file around. Not
- // used for anything else.
- SimpleThread(RegFile *regFile);
#endif
+
+ SimpleThread();
+
virtual ~SimpleThread();
virtual void takeOverFrom(ThreadContext *oldContext);
void regStats(const std::string &name);
+ void copyTC(ThreadContext *context);
+
+ void copyState(ThreadContext *oldContext);
+
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
diff --git a/src/cpu/thread_state.cc b/src/cpu/thread_state.cc
index 872678a41..6a96560f1 100644
--- a/src/cpu/thread_state.cc
+++ b/src/cpu/thread_state.cc
@@ -31,6 +31,12 @@
#include "base/output.hh"
#include "cpu/profile.hh"
#include "cpu/thread_state.hh"
+#include "sim/serialize.hh"
+
+#if FULL_SYSTEM
+#include "cpu/quiesce_event.hh"
+#include "kern/kernel_stats.hh"
+#endif
#if FULL_SYSTEM
ThreadState::ThreadState(int _cpuId, int _tid)
@@ -49,6 +55,43 @@ ThreadState::ThreadState(int _cpuId, int _tid, Process *_process,
numLoad = 0;
}
+void
+ThreadState::serialize(std::ostream &os)
+{
+ SERIALIZE_ENUM(_status);
+ // thread_num and cpu_id are deterministic from the config
+ SERIALIZE_SCALAR(funcExeInst);
+ SERIALIZE_SCALAR(inst);
+
+#if FULL_SYSTEM
+ Tick quiesceEndTick = 0;
+ if (quiesceEvent->scheduled())
+ quiesceEndTick = quiesceEvent->when();
+ SERIALIZE_SCALAR(quiesceEndTick);
+ if (kernelStats)
+ kernelStats->serialize(os);
+#endif
+}
+
+void
+ThreadState::unserialize(Checkpoint *cp, const std::string &section)
+{
+
+ UNSERIALIZE_ENUM(_status);
+ // thread_num and cpu_id are deterministic from the config
+ UNSERIALIZE_SCALAR(funcExeInst);
+ UNSERIALIZE_SCALAR(inst);
+
+#if FULL_SYSTEM
+ Tick quiesceEndTick;
+ UNSERIALIZE_SCALAR(quiesceEndTick);
+ if (quiesceEndTick)
+ quiesceEvent->schedule(quiesceEndTick);
+ if (kernelStats)
+ kernelStats->unserialize(cp, section);
+#endif
+}
+
#if FULL_SYSTEM
void
diff --git a/src/cpu/thread_state.hh b/src/cpu/thread_state.hh
index cb1449ac5..b03a2e2bb 100644
--- a/src/cpu/thread_state.hh
+++ b/src/cpu/thread_state.hh
@@ -49,6 +49,8 @@ namespace Kernel {
};
#endif
+class Checkpoint;
+
/**
* Struct for holding general thread state that is needed across CPU
* models. This includes things such as pointers to the process,
@@ -65,6 +67,10 @@ struct ThreadState {
short _asid, MemObject *mem);
#endif
+ void serialize(std::ostream &os);
+
+ void unserialize(Checkpoint *cp, const std::string &section);
+
void setCpuId(int id) { cpuId = id; }
int readCpuId() { return cpuId; }
diff --git a/src/dev/tsunami_pchip.hh b/src/dev/tsunami_pchip.hh
index b9e900526..2c97a1fea 100644
--- a/src/dev/tsunami_pchip.hh
+++ b/src/dev/tsunami_pchip.hh
@@ -46,7 +46,7 @@ class TsunamiPChip : public BasicPioDevice
{
protected:
- static const Addr TsunamiPciBus0Config = 0x801fe000000;
+ static const Addr TsunamiPciBus0Config = ULL(0x801fe000000);
/** Pchip control register */
uint64_t pctl;
diff --git a/src/python/m5/__init__.py b/src/python/m5/__init__.py
index 579785a46..dc3af7000 100644
--- a/src/python/m5/__init__.py
+++ b/src/python/m5/__init__.py
@@ -213,14 +213,28 @@ atexit.register(cc_main.doExitCleanup)
# matter since most scripts will probably 'from m5.objects import *'.
import objects
+# This loops until all objects have been fully drained.
def doDrain(root):
+ all_drained = drain(root)
+ while (not all_drained):
+ all_drained = drain(root)
+
+# Tries to drain all objects. Draining might not be completed unless
+# all objects return that they are drained on the first call. This is
+# because as objects drain they may cause other objects to no longer
+# be drained.
+def drain(root):
+ all_drained = False
drain_event = cc_main.createCountedDrain()
unready_objects = root.startDrain(drain_event, True)
# If we've got some objects that can't drain immediately, then simulate
if unready_objects > 0:
drain_event.setCount(unready_objects)
simulate()
+ else:
+ all_drained = True
cc_main.cleanupCountedDrain(drain_event)
+ return all_drained
def resume(root):
root.resume()
@@ -236,6 +250,7 @@ def checkpoint(root):
def restoreCheckpoint(root):
print "Restoring from checkpoint"
cc_main.unserializeAll()
+ resume(root)
def changeToAtomic(system):
if not isinstance(system, objects.Root) and not isinstance(system, System):
diff --git a/src/sim/pseudo_inst.cc b/src/sim/pseudo_inst.cc
index 869805f5c..fcf0b957a 100644
--- a/src/sim/pseudo_inst.cc
+++ b/src/sim/pseudo_inst.cc
@@ -37,7 +37,6 @@
#include "sim/pseudo_inst.hh"
#include "arch/vtophys.hh"
#include "cpu/base.hh"
-#include "cpu/sampler/sampler.hh"
#include "cpu/thread_context.hh"
#include "cpu/quiesce_event.hh"
#include "kern/kernel_stats.hh"