Merge ktlim@zizzer:/bk/newmem
into zamp.eecs.umich.edu:/z/ktlim2/clean/newmem-merge --HG-- extra : convert_revision : 942c43e2fdd68cde7aaaba5e88a667f80feab162
This commit is contained in:
@@ -112,6 +112,10 @@ namespace AlphaISA
|
||||
lock_flag = 0;
|
||||
lock_addr = 0;
|
||||
}
|
||||
|
||||
void serialize(std::ostream &os);
|
||||
|
||||
void unserialize(Checkpoint *cp, const std::string §ion);
|
||||
#if FULL_SYSTEM
|
||||
protected:
|
||||
typedef uint64_t InternalProcReg;
|
||||
|
||||
@@ -188,7 +188,7 @@ class DefaultCommit
|
||||
void initStage();
|
||||
|
||||
/** Initializes the draining of commit. */
|
||||
void drain();
|
||||
bool drain();
|
||||
|
||||
/** Resumes execution after draining. */
|
||||
void resume();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -707,12 +707,52 @@ 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 §ion)
|
||||
{
|
||||
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;
|
||||
|
||||
return false;
|
||||
wakeCPU();
|
||||
activityRec.activity();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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 §ion);
|
||||
|
||||
public:
|
||||
/** Executes a syscall on this cycle.
|
||||
* ---------------------------------------
|
||||
* Note: this is a virtual function. CPU-Specific
|
||||
|
||||
@@ -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() { }
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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 §ion);
|
||||
|
||||
/** Reads an integer register. */
|
||||
uint64_t readIntReg(PhysRegIndex reg_idx)
|
||||
{
|
||||
|
||||
@@ -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() { }
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
regs = *regFile;
|
||||
tc = new ProxyThreadContext<SimpleThread>(this);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
SimpleThread::SimpleThread()
|
||||
#if FULL_SYSTEM
|
||||
: ThreadState(-1, -1)
|
||||
#else
|
||||
: ThreadState(-1, -1, NULL, -1, NULL)
|
||||
#endif
|
||||
{
|
||||
tc = new ProxyThreadContext<SimpleThread>(this);
|
||||
regs.clear();
|
||||
}
|
||||
|
||||
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 §ion)
|
||||
{
|
||||
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
|
||||
|
||||
@@ -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 §ion);
|
||||
|
||||
|
||||
@@ -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 §ion)
|
||||
{
|
||||
|
||||
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
|
||||
|
||||
@@ -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 §ion);
|
||||
|
||||
void setCpuId(int id) { cpuId = id; }
|
||||
|
||||
int readCpuId() { return cpuId; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user