summaryrefslogtreecommitdiff
path: root/src/cpu/o3/cpu.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/cpu/o3/cpu.cc')
-rw-r--r--src/cpu/o3/cpu.cc132
1 files changed, 88 insertions, 44 deletions
diff --git a/src/cpu/o3/cpu.cc b/src/cpu/o3/cpu.cc
index f5aa9f712..e50741ec0 100644
--- a/src/cpu/o3/cpu.cc
+++ b/src/cpu/o3/cpu.cc
@@ -143,6 +143,8 @@ FullO3CPU<Impl>::FullO3CPU(DerivO3CPUParams *params)
dtb(params->dtb),
tickEvent([this]{ tick(); }, "FullO3CPU tick",
false, Event::CPU_Tick_Pri),
+ threadExitEvent([this]{ exitThreads(); }, "FullO3CPU exit threads",
+ false, Event::CPU_Exit_Pri),
#ifndef NDEBUG
instcount(0),
#endif
@@ -810,7 +812,7 @@ void
FullO3CPU<Impl>::haltContext(ThreadID tid)
{
//For now, this is the same as deallocate
- DPRINTF(O3CPU,"[tid:%i]: Halt Context called. Deallocating", tid);
+ DPRINTF(O3CPU,"[tid:%i]: Halt Context called. Deallocating\n", tid);
assert(!switchedOut());
deactivateThread(tid);
@@ -886,51 +888,20 @@ FullO3CPU<Impl>::removeThread(ThreadID tid)
// here to alleviate the case for double-freeing registers
// in SMT workloads.
- // Unbind Int Regs from Rename Map
- for (RegId reg_id(IntRegClass, 0); reg_id.index() < TheISA::NumIntRegs;
- reg_id.index()++) {
- PhysRegIdPtr phys_reg = renameMap[tid].lookup(reg_id);
- scoreboard.unsetReg(phys_reg);
- freeList.addReg(phys_reg);
- }
-
- // Unbind Float Regs from Rename Map
- for (RegId reg_id(FloatRegClass, 0); reg_id.index() < TheISA::NumFloatRegs;
- reg_id.index()++) {
- PhysRegIdPtr phys_reg = renameMap[tid].lookup(reg_id);
- scoreboard.unsetReg(phys_reg);
- freeList.addReg(phys_reg);
- }
-
- // Unbind Float Regs from Rename Map
- for (unsigned preg = 0; preg < TheISA::NumVecPredRegs; preg++) {
- PhysRegIdPtr phys_reg = renameMap[tid].lookup(
- RegId(VecPredRegClass, preg));
- scoreboard.unsetReg(phys_reg);
- freeList.addReg(phys_reg);
- }
-
- // Unbind condition-code Regs from Rename Map
- for (RegId reg_id(CCRegClass, 0); reg_id.index() < TheISA::NumCCRegs;
- reg_id.index()++) {
- PhysRegIdPtr phys_reg = renameMap[tid].lookup(reg_id);
- scoreboard.unsetReg(phys_reg);
- freeList.addReg(phys_reg);
- }
-
- // Squash Throughout Pipeline
- DynInstPtr inst = commit.rob->readHeadInst(tid);
- InstSeqNum squash_seq_num = inst->seqNum;
- fetch.squash(0, squash_seq_num, inst, tid);
- decode.squash(tid);
- rename.squash(squash_seq_num, tid);
- iew.squash(tid);
- iew.ldstQueue.squash(squash_seq_num, tid);
- commit.rob->squash(squash_seq_num, tid);
-
-
+ // clear all thread-specific states in each stage of the pipeline
+ // since this thread is going to be completely removed from the CPU
+ commit.clearStates(tid);
+ fetch.clearStates(tid);
+ decode.clearStates(tid);
+ rename.clearStates(tid);
+ iew.clearStates(tid);
+
+ // at this step, all instructions in the pipeline should be already
+ // either committed successfully or squashed. All thread-specific
+ // queues in the pipeline must be empty.
assert(iew.instQueue.getCount(tid) == 0);
assert(iew.ldstQueue.getCount(tid) == 0);
+ assert(commit.rob->isEmpty(tid));
// Reset ROB/IQ/LSQ Entries
@@ -1884,5 +1855,78 @@ FullO3CPU<Impl>::updateThreadPriority()
}
}
+template <class Impl>
+void
+FullO3CPU<Impl>::addThreadToExitingList(ThreadID tid)
+{
+ DPRINTF(O3CPU, "Thread %d is inserted to exitingThreads list\n", tid);
+
+ // make sure the thread is Active
+ assert(std::find(activeThreads.begin(), activeThreads.end(), tid)
+ != activeThreads.end());
+
+ // make sure the thread has not been added to the list yet
+ assert(exitingThreads.count(tid) == 0);
+
+ // add the thread to exitingThreads list to mark that this thread is
+ // trying to exit. The boolean value in the pair denotes if a thread is
+ // ready to exit. The thread is not ready to exit until the corresponding
+ // exit trap event is processed in the future. Until then, it'll be still
+ // an active thread that is trying to exit.
+ exitingThreads.emplace(std::make_pair(tid, false));
+}
+
+template <class Impl>
+bool
+FullO3CPU<Impl>::isThreadExiting(ThreadID tid) const
+{
+ return exitingThreads.count(tid) == 1;
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::scheduleThreadExitEvent(ThreadID tid)
+{
+ assert(exitingThreads.count(tid) == 1);
+
+ // exit trap event has been processed. Now, the thread is ready to exit
+ // and be removed from the CPU.
+ exitingThreads[tid] = true;
+
+ // we schedule a threadExitEvent in the next cycle to properly clean
+ // up the thread's states in the pipeline. threadExitEvent has lower
+ // priority than tickEvent, so the cleanup will happen at the very end
+ // of the next cycle after all pipeline stages complete their operations.
+ // We want all stages to complete squashing instructions before doing
+ // the cleanup.
+ if (!threadExitEvent.scheduled()) {
+ schedule(threadExitEvent, nextCycle());
+ }
+}
+
+template <class Impl>
+void
+FullO3CPU<Impl>::exitThreads()
+{
+ // there must be at least one thread trying to exit
+ assert(exitingThreads.size() > 0);
+
+ // terminate all threads that are ready to exit
+ auto it = exitingThreads.begin();
+ while (it != exitingThreads.end()) {
+ ThreadID thread_id = it->first;
+ bool readyToExit = it->second;
+
+ if (readyToExit) {
+ DPRINTF(O3CPU, "Exiting thread %d\n", thread_id);
+ haltContext(thread_id);
+ tcBase(thread_id)->setStatus(ThreadContext::Halted);
+ it = exitingThreads.erase(it);
+ } else {
+ it++;
+ }
+ }
+}
+
// Forward declaration of FullO3CPU.
template class FullO3CPU<O3CPUImpl>;