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 + -
显示快捷键?