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:
Kevin Lim
2006-07-06 23:20:44 -04:00
23 changed files with 220 additions and 69 deletions

View File

@@ -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;

View File

@@ -188,7 +188,7 @@ class DefaultCommit
void initStage();
/** Initializes the draining of commit. */
void drain();
bool drain();
/** Resumes execution after draining. */
void resume();

View File

@@ -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>

View File

@@ -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 &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;
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);
}

View File

@@ -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

View File

@@ -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() { }

View File

@@ -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>

View File

@@ -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();

View File

@@ -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>

View File

@@ -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();

View File

@@ -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>

View File

@@ -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))

View File

@@ -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)
{

View File

@@ -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() { }

View File

@@ -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>

View File

@@ -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;
}
}

View File

@@ -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 &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

View File

@@ -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);

View File

@@ -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

View File

@@ -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; }

View File

@@ -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;

View File

@@ -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):

View File

@@ -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"