using namespace ThePipeline;
FetchSeqUnit::FetchSeqUnit(std::string res_name, int res_id, int res_width,
- int res_latency, InOrderCPU *_cpu,
+ Cycles res_latency, InOrderCPU *_cpu,
ThePipeline::Params *params)
: Resource(res_name, res_id, res_width, res_latency, _cpu),
instSize(sizeof(MachInst))
pcValid[tid] = false;
pcBlockStage[tid] = 0;
+ //@todo: Use CPU's squashSeqNum here instead of maintaining our own
+ // state
squashSeqNum[tid] = (InstSeqNum)-1;
lastSquashCycle[tid] = 0;
}
ThreadID tid = inst->readTid();
int stage_num = fs_req->getStageNum();
- DPRINTF(InOrderFetchSeq, "[tid:%i]: Current PC is %s\n", tid,
- pc[tid]);
+ if (inst->fault != NoFault) {
+ DPRINTF(InOrderFetchSeq,
+ "[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
+ "next stage.\n", tid, inst->seqNum, inst->fault->name(),
+ inst->pcState());
+ fs_req->done();
+ return;
+ }
switch (fs_req->cmd)
{
case AssignNextPC:
{
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: Current PC is %s\n", tid,
+ pc[tid]);
+
if (pcValid[tid]) {
inst->pcState(pc[tid]);
inst->setMemAddr(pc[tid].instAddr());
// If it's a return, then we must wait for resolved address.
// The Predictor will mark a return a false as "not taken"
// if there is no RAS entry
+ DPRINTF(InOrderFetchSeq, "[tid:%d]: Setting block signal "
+ "for stage %i.\n",
+ tid, stage_num);
cpu->pipelineStage[stage_num]->
toPrevStages->stageBlock[stage_num][tid] = true;
pcValid[tid] = false;
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++;
+ if (inst->staticInst) {
+ 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].%s %s \n", tid, inst->seqNum,
+ inst->instName(), inst->pcState());
+ pcValid[tid] = false;
} 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_inst) {
- DPRINTF(Resource, "Evaluating %s v. %s\n",
- bdelay_inst->pc, nextPC);
-
- if (bdelay_inst->pc.instAddr() == nextPC.instAddr()) {
+ 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_inst) {
+ if (bdelay_inst->pc.instAddr() == nextPC.instAddr()) {
+ bdelay_inst->pc = nextPC;
+ advancePC(nextPC, inst->staticInst);
+ DPRINTF(InOrderFetchSeq, "Advanced PC to %s\n", nextPC);
+ }
+ }
+ } else {
+ nextPC = inst->pcState();
advancePC(nextPC, inst->staticInst);
- DPRINTF(Resource, "Advanced PC to %s\n", nextPC);
}
- }
- } 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]) {
+ DPRINTF(InOrderFetchSeq, "[tid:%d]: Setting unblock signal "
+ "for stage %i.\n",
+ tid, pcBlockStage[tid]);
- pcValid[tid] = true;
+ // Need to use "fromNextStages" instead of "toPrevStages"
+ // because the timebuffer will have already have advanced
+ // in the tick function and this squash function will happen after
+ // the tick
+ cpu->pipelineStage[pcBlockStage[tid]]->
+ fromNextStages->stageUnblock[pcBlockStage[tid]][tid] = true;
+ }
+
+ pcValid[tid] = true;
+ }
+ }
}
Resource::squash(inst, squash_stage, squash_seq_num, tid);
deactivateThread(tid);
}
+void
+FetchSeqUnit::trap(const Fault &fault, ThreadID tid, DynInstPtr inst)
+{
+ pcValid[tid] = true;
+ pc[tid] = cpu->pcState(tid);
+ DPRINTF(InOrderFetchSeq, "[tid:%i]: Trap updating to PC: "
+ "%s.\n", tid, pc[tid]);
+}
+
void
FetchSeqUnit::updateAfterContextSwitch(DynInstPtr inst, ThreadID tid)
{