iew_impl.hh

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

HH
740
字号
                DPRINTF(IEW, "IEW: Issue: IQ has become full.\n");                // Call function to start blocking.                block();                // Tell previous stage to stall.                toRename->iewInfo.stall = true;                ++iewIQFullEvents;                break;            } else if (inst->isLoad()) {                DPRINTF(IEW, "IEW: Issue: Memory instruction "                        "encountered, adding to LDSTQ.\n");                // Reserve a spot in the load store queue for this                // memory access.                ldstQueue.insertLoad(inst);                ++iewDispLoadInsts;            } else if (inst->isStore()) {                ldstQueue.insertStore(inst);                ++iewDispStoreInsts;            } else if (inst->isNonSpeculative()) {                DPRINTF(IEW, "IEW: Issue: Nonspeculative instruction "                        "encountered, skipping.\n");                // Same hack as with stores.                inst->setCanCommit();                                // Specificall insert it as nonspeculative.                instQueue.insertNonSpec(inst);                ++iewDispNonSpecInsts;                continue;            } else if (inst->isNop()) {                DPRINTF(IEW, "IEW: Issue: Nop instruction encountered "                        ", skipping.\n");                inst->setIssued();                inst->setExecuted();                inst->setCanCommit();                instQueue.advanceTail(inst);                continue;            } else if (inst->isExecuted()) {                assert(0 && "Instruction shouldn't be executed.\n");                DPRINTF(IEW, "IEW: Issue: Executed branch encountered, "                        "skipping.\n");                inst->setIssued();                inst->setCanCommit();                instQueue.advanceTail(inst);                continue;            }            // If the instruction queue is not full, then add the             // instruction.            instQueue.insert(fromRename->insts[inst_num]);            ++iewDispatchedInsts;        }    }}template <class Impl>voidSimpleIEW<Impl>::executeInsts(){    ////////////////////////////////////////    //EXECUTE/WRITEBACK stage    ////////////////////////////////////////    //Put into its own function?    //Similarly should probably have separate execution for int vs FP.    // Above comment is handled by the issue queue only issuing a valid    // mix of int/fp instructions.    //Actually okay to just have one execution, buuuuuut will need    //somewhere that defines the execution latency of all instructions.    // @todo: Move to the FU pool used in the current full cpu.    int fu_usage = 0;    bool fetch_redirect = false;    int inst_slot = 0;    int time_slot = 0;    // Execute/writeback any instructions that are available.    for (int inst_num = 0;          fu_usage < executeWidth && /* Haven't exceeded available FU's. */             inst_num < issueWidth &&             fromIssue->insts[inst_num];          ++inst_num) {        DPRINTF(IEW, "IEW: Execute: Executing instructions from IQ.\n");        // Get instruction from issue's queue.        DynInstPtr inst = fromIssue->insts[inst_num];        DPRINTF(IEW, "IEW: Execute: Processing PC %#x.\n", inst->readPC());        // Check if the instruction is squashed; if so then skip it        // and don't count it towards the FU usage.        if (inst->isSquashed()) {            DPRINTF(IEW, "IEW: Execute: Instruction was squashed.\n");            // Consider this instruction executed so that commit can go            // ahead and retire the instruction.            inst->setExecuted();            toCommit->insts[inst_num] = inst;            ++iewExecSquashedInsts;            continue;        }         inst->setExecuted();        // If an instruction is executed, then count it towards FU usage.        ++fu_usage;        // Execute instruction.        // Note that if the instruction faults, it will be handled        // at the commit stage.        if (inst->isMemRef()) {            DPRINTF(IEW, "IEW: Execute: Calculating address for memory "                    "reference.\n");            // Tell the LDSTQ to execute this instruction (if it is a load).            if (inst->isLoad()) {                ldstQueue.executeLoad(inst);                ++iewExecLoadInsts;            } else if (inst->isStore()) {                ldstQueue.executeStore(inst);                ++iewExecStoreInsts;            } else {                panic("IEW: Unexpected memory type!\n");            }        } else {            inst->execute();            ++iewExecutedInsts;        }        // First check the time slot that this instruction will write        // to.  If there are free write ports at the time, then go ahead        // and write the instruction to that time.  If there are not,        // keep looking back to see where's the first time there's a        // free slot.  What happens if you run out of free spaces?        // For now naively assume that all instructions take one cycle.        // Otherwise would have to look into the time buffer based on the        // latency of the instruction.        (*iewQueue)[time_slot].insts[inst_slot];        while ((*iewQueue)[time_slot].insts[inst_slot]) {            if (inst_slot < issueWidth) {                ++inst_slot;            } else {                ++time_slot;                inst_slot = 0;            }            assert(time_slot < 5);        }        // May actually have to work this out, especially with loads and stores        // Add finished instruction to queue to commit.        (*iewQueue)[time_slot].insts[inst_slot] = inst;        (*iewQueue)[time_slot].size++;        // Check if branch was correct.  This check happens after the        // instruction is added to the queue because even if the branch        // is mispredicted, the branch instruction itself is still valid.        // Only handle this if there hasn't already been something that         // redirects fetch in this group of instructions.        if (!fetch_redirect) {            if (inst->mispredicted()) {                fetch_redirect = true;                                DPRINTF(IEW, "IEW: Execute: Branch mispredict detected.\n");                DPRINTF(IEW, "IEW: Execute: Redirecting fetch to PC: %#x.\n",                        inst->nextPC);                                // If incorrect, then signal the ROB that it must be squashed.                squashDueToBranch(inst);                if (inst->predTaken()) {                    predictedTakenIncorrect++;                }            } else if (ldstQueue.violation()) {                fetch_redirect = true;                // Get the DynInst that caused the violation.                DynInstPtr violator = ldstQueue.getMemDepViolator();                DPRINTF(IEW, "IEW: LDSTQ detected a violation.  Violator PC: "                        "%#x, inst PC: %#x.  Addr is: %#x.\n",                        violator->readPC(), inst->readPC(), inst->physEffAddr);                // Tell the instruction queue that a violation has occured.                instQueue.violation(inst, violator);                                // Squash.                squashDueToMem(inst);                ++memOrderViolationEvents;            }        }    }}template<class Impl>void SimpleIEW<Impl>::tick(){    // Considering putting all the state-determining stuff in this section.        // Try to fill up issue queue with as many instructions as bandwidth    // allows.    // Decode should try to execute as many instructions as its bandwidth    // will allow, as long as it is not currently blocked.    // Check if the stage is in a running status.    if (_status != Blocked && _status != Squashing) {        DPRINTF(IEW, "IEW: Status is not blocked, attempting to run "                     "stage.\n");        iew();                // If it's currently unblocking, check to see if it should switch        // to running.        if (_status == Unblocking) {            unblock();            ++iewUnblockCycles;        }    } else if (_status == Squashing) {        DPRINTF(IEW, "IEW: Still squashing.\n");        // Check if stage should remain squashing.  Stop squashing if the         // squash signal clears.        if (!fromCommit->commitInfo.squash &&            !fromCommit->commitInfo.robSquashing) {            DPRINTF(IEW, "IEW: Done squashing, changing status to "                    "running.\n");            _status = Running;            instQueue.stopSquash();        } else {            instQueue.doSquash();        }        ++iewSquashCycles;    } else if (_status == Blocked) {        // Continue to tell previous stage to stall.        toRename->iewInfo.stall = true;        // Check if possible stall conditions have cleared.        if (!fromCommit->commitInfo.stall &&             !instQueue.isFull()) {            DPRINTF(IEW, "IEW: Stall signals cleared, going to unblock.\n");            _status = Unblocking;        }         // If there's still instructions coming from rename, continue to        // put them on the skid buffer.        if (fromRename->size == 0) {            block();        }        if (fromCommit->commitInfo.squash ||            fromCommit->commitInfo.robSquashing) {            squash();        }        ++iewBlockCycles;    }        // @todo: Maybe put these at the beginning, so if it's idle it can    // return early.    // Write back number of free IQ entries here.    toRename->iewInfo.freeIQEntries = instQueue.numFreeEntries();    ldstQueue.writebackStores();    // Check the committed load/store signals to see if there's a load    // or store to commit.  Also check if it's being told to execute a    // nonspeculative instruction.    // This is pretty inefficient...    if (!fromCommit->commitInfo.squash &&        !fromCommit->commitInfo.robSquashing) {        ldstQueue.commitStores(fromCommit->commitInfo.doneSeqNum);        ldstQueue.commitLoads(fromCommit->commitInfo.doneSeqNum);    }    if (fromCommit->commitInfo.nonSpecSeqNum != 0) {        instQueue.scheduleNonSpec(fromCommit->commitInfo.nonSpecSeqNum);    }    DPRINTF(IEW, "IEW: IQ has %i free entries.\n",             instQueue.numFreeEntries());}template<class Impl>voidSimpleIEW<Impl>::iew(){    // Might want to put all state checks in the tick() function.    // Check if being told to stall from commit.    if (fromCommit->commitInfo.stall) {        block();        return;    } else if (fromCommit->commitInfo.squash ||               fromCommit->commitInfo.robSquashing) {        // Also check if commit is telling this stage to squash.        squash();        return;    }    dispatchInsts();    // Have the instruction queue try to schedule any ready instructions.    instQueue.scheduleReadyInsts();    executeInsts();    // Loop through the head of the time buffer and wake any dependents.    // These instructions are about to write back.  In the simple model    // this loop can really happen within the previous loop, but when    // instructions have actual latencies, this loop must be separate.    // Also mark scoreboard that this instruction is finally complete.    // Either have IEW have direct access to rename map, or have this as    // part of backwards communication.    for (int inst_num = 0; inst_num < issueWidth &&             toCommit->insts[inst_num]; inst_num++)    {        DynInstPtr inst = toCommit->insts[inst_num];        DPRINTF(IEW, "IEW: Sending instructions to commit, PC %#x.\n",                inst->readPC());        if(!inst->isSquashed()) {            instQueue.wakeDependents(inst);                for (int i = 0; i < inst->numDestRegs(); i++)            {                renameMap->markAsReady(inst->renamedDestRegIdx(i));            }        }    }    // Also should advance its own time buffers if the stage ran.    // Not the best place for it, but this works (hopefully).    issueToExecQueue.advance();}#if !FULL_SYSTEMtemplate<class Impl>voidSimpleIEW<Impl>::lsqWriteback(){    ldstQueue.writebackAllInsts();}#endif

⌨️ 快捷键说明

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