case Trap:
DPRINTF(InOrderCPU, "Trapping CPU\n");
- cpu->trapCPU(fault, tid, inst);
+ cpu->trap(fault, tid, inst);
+ cpu->resPool->trap(fault, tid, inst);
break;
default:
if (inst->splitInst)
M.needs(DCache, CacheUnit::InitSecondSplitRead);
} else if ( inst->isStore() ) {
- if ( inst->numSrcRegs() >= 2 ) {
- M.needs(RegManager, UseDefUnit::ReadSrcReg, 1);
+ for (int i = 1; i < inst->numSrcRegs(); i++ ) {
+ M.needs(RegManager, UseDefUnit::ReadSrcReg, i);
}
M.needs(AGEN, AGENUnit::GenerateAddr);
M.needs(DCache, CacheUnit::InitiateWriteData);
#endif
void
-InOrderCPU::trap(Fault fault, ThreadID tid, DynInstPtr inst, int delay)
+InOrderCPU::trapContext(Fault fault, ThreadID tid, DynInstPtr inst, int delay)
{
- //@ Squash Pipeline during TRAP
scheduleCpuEvent(Trap, fault, tid, inst, delay);
}
void
-InOrderCPU::trapCPU(Fault fault, ThreadID tid, DynInstPtr inst)
+InOrderCPU::trap(Fault fault, ThreadID tid, DynInstPtr inst)
{
fault->invoke(tcBase(tid), inst->staticInst);
}
void
InOrderCPU::instDone(DynInstPtr inst, ThreadID tid)
{
- // Set the CPU's PCs - This contributes to the precise state of the CPU
+ // Set the nextPC to be fetched if this is the last instruction
+ // committed
+ // ========
+ // This contributes to the precise state of the CPU
// which can be used when restoring a thread to the CPU after after any
// type of context switching activity (fork, exception, etc.)
- pcState(inst->pcState(), tid);
+ TheISA::PCState comm_pc = inst->pcState();
+ lastCommittedPC[tid] = comm_pc;
+ TheISA::advancePC(comm_pc, inst->staticInst);
+ pcState(comm_pc, tid);
+ //@todo: may be unnecessary with new-ISA-specific branch handling code
if (inst->isControl()) {
thread[tid]->lastGradIsBranch = true;
thread[tid]->lastBranchPC = inst->pcState();
/** Program Counters */
TheISA::PCState pc[ThePipeline::MaxThreads];
+ /** Last Committed PC */
+ TheISA::PCState lastCommittedPC[ThePipeline::MaxThreads];
+
/** The Register File for the CPU */
union {
FloatReg f[ThePipeline::MaxThreads][TheISA::NumFloatRegs];
bool validDataAddr(Addr addr) { return true; }
#endif
- /** trap() - sets up a trap event on the cpuTraps to handle given fault.
- * trapCPU() - Traps to handle given fault
- */
- void trap(Fault fault, ThreadID tid, DynInstPtr inst, int delay = 0);
- void trapCPU(Fault fault, ThreadID tid, DynInstPtr inst);
+ /** Schedule a trap on the CPU */
+ void trapContext(Fault fault, ThreadID tid, DynInstPtr inst, int delay = 0);
- /** Add Thread to Active Threads List. */
+ /** Perform trap to Handle Given Fault */
+ void trap(Fault fault, ThreadID tid, DynInstPtr inst);
+
+ /** Schedule thread activation on the CPU */
void activateContext(ThreadID tid, int delay = 0);
+
+ /** Add Thread to Active Threads List. */
void activateThread(ThreadID tid);
+
+ /** Activate Thread In Each Pipeline Stage */
void activateThreadInPipeline(ThreadID tid);
- /** Add Thread to Active Threads List. */
+ /** Schedule Thread Activation from Ready List */
void activateNextReadyContext(int delay = 0);
+
+ /** Add Thread From Ready List to Active Threads List. */
void activateNextReadyThread();
- /** Remove from Active Thread List */
+ /** Schedule a thread deactivation on the CPU */
void deactivateContext(ThreadID tid, int delay = 0);
+
+ /** Remove from Active Thread List */
void deactivateThread(ThreadID tid);
- /** Suspend Thread, Remove from Active Threads List, Add to Suspend List */
+ /** Schedule a thread suspension on the CPU */
void suspendContext(ThreadID tid, int delay = 0);
+
+ /** Suspend Thread, Remove from Active Threads List, Add to Suspend List */
void suspendThread(ThreadID tid);
+ /** Schedule a thread halt on the CPU */
+ void haltContext(ThreadID tid, int delay = 0);
+
/** Halt Thread, Remove from Active Thread List, Place Thread on Halted
* Threads List
*/
- void haltContext(ThreadID tid, int delay = 0);
void haltThread(ThreadID tid);
/** squashFromMemStall() - sets up a squash event
InstSeqNum seq_num,
ThreadID tid,
unsigned _asid)
- : seqNum(seq_num), bdelaySeqNum(0), threadNumber(tid), asid(_asid),
+ : seqNum(seq_num), squashSeqNum(0), threadNumber(tid), asid(_asid),
virtProcNumber(0), staticInst(NULL), traceData(NULL), cpu(cpu),
thread(state), fault(NoFault), memData(NULL), loadData(0),
storeData(0), effAddr(0), physEffAddr(0), memReqFlags(0),
InOrderDynInst::setSquashInfo(unsigned stage_num)
{
squashingStage = stage_num;
- bdelaySeqNum = seqNum;
+
+ // If it's a fault, then we need to squash
+ // the faulting instruction too. Squash
+ // functions squash above a seqNum, so we
+ // decrement here for that case
+ if (fault != NoFault)
+ squashSeqNum = seqNum - 1;
+ else
+ squashSeqNum = seqNum;
#if ISA_HAS_DELAY_SLOT
if (isControl()) {
// Check to see if we should squash after the
// branch or after a branch delay slot.
if (pc.nextInstAddr() == pc.instAddr() + sizeof(MachInst))
- bdelaySeqNum = seqNum + 1;
+ squashSeqNum = seqNum + 1;
else
- bdelaySeqNum = seqNum;
-
+ squashSeqNum = seqNum;
}
#endif
}
/** The sequence number of the instruction. */
InstSeqNum seqNum;
- /** The sequence number of the instruction. */
- InstSeqNum bdelaySeqNum;
+ /** If this instruction is squashing, the number should we squash behind. */
+ InstSeqNum squashSeqNum;
enum Status {
RegDepMapEntry, /// Instruction is entered onto the RegDepMap
}
void
-PipelineStage::squashDueToBranch(DynInstPtr &inst, ThreadID tid)
+PipelineStage::setupSquash(DynInstPtr inst, ThreadID tid)
{
- if (cpu->squashSeqNum[tid] < inst->seqNum &&
- cpu->lastSquashCycle[tid] == curTick()){
+ if (cpu->lastSquashCycle[tid] == curTick() &&
+ cpu->squashSeqNum[tid] < inst->seqNum){
DPRINTF(Resource, "Ignoring [sn:%i] branch squash signal due to "
"another stage's squash signal for after [sn:%i].\n",
inst->seqNum, cpu->squashSeqNum[tid]);
} else {
- // Send back mispredict information.
- toPrevStages->stageInfo[stageNum][tid].branchMispredict = true;
- toPrevStages->stageInfo[stageNum][tid].predIncorrect = true;
- toPrevStages->stageInfo[stageNum][tid].doneSeqNum = inst->seqNum;
- toPrevStages->stageInfo[stageNum][tid].squash = true;
- toPrevStages->stageInfo[stageNum][tid].nextPC = inst->readPredTarg();
-
- toPrevStages->stageInfo[stageNum][tid].branchTaken =
- inst->pcState().branching();
-
-#if ISA_HAS_DELAY_SLOT
- toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum =
- inst->bdelaySeqNum;
+ InstSeqNum squash_seq_num = inst->squashSeqNum;
- InstSeqNum squash_seq_num = inst->bdelaySeqNum;
-#else
- toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum = inst->seqNum;
- InstSeqNum squash_seq_num = inst->seqNum;
-#endif
+ toPrevStages->stageInfo[stageNum][tid].squash = true;
+ toPrevStages->stageInfo[stageNum][tid].doneSeqNum =
+ squash_seq_num;
- DPRINTF(InOrderStage, "Target being re-set to %08p\n",
- inst->predInstAddr());
DPRINTF(InOrderStage, "[tid:%i]: Squashing after [sn:%i], "
- "due to [sn:%i] branch.\n", tid, squash_seq_num,
- inst->seqNum);
+ "due to [sn:%i] %s.\n", tid, squash_seq_num,
+ inst->seqNum, inst->instName());
// Save squash num for later stage use
- cpu->squashSeqNum[tid] = squash_seq_num;
cpu->lastSquashCycle[tid] = curTick();
+ cpu->squashSeqNum[tid] = squash_seq_num;
}
}
for (int i=0; i < insts_from_prev_stage; i++) {
if (prevStage->insts[i]->threadNumber == tid &&
prevStage->insts[i]->seqNum > squash_seq_num) {
- // Change Comment to Annulling previous instruction
DPRINTF(InOrderStage, "[tid:%i]: Squashing instruction, "
"[sn:%i] PC %s.\n",
tid,
DPRINTF(InOrderStage, "[tid:%u]: Squashing instructions due to "
"squash from stage %u.\n", tid, stage_idx);
InstSeqNum squash_seq_num = fromNextStages->
- stageInfo[stage_idx][tid].bdelayDoneSeqNum;
+ stageInfo[stage_idx][tid].doneSeqNum;
squash(squash_seq_num, tid);
break; //return true;
}
// Remove Thread From Pipeline & Resource Pool
inst->squashingStage = stageNum;
- inst->bdelaySeqNum = inst->seqNum;
+ inst->squashSeqNum = inst->seqNum;
cpu->squashFromMemStall(inst, tid);
// Switch On Cache Miss
public:
void activateThread(ThreadID tid);
- /** Squashes if there is a PC-relative branch that was predicted
- * incorrectly. Sends squash information back to fetch.
- */
- void squashDueToBranch(DynInstPtr &inst, ThreadID tid);
+ /** Setup Squashing Information to be passed back thru the pipeline */
+ void setupSquash(DynInstPtr inst, ThreadID tid);
virtual void squashDueToMemStall(InstSeqNum seq_num, ThreadID tid);
+ /** Perform squash of instructions above seq_num */
+ virtual void squash(InstSeqNum squash_num, ThreadID tid);
+
/** Squash instructions from stage buffer */
void squashPrevStageInsts(InstSeqNum squash_seq_num, ThreadID tid);
- /** Squashes due to commit signalling a squash. Changes status to
- * squashing and clears block/unblock signals as needed.
- */
- virtual void squash(InstSeqNum squash_num, ThreadID tid);
-
void dumpInsts();
protected:
void
Resource::setupSquash(DynInstPtr inst, int stage_num, ThreadID tid)
{
- assert(inst->isControl() && "Function Assumes Squash From A Branch");
-
// Squash In Pipeline Stage
- cpu->pipelineStage[stage_num]->squashDueToBranch(inst, tid);
+ cpu->pipelineStage[stage_num]->setupSquash(inst, tid);
// Schedule Squash Through-out Resource Pool
cpu->resPool->scheduleEvent(
*/
virtual void instGraduated(InstSeqNum seq_num, ThreadID tid) { }
+ /** Post-processsing for Trap Generated from this instruction */
+ virtual void trap(Fault fault, ThreadID tid, DynInstPtr inst) { }
+
/** Request usage of this resource. Returns a ResourceRequest object
* with all the necessary resource information
*/
res_pool_event->setEvent(e_type,
inst,
inst->squashingStage,
- inst->bdelaySeqNum,
+ inst->squashSeqNum,
inst->readTid());
res_pool_event->schedule(curTick() + cpu->cycles(delay));
res_pool_event->setEvent(e_type,
inst,
inst->squashingStage,
- inst->bdelaySeqNum,
+ inst->squashSeqNum,
tid);
res_pool_event->schedule(curTick() + cpu->cycles(delay));
res_pool_event->setEvent(e_type,
inst,
inst->squashingStage,
- inst->bdelaySeqNum,
+ inst->squashSeqNum,
inst->readTid());
res_pool_event->schedule(curTick() + cpu->cycles(delay));
tid);
}
+void
+ResourcePool::trap(Fault fault, ThreadID tid, DynInstPtr inst)
+{
+ DPRINTF(Resource, "[tid:%i] Broadcasting Trap to all "
+ "resources.\n", tid);
+
+ int num_resources = resources.size();
+
+ for (int idx = 0; idx < num_resources; idx++)
+ resources[idx]->trap(fault, tid, inst);
+}
+
int
ResourcePool::slotsAvail(int res_idx)
{
e_type,
inst,
inst->squashingStage,
- inst->bdelaySeqNum,
+ inst->squashSeqNum,
inst->readTid());
cpu->schedule(res_pool_event, when);
}
e_type,
inst,
inst->squashingStage,
- inst->bdelaySeqNum,
+ inst->squashSeqNum,
tid);
cpu->schedule(res_pool_event, when);
e_type,
inst,
inst->squashingStage,
- inst->bdelaySeqNum,
+ inst->squashSeqNum,
tid);
cpu->schedule(res_pool_event, sked_tick);
new ResPoolEvent(this,e_type,
inst,
inst->squashingStage,
- inst->bdelaySeqNum,
+ inst->squashSeqNum,
inst->readTid());
cpu->schedule(res_pool_event, when);
}
/** Broadcast graduation to all resources */
void instGraduated(InstSeqNum seq_num, ThreadID tid);
+ /** Broadcast trap to all resources */
+ void trap(Fault fault, ThreadID tid, DynInstPtr inst);
+
/** The number of instructions available that a resource can
* can still process.
*/
if (inst->fault == NoFault) {
agen_req->done();
} else {
- fatal("%s encountered while calculating address [sn:%i]",
- inst->fault->name(), seq_num);
+ fatal("%s encountered while calculating address [sn:%i] %s",
+ inst->fault->name(), seq_num, inst->instName());
}
agens++;
cache_req->tlbStall = true;
+ // schedule a time to process the tlb miss.
+ // latency hardcoded to 1 (for now), but will be updated
+ // when timing translation gets added in
scheduleEvent(slot_idx, 1);
-
- cpu->trap(inst->fault, tid, inst);
} else {
DPRINTF(InOrderTLB, "[tid:%i]: [sn:%i] virt. addr %08p translated "
"to phys. addr:%08p.\n", tid, inst->seqNum,
CacheUnit* tlb_res = dynamic_cast<CacheUnit*>(resource);
assert(tlb_res);
+ //@todo: eventually, we should do a timing translation w/
+ // hw page table walk on tlb miss
+ DPRINTF(Fault, "Handling Fault %s\n", inst->fault->name());
+ inst->fault->invoke(tlb_res->cpu->tcBase(tid), inst->staticInst);
+
tlb_res->tlbBlocked[tid] = false;
tlb_res->cpu->pipelineStage[stage_num]->
// Evaluate Branch
fault = inst->execute();
executions++;
- inst->setExecuted();
if (fault == NoFault) {
+ inst->setExecuted();
+
if (inst->mispredicted()) {
assert(inst->isControl());
exec_req->done();
} else {
- warn("inst [sn:%i] had a %s fault", seq_num, fault->name());
+ DPRINTF(Fault, "[tid:%i]:[sn:%i]: Fault %s found\n",
+ inst->readTid(), inst->seqNum, fault->name());
inst->fault = fault;
exec_req->done();
}
} else {
DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i]: had a %s "
"fault.\n", inst->readTid(), seq_num, fault->name());
+ DPRINTF(Fault, "[tid:%i]:[sn:%i]: Fault %s found\n",
+ inst->readTid(), inst->seqNum, fault->name());
inst->fault = fault;
}
DPRINTF(InOrderFetchSeq, "[tid:%i] Setting up squash to "
"start from stage %i, after [sn:%i].\n",
- tid, stage_num, inst->bdelaySeqNum);
+ tid, stage_num, inst->squashSeqNum);
}
} else {
DPRINTF(InOrderFetchSeq, "[tid:%i]: [sn:%i]: Ignoring branch "
"stage %i.\n", tid, inst->instName(), inst->pcState(),
squash_stage);
- if (squashSeqNum[tid] <= squash_seq_num &&
- lastSquashCycle[tid] == curTick()) {
+ if (lastSquashCycle[tid] == curTick() &&
+ squashSeqNum[tid] <= squash_seq_num) {
DPRINTF(InOrderFetchSeq, "[tid:%i]: Ignoring squash from stage %i, "
"since there is an outstanding squash that is older.\n",
tid, squash_stage);
squashSeqNum[tid] = squash_seq_num;
lastSquashCycle[tid] = curTick();
- TheISA::PCState nextPC;
- assert(inst->staticInst);
- if (inst->isControl()) {
- nextPC = inst->readPredTarg();
-
- // If we are already fetching this PC then advance to next PC
- // =======
- // This should handle ISAs w/delay slots and annulled delay
- // slots to figure out which is the next PC to fetch after
- // a mispredict
- DynInstPtr bdelay_inst = NULL;
- ListIt bdelay_it;
- if (inst->onInstList) {
- bdelay_it = inst->getInstListIt();
- bdelay_it++;
- } else {
- InstSeqNum branch_delay_num = inst->seqNum + 1;
- bdelay_it = cpu->findInst(branch_delay_num, tid);
- }
+ if (inst->fault != NoFault) {
+ // A Trap Caused This Fault and will update the pc state
+ // when done trapping
+ DPRINTF(InOrderFetchSeq, "[tid:%i] Blocking due to fault @ "
+ "[sn:%i].\n", inst->seqNum);
+ pcValid[tid] = false;
+ } else {
+ TheISA::PCState nextPC;
+ assert(inst->staticInst);
+ if (inst->isControl()) {
+ nextPC = inst->readPredTarg();
+
+ // If we are already fetching this PC then advance to next PC
+ // =======
+ // This should handle ISAs w/delay slots and annulled delay
+ // slots to figure out which is the next PC to fetch after
+ // a mispredict
+ DynInstPtr bdelay_inst = NULL;
+ ListIt bdelay_it;
+ if (inst->onInstList) {
+ bdelay_it = inst->getInstListIt();
+ bdelay_it++;
+ } else {
+ InstSeqNum branch_delay_num = inst->seqNum + 1;
+ bdelay_it = cpu->findInst(branch_delay_num, tid);
+ }
- if (bdelay_it != cpu->instList[tid].end()) {
- bdelay_inst = (*bdelay_it);
- }
+ if (bdelay_it != cpu->instList[tid].end()) {
+ bdelay_inst = (*bdelay_it);
+ }
- if (bdelay_inst) {
- DPRINTF(Resource, "Evaluating %s v. %s\n",
- bdelay_inst->pc, nextPC);
+ if (bdelay_inst) {
+ DPRINTF(Resource, "Evaluating %s v. %s\n",
+ bdelay_inst->pc, nextPC);
- if (bdelay_inst->pc.instAddr() == nextPC.instAddr()) {
- advancePC(nextPC, inst->staticInst);
- DPRINTF(Resource, "Advanced PC to %s\n", nextPC);
+ if (bdelay_inst->pc.instAddr() == nextPC.instAddr()) {
+ advancePC(nextPC, inst->staticInst);
+ DPRINTF(Resource, "Advanced PC to %s\n", nextPC);
+ }
}
+ } else {
+ nextPC = inst->pcState();
+ advancePC(nextPC, inst->staticInst);
}
- } else {
- nextPC = inst->pcState();
- advancePC(nextPC, inst->staticInst);
- }
- DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to %s.\n",
- tid, nextPC);
- pc[tid] = nextPC;
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: Setting PC to %s.\n",
+ tid, nextPC);
+ pc[tid] = nextPC;
- // Unblock Any Stages Waiting for this information to be updated ...
- if (!pcValid[tid]) {
- cpu->pipelineStage[pcBlockStage[tid]]->
- toPrevStages->stageUnblock[pcBlockStage[tid]][tid] = true;
- }
+ // Unblock Any Stages Waiting for this information to be updated ...
+ if (!pcValid[tid]) {
+ cpu->pipelineStage[pcBlockStage[tid]]->
+ toPrevStages->stageUnblock[pcBlockStage[tid]][tid] = true;
+ }
- pcValid[tid] = true;
- }
+ pcValid[tid] = true;
+ }
+ }
Resource::squash(inst, squash_stage, squash_seq_num, tid);
}
deactivateThread(tid);
}
+void
+FetchSeqUnit::trap(Fault fault, ThreadID tid, DynInstPtr inst)
+{
+ pcValid[tid] = true;
+ pc[tid] = cpu->pcState(tid);
+ DPRINTF(Fault, "[tid:%i]: Trap updating to PC: "
+ "%s.\n", tid, pc[tid]);
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: Trap updating to PC: "
+ "%s.\n", tid, pc[tid]);
+}
+
void
FetchSeqUnit::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid)
{
void updateAfterContextSwitch(DynInstPtr inst, ThreadID tid);
- /** Override default Resource squash sequence. This actually,
- * looks in the global communication buffer to get squash
- * info
- */
+ /** Update to correct PC from a squash */
void squash(DynInstPtr inst, int squash_stage,
- InstSeqNum squash_seq_num, ThreadID tid);
+ InstSeqNum squash_seq_num, ThreadID tid);
-
- inline void squashAfterInst(DynInstPtr inst, int stage_num, ThreadID tid);
+ /** Update to correct PC from a trap */
+ void trap(Fault fault, ThreadID tid, DynInstPtr inst);
protected:
unsigned instSize;
predecoder.setTC(cpu->thread[tid]->getTC());
predecoder.moreBytes(instPC, inst->instAddr(), mach_inst);
+ assert(predecoder.extMachInstReady());
ext_inst = predecoder.getExtMachInst(instPC);
inst->pcState(instPC);
CacheUnit::squashCacheRequest(req_ptr);
}
+void
+FetchUnit::trap(Fault fault, ThreadID tid, DynInstPtr inst)
+{
+ //@todo: per thread?
+ predecoder.reset();
+}
/** Executes one of the commands from the "Command" enum */
void execute(int slot_num);
+ void trap(Fault fault, ThreadID tid, DynInstPtr inst);
+
private:
void squashCacheRequest(CacheReqPtr req_ptr);
// Handle Any Faults Before Graduating Instruction
if (inst->fault != NoFault) {
- cpu->trap(inst->fault, tid, inst);
+ DPRINTF(Fault, "[sn:%i]: fault %s found for %s\n",
+ inst->seqNum, inst->fault->name(),
+ inst->instName());
+ inst->setSquashInfo(stage_num);
+ setupSquash(inst, stage_num, tid);
+ cpu->trapContext(inst->fault, tid, inst);
+ grad_req->done(false);
+ return;
}
DPRINTF(InOrderGraduation,