lsq_unit_impl.hh revision 2329
19793Sakash.bagdia@arm.com/*
27586SAli.Saidi@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
37586SAli.Saidi@arm.com * All rights reserved.
47586SAli.Saidi@arm.com *
57586SAli.Saidi@arm.com * Redistribution and use in source and binary forms, with or without
67586SAli.Saidi@arm.com * modification, are permitted provided that the following conditions are
77586SAli.Saidi@arm.com * met: redistributions of source code must retain the above copyright
87586SAli.Saidi@arm.com * notice, this list of conditions and the following disclaimer;
97586SAli.Saidi@arm.com * redistributions in binary form must reproduce the above copyright
107586SAli.Saidi@arm.com * notice, this list of conditions and the following disclaimer in the
117586SAli.Saidi@arm.com * documentation and/or other materials provided with the distribution;
127586SAli.Saidi@arm.com * neither the name of the copyright holders nor the names of its
1310118Snilay@cs.wisc.edu * contributors may be used to endorse or promote products derived from
1410118Snilay@cs.wisc.edu * this software without specific prior written permission.
153970Sgblack@eecs.umich.edu *
163005Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
173005Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183005Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193005Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
203005Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
213005Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223005Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233005Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243005Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253005Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263005Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273005Sstever@eecs.umich.edu */
283005Sstever@eecs.umich.edu
293005Sstever@eecs.umich.edu#include "cpu/checker/cpu.hh"
303005Sstever@eecs.umich.edu#include "cpu/o3/lsq_unit.hh"
313005Sstever@eecs.umich.edu#include "base/str.hh"
323005Sstever@eecs.umich.edu
333005Sstever@eecs.umich.edutemplate <class Impl>
343005Sstever@eecs.umich.eduLSQUnit<Impl>::StoreCompletionEvent::StoreCompletionEvent(int store_idx,
353005Sstever@eecs.umich.edu                                                          Event *wb_event,
363005Sstever@eecs.umich.edu                                                          LSQUnit<Impl> *lsq_ptr)
373005Sstever@eecs.umich.edu    : Event(&mainEventQueue),
383005Sstever@eecs.umich.edu      wbEvent(wb_event),
393005Sstever@eecs.umich.edu      storeIdx(store_idx),
403005Sstever@eecs.umich.edu      lsqPtr(lsq_ptr)
413005Sstever@eecs.umich.edu{
4210118Snilay@cs.wisc.edu    this->setFlags(Event::AutoDelete);
433005Sstever@eecs.umich.edu}
446654Snate@binkert.org
456654Snate@binkert.orgtemplate <class Impl>
462889SN/Avoid
472710SN/ALSQUnit<Impl>::StoreCompletionEvent::process()
486654Snate@binkert.org{
496654Snate@binkert.org    DPRINTF(LSQ, "Cache miss complete for store idx:%i\n", storeIdx);
506654Snate@binkert.org    DPRINTF(Activity, "Activity: st writeback event idx:%i\n", storeIdx);
515457Ssaidi@eecs.umich.edu
526654Snate@binkert.org    //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum);
5310118Snilay@cs.wisc.edu
5410118Snilay@cs.wisc.edu    if (lsqPtr->isSwitchedOut())
5510118Snilay@cs.wisc.edu        return;
566654Snate@binkert.org
572934SN/A    lsqPtr->cpu->wakeCPU();
582549SN/A    if (wbEvent)
592995SN/A        wbEvent->process();
603395Shsul@eecs.umich.edu    lsqPtr->completeStore(storeIdx);
616981SLisa.Hsu@amd.com}
629836Sandreas.hansson@arm.com
633448Shsul@eecs.umich.edutemplate <class Impl>
648920Snilay@cs.wisc.educonst char *
653444Sktlim@umich.eduLSQUnit<Impl>::StoreCompletionEvent::description()
663304Sstever@eecs.umich.edu{
679653SAndreas.Sandberg@ARM.com    return "LSQ store completion event";
689653SAndreas.Sandberg@ARM.com}
699653SAndreas.Sandberg@ARM.com
709653SAndreas.Sandberg@ARM.comtemplate <class Impl>
719653SAndreas.Sandberg@ARM.comLSQUnit<Impl>::LSQUnit()
729653SAndreas.Sandberg@ARM.com    : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false),
739653SAndreas.Sandberg@ARM.com      loadBlockedHandled(false)
7410594Sgabeblack@google.com{
7510594Sgabeblack@google.com}
7610594Sgabeblack@google.com
7710594Sgabeblack@google.comtemplate<class Impl>
7810594Sgabeblack@google.comvoid
7910594Sgabeblack@google.comLSQUnit<Impl>::init(Params *params, unsigned maxLQEntries,
8010594Sgabeblack@google.com                    unsigned maxSQEntries, unsigned id)
8110594Sgabeblack@google.com
8210594Sgabeblack@google.com{
8310594Sgabeblack@google.com    DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id);
8410594Sgabeblack@google.com
8510119Snilay@cs.wisc.edu    switchedOut = false;
8610594Sgabeblack@google.com
8710119Snilay@cs.wisc.edu    lsqID = id;
8810594Sgabeblack@google.com
8910594Sgabeblack@google.com    // Add 1 for the sentinel entry (they are circular queues).
9010119Snilay@cs.wisc.edu    LQEntries = maxLQEntries + 1;
9110594Sgabeblack@google.com    SQEntries = maxSQEntries + 1;
9210119Snilay@cs.wisc.edu
9310594Sgabeblack@google.com    loadQueue.resize(LQEntries);
9410119Snilay@cs.wisc.edu    storeQueue.resize(SQEntries);
9510119Snilay@cs.wisc.edu
9610594Sgabeblack@google.com    loadHead = loadTail = 0;
9710119Snilay@cs.wisc.edu
9810512SAli.Saidi@ARM.com    storeHead = storeWBIdx = storeTail = 0;
9910512SAli.Saidi@ARM.com
10010594Sgabeblack@google.com    usedPorts = 0;
10110780SCurtis.Dunham@arm.com    cachePorts = params->cachePorts;
10210780SCurtis.Dunham@arm.com
10310119Snilay@cs.wisc.edu    dcacheInterface = params->dcacheInterface;
10410119Snilay@cs.wisc.edu
10510119Snilay@cs.wisc.edu    memDepViolator = NULL;
10610119Snilay@cs.wisc.edu
1072566SN/A    blockedLoadSeqNum = 0;
10810119Snilay@cs.wisc.edu}
10910119Snilay@cs.wisc.edu
1109665Sandreas.hansson@arm.comtemplate<class Impl>
11110119Snilay@cs.wisc.edustd::string
11210119Snilay@cs.wisc.eduLSQUnit<Impl>::name() const
11310119Snilay@cs.wisc.edu{
11410119Snilay@cs.wisc.edu    if (Impl::MaxThreads == 1) {
11510119Snilay@cs.wisc.edu        return iewStage->name() + ".lsq";
11610119Snilay@cs.wisc.edu    } else {
11710119Snilay@cs.wisc.edu        return iewStage->name() + ".lsq.thread." + to_string(lsqID);
11810119Snilay@cs.wisc.edu    }
11910119Snilay@cs.wisc.edu}
12010119Snilay@cs.wisc.edu
12110119Snilay@cs.wisc.edutemplate<class Impl>
12210119Snilay@cs.wisc.eduvoid
12310119Snilay@cs.wisc.eduLSQUnit<Impl>::clearLQ()
12410119Snilay@cs.wisc.edu{
12510119Snilay@cs.wisc.edu    loadQueue.clear();
12610119Snilay@cs.wisc.edu}
12710119Snilay@cs.wisc.edu
12810119Snilay@cs.wisc.edutemplate<class Impl>
12910119Snilay@cs.wisc.eduvoid
13010119Snilay@cs.wisc.eduLSQUnit<Impl>::clearSQ()
13110119Snilay@cs.wisc.edu{
13210119Snilay@cs.wisc.edu    storeQueue.clear();
13310119Snilay@cs.wisc.edu}
13410119Snilay@cs.wisc.edu
13510119Snilay@cs.wisc.edu#if 0
13610119Snilay@cs.wisc.edutemplate<class Impl>
13710119Snilay@cs.wisc.eduvoid
13810119Snilay@cs.wisc.eduLSQUnit<Impl>::setPageTable(PageTable *pt_ptr)
13910119Snilay@cs.wisc.edu{
14010119Snilay@cs.wisc.edu    DPRINTF(LSQUnit, "Setting the page table pointer.\n");
14110119Snilay@cs.wisc.edu    pTable = pt_ptr;
14210119Snilay@cs.wisc.edu}
14310119Snilay@cs.wisc.edu#endif
14410119Snilay@cs.wisc.edu
14510119Snilay@cs.wisc.edutemplate<class Impl>
14610119Snilay@cs.wisc.eduvoid
14710119Snilay@cs.wisc.eduLSQUnit<Impl>::switchOut()
14810119Snilay@cs.wisc.edu{
14910119Snilay@cs.wisc.edu    switchedOut = true;
15010119Snilay@cs.wisc.edu    for (int i = 0; i < loadQueue.size(); ++i)
15110119Snilay@cs.wisc.edu        loadQueue[i] = NULL;
15210119Snilay@cs.wisc.edu
15310519Snilay@cs.wisc.edu    assert(storesToWB == 0);
15410519Snilay@cs.wisc.edu
15510119Snilay@cs.wisc.edu    while (storesToWB > 0 &&
15610119Snilay@cs.wisc.edu           storeWBIdx != storeTail &&
15710119Snilay@cs.wisc.edu           storeQueue[storeWBIdx].inst &&
15810119Snilay@cs.wisc.edu           storeQueue[storeWBIdx].canWB) {
15910119Snilay@cs.wisc.edu
16010547Snilay@cs.wisc.edu        if (storeQueue[storeWBIdx].size == 0 ||
16110547Snilay@cs.wisc.edu            storeQueue[storeWBIdx].inst->isDataPrefetch() ||
16210547Snilay@cs.wisc.edu            storeQueue[storeWBIdx].committed ||
16310547Snilay@cs.wisc.edu            storeQueue[storeWBIdx].req->flags & LOCKED) {
16410119Snilay@cs.wisc.edu            incrStIdx(storeWBIdx);
16510119Snilay@cs.wisc.edu
16610119Snilay@cs.wisc.edu            continue;
16710119Snilay@cs.wisc.edu        }
16810119Snilay@cs.wisc.edu
16910119Snilay@cs.wisc.edu        assert(storeQueue[storeWBIdx].req);
17010119Snilay@cs.wisc.edu        assert(!storeQueue[storeWBIdx].committed);
17110119Snilay@cs.wisc.edu
17210120Snilay@cs.wisc.edu        MemReqPtr req = storeQueue[storeWBIdx].req;
17310120Snilay@cs.wisc.edu        storeQueue[storeWBIdx].committed = true;
17410119Snilay@cs.wisc.edu
17510119Snilay@cs.wisc.edu        req->cmd = Write;
17610120Snilay@cs.wisc.edu        req->completionEvent = NULL;
17710120Snilay@cs.wisc.edu        req->time = curTick;
17810119Snilay@cs.wisc.edu        assert(!req->data);
17911150Smitch.hayenga@arm.com        req->data = new uint8_t[64];
18011150Smitch.hayenga@arm.com        memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size);
18111150Smitch.hayenga@arm.com
18210119Snilay@cs.wisc.edu        DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
1832995SN/A                "to Addr:%#x, data:%#x [sn:%lli]\n",
18410119Snilay@cs.wisc.edu                storeWBIdx,storeQueue[storeWBIdx].inst->readPC(),
18510119Snilay@cs.wisc.edu                req->paddr, *(req->data),
18610119Snilay@cs.wisc.edu                storeQueue[storeWBIdx].inst->seqNum);
18710119Snilay@cs.wisc.edu
18810119Snilay@cs.wisc.edu        switch(storeQueue[storeWBIdx].size) {
18910780SCurtis.Dunham@arm.com          case 1:
19010119Snilay@cs.wisc.edu            cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data);
19110119Snilay@cs.wisc.edu            break;
19210119Snilay@cs.wisc.edu          case 2:
1933304Sstever@eecs.umich.edu            cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data);
19410119Snilay@cs.wisc.edu            break;
19510119Snilay@cs.wisc.edu          case 4:
19610119Snilay@cs.wisc.edu            cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data);
19710119Snilay@cs.wisc.edu            break;
19810119Snilay@cs.wisc.edu          case 8:
19910119Snilay@cs.wisc.edu            cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data);
2006135Sgblack@eecs.umich.edu            break;
20110608Sdam.sunwoo@arm.com          default:
20210608Sdam.sunwoo@arm.com            panic("Unexpected store size!\n");
20310608Sdam.sunwoo@arm.com        }
20410608Sdam.sunwoo@arm.com        incrStIdx(storeWBIdx);
20510608Sdam.sunwoo@arm.com    }
20610608Sdam.sunwoo@arm.com}
20710608Sdam.sunwoo@arm.com
20810119Snilay@cs.wisc.edutemplate<class Impl>
20910119Snilay@cs.wisc.eduvoid
21010119Snilay@cs.wisc.eduLSQUnit<Impl>::takeOverFrom()
21110608Sdam.sunwoo@arm.com{
21210608Sdam.sunwoo@arm.com    switchedOut = false;
21310119Snilay@cs.wisc.edu    loads = stores = storesToWB = 0;
21410119Snilay@cs.wisc.edu
21510119Snilay@cs.wisc.edu    loadHead = loadTail = 0;
2163819Shsul@eecs.umich.edu
21711251Sradhika.jagtap@ARM.com    storeHead = storeWBIdx = storeTail = 0;
21811251Sradhika.jagtap@ARM.com
21911251Sradhika.jagtap@ARM.com    usedPorts = 0;
22011251Sradhika.jagtap@ARM.com
22111251Sradhika.jagtap@ARM.com    memDepViolator = NULL;
22211251Sradhika.jagtap@ARM.com
22311251Sradhika.jagtap@ARM.com    blockedLoadSeqNum = 0;
22411251Sradhika.jagtap@ARM.com
22511251Sradhika.jagtap@ARM.com    stalled = false;
22611251Sradhika.jagtap@ARM.com    isLoadBlocked = false;
22711251Sradhika.jagtap@ARM.com    loadBlockedHandled = false;
22810119Snilay@cs.wisc.edu}
22911183Serfan.azarkhish@unibo.it
23010119Snilay@cs.wisc.edutemplate<class Impl>
23110118Snilay@cs.wisc.eduvoid
23210119Snilay@cs.wisc.eduLSQUnit<Impl>::resizeLQ(unsigned size)
2339827Sakash.bagdia@arm.com{
23410119Snilay@cs.wisc.edu    unsigned size_plus_sentinel = size + 1;
23510119Snilay@cs.wisc.edu    assert(size_plus_sentinel >= LQEntries);
23610119Snilay@cs.wisc.edu
23710119Snilay@cs.wisc.edu    if (size_plus_sentinel > LQEntries) {
23810119Snilay@cs.wisc.edu        while (size_plus_sentinel > loadQueue.size()) {
23910119Snilay@cs.wisc.edu            DynInstPtr dummy;
2409827Sakash.bagdia@arm.com            loadQueue.push_back(dummy);
24110594Sgabeblack@google.com            LQEntries++;
2426654Snate@binkert.org        }
24310594Sgabeblack@google.com    } else {
2446654Snate@binkert.org        LQEntries = size_plus_sentinel;
24510594Sgabeblack@google.com    }
2466654Snate@binkert.org
24710594Sgabeblack@google.com}
2486654Snate@binkert.org
24910594Sgabeblack@google.comtemplate<class Impl>
25010594Sgabeblack@google.comvoid
2517586SAli.Saidi@arm.comLSQUnit<Impl>::resizeSQ(unsigned size)
25210635Satgutier@umich.edu{
25310635Satgutier@umich.edu    unsigned size_plus_sentinel = size + 1;
2548661SAli.Saidi@ARM.com    if (size_plus_sentinel > SQEntries) {
2559827Sakash.bagdia@arm.com        while (size_plus_sentinel > storeQueue.size()) {
2569827Sakash.bagdia@arm.com            SQEntry dummy;
2579827Sakash.bagdia@arm.com            storeQueue.push_back(dummy);
2589793Sakash.bagdia@arm.com            SQEntries++;
25910119Snilay@cs.wisc.edu        }
26010119Snilay@cs.wisc.edu    } else {
2619790Sakash.bagdia@arm.com        SQEntries = size_plus_sentinel;
2629827Sakash.bagdia@arm.com    }
2639827Sakash.bagdia@arm.com}
2649827Sakash.bagdia@arm.com
2659793Sakash.bagdia@arm.comtemplate <class Impl>
2669827Sakash.bagdia@arm.comvoid
2679827Sakash.bagdia@arm.comLSQUnit<Impl>::insert(DynInstPtr &inst)
2689827Sakash.bagdia@arm.com{
2699793Sakash.bagdia@arm.com    assert(inst->isMemRef());
2709793Sakash.bagdia@arm.com
2719793Sakash.bagdia@arm.com    assert(inst->isLoad() || inst->isStore());
2729384SAndreas.Sandberg@arm.com
2738863Snilay@cs.wisc.edu    if (inst->isLoad()) {
2747876Sgblack@eecs.umich.edu        insertLoad(inst);
2754968Sacolyte@umich.edu    } else {
2768926Sandreas.hansson@arm.com        insertStore(inst);
2774837Ssaidi@eecs.umich.edu    }
2784837Ssaidi@eecs.umich.edu
2799408Sandreas.hansson@arm.com    inst->setInLSQ();
2809653SAndreas.Sandberg@ARM.com}
2819653SAndreas.Sandberg@ARM.com
2829653SAndreas.Sandberg@ARM.comtemplate <class Impl>
2839164Sandreas.hansson@arm.comvoid
2849408Sandreas.hansson@arm.comLSQUnit<Impl>::insertLoad(DynInstPtr &load_inst)
2858845Sandreas.hansson@arm.com{
2868845Sandreas.hansson@arm.com    assert((loadTail + 1) % LQEntries != loadHead);
2874837Ssaidi@eecs.umich.edu    assert(loads < LQEntries);
2889826Sandreas.hansson@arm.com
2899826Sandreas.hansson@arm.com    DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n",
2909835Sandreas.hansson@arm.com            load_inst->readPC(), loadTail, load_inst->seqNum);
2919826Sandreas.hansson@arm.com
2929826Sandreas.hansson@arm.com    load_inst->lqIdx = loadTail;
2939826Sandreas.hansson@arm.com
2949826Sandreas.hansson@arm.com    if (stores == 0) {
2958659SAli.Saidi@ARM.com        load_inst->sqIdx = -1;
29610119Snilay@cs.wisc.edu    } else {
29710119Snilay@cs.wisc.edu        load_inst->sqIdx = storeTail;
29810119Snilay@cs.wisc.edu    }
29910119Snilay@cs.wisc.edu
30010119Snilay@cs.wisc.edu    loadQueue[loadTail] = load_inst;
30110119Snilay@cs.wisc.edu
30210119Snilay@cs.wisc.edu    incrLdIdx(loadTail);
30310119Snilay@cs.wisc.edu
30410119Snilay@cs.wisc.edu    ++loads;
30510119Snilay@cs.wisc.edu}
30610119Snilay@cs.wisc.edu
30710119Snilay@cs.wisc.edutemplate <class Impl>
30810119Snilay@cs.wisc.eduvoid
30910119Snilay@cs.wisc.eduLSQUnit<Impl>::insertStore(DynInstPtr &store_inst)
31010119Snilay@cs.wisc.edu{
31110119Snilay@cs.wisc.edu    // Make sure it is not full before inserting an instruction.
31210119Snilay@cs.wisc.edu    assert((storeTail + 1) % SQEntries != storeHead);
31310119Snilay@cs.wisc.edu    assert(stores < SQEntries);
31410119Snilay@cs.wisc.edu
31510119Snilay@cs.wisc.edu    DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n",
31610119Snilay@cs.wisc.edu            store_inst->readPC(), storeTail, store_inst->seqNum);
31710119Snilay@cs.wisc.edu
31810119Snilay@cs.wisc.edu    store_inst->sqIdx = storeTail;
31910119Snilay@cs.wisc.edu    store_inst->lqIdx = loadTail;
32010119Snilay@cs.wisc.edu
32110119Snilay@cs.wisc.edu    storeQueue[storeTail] = SQEntry(store_inst);
32210119Snilay@cs.wisc.edu
32310119Snilay@cs.wisc.edu    incrStIdx(storeTail);
32410119Snilay@cs.wisc.edu
32510119Snilay@cs.wisc.edu    ++stores;
32610119Snilay@cs.wisc.edu}
32710119Snilay@cs.wisc.edu
32810119Snilay@cs.wisc.edutemplate <class Impl>
32910697SCurtis.Dunham@arm.comtypename Impl::DynInstPtr
33010747SChris.Emmons@arm.comLSQUnit<Impl>::getMemDepViolator()
33110697SCurtis.Dunham@arm.com{
33210747SChris.Emmons@arm.com    DynInstPtr temp = memDepViolator;
33310119Snilay@cs.wisc.edu
33410697SCurtis.Dunham@arm.com    memDepViolator = NULL;
33510747SChris.Emmons@arm.com
33610119Snilay@cs.wisc.edu    return temp;
33710119Snilay@cs.wisc.edu}
33810119Snilay@cs.wisc.edu
33910119Snilay@cs.wisc.edutemplate <class Impl>
34010119Snilay@cs.wisc.eduunsigned
34110119Snilay@cs.wisc.eduLSQUnit<Impl>::numFreeEntries()
3428801Sgblack@eecs.umich.edu{
3433005Sstever@eecs.umich.edu    unsigned free_lq_entries = LQEntries - loads;
3448801Sgblack@eecs.umich.edu    unsigned free_sq_entries = SQEntries - stores;
3453005Sstever@eecs.umich.edu
3463005Sstever@eecs.umich.edu    // Both the LQ and SQ entries have an extra dummy entry to differentiate
3473005Sstever@eecs.umich.edu    // empty/full conditions.  Subtract 1 from the free entries.
3482566SN/A    if (free_lq_entries < free_sq_entries) {
3497861Sgblack@eecs.umich.edu        return free_lq_entries - 1;
3507861Sgblack@eecs.umich.edu    } else {
3517861Sgblack@eecs.umich.edu        return free_sq_entries - 1;
3528635Schris.emmons@arm.com    }
3538635Schris.emmons@arm.com}
3548635Schris.emmons@arm.com
3559061Snilay@cs.wisc.edutemplate <class Impl>
3563481Shsul@eecs.umich.eduint
357LSQUnit<Impl>::numLoadsReady()
358{
359    int load_idx = loadHead;
360    int retval = 0;
361
362    while (load_idx != loadTail) {
363        assert(loadQueue[load_idx]);
364
365        if (loadQueue[load_idx]->readyToIssue()) {
366            ++retval;
367        }
368    }
369
370    return retval;
371}
372
373template <class Impl>
374Fault
375LSQUnit<Impl>::executeLoad(DynInstPtr &inst)
376{
377    // Execute a specific load.
378    Fault load_fault = NoFault;
379
380    DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n",
381            inst->readPC(),inst->seqNum);
382
383//    load_fault = inst->initiateAcc();
384    load_fault = inst->execute();
385
386    // If the instruction faulted, then we need to send it along to commit
387    // without the instruction completing.
388    if (load_fault != NoFault) {
389        // Send this instruction to commit, also make sure iew stage
390        // realizes there is activity.
391        iewStage->instToCommit(inst);
392        iewStage->activityThisCycle();
393    }
394
395    return load_fault;
396}
397
398template <class Impl>
399Fault
400LSQUnit<Impl>::executeStore(DynInstPtr &store_inst)
401{
402    using namespace TheISA;
403    // Make sure that a store exists.
404    assert(stores != 0);
405
406    int store_idx = store_inst->sqIdx;
407
408    DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n",
409            store_inst->readPC(), store_inst->seqNum);
410
411    // Check the recently completed loads to see if any match this store's
412    // address.  If so, then we have a memory ordering violation.
413    int load_idx = store_inst->lqIdx;
414
415    Fault store_fault = store_inst->initiateAcc();
416//    Fault store_fault = store_inst->execute();
417
418    if (storeQueue[store_idx].size == 0) {
419        DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n",
420                store_inst->readPC(),store_inst->seqNum);
421
422        return store_fault;
423    }
424
425    assert(store_fault == NoFault);
426
427    if (store_inst->isNonSpeculative()) {
428        // Nonspeculative accesses (namely store conditionals)
429        // need to set themselves as able to writeback if we
430        // haven't had a fault by here.
431        storeQueue[store_idx].canWB = true;
432
433        ++storesToWB;
434    }
435
436    if (!memDepViolator) {
437        while (load_idx != loadTail) {
438            // Really only need to check loads that have actually executed
439            // It's safe to check all loads because effAddr is set to
440            // InvalAddr when the dyn inst is created.
441
442            // @todo: For now this is extra conservative, detecting a
443            // violation if the addresses match assuming all accesses
444            // are quad word accesses.
445
446            // @todo: Fix this, magic number being used here
447            if ((loadQueue[load_idx]->effAddr >> 8) ==
448                (store_inst->effAddr >> 8)) {
449                // A load incorrectly passed this store.  Squash and refetch.
450                // For now return a fault to show that it was unsuccessful.
451                memDepViolator = loadQueue[load_idx];
452
453                return genMachineCheckFault();
454            }
455
456            incrLdIdx(load_idx);
457        }
458
459        // If we've reached this point, there was no violation.
460        memDepViolator = NULL;
461    }
462
463    return store_fault;
464}
465
466template <class Impl>
467void
468LSQUnit<Impl>::commitLoad()
469{
470    assert(loadQueue[loadHead]);
471
472    DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n",
473            loadQueue[loadHead]->readPC());
474
475
476    loadQueue[loadHead] = NULL;
477
478    incrLdIdx(loadHead);
479
480    --loads;
481}
482
483template <class Impl>
484void
485LSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst)
486{
487    assert(loads == 0 || loadQueue[loadHead]);
488
489    while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) {
490        commitLoad();
491    }
492}
493
494template <class Impl>
495void
496LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst)
497{
498    assert(stores == 0 || storeQueue[storeHead].inst);
499
500    int store_idx = storeHead;
501
502    while (store_idx != storeTail) {
503        assert(storeQueue[store_idx].inst);
504        // Mark any stores that are now committed and have not yet
505        // been marked as able to write back.
506        if (!storeQueue[store_idx].canWB) {
507            if (storeQueue[store_idx].inst->seqNum > youngest_inst) {
508                break;
509            }
510            DPRINTF(LSQUnit, "Marking store as able to write back, PC "
511                    "%#x [sn:%lli]\n",
512                    storeQueue[store_idx].inst->readPC(),
513                    storeQueue[store_idx].inst->seqNum);
514
515            storeQueue[store_idx].canWB = true;
516
517            ++storesToWB;
518        }
519
520        incrStIdx(store_idx);
521    }
522}
523
524template <class Impl>
525void
526LSQUnit<Impl>::writebackStores()
527{
528    while (storesToWB > 0 &&
529           storeWBIdx != storeTail &&
530           storeQueue[storeWBIdx].inst &&
531           storeQueue[storeWBIdx].canWB &&
532           usedPorts < cachePorts) {
533
534        // Store didn't write any data so no need to write it back to
535        // memory.
536        if (storeQueue[storeWBIdx].size == 0) {
537            completeStore(storeWBIdx);
538
539            incrStIdx(storeWBIdx);
540
541            continue;
542        }
543
544        if (dcacheInterface && dcacheInterface->isBlocked()) {
545            DPRINTF(LSQUnit, "Unable to write back any more stores, cache"
546                    " is blocked!\n");
547            break;
548        }
549
550        ++usedPorts;
551
552        if (storeQueue[storeWBIdx].inst->isDataPrefetch()) {
553            incrStIdx(storeWBIdx);
554
555            continue;
556        }
557
558        assert(storeQueue[storeWBIdx].req);
559        assert(!storeQueue[storeWBIdx].committed);
560
561        MemReqPtr req = storeQueue[storeWBIdx].req;
562        storeQueue[storeWBIdx].committed = true;
563
564        req->cmd = Write;
565        req->completionEvent = NULL;
566        req->time = curTick;
567        assert(!req->data);
568        req->data = new uint8_t[64];
569        memcpy(req->data, (uint8_t *)&storeQueue[storeWBIdx].data, req->size);
570
571        DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
572                "to Addr:%#x, data:%#x [sn:%lli]\n",
573                storeWBIdx,storeQueue[storeWBIdx].inst->readPC(),
574                req->paddr, *(req->data),
575                storeQueue[storeWBIdx].inst->seqNum);
576
577        switch(storeQueue[storeWBIdx].size) {
578          case 1:
579            cpu->write(req, (uint8_t &)storeQueue[storeWBIdx].data);
580            break;
581          case 2:
582            cpu->write(req, (uint16_t &)storeQueue[storeWBIdx].data);
583            break;
584          case 4:
585            cpu->write(req, (uint32_t &)storeQueue[storeWBIdx].data);
586            break;
587          case 8:
588            cpu->write(req, (uint64_t &)storeQueue[storeWBIdx].data);
589            break;
590          default:
591            panic("Unexpected store size!\n");
592        }
593
594        // Stores other than store conditionals are completed at this
595        // time.  Mark them as completed and, if we have a checker,
596        // tell it that the instruction is completed.
597        // @todo: Figure out what time I can say stores are complete in
598        // the timing memory.
599        if (!(req->flags & LOCKED)) {
600            storeQueue[storeWBIdx].inst->setCompleted();
601            if (cpu->checker) {
602                cpu->checker->tick(storeQueue[storeWBIdx].inst);
603            }
604        }
605
606        if (dcacheInterface) {
607            assert(!req->completionEvent);
608            StoreCompletionEvent *store_event = new
609                StoreCompletionEvent(storeWBIdx, NULL, this);
610            req->completionEvent = store_event;
611
612            MemAccessResult result = dcacheInterface->access(req);
613
614            if (isStalled() &&
615                storeQueue[storeWBIdx].inst->seqNum == stallingStoreIsn) {
616                DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] "
617                        "load idx:%i\n",
618                        stallingStoreIsn, stallingLoadIdx);
619                stalled = false;
620                stallingStoreIsn = 0;
621                iewStage->replayMemInst(loadQueue[stallingLoadIdx]);
622            }
623
624            typename IEW::LdWritebackEvent *wb = NULL;
625            if (req->flags & LOCKED) {
626                // Stx_C should not generate a system port transaction
627                // if it misses in the cache, but that might be hard
628                // to accomplish without explicit cache support.
629                wb = new typename
630                    IEW::LdWritebackEvent(storeQueue[storeWBIdx].inst,
631                                              iewStage);
632                store_event->wbEvent = wb;
633            }
634
635            if (result != MA_HIT && dcacheInterface->doEvents()) {
636                DPRINTF(LSQUnit,"D-Cache Write Miss on idx:%i!\n",
637                        storeWBIdx);
638
639                DPRINTF(Activity, "Active st accessing mem miss [sn:%lli]\n",
640                        storeQueue[storeWBIdx].inst->seqNum);
641
642                //mshrSeqNums.push_back(storeQueue[storeWBIdx].inst->seqNum);
643
644                //DPRINTF(LSQUnit, "Added MSHR. count = %i\n",mshrSeqNums.size());
645
646                // @todo: Increment stat here.
647            } else {
648                DPRINTF(LSQUnit,"D-Cache: Write Hit on idx:%i !\n",
649                        storeWBIdx);
650
651                DPRINTF(Activity, "Active st accessing mem hit [sn:%lli]\n",
652                        storeQueue[storeWBIdx].inst->seqNum);
653            }
654
655            incrStIdx(storeWBIdx);
656        } else {
657            panic("Must HAVE DCACHE!!!!!\n");
658        }
659    }
660
661    // Not sure this should set it to 0.
662    usedPorts = 0;
663
664    assert(stores >= 0 && storesToWB >= 0);
665}
666
667/*template <class Impl>
668void
669LSQUnit<Impl>::removeMSHR(InstSeqNum seqNum)
670{
671    list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(),
672                                              mshrSeqNums.end(),
673                                              seqNum);
674
675    if (mshr_it != mshrSeqNums.end()) {
676        mshrSeqNums.erase(mshr_it);
677        DPRINTF(LSQUnit, "Removing MSHR. count = %i\n",mshrSeqNums.size());
678    }
679}*/
680
681template <class Impl>
682void
683LSQUnit<Impl>::squash(const InstSeqNum &squashed_num)
684{
685    DPRINTF(LSQUnit, "Squashing until [sn:%lli]!"
686            "(Loads:%i Stores:%i)\n", squashed_num, loads, stores);
687
688    int load_idx = loadTail;
689    decrLdIdx(load_idx);
690
691    while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) {
692        DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, "
693                "[sn:%lli]\n",
694                loadQueue[load_idx]->readPC(),
695                loadQueue[load_idx]->seqNum);
696
697        if (isStalled() && load_idx == stallingLoadIdx) {
698            stalled = false;
699            stallingStoreIsn = 0;
700            stallingLoadIdx = 0;
701        }
702
703        // Clear the smart pointer to make sure it is decremented.
704        loadQueue[load_idx]->squashed = true;
705        loadQueue[load_idx] = NULL;
706        --loads;
707
708        // Inefficient!
709        loadTail = load_idx;
710
711        decrLdIdx(load_idx);
712    }
713
714    if (isLoadBlocked) {
715        if (squashed_num < blockedLoadSeqNum) {
716            isLoadBlocked = false;
717            loadBlockedHandled = false;
718            blockedLoadSeqNum = 0;
719        }
720    }
721
722    int store_idx = storeTail;
723    decrStIdx(store_idx);
724
725    while (stores != 0 &&
726           storeQueue[store_idx].inst->seqNum > squashed_num) {
727        // Instructions marked as can WB are already committed.
728        if (storeQueue[store_idx].canWB) {
729            break;
730        }
731
732        DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, "
733                "idx:%i [sn:%lli]\n",
734                storeQueue[store_idx].inst->readPC(),
735                store_idx, storeQueue[store_idx].inst->seqNum);
736
737        // I don't think this can happen.  It should have been cleared
738        // by the stalling load.
739        if (isStalled() &&
740            storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
741            panic("Is stalled should have been cleared by stalling load!\n");
742            stalled = false;
743            stallingStoreIsn = 0;
744        }
745
746        // Clear the smart pointer to make sure it is decremented.
747        storeQueue[store_idx].inst->squashed = true;
748        storeQueue[store_idx].inst = NULL;
749        storeQueue[store_idx].canWB = 0;
750
751        if (storeQueue[store_idx].req) {
752            // There should not be a completion event if the store has
753            // not yet committed.
754            assert(!storeQueue[store_idx].req->completionEvent);
755        }
756
757        storeQueue[store_idx].req = NULL;
758        --stores;
759
760        // Inefficient!
761        storeTail = store_idx;
762
763        decrStIdx(store_idx);
764    }
765}
766
767template <class Impl>
768void
769LSQUnit<Impl>::completeStore(int store_idx)
770{
771    assert(storeQueue[store_idx].inst);
772    storeQueue[store_idx].completed = true;
773    --storesToWB;
774    // A bit conservative because a store completion may not free up entries,
775    // but hopefully avoids two store completions in one cycle from making
776    // the CPU tick twice.
777    cpu->activityThisCycle();
778
779    if (store_idx == storeHead) {
780        do {
781            incrStIdx(storeHead);
782
783            --stores;
784        } while (storeQueue[storeHead].completed &&
785                 storeHead != storeTail);
786
787        iewStage->updateLSQNextCycle = true;
788    }
789
790    DPRINTF(LSQUnit, "Completing store [sn:%lli], idx:%i, store head "
791            "idx:%i\n",
792            storeQueue[store_idx].inst->seqNum, store_idx, storeHead);
793
794    if (isStalled() &&
795        storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
796        DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] "
797                "load idx:%i\n",
798                stallingStoreIsn, stallingLoadIdx);
799        stalled = false;
800        stallingStoreIsn = 0;
801        iewStage->replayMemInst(loadQueue[stallingLoadIdx]);
802    }
803
804    storeQueue[store_idx].inst->setCompleted();
805
806    // Tell the checker we've completed this instruction.  Some stores
807    // may get reported twice to the checker, but the checker can
808    // handle that case.
809    if (cpu->checker) {
810        cpu->checker->tick(storeQueue[store_idx].inst);
811    }
812}
813
814template <class Impl>
815inline void
816LSQUnit<Impl>::incrStIdx(int &store_idx)
817{
818    if (++store_idx >= SQEntries)
819        store_idx = 0;
820}
821
822template <class Impl>
823inline void
824LSQUnit<Impl>::decrStIdx(int &store_idx)
825{
826    if (--store_idx < 0)
827        store_idx += SQEntries;
828}
829
830template <class Impl>
831inline void
832LSQUnit<Impl>::incrLdIdx(int &load_idx)
833{
834    if (++load_idx >= LQEntries)
835        load_idx = 0;
836}
837
838template <class Impl>
839inline void
840LSQUnit<Impl>::decrLdIdx(int &load_idx)
841{
842    if (--load_idx < 0)
843        load_idx += LQEntries;
844}
845
846template <class Impl>
847void
848LSQUnit<Impl>::dumpInsts()
849{
850    cprintf("Load store queue: Dumping instructions.\n");
851    cprintf("Load queue size: %i\n", loads);
852    cprintf("Load queue: ");
853
854    int load_idx = loadHead;
855
856    while (load_idx != loadTail && loadQueue[load_idx]) {
857        cprintf("%#x ", loadQueue[load_idx]->readPC());
858
859        incrLdIdx(load_idx);
860    }
861
862    cprintf("Store queue size: %i\n", stores);
863    cprintf("Store queue: ");
864
865    int store_idx = storeHead;
866
867    while (store_idx != storeTail && storeQueue[store_idx].inst) {
868        cprintf("%#x ", storeQueue[store_idx].inst->readPC());
869
870        incrStIdx(store_idx);
871    }
872
873    cprintf("\n");
874}
875