/* * Copyright (c) 2011-2012, 2014 ARM Limited * Copyright (c) 2013 Advanced Micro Devices, Inc. * All rights reserved * * The license below extends only to copyright in the software and shall * not be construed as granting a license to any other intellectual * property including but not limited to intellectual property relating * to a hardware implementation of the functionality of the software * licensed hereunder. You may use the software subject to the license * terms below provided that you ensure that this notice is replicated * unmodified and in its entirety in all distributions of the software, * modified or unmodified, in source code or in binary form. * * Copyright (c) 2005-2006 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Korey Sewell */ #ifndef __CPU_O3_LSQ_IMPL_HH__ #define __CPU_O3_LSQ_IMPL_HH__ #include #include #include #include "base/logging.hh" #include "cpu/o3/lsq.hh" #include "debug/Drain.hh" #include "debug/Fetch.hh" #include "debug/LSQ.hh" #include "debug/Writeback.hh" #include "params/DerivO3CPU.hh" using namespace std; template LSQ::LSQ(O3CPU *cpu_ptr, IEW *iew_ptr, DerivO3CPUParams *params) : cpu(cpu_ptr), iewStage(iew_ptr), lsqPolicy(readLSQPolicy(params->smtLSQPolicy)), LQEntries(params->LQEntries), SQEntries(params->SQEntries), maxLQEntries(maxLSQAllocation(lsqPolicy, LQEntries, params->numThreads, params->smtLSQThreshold)), maxSQEntries(maxLSQAllocation(lsqPolicy, SQEntries, params->numThreads, params->smtLSQThreshold)), numThreads(params->numThreads) { assert(numThreads > 0 && numThreads <= Impl::MaxThreads); //**********************************************/ //************ Handle SMT Parameters ***********/ //**********************************************/ //Figure out fetch policy if (lsqPolicy == Dynamic) { DPRINTF(LSQ, "LSQ sharing policy set to Dynamic\n"); } else if (lsqPolicy == Partitioned) { DPRINTF(Fetch, "LSQ sharing policy set to Partitioned: " "%i entries per LQ | %i entries per SQ\n", maxLQEntries,maxSQEntries); } else if (lsqPolicy == Threshold) { assert(params->smtLSQThreshold > LQEntries); assert(params->smtLSQThreshold > SQEntries); DPRINTF(LSQ, "LSQ sharing policy set to Threshold: " "%i entries per LQ | %i entries per SQ\n", maxLQEntries,maxSQEntries); } else { panic("Invalid LSQ sharing policy. Options are: Dynamic, " "Partitioned, Threshold"); } thread.reserve(numThreads); for (ThreadID tid = 0; tid < numThreads; tid++) { thread.emplace_back(maxLQEntries, maxSQEntries); thread[tid].init(cpu, iew_ptr, params, this, tid); thread[tid].setDcachePort(&cpu_ptr->getDataPort()); } } template std::string LSQ::name() const { return iewStage->name() + ".lsq"; } template void LSQ::regStats() { //Initialize LSQs for (ThreadID tid = 0; tid < numThreads; tid++) { thread[tid].regStats(); } } template void LSQ::setActiveThreads(list *at_ptr) { activeThreads = at_ptr; assert(activeThreads != 0); } template void LSQ::drainSanityCheck() const { assert(isDrained()); for (ThreadID tid = 0; tid < numThreads; tid++) thread[tid].drainSanityCheck(); } template bool LSQ::isDrained() const { bool drained(true); if (!lqEmpty()) { DPRINTF(Drain, "Not drained, LQ not empty.\n"); drained = false; } if (!sqEmpty()) { DPRINTF(Drain, "Not drained, SQ not empty.\n"); drained = false; } return drained; } template void LSQ::takeOverFrom() { for (ThreadID tid = 0; tid < numThreads; tid++) { thread[tid].takeOverFrom(); } } template int LSQ::entryAmount(ThreadID num_threads) { if (lsqPolicy == Partitioned) { return LQEntries / num_threads; } else { return 0; } } template void LSQ::resetEntries() { if (lsqPolicy != Dynamic || numThreads > 1) { int active_threads = activeThreads->size(); int maxEntries; if (lsqPolicy == Partitioned) { maxEntries = LQEntries / active_threads; } else if (lsqPolicy == Threshold && active_threads == 1) { maxEntries = LQEntries; } else { maxEntries = LQEntries; } list::iterator threads = activeThreads->begin(); list::iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; resizeEntries(maxEntries, tid); } } } template void LSQ::removeEntries(ThreadID tid) { thread[tid].clearLQ(); thread[tid].clearSQ(); } template void LSQ::resizeEntries(unsigned size, ThreadID tid) { thread[tid].resizeLQ(size); thread[tid].resizeSQ(size); } template void LSQ::tick() { list::iterator threads = activeThreads->begin(); list::iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; thread[tid].tick(); } } template void LSQ::insertLoad(const DynInstPtr &load_inst) { ThreadID tid = load_inst->threadNumber; thread[tid].insertLoad(load_inst); } template void LSQ::insertStore(const DynInstPtr &store_inst) { ThreadID tid = store_inst->threadNumber; thread[tid].insertStore(store_inst); } template Fault LSQ::executeLoad(const DynInstPtr &inst) { ThreadID tid = inst->threadNumber; return thread[tid].executeLoad(inst); } template Fault LSQ::executeStore(const DynInstPtr &inst) { ThreadID tid = inst->threadNumber; return thread[tid].executeStore(inst); } template void LSQ::writebackStores() { list::iterator threads = activeThreads->begin(); list::iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; if (numStoresToWB(tid) > 0) { DPRINTF(Writeback,"[tid:%i] Writing back stores. %i stores " "available for Writeback.\n", tid, numStoresToWB(tid)); } thread[tid].writebackStores(); } } // [mengjia] template void LSQ::updateVisibleState() { list::iterator threads = activeThreads->begin(); list::iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; thread[tid].updateVisibleState(); } } template bool LSQ::violation() { /* Answers: Does Anybody Have a Violation?*/ list::iterator threads = activeThreads->begin(); list::iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; if (thread[tid].violation()) return true; } return false; } template void LSQ::recvReqRetry() { iewStage->cacheUnblocked(); for (ThreadID tid : *activeThreads) { thread[tid].recvRetry(); } } // [InvisiSpec] Callback function for receiving a response template bool LSQ::recvTimingResp(PacketPtr pkt) { if (pkt->isError()) DPRINTF(LSQ, "Got error packet back for address: %#X\n", pkt->getAddr()); // for expose or validate request, // if the instruction is squashed, maybe the req has been deleted if (pkt->isValidate() || pkt->isExpose()){ if (!pkt->req){ delete pkt; return true; } DPRINTF(LSQ, "Receive an expose/validate response, idx=%d\n", pkt->reqIdx); } thread[cpu->contextToThread(pkt->req->contextId())] .completeDataAccess(pkt); if (pkt->isInvalidate()) { // This response also contains an invalidate; e.g. this can be the case // if cmd is ReadRespWithInvalidate. // // The calling order between completeDataAccess and checkSnoop matters. // By calling checkSnoop after completeDataAccess, we ensure that the // fault set by checkSnoop is not lost. Calling writeback (more // specifically inst->completeAcc) in completeDataAccess overwrites // fault, and in case this instruction requires squashing (as // determined by checkSnoop), the ReExec fault set by checkSnoop would // be lost otherwise. DPRINTF(LSQ, "received invalidation with response for addr:%#x\n", pkt->getAddr()); for (ThreadID tid = 0; tid < numThreads; tid++) { thread[tid].checkSnoop(pkt); } } delete pkt; return true; } template void LSQ::recvTimingSnoopReq(PacketPtr pkt) { DPRINTF(LSQ, "received pkt for addr:%#x %s\n", pkt->getAddr(), pkt->cmdString()); // must be a snoop if (pkt->isInvalidate()) { DPRINTF(LSQ, "received invalidation for addr:%#x\n", pkt->getAddr()); for (ThreadID tid = 0; tid < numThreads; tid++) { thread[tid].checkSnoop(pkt); } } } template int LSQ::getCount() { unsigned total = 0; list::iterator threads = activeThreads->begin(); list::iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; total += getCount(tid); } return total; } template int LSQ::numLoads() { unsigned total = 0; list::iterator threads = activeThreads->begin(); list::iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; total += numLoads(tid); } return total; } template int LSQ::numStores() { unsigned total = 0; list::iterator threads = activeThreads->begin(); list::iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; total += thread[tid].numStores(); } return total; } template unsigned LSQ::numFreeLoadEntries() { unsigned total = 0; list::iterator threads = activeThreads->begin(); list::iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; total += thread[tid].numFreeLoadEntries(); } return total; } template unsigned LSQ::numFreeStoreEntries() { unsigned total = 0; list::iterator threads = activeThreads->begin(); list::iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; total += thread[tid].numFreeStoreEntries(); } return total; } template unsigned LSQ::numFreeLoadEntries(ThreadID tid) { return thread[tid].numFreeLoadEntries(); } template unsigned LSQ::numFreeStoreEntries(ThreadID tid) { return thread[tid].numFreeStoreEntries(); } template bool LSQ::isFull() { list::iterator threads = activeThreads->begin(); list::iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; if (!(thread[tid].lqFull() || thread[tid].sqFull())) return false; } return true; } template bool LSQ::isFull(ThreadID tid) { //@todo: Change to Calculate All Entries for //Dynamic Policy if (lsqPolicy == Dynamic) return isFull(); else return thread[tid].lqFull() || thread[tid].sqFull(); } template bool LSQ::isEmpty() const { return lqEmpty() && sqEmpty(); } template bool LSQ::lqEmpty() const { list::const_iterator threads = activeThreads->begin(); list::const_iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; if (!thread[tid].lqEmpty()) return false; } return true; } template bool LSQ::sqEmpty() const { list::const_iterator threads = activeThreads->begin(); list::const_iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; if (!thread[tid].sqEmpty()) return false; } return true; } template bool LSQ::lqFull() { list::iterator threads = activeThreads->begin(); list::iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; if (!thread[tid].lqFull()) return false; } return true; } template bool LSQ::lqFull(ThreadID tid) { //@todo: Change to Calculate All Entries for //Dynamic Policy if (lsqPolicy == Dynamic) return lqFull(); else return thread[tid].lqFull(); } template bool LSQ::sqFull() { list::iterator threads = activeThreads->begin(); list::iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; if (!sqFull(tid)) return false; } return true; } template bool LSQ::sqFull(ThreadID tid) { //@todo: Change to Calculate All Entries for //Dynamic Policy if (lsqPolicy == Dynamic) return sqFull(); else return thread[tid].sqFull(); } template bool LSQ::isStalled() { list::iterator threads = activeThreads->begin(); list::iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; if (!thread[tid].isStalled()) return false; } return true; } template bool LSQ::isStalled(ThreadID tid) { if (lsqPolicy == Dynamic) return isStalled(); else return thread[tid].isStalled(); } template bool LSQ::hasStoresToWB() { list::iterator threads = activeThreads->begin(); list::iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; if (hasStoresToWB(tid)) return true; } return false; } template bool LSQ::willWB() { list::iterator threads = activeThreads->begin(); list::iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; if (willWB(tid)) return true; } return false; } template void LSQ::dumpInsts() const { list::const_iterator threads = activeThreads->begin(); list::const_iterator end = activeThreads->end(); while (threads != end) { ThreadID tid = *threads++; thread[tid].dumpInsts(); } } #endif//__CPU_O3_LSQ_IMPL_HH__