fetch_impl.hh

来自「linux下基于c++的处理器仿真平台。具有处理器流水线」· HH 代码 · 共 621 行 · 第 1/2 页

HH
621
字号
        DPRINTF(Fetch, "Fetch: Squashing outstanding Icache miss.\n");        // @todo: Use an actual thread number here.        icacheInterface->squash(0);    }    _status = Squashing;        ++fetchSquashCycles;}template<class Impl>voidSimpleFetch<Impl>::squashFromDecode(const Addr &new_PC,                                    const InstSeqNum &seq_num){    DPRINTF(Fetch, "Fetch: Squashing from decode.\n");    doSquash(new_PC);    // Tell the CPU to remove any instructions that are in flight between    // fetch and decode.    cpu->removeInstsUntil(seq_num);}template <class Impl>voidSimpleFetch<Impl>::squash(const Addr &new_PC){    DPRINTF(Fetch, "Fetch: Squash from commit.\n");    doSquash(new_PC);    // Tell the CPU to remove any instructions that are not in the ROB.    cpu->removeInstsNotInROB();}template<class Impl>voidSimpleFetch<Impl>::tick(){    // Check squash signals from commit.    if (fromCommit->commitInfo.squash) {        DPRINTF(Fetch, "Fetch: Squashing instructions due to squash "                "from commit.\n");        // In any case, squash.        squash(fromCommit->commitInfo.nextPC);        // Also check if there's a mispredict that happened.        if (fromCommit->commitInfo.branchMispredict) {            branchPred.squash(fromCommit->commitInfo.doneSeqNum,                              fromCommit->commitInfo.nextPC,                              fromCommit->commitInfo.branchTaken);        } else {            branchPred.squash(fromCommit->commitInfo.doneSeqNum);        }        return;    } else if (fromCommit->commitInfo.doneSeqNum) {        // Update the branch predictor if it wasn't a squashed instruction         // that was braodcasted.        branchPred.update(fromCommit->commitInfo.doneSeqNum);    }    // Check ROB squash signals from commit.    if (fromCommit->commitInfo.robSquashing) {        DPRINTF(Fetch, "Fetch: ROB is still squashing.\n");        // Continue to squash.        _status = Squashing;        ++fetchSquashCycles;        return;    }    // Check squash signals from decode.    if (fromDecode->decodeInfo.squash) {        DPRINTF(Fetch, "Fetch: Squashing instructions due to squash "                "from decode.\n");        // Update the branch predictor.        if (fromDecode->decodeInfo.branchMispredict) {            branchPred.squash(fromDecode->decodeInfo.doneSeqNum,                              fromDecode->decodeInfo.nextPC,                              fromDecode->decodeInfo.branchTaken);        } else {            branchPred.squash(fromDecode->decodeInfo.doneSeqNum);        }        if (_status != Squashing) {            // Squash unless we're already squashing?            squashFromDecode(fromDecode->decodeInfo.nextPC,                             fromDecode->decodeInfo.doneSeqNum);            return;        }    }    // Check if any of the stall signals are high.    if (fromDecode->decodeInfo.stall ||        fromRename->renameInfo.stall ||        fromIEW->iewInfo.stall ||        fromCommit->commitInfo.stall)     {        // Block stage, regardless of current status.        DPRINTF(Fetch, "Fetch: Stalling stage.\n");        DPRINTF(Fetch, "Fetch: Statuses: Decode: %i Rename: %i IEW: %i "                "Commit: %i\n",                 fromDecode->decodeInfo.stall,                fromRename->renameInfo.stall,                fromIEW->iewInfo.stall,                fromCommit->commitInfo.stall);                _status = Blocked;        ++fetchBlockedCycles;        return;    } else if (_status == Blocked) {        // Unblock stage if status is currently blocked and none of the        // stall signals are being held high.        _status = Running;        ++fetchBlockedCycles;        return;    }     // If fetch has reached this point, then there are no squash signals    // still being held high.  Check if fetch is in the squashing state;    // if so, fetch can switch to running.    // Similarly, there are no blocked signals still being held high.    // Check if fetch is in the blocked state; if so, fetch can switch to    // running.    if (_status == Squashing) {        DPRINTF(Fetch, "Fetch: Done squashing, switching to running.\n");        // Switch status to running        _status = Running;        ++fetchCycles;        fetch();    } else if (_status != IcacheMissStall) {        DPRINTF(Fetch, "Fetch: Running stage.\n");        ++fetchCycles;        fetch();    }}template<class Impl>voidSimpleFetch<Impl>::fetch(){    //////////////////////////////////////////    // Start actual fetch    //////////////////////////////////////////    // The current PC.    Addr fetch_PC = cpu->readPC();    // Fault code for memory access.    Fault fault = No_Fault;    // If returning from the delay of a cache miss, then update the status    // to running, otherwise do the cache access.  Possibly move this up    // to tick() function.    if (_status == IcacheMissComplete) {        DPRINTF(Fetch, "Fetch: Icache miss is complete.\n");        // Reset the completion event to NULL.        memReq->completionEvent = NULL;        _status = Running;    } else {        DPRINTF(Fetch, "Fetch: Attempting to translate and read "                       "instruction, starting at PC %08p.\n",                fetch_PC);        fault = fetchCacheLine(fetch_PC);    }    // If we had a stall due to an icache miss, then return.  It'd    // be nicer if this were handled through the kind of fault that    // is returned by the function.    if (_status == IcacheMissStall) {        return;    }    // As far as timing goes, the CPU will need to send an event through    // the MemReq in order to be woken up once the memory access completes.    // Probably have a status on a per thread basis so each thread can    // block independently and be woken up independently.    Addr next_PC = fetch_PC;    InstSeqNum inst_seq;    MachInst inst;    unsigned offset = fetch_PC & cacheBlkMask;    unsigned fetched;    if (fault == No_Fault) {        // If the read of the first instruction was successful, then grab the        // instructions from the rest of the cache line and put them into the        // queue heading to decode.        DPRINTF(Fetch, "Fetch: Adding instructions to queue to decode.\n");        //////////////////////////        // Fetch first instruction        //////////////////////////            // Need to keep track of whether or not a predicted branch        // ended this fetch block.        bool predicted_branch = false;        for (fetched = 0;              offset < cacheBlkSize &&                 fetched < fetchWidth &&                 !predicted_branch;              ++fetched)        {            // Get a sequence number.            inst_seq = cpu->getAndIncrementInstSeq();            // Make sure this is a valid index.            assert(offset <= cacheBlkSize - instSize);            // Get the instruction from the array of the cache line.            inst = gtoh(*reinterpret_cast<MachInst *>                        (&cacheData[offset]));            // Create a new DynInst from the instruction fetched.            DynInstPtr instruction = new DynInst(inst, fetch_PC, next_PC,                                                 inst_seq, cpu);            DPRINTF(Fetch, "Fetch: Instruction %i created, with PC %#x\n",                    inst_seq, instruction->readPC());            DPRINTF(Fetch, "Fetch: Instruction opcode is: %03p\n",                    OPCODE(inst));                        instruction->traceData =                Trace::getInstRecord(curTick, cpu->xcBase(), cpu,                                     instruction->staticInst,                                     instruction->readPC(), 0);            predicted_branch = lookupAndUpdateNextPC(instruction, next_PC);            // Add instruction to the CPU's list of instructions.            cpu->addInst(instruction);            // Write the instruction to the first slot in the queue            // that heads to decode.            toDecode->insts[fetched] = instruction;            toDecode->size++;            // Increment stat of fetched instructions.            ++fetchedInsts;            // Move to the next instruction, unless we have a branch.            fetch_PC = next_PC;            offset+= instSize;        }        fetch_nisn_dist.sample(fetched);    }    // Now that fetching is completed, update the PC to signify what the next    // cycle will be.  Might want to move this to the beginning of this    // function so that the PC updates at the beginning of everything.    // Or might want to leave setting the PC to the main CPU, with fetch    // only changing the nextPC (will require correct determination of    // next PC).    if (fault == No_Fault) {        DPRINTF(Fetch, "Fetch: Setting PC to %08p.\n", next_PC);        cpu->setPC(next_PC);        cpu->setNextPC(next_PC + instSize);    } else {        // If the issue was an icache miss, then we can just return and        // wait until it is handled.        if (_status == IcacheMissStall) {            return;        }        // Handle the fault.        // 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.        DPRINTF(Fetch, "Fetch: Blocked, need to handle the trap.\n");        _status = Blocked;#if FULL_SYSTEM//        cpu->trap(fault);        // Send a signal to the ROB indicating that there's a trap from the         // fetch stage that needs to be handled.  Need to indicate that        // there's a fault, and the fault type.#else // !FULL_SYSTEM    	fatal("fault (%d) detected @ PC %08p", fault, cpu->readPC());#endif // FULL_SYSTEM    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?