* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Kevin Lim
+ * Korey Sewell
*/
#include "config/full_system.hh"
+#include "config/use_checker.hh"
#if FULL_SYSTEM
#include "sim/system.hh"
#endif
#include "cpu/activity.hh"
-#include "cpu/checker/cpu.hh"
-#include "cpu/cpu_exec_context.hh"
-#include "cpu/exec_context.hh"
-#include "cpu/o3/alpha_dyn_inst.hh"
-#include "cpu/o3/alpha_impl.hh"
+#include "cpu/simple_thread.hh"
+#include "cpu/thread_context.hh"
+#include "cpu/o3/isa_specific.hh"
#include "cpu/o3/cpu.hh"
#include "sim/root.hh"
#include "sim/stat_control.hh"
+#if USE_CHECKER
+#include "cpu/checker/cpu.hh"
+#endif
+
using namespace std;
using namespace TheISA;
-BaseFullCPU::BaseFullCPU(Params *params)
+BaseO3CPU::BaseO3CPU(Params *params)
: BaseCPU(params), cpu_id(0)
{
}
void
-BaseFullCPU::regStats()
+BaseO3CPU::regStats()
{
BaseCPU::regStats();
}
return "FullO3CPU tick event";
}
+template <class Impl>
+FullO3CPU<Impl>::ActivateThreadEvent::ActivateThreadEvent()
+ : Event(&mainEventQueue, CPU_Tick_Pri)
+{
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::ActivateThreadEvent::init(int thread_num,
+ FullO3CPU<Impl> *thread_cpu)
+{
+ tid = thread_num;
+ cpu = thread_cpu;
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::ActivateThreadEvent::process()
+{
+ cpu->activateThread(tid);
+}
+
+template <class Impl>
+const char *
+FullO3CPU<Impl>::ActivateThreadEvent::description()
+{
+ return "FullO3CPU \"Activate Thread\" event";
+}
+
template <class Impl>
FullO3CPU<Impl>::FullO3CPU(Params *params)
- : BaseFullCPU(params),
+ : BaseO3CPU(params),
tickEvent(this),
removeInstsThisCycle(false),
fetch(params),
regFile(params->numPhysIntRegs, params->numPhysFloatRegs),
- freeList(params->numberOfThreads,//number of activeThreads
+ freeList(params->numberOfThreads,
TheISA::NumIntRegs, params->numPhysIntRegs,
TheISA::NumFloatRegs, params->numPhysFloatRegs),
params->smtROBPolicy, params->smtROBThreshold,
params->numberOfThreads),
- scoreboard(params->numberOfThreads,//number of activeThreads
+ scoreboard(params->numberOfThreads,
TheISA::NumIntRegs, params->numPhysIntRegs,
TheISA::NumFloatRegs, params->numPhysFloatRegs,
TheISA::NumMiscRegs * number_of_threads,
#if FULL_SYSTEM
system(params->system),
- memCtrl(system->memctrl),
physmem(system->physmem),
#endif // FULL_SYSTEM
mem(params->mem),
- switchCount(0),
+ drainCount(0),
deferRegistration(params->deferRegistration),
numThreads(number_of_threads)
{
_status = Idle;
+ checker = NULL;
+
if (params->checker) {
+#if USE_CHECKER
BaseCPU *temp_checker = params->checker;
checker = dynamic_cast<Checker<DynInstPtr> *>(temp_checker);
checker->setMemory(mem);
#if FULL_SYSTEM
checker->setSystem(params->system);
#endif
- } else {
- checker = NULL;
+#else
+ panic("Checker enabled but not compiled in!");
+#endif // USE_CHECKER
}
#if !FULL_SYSTEM
#if !FULL_SYSTEM
int active_threads = params->workload.size();
+
+ if (active_threads > Impl::MaxThreads) {
+ panic("Workload Size too large. Increase the 'MaxThreads'"
+ "constant in your O3CPU impl. file (e.g. o3/alpha/impl.hh) or "
+ "edit your workload size.");
+ }
#else
int active_threads = 1;
#endif
}
rename.setFreeList(&freeList);
- // Setup the page table for whichever stages need it.
-#if !FULL_SYSTEM
-// fetch.setPageTable(pTable);
-// iew.setPageTable(pTable);
-#endif
-
// Setup the ROB for whichever stages need it.
commit.setROB(&rob);
lastRunningCycle = curTick;
+ lastActivatedCycle = -1;
+
contextSwitch = false;
}
void
FullO3CPU<Impl>::fullCPURegStats()
{
- BaseFullCPU::regStats();
+ BaseO3CPU::regStats();
- // Register any of the FullCPU's stats here.
+ // Register any of the O3CPU's stats here.
timesIdled
.name(name() + ".timesIdled")
.desc("Number of times that the entire CPU went into an idle state and"
void
FullO3CPU<Impl>::tick()
{
- DPRINTF(FullCPU, "\n\nFullCPU: Ticking main, FullO3CPU.\n");
+ DPRINTF(O3CPU, "\n\nFullO3CPU: Ticking main, FullO3CPU.\n");
++numCycles;
}
if (!tickEvent.scheduled()) {
- if (_status == SwitchedOut) {
+ if (_status == SwitchedOut ||
+ getState() == SimObject::DrainedTiming) {
// increment stat
lastRunningCycle = curTick;
} else if (!activityRec.active()) {
FullO3CPU<Impl>::init()
{
if (!deferRegistration) {
- registerExecContexts();
+ registerThreadContexts();
}
// Set inSyscall so that the CPU doesn't squash when initially
for (int tid=0; tid < number_of_threads; tid++) {
#if FULL_SYSTEM
- ExecContext *src_xc = execContexts[tid];
+ ThreadContext *src_tc = threadContexts[tid];
#else
- ExecContext *src_xc = thread[tid]->getXCProxy();
+ ThreadContext *src_tc = thread[tid]->getTC();
#endif
// Threads start in the Suspended State
- if (src_xc->status() != ExecContext::Suspended) {
+ if (src_tc->status() != ThreadContext::Suspended) {
continue;
}
#if FULL_SYSTEM
- TheISA::initCPU(src_xc, src_xc->readCpuId());
+ TheISA::initCPU(src_tc, src_tc->readCpuId());
#endif
}
void
FullO3CPU<Impl>::insertThread(unsigned tid)
{
- DPRINTF(FullCPU,"[tid:%i] Initializing thread data");
+ DPRINTF(O3CPU,"[tid:%i] Initializing thread into CPU");
// Will change now that the PC and thread state is internal to the CPU
- // and not in the CPUExecContext.
-#if 0
+ // and not in the ThreadContext.
#if FULL_SYSTEM
- ExecContext *src_xc = system->execContexts[tid];
+ ThreadContext *src_tc = system->threadContexts[tid];
#else
- CPUExecContext *src_xc = thread[tid];
+ ThreadContext *src_tc = tcBase(tid);
#endif
//Bind Int Regs to Rename Map
}
//Copy Thread Data Into RegFile
- this->copyFromXC(tid);
+ //this->copyFromTC(tid);
- //Set PC/NPC
- regFile.pc[tid] = src_xc->readPC();
- regFile.npc[tid] = src_xc->readNextPC();
+ //Set PC/NPC/NNPC
+ setPC(src_tc->readPC(), tid);
+ setNextPC(src_tc->readNextPC(), tid);
+#if THE_ISA != ALPHA_ISA
+ setNextNPC(src_tc->readNextNPC(), tid);
+#endif
- src_xc->setStatus(ExecContext::Active);
+ src_tc->setStatus(ThreadContext::Active);
activateContext(tid,1);
//Reset ROB/IQ/LSQ Entries
commit.rob->resetEntries();
iew.resetEntries();
-#endif
}
template <class Impl>
void
FullO3CPU<Impl>::removeThread(unsigned tid)
{
- DPRINTF(FullCPU,"[tid:%i] Removing thread data");
-#if 0
- //Unbind Int Regs from Rename Map
+ DPRINTF(O3CPU,"[tid:%i] Removing thread from CPU.");
+
+ // Copy Thread Data From RegFile
+ // If thread is suspended, it might be re-allocated
+ //this->copyToTC(tid);
+
+ // Unbind Int Regs from Rename Map
for (int ireg = 0; ireg < TheISA::NumIntRegs; ireg++) {
PhysRegIndex phys_reg = renameMap[tid].lookup(ireg);
freeList.addReg(phys_reg);
}
- //Unbind Float Regs from Rename Map
+ // Unbind Float Regs from Rename Map
for (int freg = 0; freg < TheISA::NumFloatRegs; freg++) {
PhysRegIndex phys_reg = renameMap[tid].lookup(freg);
freeList.addReg(phys_reg);
}
- //Copy Thread Data From RegFile
- /* Fix Me:
- * Do we really need to do this if we are removing a thread
- * in the sense that it's finished (exiting)? If the thread is just
- * being suspended we might...
- */
-// this->copyToXC(tid);
-
- //Squash Throughout Pipeline
+ // Squash Throughout Pipeline
fetch.squash(0,tid);
decode.squash(tid);
rename.squash(tid);
assert(iew.ldstQueue.getCount(tid) == 0);
- //Reset ROB/IQ/LSQ Entries
+ // Reset ROB/IQ/LSQ Entries
if (activeThreads.size() >= 1) {
commit.rob->resetEntries();
iew.resetEntries();
}
-#endif
}
void
FullO3CPU<Impl>::activateWhenReady(int tid)
{
- DPRINTF(FullCPU,"[tid:%i]: Checking if resources are available for incoming"
+ DPRINTF(O3CPU,"[tid:%i]: Checking if resources are available for incoming"
"(e.g. PhysRegs/ROB/IQ/LSQ) \n",
tid);
bool ready = true;
if (freeList.numFreeIntRegs() >= TheISA::NumIntRegs) {
- DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough "
+ DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
"Phys. Int. Regs.\n",
tid);
ready = false;
} else if (freeList.numFreeFloatRegs() >= TheISA::NumFloatRegs) {
- DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough "
+ DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
"Phys. Float. Regs.\n",
tid);
ready = false;
} else if (commit.rob->numFreeEntries() >=
commit.rob->entryAmount(activeThreads.size() + 1)) {
- DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough "
+ DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
"ROB entries.\n",
tid);
ready = false;
} else if (iew.instQueue.numFreeEntries() >=
iew.instQueue.entryAmount(activeThreads.size() + 1)) {
- DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough "
+ DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
"IQ entries.\n",
tid);
ready = false;
} else if (iew.ldstQueue.numFreeEntries() >=
iew.ldstQueue.entryAmount(activeThreads.size() + 1)) {
- DPRINTF(FullCPU,"[tid:%i] Suspending thread due to not enough "
+ DPRINTF(O3CPU,"[tid:%i] Suspending thread due to not enough "
"LSQ entries.\n",
tid);
ready = false;
template <class Impl>
void
-FullO3CPU<Impl>::activateContext(int tid, int delay)
+FullO3CPU<Impl>::activateThread(unsigned int tid)
{
- // Needs to set each stage to running as well.
list<unsigned>::iterator isActive = find(
activeThreads.begin(), activeThreads.end(), tid);
if (isActive == activeThreads.end()) {
- //May Need to Re-code this if the delay variable is the
- //delay needed for thread to activate
- DPRINTF(FullCPU, "Adding Thread %i to active threads list\n",
+ DPRINTF(O3CPU, "[tid:%i]: Adding to active threads list\n",
tid);
activeThreads.push_back(tid);
}
+}
- assert(_status == Idle || _status == SwitchedOut);
- scheduleTickEvent(delay);
+template <class Impl>
+void
+FullO3CPU<Impl>::activateContext(int tid, int delay)
+{
+ // Needs to set each stage to running as well.
+ if (delay){
+ DPRINTF(O3CPU, "[tid:%i]: Scheduling thread context to activate "
+ "on cycle %d\n", tid, curTick + cycles(delay));
+ scheduleActivateThreadEvent(tid, delay);
+ } else {
+ activateThread(tid);
+ }
- // Be sure to signal that there's some activity so the CPU doesn't
- // deschedule itself.
- activityRec.activity();
- fetch.wakeFromQuiesce();
+ if(lastActivatedCycle < curTick) {
+ scheduleTickEvent(delay);
- _status = Running;
+ // Be sure to signal that there's some activity so the CPU doesn't
+ // deschedule itself.
+ activityRec.activity();
+ fetch.wakeFromQuiesce();
+
+ lastActivatedCycle = curTick;
+
+ _status = Running;
+ }
}
template <class Impl>
void
FullO3CPU<Impl>::suspendContext(int tid)
{
- DPRINTF(FullCPU,"[tid: %i]: Suspended ...\n", tid);
+ DPRINTF(O3CPU,"[tid: %i]: Suspending Thread Context.\n", tid);
unscheduleTickEvent();
_status = Idle;
/*
activeThreads.begin(), activeThreads.end(), tid);
if (isActive != activeThreads.end()) {
- DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n",
+ DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
tid);
activeThreads.erase(isActive);
}
void
FullO3CPU<Impl>::deallocateContext(int tid)
{
- DPRINTF(FullCPU,"[tid:%i]: Deallocating ...", tid);
-/*
+ DPRINTF(O3CPU,"[tid:%i]: Deallocating Thread Context", tid);
+
//Remove From Active List, if Active
- list<unsigned>::iterator isActive = find(
- activeThreads.begin(), activeThreads.end(), tid);
+ list<unsigned>::iterator thread_it =
+ find(activeThreads.begin(), activeThreads.end(), tid);
- if (isActive != activeThreads.end()) {
- DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n",
+ if (thread_it != activeThreads.end()) {
+ DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
tid);
- activeThreads.erase(isActive);
+ activeThreads.erase(thread_it);
removeThread(tid);
}
-*/
}
template <class Impl>
void
FullO3CPU<Impl>::haltContext(int tid)
{
- DPRINTF(FullCPU,"[tid:%i]: Halted ...", tid);
+ DPRINTF(O3CPU,"[tid:%i]: Halting Thread Context", tid);
/*
//Remove From Active List, if Active
list<unsigned>::iterator isActive = find(
activeThreads.begin(), activeThreads.end(), tid);
if (isActive != activeThreads.end()) {
- DPRINTF(FullCPU,"[tid:%i]: Removing from active threads list\n",
+ DPRINTF(O3CPU,"[tid:%i]: Removing from active threads list\n",
tid);
activeThreads.erase(isActive);
template <class Impl>
void
-FullO3CPU<Impl>::switchOut(Sampler *_sampler)
+FullO3CPU<Impl>::serialize(std::ostream &os)
{
- sampler = _sampler;
- switchCount = 0;
- fetch.switchOut();
- decode.switchOut();
- rename.switchOut();
- iew.switchOut();
- commit.switchOut();
+ 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;
+ fetch.drain();
+ decode.drain();
+ rename.drain();
+ iew.drain();
+ 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;
+ } else {
+ return true;
+ }
}
template <class Impl>
void
-FullO3CPU<Impl>::signalSwitched()
-{
- if (++switchCount == NumStages) {
- fetch.doSwitchOut();
- rename.doSwitchOut();
- commit.doSwitchOut();
- instList.clear();
- while (!removeList.empty()) {
- removeList.pop();
- }
+FullO3CPU<Impl>::resume()
+{
+ fetch.resume();
+ decode.resume();
+ rename.resume();
+ iew.resume();
+ commit.resume();
+
+ if (_status == SwitchedOut || _status == Idle)
+ return;
- if (checker)
- checker->switchOut(sampler);
+ if (!tickEvent.scheduled())
+ tickEvent.schedule(curTick);
+ _status = Running;
+ changeState(SimObject::Timing);
+}
+template <class Impl>
+void
+FullO3CPU<Impl>::signalDrained()
+{
+ if (++drainCount == NumStages) {
if (tickEvent.scheduled())
tickEvent.squash();
- sampler->signalSwitched();
- _status = SwitchedOut;
+
+ changeState(SimObject::DrainedTiming);
+
+ if (drainEvent) {
+ drainEvent->process();
+ drainEvent = NULL;
+ }
+ }
+ assert(drainCount <= 5);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::switchOut()
+{
+ fetch.switchOut();
+ rename.switchOut();
+ commit.switchOut();
+ instList.clear();
+ while (!removeList.empty()) {
+ removeList.pop();
}
- assert(switchCount <= 5);
+
+ _status = SwitchedOut;
+#if USE_CHECKER
+ if (checker)
+ checker->switchOut();
+#endif
}
template <class Impl>
if (isActive == activeThreads.end()) {
//May Need to Re-code this if the delay variable is the delay
//needed for thread to activate
- DPRINTF(FullCPU, "Adding Thread %i to active threads list\n",
+ DPRINTF(O3CPU, "Adding Thread %i to active threads list\n",
tid);
activeThreads.push_back(tid);
// Set all statuses to active, schedule the CPU's tick event.
// @todo: Fix up statuses so this is handled properly
- for (int i = 0; i < execContexts.size(); ++i) {
- ExecContext *xc = execContexts[i];
- if (xc->status() == ExecContext::Active && _status != Running) {
+ for (int i = 0; i < threadContexts.size(); ++i) {
+ ThreadContext *tc = threadContexts[i];
+ if (tc->status() == ThreadContext::Active && _status != Running) {
_status = Running;
tickEvent.schedule(curTick);
}
commit.setNextPC(val, tid);
}
+#if THE_ISA != ALPHA_ISA
+template <class Impl>
+uint64_t
+FullO3CPU<Impl>::readNextNPC(unsigned tid)
+{
+ return commit.readNextNPC(tid);
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::setNextNNPC(uint64_t val,unsigned tid)
+{
+ commit.setNextNPC(val, tid);
+}
+#endif
+
template <class Impl>
typename FullO3CPU<Impl>::ListIt
FullO3CPU<Impl>::addInst(DynInstPtr &inst)
void
FullO3CPU<Impl>::removeFrontInst(DynInstPtr &inst)
{
- DPRINTF(FullCPU, "FullCPU: Removing committed instruction [tid:%i] PC %#x "
+ DPRINTF(O3CPU, "Removing committed instruction [tid:%i] PC %#x "
"[sn:%lli]\n",
inst->threadNumber, inst->readPC(), inst->seqNum);
void
FullO3CPU<Impl>::removeInstsNotInROB(unsigned tid)
{
- DPRINTF(FullCPU, "FullCPU: Thread %i: Deleting instructions from instruction"
+ DPRINTF(O3CPU, "Thread %i: Deleting instructions from instruction"
" list.\n", tid);
ListIt end_it;
if (instList.empty()) {
return;
} else if (rob.isEmpty(/*tid*/)) {
- DPRINTF(FullCPU, "FullCPU: ROB is empty, squashing all insts.\n");
+ DPRINTF(O3CPU, "ROB is empty, squashing all insts.\n");
end_it = instList.begin();
rob_empty = true;
} else {
end_it = (rob.readTailInst(tid))->getInstListIt();
- DPRINTF(FullCPU, "FullCPU: ROB is not empty, squashing insts not in ROB.\n");
+ DPRINTF(O3CPU, "ROB is not empty, squashing insts not in ROB.\n");
}
removeInstsThisCycle = true;
inst_iter--;
- DPRINTF(FullCPU, "FullCPU: Deleting instructions from instruction "
+ DPRINTF(O3CPU, "Deleting instructions from instruction "
"list that are from [tid:%i] and above [sn:%lli] (end=%lli).\n",
tid, seq_num, (*inst_iter)->seqNum);
FullO3CPU<Impl>::squashInstIt(const ListIt &instIt, const unsigned &tid)
{
if ((*instIt)->threadNumber == tid) {
- DPRINTF(FullCPU, "FullCPU: Squashing instruction, "
+ DPRINTF(O3CPU, "Squashing instruction, "
"[tid:%i] [sn:%lli] PC %#x\n",
(*instIt)->threadNumber,
(*instIt)->seqNum,
FullO3CPU<Impl>::cleanUpRemovedInsts()
{
while (!removeList.empty()) {
- DPRINTF(FullCPU, "FullCPU: Removing instruction, "
+ DPRINTF(O3CPU, "Removing instruction, "
"[tid:%i] [sn:%lli] PC %#x\n",
(*removeList.front())->threadNumber,
(*removeList.front())->seqNum,
}
// Forward declaration of FullO3CPU.
-template class FullO3CPU<AlphaSimpleImpl>;
+template class FullO3CPU<O3CPUImpl>;