From: Kevin Lim Date: Wed, 17 May 2006 18:25:10 +0000 (-0400) Subject: Faults generated at fetch are passed to the backend by creating a dummy nop instructi... X-Git-Tag: m5_2.0_beta1~36^2~108^2~20 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=36581a534240c322e1fc28b8bd6e8f13f2b0fefd;p=gem5.git Faults generated at fetch are passed to the backend by creating a dummy nop instruction and giving it the fault. This unifies front end faults and normal instruction faults. cpu/checker/cpu.cc: Fixups for fetch fault being sent with the instruction. cpu/o3/fetch_impl.hh: cpu/ozone/front_end_impl.hh: Send any faults generated at fetch along with a fake nop instruction to the back end. This avoids having to use direct communication to check if the entire front end has drained; it is naturally handled through the nop's fault being handled when it reaches the head of commit. cpu/ozone/front_end.hh: Add extra status TrapPending. cpu/ozone/lw_back_end_impl.hh: Fetch fault handled through a dummy nop carrying the fetch fault. Avoid putting Nops on the exeList. --HG-- extra : convert_revision : 8d9899748b34c204763a49c48a9b5113864f5789 --- diff --git a/cpu/checker/cpu.cc b/cpu/checker/cpu.cc index f1b43f601..f76f1e063 100644 --- a/cpu/checker/cpu.cc +++ b/cpu/checker/cpu.cc @@ -607,41 +607,46 @@ Checker::tick(DynInstPtr &completed_inst) bool succeeded = translateInstReq(memReq); if (!succeeded) { - warn("Instruction PC %#x was not found in the ITB!", - cpuXC->readPC()); - handleError(); + if (inst->getFault() == NoFault) { + warn("Instruction PC %#x was not found in the ITB!", + cpuXC->readPC()); + handleError(); - // go to the next instruction - cpuXC->setPC(cpuXC->readNextPC()); - cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst)); + // go to the next instruction + cpuXC->setPC(cpuXC->readNextPC()); + cpuXC->setNextPC(cpuXC->readNextPC() + sizeof(MachInst)); - return; + return; + } else { + fault = inst->getFault(); + } } -// if (fault == NoFault) + if (fault == NoFault) { // fault = cpuXC->mem->read(memReq, machInst); - cpuXC->mem->read(memReq, machInst); + cpuXC->mem->read(memReq, machInst); - // If we've got a valid instruction (i.e., no fault on instruction - // fetch), then execute it. + // If we've got a valid instruction (i.e., no fault on instruction + // fetch), then execute it. // keep an instruction count - numInst++; + numInst++; // numInsts++; - // decode the instruction - machInst = gtoh(machInst); - // Checks that the instruction matches what we expected it to be. - // Checks both the machine instruction and the PC. - validateInst(inst); + // decode the instruction + machInst = gtoh(machInst); + // Checks that the instruction matches what we expected it to be. + // Checks both the machine instruction and the PC. + validateInst(inst); - curStaticInst = StaticInst::decode(makeExtMI(machInst, cpuXC->readPC())); + curStaticInst = StaticInst::decode(makeExtMI(machInst, cpuXC->readPC())); #if FULL_SYSTEM - cpuXC->setInst(machInst); + cpuXC->setInst(machInst); #endif // FULL_SYSTEM - fault = inst->getFault(); + fault = inst->getFault(); + } // Either the instruction was a fault and we should process the fault, // or we should just go ahead execute the instruction. This assumes diff --git a/cpu/o3/fetch_impl.hh b/cpu/o3/fetch_impl.hh index b4ff69d89..523719945 100644 --- a/cpu/o3/fetch_impl.hh +++ b/cpu/o3/fetch_impl.hh @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2005 The Regents of The University of Michigan + * Copyright (c) 2004-2006 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -27,22 +27,21 @@ */ #include "arch/isa_traits.hh" -#include "sim/byteswap.hh" #include "cpu/exetrace.hh" #include "cpu/o3/fetch.hh" #include "mem/base_mem.hh" #include "mem/mem_interface.hh" #include "mem/mem_req.hh" - +#include "sim/byteswap.hh" #include "sim/root.hh" #if FULL_SYSTEM +#include "arch/tlb.hh" +#include "arch/vtophys.hh" #include "base/remote_gdb.hh" #include "mem/functional/memory_control.hh" #include "mem/functional/physical.hh" #include "sim/system.hh" -#include "arch/tlb.hh" -#include "arch/vtophys.hh" #else // !FULL_SYSTEM #include "mem/functional/functional.hh" #endif // FULL_SYSTEM @@ -136,14 +135,7 @@ DefaultFetch::DefaultFetch(Params *params) // Create a new memory request. memReq[tid] = NULL; -// memReq[tid] = new MemReq(); -/* - // Need a way of setting this correctly for parallel programs - // @todo: Figure out how to properly set asid vs thread_num. - memReq[tid]->asid = tid; - memReq[tid]->thread_num = tid; - memReq[tid]->data = new uint8_t[64]; -*/ + // Create space to store a cache line. cacheData[tid] = new uint8_t[cacheBlkSize]; @@ -261,10 +253,6 @@ DefaultFetch::setCPU(FullCPU *cpu_ptr) DPRINTF(Fetch, "Setting the CPU pointer.\n"); cpu = cpu_ptr; - // Set ExecContexts for Memory Requests -// for (int tid=0; tid < numThreads; tid++) -// memReq[tid]->xc = cpu->xcBase(tid); - // Fetch needs to start fetching instructions at the very beginning, // so it must start up in active state. switchToActive(); @@ -362,9 +350,8 @@ DefaultFetch::processCacheCompletion(MemReqPtr &req) // memcpy(cacheData[tid], memReq[tid]->data, memReq[tid]->size); - // Reset the completion event to NULL. + // Reset the mem req to NULL. memReq[tid] = NULL; -// memReq[tid]->completionEvent = NULL; } template @@ -468,10 +455,6 @@ template bool DefaultFetch::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid) { - // Check if the instruction exists within the cache. - // If it does, then proceed on to read the instruction and the rest - // of the instructions in the cache line until either the end of the - // cache line or a predicted taken branch is encountered. Fault fault = NoFault; #if FULL_SYSTEM @@ -509,7 +492,7 @@ DefaultFetch::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid //#endif // In the case of faults, the fetch stage may need to stall and wait - // on what caused the fetch (ITB or Icache miss). + // for the ITB miss to be handled. // If translation was successful, attempt to read the first // instruction. @@ -518,7 +501,7 @@ DefaultFetch::fetchCacheLine(Addr fetch_PC, Fault &ret_fault, unsigned tid if (cpu->system->memctrl->badaddr(memReq[tid]->paddr) || memReq[tid]->flags & UNCACHEABLE) { DPRINTF(Fetch, "Fetch: Bad address %#x (hopefully on a " - "misspeculating path!", + "misspeculating path)!", memReq[tid]->paddr); ret_fault = TheISA::genMachineCheckFault(); return false; @@ -587,44 +570,9 @@ DefaultFetch::doSquash(const Addr &new_PC, unsigned tid) if (fetchStatus[tid] == IcacheMissStall && icacheInterface) { DPRINTF(Fetch, "[tid:%i]: Squashing outstanding Icache miss.\n", tid); -// icacheInterface->squash(tid); -/* - if (memReq[tid]->completionEvent) { - if (memReq[tid]->completionEvent->scheduled()) { - memReq[tid]->completionEvent->squash(); - } else { - delete memReq[tid]->completionEvent; - memReq[tid]->completionEvent = NULL; - } - } -*/ memReq[tid] = NULL; } - if (fetchStatus[tid] == TrapPending) { - // @todo: Hardcoded number here - - // This is only effective if communication to and from commit - // is identical. If it's faster to commit than it is from - // commit to here, then it causes problems. - - bool found_fault = false; - for (int i = 0; i > -5; --i) { - if (fetchQueue->access(i)->fetchFault) { - DPRINTF(Fetch, "[tid:%i]: Fetch used to be in a trap, " - "clearing it.\n", - tid); - fetchQueue->access(i)->fetchFault = NoFault; - found_fault = true; - } - } - if (!found_fault) { - warn("%lli Fault from fetch not found in time buffer!", - curTick); - } - toDecode->clearFetchFault = true; - } - fetchStatus[tid] = Squashing; ++fetchSquashCycles; @@ -643,7 +591,6 @@ DefaultFetch::squashFromDecode(const Addr &new_PC, // Tell the CPU to remove any instructions that are in flight between // fetch and decode. cpu->removeInstsUntil(seq_num, tid); - youngestSN = seq_num; } template @@ -829,7 +776,6 @@ DefaultFetch::checkSignalsAndUpdate(unsigned tid) // In any case, squash. squash(fromCommit->commitInfo[tid].nextPC,tid); - youngestSN = fromCommit->commitInfo[tid].doneSeqNum; // Also check if there's a mispredict that happened. if (fromCommit->commitInfo[tid].branchMispredict) { @@ -1009,8 +955,6 @@ DefaultFetch::fetch(bool &status_change) // Get a sequence number. inst_seq = cpu->getAndIncrementInstSeq(); - youngestSN = inst_seq; - // Make sure this is a valid index. assert(offset <= cacheBlkSize - instSize); @@ -1095,14 +1039,37 @@ DefaultFetch::fetch(bool &status_change) // This stage will not be able to continue until all the ROB // slots are empty, at which point the fault can be handled. // The only other way it can wake up is if a squash comes along - // and changes the PC. Not sure how to handle that case...perhaps - // have it handled by the upper level CPU class which peeks into the - // time buffer and sees if a squash comes along, in which case it - // changes the status. + // and changes the PC. #if FULL_SYSTEM + assert(numInst != fetchWidth); + // Get a sequence number. + inst_seq = cpu->getAndIncrementInstSeq(); + // We will use a nop in order to carry the fault. + ext_inst = TheISA::NoopMachInst; + + // Create a new DynInst from the dummy nop. + DynInstPtr instruction = new DynInst(ext_inst, fetch_PC, + next_PC, + inst_seq, cpu); + instruction->setPredTarg(next_PC + instSize); + instruction->setThread(tid); + + instruction->setASID(tid); + + instruction->setState(cpu->thread[tid]); + + instruction->traceData = NULL; + + instruction->setInstListIt(cpu->addInst(instruction)); + + instruction->fault = fault; + + toDecode->insts[numInst] = instruction; + toDecode->size++; + // Tell the commit stage the fault we had. - toDecode->fetchFault = fault; - toDecode->fetchFaultSN = cpu->globalSeqNum; +// toDecode->fetchFault = fault; +// toDecode->fetchFaultSN = cpu->globalSeqNum; DPRINTF(Fetch, "[tid:%i]: Blocked, need to handle the trap.\n",tid); diff --git a/cpu/ozone/front_end.hh b/cpu/ozone/front_end.hh index f9db9ea5c..326f7d2c9 100644 --- a/cpu/ozone/front_end.hh +++ b/cpu/ozone/front_end.hh @@ -120,6 +120,7 @@ class FrontEnd SerializeComplete, RenameBlocked, QuiescePending, + TrapPending, BEBlocked }; diff --git a/cpu/ozone/front_end_impl.hh b/cpu/ozone/front_end_impl.hh index 8ae9ec696..cd57aeef4 100644 --- a/cpu/ozone/front_end_impl.hh +++ b/cpu/ozone/front_end_impl.hh @@ -268,11 +268,9 @@ FrontEnd::tick() } if (status == RenameBlocked || status == SerializeBlocked || - status == BEBlocked) { - // This might cause the front end to run even though it - // shouldn't, but this should only be a problem for one cycle. - // Also will cause a one cycle bubble between changing state - // and restarting. + status == TrapPending || status == BEBlocked) { + // Will cause a one cycle bubble between changing state and + // restarting. DPRINTF(FE, "In blocked status.\n"); fetchBlockedCycles++; @@ -537,9 +535,32 @@ void FrontEnd::handleFault(Fault &fault) { DPRINTF(FE, "Fault at fetch, telling commit\n"); - backEnd->fetchFault(fault); +// backEnd->fetchFault(fault); // We're blocked on the back end until it handles this fault. - status = BEBlocked; + status = TrapPending; + + // Get a sequence number. + InstSeqNum inst_seq = getAndIncrementInstSeq(); + // We will use a nop in order to carry the fault. + ExtMachInst ext_inst = TheISA::NoopMachInst; + + // Create a new DynInst from the dummy nop. + DynInstPtr instruction = new DynInst(ext_inst, PC, + PC+sizeof(MachInst), + inst_seq, cpu); + instruction->setPredTarg(instruction->readNextPC()); +// instruction->setThread(tid); + +// instruction->setASID(tid); + + instruction->setState(thread); + + instruction->traceData = NULL; + + instruction->fault = fault; + instruction->setCanIssue(); + instBuffer.push_back(instruction); + ++instBufferSize; } template @@ -881,7 +902,6 @@ FrontEnd::dumpInsts() (*buff_it)->isSquashed()); buff_it++; } - } template diff --git a/cpu/ozone/lw_back_end_impl.hh b/cpu/ozone/lw_back_end_impl.hh index a82dd5b70..db0872e52 100644 --- a/cpu/ozone/lw_back_end_impl.hh +++ b/cpu/ozone/lw_back_end_impl.hh @@ -652,7 +652,7 @@ LWBackEnd::tick() squashFromTrap(); } else if (xcSquash) { squashFromXC(); - } else if (fetchHasFault && robEmpty() && frontEnd->isEmpty() && !LSQ.hasStoresToWB()) { + } /*else if (fetchHasFault && robEmpty() && frontEnd->isEmpty() && !LSQ.hasStoresToWB()) { DPRINTF(BE, "ROB and front end empty, handling fetch fault\n"); Fault fetch_fault = frontEnd->getFault(); if (fetch_fault == NoFault) { @@ -662,7 +662,7 @@ LWBackEnd::tick() handleFault(fetch_fault); fetchHasFault = false; } - } + }*/ #endif if (dispatchStatus != Blocked) { @@ -777,6 +777,12 @@ LWBackEnd::dispatchInsts() inst->seqNum); exeList.push(inst); } + } else if (inst->isNop()) { + DPRINTF(BE, "Nop encountered [sn:%lli], skipping exeList.\n", + inst->seqNum); + inst->setIssued(); + inst->setExecuted(); + inst->setCanCommit(); } else { DPRINTF(BE, "Instruction [sn:%lli] ready, addding to exeList.\n", inst->seqNum);