/*
+ * Copyright 2014 Google, Inc.
+ * Copyright (c) 2010-2014 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2004-2006 The Regents of The University of Michigan
* All rights reserved.
*
* Authors: Kevin Lim
* Korey Sewell
*/
-
-#include "config/full_system.hh"
-#include "config/use_checker.hh"
+#ifndef __CPU_O3_COMMIT_IMPL_HH__
+#define __CPU_O3_COMMIT_IMPL_HH__
#include <algorithm>
+#include <set>
#include <string>
#include "arch/utility.hh"
#include "base/loader/symtab.hh"
-#include "base/timebuf.hh"
-#include "cpu/exetrace.hh"
+#include "base/cp_annotate.hh"
+#include "config/the_isa.hh"
+#include "cpu/checker/cpu.hh"
#include "cpu/o3/commit.hh"
#include "cpu/o3/thread_state.hh"
-
-#if USE_CHECKER
-#include "cpu/checker/cpu.hh"
-#endif
+#include "cpu/base.hh"
+#include "cpu/exetrace.hh"
+#include "cpu/timebuf.hh"
+#include "debug/Activity.hh"
+#include "debug/Commit.hh"
+#include "debug/CommitRate.hh"
+#include "debug/Drain.hh"
+#include "debug/ExecFaulting.hh"
+#include "debug/O3PipeView.hh"
+#include "params/DerivO3CPU.hh"
+#include "sim/faults.hh"
+#include "sim/full_system.hh"
+
+using namespace std;
template <class Impl>
DefaultCommit<Impl>::TrapEvent::TrapEvent(DefaultCommit<Impl> *_commit,
- unsigned _tid)
- : Event(&mainEventQueue, CPU_Tick_Pri), commit(_commit), tid(_tid)
+ ThreadID _tid)
+ : Event(CPU_Tick_Pri, AutoDelete), commit(_commit), tid(_tid)
{
- this->setFlags(Event::AutoDelete);
}
template <class Impl>
template <class Impl>
const char *
-DefaultCommit<Impl>::TrapEvent::description()
+DefaultCommit<Impl>::TrapEvent::description() const
{
return "Trap";
}
template <class Impl>
-DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, Params *params)
+DefaultCommit<Impl>::DefaultCommit(O3CPU *_cpu, DerivO3CPUParams *params)
: cpu(_cpu),
- squashCounter(0),
iewToCommitDelay(params->iewToCommitDelay),
commitToIEWDelay(params->commitToIEWDelay),
renameToROBDelay(params->renameToROBDelay),
fetchToCommitDelay(params->commitToFetchDelay),
renameWidth(params->renameWidth),
commitWidth(params->commitWidth),
- numThreads(params->numberOfThreads),
+ numThreads(params->numThreads),
drainPending(false),
- switchedOut(false),
- trapLatency(params->trapLatency)
+ drainImminent(false),
+ trapLatency(params->trapLatency),
+ canHandleInterrupts(true),
+ avoidQuiesceLiveLock(false)
{
+ if (commitWidth > Impl::MaxWidth)
+ fatal("commitWidth (%d) is larger than compiled limit (%d),\n"
+ "\tincrease MaxWidth in src/cpu/o3/impl.hh\n",
+ commitWidth, static_cast<int>(Impl::MaxWidth));
+
_status = Active;
_nextStatus = Inactive;
std::string policy = params->smtCommitPolicy;
if (policy == "aggressive"){
commitPolicy = Aggressive;
- DPRINTF(Commit,"Commit Policy set to Aggressive.");
+ DPRINTF(Commit,"Commit Policy set to Aggressive.\n");
} else if (policy == "roundrobin"){
commitPolicy = RoundRobin;
//Set-Up Priority List
- for (int tid=0; tid < numThreads; tid++) {
+ for (ThreadID tid = 0; tid < numThreads; tid++) {
priority_list.push_back(tid);
}
- DPRINTF(Commit,"Commit Policy set to Round Robin.");
+ DPRINTF(Commit,"Commit Policy set to Round Robin.\n");
} else if (policy == "oldestready"){
commitPolicy = OldestReady;
"RoundRobin,OldestReady}");
}
- for (int i=0; i < numThreads; i++) {
- commitStatus[i] = Idle;
- changedROBNumEntries[i] = false;
- checkEmptyROB[i] = false;
- trapInFlight[i] = false;
- committedStores[i] = false;
- trapSquash[i] = false;
- tcSquash[i] = false;
- microPC[i] = nextMicroPC[i] = PC[i] = nextPC[i] = nextNPC[i] = 0;
+ for (ThreadID tid = 0; tid < numThreads; tid++) {
+ commitStatus[tid] = Idle;
+ changedROBNumEntries[tid] = false;
+ checkEmptyROB[tid] = false;
+ trapInFlight[tid] = false;
+ committedStores[tid] = false;
+ trapSquash[tid] = false;
+ tcSquash[tid] = false;
+ pc[tid].set(0);
+ lastCommitedSeqNum[tid] = 0;
+ squashAfterInst[tid] = NULL;
}
-#if FULL_SYSTEM
interrupt = NoFault;
-#endif
}
template <class Impl>
return cpu->name() + ".commit";
}
+template <class Impl>
+void
+DefaultCommit<Impl>::regProbePoints()
+{
+ ppCommit = new ProbePointArg<DynInstPtr>(cpu->getProbeManager(), "Commit");
+ ppCommitStall = new ProbePointArg<DynInstPtr>(cpu->getProbeManager(), "CommitStall");
+ ppSquash = new ProbePointArg<DynInstPtr>(cpu->getProbeManager(), "Squash");
+}
+
template <class Impl>
void
DefaultCommit<Impl>::regStats()
{
using namespace Stats;
- commitCommittedInsts
- .name(name() + ".commitCommittedInsts")
- .desc("The number of committed instructions")
- .prereq(commitCommittedInsts);
commitSquashedInsts
.name(name() + ".commitSquashedInsts")
.desc("The number of squashed insts skipped by commit")
.prereq(commitSquashedInsts);
- commitSquashEvents
- .name(name() + ".commitSquashEvents")
- .desc("The number of times commit is told to squash")
- .prereq(commitSquashEvents);
+
commitNonSpecStalls
.name(name() + ".commitNonSpecStalls")
.desc("The number of times commit has been forced to stall to "
"communicate backwards")
.prereq(commitNonSpecStalls);
+
branchMispredicts
.name(name() + ".branchMispredicts")
.desc("The number of times a branch was mispredicted")
.prereq(branchMispredicts);
+
numCommittedDist
.init(0,commitWidth,1)
- .name(name() + ".COM:committed_per_cycle")
+ .name(name() + ".committed_per_cycle")
.desc("Number of insts commited each cycle")
.flags(Stats::pdf)
;
- statComInst
- .init(cpu->number_of_threads)
- .name(name() + ".COM:count")
+ instsCommitted
+ .init(cpu->numThreads)
+ .name(name() + ".committedInsts")
.desc("Number of instructions committed")
.flags(total)
;
+ opsCommitted
+ .init(cpu->numThreads)
+ .name(name() + ".committedOps")
+ .desc("Number of ops (including micro ops) committed")
+ .flags(total)
+ ;
+
statComSwp
- .init(cpu->number_of_threads)
- .name(name() + ".COM:swp_count")
+ .init(cpu->numThreads)
+ .name(name() + ".swp_count")
.desc("Number of s/w prefetches committed")
.flags(total)
;
statComRefs
- .init(cpu->number_of_threads)
- .name(name() + ".COM:refs")
+ .init(cpu->numThreads)
+ .name(name() + ".refs")
.desc("Number of memory references committed")
.flags(total)
;
statComLoads
- .init(cpu->number_of_threads)
- .name(name() + ".COM:loads")
+ .init(cpu->numThreads)
+ .name(name() + ".loads")
.desc("Number of loads committed")
.flags(total)
;
statComMembars
- .init(cpu->number_of_threads)
- .name(name() + ".COM:membars")
+ .init(cpu->numThreads)
+ .name(name() + ".membars")
.desc("Number of memory barriers committed")
.flags(total)
;
statComBranches
- .init(cpu->number_of_threads)
- .name(name() + ".COM:branches")
+ .init(cpu->numThreads)
+ .name(name() + ".branches")
.desc("Number of branches committed")
.flags(total)
;
- commitEligible
- .init(cpu->number_of_threads)
- .name(name() + ".COM:bw_limited")
- .desc("number of insts not committed due to BW limits")
+ statComFloating
+ .init(cpu->numThreads)
+ .name(name() + ".fp_insts")
+ .desc("Number of committed floating point instructions.")
+ .flags(total)
+ ;
+
+ statComInteger
+ .init(cpu->numThreads)
+ .name(name()+".int_insts")
+ .desc("Number of committed integer instructions.")
.flags(total)
;
+ statComFunctionCalls
+ .init(cpu->numThreads)
+ .name(name()+".function_calls")
+ .desc("Number of function calls committed.")
+ .flags(total)
+ ;
+
+ statCommittedInstType
+ .init(numThreads,Enums::Num_OpClass)
+ .name(name() + ".op_class")
+ .desc("Class of committed instruction")
+ .flags(total | pdf | dist)
+ ;
+ statCommittedInstType.ysubnames(Enums::OpClassStrings);
+
commitEligibleSamples
- .name(name() + ".COM:bw_lim_events")
+ .name(name() + ".bw_lim_events")
.desc("number cycles where commit BW limit reached")
;
}
template<class Impl>
void
-DefaultCommit<Impl>::setActiveThreads(std::list<unsigned> *at_ptr)
+DefaultCommit<Impl>::setActiveThreads(list<ThreadID> *at_ptr)
{
activeThreads = at_ptr;
}
void
DefaultCommit<Impl>::setRenameMap(RenameMap rm_ptr[])
{
- for (int i=0; i < numThreads; i++) {
- renameMap[i] = &rm_ptr[i];
- }
+ for (ThreadID tid = 0; tid < numThreads; tid++)
+ renameMap[tid] = &rm_ptr[tid];
}
template <class Impl>
template <class Impl>
void
-DefaultCommit<Impl>::initStage()
+DefaultCommit<Impl>::startupStage()
{
rob->setActiveThreads(activeThreads);
rob->resetEntries();
// Broadcast the number of free entries.
- for (int i=0; i < numThreads; i++) {
- toIEW->commitInfo[i].usedROB = true;
- toIEW->commitInfo[i].freeROBEntries = rob->numFreeEntries(i);
- toIEW->commitInfo[i].emptyROB = true;
+ for (ThreadID tid = 0; tid < numThreads; tid++) {
+ toIEW->commitInfo[tid].usedROB = true;
+ toIEW->commitInfo[tid].freeROBEntries = rob->numFreeEntries(tid);
+ toIEW->commitInfo[tid].emptyROB = true;
}
// Commit must broadcast the number of free entries it has at the
cpu->activateStage(O3CPU::CommitIdx);
cpu->activityThisCycle();
- trapLatency = cpu->ticks(trapLatency);
}
template <class Impl>
-bool
+void
DefaultCommit<Impl>::drain()
{
drainPending = true;
-
- return false;
}
template <class Impl>
void
-DefaultCommit<Impl>::switchOut()
+DefaultCommit<Impl>::drainResume()
{
- switchedOut = true;
drainPending = false;
- rob->switchOut();
+ drainImminent = false;
}
template <class Impl>
void
-DefaultCommit<Impl>::resume()
+DefaultCommit<Impl>::drainSanityCheck() const
{
- drainPending = false;
+ assert(isDrained());
+ rob->drainSanityCheck();
+}
+
+template <class Impl>
+bool
+DefaultCommit<Impl>::isDrained() const
+{
+ /* Make sure no one is executing microcode. There are two reasons
+ * for this:
+ * - Hardware virtualized CPUs can't switch into the middle of a
+ * microcode sequence.
+ * - The current fetch implementation will most likely get very
+ * confused if it tries to start fetching an instruction that
+ * is executing in the middle of a ucode sequence that changes
+ * address mappings. This can happen on for example x86.
+ */
+ for (ThreadID tid = 0; tid < numThreads; tid++) {
+ if (pc[tid].microPC() != 0)
+ return false;
+ }
+
+ /* Make sure that all instructions have finished committing before
+ * declaring the system as drained. We want the pipeline to be
+ * completely empty when we declare the CPU to be drained. This
+ * makes debugging easier since CPU handover and restoring from a
+ * checkpoint with a different CPU should have the same timing.
+ */
+ return rob->isEmpty() &&
+ interrupt == NoFault;
}
template <class Impl>
void
DefaultCommit<Impl>::takeOverFrom()
{
- switchedOut = false;
_status = Active;
_nextStatus = Inactive;
- for (int i=0; i < numThreads; i++) {
- commitStatus[i] = Idle;
- changedROBNumEntries[i] = false;
- trapSquash[i] = false;
- tcSquash[i] = false;
+ for (ThreadID tid = 0; tid < numThreads; tid++) {
+ commitStatus[tid] = Idle;
+ changedROBNumEntries[tid] = false;
+ trapSquash[tid] = false;
+ tcSquash[tid] = false;
+ squashAfterInst[tid] = NULL;
}
- squashCounter = 0;
rob->takeOverFrom();
}
+template <class Impl>
+void
+DefaultCommit<Impl>::deactivateThread(ThreadID tid)
+{
+ list<ThreadID>::iterator thread_it = std::find(priority_list.begin(),
+ priority_list.end(), tid);
+
+ if (thread_it != priority_list.end()) {
+ priority_list.erase(thread_it);
+ }
+}
+
+
template <class Impl>
void
DefaultCommit<Impl>::updateStatus()
{
// reset ROB changed variable
- std::list<unsigned>::iterator threads = activeThreads->begin();
- std::list<unsigned>::iterator end = activeThreads->end();
+ list<ThreadID>::iterator threads = activeThreads->begin();
+ list<ThreadID>::iterator end = activeThreads->end();
while (threads != end) {
- unsigned tid = *threads++;
+ ThreadID tid = *threads++;
changedROBNumEntries[tid] = false;
_status = _nextStatus;
}
-template <class Impl>
-void
-DefaultCommit<Impl>::setNextStatus()
-{
- int squashes = 0;
-
- std::list<unsigned>::iterator threads = activeThreads->begin();
- std::list<unsigned>::iterator end = activeThreads->end();
-
- while (threads != end) {
- unsigned tid = *threads++;
-
- if (commitStatus[tid] == ROBSquashing) {
- squashes++;
- }
- }
-
- squashCounter = squashes;
-
- // If commit is currently squashing, then it will have activity for the
- // next cycle. Set its next status as active.
- if (squashCounter) {
- _nextStatus = Active;
- }
-}
-
template <class Impl>
bool
DefaultCommit<Impl>::changedROBEntries()
{
- std::list<unsigned>::iterator threads = activeThreads->begin();
- std::list<unsigned>::iterator end = activeThreads->end();
+ list<ThreadID>::iterator threads = activeThreads->begin();
+ list<ThreadID>::iterator end = activeThreads->end();
while (threads != end) {
- unsigned tid = *threads++;
+ ThreadID tid = *threads++;
if (changedROBNumEntries[tid]) {
return true;
}
template <class Impl>
-unsigned
-DefaultCommit<Impl>::numROBFreeEntries(unsigned tid)
+size_t
+DefaultCommit<Impl>::numROBFreeEntries(ThreadID tid)
{
return rob->numFreeEntries(tid);
}
template <class Impl>
void
-DefaultCommit<Impl>::generateTrapEvent(unsigned tid)
+DefaultCommit<Impl>::generateTrapEvent(ThreadID tid, Fault inst_fault)
{
DPRINTF(Commit, "Generating trap event for [tid:%i]\n", tid);
TrapEvent *trap = new TrapEvent(this, tid);
- trap->schedule(curTick + trapLatency);
+ Cycles latency = dynamic_pointer_cast<SyscallRetryFault>(inst_fault) ?
+ cpu->syscallRetryLatency : trapLatency;
+
+ cpu->schedule(trap, cpu->clockEdge(latency));
trapInFlight[tid] = true;
+ thread[tid]->trapPending = true;
}
template <class Impl>
void
-DefaultCommit<Impl>::generateTCEvent(unsigned tid)
+DefaultCommit<Impl>::generateTCEvent(ThreadID tid)
{
assert(!trapInFlight[tid]);
DPRINTF(Commit, "Generating TC squash event for [tid:%i]\n", tid);
template <class Impl>
void
-DefaultCommit<Impl>::squashAll(unsigned tid)
+DefaultCommit<Impl>::squashAll(ThreadID tid)
{
// If we want to include the squashing instruction in the squash,
// then use one older sequence number.
// Hopefully this doesn't mess things up. Basically I want to squash
// all instructions of this thread.
- InstSeqNum squashed_inst = rob->isEmpty() ?
- 0 : rob->readHeadInst(tid)->seqNum - 1;
+ InstSeqNum squashed_inst = rob->isEmpty(tid) ?
+ lastCommitedSeqNum[tid] : rob->readHeadInst(tid)->seqNum - 1;
// All younger instructions will be squashed. Set the sequence
// number as the youngest instruction in the ROB (0 in this case.
// Hopefully nothing breaks.)
- youngestSeqNum[tid] = 0;
+ youngestSeqNum[tid] = lastCommitedSeqNum[tid];
rob->squash(squashed_inst, tid);
changedROBNumEntries[tid] = true;
// the ROB is in the process of squashing.
toIEW->commitInfo[tid].robSquashing = true;
- toIEW->commitInfo[tid].branchMispredict = false;
+ toIEW->commitInfo[tid].mispredictInst = NULL;
+ toIEW->commitInfo[tid].squashInst = NULL;
- toIEW->commitInfo[tid].nextPC = PC[tid];
- toIEW->commitInfo[tid].nextNPC = nextPC[tid];
- toIEW->commitInfo[tid].nextMicroPC = nextMicroPC[tid];
+ toIEW->commitInfo[tid].pc = pc[tid];
}
template <class Impl>
void
-DefaultCommit<Impl>::squashFromTrap(unsigned tid)
+DefaultCommit<Impl>::squashFromTrap(ThreadID tid)
{
squashAll(tid);
- DPRINTF(Commit, "Squashing from trap, restarting at PC %#x\n", PC[tid]);
+ DPRINTF(Commit, "Squashing from trap, restarting at PC %s\n", pc[tid]);
thread[tid]->trapPending = false;
- thread[tid]->inSyscall = false;
+ thread[tid]->noSquashFromTC = false;
trapInFlight[tid] = false;
trapSquash[tid] = false;
template <class Impl>
void
-DefaultCommit<Impl>::squashFromTC(unsigned tid)
+DefaultCommit<Impl>::squashFromTC(ThreadID tid)
{
squashAll(tid);
- DPRINTF(Commit, "Squashing from TC, restarting at PC %#x\n", PC[tid]);
+ DPRINTF(Commit, "Squashing from TC, restarting at PC %s\n", pc[tid]);
- thread[tid]->inSyscall = false;
+ thread[tid]->noSquashFromTC = false;
assert(!thread[tid]->trapPending);
commitStatus[tid] = ROBSquashing;
tcSquash[tid] = false;
}
+template <class Impl>
+void
+DefaultCommit<Impl>::squashFromSquashAfter(ThreadID tid)
+{
+ DPRINTF(Commit, "Squashing after squash after request, "
+ "restarting at PC %s\n", pc[tid]);
+
+ squashAll(tid);
+ // Make sure to inform the fetch stage of which instruction caused
+ // the squash. It'll try to re-fetch an instruction executing in
+ // microcode unless this is set.
+ toIEW->commitInfo[tid].squashInst = squashAfterInst[tid];
+ squashAfterInst[tid] = NULL;
+
+ commitStatus[tid] = ROBSquashing;
+ cpu->activityThisCycle();
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::squashAfter(ThreadID tid, DynInstPtr &head_inst)
+{
+ DPRINTF(Commit, "Executing squash after for [tid:%i] inst [sn:%lli]\n",
+ tid, head_inst->seqNum);
+
+ assert(!squashAfterInst[tid] || squashAfterInst[tid] == head_inst);
+ commitStatus[tid] = SquashAfterPending;
+ squashAfterInst[tid] = head_inst;
+}
+
template <class Impl>
void
DefaultCommit<Impl>::tick()
wroteToTimeBuffer = false;
_nextStatus = Inactive;
- if (drainPending && rob->isEmpty() && !iewStage->hasStoresToWB()) {
- cpu->signalDrained();
- drainPending = false;
- return;
- }
-
if (activeThreads->empty())
return;
- std::list<unsigned>::iterator threads = activeThreads->begin();
- std::list<unsigned>::iterator end = activeThreads->end();
+ list<ThreadID>::iterator threads = activeThreads->begin();
+ list<ThreadID>::iterator end = activeThreads->end();
// Check if any of the threads are done squashing. Change the
// status if they are done.
while (threads != end) {
- unsigned tid = *threads++;
+ ThreadID tid = *threads++;
// Clear the bit saying if the thread has committed stores
// this cycle.
threads = activeThreads->begin();
while (threads != end) {
- unsigned tid = *threads++;
+ ThreadID tid = *threads++;
if (!rob->isEmpty(tid) && rob->readHeadInst(tid)->readyToCommit()) {
// The ROB has more instructions it can commit. Its next status
DynInstPtr inst = rob->readHeadInst(tid);
- DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %#x is head of"
+ DPRINTF(Commit,"[tid:%i]: Instruction [sn:%lli] PC %s is head of"
" ROB and ready to commit\n",
- tid, inst->seqNum, inst->readPC());
+ tid, inst->seqNum, inst->pcState());
} else if (!rob->isEmpty(tid)) {
DynInstPtr inst = rob->readHeadInst(tid);
+ ppCommitStall->notify(inst);
+
DPRINTF(Commit,"[tid:%i]: Can't commit, Instruction [sn:%lli] PC "
- "%#x is head of ROB and not ready\n",
- tid, inst->seqNum, inst->readPC());
+ "%s is head of ROB and not ready\n",
+ tid, inst->seqNum, inst->pcState());
}
DPRINTF(Commit, "[tid:%i]: ROB has %d insts & %d free entries.\n",
updateStatus();
}
-#if FULL_SYSTEM
template <class Impl>
void
DefaultCommit<Impl>::handleInterrupt()
{
- if (interrupt != NoFault) {
- // Wait until the ROB is empty and all stores have drained in
- // order to enter the interrupt.
- if (rob->isEmpty() && !iewStage->hasStoresToWB()) {
- // Squash or record that I need to squash this cycle if
- // an interrupt needed to be handled.
- DPRINTF(Commit, "Interrupt detected.\n");
+ // Verify that we still have an interrupt to handle
+ if (!cpu->checkInterrupts(cpu->tcBase(0))) {
+ DPRINTF(Commit, "Pending interrupt is cleared by master before "
+ "it got handled. Restart fetching from the orig path.\n");
+ toIEW->commitInfo[0].clearInterrupt = true;
+ interrupt = NoFault;
+ avoidQuiesceLiveLock = true;
+ return;
+ }
- // Clear the interrupt now that it's going to be handled
- toIEW->commitInfo[0].clearInterrupt = true;
+ // Wait until all in flight instructions are finished before enterring
+ // the interrupt.
+ if (canHandleInterrupts && cpu->instList.empty()) {
+ // Squash or record that I need to squash this cycle if
+ // an interrupt needed to be handled.
+ DPRINTF(Commit, "Interrupt detected.\n");
- assert(!thread[0]->inSyscall);
- thread[0]->inSyscall = true;
+ // Clear the interrupt now that it's going to be handled
+ toIEW->commitInfo[0].clearInterrupt = true;
- // CPU will handle interrupt.
- cpu->processInterrupts(interrupt);
+ assert(!thread[0]->noSquashFromTC);
+ thread[0]->noSquashFromTC = true;
- thread[0]->inSyscall = false;
+ if (cpu->checker) {
+ cpu->checker->handlePendingInt();
+ }
- commitStatus[0] = TrapPending;
+ // CPU will handle interrupt. Note that we ignore the local copy of
+ // interrupt. This is because the local copy may no longer be the
+ // interrupt that the interrupt controller thinks is being handled.
+ cpu->processInterrupts(cpu->getInterrupts());
- // Generate trap squash event.
- generateTrapEvent(0);
+ thread[0]->noSquashFromTC = false;
- interrupt = NoFault;
- } else {
- DPRINTF(Commit, "Interrupt pending, waiting for ROB to empty.\n");
- }
- } else if (commitStatus[0] != TrapPending &&
- cpu->check_interrupts(cpu->tcBase(0)) &&
- !trapSquash[0] &&
- !tcSquash[0]) {
- // Process interrupts if interrupts are enabled, not in PAL
- // mode, and no other traps or external squashes are currently
- // pending.
- // @todo: Allow other threads to handle interrupts.
-
- // Get any interrupt that happened
- interrupt = cpu->getInterrupts();
-
- if (interrupt != NoFault) {
- // Tell fetch that there is an interrupt pending. This
- // will make fetch wait until it sees a non PAL-mode PC,
- // at which point it stops fetching instructions.
- toIEW->commitInfo[0].interruptPending = true;
- }
+ commitStatus[0] = TrapPending;
+
+ interrupt = NoFault;
+
+ // Generate trap squash event.
+ generateTrapEvent(0, interrupt);
+
+ avoidQuiesceLiveLock = false;
+ } else {
+ DPRINTF(Commit, "Interrupt pending: instruction is %sin "
+ "flight, ROB is %sempty\n",
+ canHandleInterrupts ? "not " : "",
+ cpu->instList.empty() ? "" : "not " );
}
}
-#endif // FULL_SYSTEM
template <class Impl>
void
-DefaultCommit<Impl>::commit()
+DefaultCommit<Impl>::propagateInterrupt()
{
+ // Don't propagate intterupts if we are currently handling a trap or
+ // in draining and the last observable instruction has been committed.
+ if (commitStatus[0] == TrapPending || interrupt || trapSquash[0] ||
+ tcSquash[0] || drainImminent)
+ return;
+
+ // Process interrupts if interrupts are enabled, not in PAL
+ // mode, and no other traps or external squashes are currently
+ // pending.
+ // @todo: Allow other threads to handle interrupts.
+
+ // Get any interrupt that happened
+ interrupt = cpu->getInterrupts();
-#if FULL_SYSTEM
- // Check for any interrupt, and start processing it. Or if we
- // have an outstanding interrupt and are at a point when it is
- // valid to take an interrupt, process it.
- if (cpu->check_interrupts(cpu->tcBase(0))) {
- handleInterrupt();
+ // Tell fetch that there is an interrupt pending. This
+ // will make fetch wait until it sees a non PAL-mode PC,
+ // at which point it stops fetching instructions.
+ if (interrupt != NoFault)
+ toIEW->commitInfo[0].interruptPending = true;
+}
+
+template <class Impl>
+void
+DefaultCommit<Impl>::commit()
+{
+ if (FullSystem) {
+ // Check if we have a interrupt and get read to handle it
+ if (cpu->checkInterrupts(cpu->tcBase(0)))
+ propagateInterrupt();
}
-#endif // FULL_SYSTEM
////////////////////////////////////
// Check for any possible squashes, handle them first
////////////////////////////////////
- std::list<unsigned>::iterator threads = activeThreads->begin();
- std::list<unsigned>::iterator end = activeThreads->end();
+ list<ThreadID>::iterator threads = activeThreads->begin();
+ list<ThreadID>::iterator end = activeThreads->end();
+
+ int num_squashing_threads = 0;
while (threads != end) {
- unsigned tid = *threads++;
+ ThreadID tid = *threads++;
// Not sure which one takes priority. I think if we have
// both, that's a bad sign.
- if (trapSquash[tid] == true) {
+ if (trapSquash[tid]) {
assert(!tcSquash[tid]);
squashFromTrap(tid);
- } else if (tcSquash[tid] == true) {
+ } else if (tcSquash[tid]) {
assert(commitStatus[tid] != TrapPending);
squashFromTC(tid);
+ } else if (commitStatus[tid] == SquashAfterPending) {
+ // A squash from the previous cycle of the commit stage (i.e.,
+ // commitInsts() called squashAfter) is pending. Squash the
+ // thread now.
+ squashFromSquashAfter(tid);
}
// Squashed sequence number must be older than youngest valid
commitStatus[tid] != TrapPending &&
fromIEW->squashedSeqNum[tid] <= youngestSeqNum[tid]) {
- DPRINTF(Commit, "[tid:%i]: Squashing due to PC %#x [sn:%i]\n",
+ if (fromIEW->mispredictInst[tid]) {
+ DPRINTF(Commit,
+ "[tid:%i]: Squashing due to branch mispred PC:%#x [sn:%i]\n",
tid,
- fromIEW->mispredPC[tid],
+ fromIEW->mispredictInst[tid]->instAddr(),
fromIEW->squashedSeqNum[tid]);
+ } else {
+ DPRINTF(Commit,
+ "[tid:%i]: Squashing due to order violation [sn:%i]\n",
+ tid, fromIEW->squashedSeqNum[tid]);
+ }
DPRINTF(Commit, "[tid:%i]: Redirecting to PC %#x\n",
tid,
- fromIEW->nextPC[tid]);
+ fromIEW->pc[tid].nextInstAddr());
commitStatus[tid] = ROBSquashing;
// then use one older sequence number.
InstSeqNum squashed_inst = fromIEW->squashedSeqNum[tid];
- if (fromIEW->includeSquashInst[tid] == true) {
+ if (fromIEW->includeSquashInst[tid]) {
squashed_inst--;
}
// the ROB is in the process of squashing.
toIEW->commitInfo[tid].robSquashing = true;
- toIEW->commitInfo[tid].branchMispredict =
- fromIEW->branchMispredict[tid];
-
+ toIEW->commitInfo[tid].mispredictInst =
+ fromIEW->mispredictInst[tid];
toIEW->commitInfo[tid].branchTaken =
fromIEW->branchTaken[tid];
-
- toIEW->commitInfo[tid].nextPC = fromIEW->nextPC[tid];
- toIEW->commitInfo[tid].nextNPC = fromIEW->nextNPC[tid];
- toIEW->commitInfo[tid].nextMicroPC = fromIEW->nextMicroPC[tid];
-
- toIEW->commitInfo[tid].mispredPC = fromIEW->mispredPC[tid];
-
- if (toIEW->commitInfo[tid].branchMispredict) {
+ toIEW->commitInfo[tid].squashInst =
+ rob->findInst(tid, squashed_inst);
+ if (toIEW->commitInfo[tid].mispredictInst) {
+ if (toIEW->commitInfo[tid].mispredictInst->isUncondCtrl()) {
+ toIEW->commitInfo[tid].branchTaken = true;
+ }
++branchMispredicts;
}
+
+ toIEW->commitInfo[tid].pc = fromIEW->pc[tid];
}
+ if (commitStatus[tid] == ROBSquashing) {
+ num_squashing_threads++;
+ }
}
- setNextStatus();
+ // If commit is currently squashing, then it will have activity for the
+ // next cycle. Set its next status as active.
+ if (num_squashing_threads) {
+ _nextStatus = Active;
+ }
- if (squashCounter != numThreads) {
+ if (num_squashing_threads != numThreads) {
// If we're not currently squashing, then get instructions.
getInsts();
threads = activeThreads->begin();
while (threads != end) {
- unsigned tid = *threads++;
+ ThreadID tid = *threads++;
if (changedROBNumEntries[tid]) {
toIEW->commitInfo[tid].usedROB = true;
// @todo: Make this handle multi-cycle communication between
// commit and IEW.
if (checkEmptyROB[tid] && rob->isEmpty(tid) &&
- !iewStage->hasStoresToWB() && !committedStores[tid]) {
+ !iewStage->hasStoresToWB(tid) && !committedStores[tid]) {
checkEmptyROB[tid] = false;
toIEW->commitInfo[tid].usedROB = true;
toIEW->commitInfo[tid].emptyROB = true;
// Commit as many instructions as possible until the commit bandwidth
// limit is reached, or it becomes impossible to commit any more.
while (num_committed < commitWidth) {
- int commit_thread = getCommittingThread();
+ // Check for any interrupt that we've already squashed for
+ // and start processing it.
+ if (interrupt != NoFault)
+ handleInterrupt();
+
+ ThreadID commit_thread = getCommittingThread();
if (commit_thread == -1 || !rob->isHeadReady(commit_thread))
break;
head_inst = rob->readHeadInst(commit_thread);
- int tid = head_inst->threadNumber;
+ ThreadID tid = head_inst->threadNumber;
assert(tid == commit_thread);
rob->retireHead(commit_thread);
++commitSquashedInsts;
+ // Notify potential listeners that this instruction is squashed
+ ppSquash->notify(head_inst);
// Record that the number of ROB entries has changed.
changedROBNumEntries[tid] = true;
} else {
- PC[tid] = head_inst->readPC();
- nextPC[tid] = head_inst->readNextPC();
- nextNPC[tid] = head_inst->readNextNPC();
- nextMicroPC[tid] = head_inst->readNextMicroPC();
+ pc[tid] = head_inst->pcState();
// Increment the total number of non-speculative instructions
// executed.
if (commit_success) {
++num_committed;
+ statCommittedInstType[tid][head_inst->opClass()]++;
+ ppCommit->notify(head_inst);
changedROBNumEntries[tid] = true;
// Set the doneSeqNum to the youngest committed instruction.
toIEW->commitInfo[tid].doneSeqNum = head_inst->seqNum;
- ++commitCommittedInsts;
+ if (tid == 0) {
+ canHandleInterrupts = (!head_inst->isDelayedCommit()) &&
+ ((THE_ISA != ALPHA_ISA) ||
+ (!(pc[0].instAddr() & 0x3)));
+ }
+
+ // Updates misc. registers.
+ head_inst->updateMiscRegs();
+
+ // Check instruction execution if it successfully commits and
+ // is not carrying a fault.
+ if (cpu->checker) {
+ cpu->checker->verify(head_inst);
+ }
- // To match the old model, don't count nops and instruction
- // prefetches towards the total commit count.
- if (!head_inst->isNop() && !head_inst->isInstPrefetch()) {
- cpu->instDone(tid);
+ cpu->traceFunctions(pc[tid].instAddr());
+
+ TheISA::advancePC(pc[tid], head_inst->staticInst);
+
+ // Keep track of the last sequence number commited
+ lastCommitedSeqNum[tid] = head_inst->seqNum;
+
+ // If this is an instruction that doesn't play nicely with
+ // others squash everything and restart fetch
+ if (head_inst->isSquashAfter())
+ squashAfter(tid, head_inst);
+
+ if (drainPending) {
+ if (pc[tid].microPC() == 0 && interrupt == NoFault &&
+ !thread[tid]->trapPending) {
+ // Last architectually committed instruction.
+ // Squash the pipeline, stall fetch, and use
+ // drainImminent to disable interrupts
+ DPRINTF(Drain, "Draining: %i:%s\n", tid, pc[tid]);
+ squashAfter(tid, head_inst);
+ cpu->commitDrained(tid);
+ drainImminent = true;
+ }
}
- PC[tid] = nextPC[tid];
- nextPC[tid] = nextNPC[tid];
- nextNPC[tid] = nextNPC[tid] + sizeof(TheISA::MachInst);
- microPC[tid] = nextMicroPC[tid];
- nextMicroPC[tid] = microPC[tid] + 1;
-
- int count = 0;
- Addr oldpc;
- // Debug statement. Checks to make sure we're not
- // currently updating state while handling PC events.
- assert(!thread[tid]->inSyscall && !thread[tid]->trapPending);
- do {
- oldpc = PC[tid];
- cpu->system->pcEventQueue.service(thread[tid]->getTC());
- count++;
- } while (oldpc != PC[tid]);
- if (count > 1) {
- DPRINTF(Commit,
- "PC skip function event, stopping commit\n");
- break;
+ bool onInstBoundary = !head_inst->isMicroop() ||
+ head_inst->isLastMicroop() ||
+ !head_inst->isDelayedCommit();
+
+ if (onInstBoundary) {
+ int count = 0;
+ Addr oldpc;
+ // Make sure we're not currently updating state while
+ // handling PC events.
+ assert(!thread[tid]->noSquashFromTC &&
+ !thread[tid]->trapPending);
+ do {
+ oldpc = pc[tid].instAddr();
+ cpu->system->pcEventQueue.service(thread[tid]->getTC());
+ count++;
+ } while (oldpc != pc[tid].instAddr());
+ if (count > 1) {
+ DPRINTF(Commit,
+ "PC skip function event, stopping commit\n");
+ break;
+ }
}
+
+ // Check if an instruction just enabled interrupts and we've
+ // previously had an interrupt pending that was not handled
+ // because interrupts were subsequently disabled before the
+ // pipeline reached a place to handle the interrupt. In that
+ // case squash now to make sure the interrupt is handled.
+ //
+ // If we don't do this, we might end up in a live lock situation
+ if (!interrupt && avoidQuiesceLiveLock &&
+ onInstBoundary && cpu->checkInterrupts(cpu->tcBase(0)))
+ squashAfter(tid, head_inst);
} else {
- DPRINTF(Commit, "Unable to commit head instruction PC:%#x "
+ DPRINTF(Commit, "Unable to commit head instruction PC:%s "
"[tid:%i] [sn:%i].\n",
- head_inst->readPC(), tid ,head_inst->seqNum);
+ head_inst->pcState(), tid ,head_inst->seqNum);
break;
}
}
{
assert(head_inst);
- int tid = head_inst->threadNumber;
+ ThreadID tid = head_inst->threadNumber;
// If the instruction is not executed yet, then it will need extra
// handling. Signal backwards that it should be executed.
// and committed this instruction.
thread[tid]->funcExeInst--;
- if (head_inst->isNonSpeculative() ||
- head_inst->isStoreConditional() ||
- head_inst->isMemBarrier() ||
- head_inst->isWriteBarrier()) {
+ // Make sure we are only trying to commit un-executed instructions we
+ // think are possible.
+ assert(head_inst->isNonSpeculative() || head_inst->isStoreConditional()
+ || head_inst->isMemBarrier() || head_inst->isWriteBarrier() ||
+ (head_inst->isLoad() && head_inst->strictlyOrdered()));
- DPRINTF(Commit, "Encountered a barrier or non-speculative "
- "instruction [sn:%lli] at the head of the ROB, PC %#x.\n",
- head_inst->seqNum, head_inst->readPC());
-
- if (inst_num > 0 || iewStage->hasStoresToWB()) {
- DPRINTF(Commit, "Waiting for all stores to writeback.\n");
- return false;
- }
-
- toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
-
- // Change the instruction so it won't try to commit again until
- // it is executed.
- head_inst->clearCanCommit();
-
- ++commitNonSpecStalls;
+ DPRINTF(Commit, "Encountered a barrier or non-speculative "
+ "instruction [sn:%lli] at the head of the ROB, PC %s.\n",
+ head_inst->seqNum, head_inst->pcState());
+ if (inst_num > 0 || iewStage->hasStoresToWB(tid)) {
+ DPRINTF(Commit, "Waiting for all stores to writeback.\n");
return false;
- } else if (head_inst->isLoad()) {
- if (inst_num > 0 || iewStage->hasStoresToWB()) {
- DPRINTF(Commit, "Waiting for all stores to writeback.\n");
- return false;
- }
-
- assert(head_inst->uncacheable());
- DPRINTF(Commit, "[sn:%lli]: Uncached load, PC %#x.\n",
- head_inst->seqNum, head_inst->readPC());
+ }
- // Send back the non-speculative instruction's sequence
- // number. Tell the lsq to re-execute the load.
- toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
- toIEW->commitInfo[tid].uncached = true;
- toIEW->commitInfo[tid].uncachedLoad = head_inst;
+ toIEW->commitInfo[tid].nonSpecSeqNum = head_inst->seqNum;
- head_inst->clearCanCommit();
+ // Change the instruction so it won't try to commit again until
+ // it is executed.
+ head_inst->clearCanCommit();
- return false;
+ if (head_inst->isLoad() && head_inst->strictlyOrdered()) {
+ DPRINTF(Commit, "[sn:%lli]: Strictly ordered load, PC %s.\n",
+ head_inst->seqNum, head_inst->pcState());
+ toIEW->commitInfo[tid].strictlyOrdered = true;
+ toIEW->commitInfo[tid].strictlyOrderedLoad = head_inst;
} else {
- panic("Trying to commit un-executed instruction "
- "of unknown type!\n");
+ ++commitNonSpecStalls;
}
+
+ return false;
}
if (head_inst->isThreadSync()) {
head_inst->setCompleted();
}
-#if USE_CHECKER
- // Use checker prior to updating anything due to traps or PC
- // based events.
- if (cpu->checker) {
- cpu->checker->verify(head_inst);
- }
-#endif
-
- // DTB will sometimes need the machine instruction for when
- // faults happen. So we will set it here, prior to the DTB
- // possibly needing it for its fault.
- thread[tid]->setInst(
- static_cast<TheISA::MachInst>(head_inst->staticInst->machInst));
-
if (inst_fault != NoFault) {
- DPRINTF(Commit, "Inst [sn:%lli] PC %#x has a fault\n",
- head_inst->seqNum, head_inst->readPC());
+ DPRINTF(Commit, "Inst [sn:%lli] PC %s has a fault\n",
+ head_inst->seqNum, head_inst->pcState());
- if (iewStage->hasStoresToWB() || inst_num > 0) {
+ if (iewStage->hasStoresToWB(tid) || inst_num > 0) {
DPRINTF(Commit, "Stores outstanding, fault must wait.\n");
return false;
}
head_inst->setCompleted();
-#if USE_CHECKER
- if (cpu->checker && head_inst->isStore()) {
+ // If instruction has faulted, let the checker execute it and
+ // check if it sees the same fault and control flow.
+ if (cpu->checker) {
+ // Need to check the instruction before its fault is processed
cpu->checker->verify(head_inst);
}
-#endif
- assert(!thread[tid]->inSyscall);
+ assert(!thread[tid]->noSquashFromTC);
// Mark that we're in state update mode so that the trap's
// execution doesn't generate extra squashes.
- thread[tid]->inSyscall = true;
+ thread[tid]->noSquashFromTC = true;
// Execute the trap. Although it's slightly unrealistic in
// terms of timing (as it doesn't wait for the full timing of
// needed to update the state as soon as possible. This
// prevents external agents from changing any specific state
// that the trap need.
- cpu->trap(inst_fault, tid);
+ cpu->trap(inst_fault, tid, head_inst->staticInst);
// Exit state update mode to avoid accidental updating.
- thread[tid]->inSyscall = false;
+ thread[tid]->noSquashFromTC = false;
commitStatus[tid] = TrapPending;
+ DPRINTF(Commit, "Committing instruction with fault [sn:%lli]\n",
+ head_inst->seqNum);
if (head_inst->traceData) {
- head_inst->traceData->setFetchSeq(head_inst->seqNum);
- head_inst->traceData->setCPSeq(thread[tid]->numInst);
- head_inst->traceData->dump();
+ if (DTRACE(ExecFaulting)) {
+ head_inst->traceData->setFetchSeq(head_inst->seqNum);
+ head_inst->traceData->setCPSeq(thread[tid]->numOp);
+ head_inst->traceData->dump();
+ }
delete head_inst->traceData;
head_inst->traceData = NULL;
}
// Generate trap squash event.
- generateTrapEvent(tid);
-// warn("%lli fault (%d) handled @ PC %08p", curTick, inst_fault->name(), head_inst->readPC());
+ generateTrapEvent(tid, inst_fault);
return false;
}
updateComInstStats(head_inst);
-#if FULL_SYSTEM
- if (thread[tid]->profile) {
-// bool usermode = TheISA::inUserMode(thread[tid]->getTC());
-// thread[tid]->profilePC = usermode ? 1 : head_inst->readPC();
- thread[tid]->profilePC = head_inst->readPC();
- ProfileNode *node = thread[tid]->profile->consume(thread[tid]->getTC(),
- head_inst->staticInst);
+ if (FullSystem) {
+ if (thread[tid]->profile) {
+ thread[tid]->profilePC = head_inst->instAddr();
+ ProfileNode *node = thread[tid]->profile->consume(
+ thread[tid]->getTC(), head_inst->staticInst);
- if (node)
- thread[tid]->profileNode = node;
+ if (node)
+ thread[tid]->profileNode = node;
+ }
+ if (CPA::available()) {
+ if (head_inst->isControl()) {
+ ThreadContext *tc = thread[tid]->getTC();
+ CPA::cpa()->swAutoBegin(tc, head_inst->nextInstAddr());
+ }
+ }
}
-#endif
-
+ DPRINTF(Commit, "Committing instruction with [sn:%lli] PC %s\n",
+ head_inst->seqNum, head_inst->pcState());
if (head_inst->traceData) {
head_inst->traceData->setFetchSeq(head_inst->seqNum);
- head_inst->traceData->setCPSeq(thread[tid]->numInst);
+ head_inst->traceData->setCPSeq(thread[tid]->numOp);
head_inst->traceData->dump();
delete head_inst->traceData;
head_inst->traceData = NULL;
}
+ if (head_inst->isReturn()) {
+ DPRINTF(Commit,"Return Instruction Committed [sn:%lli] PC %s \n",
+ head_inst->seqNum, head_inst->pcState());
+ }
// Update the commit rename map
for (int i = 0; i < head_inst->numDestRegs(); i++) {
head_inst->renamedDestRegIdx(i));
}
- if (head_inst->isCopy())
- panic("Should not commit any copy instructions!");
-
// Finally clear the head ROB entry.
rob->retireHead(tid);
+#if TRACING_ON
+ if (DTRACE(O3PipeView)) {
+ head_inst->commitTick = curTick() - head_inst->fetchTick;
+ }
+#endif
+
// If this was a store, record it for this cycle.
if (head_inst->isStore())
committedStores[tid] = true;
DynInstPtr inst;
inst = fromRename->insts[inst_num];
- int tid = inst->threadNumber;
+ ThreadID tid = inst->threadNumber;
if (!inst->isSquashed() &&
commitStatus[tid] != ROBSquashing &&
commitStatus[tid] != TrapPending) {
changedROBNumEntries[tid] = true;
- DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ROB.\n",
- inst->readPC(), inst->seqNum, tid);
+ DPRINTF(Commit, "Inserting PC %s [sn:%i] [tid:%i] into ROB.\n",
+ inst->pcState(), inst->seqNum, tid);
rob->insertInst(inst);
youngestSeqNum[tid] = inst->seqNum;
} else {
- DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
+ DPRINTF(Commit, "Instruction PC %s [sn:%i] [tid:%i] was "
"squashed, skipping.\n",
- inst->readPC(), inst->seqNum, tid);
- }
- }
-}
-
-template <class Impl>
-void
-DefaultCommit<Impl>::skidInsert()
-{
- DPRINTF(Commit, "Attempting to any instructions from rename into "
- "skidBuffer.\n");
-
- for (int inst_num = 0; inst_num < fromRename->size; ++inst_num) {
- DynInstPtr inst = fromRename->insts[inst_num];
-
- if (!inst->isSquashed()) {
- DPRINTF(Commit, "Inserting PC %#x [sn:%i] [tid:%i] into ",
- "skidBuffer.\n", inst->readPC(), inst->seqNum,
- inst->threadNumber);
- skidBuffer.push(inst);
- } else {
- DPRINTF(Commit, "Instruction PC %#x [sn:%i] [tid:%i] was "
- "squashed, skipping.\n",
- inst->readPC(), inst->seqNum, inst->threadNumber);
+ inst->pcState(), inst->seqNum, tid);
}
}
}
{
// Grab completed insts out of the IEW instruction queue, and mark
// instructions completed within the ROB.
- for (int inst_num = 0;
- inst_num < fromIEW->size && fromIEW->insts[inst_num];
- ++inst_num)
- {
+ for (int inst_num = 0; inst_num < fromIEW->size; ++inst_num) {
+ assert(fromIEW->insts[inst_num]);
if (!fromIEW->insts[inst_num]->isSquashed()) {
- DPRINTF(Commit, "[tid:%i]: Marking PC %#x, [sn:%lli] ready "
+ DPRINTF(Commit, "[tid:%i]: Marking PC %s, [sn:%lli] ready "
"within ROB.\n",
fromIEW->insts[inst_num]->threadNumber,
- fromIEW->insts[inst_num]->readPC(),
+ fromIEW->insts[inst_num]->pcState(),
fromIEW->insts[inst_num]->seqNum);
// Mark the instruction as ready to commit.
}
}
-template <class Impl>
-bool
-DefaultCommit<Impl>::robDoneSquashing()
-{
- std::list<unsigned>::iterator threads = activeThreads->begin();
- std::list<unsigned>::iterator end = activeThreads->end();
-
- while (threads != end) {
- unsigned tid = *threads++;
-
- if (!rob->isDoneSquashing(tid))
- return false;
- }
-
- return true;
-}
-
template <class Impl>
void
DefaultCommit<Impl>::updateComInstStats(DynInstPtr &inst)
{
- unsigned thread = inst->threadNumber;
+ ThreadID tid = inst->threadNumber;
- //
- // Pick off the software prefetches
- //
-#ifdef TARGET_ALPHA
- if (inst->isDataPrefetch()) {
- statComSwp[thread]++;
- } else {
- statComInst[thread]++;
+ if (!inst->isMicroop() || inst->isLastMicroop())
+ instsCommitted[tid]++;
+ opsCommitted[tid]++;
+
+ // To match the old model, don't count nops and instruction
+ // prefetches towards the total commit count.
+ if (!inst->isNop() && !inst->isInstPrefetch()) {
+ cpu->instDone(tid, inst);
}
-#else
- statComInst[thread]++;
-#endif
//
// Control Instructions
//
if (inst->isControl())
- statComBranches[thread]++;
+ statComBranches[tid]++;
//
// Memory references
//
if (inst->isMemRef()) {
- statComRefs[thread]++;
+ statComRefs[tid]++;
if (inst->isLoad()) {
- statComLoads[thread]++;
+ statComLoads[tid]++;
}
}
if (inst->isMemBarrier()) {
- statComMembars[thread]++;
+ statComMembars[tid]++;
}
+
+ // Integer Instruction
+ if (inst->isInteger())
+ statComInteger[tid]++;
+
+ // Floating Point Instruction
+ if (inst->isFloating())
+ statComFloating[tid]++;
+
+ // Function Calls
+ if (inst->isCall())
+ statComFunctionCalls[tid]++;
+
}
////////////////////////////////////////
// //
////////////////////////////////////////
template <class Impl>
-int
+ThreadID
DefaultCommit<Impl>::getCommittingThread()
{
if (numThreads > 1) {
return oldestReady();
default:
- return -1;
+ return InvalidThreadID;
}
} else {
assert(!activeThreads->empty());
- int tid = activeThreads->front();
+ ThreadID tid = activeThreads->front();
if (commitStatus[tid] == Running ||
commitStatus[tid] == Idle ||
commitStatus[tid] == FetchTrapPending) {
return tid;
} else {
- return -1;
+ return InvalidThreadID;
}
}
}
template<class Impl>
-int
+ThreadID
DefaultCommit<Impl>::roundRobin()
{
- std::list<unsigned>::iterator pri_iter = priority_list.begin();
- std::list<unsigned>::iterator end = priority_list.end();
+ list<ThreadID>::iterator pri_iter = priority_list.begin();
+ list<ThreadID>::iterator end = priority_list.end();
while (pri_iter != end) {
- unsigned tid = *pri_iter;
+ ThreadID tid = *pri_iter;
if (commitStatus[tid] == Running ||
commitStatus[tid] == Idle ||
pri_iter++;
}
- return -1;
+ return InvalidThreadID;
}
template<class Impl>
-int
+ThreadID
DefaultCommit<Impl>::oldestReady()
{
unsigned oldest = 0;
bool first = true;
- std::list<unsigned>::iterator threads = activeThreads->begin();
- std::list<unsigned>::iterator end = activeThreads->end();
+ list<ThreadID>::iterator threads = activeThreads->begin();
+ list<ThreadID>::iterator end = activeThreads->end();
while (threads != end) {
- unsigned tid = *threads++;
+ ThreadID tid = *threads++;
if (!rob->isEmpty(tid) &&
(commitStatus[tid] == Running ||
if (!first) {
return oldest;
} else {
- return -1;
+ return InvalidThreadID;
}
}
+
+#endif//__CPU_O3_COMMIT_IMPL_HH__