/* * Copyright (c) 2004-2005 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. */ #include "cpu/o3/lsq.hh" using namespace std; template LSQ::LSQ(Params *params) : LQEntries(params->LQEntries), SQEntries(params->SQEntries), numThreads(params->numberOfThreads) { DPRINTF(LSQ, "Creating LSQ object.\n"); //**********************************************/ //************ Handle SMT Parameters ***********/ //**********************************************/ string policy = params->smtLSQPolicy; //Convert string to lowercase std::transform(policy.begin(), policy.end(), policy.begin(), (int(*)(int)) tolower); //Figure out fetch policy if (policy == "dynamic") { lsqPolicy = Dynamic; maxLQEntries = LQEntries; maxSQEntries = SQEntries; DPRINTF(LSQ, "LSQ sharing policy set to Dynamic\n"); } else if (policy == "partitioned") { lsqPolicy = Partitioned; //@todo:make work if part_amt doesnt divide evenly. maxLQEntries = LQEntries / numThreads; maxSQEntries = SQEntries / numThreads; DPRINTF(Fetch, "LSQ sharing policy set to Partitioned: " "%i entries per LQ | %i entries per SQ", maxLQEntries,maxSQEntries); } else if (policy == "threshold") { lsqPolicy = Threshold; assert(params->smtLSQThreshold > LQEntries); assert(params->smtLSQThreshold > SQEntries); //Divide up by threshold amount //@todo: Should threads check the max and the total //amount of the LSQ maxLQEntries = params->smtLSQThreshold; maxSQEntries = params->smtLSQThreshold; DPRINTF(LSQ, "LSQ sharing policy set to Threshold: " "%i entries per LQ | %i entries per SQ", maxLQEntries,maxSQEntries); } else { assert(0 && "Invalid LSQ Sharing Policy.Options Are:{Dynamic," "Partitioned, Threshold}"); } //Initialize LSQs for (int tid=0; tid < numThreads; tid++) { thread[tid].init(params, maxLQEntries+1, maxSQEntries+1, tid); } } template std::string LSQ::name() const { return iewStage->name() + ".lsq"; } template void LSQ::setActiveThreads(list *at_ptr) { activeThreads = at_ptr; assert(activeThreads != 0); } template void LSQ::setCPU(FullCPU *cpu_ptr) { cpu = cpu_ptr; for (int tid=0; tid < numThreads; tid++) { thread[tid].setCPU(cpu_ptr); } } template void LSQ::setIEW(IEW *iew_ptr) { iewStage = iew_ptr; for (int tid=0; tid < numThreads; tid++) { thread[tid].setIEW(iew_ptr); } } #if 0 template void LSQ::setPageTable(PageTable *pt_ptr) { for (int tid=0; tid < numThreads; tid++) { thread[tid].setPageTable(pt_ptr); } } #endif template void LSQ::switchOut() { for (int tid = 0; tid < numThreads; tid++) { thread[tid].switchOut(); } } template void LSQ::takeOverFrom() { for (int tid = 0; tid < numThreads; tid++) { thread[tid].takeOverFrom(); } } template int LSQ::entryAmount(int 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(); list::iterator threads = (*activeThreads).begin(); list::iterator list_end = (*activeThreads).end(); int maxEntries; if (lsqPolicy == Partitioned) { maxEntries = LQEntries / active_threads; } else if (lsqPolicy == Threshold && active_threads == 1) { maxEntries = LQEntries; } else { maxEntries = LQEntries; } while (threads != list_end) { resizeEntries(maxEntries,*threads++); } } } template void LSQ::removeEntries(unsigned tid) { thread[tid].clearLQ(); thread[tid].clearSQ(); } template void LSQ::resizeEntries(unsigned size,unsigned tid) { thread[tid].resizeLQ(size); thread[tid].resizeSQ(size); } template void LSQ::tick() { list::iterator active_threads = (*activeThreads).begin(); while (active_threads != (*activeThreads).end()) { unsigned tid = *active_threads++; thread[tid].tick(); } } template void LSQ::tick(unsigned tid) { thread[tid].tick(); } template void LSQ::insertLoad(DynInstPtr &load_inst) { unsigned tid = load_inst->threadNumber; thread[tid].insertLoad(load_inst); } template void LSQ::insertStore(DynInstPtr &store_inst) { unsigned tid = store_inst->threadNumber; thread[tid].insertStore(store_inst); } template Fault LSQ::executeLoad(DynInstPtr &inst) { unsigned tid = inst->threadNumber; return thread[tid].executeLoad(inst); } template Fault LSQ::executeLoad(int lq_idx, unsigned tid) { return thread[tid].executeLoad(lq_idx); } template Fault LSQ::executeStore(DynInstPtr &inst) { unsigned tid = inst->threadNumber; return thread[tid].executeStore(inst); } template void LSQ::commitLoads(InstSeqNum &youngest_inst,unsigned tid) { thread[tid].commitLoads(youngest_inst); } template void LSQ::commitStores(InstSeqNum &youngest_inst,unsigned tid) { thread[tid].commitStores(youngest_inst); } template void LSQ::writebackStores() { list::iterator active_threads = (*activeThreads).begin(); while (active_threads != (*activeThreads).end()) { unsigned tid = *active_threads++; if (numStoresToWB(tid) > 0) { DPRINTF(Writeback,"[tid:%i] Writing back stores. %i stores available" " for Writeback.\n", tid, numStoresToWB(tid)); } thread[tid].writebackStores(); } } template int LSQ::numStoresToWB(unsigned tid) { return thread[tid].numStoresToWB(); } template void LSQ::squash(const InstSeqNum &squashed_num, unsigned tid) { thread[tid].squash(squashed_num); } template bool LSQ::violation() { /* Answers: Does Anybody Have a Violation?*/ list::iterator active_threads = (*activeThreads).begin(); while (active_threads != (*activeThreads).end()) { unsigned tid = *active_threads++; if (thread[tid].violation()) return true; } return false; } template bool LSQ::violation(unsigned tid) { return thread[tid].violation(); } template bool LSQ::loadBlocked(unsigned tid) { return thread[tid].loadBlocked(); } template typename Impl::DynInstPtr LSQ::getMemDepViolator(unsigned tid) { return thread[tid].getMemDepViolator(); } template int LSQ::getLoadHead(unsigned tid) { return thread[tid].getLoadHead(); } template int LSQ::getStoreHead(unsigned tid) { return thread[tid].getStoreHead(); } template int LSQ::getCount() { unsigned total = 0; list::iterator active_threads = (*activeThreads).begin(); while (active_threads != (*activeThreads).end()) { unsigned tid = *active_threads++; total += getCount(tid); } return total; } template int LSQ::getCount(unsigned tid) { return thread[tid].getCount(); } template int LSQ::numLoads() { unsigned total = 0; list::iterator active_threads = (*activeThreads).begin(); while (active_threads != (*activeThreads).end()) { unsigned tid = *active_threads++; total += numLoads(tid); } return total; } template int LSQ::numLoads(unsigned tid) { return thread[tid].numLoads(); } template int LSQ::numStores() { unsigned total = 0; list::iterator active_threads = (*activeThreads).begin(); while (active_threads != (*activeThreads).end()) { unsigned tid = *active_threads++; total += thread[tid].numStores(); } return total; } template int LSQ::numStores(unsigned tid) { return thread[tid].numStores(); } template int LSQ::numLoadsReady() { unsigned total = 0; list::iterator active_threads = (*activeThreads).begin(); while (active_threads != (*activeThreads).end()) { unsigned tid = *active_threads++; total += thread[tid].numLoadsReady(); } return total; } template int LSQ::numLoadsReady(unsigned tid) { return thread[tid].numLoadsReady(); } template unsigned LSQ::numFreeEntries() { unsigned total = 0; list::iterator active_threads = (*activeThreads).begin(); while (active_threads != (*activeThreads).end()) { unsigned tid = *active_threads++; total += thread[tid].numFreeEntries(); } return total; } template unsigned LSQ::numFreeEntries(unsigned tid) { //if( lsqPolicy == Dynamic ) //return numFreeEntries(); //else return thread[tid].numFreeEntries(); } template bool LSQ::isFull() { list::iterator active_threads = (*activeThreads).begin(); while (active_threads != (*activeThreads).end()) { unsigned tid = *active_threads++; if (! (thread[tid].lqFull() || thread[tid].sqFull()) ) return false; } return true; } template bool LSQ::isFull(unsigned 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::lqFull() { list::iterator active_threads = (*activeThreads).begin(); while (active_threads != (*activeThreads).end()) { unsigned tid = *active_threads++; if (!thread[tid].lqFull()) return false; } return true; } template bool LSQ::lqFull(unsigned 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 active_threads = (*activeThreads).begin(); while (active_threads != (*activeThreads).end()) { unsigned tid = *active_threads++; if (!sqFull(tid)) return false; } return true; } template bool LSQ::sqFull(unsigned 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 active_threads = (*activeThreads).begin(); while (active_threads != (*activeThreads).end()) { unsigned tid = *active_threads++; if (!thread[tid].isStalled()) return false; } return true; } template bool LSQ::isStalled(unsigned tid) { if( lsqPolicy == Dynamic ) return isStalled(); else return thread[tid].isStalled(); } template bool LSQ::hasStoresToWB() { list::iterator active_threads = (*activeThreads).begin(); while (active_threads != (*activeThreads).end()) { unsigned tid = *active_threads++; if (!hasStoresToWB(tid)) return false; } return true; } template bool LSQ::hasStoresToWB(unsigned tid) { return thread[tid].hasStoresToWB(); } template bool LSQ::willWB() { list::iterator active_threads = (*activeThreads).begin(); while (active_threads != (*activeThreads).end()) { unsigned tid = *active_threads++; if (!willWB(tid)) return false; } return true; } template bool LSQ::willWB(unsigned tid) { return thread[tid].willWB(); } template void LSQ::dumpInsts() { list::iterator active_threads = (*activeThreads).begin(); while (active_threads != (*activeThreads).end()) { unsigned tid = *active_threads++; thread[tid].dumpInsts(); } } template void LSQ::dumpInsts(unsigned tid) { thread[tid].dumpInsts(); }