inorder: implement trap handling
This commit is contained in:
parent
061b369d28
commit
7dea79535c
19 changed files with 205 additions and 139 deletions
|
@ -142,7 +142,8 @@ InOrderCPU::CPUEvent::process()
|
|||
|
||||
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:
|
||||
|
@ -451,8 +452,8 @@ InOrderCPU::createBackEndSked(DynInstPtr inst)
|
|||
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);
|
||||
|
@ -795,14 +796,13 @@ InOrderCPU::updateMemPorts()
|
|||
#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);
|
||||
}
|
||||
|
@ -1302,11 +1302,18 @@ InOrderCPU::updateContextSwitchStats()
|
|||
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();
|
||||
|
|
|
@ -275,6 +275,9 @@ class InOrderCPU : public BaseCPU
|
|||
/** 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];
|
||||
|
@ -430,33 +433,45 @@ class InOrderCPU : public BaseCPU
|
|||
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);
|
||||
|
||||
/** 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 activateContext(ThreadID tid, int delay = 0);
|
||||
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
|
||||
|
|
|
@ -54,7 +54,7 @@ InOrderDynInst::InOrderDynInst(InOrderCPU *cpu,
|
|||
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),
|
||||
|
@ -319,7 +319,15 @@ void
|
|||
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()) {
|
||||
|
@ -329,10 +337,9 @@ InOrderDynInst::setSquashInfo(unsigned stage_num)
|
|||
// 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
|
||||
}
|
||||
|
|
|
@ -122,8 +122,8 @@ class InOrderDynInst : public FastAlloc, public RefCounted
|
|||
/** 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
|
||||
|
|
|
@ -342,43 +342,27 @@ PipelineStage::unblock(ThreadID tid)
|
|||
}
|
||||
|
||||
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;
|
||||
InstSeqNum squash_seq_num = inst->squashSeqNum;
|
||||
|
||||
toPrevStages->stageInfo[stageNum][tid].squash = true;
|
||||
toPrevStages->stageInfo[stageNum][tid].nextPC = inst->readPredTarg();
|
||||
toPrevStages->stageInfo[stageNum][tid].doneSeqNum =
|
||||
squash_seq_num;
|
||||
|
||||
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->bdelaySeqNum;
|
||||
#else
|
||||
toPrevStages->stageInfo[stageNum][tid].bdelayDoneSeqNum = inst->seqNum;
|
||||
InstSeqNum squash_seq_num = inst->seqNum;
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -398,7 +382,6 @@ PipelineStage::squashPrevStageInsts(InstSeqNum squash_seq_num, ThreadID tid)
|
|||
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,
|
||||
|
@ -676,7 +659,7 @@ PipelineStage::checkSignalsAndUpdate(ThreadID 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;
|
||||
}
|
||||
|
@ -989,7 +972,7 @@ PipelineStage::processInstSchedule(DynInstPtr inst,int &reqs_processed)
|
|||
|
||||
// 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
|
||||
|
|
|
@ -227,21 +227,17 @@ class PipelineStage
|
|||
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:
|
||||
|
|
|
@ -290,10 +290,8 @@ Resource::deactivateThread(ThreadID tid)
|
|||
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(
|
||||
|
|
|
@ -106,6 +106,9 @@ class Resource {
|
|||
*/
|
||||
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
|
||||
*/
|
||||
|
|
|
@ -192,7 +192,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
|
|||
res_pool_event->setEvent(e_type,
|
||||
inst,
|
||||
inst->squashingStage,
|
||||
inst->bdelaySeqNum,
|
||||
inst->squashSeqNum,
|
||||
inst->readTid());
|
||||
res_pool_event->schedule(curTick() + cpu->cycles(delay));
|
||||
|
||||
|
@ -208,7 +208,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
|
|||
res_pool_event->setEvent(e_type,
|
||||
inst,
|
||||
inst->squashingStage,
|
||||
inst->bdelaySeqNum,
|
||||
inst->squashSeqNum,
|
||||
tid);
|
||||
|
||||
res_pool_event->schedule(curTick() + cpu->cycles(delay));
|
||||
|
@ -238,7 +238,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
|
|||
res_pool_event->setEvent(e_type,
|
||||
inst,
|
||||
inst->squashingStage,
|
||||
inst->bdelaySeqNum,
|
||||
inst->squashSeqNum,
|
||||
inst->readTid());
|
||||
res_pool_event->schedule(curTick() + cpu->cycles(delay));
|
||||
|
||||
|
|
|
@ -234,6 +234,18 @@ ResourcePool::squash(DynInstPtr inst, int res_idx, InstSeqNum done_seq_num,
|
|||
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)
|
||||
{
|
||||
|
@ -272,7 +284,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
|
|||
e_type,
|
||||
inst,
|
||||
inst->squashingStage,
|
||||
inst->bdelaySeqNum,
|
||||
inst->squashSeqNum,
|
||||
inst->readTid());
|
||||
cpu->schedule(res_pool_event, when);
|
||||
}
|
||||
|
@ -289,7 +301,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
|
|||
e_type,
|
||||
inst,
|
||||
inst->squashingStage,
|
||||
inst->bdelaySeqNum,
|
||||
inst->squashSeqNum,
|
||||
tid);
|
||||
|
||||
cpu->schedule(res_pool_event, when);
|
||||
|
@ -308,7 +320,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
|
|||
e_type,
|
||||
inst,
|
||||
inst->squashingStage,
|
||||
inst->bdelaySeqNum,
|
||||
inst->squashSeqNum,
|
||||
tid);
|
||||
|
||||
cpu->schedule(res_pool_event, sked_tick);
|
||||
|
@ -337,7 +349,7 @@ ResourcePool::scheduleEvent(InOrderCPU::CPUEventType e_type, DynInstPtr inst,
|
|||
new ResPoolEvent(this,e_type,
|
||||
inst,
|
||||
inst->squashingStage,
|
||||
inst->bdelaySeqNum,
|
||||
inst->squashSeqNum,
|
||||
inst->readTid());
|
||||
cpu->schedule(res_pool_event, when);
|
||||
}
|
||||
|
|
|
@ -182,6 +182,9 @@ class ResourcePool {
|
|||
/** 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.
|
||||
*/
|
||||
|
|
|
@ -78,8 +78,8 @@ AGENUnit::execute(int slot_num)
|
|||
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++;
|
||||
|
|
|
@ -441,9 +441,10 @@ CacheUnit::doTLBAccess(DynInstPtr inst, CacheReqPtr cache_req, int acc_size,
|
|||
|
||||
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,
|
||||
|
@ -1072,6 +1073,11 @@ CacheUnitEvent::process()
|
|||
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]->
|
||||
|
|
|
@ -140,9 +140,10 @@ ExecutionUnit::execute(int slot_num)
|
|||
// Evaluate Branch
|
||||
fault = inst->execute();
|
||||
executions++;
|
||||
inst->setExecuted();
|
||||
|
||||
if (fault == NoFault) {
|
||||
inst->setExecuted();
|
||||
|
||||
if (inst->mispredicted()) {
|
||||
assert(inst->isControl());
|
||||
|
||||
|
@ -190,7 +191,8 @@ ExecutionUnit::execute(int slot_num)
|
|||
|
||||
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();
|
||||
}
|
||||
|
@ -210,6 +212,8 @@ ExecutionUnit::execute(int slot_num)
|
|||
} 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -127,7 +127,7 @@ FetchSeqUnit::execute(int slot_num)
|
|||
|
||||
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 "
|
||||
|
@ -152,8 +152,8 @@ FetchSeqUnit::squash(DynInstPtr inst, int squash_stage,
|
|||
"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);
|
||||
|
@ -161,57 +161,65 @@ FetchSeqUnit::squash(DynInstPtr inst, int 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 (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()) {
|
||||
advancePC(nextPC, inst->staticInst);
|
||||
DPRINTF(Resource, "Advanced PC to %s\n", nextPC);
|
||||
}
|
||||
}
|
||||
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 {
|
||||
nextPC = inst->pcState();
|
||||
advancePC(nextPC, inst->staticInst);
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nextPC = inst->pcState();
|
||||
advancePC(nextPC, inst->staticInst);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
pcValid[tid] = true;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
pcValid[tid] = true;
|
||||
}
|
||||
}
|
||||
|
||||
Resource::squash(inst, squash_stage, squash_seq_num, tid);
|
||||
}
|
||||
|
@ -272,6 +280,17 @@ FetchSeqUnit::suspendThread(ThreadID 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)
|
||||
{
|
||||
|
|
|
@ -65,15 +65,12 @@ class FetchSeqUnit : public Resource {
|
|||
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;
|
||||
|
|
|
@ -111,6 +111,7 @@ FetchUnit::createMachInst(std::list<FetchBlock*>::iterator fetch_it,
|
|||
|
||||
predecoder.setTC(cpu->thread[tid]->getTC());
|
||||
predecoder.moreBytes(instPC, inst->instAddr(), mach_inst);
|
||||
assert(predecoder.extMachInstReady());
|
||||
ext_inst = predecoder.getExtMachInst(instPC);
|
||||
|
||||
inst->pcState(instPC);
|
||||
|
@ -552,3 +553,9 @@ FetchUnit::squashCacheRequest(CacheReqPtr req_ptr)
|
|||
CacheUnit::squashCacheRequest(req_ptr);
|
||||
}
|
||||
|
||||
void
|
||||
FetchUnit::trap(Fault fault, ThreadID tid, DynInstPtr inst)
|
||||
{
|
||||
//@todo: per thread?
|
||||
predecoder.reset();
|
||||
}
|
||||
|
|
|
@ -88,6 +88,8 @@ class FetchUnit : public CacheUnit
|
|||
/** 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);
|
||||
|
||||
|
|
|
@ -67,7 +67,14 @@ GraduationUnit::execute(int slot_num)
|
|||
|
||||
// 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,
|
||||
|
|
Loading…
Reference in a new issue