lsq_unit_impl.hh

来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· HH 代码 · 共 1,015 行 · 第 1/2 页

HH
1,015
字号
        ++storesToWB;    }    assert(store_inst->effAddrValid);    while (load_idx != loadTail) {        // Really only need to check loads that have actually executed        // It's safe to check all loads because effAddr is set to        // InvalAddr when the dyn inst is created.        // @todo: For now this is extra conservative, detecting a        // violation if the addresses match assuming all accesses        // are quad word accesses.        // @todo: Fix this, magic number being used here        if (loadQueue[load_idx]->effAddrValid &&            (loadQueue[load_idx]->effAddr >> 8) ==            (store_inst->effAddr >> 8)) {            // A load incorrectly passed this store.  Squash and refetch.            // For now return a fault to show that it was unsuccessful.            DynInstPtr violator = loadQueue[load_idx];            if (!memDepViolator ||                (violator->seqNum < memDepViolator->seqNum)) {                memDepViolator = violator;            } else {                break;            }            ++lsqMemOrderViolation;            return genMachineCheckFault();        }        incrLdIdx(load_idx);    }    return store_fault;}template <class Impl>voidLSQUnit<Impl>::commitLoad(){    assert(loadQueue[loadHead]);    DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n",            loadQueue[loadHead]->readPC());    loadQueue[loadHead] = NULL;    incrLdIdx(loadHead);    --loads;}template <class Impl>voidLSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst){    assert(loads == 0 || loadQueue[loadHead]);    while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) {        commitLoad();    }}template <class Impl>voidLSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst){    assert(stores == 0 || storeQueue[storeHead].inst);    int store_idx = storeHead;    while (store_idx != storeTail) {        assert(storeQueue[store_idx].inst);        // Mark any stores that are now committed and have not yet        // been marked as able to write back.        if (!storeQueue[store_idx].canWB) {            if (storeQueue[store_idx].inst->seqNum > youngest_inst) {                break;            }            DPRINTF(LSQUnit, "Marking store as able to write back, PC "                    "%#x [sn:%lli]\n",                    storeQueue[store_idx].inst->readPC(),                    storeQueue[store_idx].inst->seqNum);            storeQueue[store_idx].canWB = true;            ++storesToWB;        }        incrStIdx(store_idx);    }}template <class Impl>voidLSQUnit<Impl>::writebackStores(){    while (storesToWB > 0 &&           storeWBIdx != storeTail &&           storeQueue[storeWBIdx].inst &&           storeQueue[storeWBIdx].canWB &&           usedPorts < cachePorts) {        if (isStoreBlocked || lsq->cacheBlocked()) {            DPRINTF(LSQUnit, "Unable to write back any more stores, cache"                    " is blocked!\n");            break;        }        // Store didn't write any data so no need to write it back to        // memory.        if (storeQueue[storeWBIdx].size == 0) {            completeStore(storeWBIdx);            incrStIdx(storeWBIdx);            continue;        }        ++usedPorts;        if (storeQueue[storeWBIdx].inst->isDataPrefetch()) {            incrStIdx(storeWBIdx);            continue;        }        assert(storeQueue[storeWBIdx].req);        assert(!storeQueue[storeWBIdx].committed);        DynInstPtr inst = storeQueue[storeWBIdx].inst;        Request *req = storeQueue[storeWBIdx].req;        storeQueue[storeWBIdx].committed = true;        assert(!inst->memData);        inst->memData = new uint8_t[64];        memcpy(inst->memData, storeQueue[storeWBIdx].data, req->getSize());        MemCmd command =            req->isSwap() ? MemCmd::SwapReq :            (req->isLocked() ? MemCmd::StoreCondReq : MemCmd::WriteReq);        PacketPtr data_pkt = new Packet(req, command,                                        Packet::Broadcast);        data_pkt->dataStatic(inst->memData);        LSQSenderState *state = new LSQSenderState;        state->isLoad = false;        state->idx = storeWBIdx;        state->inst = inst;        data_pkt->senderState = state;        DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "                "to Addr:%#x, data:%#x [sn:%lli]\n",                storeWBIdx, inst->readPC(),                req->getPaddr(), (int)*(inst->memData),                inst->seqNum);        // @todo: Remove this SC hack once the memory system handles it.        if (inst->isStoreConditional()) {            // Disable recording the result temporarily.  Writing to            // misc regs normally updates the result, but this is not            // the desired behavior when handling store conditionals.            inst->recordResult = false;            bool success = TheISA::handleLockedWrite(inst.get(), req);            inst->recordResult = true;            if (!success) {                // Instantly complete this store.                DPRINTF(LSQUnit, "Store conditional [sn:%lli] failed.  "                        "Instantly completing it.\n",                        inst->seqNum);                WritebackEvent *wb = new WritebackEvent(inst, data_pkt, this);                wb->schedule(curTick + 1);                completeStore(storeWBIdx);                incrStIdx(storeWBIdx);                continue;            }        } else {            // Non-store conditionals do not need a writeback.            state->noWB = true;        }        if (!dcachePort->sendTiming(data_pkt)) {            // Need to handle becoming blocked on a store.            DPRINTF(IEW, "D-Cache became blocked when writing [sn:%lli], will"                    "retry later\n",                    inst->seqNum);            isStoreBlocked = true;            ++lsqCacheBlocked;            assert(retryPkt == NULL);            retryPkt = data_pkt;            lsq->setRetryTid(lsqID);        } else {            storePostSend(data_pkt);        }    }    // Not sure this should set it to 0.    usedPorts = 0;    assert(stores >= 0 && storesToWB >= 0);}/*template <class Impl>voidLSQUnit<Impl>::removeMSHR(InstSeqNum seqNum){    list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(),                                              mshrSeqNums.end(),                                              seqNum);    if (mshr_it != mshrSeqNums.end()) {        mshrSeqNums.erase(mshr_it);        DPRINTF(LSQUnit, "Removing MSHR. count = %i\n",mshrSeqNums.size());    }}*/template <class Impl>voidLSQUnit<Impl>::squash(const InstSeqNum &squashed_num){    DPRINTF(LSQUnit, "Squashing until [sn:%lli]!"            "(Loads:%i Stores:%i)\n", squashed_num, loads, stores);    int load_idx = loadTail;    decrLdIdx(load_idx);    while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) {        DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, "                "[sn:%lli]\n",                loadQueue[load_idx]->readPC(),                loadQueue[load_idx]->seqNum);        if (isStalled() && load_idx == stallingLoadIdx) {            stalled = false;            stallingStoreIsn = 0;            stallingLoadIdx = 0;        }        // Clear the smart pointer to make sure it is decremented.        loadQueue[load_idx]->setSquashed();        loadQueue[load_idx] = NULL;        --loads;        // Inefficient!        loadTail = load_idx;        decrLdIdx(load_idx);        ++lsqSquashedLoads;    }    if (isLoadBlocked) {        if (squashed_num < blockedLoadSeqNum) {            isLoadBlocked = false;            loadBlockedHandled = false;            blockedLoadSeqNum = 0;        }    }    if (memDepViolator && squashed_num < memDepViolator->seqNum) {        memDepViolator = NULL;    }    int store_idx = storeTail;    decrStIdx(store_idx);    while (stores != 0 &&           storeQueue[store_idx].inst->seqNum > squashed_num) {        // Instructions marked as can WB are already committed.        if (storeQueue[store_idx].canWB) {            break;        }        DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, "                "idx:%i [sn:%lli]\n",                storeQueue[store_idx].inst->readPC(),                store_idx, storeQueue[store_idx].inst->seqNum);        // I don't think this can happen.  It should have been cleared        // by the stalling load.        if (isStalled() &&            storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {            panic("Is stalled should have been cleared by stalling load!\n");            stalled = false;            stallingStoreIsn = 0;        }        // Clear the smart pointer to make sure it is decremented.        storeQueue[store_idx].inst->setSquashed();        storeQueue[store_idx].inst = NULL;        storeQueue[store_idx].canWB = 0;        // Must delete request now that it wasn't handed off to        // memory.  This is quite ugly.  @todo: Figure out the proper        // place to really handle request deletes.        delete storeQueue[store_idx].req;        storeQueue[store_idx].req = NULL;        --stores;        // Inefficient!        storeTail = store_idx;        decrStIdx(store_idx);        ++lsqSquashedStores;    }}template <class Impl>voidLSQUnit<Impl>::storePostSend(PacketPtr pkt){    if (isStalled() &&        storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) {        DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] "                "load idx:%i\n",                stallingStoreIsn, stallingLoadIdx);        stalled = false;        stallingStoreIsn = 0;        iewStage->replayMemInst(loadQueue[stallingLoadIdx]);    }    if (!storeQueue[storeWBIdx].inst->isStoreConditional()) {        // The store is basically completed at this time. This        // only works so long as the checker doesn't try to        // verify the value in memory for stores.        storeQueue[storeWBIdx].inst->setCompleted();#if USE_CHECKER        if (cpu->checker) {            cpu->checker->verify(storeQueue[storeWBIdx].inst);        }#endif    }    incrStIdx(storeWBIdx);}template <class Impl>voidLSQUnit<Impl>::writeback(DynInstPtr &inst, PacketPtr pkt){    iewStage->wakeCPU();    // Squashed instructions do not need to complete their access.    if (inst->isSquashed()) {        iewStage->decrWb(inst->seqNum);        assert(!inst->isStore());        ++lsqIgnoredResponses;        return;    }    if (!inst->isExecuted()) {        inst->setExecuted();        // Complete access to copy data to proper place.        inst->completeAcc(pkt);    }    // Need to insert instruction into queue to commit    iewStage->instToCommit(inst);    iewStage->activityThisCycle();}template <class Impl>voidLSQUnit<Impl>::completeStore(int store_idx){    assert(storeQueue[store_idx].inst);    storeQueue[store_idx].completed = true;    --storesToWB;    // A bit conservative because a store completion may not free up entries,    // but hopefully avoids two store completions in one cycle from making    // the CPU tick twice.    cpu->wakeCPU();    cpu->activityThisCycle();    if (store_idx == storeHead) {        do {            incrStIdx(storeHead);            --stores;        } while (storeQueue[storeHead].completed &&                 storeHead != storeTail);        iewStage->updateLSQNextCycle = true;    }    DPRINTF(LSQUnit, "Completing store [sn:%lli], idx:%i, store head "            "idx:%i\n",            storeQueue[store_idx].inst->seqNum, store_idx, storeHead);    if (isStalled() &&        storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {        DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] "                "load idx:%i\n",                stallingStoreIsn, stallingLoadIdx);        stalled = false;        stallingStoreIsn = 0;        iewStage->replayMemInst(loadQueue[stallingLoadIdx]);    }    storeQueue[store_idx].inst->setCompleted();    // Tell the checker we've completed this instruction.  Some stores    // may get reported twice to the checker, but the checker can    // handle that case.#if USE_CHECKER    if (cpu->checker) {        cpu->checker->verify(storeQueue[store_idx].inst);    }#endif}template <class Impl>voidLSQUnit<Impl>::recvRetry(){    if (isStoreBlocked) {        DPRINTF(LSQUnit, "Receiving retry: store blocked\n");        assert(retryPkt != NULL);        if (dcachePort->sendTiming(retryPkt)) {            storePostSend(retryPkt);            retryPkt = NULL;            isStoreBlocked = false;            lsq->setRetryTid(-1);        } else {            // Still blocked!            ++lsqCacheBlocked;            lsq->setRetryTid(lsqID);        }    } else if (isLoadBlocked) {        DPRINTF(LSQUnit, "Loads squash themselves and all younger insts, "                "no need to resend packet.\n");    } else {        DPRINTF(LSQUnit, "Retry received but LSQ is no longer blocked.\n");    }}template <class Impl>inline voidLSQUnit<Impl>::incrStIdx(int &store_idx){    if (++store_idx >= SQEntries)        store_idx = 0;}template <class Impl>inline voidLSQUnit<Impl>::decrStIdx(int &store_idx){    if (--store_idx < 0)        store_idx += SQEntries;}template <class Impl>inline voidLSQUnit<Impl>::incrLdIdx(int &load_idx){    if (++load_idx >= LQEntries)        load_idx = 0;}template <class Impl>inline voidLSQUnit<Impl>::decrLdIdx(int &load_idx){    if (--load_idx < 0)        load_idx += LQEntries;}template <class Impl>voidLSQUnit<Impl>::dumpInsts(){    cprintf("Load store queue: Dumping instructions.\n");    cprintf("Load queue size: %i\n", loads);    cprintf("Load queue: ");    int load_idx = loadHead;    while (load_idx != loadTail && loadQueue[load_idx]) {        cprintf("%#x ", loadQueue[load_idx]->readPC());        incrLdIdx(load_idx);    }    cprintf("Store queue size: %i\n", stores);    cprintf("Store queue: ");    int store_idx = storeHead;    while (store_idx != storeTail && storeQueue[store_idx].inst) {        cprintf("%#x ", storeQueue[store_idx].inst->readPC());        incrStIdx(store_idx);    }    cprintf("\n");}

⌨️ 快捷键说明

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