inorder: dont handle multiple faults on same cycle

if a faulting instruction reaches an execution unit,
then ignore it and pass it through the pipeline.

Once we recognize the fault in the graduation unit,
dont allow a second fault to creep in on the same cycle.
This commit is contained in:
Korey Sewell 2011-06-19 21:43:40 -04:00
parent c4deabfb97
commit 561c33f082
16 changed files with 171 additions and 58 deletions

View file

@ -196,7 +196,6 @@ InOrderCPU::InOrderCPU(Params *params)
timeBuffer(2 , 2),
removeInstsThisCycle(false),
activityRec(params->name, NumStages, 10, params->activity),
stCondFails(0),
#if FULL_SYSTEM
system(params->system),
#endif // FULL_SYSTEM
@ -372,7 +371,8 @@ InOrderCPU::InOrderCPU(Params *params)
endOfSkedIt = skedCache.end();
frontEndSked = createFrontEndSked();
faultSked = createFaultSked();
lastRunningCycle = curTick();
lockAddr = 0;
@ -417,11 +417,21 @@ InOrderCPU::createFrontEndSked()
D.needs(FetchSeq, FetchSeqUnit::UpdateTargetPC);
DPRINTF(SkedCache, "Resource Sked created for instruction \"front_end\"\n");
DPRINTF(SkedCache, "Resource Sked created for instruction Front End\n");
return res_sked;
}
RSkedPtr
InOrderCPU::createFaultSked()
{
RSkedPtr res_sked = new ResourceSked();
StageScheduler W(res_sked, NumStages - 1);
W.needs(Grad, GraduationUnit::CheckFault);
DPRINTF(SkedCache, "Resource Sked created for instruction Faults\n");
return res_sked;
}
RSkedPtr
InOrderCPU::createBackEndSked(DynInstPtr inst)
{

View file

@ -319,6 +319,7 @@ class InOrderCPU : public BaseCPU
SkedCacheIt endOfSkedIt;
ThePipeline::RSkedPtr frontEndSked;
ThePipeline::RSkedPtr faultSked;
/** Add a new instruction schedule to the schedule cache */
void addToSkedCache(DynInstPtr inst, ThePipeline::RSkedPtr inst_sked)
@ -366,6 +367,7 @@ class InOrderCPU : public BaseCPU
}
ThePipeline::RSkedPtr createFrontEndSked();
ThePipeline::RSkedPtr createFaultSked();
ThePipeline::RSkedPtr createBackEndSked(DynInstPtr inst);
class StageScheduler {
@ -751,7 +753,7 @@ class InOrderCPU : public BaseCPU
virtual void wakeup();
#endif
// LL/SC debug functionality
/* LL/SC debug functionality
unsigned stCondFails;
unsigned readStCondFailures()
@ -759,6 +761,7 @@ class InOrderCPU : public BaseCPU
unsigned setStCondFailures(unsigned st_fails)
{ return stCondFails = st_fails; }
*/
/** Returns a pointer to a thread context. */
ThreadContext *tcBase(ThreadID tid = 0)

View file

@ -87,6 +87,12 @@ InOrderDynInst::InOrderDynInst(InOrderCPU *cpu,
int InOrderDynInst::instcount = 0;
int
InOrderDynInst::cpuId()
{
return cpu->cpuId();
}
void
InOrderDynInst::setMachInst(ExtMachInst machInst)
{
@ -330,7 +336,7 @@ InOrderDynInst::setSquashInfo(unsigned stage_num)
squashSeqNum = seqNum;
#if ISA_HAS_DELAY_SLOT
if (isControl()) {
if (staticInst && isControl()) {
TheISA::PCState nextPC = pc;
TheISA::advancePC(nextPC, staticInst);

View file

@ -355,6 +355,12 @@ class InOrderDynInst : public FastAlloc, public RefCounted
/** Returns the fault type. */
Fault getFault() { return fault; }
/** Read this CPU's ID. */
int cpuId();
/** Read this context's system-wide ID **/
int contextId() { return thread->contextId(); }
////////////////////////////////////////////////////////////
//
// INSTRUCTION TYPES - Forward checks to StaticInst object.
@ -473,12 +479,12 @@ class InOrderDynInst : public FastAlloc, public RefCounted
curSkedEntry++;
if (inFrontEnd && curSkedEntry == frontSked_end) {
DPRINTF(InOrderDynInst, "[sn:%i] Switching to "
DPRINTF(InOrderDynInst, "[sn:%i] Switching to "
"back end schedule.\n", seqNum);
assert(backSked != NULL);
curSkedEntry.init(backSked);
curSkedEntry = backSked->begin();
inFrontEnd = false;
curSkedEntry.init(backSked);
curSkedEntry = backSked->begin();
inFrontEnd = false;
} else if (!inFrontEnd && curSkedEntry == backSked_end) {
return true;
}
@ -915,6 +921,10 @@ class InOrderDynInst : public FastAlloc, public RefCounted
virtual void setRegOtherThread(unsigned idx, const uint64_t &val,
ThreadID tid = InvalidThreadID);
/** Returns the number of consecutive store conditional failures. */
unsigned readStCondFailures()
{ return thread->storeCondFailures; }
/** Sets the number of consecutive store conditional failures. */
void setStCondFailures(unsigned sc_failures)
{ thread->storeCondFailures = sc_failures; }

View file

@ -130,6 +130,7 @@ PipelineStage::setTimeBuffer(TimeBuffer<TimeStruct> *tb_ptr)
timeBuffer = tb_ptr;
// Setup wire to write information back to fetch.
// @todo: should this be writing to the next stage => -1 and reading from is (0)???
toPrevStages = timeBuffer->getWire(0);
// Create wires to get information from proper places in time buffer.

View file

@ -58,6 +58,15 @@ AGENUnit::execute(int slot_num)
#endif
InstSeqNum seq_num = inst->seqNum;
if (inst->fault != NoFault) {
DPRINTF(InOrderAGEN,
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
"next stage.\n", tid, inst->seqNum, inst->fault->name(),
inst->pcState());
agen_req->done();
return;
}
switch (agen_req->cmd)
{
case GenerateAddr:

View file

@ -68,8 +68,14 @@ BranchPredictor::execute(int slot_num)
{
ResourceRequest* bpred_req = reqs[slot_num];
DynInstPtr inst = bpred_req->inst;
ThreadID tid = inst->readTid();
InstSeqNum seq_num = inst->seqNum;
if (inst->fault != NoFault) {
DPRINTF(InOrderBPred,
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
"next stage.\n", inst->readTid(), inst->seqNum, inst->fault->name(),
inst->pcState());
bpred_req->done();
return;
}
if (!inst->isControl()) {
DPRINTF(Resource, "Ignoring %s, not a control inst.\n",
@ -78,7 +84,8 @@ BranchPredictor::execute(int slot_num)
return;
}
ThreadID tid = inst->readTid();
InstSeqNum seq_num = inst->seqNum;
switch (bpred_req->cmd)
{
case PredictBranch:
@ -110,6 +117,8 @@ BranchPredictor::execute(int slot_num)
inst->setBranchPred(predict_taken);
}
//@todo: Check to see how hw_rei is handled here...how does PC,NPC get
// updated to compare mispredict against???
inst->setPredTarg(pred_PC);
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: %s Predicted PC is "
"%s.\n", tid, seq_num, inst->instName(), pred_PC);

View file

@ -395,7 +395,7 @@ CacheUnit::setupMemRequest(DynInstPtr inst, CacheReqPtr cache_req,
if (cache_req->memReq == NULL) {
cache_req->memReq =
new Request(cpu->asid[tid], aligned_addr, acc_size, flags,
inst->instAddr(), cpu->readCpuId(),
inst->instAddr(), cpu->readCpuId(), //@todo: use context id
tid);
DPRINTF(InOrderCachePort, "[sn:%i] Created memReq @%x, ->%x\n",
inst->seqNum, &cache_req->memReq, cache_req->memReq);
@ -685,6 +685,15 @@ CacheUnit::execute(int slot_num)
}
DynInstPtr inst = cache_req->inst;
if (inst->fault != NoFault) {
DPRINTF(InOrderCachePort,
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
"next stage.\n", inst->readTid(), inst->seqNum, inst->fault->name(),
inst->getMemAddr());
finishCacheUnitReq(inst, cache_req);
return;
}
#if TRACING_ON
ThreadID tid = inst->readTid();
std::string acc_type = "write";
@ -747,14 +756,6 @@ CacheUnit::execute(int slot_num)
"[tid:%i]: [sn:%i]: Trying to Complete Data Read Access\n",
tid, inst->seqNum);
if (inst->fault != NoFault) {
DPRINTF(InOrderCachePort,
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
"next stage.\n", tid, inst->seqNum, inst->fault->name(),
inst->getMemAddr());
finishCacheUnitReq(inst, cache_req);
return;
}
//@todo: timing translations need to check here...
assert(!inst->isInstPrefetch() && "Can't Handle Inst. Prefecthes");
@ -774,14 +775,6 @@ CacheUnit::execute(int slot_num)
"[tid:%i]: [sn:%i]: Trying to Complete Data Write Access\n",
tid, inst->seqNum);
if (inst->fault != NoFault) {
DPRINTF(InOrderCachePort,
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to ",
"next stage.\n", tid, inst->seqNum, inst->fault->name(),
inst->getMemAddr());
finishCacheUnitReq(inst, cache_req);
return;
}
//@todo: check that timing translation is finished here
RequestPtr mem_req = cache_req->memReq;
@ -937,7 +930,7 @@ CacheUnit::doCacheAccess(DynInstPtr inst, uint64_t *write_res,
if (mem_req->isLLSC()) {
assert(cache_req->inst->isStoreConditional());
DPRINTF(InOrderCachePort, "Evaluating Store Conditional access\n");
do_access = TheISA::handleLockedWrite(cpu, mem_req);
do_access = TheISA::handleLockedWrite(inst.get(), mem_req);
}
}
@ -1129,7 +1122,7 @@ CacheUnit::processCacheCompletion(PacketPtr pkt)
DPRINTF(InOrderCachePort,
"[tid:%u]: Handling Load-Linked for [sn:%u]\n",
tid, inst->seqNum);
TheISA::handleLockedRead(cpu, cache_pkt->req);
TheISA::handleLockedRead(inst.get(), cache_pkt->req);
}
DPRINTF(InOrderCachePort,
@ -1280,7 +1273,7 @@ void
CacheUnit::squash(DynInstPtr inst, int stage_num,
InstSeqNum squash_seq_num, ThreadID tid)
{
if (tlbBlockSeqNum[tid] &&
if (tlbBlocked[tid] &&
tlbBlockSeqNum[tid] > squash_seq_num) {
DPRINTF(InOrderCachePort, "Releasing TLB Block due to "
" squash after [sn:%i].\n", squash_seq_num);

View file

@ -59,13 +59,18 @@ DecodeUnit::execute(int slot_num)
{
case DecodeInst:
{
assert(!inst->staticInst->isMacroop());
DPRINTF(Decode,"Decoded instruction [sn:%i]: %s : 0x%x\n",
inst->seqNum, inst->instName(),
inst->staticInst->machInst);
inst->setBackSked(cpu->createBackEndSked(inst));
if (inst->fault != NoFault) {
inst->setBackSked(cpu->faultSked);
DPRINTF(Decode,"[tid:%i]: Fault found for instruction [sn:%i]\n",
inst->readTid(), inst->seqNum);
} else {
assert(!inst->staticInst->isMacroop());
inst->setBackSked(cpu->createBackEndSked(inst));
DPRINTF(Decode,"Decoded instruction [sn:%i]: %s : 0x%x\n",
inst->seqNum, inst->instName(),
inst->staticInst->machInst);
}
if (inst->backSked != NULL) {
DPRINTF(InOrderDecode,

View file

@ -87,6 +87,15 @@ ExecutionUnit::execute(int slot_num)
{
ResourceRequest* exec_req = reqs[slot_num];
DynInstPtr inst = reqs[slot_num]->inst;
if (inst->fault != NoFault) {
DPRINTF(InOrderExecute,
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
"next stage.\n", inst->readTid(), inst->seqNum, inst->fault->name(),
inst->pcState());
exec_req->done();
return;
}
Fault fault = NoFault;
Tick cur_tick = curTick();
unsigned stage_num = exec_req->getStageNum();

View file

@ -81,6 +81,15 @@ FetchSeqUnit::execute(int slot_num)
ThreadID tid = inst->readTid();
int stage_num = fs_req->getStageNum();
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:
@ -302,8 +311,6 @@ 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]);
}

View file

@ -247,7 +247,14 @@ FetchUnit::execute(int slot_num)
Addr block_addr = cacheBlockAlign(inst->getMemAddr());
int asid = cpu->asid[tid];
inst->fault = NoFault;
if (inst->fault != NoFault) {
DPRINTF(InOrderCachePort,
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
"next stage.\n", tid, inst->seqNum, inst->fault->name(),
cacheBlockAlign(inst->getMemAddr()));
finishCacheUnitReq(inst, cache_req);
return;
}
switch (cache_req->cmd)
{
@ -295,7 +302,7 @@ FetchUnit::execute(int slot_num)
return;
}
doTLBAccess(inst, cache_req, cacheBlkSize, 0, TheISA::TLB::Execute);
doTLBAccess(inst, cache_req, cacheBlkSize, Request::INST_FETCH, TheISA::TLB::Execute);
if (inst->fault == NoFault) {
DPRINTF(InOrderCachePort,
@ -320,6 +327,15 @@ FetchUnit::execute(int slot_num)
}
case CompleteFetch:
if (inst->fault != NoFault) {
DPRINTF(InOrderCachePort,
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
"next stage.\n", tid, inst->seqNum, inst->fault->name(),
inst->getMemAddr());
finishCacheUnitReq(inst, cache_req);
return;
}
if (cache_req->fetchBufferFill) {
// Block request if it's depending on a previous fetch, but it hasnt made it yet
std::list<FetchBlock*>::iterator fetch_it = findBlock(fetchBuffer, asid, block_addr);

View file

@ -37,12 +37,13 @@ using namespace ThePipeline;
GraduationUnit::GraduationUnit(std::string res_name, int res_id, int res_width,
int res_latency, InOrderCPU *_cpu,
ThePipeline::Params *params)
: Resource(res_name, res_id, res_width, res_latency, _cpu),
lastNonSpecTick(0)
: Resource(res_name, res_id, res_width, res_latency, _cpu)
{
for (ThreadID tid = 0; tid < ThePipeline::MaxThreads; tid++) {
nonSpecInstActive[tid] = &cpu->nonSpecInstActive[tid];
nonSpecSeqNum[tid] = &cpu->nonSpecSeqNum[tid];
lastNonSpecTick[tid] = 0;
lastFaultTick[tid] = 0;
}
}
@ -53,6 +54,25 @@ GraduationUnit::execute(int slot_num)
DynInstPtr inst = reqs[slot_num]->inst;
ThreadID tid = inst->readTid();
int stage_num = inst->curSkedEntry->stageNum;
Tick cur_tick = curTick();
//@todo: not the common case, anyway we can move this
// check to the stage and just ignore instructions
// after?
if (lastNonSpecTick[tid] == cur_tick) {
DPRINTF(InOrderGraduation, "Unable to graduate [sn:%i]. "
"Only 1 nonspec inst. per cycle can graduate.\n");
grad_req->done(false);
return;
}
if (lastFaultTick[tid] == cur_tick) {
DPRINTF(InOrderGraduation, "Unable to graduate [sn:%i]. "
"Only 1 fault can be handled per tick.\n");
grad_req->done(false);
return;
}
switch (grad_req->cmd)
{
@ -64,6 +84,7 @@ GraduationUnit::execute(int slot_num)
tid, inst->seqNum, inst->fault->name(),
inst->instName());
squashThenTrap(stage_num, inst);
lastFaultTick[tid] = cur_tick;
grad_req->done(false);
return;
}
@ -76,13 +97,6 @@ GraduationUnit::execute(int slot_num)
case GraduateInst:
{
if (lastNonSpecTick == curTick()) {
DPRINTF(InOrderGraduation, "Unable to graduate [sn:%i]. "
"Only 1 nonspec inst. per cycle can graduate.\n");
grad_req->done(false);
return;
}
DPRINTF(InOrderGraduation,
"[tid:%i]:[sn:%i]: Graduating instruction %s.\n",
tid, inst->seqNum, inst->staticInst->disassemble(inst->instAddr()));
@ -90,16 +104,19 @@ GraduationUnit::execute(int slot_num)
// Release Non-Speculative "Block" on instructions that could not
// execute because there was a non-speculative inst. active.
// @TODO: Fix this functionality. Probably too conservative.
// Maybe it should be, non-spec. insts should block other
// non-spec insts because they can potentially be reading
// system state that will be changed by the 1st non-spec inst.
if (inst->isNonSpeculative()) {
*nonSpecInstActive[tid] = false;
DPRINTF(InOrderGraduation,
"[tid:%i] Non-speculative inst [sn:%i] graduated\n",
tid, inst->seqNum);
lastNonSpecTick = curTick();
lastNonSpecTick[tid] = cur_tick;
}
if (inst->traceData) {
inst->traceData->setStageCycle(stage_num, curTick());
inst->traceData->setStageCycle(stage_num, cur_tick);
}
// Tell CPU that instruction is finished processing

View file

@ -58,9 +58,9 @@ class GraduationUnit : public Resource {
void execute(int slot_num);
protected:
Tick lastNonSpecTick;
Tick lastNonSpecTick[ThePipeline::MaxThreads];
Tick lastFaultTick[ThePipeline::MaxThreads];
bool *nonSpecInstActive[ThePipeline::MaxThreads];
InstSeqNum *nonSpecSeqNum[ThePipeline::MaxThreads];
};

View file

@ -192,7 +192,15 @@ MultDivUnit::execute(int slot_num)
{
ResourceRequest* mult_div_req = reqs[slot_num];
DynInstPtr inst = reqs[slot_num]->inst;
if (inst->fault != NoFault) {
DPRINTF(InOrderMDU,
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
"next stage.\n", inst->readTid(), inst->seqNum, inst->fault->name(),
inst->pcState());
mult_div_req->done();
return;
}
DPRINTF(InOrderMDU, "Executing [sn:%i] ...\n", slot_num);
switch (mult_div_req->cmd)

View file

@ -92,6 +92,9 @@ UseDefUnit::regStats()
.desc("Total Accesses (Read+Write) to the FP Register File");
floatRegFileAccs = floatRegFileReads + floatRegFileWrites;
//@todo: add miscreg reads/writes
// add forwarding by type???
regForwards
.name(name() + ".regForwards")
.desc("Number of Registers Read Through Forwarding Logic");
@ -153,12 +156,19 @@ UseDefUnit::execute(int slot_idx)
// for performance considerations
UseDefRequest* ud_req = dynamic_cast<UseDefRequest*>(reqs[slot_idx]);
assert(ud_req);
DynInstPtr inst = ud_req->inst;
if (inst->fault != NoFault) {
DPRINTF(InOrderUseDef,
"[tid:%i]: [sn:%i]: Detected %s fault @ %x. Forwarding to "
"next stage.\n", inst->readTid(), inst->seqNum, inst->fault->name(),
inst->pcState());
ud_req->done();
return;
}
ThreadID tid = inst->readTid();
InstSeqNum seq_num = inst->seqNum;
int ud_idx = ud_req->useDefIdx;
// If there is a non-speculative instruction
// in the pipeline then stall instructions here
if (*nonSpecInstActive[tid] == true && seq_num > *nonSpecSeqNum[tid]) {