lsq_unit_impl.hh revision 2722:610b13e19da0
13116SN/A/* 23116SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan 33116SN/A * All rights reserved. 43116SN/A * 53116SN/A * Redistribution and use in source and binary forms, with or without 63116SN/A * modification, are permitted provided that the following conditions are 73116SN/A * met: redistributions of source code must retain the above copyright 83116SN/A * notice, this list of conditions and the following disclaimer; 93116SN/A * redistributions in binary form must reproduce the above copyright 103116SN/A * notice, this list of conditions and the following disclaimer in the 113116SN/A * documentation and/or other materials provided with the distribution; 123116SN/A * neither the name of the copyright holders nor the names of its 133116SN/A * contributors may be used to endorse or promote products derived from 143116SN/A * this software without specific prior written permission. 153116SN/A * 163116SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 173116SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 183116SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 193116SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 203116SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 213116SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 223116SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233116SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243116SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253116SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 263116SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273116SN/A * 283116SN/A * Authors: Kevin Lim 293116SN/A * Korey Sewell 303116SN/A */ 313116SN/A 323116SN/A#include "cpu/checker/cpu.hh" 333318SN/A#include "cpu/o3/lsq_unit.hh" 343318SN/A#include "base/str.hh" 353318SN/A#include "mem/packet.hh" 363116SN/A#include "mem/request.hh" 373116SN/A 3811263Sandreas.sandberg@arm.comtemplate<class Impl> 394263SN/ALSQUnit<Impl>::WritebackEvent::WritebackEvent(DynInstPtr &_inst, PacketPtr _pkt, 404263SN/A LSQUnit *lsq_ptr) 414263SN/A : Event(&mainEventQueue), inst(_inst), pkt(_pkt), lsqPtr(lsq_ptr) 424263SN/A{ 434263SN/A this->setFlags(Event::AutoDelete); 444762SN/A} 4510469SN/A 464762SN/Atemplate<class Impl> 473116SN/Avoid 484263SN/ALSQUnit<Impl>::WritebackEvent::process() 499152SN/A{ 508232SN/A if (!lsqPtr->isSwitchedOut()) { 513116SN/A lsqPtr->writeback(inst, pkt); 523405SN/A } 534762SN/A delete pkt; 543116SN/A} 553116SN/A 563116SN/Atemplate<class Impl> 573318SN/Aconst char * 584263SN/ALSQUnit<Impl>::WritebackEvent::description() 593318SN/A{ 604981SN/A return "Store writeback event"; 6110913SN/A} 6212064Sgabeblack@google.com 6312064Sgabeblack@google.comtemplate<class Impl> 6412064Sgabeblack@google.comvoid 6511320Ssteve.reinhardt@amd.comLSQUnit<Impl>::completeDataAccess(PacketPtr pkt) 6611320Ssteve.reinhardt@amd.com{ 6712087Sspwilson2@wisc.edu LSQSenderState *state = dynamic_cast<LSQSenderState *>(pkt->senderState); 6812087Sspwilson2@wisc.edu DynInstPtr inst = state->inst; 6912087Sspwilson2@wisc.edu DPRINTF(IEW, "Writeback event [sn:%lli]\n", inst->seqNum); 7012087Sspwilson2@wisc.edu DPRINTF(Activity, "Activity: Writeback event [sn:%lli]\n", inst->seqNum); 7112087Sspwilson2@wisc.edu 7212087Sspwilson2@wisc.edu //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum); 734283SN/A 745500SN/A if (isSwitchedOut() || inst->isSquashed()) { 759157SN/A delete state; 763116SN/A delete pkt; 774981SN/A return; 784981SN/A } else { 793318SN/A if (!state->noWB) { 804263SN/A writeback(inst, pkt); 814218SN/A } 824218SN/A 834218SN/A if (inst->isStore()) { 844218SN/A completeStore(state->idx); 854218SN/A } 864218SN/A } 874283SN/A 884218SN/A delete state; 894218SN/A delete pkt; 904263SN/A} 914263SN/A 924263SN/Atemplate <class Impl> 934263SN/ATick 944218SN/ALSQUnit<Impl>::DcachePort::recvAtomic(PacketPtr pkt) 955763SN/A{ 965763SN/A panic("O3CPU model does not work with atomic mode!"); 975763SN/A return curTick; 983116SN/A} 994218SN/A 1004218SN/Atemplate <class Impl> 1013405SN/Avoid 1023318SN/ALSQUnit<Impl>::DcachePort::recvFunctional(PacketPtr pkt) 1033318SN/A{ 1043318SN/A panic("O3CPU doesn't expect recvFunctional callback!"); 1053318SN/A} 1063318SN/A 1073405SN/Atemplate <class Impl> 1083405SN/Avoid 1093405SN/ALSQUnit<Impl>::DcachePort::recvStatusChange(Status status) 1104283SN/A{ 1114283SN/A if (status == RangeChange) 1124283SN/A return; 1134283SN/A 1144218SN/A panic("O3CPU doesn't expect recvStatusChange callback!"); 1154218SN/A} 1164218SN/A 1174283SN/Atemplate <class Impl> 1184283SN/Abool 1194218SN/ALSQUnit<Impl>::DcachePort::recvTiming(PacketPtr pkt) 1203318SN/A{ 1214218SN/A lsq->completeDataAccess(pkt); 1224263SN/A return true; 1235954SN/A} 1245954SN/A 1255954SN/Atemplate <class Impl> 1264263SN/Avoid 1274263SN/ALSQUnit<Impl>::DcachePort::recvRetry() 1283116SN/A{ 1293116SN/A lsq->recvRetry(); 1309086SN/A} 1319086SN/A 1329086SN/Atemplate <class Impl> 1339086SN/ALSQUnit<Impl>::LSQUnit() 1349086SN/A : loads(0), stores(0), storesToWB(0), stalled(false), 1355954SN/A isStoreBlocked(false), isLoadBlocked(false), 1365954SN/A loadBlockedHandled(false) 1375954SN/A{ 1385954SN/A} 1399807SN/A 1405954SN/Atemplate<class Impl> 1415954SN/Avoid 14213784Sgabeblack@google.comLSQUnit<Impl>::init(Params *params, unsigned maxLQEntries, 14313784Sgabeblack@google.com unsigned maxSQEntries, unsigned id) 1444981SN/A{ 14513784Sgabeblack@google.com DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id); 14613784Sgabeblack@google.com 14713784Sgabeblack@google.com switchedOut = false; 1484981SN/A 1493116SN/A lsqID = id; 1503116SN/A 1513349SN/A // Add 1 for the sentinel entry (they are circular queues). 1523116SN/A LQEntries = maxLQEntries + 1; 1533116SN/A SQEntries = maxSQEntries + 1; 1543116SN/A 1559807SN/A loadQueue.resize(LQEntries); 1563116SN/A storeQueue.resize(SQEntries); 1573116SN/A 1583116SN/A loadHead = loadTail = 0; 1596124SN/A 1606124SN/A storeHead = storeWBIdx = storeTail = 0; 1616124SN/A 1623116SN/A usedPorts = 0; 1639198SN/A cachePorts = params->cachePorts; 1643116SN/A 1653116SN/A mem = params->mem; 1666124SN/A 1676124SN/A memDepViolator = NULL; 1686124SN/A 1693116SN/A blockedLoadSeqNum = 0; 1703349SN/A} 1713116SN/A 1723116SN/Atemplate<class Impl> 1733116SN/Avoid 1743116SN/ALSQUnit<Impl>::setCPU(FullCPU *cpu_ptr) 1753116SN/A{ 1763116SN/A cpu = cpu_ptr; 1773116SN/A dcachePort = new DcachePort(cpu, this); 1783116SN/A 1793116SN/A Port *mem_dport = mem->getPort(""); 1803116SN/A dcachePort->setPeer(mem_dport); 1813318SN/A mem_dport->setPeer(dcachePort); 1823318SN/A 1833318SN/A if (cpu->checker) { 1844283SN/A cpu->checker->setDcachePort(dcachePort); 1853116SN/A } 1866124SN/A} 1876124SN/A 1886124SN/Atemplate<class Impl> 1893116SN/Astd::string 1903405SN/ALSQUnit<Impl>::name() const 1913318SN/A{ 1924218SN/A if (Impl::MaxThreads == 1) { 19313342Sgabeblack@google.com return iewStage->name() + ".lsq"; 1944218SN/A } else { 1954218SN/A return iewStage->name() + ".lsq.thread." + to_string(lsqID); 19613342Sgabeblack@google.com } 1974218SN/A} 1984218SN/A 19913342Sgabeblack@google.comtemplate<class Impl> 2004218SN/Avoid 2014218SN/ALSQUnit<Impl>::clearLQ() 20213342Sgabeblack@google.com{ 2034218SN/A loadQueue.clear(); 2044218SN/A} 20513342Sgabeblack@google.com 2064218SN/Atemplate<class Impl> 2074218SN/Avoid 20813342Sgabeblack@google.comLSQUnit<Impl>::clearSQ() 2094218SN/A{ 2104218SN/A storeQueue.clear(); 2116124SN/A} 2126124SN/A 21313342Sgabeblack@google.comtemplate<class Impl> 2144283SN/Avoid 2154283SN/ALSQUnit<Impl>::switchOut() 2164283SN/A{ 2174263SN/A switchedOut = true; 2184283SN/A for (int i = 0; i < loadQueue.size(); ++i) 2194283SN/A loadQueue[i] = NULL; 2204283SN/A 2214218SN/A assert(storesToWB == 0); 2225763SN/A} 2235763SN/A 2245763SN/Atemplate<class Impl> 22513342Sgabeblack@google.comvoid 2265763SN/ALSQUnit<Impl>::takeOverFrom() 2274218SN/A{ 22813342Sgabeblack@google.com switchedOut = false; 2294218SN/A loads = stores = storesToWB = 0; 2304218SN/A 23113342Sgabeblack@google.com loadHead = loadTail = 0; 2324218SN/A 2334218SN/A storeHead = storeWBIdx = storeTail = 0; 23413342Sgabeblack@google.com 2354218SN/A usedPorts = 0; 2364218SN/A 23713342Sgabeblack@google.com memDepViolator = NULL; 2384218SN/A 2394218SN/A blockedLoadSeqNum = 0; 24013342Sgabeblack@google.com 2414218SN/A stalled = false; 2424218SN/A isLoadBlocked = false; 24311810Sbaz21@cam.ac.uk loadBlockedHandled = false; 24411810Sbaz21@cam.ac.uk} 2454218SN/A 24613342Sgabeblack@google.comtemplate<class Impl> 2474218SN/Avoid 2484218SN/ALSQUnit<Impl>::resizeLQ(unsigned size) 24913342Sgabeblack@google.com{ 2504218SN/A unsigned size_plus_sentinel = size + 1; 2514218SN/A assert(size_plus_sentinel >= LQEntries); 25213342Sgabeblack@google.com 2534218SN/A if (size_plus_sentinel > LQEntries) { 2544218SN/A while (size_plus_sentinel > loadQueue.size()) { 25513342Sgabeblack@google.com DynInstPtr dummy; 2564218SN/A loadQueue.push_back(dummy); 2574218SN/A LQEntries++; 25813342Sgabeblack@google.com } 2594218SN/A } else { 2604218SN/A LQEntries = size_plus_sentinel; 26113342Sgabeblack@google.com } 2624218SN/A 2635763SN/A} 26413342Sgabeblack@google.com 2655763SN/Atemplate<class Impl> 2664218SN/Avoid 26713342Sgabeblack@google.comLSQUnit<Impl>::resizeSQ(unsigned size) 2684218SN/A{ 2694218SN/A unsigned size_plus_sentinel = size + 1; 27013342Sgabeblack@google.com if (size_plus_sentinel > SQEntries) { 2714218SN/A while (size_plus_sentinel > storeQueue.size()) { 2724218SN/A SQEntry dummy; 27313342Sgabeblack@google.com storeQueue.push_back(dummy); 2744263SN/A SQEntries++; 2754263SN/A } 2766124SN/A } else { 2776124SN/A SQEntries = size_plus_sentinel; 2784263SN/A } 2794263SN/A} 2804263SN/A 2814218SN/Atemplate <class Impl> 2825763SN/Avoid 28313342Sgabeblack@google.comLSQUnit<Impl>::insert(DynInstPtr &inst) 2845763SN/A{ 2854218SN/A assert(inst->isMemRef()); 28613342Sgabeblack@google.com 2874218SN/A assert(inst->isLoad() || inst->isStore()); 2884218SN/A 28913342Sgabeblack@google.com if (inst->isLoad()) { 2904218SN/A insertLoad(inst); 2914218SN/A } else { 29213342Sgabeblack@google.com insertStore(inst); 2934218SN/A } 2944218SN/A 29513342Sgabeblack@google.com inst->setInLSQ(); 2964218SN/A} 2974218SN/A 29813342Sgabeblack@google.comtemplate <class Impl> 2994218SN/Avoid 3005763SN/ALSQUnit<Impl>::insertLoad(DynInstPtr &load_inst) 30113342Sgabeblack@google.com{ 3025763SN/A assert((loadTail + 1) % LQEntries != loadHead); 3034218SN/A assert(loads < LQEntries); 30413342Sgabeblack@google.com 3054218SN/A DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n", 3064218SN/A load_inst->readPC(), loadTail, load_inst->seqNum); 30713342Sgabeblack@google.com 3084218SN/A load_inst->lqIdx = loadTail; 3094218SN/A 31013342Sgabeblack@google.com if (stores == 0) { 3114218SN/A load_inst->sqIdx = -1; 3124218SN/A } else { 31313342Sgabeblack@google.com load_inst->sqIdx = storeTail; 3144218SN/A } 3155763SN/A 31613342Sgabeblack@google.com loadQueue[loadTail] = load_inst; 3175763SN/A 3185763SN/A incrLdIdx(loadTail); 31913342Sgabeblack@google.com 3205763SN/A ++loads; 3214218SN/A} 32213342Sgabeblack@google.com 3234218SN/Atemplate <class Impl> 3245763SN/Avoid 32513342Sgabeblack@google.comLSQUnit<Impl>::insertStore(DynInstPtr &store_inst) 3265763SN/A{ 3275763SN/A // Make sure it is not full before inserting an instruction. 32813342Sgabeblack@google.com assert((storeTail + 1) % SQEntries != storeHead); 3295763SN/A assert(stores < SQEntries); 3304218SN/A 33113342Sgabeblack@google.com DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n", 3324218SN/A store_inst->readPC(), storeTail, store_inst->seqNum); 3335763SN/A 33413342Sgabeblack@google.com store_inst->sqIdx = storeTail; 3355763SN/A store_inst->lqIdx = loadTail; 3365763SN/A 3375763SN/A storeQueue[storeTail] = SQEntry(store_inst); 33813342Sgabeblack@google.com 3395763SN/A incrStIdx(storeTail); 3405763SN/A 34113342Sgabeblack@google.com ++stores; 3425763SN/A} 3433318SN/A 3446124SN/Atemplate <class Impl> 3456124SN/Atypename Impl::DynInstPtr 3466124SN/ALSQUnit<Impl>::getMemDepViolator() 3476124SN/A{ 3484218SN/A DynInstPtr temp = memDepViolator; 3494218SN/A 35013342Sgabeblack@google.com memDepViolator = NULL; 3513318SN/A 3523318SN/A return temp; 3534870SN/A} 3543116SN/A 3553116SN/Atemplate <class Impl> 3563116SN/Aunsigned 3573116SN/ALSQUnit<Impl>::numFreeEntries() 3583349SN/A{ 3593116SN/A unsigned free_lq_entries = LQEntries - loads; 3603116SN/A unsigned free_sq_entries = SQEntries - stores; 3613116SN/A 3623116SN/A // Both the LQ and SQ entries have an extra dummy entry to differentiate 3633318SN/A // empty/full conditions. Subtract 1 from the free entries. 3643116SN/A if (free_lq_entries < free_sq_entries) { 3653116SN/A return free_lq_entries - 1; 3663116SN/A } else { 3673116SN/A return free_sq_entries - 1; 3683116SN/A } 3693116SN/A} 3703318SN/A 3713318SN/Atemplate <class Impl> 3723318SN/Aint 3736124SN/ALSQUnit<Impl>::numLoadsReady() 37413342Sgabeblack@google.com{ 3753116SN/A int load_idx = loadHead; 3766124SN/A int retval = 0; 3776124SN/A 3786124SN/A while (load_idx != loadTail) { 37913342Sgabeblack@google.com assert(loadQueue[load_idx]); 3803318SN/A 3814263SN/A if (loadQueue[load_idx]->readyToIssue()) { 3824263SN/A ++retval; 3834263SN/A } 3843318SN/A } 3854218SN/A 3864218SN/A return retval; 3874218SN/A} 3884218SN/A 3894218SN/Atemplate <class Impl> 3904218SN/AFault 3914218SN/ALSQUnit<Impl>::executeLoad(DynInstPtr &inst) 3924218SN/A{ 3934218SN/A // Execute a specific load. 3944218SN/A Fault load_fault = NoFault; 3954218SN/A 3964218SN/A DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n", 3974218SN/A inst->readPC(),inst->seqNum); 3984218SN/A 3994218SN/A load_fault = inst->initiateAcc(); 4004218SN/A 4014218SN/A // If the instruction faulted, then we need to send it along to commit 4024218SN/A // without the instruction completing. 4034218SN/A if (load_fault != NoFault) { 4044218SN/A // Send this instruction to commit, also make sure iew stage 4054218SN/A // realizes there is activity. 4064218SN/A iewStage->instToCommit(inst); 4074218SN/A iewStage->activityThisCycle(); 4084218SN/A } 4094218SN/A 4104218SN/A return load_fault; 4114218SN/A} 4124218SN/A 4136124SN/Atemplate <class Impl> 4146124SN/AFault 4154218SN/ALSQUnit<Impl>::executeStore(DynInstPtr &store_inst) 4164218SN/A{ 4174218SN/A using namespace TheISA; 4184218SN/A // Make sure that a store exists. 4194218SN/A assert(stores != 0); 4204218SN/A 4214218SN/A int store_idx = store_inst->sqIdx; 4226124SN/A 4236124SN/A DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n", 4246124SN/A store_inst->readPC(), store_inst->seqNum); 4253318SN/A 4264218SN/A // Check the recently completed loads to see if any match this store's 4274218SN/A // address. If so, then we have a memory ordering violation. 4286124SN/A int load_idx = store_inst->lqIdx; 4294218SN/A 4304218SN/A Fault store_fault = store_inst->initiateAcc(); 4314218SN/A 4326124SN/A if (storeQueue[store_idx].size == 0) { 4334218SN/A DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n", 4344218SN/A store_inst->readPC(),store_inst->seqNum); 4353318SN/A 4366124SN/A return store_fault; 4374218SN/A } 4384218SN/A 4396124SN/A assert(store_fault == NoFault); 4404218SN/A 4414218SN/A if (store_inst->isStoreConditional()) { 4426124SN/A // Store conditionals need to set themselves as able to 4433318SN/A // writeback if we haven't had a fault by here. 4443318SN/A storeQueue[store_idx].canWB = true; 4454218SN/A 4464218SN/A ++storesToWB; 4474218SN/A } 4484218SN/A 4494218SN/A if (!memDepViolator) { 4504218SN/A while (load_idx != loadTail) { 4515763SN/A // Really only need to check loads that have actually executed 4525763SN/A // It's safe to check all loads because effAddr is set to 4535763SN/A // InvalAddr when the dyn inst is created. 4545763SN/A 4555763SN/A // @todo: For now this is extra conservative, detecting a 4565763SN/A // violation if the addresses match assuming all accesses 4575763SN/A // are quad word accesses. 4585763SN/A 4594218SN/A // @todo: Fix this, magic number being used here 4604218SN/A if ((loadQueue[load_idx]->effAddr >> 8) == 4614218SN/A (store_inst->effAddr >> 8)) { 4624218SN/A // A load incorrectly passed this store. Squash and refetch. 4634218SN/A // For now return a fault to show that it was unsuccessful. 4644218SN/A memDepViolator = loadQueue[load_idx]; 4654218SN/A 4666124SN/A return genMachineCheckFault(); 4676124SN/A } 4686124SN/A 4694218SN/A incrLdIdx(load_idx); 4706124SN/A } 4716124SN/A 4726124SN/A // If we've reached this point, there was no violation. 4736124SN/A memDepViolator = NULL; 4746124SN/A } 4756124SN/A 4766124SN/A return store_fault; 4776124SN/A} 4786124SN/A 4796124SN/Atemplate <class Impl> 4806124SN/Avoid 4816124SN/ALSQUnit<Impl>::commitLoad() 4826124SN/A{ 4836124SN/A assert(loadQueue[loadHead]); 4846124SN/A 4856124SN/A DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n", 4866124SN/A loadQueue[loadHead]->readPC()); 4876124SN/A 4886124SN/A loadQueue[loadHead] = NULL; 4896124SN/A 4904218SN/A incrLdIdx(loadHead); 4914218SN/A 4924218SN/A --loads; 4934218SN/A} 4946124SN/A 4956124SN/Atemplate <class Impl> 4964283SN/Avoid 4974283SN/ALSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst) 4984263SN/A{ 4994283SN/A assert(loads == 0 || loadQueue[loadHead]); 5004218SN/A 5014218SN/A while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) { 5024218SN/A commitLoad(); 5034218SN/A } 5044218SN/A} 5054291SN/A 5064263SN/Atemplate <class Impl> 5074218SN/Avoid 5086124SN/ALSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst) 5094218SN/A{ 5104263SN/A assert(stores == 0 || storeQueue[storeHead].inst); 5114218SN/A 5124218SN/A int store_idx = storeHead; 5134263SN/A 5144263SN/A while (store_idx != storeTail) { 5154218SN/A assert(storeQueue[store_idx].inst); 5164218SN/A // Mark any stores that are now committed and have not yet 5174218SN/A // been marked as able to write back. 5184218SN/A if (!storeQueue[store_idx].canWB) { 5194218SN/A if (storeQueue[store_idx].inst->seqNum > youngest_inst) { 5204263SN/A break; 5214218SN/A } 5224263SN/A DPRINTF(LSQUnit, "Marking store as able to write back, PC " 5234263SN/A "%#x [sn:%lli]\n", 5244291SN/A storeQueue[store_idx].inst->readPC(), 5254263SN/A storeQueue[store_idx].inst->seqNum); 5264263SN/A 5274263SN/A storeQueue[store_idx].canWB = true; 5284263SN/A 5294263SN/A ++storesToWB; 5304283SN/A } 5314218SN/A 5324218SN/A incrStIdx(store_idx); 5334218SN/A } 5344218SN/A} 5354218SN/A 5364218SN/Atemplate <class Impl> 5374263SN/Avoid 5384263SN/ALSQUnit<Impl>::writebackStores() 5394263SN/A{ 5406124SN/A while (storesToWB > 0 && 5414283SN/A storeWBIdx != storeTail && 5424263SN/A storeQueue[storeWBIdx].inst && 5434263SN/A storeQueue[storeWBIdx].canWB && 5444263SN/A usedPorts < cachePorts) { 5456124SN/A 5464218SN/A if (isStoreBlocked) { 5474218SN/A DPRINTF(LSQUnit, "Unable to write back any more stores, cache" 5484218SN/A " is blocked!\n"); 5494218SN/A break; 5504218SN/A } 55111810Sbaz21@cam.ac.uk 55211810Sbaz21@cam.ac.uk // Store didn't write any data so no need to write it back to 5534218SN/A // memory. 5544218SN/A if (storeQueue[storeWBIdx].size == 0) { 5554218SN/A completeStore(storeWBIdx); 5564218SN/A 5574218SN/A incrStIdx(storeWBIdx); 5584218SN/A 5594218SN/A continue; 5604218SN/A } 5614218SN/A 5625763SN/A ++usedPorts; 5635763SN/A 5645763SN/A if (storeQueue[storeWBIdx].inst->isDataPrefetch()) { 5654218SN/A incrStIdx(storeWBIdx); 5664218SN/A 5674218SN/A continue; 5684218SN/A } 5694218SN/A 5704218SN/A assert(storeQueue[storeWBIdx].req); 5714218SN/A assert(!storeQueue[storeWBIdx].committed); 5724218SN/A 5734263SN/A DynInstPtr inst = storeQueue[storeWBIdx].inst; 5744218SN/A 5754218SN/A Request *req = storeQueue[storeWBIdx].req; 5764218SN/A storeQueue[storeWBIdx].committed = true; 5774263SN/A 5784218SN/A assert(!inst->memData); 5794218SN/A inst->memData = new uint8_t[64]; 5804218SN/A memcpy(inst->memData, (uint8_t *)&storeQueue[storeWBIdx].data, 5814263SN/A req->getSize()); 5824218SN/A 5835763SN/A PacketPtr data_pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast); 5845763SN/A data_pkt->dataStatic(inst->memData); 5855763SN/A 5864218SN/A LSQSenderState *state = new LSQSenderState; 5874218SN/A state->isLoad = false; 5884263SN/A state->idx = storeWBIdx; 5894218SN/A state->inst = inst; 5904218SN/A data_pkt->senderState = state; 5914218SN/A 5924987SN/A DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x " 59310913SN/A "to Addr:%#x, data:%#x [sn:%lli]\n", 5944987SN/A storeWBIdx, storeQueue[storeWBIdx].inst->readPC(), 5954987SN/A req->getPaddr(), *(inst->memData), 5964987SN/A storeQueue[storeWBIdx].inst->seqNum); 5974987SN/A 5984987SN/A // @todo: Remove this SC hack once the memory system handles it. 5994218SN/A if (req->getFlags() & LOCKED) { 6004218SN/A if (req->getFlags() & UNCACHEABLE) { 6014218SN/A req->setScResult(2); 6024218SN/A } else { 6034218SN/A if (cpu->lockFlag) { 6044218SN/A req->setScResult(1); 6054218SN/A } else { 6065763SN/A req->setScResult(0); 6075763SN/A // Hack: Instantly complete this store. 6085763SN/A completeDataAccess(data_pkt); 6094218SN/A incrStIdx(storeWBIdx); 6104218SN/A continue; 6114263SN/A } 6124218SN/A } 6134218SN/A } else { 6144218SN/A // Non-store conditionals do not need a writeback. 6154263SN/A state->noWB = true; 6164218SN/A } 6174218SN/A 6184218SN/A if (!dcachePort->sendTiming(data_pkt)) { 6194263SN/A // Need to handle becoming blocked on a store. 6204218SN/A isStoreBlocked = true; 6214218SN/A 6224218SN/A assert(retryPkt == NULL); 6234263SN/A retryPkt = data_pkt; 6244218SN/A } else { 6255763SN/A storePostSend(data_pkt); 6265763SN/A } 6275763SN/A } 6285763SN/A 6295763SN/A // Not sure this should set it to 0. 6304218SN/A usedPorts = 0; 6314218SN/A 6324987SN/A assert(stores >= 0 && storesToWB >= 0); 63310913SN/A} 6344987SN/A 6354987SN/A/*template <class Impl> 6364987SN/Avoid 6374987SN/ALSQUnit<Impl>::removeMSHR(InstSeqNum seqNum) 6384987SN/A{ 6394218SN/A list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(), 6404218SN/A mshrSeqNums.end(), 6414218SN/A seqNum); 6424218SN/A 6434218SN/A if (mshr_it != mshrSeqNums.end()) { 6444218SN/A mshrSeqNums.erase(mshr_it); 6454218SN/A DPRINTF(LSQUnit, "Removing MSHR. count = %i\n",mshrSeqNums.size()); 6464218SN/A } 6474218SN/A}*/ 6484218SN/A 6495763SN/Atemplate <class Impl> 6505763SN/Avoid 6515763SN/ALSQUnit<Impl>::squash(const InstSeqNum &squashed_num) 6526124SN/A{ 6536124SN/A DPRINTF(LSQUnit, "Squashing until [sn:%lli]!" 6545763SN/A "(Loads:%i Stores:%i)\n", squashed_num, loads, stores); 6555763SN/A 6565763SN/A int load_idx = loadTail; 6575763SN/A decrLdIdx(load_idx); 6586124SN/A 6596124SN/A while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) { 6605763SN/A DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, " 6614218SN/A "[sn:%lli]\n", 6624218SN/A loadQueue[load_idx]->readPC(), 6634218SN/A loadQueue[load_idx]->seqNum); 6645763SN/A 6655763SN/A if (isStalled() && load_idx == stallingLoadIdx) { 6665763SN/A stalled = false; 6675763SN/A stallingStoreIsn = 0; 6685763SN/A stallingLoadIdx = 0; 6695763SN/A } 6705763SN/A 6715763SN/A // Clear the smart pointer to make sure it is decremented. 6724218SN/A loadQueue[load_idx]->squashed = true; 6734218SN/A loadQueue[load_idx] = NULL; 6744218SN/A --loads; 6755763SN/A 6765763SN/A // Inefficient! 6775763SN/A loadTail = load_idx; 6785763SN/A 6795763SN/A decrLdIdx(load_idx); 6805763SN/A } 6815763SN/A 6825763SN/A if (isLoadBlocked) { 6833318SN/A if (squashed_num < blockedLoadSeqNum) { 6846124SN/A isLoadBlocked = false; 6856124SN/A loadBlockedHandled = false; 6866124SN/A blockedLoadSeqNum = 0; 6876124SN/A } 6883318SN/A } 6893116SN/A 6904870SN/A int store_idx = storeTail; 6913116SN/A decrStIdx(store_idx); 6923116SN/A 6933116SN/A while (stores != 0 && 6944263SN/A storeQueue[store_idx].inst->seqNum > squashed_num) { 6954263SN/A // Instructions marked as can WB are already committed. 6964263SN/A if (storeQueue[store_idx].canWB) { 6974283SN/A break; 6984283SN/A } 6994263SN/A 7004987SN/A DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, " 7014263SN/A "idx:%i [sn:%lli]\n", 7024263SN/A storeQueue[store_idx].inst->readPC(), 7034987SN/A store_idx, storeQueue[store_idx].inst->seqNum); 7045500SN/A 7057064SN/A // I don't think this can happen. It should have been cleared 7066124SN/A // by the stalling load. 7077823SN/A if (isStalled() && 7087823SN/A storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { 7095500SN/A panic("Is stalled should have been cleared by stalling load!\n"); 7106124SN/A stalled = false; 7117823SN/A stallingStoreIsn = 0; 7124987SN/A } 7135606SN/A 7144987SN/A // Clear the smart pointer to make sure it is decremented. 7154987SN/A storeQueue[store_idx].inst->squashed = true; 7164263SN/A storeQueue[store_idx].inst = NULL; 7176124SN/A storeQueue[store_idx].canWB = 0; 7186124SN/A 7196124SN/A storeQueue[store_idx].req = NULL; 7205500SN/A --stores; 7216124SN/A 7226124SN/A // Inefficient! 7236124SN/A storeTail = store_idx; 7244263SN/A 7254263SN/A decrStIdx(store_idx); 7264263SN/A } 7274263SN/A} 7284987SN/A 7294987SN/Atemplate <class Impl> 7304987SN/Avoid 7314987SN/ALSQUnit<Impl>::storePostSend(Packet *pkt) 7324987SN/A{ 7334987SN/A if (isStalled() && 7344987SN/A storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) { 7354263SN/A DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] " 7364263SN/A "load idx:%i\n", 7374987SN/A stallingStoreIsn, stallingLoadIdx); 7385533SN/A stalled = false; 7395533SN/A stallingStoreIsn = 0; 7404987SN/A iewStage->replayMemInst(loadQueue[stallingLoadIdx]); 7414987SN/A } 7424987SN/A 7434987SN/A if (!storeQueue[storeWBIdx].inst->isStoreConditional()) { 7444987SN/A // The store is basically completed at this time. This 7454987SN/A // only works so long as the checker doesn't try to 7464987SN/A // verify the value in memory for stores. 7474987SN/A storeQueue[storeWBIdx].inst->setCompleted(); 7484987SN/A if (cpu->checker) { 7495606SN/A cpu->checker->tick(storeQueue[storeWBIdx].inst); 7504987SN/A } 7514987SN/A } 7524263SN/A 7534263SN/A if (pkt->result != Packet::Success) { 7545606SN/A DPRINTF(LSQUnit,"D-Cache Write Miss on idx:%i!\n", 7554263SN/A storeWBIdx); 7564263SN/A 7574263SN/A DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n", 7585606SN/A storeQueue[storeWBIdx].inst->seqNum); 7594263SN/A 7604263SN/A //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum); 7614263SN/A 7625606SN/A //DPRINTF(LSQUnit, "Added MSHR. count = %i\n",mshrSeqNums.size()); 7634263SN/A 7644263SN/A // @todo: Increment stat here. 7654263SN/A } else { 7665606SN/A DPRINTF(LSQUnit,"D-Cache: Write Hit on idx:%i !\n", 7674263SN/A storeWBIdx); 7684263SN/A 7694263SN/A DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n", 7704263SN/A storeQueue[storeWBIdx].inst->seqNum); 7714263SN/A } 7724987SN/A 7734263SN/A incrStIdx(storeWBIdx); 7744987SN/A} 7757823SN/A 7764263SN/Atemplate <class Impl> 7774263SN/Avoid 7784263SN/ALSQUnit<Impl>::writeback(DynInstPtr &inst, PacketPtr pkt) 7794263SN/A{ 7804263SN/A iewStage->wakeCPU(); 7814283SN/A 7824283SN/A // Squashed instructions do not need to complete their access. 7836124SN/A if (inst->isSquashed()) { 7846124SN/A assert(!inst->isStore()); 7854283SN/A return; 7864283SN/A } 7874283SN/A 7884263SN/A if (!inst->isExecuted()) { 7894263SN/A inst->setExecuted(); 7904263SN/A 7914263SN/A // Complete access to copy data to proper place. 7924263SN/A inst->completeAcc(pkt); 7934987SN/A } 7944987SN/A 7954263SN/A // Need to insert instruction into queue to commit 7964283SN/A iewStage->instToCommit(inst); 7974987SN/A 7984283SN/A iewStage->activityThisCycle(); 7996124SN/A} 8004283SN/A 8014283SN/Atemplate <class Impl> 8024283SN/Avoid 8036124SN/ALSQUnit<Impl>::completeStore(int store_idx) 8046124SN/A{ 8054263SN/A assert(storeQueue[store_idx].inst); 8064283SN/A storeQueue[store_idx].completed = true; 8074283SN/A --storesToWB; 8084283SN/A // A bit conservative because a store completion may not free up entries, 8094283SN/A // but hopefully avoids two store completions in one cycle from making 8106124SN/A // the CPU tick twice. 8116124SN/A cpu->activityThisCycle(); 8124987SN/A 8137823SN/A if (store_idx == storeHead) { 8146124SN/A do { 8156124SN/A incrStIdx(storeHead); 8164987SN/A 8174283SN/A --stores; 8184283SN/A } while (storeQueue[storeHead].completed && 8196124SN/A storeHead != storeTail); 8204283SN/A 8214283SN/A iewStage->updateLSQNextCycle = true; 8226124SN/A } 8236124SN/A 8246124SN/A DPRINTF(LSQUnit, "Completing store [sn:%lli], idx:%i, store head " 8256124SN/A "idx:%i\n", 8266124SN/A storeQueue[store_idx].inst->seqNum, store_idx, storeHead); 82710420SN/A 82812087Sspwilson2@wisc.edu if (isStalled() && 82912087Sspwilson2@wisc.edu storeQueue[store_idx].inst->seqNum == stallingStoreIsn) { 83012087Sspwilson2@wisc.edu DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] " 83112087Sspwilson2@wisc.edu "load idx:%i\n", 8326124SN/A stallingStoreIsn, stallingLoadIdx); 8336124SN/A stalled = false; 8346124SN/A stallingStoreIsn = 0; 8356124SN/A iewStage->replayMemInst(loadQueue[stallingLoadIdx]); 8366124SN/A } 8376124SN/A 8386124SN/A storeQueue[store_idx].inst->setCompleted(); 8396124SN/A 8406124SN/A // Tell the checker we've completed this instruction. Some stores 8419086SN/A // may get reported twice to the checker, but the checker can 8429086SN/A // handle that case. 8436124SN/A if (cpu->checker) { 8446124SN/A cpu->checker->tick(storeQueue[store_idx].inst); 8456124SN/A } 8466124SN/A} 8476124SN/A 8486124SN/Atemplate <class Impl> 8496124SN/Avoid 8506124SN/ALSQUnit<Impl>::recvRetry() 8516124SN/A{ 8526124SN/A if (isStoreBlocked) { 8534263SN/A assert(retryPkt != NULL); 8544263SN/A 8556124SN/A if (dcachePort->sendTiming(retryPkt)) { 8566124SN/A storePostSend(retryPkt); 8576124SN/A retryPkt = NULL; 8586124SN/A isStoreBlocked = false; 8596124SN/A } else { 8606124SN/A // Still blocked! 8616124SN/A } 8626124SN/A } else if (isLoadBlocked) { 8636124SN/A DPRINTF(LSQUnit, "Loads squash themselves and all younger insts, " 8646124SN/A "no need to resend packet.\n"); 8656124SN/A } else { 8666124SN/A DPRINTF(LSQUnit, "Retry received but LSQ is no longer blocked.\n"); 8676124SN/A } 8686124SN/A} 8696124SN/A 8706124SN/Atemplate <class Impl> 8716124SN/Ainline void 8726124SN/ALSQUnit<Impl>::incrStIdx(int &store_idx) 8736124SN/A{ 8746124SN/A if (++store_idx >= SQEntries) 8756124SN/A store_idx = 0; 87611320Ssteve.reinhardt@amd.com} 8776124SN/A 8786124SN/Atemplate <class Impl> 8796124SN/Ainline void 8806124SN/ALSQUnit<Impl>::decrStIdx(int &store_idx) 8816124SN/A{ 8826124SN/A if (--store_idx < 0) 8836124SN/A store_idx += SQEntries; 8846124SN/A} 8856124SN/A 8866124SN/Atemplate <class Impl> 8876124SN/Ainline void 8886124SN/ALSQUnit<Impl>::incrLdIdx(int &load_idx) 8896124SN/A{ 8906124SN/A if (++load_idx >= LQEntries) 8916124SN/A load_idx = 0; 8926124SN/A} 8936124SN/A 8946124SN/Atemplate <class Impl> 8956124SN/Ainline void 8966124SN/ALSQUnit<Impl>::decrLdIdx(int &load_idx) 8976124SN/A{ 8986124SN/A if (--load_idx < 0) 8996124SN/A load_idx += LQEntries; 9006124SN/A} 9016124SN/A 9026124SN/Atemplate <class Impl> 9036124SN/Avoid 90411320Ssteve.reinhardt@amd.comLSQUnit<Impl>::dumpInsts() 9057823SN/A{ 9066124SN/A cprintf("Load store queue: Dumping instructions.\n"); 9076124SN/A cprintf("Load queue size: %i\n", loads); 90811320Ssteve.reinhardt@amd.com cprintf("Load queue: "); 9096124SN/A 9106124SN/A int load_idx = loadHead; 9116124SN/A 9126124SN/A while (load_idx != loadTail && loadQueue[load_idx]) { 9136124SN/A cprintf("%#x ", loadQueue[load_idx]->readPC()); 91410913SN/A 9157823SN/A incrLdIdx(load_idx); 9166124SN/A } 9176124SN/A 9186124SN/A cprintf("Store queue size: %i\n", stores); 9196124SN/A cprintf("Store queue: "); 92011320Ssteve.reinhardt@amd.com 9216124SN/A int store_idx = storeHead; 9226124SN/A 9236124SN/A while (store_idx != storeTail && storeQueue[store_idx].inst) { 9246124SN/A cprintf("%#x ", storeQueue[store_idx].inst->readPC()); 9256124SN/A 9266124SN/A incrStIdx(store_idx); 9276124SN/A } 9286124SN/A 92911320Ssteve.reinhardt@amd.com cprintf("\n"); 9306124SN/A} 9316124SN/A