lsq_unit_impl.hh revision 2316
12292SN/A/* 22727Sktlim@umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan 32292SN/A * All rights reserved. 42292SN/A * 52292SN/A * Redistribution and use in source and binary forms, with or without 62292SN/A * modification, are permitted provided that the following conditions are 72292SN/A * met: redistributions of source code must retain the above copyright 82292SN/A * notice, this list of conditions and the following disclaimer; 92292SN/A * redistributions in binary form must reproduce the above copyright 102292SN/A * notice, this list of conditions and the following disclaimer in the 112292SN/A * documentation and/or other materials provided with the distribution; 122292SN/A * neither the name of the copyright holders nor the names of its 132292SN/A * contributors may be used to endorse or promote products derived from 142292SN/A * this software without specific prior written permission. 152292SN/A * 162292SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182292SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192292SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202292SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212292SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222292SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232292SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242292SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252292SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262292SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272689Sktlim@umich.edu */ 282689Sktlim@umich.edu 292292SN/A#include "cpu/checker/cpu.hh" 302292SN/A#include "cpu/o3/lsq_unit.hh" 312329SN/A#include "base/str.hh" 322329SN/A 332329SN/Atemplate <class Impl> 342292SN/ALSQUnit<Impl>::StoreCompletionEvent::StoreCompletionEvent(int store_idx, 352292SN/A Event *wb_event, 362292SN/A LSQUnit<Impl> *lsq_ptr) 372292SN/A : Event(&mainEventQueue), 382292SN/A storeIdx(store_idx), 392907Sktlim@umich.edu wbEvent(wb_event), 402907Sktlim@umich.edu lsqPtr(lsq_ptr) 412907Sktlim@umich.edu{ 422907Sktlim@umich.edu this->setFlags(Event::AutoDelete); 432907Sktlim@umich.edu} 442907Sktlim@umich.edu 452907Sktlim@umich.edutemplate <class Impl> 462907Sktlim@umich.eduvoid 472907Sktlim@umich.eduLSQUnit<Impl>::StoreCompletionEvent::process() 482907Sktlim@umich.edu{ 492907Sktlim@umich.edu DPRINTF(LSQ, "Cache miss complete for store idx:%i\n", storeIdx); 502907Sktlim@umich.edu DPRINTF(Activity, "Activity: st writeback event idx:%i\n", storeIdx); 512907Sktlim@umich.edu 522907Sktlim@umich.edu //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum); 532907Sktlim@umich.edu 542907Sktlim@umich.edu if (lsqPtr->isSwitchedOut()) 552907Sktlim@umich.edu return; 562907Sktlim@umich.edu 572907Sktlim@umich.edu lsqPtr->cpu->wakeCPU(); 582907Sktlim@umich.edu if (wbEvent) 592907Sktlim@umich.edu wbEvent->process(); 602907Sktlim@umich.edu lsqPtr->completeStore(storeIdx); 612907Sktlim@umich.edu} 622907Sktlim@umich.edu 632907Sktlim@umich.edutemplate <class Impl> 642907Sktlim@umich.educonst char * 652907Sktlim@umich.eduLSQUnit<Impl>::StoreCompletionEvent::description() 662907Sktlim@umich.edu{ 672907Sktlim@umich.edu return "LSQ store completion event"; 682907Sktlim@umich.edu} 692907Sktlim@umich.edu 702907Sktlim@umich.edutemplate <class Impl> 712907Sktlim@umich.eduLSQUnit<Impl>::LSQUnit() 722907Sktlim@umich.edu : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false), 732907Sktlim@umich.edu loadBlockedHandled(false) 742907Sktlim@umich.edu{ 752907Sktlim@umich.edu} 762907Sktlim@umich.edu 772907Sktlim@umich.edutemplate<class Impl> 782907Sktlim@umich.eduvoid 792907Sktlim@umich.eduLSQUnit<Impl>::init(Params *params, unsigned maxLQEntries, 802907Sktlim@umich.edu unsigned maxSQEntries, unsigned id) 812907Sktlim@umich.edu 822292SN/A{ 832907Sktlim@umich.edu DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id); 842907Sktlim@umich.edu 852907Sktlim@umich.edu switchedOut = false; 862292SN/A 872292SN/A lsqID = id; 882292SN/A 892292SN/A LQEntries = maxLQEntries; 902292SN/A SQEntries = maxSQEntries; 912292SN/A 922292SN/A loadQueue.resize(LQEntries); 932292SN/A storeQueue.resize(SQEntries); 942292SN/A 952292SN/A 962292SN/A // May want to initialize these entries to NULL 972292SN/A 982292SN/A loadHead = loadTail = 0; 992292SN/A 1002292SN/A storeHead = storeWBIdx = storeTail = 0; 1012292SN/A 1022292SN/A usedPorts = 0; 1032292SN/A cachePorts = params->cachePorts; 1042292SN/A 1052292SN/A dcacheInterface = params->dcacheInterface; 1062292SN/A 1072292SN/A loadFaultInst = storeFaultInst = memDepViolator = NULL; 1082292SN/A 1092292SN/A blockedLoadSeqNum = 0; 1102292SN/A} 1112292SN/A 1122292SN/Atemplate<class Impl> 1132292SN/Astd::string 1142292SN/ALSQUnit<Impl>::name() const 1152292SN/A{ 1162292SN/A if (Impl::MaxThreads == 1) { 1172292SN/A return iewStage->name() + ".lsq"; 1182292SN/A } else { 1192292SN/A return iewStage->name() + ".lsq.thread." + to_string(lsqID); 1202292SN/A } 1212292SN/A} 1222292SN/A 1232292SN/Atemplate<class Impl> 1242292SN/Avoid 1252292SN/ALSQUnit<Impl>::clearLQ() 1262292SN/A{ 1272292SN/A loadQueue.clear(); 1282292SN/A} 1292292SN/A 1302292SN/Atemplate<class Impl> 1312292SN/Avoid 1322292SN/ALSQUnit<Impl>::clearSQ() 1332292SN/A{ 1342292SN/A storeQueue.clear(); 1352292SN/A} 1362292SN/A 1372292SN/A#if 0 1382292SN/Atemplate<class Impl> 1392292SN/Avoid 1402292SN/ALSQUnit<Impl>::setPageTable(PageTable *pt_ptr) 1412907Sktlim@umich.edu{ 1422907Sktlim@umich.edu DPRINTF(LSQUnit, "Setting the page table pointer.\n"); 1432292SN/A pTable = pt_ptr; 1442292SN/A} 1452292SN/A#endif 1462292SN/A 1472292SN/Atemplate<class Impl> 1482292SN/Avoid 1492292SN/ALSQUnit<Impl>::switchOut() 1502292SN/A{ 1512292SN/A switchedOut = true; 1522292SN/A for (int i = 0; i < loadQueue.size(); ++i) 1532292SN/A loadQueue[i] = NULL; 1542292SN/A 1552292SN/A while (storesToWB > 0 && 1562727Sktlim@umich.edu storeWBIdx != storeTail && 1572727Sktlim@umich.edu storeQueue[storeWBIdx].inst && 1582727Sktlim@umich.edu storeQueue[storeWBIdx].canWB) { 1592727Sktlim@umich.edu 1602727Sktlim@umich.edu if (storeQueue[storeWBIdx].size == 0 || 1612727Sktlim@umich.edu storeQueue[storeWBIdx].inst->isDataPrefetch() || 1622727Sktlim@umich.edu storeQueue[storeWBIdx].committed || 1632727Sktlim@umich.edu storeQueue[storeWBIdx].req->flags & LOCKED) { 1642727Sktlim@umich.edu incrStIdx(storeWBIdx); 1652727Sktlim@umich.edu 1662292SN/A continue; 1672292SN/A } 1682292SN/A 1692292SN/A assert(storeQueue[storeWBIdx].req); 1702292SN/A assert(!storeQueue[storeWBIdx].committed); 1712292SN/A 1722292SN/A MemReqPtr req = storeQueue[storeWBIdx].req; 1732292SN/A storeQueue[storeWBIdx].committed = true; 1742733Sktlim@umich.edu 1752292SN/A req->cmd = Write; 1762292SN/A req->completionEvent = NULL; 1772292SN/A req->time = curTick; 1782907Sktlim@umich.edu assert(!req->data); 1792907Sktlim@umich.edu req->data = new uint8_t[64]; 1802292SN/A memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size); 1812292SN/A 1822292SN/A DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x " 1832292SN/A "to Addr:%#x, data:%#x [sn:%lli]\n", 1842292SN/A storeWBIdx,storeQueue[storeWBIdx].inst->readPC(), 1852292SN/A req->paddr, *(req->data), 1862292SN/A storeQueue[storeWBIdx].inst->seqNum); 1872292SN/A 1882292SN/A switch(storeQueue[storeWBIdx].size) { 1892292SN/A case 1: 1902292SN/A cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data); 1912292SN/A break; 1922292SN/A case 2: 1932292SN/A cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data); 1942292SN/A break; 1952292SN/A case 4: 1962292SN/A cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data); 1972307SN/A break; 1982307SN/A case 8: 1992307SN/A cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data); 2002307SN/A break; 2012307SN/A default: 2022307SN/A panic("Unexpected store size!\n"); 2032307SN/A } 2042307SN/A incrStIdx(storeWBIdx); 2052307SN/A } 2062307SN/A} 2072307SN/A 2082307SN/Atemplate<class Impl> 2092307SN/Avoid 2102307SN/ALSQUnit<Impl>::takeOverFrom() 2112307SN/A{ 2122307SN/A switchedOut = false; 2132307SN/A loads = stores = storesToWB = 0; 2142307SN/A 2152292SN/A loadHead = loadTail = 0; 2162292SN/A 2172292SN/A storeHead = storeWBIdx = storeTail = 0; 2182292SN/A 2192292SN/A usedPorts = 0; 2202292SN/A 2212292SN/A loadFaultInst = storeFaultInst = memDepViolator = NULL; 2222292SN/A 2232292SN/A blockedLoadSeqNum = 0; 2242292SN/A 2252292SN/A stalled = false; 2262292SN/A isLoadBlocked = false; 2272292SN/A loadBlockedHandled = false; 2282292SN/A} 2292292SN/A 2302292SN/Atemplate<class Impl> 2312292SN/Avoid 2322292SN/ALSQUnit<Impl>::resizeLQ(unsigned size) 2332292SN/A{ 2342292SN/A assert( size >= LQEntries); 2352292SN/A 2362292SN/A if (size > LQEntries) { 2372292SN/A while (size > loadQueue.size()) { 2382292SN/A DynInstPtr dummy; 2392292SN/A loadQueue.push_back(dummy); 2402292SN/A LQEntries++; 2412292SN/A } 2422292SN/A } else { 2432292SN/A LQEntries = size; 2442292SN/A } 2452292SN/A 2462292SN/A} 2472292SN/A 2482292SN/Atemplate<class Impl> 2492292SN/Avoid 2502292SN/ALSQUnit<Impl>::resizeSQ(unsigned size) 2512292SN/A{ 2522292SN/A if (size > SQEntries) { 2532292SN/A while (size > storeQueue.size()) { 2542292SN/A SQEntry dummy; 2552292SN/A storeQueue.push_back(dummy); 2562292SN/A SQEntries++; 2572292SN/A } 2582292SN/A } else { 2592292SN/A SQEntries = size; 2602292SN/A } 2612292SN/A} 2622292SN/A 2632292SN/Atemplate <class Impl> 2642292SN/Avoid 2652292SN/ALSQUnit<Impl>::insert(DynInstPtr &inst) 2662292SN/A{ 2672292SN/A // Make sure we really have a memory reference. 2682292SN/A assert(inst->isMemRef()); 2692292SN/A 2702292SN/A // Make sure it's one of the two classes of memory references. 2712292SN/A assert(inst->isLoad() || inst->isStore()); 2722292SN/A 2732292SN/A if (inst->isLoad()) { 2742292SN/A insertLoad(inst); 2752292SN/A } else { 2762292SN/A insertStore(inst); 2772292SN/A } 2782292SN/A 2792292SN/A inst->setInLSQ(); 2802292SN/A} 2812292SN/A 2822292SN/Atemplate <class Impl> 2832292SN/Avoid 2842292SN/ALSQUnit<Impl>::insertLoad(DynInstPtr &load_inst) 2852292SN/A{ 2862292SN/A assert((loadTail + 1) % LQEntries != loadHead && loads < LQEntries); 2872292SN/A 2882292SN/A DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n", 2892292SN/A load_inst->readPC(), loadTail, load_inst->seqNum); 2902292SN/A 2912292SN/A load_inst->lqIdx = loadTail; 2922292SN/A 2932292SN/A if (stores == 0) { 2942292SN/A load_inst->sqIdx = -1; 2952292SN/A } else { 2962292SN/A load_inst->sqIdx = storeTail; 2972292SN/A } 2982292SN/A 2992292SN/A loadQueue[loadTail] = load_inst; 3002292SN/A 3012292SN/A incrLdIdx(loadTail); 3022292SN/A 3032292SN/A ++loads; 3042292SN/A} 3052292SN/A 3062292SN/Atemplate <class Impl> 3072292SN/Avoid 3082292SN/ALSQUnit<Impl>::insertStore(DynInstPtr &store_inst) 3092292SN/A{ 3102292SN/A // Make sure it is not full before inserting an instruction. 3112292SN/A assert((storeTail + 1) % SQEntries != storeHead); 3122292SN/A assert(stores < SQEntries); 3132292SN/A 3142292SN/A DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n", 3152292SN/A store_inst->readPC(), storeTail, store_inst->seqNum); 3162292SN/A 3172292SN/A store_inst->sqIdx = storeTail; 3182292SN/A store_inst->lqIdx = loadTail; 3192292SN/A 3202292SN/A storeQueue[storeTail] = SQEntry(store_inst); 3212292SN/A 3222292SN/A incrStIdx(storeTail); 3232292SN/A 3242292SN/A ++stores; 3252292SN/A 3262329SN/A} 3272329SN/A 3282292SN/Atemplate <class Impl> 3292292SN/Atypename Impl::DynInstPtr 3302292SN/ALSQUnit<Impl>::getMemDepViolator() 3312292SN/A{ 3322292SN/A DynInstPtr temp = memDepViolator; 3332292SN/A 3342292SN/A memDepViolator = NULL; 3352292SN/A 3362292SN/A return temp; 3372292SN/A} 3382292SN/A 3392292SN/Atemplate <class Impl> 3402292SN/Aunsigned 3412292SN/ALSQUnit<Impl>::numFreeEntries() 3422292SN/A{ 3432292SN/A unsigned free_lq_entries = LQEntries - loads; 3442292SN/A unsigned free_sq_entries = SQEntries - stores; 3452292SN/A 3462292SN/A // Both the LQ and SQ entries have an extra dummy entry to differentiate 3472292SN/A // empty/full conditions. Subtract 1 from the free entries. 3482292SN/A if (free_lq_entries < free_sq_entries) { 3492292SN/A return free_lq_entries - 1; 3502292SN/A } else { 3512292SN/A return free_sq_entries - 1; 3522292SN/A } 3532292SN/A} 3542292SN/A 3552292SN/Atemplate <class Impl> 3562292SN/Aint 3572292SN/ALSQUnit<Impl>::numLoadsReady() 3582292SN/A{ 3592292SN/A int load_idx = loadHead; 3602292SN/A int retval = 0; 3612292SN/A 3622292SN/A while (load_idx != loadTail) { 3632292SN/A assert(loadQueue[load_idx]); 3642292SN/A 3652292SN/A if (loadQueue[load_idx]->readyToIssue()) { 3662292SN/A ++retval; 3672292SN/A } 3682292SN/A } 3692292SN/A 3702292SN/A return retval; 3712292SN/A} 3722292SN/A 3732292SN/A#if 0 3742292SN/Atemplate <class Impl> 3752292SN/AFault 3762292SN/ALSQUnit<Impl>::executeLoad() 3772292SN/A{ 3782292SN/A Fault load_fault = NoFault; 3792292SN/A DynInstPtr load_inst; 3802292SN/A 3812292SN/A assert(readyLoads.size() != 0); 3822292SN/A 3832292SN/A // Execute a ready load. 3842292SN/A LdMapIt ready_it = readyLoads.begin(); 3852292SN/A 3862292SN/A load_inst = (*ready_it).second; 3872292SN/A 3882292SN/A // Execute the instruction, which is held in the data portion of the 3892292SN/A // iterator. 3902292SN/A load_fault = load_inst->execute(); 3912292SN/A 3922292SN/A // If it executed successfully, then switch it over to the executed 3932292SN/A // loads list. 3942292SN/A if (load_fault == NoFault) { 3952292SN/A executedLoads[load_inst->seqNum] = load_inst; 3962292SN/A 3972292SN/A readyLoads.erase(ready_it); 3982292SN/A } else { 3992292SN/A loadFaultInst = load_inst; 4002292SN/A } 4012292SN/A 4022292SN/A return load_fault; 4032292SN/A} 4042292SN/A#endif 4052292SN/A 4062292SN/Atemplate <class Impl> 4072292SN/AFault 4082292SN/ALSQUnit<Impl>::executeLoad(DynInstPtr &inst) 4092292SN/A{ 4102292SN/A // Execute a specific load. 4112292SN/A Fault load_fault = NoFault; 4122292SN/A 4132292SN/A DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n", 4142292SN/A inst->readPC(),inst->seqNum); 4152292SN/A 4162292SN/A // Make sure it's really in the list. 4172292SN/A // Normally it should always be in the list. However, 4182292SN/A /* due to a syscall it may not be the list. 4192292SN/A#ifdef DEBUG 4202292SN/A int i = loadHead; 4212292SN/A while (1) { 4222292SN/A if (i == loadTail && !find(inst)) { 4232292SN/A assert(0 && "Load not in the queue!"); 4242292SN/A } else if (loadQueue[i] == inst) { 4252292SN/A break; 4262292SN/A } 4272292SN/A 4282292SN/A i = i + 1; 4292292SN/A if (i >= LQEntries) { 4302292SN/A i = 0; 4312292SN/A } 4322292SN/A } 4332292SN/A#endif // DEBUG*/ 4342292SN/A 4352292SN/A// load_fault = inst->initiateAcc(); 4362292SN/A load_fault = inst->execute(); 4372292SN/A 4382292SN/A // If the instruction faulted, then we need to send it along to commit 4392292SN/A // without the instruction completing. 4402292SN/A if (load_fault != NoFault) { 4412292SN/A // Maybe just set it as can commit here, although that might cause 4422292SN/A // some other problems with sending traps to the ROB too quickly. 4432292SN/A iewStage->instToCommit(inst); 4442292SN/A iewStage->activityThisCycle(); 4452292SN/A } 4462292SN/A 4472292SN/A return load_fault; 4482292SN/A} 4492292SN/A 4502292SN/Atemplate <class Impl> 4512292SN/AFault 4522292SN/ALSQUnit<Impl>::executeLoad(int lq_idx) 4532292SN/A{ 4542292SN/A // Very hackish. Not sure the best way to check that this 4552292SN/A // instruction is at the head of the ROB. I should have some sort 4562292SN/A // of extra information here so that I'm not overloading the 4572292SN/A // canCommit signal for 15 different things. 4582292SN/A loadQueue[lq_idx]->setCanCommit(); 4592292SN/A Fault ret_fault = executeLoad(loadQueue[lq_idx]); 4602292SN/A loadQueue[lq_idx]->clearCanCommit(); 4612292SN/A return ret_fault; 4622292SN/A} 4632292SN/A 4642292SN/Atemplate <class Impl> 4652292SN/AFault 4662292SN/ALSQUnit<Impl>::executeStore(DynInstPtr &store_inst) 4672292SN/A{ 4682292SN/A using namespace TheISA; 4692292SN/A // Make sure that a store exists. 4702292SN/A assert(stores != 0); 4712292SN/A 4722292SN/A int store_idx = store_inst->sqIdx; 4732292SN/A 4742292SN/A DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n", 4752292SN/A store_inst->readPC(), store_inst->seqNum); 4762292SN/A 4772292SN/A // Check the recently completed loads to see if any match this store's 4782292SN/A // address. If so, then we have a memory ordering violation. 4792292SN/A int load_idx = store_inst->lqIdx; 4802292SN/A 4812292SN/A Fault store_fault = store_inst->initiateAcc(); 4822292SN/A// Fault store_fault = store_inst->execute(); 4832292SN/A 4842292SN/A // Store size should now be available. Use it to get proper offset for 4852292SN/A // addr comparisons. 4862292SN/A int size = storeQueue[store_idx].size; 4872292SN/A 4882292SN/A if (size == 0) { 4892292SN/A DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n", 4902292SN/A store_inst->readPC(),store_inst->seqNum); 4912292SN/A 4922292SN/A return store_fault; 4932292SN/A } 4942292SN/A 4952292SN/A assert(store_fault == NoFault); 4962292SN/A 4972292SN/A if (!storeFaultInst) { 4982292SN/A if (store_fault != NoFault) { 4992292SN/A panic("Fault in a store instruction!"); 5002292SN/A storeFaultInst = store_inst; 5012292SN/A } else if (store_inst->isNonSpeculative()) { 5022292SN/A // Nonspeculative accesses (namely store conditionals) 5032292SN/A // need to set themselves as able to writeback if we 5042292SN/A // haven't had a fault by here. 5052292SN/A storeQueue[store_idx].canWB = true; 5062292SN/A 5072292SN/A ++storesToWB; 5082292SN/A } 5092292SN/A } 5102292SN/A 5112292SN/A if (!memDepViolator) { 5122292SN/A while (load_idx != loadTail) { 5132292SN/A // Actually should only check loads that have actually executed 5142292SN/A // Might be safe because effAddr is set to InvalAddr when the 5152292SN/A // dyn inst is created. 5162292SN/A 5172292SN/A // Must actually check all addrs in the proper size range 5182292SN/A // Which is more correct than needs to be. What if for now we just 5192292SN/A // assume all loads are quad-word loads, and do the addr based 5202292SN/A // on that. 5212292SN/A // @todo: Fix this, magic number being used here 5222292SN/A if ((loadQueue[load_idx]->effAddr >> 8) == 5232292SN/A (store_inst->effAddr >> 8)) { 5242292SN/A // A load incorrectly passed this store. Squash and refetch. 5252292SN/A // For now return a fault to show that it was unsuccessful. 5262292SN/A memDepViolator = loadQueue[load_idx]; 5272292SN/A 5282292SN/A return genMachineCheckFault(); 5292292SN/A } 5302292SN/A 5312292SN/A incrLdIdx(load_idx); 5322292SN/A } 5332292SN/A 5342292SN/A // If we've reached this point, there was no violation. 5352292SN/A memDepViolator = NULL; 5362292SN/A } 5372292SN/A 5382292SN/A return store_fault; 5392292SN/A} 5402292SN/A 5412292SN/Atemplate <class Impl> 5422292SN/Avoid 5432292SN/ALSQUnit<Impl>::commitLoad() 5442292SN/A{ 5452292SN/A assert(loadQueue[loadHead]); 5462292SN/A 5472292SN/A DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n", 5482292SN/A loadQueue[loadHead]->readPC()); 5492292SN/A 5502292SN/A 5512292SN/A loadQueue[loadHead] = NULL; 5522864Sktlim@umich.edu 5532864Sktlim@umich.edu incrLdIdx(loadHead); 5542864Sktlim@umich.edu 5552292SN/A --loads; 5562292SN/A} 5572292SN/A 5582292SN/Atemplate <class Impl> 5592292SN/Avoid 5602292SN/ALSQUnit<Impl>::commitLoad(InstSeqNum &inst) 5612292SN/A{ 5622292SN/A // Hopefully I don't use this function too much 5632292SN/A panic("Don't use this function!"); 5642292SN/A 5652292SN/A int i = loadHead; 5662292SN/A while (1) { 5672292SN/A if (i == loadTail) { 5682292SN/A assert(0 && "Load not in the queue!"); 5692292SN/A } else if (loadQueue[i]->seqNum == inst) { 5702292SN/A break; 5712292SN/A } 5722292SN/A 5732292SN/A ++i; 5742292SN/A if (i >= LQEntries) { 5752292SN/A i = 0; 5762292SN/A } 5772292SN/A } 5782292SN/A 5792292SN/A loadQueue[i]->removeInLSQ(); 5802292SN/A loadQueue[i] = NULL; 5812292SN/A --loads; 5822292SN/A} 5832292SN/A 5842292SN/Atemplate <class Impl> 5852292SN/Avoid 5862292SN/ALSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst) 5872292SN/A{ 5882292SN/A assert(loads == 0 || loadQueue[loadHead]); 5892292SN/A 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