lsq_unit_impl.hh

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

HH
1,015
字号
/* * Copyright (c) 2004, 2005 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. * * Authors: Kevin T. Lim *          Korey L. Sewell */#include "arch/locked_mem.hh"#include "config/use_checker.hh"#include "cpu/o3/lsq.hh"#include "cpu/o3/lsq_unit.hh"#include "base/str.hh"#include "mem/packet.hh"#include "mem/request.hh"#if USE_CHECKER#include "cpu/checker/cpu.hh"#endiftemplate<class Impl>LSQUnit<Impl>::WritebackEvent::WritebackEvent(DynInstPtr &_inst, PacketPtr _pkt,                                              LSQUnit *lsq_ptr)    : Event(&mainEventQueue), inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr){    this->setFlags(Event::AutoDelete);}template<class Impl>voidLSQUnit<Impl>::WritebackEvent::process(){    if (!lsqPtr->isSwitchedOut()) {        lsqPtr->writeback(inst, pkt);    }    if (pkt->senderState)        delete pkt->senderState;    delete pkt->req;    delete pkt;}template<class Impl>const char *LSQUnit<Impl>::WritebackEvent::description() const{    return "Store writeback";}template<class Impl>voidLSQUnit<Impl>::completeDataAccess(PacketPtr pkt){    LSQSenderState *state = dynamic_cast<LSQSenderState *>(pkt->senderState);    DynInstPtr inst = state->inst;    DPRINTF(IEW, "Writeback event [sn:%lli]\n", inst->seqNum);    DPRINTF(Activity, "Activity: Writeback event [sn:%lli]\n", inst->seqNum);    //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum);    assert(!pkt->wasNacked());    if (isSwitchedOut() || inst->isSquashed()) {        iewStage->decrWb(inst->seqNum);    } else {        if (!state->noWB) {            writeback(inst, pkt);        }        if (inst->isStore()) {            completeStore(state->idx);        }    }    delete state;    delete pkt->req;    delete pkt;}template <class Impl>LSQUnit<Impl>::LSQUnit()    : loads(0), stores(0), storesToWB(0), stalled(false),      isStoreBlocked(false), isLoadBlocked(false),      loadBlockedHandled(false){}template<class Impl>voidLSQUnit<Impl>::init(O3CPU *cpu_ptr, IEW *iew_ptr, Params *params, LSQ *lsq_ptr,                    unsigned maxLQEntries, unsigned maxSQEntries, unsigned id){    cpu = cpu_ptr;    iewStage = iew_ptr;    DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id);    switchedOut = false;    lsq = lsq_ptr;    lsqID = id;    // Add 1 for the sentinel entry (they are circular queues).    LQEntries = maxLQEntries + 1;    SQEntries = maxSQEntries + 1;    loadQueue.resize(LQEntries);    storeQueue.resize(SQEntries);    loadHead = loadTail = 0;    storeHead = storeWBIdx = storeTail = 0;    usedPorts = 0;    cachePorts = params->cachePorts;    retryPkt = NULL;    memDepViolator = NULL;    blockedLoadSeqNum = 0;}template<class Impl>std::stringLSQUnit<Impl>::name() const{    if (Impl::MaxThreads == 1) {        return iewStage->name() + ".lsq";    } else {        return iewStage->name() + ".lsq.thread." + to_string(lsqID);    }}template<class Impl>voidLSQUnit<Impl>::regStats(){    lsqForwLoads        .name(name() + ".forwLoads")        .desc("Number of loads that had data forwarded from stores");    invAddrLoads        .name(name() + ".invAddrLoads")        .desc("Number of loads ignored due to an invalid address");    lsqSquashedLoads        .name(name() + ".squashedLoads")        .desc("Number of loads squashed");    lsqIgnoredResponses        .name(name() + ".ignoredResponses")        .desc("Number of memory responses ignored because the instruction is squashed");    lsqMemOrderViolation        .name(name() + ".memOrderViolation")        .desc("Number of memory ordering violations");    lsqSquashedStores        .name(name() + ".squashedStores")        .desc("Number of stores squashed");    invAddrSwpfs        .name(name() + ".invAddrSwpfs")        .desc("Number of software prefetches ignored due to an invalid address");    lsqBlockedLoads        .name(name() + ".blockedLoads")        .desc("Number of blocked loads due to partial load-store forwarding");    lsqRescheduledLoads        .name(name() + ".rescheduledLoads")        .desc("Number of loads that were rescheduled");    lsqCacheBlocked        .name(name() + ".cacheBlocked")        .desc("Number of times an access to memory failed due to the cache being blocked");}template<class Impl>voidLSQUnit<Impl>::setDcachePort(Port *dcache_port){    dcachePort = dcache_port;#if USE_CHECKER    if (cpu->checker) {        cpu->checker->setDcachePort(dcachePort);    }#endif}template<class Impl>voidLSQUnit<Impl>::clearLQ(){    loadQueue.clear();}template<class Impl>voidLSQUnit<Impl>::clearSQ(){    storeQueue.clear();}template<class Impl>voidLSQUnit<Impl>::switchOut(){    switchedOut = true;    for (int i = 0; i < loadQueue.size(); ++i) {        assert(!loadQueue[i]);        loadQueue[i] = NULL;    }    assert(storesToWB == 0);}template<class Impl>voidLSQUnit<Impl>::takeOverFrom(){    switchedOut = false;    loads = stores = storesToWB = 0;    loadHead = loadTail = 0;    storeHead = storeWBIdx = storeTail = 0;    usedPorts = 0;    memDepViolator = NULL;    blockedLoadSeqNum = 0;    stalled = false;    isLoadBlocked = false;    loadBlockedHandled = false;}template<class Impl>voidLSQUnit<Impl>::resizeLQ(unsigned size){    unsigned size_plus_sentinel = size + 1;    assert(size_plus_sentinel >= LQEntries);    if (size_plus_sentinel > LQEntries) {        while (size_plus_sentinel > loadQueue.size()) {            DynInstPtr dummy;            loadQueue.push_back(dummy);            LQEntries++;        }    } else {        LQEntries = size_plus_sentinel;    }}template<class Impl>voidLSQUnit<Impl>::resizeSQ(unsigned size){    unsigned size_plus_sentinel = size + 1;    if (size_plus_sentinel > SQEntries) {        while (size_plus_sentinel > storeQueue.size()) {            SQEntry dummy;            storeQueue.push_back(dummy);            SQEntries++;        }    } else {        SQEntries = size_plus_sentinel;    }}template <class Impl>voidLSQUnit<Impl>::insert(DynInstPtr &inst){    assert(inst->isMemRef());    assert(inst->isLoad() || inst->isStore());    if (inst->isLoad()) {        insertLoad(inst);    } else {        insertStore(inst);    }    inst->setInLSQ();}template <class Impl>voidLSQUnit<Impl>::insertLoad(DynInstPtr &load_inst){    assert((loadTail + 1) % LQEntries != loadHead);    assert(loads < LQEntries);    DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n",            load_inst->readPC(), loadTail, load_inst->seqNum);    load_inst->lqIdx = loadTail;    if (stores == 0) {        load_inst->sqIdx = -1;    } else {        load_inst->sqIdx = storeTail;    }    loadQueue[loadTail] = load_inst;    incrLdIdx(loadTail);    ++loads;}template <class Impl>voidLSQUnit<Impl>::insertStore(DynInstPtr &store_inst){    // Make sure it is not full before inserting an instruction.    assert((storeTail + 1) % SQEntries != storeHead);    assert(stores < SQEntries);    DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n",            store_inst->readPC(), storeTail, store_inst->seqNum);    store_inst->sqIdx = storeTail;    store_inst->lqIdx = loadTail;    storeQueue[storeTail] = SQEntry(store_inst);    incrStIdx(storeTail);    ++stores;}template <class Impl>typename Impl::DynInstPtrLSQUnit<Impl>::getMemDepViolator(){    DynInstPtr temp = memDepViolator;    memDepViolator = NULL;    return temp;}template <class Impl>unsignedLSQUnit<Impl>::numFreeEntries(){    unsigned free_lq_entries = LQEntries - loads;    unsigned free_sq_entries = SQEntries - stores;    // Both the LQ and SQ entries have an extra dummy entry to differentiate    // empty/full conditions.  Subtract 1 from the free entries.    if (free_lq_entries < free_sq_entries) {        return free_lq_entries - 1;    } else {        return free_sq_entries - 1;    }}template <class Impl>intLSQUnit<Impl>::numLoadsReady(){    int load_idx = loadHead;    int retval = 0;    while (load_idx != loadTail) {        assert(loadQueue[load_idx]);        if (loadQueue[load_idx]->readyToIssue()) {            ++retval;        }    }    return retval;}template <class Impl>FaultLSQUnit<Impl>::executeLoad(DynInstPtr &inst){    using namespace TheISA;    // Execute a specific load.    Fault load_fault = NoFault;    DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n",            inst->readPC(),inst->seqNum);    assert(!inst->isSquashed());    load_fault = inst->initiateAcc();    // If the instruction faulted, then we need to send it along to commit    // without the instruction completing.    if (load_fault != NoFault) {        // Send this instruction to commit, also make sure iew stage        // realizes there is activity.        // Mark it as executed unless it is an uncached load that        // needs to hit the head of commit.        if (!(inst->hasRequest() && inst->uncacheable()) ||            inst->isAtCommit()) {            inst->setExecuted();        }        iewStage->instToCommit(inst);        iewStage->activityThisCycle();    } else if (!loadBlocked()) {        assert(inst->effAddrValid);        int load_idx = inst->lqIdx;        incrLdIdx(load_idx);        while (load_idx != loadTail) {            // Really only need to check loads that have actually executed            // @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) ==                (inst->effAddr >> 8)) {                // A load incorrectly passed this load.  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 load_fault;}template <class Impl>FaultLSQUnit<Impl>::executeStore(DynInstPtr &store_inst){    using namespace TheISA;    // Make sure that a store exists.    assert(stores != 0);    int store_idx = store_inst->sqIdx;    DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n",            store_inst->readPC(), store_inst->seqNum);    assert(!store_inst->isSquashed());    // Check the recently completed loads to see if any match this store's    // address.  If so, then we have a memory ordering violation.    int load_idx = store_inst->lqIdx;    Fault store_fault = store_inst->initiateAcc();    if (storeQueue[store_idx].size == 0) {        DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n",                store_inst->readPC(),store_inst->seqNum);        return store_fault;    }    assert(store_fault == NoFault);    if (store_inst->isStoreConditional()) {        // Store conditionals need to set themselves as able to        // writeback if we haven't had a fault by here.        storeQueue[store_idx].canWB = true;

⌨️ 快捷键说明

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