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