lsq_unit_impl.hh revision 2316
15086Sgblack@eecs.umich.edu/* 25086Sgblack@eecs.umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan 38466Snilay@cs.wisc.edu * All rights reserved. 45086Sgblack@eecs.umich.edu * 55086Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 67087Snate@binkert.org * modification, are permitted provided that the following conditions are 77087Snate@binkert.org * met: redistributions of source code must retain the above copyright 87087Snate@binkert.org * notice, this list of conditions and the following disclaimer; 97087Snate@binkert.org * redistributions in binary form must reproduce the above copyright 107087Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 117087Snate@binkert.org * documentation and/or other materials provided with the distribution; 127087Snate@binkert.org * neither the name of the copyright holders nor the names of its 137087Snate@binkert.org * contributors may be used to endorse or promote products derived from 145086Sgblack@eecs.umich.edu * this software without specific prior written permission. 157087Snate@binkert.org * 167087Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 177087Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 187087Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 197087Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 207087Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 217087Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 227087Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 235086Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 247087Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255086Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 265086Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275086Sgblack@eecs.umich.edu */ 285086Sgblack@eecs.umich.edu 295086Sgblack@eecs.umich.edu#include "cpu/checker/cpu.hh" 305086Sgblack@eecs.umich.edu#include "cpu/o3/lsq_unit.hh" 315086Sgblack@eecs.umich.edu#include "base/str.hh" 325086Sgblack@eecs.umich.edu 335086Sgblack@eecs.umich.edutemplate <class Impl> 345086Sgblack@eecs.umich.eduLSQUnit<Impl>::StoreCompletionEvent::StoreCompletionEvent(int store_idx, 355086Sgblack@eecs.umich.edu Event *wb_event, 365086Sgblack@eecs.umich.edu LSQUnit<Impl> *lsq_ptr) 375086Sgblack@eecs.umich.edu : Event(&mainEventQueue), 385086Sgblack@eecs.umich.edu storeIdx(store_idx), 395086Sgblack@eecs.umich.edu wbEvent(wb_event), 405086Sgblack@eecs.umich.edu lsqPtr(lsq_ptr) 4111793Sbrandon.potter@amd.com{ 4211793Sbrandon.potter@amd.com this->setFlags(Event::AutoDelete); 435647Sgblack@eecs.umich.edu} 448466Snilay@cs.wisc.edu 455135Sgblack@eecs.umich.edutemplate <class Impl> 465647Sgblack@eecs.umich.eduvoid 479889Sandreas@sandberg.pp.seLSQUnit<Impl>::StoreCompletionEvent::process() 4811800Sbrandon.potter@amd.com{ 495086Sgblack@eecs.umich.edu DPRINTF(LSQ, "Cache miss complete for store idx:%i\n", storeIdx); 505086Sgblack@eecs.umich.edu DPRINTF(Activity, "Activity: st writeback event idx:%i\n", storeIdx); 515086Sgblack@eecs.umich.edu 527707Sgblack@eecs.umich.edu //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum); 537707Sgblack@eecs.umich.edu 547707Sgblack@eecs.umich.edu if (lsqPtr->isSwitchedOut()) 5510553Salexandru.dutu@amd.com return; 569887Sandreas@sandberg.pp.se 579887Sandreas@sandberg.pp.se lsqPtr->cpu->wakeCPU(); 589887Sandreas@sandberg.pp.se if (wbEvent) 599887Sandreas@sandberg.pp.se wbEvent->process(); 609887Sandreas@sandberg.pp.se lsqPtr->completeStore(storeIdx); 619887Sandreas@sandberg.pp.se} 629887Sandreas@sandberg.pp.se 639887Sandreas@sandberg.pp.setemplate <class Impl> 649887Sandreas@sandberg.pp.seconst char * 659887Sandreas@sandberg.pp.seLSQUnit<Impl>::StoreCompletionEvent::description() 669887Sandreas@sandberg.pp.se{ 679887Sandreas@sandberg.pp.se return "LSQ store completion event"; 689887Sandreas@sandberg.pp.se} 699887Sandreas@sandberg.pp.se 709887Sandreas@sandberg.pp.setemplate <class Impl> 719887Sandreas@sandberg.pp.seLSQUnit<Impl>::LSQUnit() 725086Sgblack@eecs.umich.edu : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false), 735135Sgblack@eecs.umich.edu loadBlockedHandled(false) 745135Sgblack@eecs.umich.edu{ 755135Sgblack@eecs.umich.edu} 766048Sgblack@eecs.umich.edu 776048Sgblack@eecs.umich.edutemplate<class Impl> 786048Sgblack@eecs.umich.eduvoid 796048Sgblack@eecs.umich.eduLSQUnit<Impl>::init(Params *params, unsigned maxLQEntries, 806048Sgblack@eecs.umich.edu unsigned maxSQEntries, unsigned id) 816048Sgblack@eecs.umich.edu 827720Sgblack@eecs.umich.edu{ 837720Sgblack@eecs.umich.edu DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id); 847720Sgblack@eecs.umich.edu 857720Sgblack@eecs.umich.edu switchedOut = false; 865135Sgblack@eecs.umich.edu 875135Sgblack@eecs.umich.edu lsqID = id; 885135Sgblack@eecs.umich.edu 895135Sgblack@eecs.umich.edu LQEntries = maxLQEntries; 905135Sgblack@eecs.umich.edu SQEntries = maxSQEntries; 915135Sgblack@eecs.umich.edu 925135Sgblack@eecs.umich.edu loadQueue.resize(LQEntries); 935135Sgblack@eecs.umich.edu storeQueue.resize(SQEntries); 945135Sgblack@eecs.umich.edu 955135Sgblack@eecs.umich.edu 965135Sgblack@eecs.umich.edu // May want to initialize these entries to NULL 975135Sgblack@eecs.umich.edu 985135Sgblack@eecs.umich.edu loadHead = loadTail = 0; 995135Sgblack@eecs.umich.edu 1005135Sgblack@eecs.umich.edu storeHead = storeWBIdx = storeTail = 0; 1015135Sgblack@eecs.umich.edu 1025135Sgblack@eecs.umich.edu usedPorts = 0; 1035264Sgblack@eecs.umich.edu cachePorts = params->cachePorts; 1045135Sgblack@eecs.umich.edu 1055135Sgblack@eecs.umich.edu dcacheInterface = params->dcacheInterface; 1065135Sgblack@eecs.umich.edu 1075135Sgblack@eecs.umich.edu loadFaultInst = storeFaultInst = memDepViolator = NULL; 1085141Sgblack@eecs.umich.edu 1095141Sgblack@eecs.umich.edu blockedLoadSeqNum = 0; 1105141Sgblack@eecs.umich.edu} 1115141Sgblack@eecs.umich.edu 1125141Sgblack@eecs.umich.edutemplate<class Impl> 1135141Sgblack@eecs.umich.edustd::string 1145141Sgblack@eecs.umich.eduLSQUnit<Impl>::name() const 1155141Sgblack@eecs.umich.edu{ 1165141Sgblack@eecs.umich.edu if (Impl::MaxThreads == 1) { 1175182Sgblack@eecs.umich.edu return iewStage->name() + ".lsq"; 1185141Sgblack@eecs.umich.edu } else { 1195141Sgblack@eecs.umich.edu return iewStage->name() + ".lsq.thread." + to_string(lsqID); 1205141Sgblack@eecs.umich.edu } 1215141Sgblack@eecs.umich.edu} 1225141Sgblack@eecs.umich.edu 1235141Sgblack@eecs.umich.edutemplate<class Impl> 1245135Sgblack@eecs.umich.eduvoid 1255141Sgblack@eecs.umich.eduLSQUnit<Impl>::clearLQ() 1265141Sgblack@eecs.umich.edu{ 1275141Sgblack@eecs.umich.edu loadQueue.clear(); 1285141Sgblack@eecs.umich.edu} 1295141Sgblack@eecs.umich.edu 1305141Sgblack@eecs.umich.edutemplate<class Impl> 1315141Sgblack@eecs.umich.eduvoid 1325141Sgblack@eecs.umich.eduLSQUnit<Impl>::clearSQ() 1335141Sgblack@eecs.umich.edu{ 1345141Sgblack@eecs.umich.edu storeQueue.clear(); 1355141Sgblack@eecs.umich.edu} 1365141Sgblack@eecs.umich.edu 1375135Sgblack@eecs.umich.edu#if 0 1385141Sgblack@eecs.umich.edutemplate<class Impl> 1395141Sgblack@eecs.umich.eduvoid 1405135Sgblack@eecs.umich.eduLSQUnit<Impl>::setPageTable(PageTable *pt_ptr) 1415141Sgblack@eecs.umich.edu{ 1425141Sgblack@eecs.umich.edu DPRINTF(LSQUnit, "Setting the page table pointer.\n"); 1435141Sgblack@eecs.umich.edu pTable = pt_ptr; 1445141Sgblack@eecs.umich.edu} 1455135Sgblack@eecs.umich.edu#endif 1465141Sgblack@eecs.umich.edu 1475141Sgblack@eecs.umich.edutemplate<class Impl> 1485141Sgblack@eecs.umich.eduvoid 1495141Sgblack@eecs.umich.eduLSQUnit<Impl>::switchOut() 1505141Sgblack@eecs.umich.edu{ 1515141Sgblack@eecs.umich.edu switchedOut = true; 1525141Sgblack@eecs.umich.edu for (int i = 0; i < loadQueue.size(); ++i) 1535141Sgblack@eecs.umich.edu loadQueue[i] = NULL; 1545141Sgblack@eecs.umich.edu 1555141Sgblack@eecs.umich.edu while (storesToWB > 0 && 1565141Sgblack@eecs.umich.edu storeWBIdx != storeTail && 1575141Sgblack@eecs.umich.edu storeQueue[storeWBIdx].inst && 1585264Sgblack@eecs.umich.edu storeQueue[storeWBIdx].canWB) { 1595141Sgblack@eecs.umich.edu 1605141Sgblack@eecs.umich.edu if (storeQueue[storeWBIdx].size == 0 || 1615141Sgblack@eecs.umich.edu storeQueue[storeWBIdx].inst->isDataPrefetch() || 1625141Sgblack@eecs.umich.edu storeQueue[storeWBIdx].committed || 1635141Sgblack@eecs.umich.edu storeQueue[storeWBIdx].req->flags & LOCKED) { 1645141Sgblack@eecs.umich.edu incrStIdx(storeWBIdx); 1655141Sgblack@eecs.umich.edu 1665141Sgblack@eecs.umich.edu continue; 1675141Sgblack@eecs.umich.edu } 1685141Sgblack@eecs.umich.edu 1695141Sgblack@eecs.umich.edu assert(storeQueue[storeWBIdx].req); 1705141Sgblack@eecs.umich.edu assert(!storeQueue[storeWBIdx].committed); 1715141Sgblack@eecs.umich.edu 1725141Sgblack@eecs.umich.edu MemReqPtr req = storeQueue[storeWBIdx].req; 1735141Sgblack@eecs.umich.edu storeQueue[storeWBIdx].committed = true; 1745141Sgblack@eecs.umich.edu 1755141Sgblack@eecs.umich.edu req->cmd = Write; 1765135Sgblack@eecs.umich.edu req->completionEvent = NULL; 1775135Sgblack@eecs.umich.edu req->time = curTick; 1785135Sgblack@eecs.umich.edu assert(!req->data); 1795360Sgblack@eecs.umich.edu req->data = new uint8_t[64]; 1805360Sgblack@eecs.umich.edu memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size); 1815360Sgblack@eecs.umich.edu 1825360Sgblack@eecs.umich.edu DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x " 1835360Sgblack@eecs.umich.edu "to Addr:%#x, data:%#x [sn:%lli]\n", 1845360Sgblack@eecs.umich.edu storeWBIdx,storeQueue[storeWBIdx].inst->readPC(), 1855647Sgblack@eecs.umich.edu req->paddr, *(req->data), 18611150Smitch.hayenga@arm.com storeQueue[storeWBIdx].inst->seqNum); 1875647Sgblack@eecs.umich.edu 1885360Sgblack@eecs.umich.edu switch(storeQueue[storeWBIdx].size) { 1895647Sgblack@eecs.umich.edu case 1: 1905647Sgblack@eecs.umich.edu cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data); 1915647Sgblack@eecs.umich.edu break; 1929157Sandreas.hansson@arm.com case 2: 1935141Sgblack@eecs.umich.edu cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data); 1945141Sgblack@eecs.umich.edu break; 1955141Sgblack@eecs.umich.edu case 4: 1965141Sgblack@eecs.umich.edu cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data); 1975141Sgblack@eecs.umich.edu break; 1985141Sgblack@eecs.umich.edu case 8: 1995135Sgblack@eecs.umich.edu cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data); 2005135Sgblack@eecs.umich.edu break; 2015135Sgblack@eecs.umich.edu default: 2025135Sgblack@eecs.umich.edu panic("Unexpected store size!\n"); 2038768Sgblack@eecs.umich.edu } 20410407Smitch.hayenga@arm.com incrStIdx(storeWBIdx); 2055135Sgblack@eecs.umich.edu } 2065135Sgblack@eecs.umich.edu} 2075135Sgblack@eecs.umich.edu 2085135Sgblack@eecs.umich.edutemplate<class Impl> 20910407Smitch.hayenga@arm.comvoid 2105135Sgblack@eecs.umich.eduLSQUnit<Impl>::takeOverFrom() 2115135Sgblack@eecs.umich.edu{ 2125135Sgblack@eecs.umich.edu switchedOut = false; 2136329Sgblack@eecs.umich.edu loads = stores = storesToWB = 0; 2146329Sgblack@eecs.umich.edu 2156329Sgblack@eecs.umich.edu loadHead = loadTail = 0; 2168466Snilay@cs.wisc.edu 2178466Snilay@cs.wisc.edu storeHead = storeWBIdx = storeTail = 0; 2188466Snilay@cs.wisc.edu 2196329Sgblack@eecs.umich.edu usedPorts = 0; 22011324Ssteve.reinhardt@amd.com 2216329Sgblack@eecs.umich.edu loadFaultInst = storeFaultInst = memDepViolator = NULL; 22211324Ssteve.reinhardt@amd.com 2236329Sgblack@eecs.umich.edu blockedLoadSeqNum = 0; 2246329Sgblack@eecs.umich.edu 2258466Snilay@cs.wisc.edu stalled = false; 2269751Sandreas@sandberg.pp.se isLoadBlocked = false; 2279751Sandreas@sandberg.pp.se loadBlockedHandled = false; 2289751Sandreas@sandberg.pp.se} 2299751Sandreas@sandberg.pp.se 2309423SAndreas.Sandberg@arm.comtemplate<class Impl> 2319423SAndreas.Sandberg@arm.comvoid 2326329Sgblack@eecs.umich.eduLSQUnit<Impl>::resizeLQ(unsigned size) 2336329Sgblack@eecs.umich.edu{ 2346329Sgblack@eecs.umich.edu assert( size >= LQEntries); 2356329Sgblack@eecs.umich.edu 2366329Sgblack@eecs.umich.edu if (size > LQEntries) { 2376329Sgblack@eecs.umich.edu while (size > loadQueue.size()) { 2388466Snilay@cs.wisc.edu DynInstPtr dummy; 23910058Sandreas@sandberg.pp.se loadQueue.push_back(dummy); 2406329Sgblack@eecs.umich.edu LQEntries++; 2418466Snilay@cs.wisc.edu } 24210058Sandreas@sandberg.pp.se } else { 2439921Syasuko.eckert@amd.com LQEntries = size; 2449921Syasuko.eckert@amd.com } 24510058Sandreas@sandberg.pp.se 2466329Sgblack@eecs.umich.edu} 2477720Sgblack@eecs.umich.edu 2486329Sgblack@eecs.umich.edutemplate<class Impl> 2496329Sgblack@eecs.umich.eduvoid 2507693SAli.Saidi@ARM.comLSQUnit<Impl>::resizeSQ(unsigned size) 2517693SAli.Saidi@ARM.com{ 2527693SAli.Saidi@ARM.com if (size > SQEntries) { 2537693SAli.Saidi@ARM.com while (size > storeQueue.size()) { 2547693SAli.Saidi@ARM.com SQEntry dummy; 2557693SAli.Saidi@ARM.com storeQueue.push_back(dummy); 2569759Sandreas@sandberg.pp.se SQEntries++; 2579759Sandreas@sandberg.pp.se } 2589759Sandreas@sandberg.pp.se } else { 2599759Sandreas@sandberg.pp.se SQEntries = size; 26010057Snikos.nikoleris@gmail.com } 26110057Snikos.nikoleris@gmail.com} 26210057Snikos.nikoleris@gmail.com 2639759Sandreas@sandberg.pp.setemplate <class Impl> 2649759Sandreas@sandberg.pp.sevoid 2659759Sandreas@sandberg.pp.seLSQUnit<Impl>::insert(DynInstPtr &inst) 2669759Sandreas@sandberg.pp.se{ 2679759Sandreas@sandberg.pp.se // Make sure we really have a memory reference. 2689759Sandreas@sandberg.pp.se assert(inst->isMemRef()); 2699759Sandreas@sandberg.pp.se 2709759Sandreas@sandberg.pp.se // Make sure it's one of the two classes of memory references. 2719759Sandreas@sandberg.pp.se assert(inst->isLoad() || inst->isStore()); 2729759Sandreas@sandberg.pp.se 2739759Sandreas@sandberg.pp.se if (inst->isLoad()) { 2749759Sandreas@sandberg.pp.se insertLoad(inst); 27510057Snikos.nikoleris@gmail.com } else { 27610057Snikos.nikoleris@gmail.com insertStore(inst); 27710057Snikos.nikoleris@gmail.com } 2789759Sandreas@sandberg.pp.se 2799759Sandreas@sandberg.pp.se inst->setInLSQ(); 28010057Snikos.nikoleris@gmail.com} 28110057Snikos.nikoleris@gmail.com 2829759Sandreas@sandberg.pp.setemplate <class Impl> 2839759Sandreas@sandberg.pp.sevoid 2849759Sandreas@sandberg.pp.seLSQUnit<Impl>::insertLoad(DynInstPtr &load_inst) 2859759Sandreas@sandberg.pp.se{ 2869759Sandreas@sandberg.pp.se assert((loadTail + 1) % LQEntries != loadHead && loads < LQEntries); 2877693SAli.Saidi@ARM.com 2889880Sandreas@sandberg.pp.se DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n", 2899880Sandreas@sandberg.pp.se load_inst->readPC(), loadTail, load_inst->seqNum); 2909880Sandreas@sandberg.pp.se 2919880Sandreas@sandberg.pp.se load_inst->lqIdx = loadTail; 2929880Sandreas@sandberg.pp.se 2939880Sandreas@sandberg.pp.se if (stores == 0) { 2949880Sandreas@sandberg.pp.se load_inst->sqIdx = -1; 2959880Sandreas@sandberg.pp.se } else { 2969880Sandreas@sandberg.pp.se load_inst->sqIdx = storeTail; 2979880Sandreas@sandberg.pp.se } 2989880Sandreas@sandberg.pp.se 2999880Sandreas@sandberg.pp.se loadQueue[loadTail] = load_inst; 3009880Sandreas@sandberg.pp.se 3019880Sandreas@sandberg.pp.se incrLdIdx(loadTail); 3029880Sandreas@sandberg.pp.se 3039880Sandreas@sandberg.pp.se ++loads; 3049880Sandreas@sandberg.pp.se} 3059880Sandreas@sandberg.pp.se 3069880Sandreas@sandberg.pp.setemplate <class Impl> 3079880Sandreas@sandberg.pp.sevoid 3089880Sandreas@sandberg.pp.seLSQUnit<Impl>::insertStore(DynInstPtr &store_inst) 3099880Sandreas@sandberg.pp.se{ 3109880Sandreas@sandberg.pp.se // Make sure it is not full before inserting an instruction. 3119880Sandreas@sandberg.pp.se assert((storeTail + 1) % SQEntries != storeHead); 3129880Sandreas@sandberg.pp.se assert(stores < SQEntries); 3139880Sandreas@sandberg.pp.se 3149880Sandreas@sandberg.pp.se DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n", 3159880Sandreas@sandberg.pp.se store_inst->readPC(), storeTail, store_inst->seqNum); 3169880Sandreas@sandberg.pp.se 3179880Sandreas@sandberg.pp.se store_inst->sqIdx = storeTail; 3189880Sandreas@sandberg.pp.se store_inst->lqIdx = loadTail; 3199880Sandreas@sandberg.pp.se 3209880Sandreas@sandberg.pp.se storeQueue[storeTail] = SQEntry(store_inst); 3219880Sandreas@sandberg.pp.se 3229880Sandreas@sandberg.pp.se incrStIdx(storeTail); 3239880Sandreas@sandberg.pp.se 3249880Sandreas@sandberg.pp.se ++stores; 3259880Sandreas@sandberg.pp.se 3269880Sandreas@sandberg.pp.se} 3279880Sandreas@sandberg.pp.se 3289880Sandreas@sandberg.pp.setemplate <class Impl> 3299880Sandreas@sandberg.pp.setypename Impl::DynInstPtr 3309880Sandreas@sandberg.pp.seLSQUnit<Impl>::getMemDepViolator() 3319880Sandreas@sandberg.pp.se{ 3329880Sandreas@sandberg.pp.se DynInstPtr temp = memDepViolator; 3339880Sandreas@sandberg.pp.se 3349765Sandreas@sandberg.pp.se memDepViolator = NULL; 3359765Sandreas@sandberg.pp.se 3369765Sandreas@sandberg.pp.se return temp; 3379765Sandreas@sandberg.pp.se} 3389765Sandreas@sandberg.pp.se 3399765Sandreas@sandberg.pp.setemplate <class Impl> 3409765Sandreas@sandberg.pp.seunsigned 3419765Sandreas@sandberg.pp.seLSQUnit<Impl>::numFreeEntries() 3429765Sandreas@sandberg.pp.se{ 3439765Sandreas@sandberg.pp.se unsigned free_lq_entries = LQEntries - loads; 3449765Sandreas@sandberg.pp.se unsigned free_sq_entries = SQEntries - stores; 3459765Sandreas@sandberg.pp.se 3469765Sandreas@sandberg.pp.se // Both the LQ and SQ entries have an extra dummy entry to differentiate 3479765Sandreas@sandberg.pp.se // empty/full conditions. Subtract 1 from the free entries. 3489765Sandreas@sandberg.pp.se if (free_lq_entries < free_sq_entries) { 3499765Sandreas@sandberg.pp.se return free_lq_entries - 1; 3509765Sandreas@sandberg.pp.se } else { 3519765Sandreas@sandberg.pp.se return free_sq_entries - 1; 3529765Sandreas@sandberg.pp.se } 3539765Sandreas@sandberg.pp.se} 3549889Sandreas@sandberg.pp.se 3559889Sandreas@sandberg.pp.setemplate <class Impl> 3569889Sandreas@sandberg.pp.seint 35711709Santhony.gutierrez@amd.comLSQUnit<Impl>::numLoadsReady() 35811709Santhony.gutierrez@amd.com{ 3599889Sandreas@sandberg.pp.se int load_idx = loadHead; 36011709Santhony.gutierrez@amd.com int retval = 0; 3619889Sandreas@sandberg.pp.se 3629889Sandreas@sandberg.pp.se while (load_idx != loadTail) { 3639889Sandreas@sandberg.pp.se assert(loadQueue[load_idx]); 3649889Sandreas@sandberg.pp.se 3659889Sandreas@sandberg.pp.se if (loadQueue[load_idx]->readyToIssue()) { 36611709Santhony.gutierrez@amd.com ++retval; 36711709Santhony.gutierrez@amd.com } 3689889Sandreas@sandberg.pp.se } 3699889Sandreas@sandberg.pp.se 3707811Ssteve.reinhardt@amd.com return retval; 371} 372 373#if 0 374template <class Impl> 375Fault 376LSQUnit<Impl>::executeLoad() 377{ 378 Fault load_fault = NoFault; 379 DynInstPtr load_inst; 380 381 assert(readyLoads.size() != 0); 382 383 // Execute a ready load. 384 LdMapIt ready_it = readyLoads.begin(); 385 386 load_inst = (*ready_it).second; 387 388 // Execute the instruction, which is held in the data portion of the 389 // iterator. 390 load_fault = load_inst->execute(); 391 392 // If it executed successfully, then switch it over to the executed 393 // loads list. 394 if (load_fault == NoFault) { 395 executedLoads[load_inst->seqNum] = load_inst; 396 397 readyLoads.erase(ready_it); 398 } else { 399 loadFaultInst = load_inst; 400 } 401 402 return load_fault; 403} 404#endif 405 406template <class Impl> 407Fault 408LSQUnit<Impl>::executeLoad(DynInstPtr &inst) 409{ 410 // Execute a specific load. 411 Fault load_fault = NoFault; 412 413 DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n", 414 inst->readPC(),inst->seqNum); 415 416 // Make sure it's really in the list. 417 // Normally it should always be in the list. However, 418 /* due to a syscall it may not be the list. 419#ifdef DEBUG 420 int i = loadHead; 421 while (1) { 422 if (i == loadTail && !find(inst)) { 423 assert(0 && "Load not in the queue!"); 424 } else if (loadQueue[i] == inst) { 425 break; 426 } 427 428 i = i + 1; 429 if (i >= LQEntries) { 430 i = 0; 431 } 432 } 433#endif // DEBUG*/ 434 435// load_fault = inst->initiateAcc(); 436 load_fault = inst->execute(); 437 438 // If the instruction faulted, then we need to send it along to commit 439 // without the instruction completing. 440 if (load_fault != NoFault) { 441 // Maybe just set it as can commit here, although that might cause 442 // some other problems with sending traps to the ROB too quickly. 443 iewStage->instToCommit(inst); 444 iewStage->activityThisCycle(); 445 } 446 447 return load_fault; 448} 449 450template <class Impl> 451Fault 452LSQUnit<Impl>::executeLoad(int lq_idx) 453{ 454 // Very hackish. Not sure the best way to check that this 455 // instruction is at the head of the ROB. I should have some sort 456 // of extra information here so that I'm not overloading the 457 // canCommit signal for 15 different things. 458 loadQueue[lq_idx]->setCanCommit(); 459 Fault ret_fault = executeLoad(loadQueue[lq_idx]); 460 loadQueue[lq_idx]->clearCanCommit(); 461 return ret_fault; 462} 463 464template <class Impl> 465Fault 466LSQUnit<Impl>::executeStore(DynInstPtr &store_inst) 467{ 468 using namespace TheISA; 469 // Make sure that a store exists. 470 assert(stores != 0); 471 472 int store_idx = store_inst->sqIdx; 473 474 DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n", 475 store_inst->readPC(), store_inst->seqNum); 476 477 // Check the recently completed loads to see if any match this store's 478 // address. If so, then we have a memory ordering violation. 479 int load_idx = store_inst->lqIdx; 480 481 Fault store_fault = store_inst->initiateAcc(); 482// Fault store_fault = store_inst->execute(); 483 484 // Store size should now be available. Use it to get proper offset for 485 // addr comparisons. 486 int size = storeQueue[store_idx].size; 487 488 if (size == 0) { 489 DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n", 490 store_inst->readPC(),store_inst->seqNum); 491 492 return store_fault; 493 } 494 495 assert(store_fault == NoFault); 496 497 if (!storeFaultInst) { 498 if (store_fault != NoFault) { 499 panic("Fault in a store instruction!"); 500 storeFaultInst = store_inst; 501 } else if (store_inst->isNonSpeculative()) { 502 // Nonspeculative accesses (namely store conditionals) 503 // need to set themselves as able to writeback if we 504 // haven't had a fault by here. 505 storeQueue[store_idx].canWB = true; 506 507 ++storesToWB; 508 } 509 } 510 511 if (!memDepViolator) { 512 while (load_idx != loadTail) { 513 // Actually should only check loads that have actually executed 514 // Might be safe because effAddr is set to InvalAddr when the 515 // dyn inst is created. 516 517 // Must actually check all addrs in the proper size range 518 // Which is more correct than needs to be. What if for now we just 519 // assume all loads are quad-word loads, and do the addr based 520 // on that. 521 // @todo: Fix this, magic number being used here 522 if ((loadQueue[load_idx]->effAddr >> 8) == 523 (store_inst->effAddr >> 8)) { 524 // A load incorrectly passed this store. Squash and refetch. 525 // For now return a fault to show that it was unsuccessful. 526 memDepViolator = loadQueue[load_idx]; 527 528 return genMachineCheckFault(); 529 } 530 531 incrLdIdx(load_idx); 532 } 533 534 // If we've reached this point, there was no violation. 535 memDepViolator = NULL; 536 } 537 538 return store_fault; 539} 540 541template <class Impl> 542void 543LSQUnit<Impl>::commitLoad() 544{ 545 assert(loadQueue[loadHead]); 546 547 DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n", 548 loadQueue[loadHead]->readPC()); 549 550 551 loadQueue[loadHead] = NULL; 552 553 incrLdIdx(loadHead); 554 555 --loads; 556} 557 558template <class Impl> 559void 560LSQUnit<Impl>::commitLoad(InstSeqNum &inst) 561{ 562 // Hopefully I don't use this function too much 563 panic("Don't use this function!"); 564 565 int i = loadHead; 566 while (1) { 567 if (i == loadTail) { 568 assert(0 && "Load not in the queue!"); 569 } else if (loadQueue[i]->seqNum == inst) { 570 break; 571 } 572 573 ++i; 574 if (i >= LQEntries) { 575 i = 0; 576 } 577 } 578 579 loadQueue[i]->removeInLSQ(); 580 loadQueue[i] = NULL; 581 --loads; 582} 583 584template <class Impl> 585void 586LSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst) 587{ 588 assert(loads == 0 || loadQueue[loadHead]); 589 590 while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) { 591 commitLoad(); 592 } 593} 594 595template <class Impl> 596void 597LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst) 598{ 599 assert(stores == 0 || storeQueue[storeHead].inst); 600 601 int store_idx = storeHead; 602 603 while (store_idx != storeTail) { 604 assert(storeQueue[store_idx].inst); 605 if (!storeQueue[store_idx].canWB) { 606 if (storeQueue[store_idx].inst->seqNum > youngest_inst) { 607 break; 608 } 609 DPRINTF(LSQUnit, "Marking store as able to write back, PC " 610 "%#x [sn:%lli]\n", 611 storeQueue[store_idx].inst->readPC(), 612 storeQueue[store_idx].inst->seqNum); 613 614 storeQueue[store_idx].canWB = true; 615 616// --stores; 617 ++storesToWB; 618 } 619 620 incrStIdx(store_idx); 621 } 622} 623 624template <class Impl> 625void 626LSQUnit<Impl>::writebackStores() 627{ 628 while (storesToWB > 0 && 629 storeWBIdx != storeTail && 630 storeQueue[storeWBIdx].inst && 631 storeQueue[storeWBIdx].canWB && 632 usedPorts < cachePorts) { 633 634 if (storeQueue[storeWBIdx].size == 0) { 635 completeStore(storeWBIdx); 636 637 incrStIdx(storeWBIdx); 638 639 continue; 640 } 641 642 if (dcacheInterface && dcacheInterface->isBlocked()) { 643 DPRINTF(LSQUnit, "Unable to write back any more stores, cache" 644 " is blocked!\n"); 645 break; 646 } 647 648 ++usedPorts; 649 650 if (storeQueue[storeWBIdx].inst->isDataPrefetch()) { 651 incrStIdx(storeWBIdx); 652 653 continue; 654 } 655 656 assert(storeQueue[storeWBIdx].req); 657 assert(!storeQueue[storeWBIdx].committed); 658 659 MemReqPtr req = storeQueue[storeWBIdx].req; 660 storeQueue[storeWBIdx].committed = true; 661 662// Fault fault = cpu->translateDataWriteReq(req); 663 req->cmd = Write; 664 req->completionEvent = NULL; 665 req->time = curTick; 666 assert(!req->data); 667 req->data = new uint8_t[64]; 668 memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size); 669 670 DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x " 671 "to Addr:%#x, data:%#x [sn:%lli]\n", 672 storeWBIdx,storeQueue[storeWBIdx].inst->readPC(), 673 req->paddr, *(req->data), 674 storeQueue[storeWBIdx].inst->seqNum); 675 676 switch(storeQueue[storeWBIdx].size) { 677 case 1: 678 cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data); 679 break; 680 case 2: 681 cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data); 682 break; 683 case 4: 684 cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data); 685 break; 686 case 8: 687 cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data); 688 break; 689 default: 690 panic("Unexpected store size!\n"); 691 } 692 if (!(req->flags & LOCKED)) { 693 storeQueue[storeWBIdx].inst->setCompleted(); 694 if (cpu->checker) { 695 cpu->checker->tick(storeQueue[storeWBIdx].inst); 696 } 697 } 698 699 if (dcacheInterface) { 700 assert(!req->completionEvent); 701 StoreCompletionEvent *store_event = new 702 StoreCompletionEvent(storeWBIdx, NULL, this); 703 req->completionEvent = store_event; 704 705 MemAccessResult result = dcacheInterface->access(req); 706 707 if (isStalled() && 708 storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) { 709 DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] " 710 "load idx:%i\n", 711 stallingStoreIsn, stallingLoadIdx); 712 stalled = false; 713 stallingStoreIsn = 0; 714 iewStage->replayMemInst(loadQueue[stallingLoadIdx]); 715 } 716 717 if (result != MA_HIT && dcacheInterface->doEvents()) { 718 typename IEW::LdWritebackEvent *wb = NULL; 719 if (req->flags & LOCKED) { 720 // Stx_C should not generate a system port transaction, 721 // but that might be hard to accomplish. 722 wb = new typename 723 IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst, 724 iewStage); 725 store_event->wbEvent = wb; 726 } 727 728 DPRINTF(LSQUnit,"D-Cache Write Miss!\n"); 729 730 DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n", 731 storeQueue[storeWBIdx].inst->seqNum); 732 733 lastDcacheStall = curTick; 734 735// _status = DcacheMissStall; 736 737 //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum); 738 739 //DPRINTF(LSQUnit, "Added MSHR. count = %i\n",mshrSeqNums.size()); 740 741 // Increment stat here or something 742 } else { 743 DPRINTF(LSQUnit,"D-Cache: Write Hit on idx:%i !\n", 744 storeWBIdx); 745 746 DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n", 747 storeQueue[storeWBIdx].inst->seqNum); 748 749 750 if (req->flags & LOCKED) { 751 // Stx_C does not generate a system port transaction. 752/* 753 if (req->flags & UNCACHEABLE) { 754 req->result = 2; 755 } else { 756 if (cpu->lockFlag && cpu->lockAddr == req->paddr) { 757 req->result=1; 758 } else { 759 req->result = 0; 760 } 761 } 762*/ 763 typename IEW::LdWritebackEvent *wb = 764 new typename IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst, 765 iewStage); 766 store_event->wbEvent = wb; 767 } 768 } 769 770 incrStIdx(storeWBIdx); 771 } else { 772 panic("Must HAVE DCACHE!!!!!\n"); 773 } 774 } 775 776 // Not sure this should set it to 0. 777 usedPorts = 0; 778 779 assert(stores >= 0 && storesToWB >= 0); 780} 781 782/*template <class Impl> 783void 784LSQUnit<Impl>::removeMSHR(InstSeqNum seqNum) 785{ 786 list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(), 787 mshrSeqNums.end(), 788 seqNum); 789 790 if (mshr_it != mshrSeqNums.end()) { 791 mshrSeqNums.erase(mshr_it); 792 DPRINTF(LSQUnit, "Removing MSHR. count = %i\n",mshrSeqNums.size()); 793 } 794}*/ 795 796template <class Impl> 797void 798LSQUnit<Impl>::squash(const InstSeqNum &squashed_num) 799{ 800 DPRINTF(LSQUnit, "Squashing until [sn:%lli]!" 801 "(Loads:%i Stores:%i)\n",squashed_num,loads,stores); 802 803 int load_idx = loadTail; 804 decrLdIdx(load_idx); 805 806 while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) { 807 808 // Clear the smart pointer to make sure it is decremented. 809 DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, " 810 "[sn:%lli]\n", 811 loadQueue[load_idx]->readPC(), 812 loadQueue[load_idx]->seqNum); 813 814 if (isStalled() && load_idx == stallingLoadIdx) { 815 stalled = false; 816 stallingStoreIsn = 0; 817 stallingLoadIdx = 0; 818 } 819 820 loadQueue[load_idx]->squashed = true; 821 loadQueue[load_idx] = NULL; 822 --loads; 823 824 // Inefficient! 825 loadTail = load_idx; 826 827 decrLdIdx(load_idx); 828 } 829 830 if (isLoadBlocked) { 831 if (squashed_num < blockedLoadSeqNum) { 832 isLoadBlocked = false; 833 loadBlockedHandled = false; 834 blockedLoadSeqNum = 0; 835 } 836 } 837 838 int store_idx = storeTail; 839 decrStIdx(store_idx); 840 841 while (stores != 0 && 842 storeQueue[store_idx].inst->seqNum > squashed_num) { 843 844 if (storeQueue[store_idx].canWB) { 845 break; 846 } 847 848 // Clear the smart pointer to make sure it is decremented. 849 DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, " 850 "idx:%i [sn:%lli]\n", 851 storeQueue[store_idx].inst->readPC(), 852 store_idx, storeQueue[store_idx].inst->seqNum); 853 854 // I don't think this can happen. It should have been cleared by the 855 // stalling load. 856 if (isStalled() && 857 storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { 858 panic("Is stalled should have been cleared by stalling load!\n"); 859 stalled = false; 860 stallingStoreIsn = 0; 861 } 862 863 storeQueue[store_idx].inst->squashed = true; 864 storeQueue[store_idx].inst = NULL; 865 storeQueue[store_idx].canWB = 0; 866 867 if (storeQueue[store_idx].req) { 868 assert(!storeQueue[store_idx].req->completionEvent); 869 } 870 storeQueue[store_idx].req = NULL; 871 --stores; 872 873 // Inefficient! 874 storeTail = store_idx; 875 876 decrStIdx(store_idx); 877 } 878} 879 880template <class Impl> 881void 882LSQUnit<Impl>::dumpInsts() 883{ 884 cprintf("Load store queue: Dumping instructions.\n"); 885 cprintf("Load queue size: %i\n", loads); 886 cprintf("Load queue: "); 887 888 int load_idx = loadHead; 889 890 while (load_idx != loadTail && loadQueue[load_idx]) { 891 cprintf("%#x ", loadQueue[load_idx]->readPC()); 892 893 incrLdIdx(load_idx); 894 } 895 896 cprintf("Store queue size: %i\n", stores); 897 cprintf("Store queue: "); 898 899 int store_idx = storeHead; 900 901 while (store_idx != storeTail && storeQueue[store_idx].inst) { 902 cprintf("%#x ", storeQueue[store_idx].inst->readPC()); 903 904 incrStIdx(store_idx); 905 } 906 907 cprintf("\n"); 908} 909 910template <class Impl> 911void 912LSQUnit<Impl>::completeStore(int store_idx) 913{ 914 assert(storeQueue[store_idx].inst); 915 storeQueue[store_idx].completed = true; 916 --storesToWB; 917 // A bit conservative because a store completion may not free up entries, 918 // but hopefully avoids two store completions in one cycle from making 919 // the CPU tick twice. 920 cpu->activityThisCycle(); 921 922 if (store_idx == storeHead) { 923 do { 924 incrStIdx(storeHead); 925 926 --stores; 927 } while (storeQueue[storeHead].completed && 928 storeHead != storeTail); 929 930 iewStage->updateLSQNextCycle = true; 931 } 932 933 DPRINTF(LSQUnit, "Store head idx:%i\n", storeHead); 934 935 if (isStalled() && 936 storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { 937 DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] " 938 "load idx:%i\n", 939 stallingStoreIsn, stallingLoadIdx); 940 stalled = false; 941 stallingStoreIsn = 0; 942 iewStage->replayMemInst(loadQueue[stallingLoadIdx]); 943 } 944 945 storeQueue[store_idx].inst->setCompleted(); 946 if (cpu->checker) { 947 cpu->checker->tick(storeQueue[store_idx].inst); 948 } 949} 950 951template <class Impl> 952inline void 953LSQUnit<Impl>::incrStIdx(int &store_idx) 954{ 955 if (++store_idx >= SQEntries) 956 store_idx = 0; 957} 958 959template <class Impl> 960inline void 961LSQUnit<Impl>::decrStIdx(int &store_idx) 962{ 963 if (--store_idx < 0) 964 store_idx += SQEntries; 965} 966 967template <class Impl> 968inline void 969LSQUnit<Impl>::incrLdIdx(int &load_idx) 970{ 971 if (++load_idx >= LQEntries) 972 load_idx = 0; 973} 974 975template <class Impl> 976inline void 977LSQUnit<Impl>::decrLdIdx(int &load_idx) 978{ 979 if (--load_idx < 0) 980 load_idx += LQEntries; 981} 982