lsq_unit_impl.hh revision 2669:f2b336e89d2a
111308Santhony.gutierrez@amd.com/*
211308Santhony.gutierrez@amd.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
311308Santhony.gutierrez@amd.com * All rights reserved.
411308Santhony.gutierrez@amd.com *
511308Santhony.gutierrez@amd.com * Redistribution and use in source and binary forms, with or without
611308Santhony.gutierrez@amd.com * modification, are permitted provided that the following conditions are
711308Santhony.gutierrez@amd.com * met: redistributions of source code must retain the above copyright
811308Santhony.gutierrez@amd.com * notice, this list of conditions and the following disclaimer;
911308Santhony.gutierrez@amd.com * redistributions in binary form must reproduce the above copyright
1011308Santhony.gutierrez@amd.com * notice, this list of conditions and the following disclaimer in the
1111308Santhony.gutierrez@amd.com * documentation and/or other materials provided with the distribution;
1211308Santhony.gutierrez@amd.com * neither the name of the copyright holders nor the names of its
1311308Santhony.gutierrez@amd.com * contributors may be used to endorse or promote products derived from
1411308Santhony.gutierrez@amd.com * this software without specific prior written permission.
1511308Santhony.gutierrez@amd.com *
1611308Santhony.gutierrez@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1712697Santhony.gutierrez@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1812697Santhony.gutierrez@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1912697Santhony.gutierrez@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2011308Santhony.gutierrez@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2111308Santhony.gutierrez@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2211308Santhony.gutierrez@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2311308Santhony.gutierrez@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2411308Santhony.gutierrez@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2511308Santhony.gutierrez@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2611308Santhony.gutierrez@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2711308Santhony.gutierrez@amd.com */
2811308Santhony.gutierrez@amd.com
2911308Santhony.gutierrez@amd.com#include "cpu/checker/cpu.hh"
3011308Santhony.gutierrez@amd.com#include "cpu/o3/lsq_unit.hh"
3111308Santhony.gutierrez@amd.com#include "base/str.hh"
3211308Santhony.gutierrez@amd.com#include "mem/request.hh"
3312697Santhony.gutierrez@amd.com
3411308Santhony.gutierrez@amd.comtemplate<class Impl>
3511308Santhony.gutierrez@amd.comvoid
3611308Santhony.gutierrez@amd.comLSQUnit<Impl>::completeDataAccess(PacketPtr pkt)
3711308Santhony.gutierrez@amd.com{
3811308Santhony.gutierrez@amd.com/*
3911308Santhony.gutierrez@amd.com    DPRINTF(IEW, "Load writeback event [sn:%lli]\n", inst->seqNum);
4011308Santhony.gutierrez@amd.com    DPRINTF(Activity, "Activity: Ld Writeback event [sn:%lli]\n", inst->seqNum);
4111308Santhony.gutierrez@amd.com
4211308Santhony.gutierrez@amd.com    //iewStage->ldstQueue.removeMSHR(inst->threadNumber,inst->seqNum);
4311308Santhony.gutierrez@amd.com
4411308Santhony.gutierrez@amd.com    if (iewStage->isSwitchedOut()) {
4511308Santhony.gutierrez@amd.com        inst = NULL;
4611308Santhony.gutierrez@amd.com        return;
4711308Santhony.gutierrez@amd.com    } else if (inst->isSquashed()) {
4811308Santhony.gutierrez@amd.com        iewStage->wakeCPU();
4911308Santhony.gutierrez@amd.com        inst = NULL;
5012334Sgabeblack@google.com        return;
5111308Santhony.gutierrez@amd.com    }
5211308Santhony.gutierrez@amd.com
5311308Santhony.gutierrez@amd.com    iewStage->wakeCPU();
5411308Santhony.gutierrez@amd.com
5511308Santhony.gutierrez@amd.com    if (!inst->isExecuted()) {
5611308Santhony.gutierrez@amd.com        inst->setExecuted();
5711308Santhony.gutierrez@amd.com
5811308Santhony.gutierrez@amd.com        // Complete access to copy data to proper place.
5911308Santhony.gutierrez@amd.com        inst->completeAcc();
6011308Santhony.gutierrez@amd.com    }
6111308Santhony.gutierrez@amd.com
6211308Santhony.gutierrez@amd.com    // Need to insert instruction into queue to commit
6311308Santhony.gutierrez@amd.com    iewStage->instToCommit(inst);
6411308Santhony.gutierrez@amd.com
6511308Santhony.gutierrez@amd.com    iewStage->activityThisCycle();
6611308Santhony.gutierrez@amd.com
6711308Santhony.gutierrez@amd.com    inst = NULL;
6811308Santhony.gutierrez@amd.com*/
6911308Santhony.gutierrez@amd.com}
7012717Sbrandon.potter@amd.com
7111308Santhony.gutierrez@amd.comtemplate<class Impl>
7211308Santhony.gutierrez@amd.comvoid
7311308Santhony.gutierrez@amd.comLSQUnit<Impl>::completeStoreDataAccess(DynInstPtr &inst)
7411308Santhony.gutierrez@amd.com{
7511308Santhony.gutierrez@amd.com/*
7611308Santhony.gutierrez@amd.com    DPRINTF(LSQ, "Cache miss complete for store idx:%i\n", storeIdx);
7711308Santhony.gutierrez@amd.com    DPRINTF(Activity, "Activity: st writeback event idx:%i\n", storeIdx);
7811308Santhony.gutierrez@amd.com
7911308Santhony.gutierrez@amd.com    //lsqPtr->removeMSHR(lsqPtr->storeQueue[storeIdx].inst->seqNum);
8011308Santhony.gutierrez@amd.com
8111308Santhony.gutierrez@amd.com    if (lsqPtr->isSwitchedOut())
8211308Santhony.gutierrez@amd.com        return;
8311308Santhony.gutierrez@amd.com
8411308Santhony.gutierrez@amd.com    lsqPtr->cpu->wakeCPU();
8511308Santhony.gutierrez@amd.com
8611308Santhony.gutierrez@amd.com    if (wb)
8711308Santhony.gutierrez@amd.com        lsqPtr->completeDataAccess(storeIdx);
8811308Santhony.gutierrez@amd.com    lsqPtr->completeStore(storeIdx);
8911308Santhony.gutierrez@amd.com*/
9011308Santhony.gutierrez@amd.com}
9111308Santhony.gutierrez@amd.com
9211308Santhony.gutierrez@amd.comtemplate <class Impl>
9311308Santhony.gutierrez@amd.comTick
9411308Santhony.gutierrez@amd.comLSQUnit<Impl>::DcachePort::recvAtomic(PacketPtr pkt)
9511308Santhony.gutierrez@amd.com{
9611308Santhony.gutierrez@amd.com    panic("O3CPU model does not work with atomic mode!");
9711308Santhony.gutierrez@amd.com    return curTick;
9811308Santhony.gutierrez@amd.com}
9911308Santhony.gutierrez@amd.com
10011308Santhony.gutierrez@amd.comtemplate <class Impl>
10111308Santhony.gutierrez@amd.comvoid
10211308Santhony.gutierrez@amd.comLSQUnit<Impl>::DcachePort::recvFunctional(PacketPtr pkt)
10311308Santhony.gutierrez@amd.com{
10411308Santhony.gutierrez@amd.com    panic("O3CPU doesn't expect recvFunctional callback!");
10511308Santhony.gutierrez@amd.com}
10611308Santhony.gutierrez@amd.com
10711308Santhony.gutierrez@amd.comtemplate <class Impl>
10811308Santhony.gutierrez@amd.comvoid
10911308Santhony.gutierrez@amd.comLSQUnit<Impl>::DcachePort::recvStatusChange(Status status)
11011308Santhony.gutierrez@amd.com{
11111308Santhony.gutierrez@amd.com    if (status == RangeChange)
11211308Santhony.gutierrez@amd.com        return;
11311308Santhony.gutierrez@amd.com
11411308Santhony.gutierrez@amd.com    panic("O3CPU doesn't expect recvStatusChange callback!");
11511308Santhony.gutierrez@amd.com}
11612749Sgiacomo.travaglini@arm.com
11712749Sgiacomo.travaglini@arm.comtemplate <class Impl>
11811308Santhony.gutierrez@amd.combool
11911308Santhony.gutierrez@amd.comLSQUnit<Impl>::DcachePort::recvTiming(PacketPtr pkt)
12011308Santhony.gutierrez@amd.com{
12112717Sbrandon.potter@amd.com    lsq->completeDataAccess(pkt);
12211308Santhony.gutierrez@amd.com    return true;
12311308Santhony.gutierrez@amd.com}
12411308Santhony.gutierrez@amd.com
12511308Santhony.gutierrez@amd.comtemplate <class Impl>
12611308Santhony.gutierrez@amd.comvoid
12711308Santhony.gutierrez@amd.comLSQUnit<Impl>::DcachePort::recvRetry()
12811308Santhony.gutierrez@amd.com{
12911308Santhony.gutierrez@amd.com    panic("Retry unsupported for now!");
13011308Santhony.gutierrez@amd.com    // we shouldn't get a retry unless we have a packet that we're
13111308Santhony.gutierrez@amd.com    // waiting to transmit
13211308Santhony.gutierrez@amd.com/*
13311308Santhony.gutierrez@amd.com    assert(cpu->dcache_pkt != NULL);
13411308Santhony.gutierrez@amd.com    assert(cpu->_status == DcacheRetry);
13511308Santhony.gutierrez@amd.com    PacketPtr tmp = cpu->dcache_pkt;
13611308Santhony.gutierrez@amd.com    if (sendTiming(tmp)) {
13711308Santhony.gutierrez@amd.com        cpu->_status = DcacheWaitResponse;
13811308Santhony.gutierrez@amd.com        cpu->dcache_pkt = NULL;
13911308Santhony.gutierrez@amd.com    }
14011308Santhony.gutierrez@amd.com*/
14111308Santhony.gutierrez@amd.com}
14211308Santhony.gutierrez@amd.com
14311308Santhony.gutierrez@amd.comtemplate <class Impl>
14411308Santhony.gutierrez@amd.comLSQUnit<Impl>::LSQUnit()
14511308Santhony.gutierrez@amd.com    : loads(0), stores(0), storesToWB(0), stalled(false), isLoadBlocked(false),
14611308Santhony.gutierrez@amd.com      loadBlockedHandled(false)
14711308Santhony.gutierrez@amd.com{
14811308Santhony.gutierrez@amd.com}
14911308Santhony.gutierrez@amd.com
15011308Santhony.gutierrez@amd.comtemplate<class Impl>
15111308Santhony.gutierrez@amd.comvoid
15211308Santhony.gutierrez@amd.comLSQUnit<Impl>::init(Params *params, unsigned maxLQEntries,
15311308Santhony.gutierrez@amd.com                    unsigned maxSQEntries, unsigned id)
15411308Santhony.gutierrez@amd.com{
15511308Santhony.gutierrez@amd.com    DPRINTF(LSQUnit, "Creating LSQUnit%i object.\n",id);
15611308Santhony.gutierrez@amd.com
15711308Santhony.gutierrez@amd.com    switchedOut = false;
15811308Santhony.gutierrez@amd.com
15911308Santhony.gutierrez@amd.com    lsqID = id;
16011308Santhony.gutierrez@amd.com
16111308Santhony.gutierrez@amd.com    // Add 1 for the sentinel entry (they are circular queues).
16212717Sbrandon.potter@amd.com    LQEntries = maxLQEntries + 1;
16311308Santhony.gutierrez@amd.com    SQEntries = maxSQEntries + 1;
16411308Santhony.gutierrez@amd.com
16511308Santhony.gutierrez@amd.com    loadQueue.resize(LQEntries);
16611308Santhony.gutierrez@amd.com    storeQueue.resize(SQEntries);
16711308Santhony.gutierrez@amd.com
16811308Santhony.gutierrez@amd.com    loadHead = loadTail = 0;
16911308Santhony.gutierrez@amd.com
17011308Santhony.gutierrez@amd.com    storeHead = storeWBIdx = storeTail = 0;
17111308Santhony.gutierrez@amd.com
17211308Santhony.gutierrez@amd.com    usedPorts = 0;
17311308Santhony.gutierrez@amd.com    cachePorts = params->cachePorts;
17411308Santhony.gutierrez@amd.com
17511308Santhony.gutierrez@amd.com    Port *mem_dport = params->mem->getPort("");
17611308Santhony.gutierrez@amd.com    dcachePort->setPeer(mem_dport);
17711308Santhony.gutierrez@amd.com    mem_dport->setPeer(dcachePort);
17811308Santhony.gutierrez@amd.com
17911308Santhony.gutierrez@amd.com    memDepViolator = NULL;
18012749Sgiacomo.travaglini@arm.com
18111308Santhony.gutierrez@amd.com    blockedLoadSeqNum = 0;
18212749Sgiacomo.travaglini@arm.com}
18311308Santhony.gutierrez@amd.com
18411308Santhony.gutierrez@amd.comtemplate<class Impl>
18511308Santhony.gutierrez@amd.comvoid
18611308Santhony.gutierrez@amd.comLSQUnit<Impl>::setCPU(FullCPU *cpu_ptr)
18711308Santhony.gutierrez@amd.com{
18811308Santhony.gutierrez@amd.com    cpu = cpu_ptr;
18911308Santhony.gutierrez@amd.com    dcachePort = new DcachePort(cpu, this);
19011308Santhony.gutierrez@amd.com}
19111308Santhony.gutierrez@amd.com
19211308Santhony.gutierrez@amd.comtemplate<class Impl>
19311308Santhony.gutierrez@amd.comstd::string
19411308Santhony.gutierrez@amd.comLSQUnit<Impl>::name() const
19511308Santhony.gutierrez@amd.com{
19611308Santhony.gutierrez@amd.com    if (Impl::MaxThreads == 1) {
19711308Santhony.gutierrez@amd.com        return iewStage->name() + ".lsq";
19811308Santhony.gutierrez@amd.com    } else {
19911308Santhony.gutierrez@amd.com        return iewStage->name() + ".lsq.thread." + to_string(lsqID);
20011308Santhony.gutierrez@amd.com    }
20111308Santhony.gutierrez@amd.com}
20211308Santhony.gutierrez@amd.com
20311308Santhony.gutierrez@amd.comtemplate<class Impl>
20411308Santhony.gutierrez@amd.comvoid
20511308Santhony.gutierrez@amd.comLSQUnit<Impl>::clearLQ()
20611308Santhony.gutierrez@amd.com{
20711308Santhony.gutierrez@amd.com    loadQueue.clear();
20811308Santhony.gutierrez@amd.com}
20911308Santhony.gutierrez@amd.com
21011308Santhony.gutierrez@amd.comtemplate<class Impl>
21111308Santhony.gutierrez@amd.comvoid
21211308Santhony.gutierrez@amd.comLSQUnit<Impl>::clearSQ()
21311308Santhony.gutierrez@amd.com{
21411308Santhony.gutierrez@amd.com    storeQueue.clear();
21511308Santhony.gutierrez@amd.com}
21611308Santhony.gutierrez@amd.com
21711308Santhony.gutierrez@amd.com#if 0
21811308Santhony.gutierrez@amd.comtemplate<class Impl>
21911308Santhony.gutierrez@amd.comvoid
22011308Santhony.gutierrez@amd.comLSQUnit<Impl>::setPageTable(PageTable *pt_ptr)
22111308Santhony.gutierrez@amd.com{
22211308Santhony.gutierrez@amd.com    DPRINTF(LSQUnit, "Setting the page table pointer.\n");
22311308Santhony.gutierrez@amd.com    pTable = pt_ptr;
22411308Santhony.gutierrez@amd.com}
22512749Sgiacomo.travaglini@arm.com#endif
22612749Sgiacomo.travaglini@arm.com
22711308Santhony.gutierrez@amd.comtemplate<class Impl>
22812749Sgiacomo.travaglini@arm.comvoid
22911308Santhony.gutierrez@amd.comLSQUnit<Impl>::switchOut()
23011308Santhony.gutierrez@amd.com{
23111308Santhony.gutierrez@amd.com    switchedOut = true;
23211308Santhony.gutierrez@amd.com    for (int i = 0; i < loadQueue.size(); ++i)
23311308Santhony.gutierrez@amd.com        loadQueue[i] = NULL;
23411308Santhony.gutierrez@amd.com
23512717Sbrandon.potter@amd.com    assert(storesToWB == 0);
23611308Santhony.gutierrez@amd.com}
23711308Santhony.gutierrez@amd.com
23811308Santhony.gutierrez@amd.comtemplate<class Impl>
23911308Santhony.gutierrez@amd.comvoid
24011308Santhony.gutierrez@amd.comLSQUnit<Impl>::takeOverFrom()
24111308Santhony.gutierrez@amd.com{
24212749Sgiacomo.travaglini@arm.com    switchedOut = false;
24312749Sgiacomo.travaglini@arm.com    loads = stores = storesToWB = 0;
24411308Santhony.gutierrez@amd.com
24511308Santhony.gutierrez@amd.com    loadHead = loadTail = 0;
24611308Santhony.gutierrez@amd.com
24711308Santhony.gutierrez@amd.com    storeHead = storeWBIdx = storeTail = 0;
24811308Santhony.gutierrez@amd.com
24911308Santhony.gutierrez@amd.com    usedPorts = 0;
25011308Santhony.gutierrez@amd.com
25112717Sbrandon.potter@amd.com    memDepViolator = NULL;
25211308Santhony.gutierrez@amd.com
25312717Sbrandon.potter@amd.com    blockedLoadSeqNum = 0;
25411308Santhony.gutierrez@amd.com
25511308Santhony.gutierrez@amd.com    stalled = false;
25611308Santhony.gutierrez@amd.com    isLoadBlocked = false;
25711308Santhony.gutierrez@amd.com    loadBlockedHandled = false;
25811308Santhony.gutierrez@amd.com}
25911308Santhony.gutierrez@amd.com
26011308Santhony.gutierrez@amd.comtemplate<class Impl>
26111308Santhony.gutierrez@amd.comvoid
26211308Santhony.gutierrez@amd.comLSQUnit<Impl>::resizeLQ(unsigned size)
26311308Santhony.gutierrez@amd.com{
26411308Santhony.gutierrez@amd.com    unsigned size_plus_sentinel = size + 1;
26511308Santhony.gutierrez@amd.com    assert(size_plus_sentinel >= LQEntries);
26611308Santhony.gutierrez@amd.com
26711308Santhony.gutierrez@amd.com    if (size_plus_sentinel > LQEntries) {
26811308Santhony.gutierrez@amd.com        while (size_plus_sentinel > loadQueue.size()) {
26911308Santhony.gutierrez@amd.com            DynInstPtr dummy;
27011308Santhony.gutierrez@amd.com            loadQueue.push_back(dummy);
27111308Santhony.gutierrez@amd.com            LQEntries++;
27211308Santhony.gutierrez@amd.com        }
27311308Santhony.gutierrez@amd.com    } else {
27411308Santhony.gutierrez@amd.com        LQEntries = size_plus_sentinel;
27513449Sgabeblack@google.com    }
27611308Santhony.gutierrez@amd.com
27711308Santhony.gutierrez@amd.com}
27811308Santhony.gutierrez@amd.com
27911308Santhony.gutierrez@amd.comtemplate<class Impl>
28011308Santhony.gutierrez@amd.comvoid
28111308Santhony.gutierrez@amd.comLSQUnit<Impl>::resizeSQ(unsigned size)
28211308Santhony.gutierrez@amd.com{
28311308Santhony.gutierrez@amd.com    unsigned size_plus_sentinel = size + 1;
28411308Santhony.gutierrez@amd.com    if (size_plus_sentinel > SQEntries) {
28511308Santhony.gutierrez@amd.com        while (size_plus_sentinel > storeQueue.size()) {
28611308Santhony.gutierrez@amd.com            SQEntry dummy;
28711308Santhony.gutierrez@amd.com            storeQueue.push_back(dummy);
28811308Santhony.gutierrez@amd.com            SQEntries++;
28911308Santhony.gutierrez@amd.com        }
29011308Santhony.gutierrez@amd.com    } else {
29111308Santhony.gutierrez@amd.com        SQEntries = size_plus_sentinel;
29211308Santhony.gutierrez@amd.com    }
29311308Santhony.gutierrez@amd.com}
29411308Santhony.gutierrez@amd.com
29511308Santhony.gutierrez@amd.comtemplate <class Impl>
29611308Santhony.gutierrez@amd.comvoid
29711308Santhony.gutierrez@amd.comLSQUnit<Impl>::insert(DynInstPtr &inst)
29811308Santhony.gutierrez@amd.com{
29911308Santhony.gutierrez@amd.com    assert(inst->isMemRef());
30011308Santhony.gutierrez@amd.com
30111308Santhony.gutierrez@amd.com    assert(inst->isLoad() || inst->isStore());
30211308Santhony.gutierrez@amd.com
30311308Santhony.gutierrez@amd.com    if (inst->isLoad()) {
30411308Santhony.gutierrez@amd.com        insertLoad(inst);
30511308Santhony.gutierrez@amd.com    } else {
30611308Santhony.gutierrez@amd.com        insertStore(inst);
30711308Santhony.gutierrez@amd.com    }
30811308Santhony.gutierrez@amd.com
30911308Santhony.gutierrez@amd.com    inst->setInLSQ();
31011308Santhony.gutierrez@amd.com}
31113784Sgabeblack@google.com
31213784Sgabeblack@google.comtemplate <class Impl>
31311308Santhony.gutierrez@amd.comvoid
31411308Santhony.gutierrez@amd.comLSQUnit<Impl>::insertLoad(DynInstPtr &load_inst)
31511308Santhony.gutierrez@amd.com{
31611308Santhony.gutierrez@amd.com    assert((loadTail + 1) % LQEntries != loadHead);
31711308Santhony.gutierrez@amd.com    assert(loads < LQEntries);
31811308Santhony.gutierrez@amd.com
31911308Santhony.gutierrez@amd.com    DPRINTF(LSQUnit, "Inserting load PC %#x, idx:%i [sn:%lli]\n",
32011308Santhony.gutierrez@amd.com            load_inst->readPC(), loadTail, load_inst->seqNum);
32111308Santhony.gutierrez@amd.com
32211308Santhony.gutierrez@amd.com    load_inst->lqIdx = loadTail;
32311308Santhony.gutierrez@amd.com
32411308Santhony.gutierrez@amd.com    if (stores == 0) {
32511308Santhony.gutierrez@amd.com        load_inst->sqIdx = -1;
32611308Santhony.gutierrez@amd.com    } else {
32711308Santhony.gutierrez@amd.com        load_inst->sqIdx = storeTail;
32811308Santhony.gutierrez@amd.com    }
32911308Santhony.gutierrez@amd.com
33011308Santhony.gutierrez@amd.com    loadQueue[loadTail] = load_inst;
33111308Santhony.gutierrez@amd.com
33211308Santhony.gutierrez@amd.com    incrLdIdx(loadTail);
33311308Santhony.gutierrez@amd.com
33411308Santhony.gutierrez@amd.com    ++loads;
33511308Santhony.gutierrez@amd.com}
33611308Santhony.gutierrez@amd.com
33711308Santhony.gutierrez@amd.comtemplate <class Impl>
33811308Santhony.gutierrez@amd.comvoid
33911308Santhony.gutierrez@amd.comLSQUnit<Impl>::insertStore(DynInstPtr &store_inst)
34011308Santhony.gutierrez@amd.com{
34111308Santhony.gutierrez@amd.com    // Make sure it is not full before inserting an instruction.
34212717Sbrandon.potter@amd.com    assert((storeTail + 1) % SQEntries != storeHead);
34311308Santhony.gutierrez@amd.com    assert(stores < SQEntries);
34411308Santhony.gutierrez@amd.com
34511308Santhony.gutierrez@amd.com    DPRINTF(LSQUnit, "Inserting store PC %#x, idx:%i [sn:%lli]\n",
34611308Santhony.gutierrez@amd.com            store_inst->readPC(), storeTail, store_inst->seqNum);
34711308Santhony.gutierrez@amd.com
34811308Santhony.gutierrez@amd.com    store_inst->sqIdx = storeTail;
34911308Santhony.gutierrez@amd.com    store_inst->lqIdx = loadTail;
35011308Santhony.gutierrez@amd.com
35111308Santhony.gutierrez@amd.com    storeQueue[storeTail] = SQEntry(store_inst);
35211308Santhony.gutierrez@amd.com
35311308Santhony.gutierrez@amd.com    incrStIdx(storeTail);
35411308Santhony.gutierrez@amd.com
35511308Santhony.gutierrez@amd.com    ++stores;
35611308Santhony.gutierrez@amd.com}
35711308Santhony.gutierrez@amd.com
35811308Santhony.gutierrez@amd.comtemplate <class Impl>
35911308Santhony.gutierrez@amd.comtypename Impl::DynInstPtr
36011308Santhony.gutierrez@amd.comLSQUnit<Impl>::getMemDepViolator()
36111308Santhony.gutierrez@amd.com{
36211308Santhony.gutierrez@amd.com    DynInstPtr temp = memDepViolator;
36311308Santhony.gutierrez@amd.com
36411308Santhony.gutierrez@amd.com    memDepViolator = NULL;
36511308Santhony.gutierrez@amd.com
36611308Santhony.gutierrez@amd.com    return temp;
36711308Santhony.gutierrez@amd.com}
36811308Santhony.gutierrez@amd.com
36911308Santhony.gutierrez@amd.comtemplate <class Impl>
37011308Santhony.gutierrez@amd.comunsigned
37111308Santhony.gutierrez@amd.comLSQUnit<Impl>::numFreeEntries()
37211308Santhony.gutierrez@amd.com{
37311308Santhony.gutierrez@amd.com    unsigned free_lq_entries = LQEntries - loads;
37411308Santhony.gutierrez@amd.com    unsigned free_sq_entries = SQEntries - stores;
37511308Santhony.gutierrez@amd.com
37611308Santhony.gutierrez@amd.com    // Both the LQ and SQ entries have an extra dummy entry to differentiate
37711308Santhony.gutierrez@amd.com    // empty/full conditions.  Subtract 1 from the free entries.
37811308Santhony.gutierrez@amd.com    if (free_lq_entries < free_sq_entries) {
37911308Santhony.gutierrez@amd.com        return free_lq_entries - 1;
38011308Santhony.gutierrez@amd.com    } else {
38111308Santhony.gutierrez@amd.com        return free_sq_entries - 1;
38211308Santhony.gutierrez@amd.com    }
38311308Santhony.gutierrez@amd.com}
38411308Santhony.gutierrez@amd.com
38511308Santhony.gutierrez@amd.comtemplate <class Impl>
38611308Santhony.gutierrez@amd.comint
38711308Santhony.gutierrez@amd.comLSQUnit<Impl>::numLoadsReady()
38811308Santhony.gutierrez@amd.com{
38911308Santhony.gutierrez@amd.com    int load_idx = loadHead;
39011308Santhony.gutierrez@amd.com    int retval = 0;
39111308Santhony.gutierrez@amd.com
39211308Santhony.gutierrez@amd.com    while (load_idx != loadTail) {
39311308Santhony.gutierrez@amd.com        assert(loadQueue[load_idx]);
39411308Santhony.gutierrez@amd.com
39511308Santhony.gutierrez@amd.com        if (loadQueue[load_idx]->readyToIssue()) {
39611308Santhony.gutierrez@amd.com            ++retval;
39711308Santhony.gutierrez@amd.com        }
39811308Santhony.gutierrez@amd.com    }
39911308Santhony.gutierrez@amd.com
40011308Santhony.gutierrez@amd.com    return retval;
40111308Santhony.gutierrez@amd.com}
40211308Santhony.gutierrez@amd.com
40311308Santhony.gutierrez@amd.comtemplate <class Impl>
40411308Santhony.gutierrez@amd.comFault
40511308Santhony.gutierrez@amd.comLSQUnit<Impl>::executeLoad(DynInstPtr &inst)
40611308Santhony.gutierrez@amd.com{
40711308Santhony.gutierrez@amd.com    // Execute a specific load.
40811308Santhony.gutierrez@amd.com    Fault load_fault = NoFault;
40911308Santhony.gutierrez@amd.com
41011308Santhony.gutierrez@amd.com    DPRINTF(LSQUnit, "Executing load PC %#x, [sn:%lli]\n",
41111308Santhony.gutierrez@amd.com            inst->readPC(),inst->seqNum);
41211308Santhony.gutierrez@amd.com
41311308Santhony.gutierrez@amd.com    load_fault = inst->initiateAcc();
41411308Santhony.gutierrez@amd.com
41512085Sspwilson2@wisc.edu    // If the instruction faulted, then we need to send it along to commit
41611308Santhony.gutierrez@amd.com    // without the instruction completing.
41711308Santhony.gutierrez@amd.com    if (load_fault != NoFault) {
41811308Santhony.gutierrez@amd.com        // Send this instruction to commit, also make sure iew stage
41911308Santhony.gutierrez@amd.com        // realizes there is activity.
42011308Santhony.gutierrez@amd.com        iewStage->instToCommit(inst);
42111308Santhony.gutierrez@amd.com        iewStage->activityThisCycle();
42211308Santhony.gutierrez@amd.com    }
42311308Santhony.gutierrez@amd.com
42411308Santhony.gutierrez@amd.com    return load_fault;
42511308Santhony.gutierrez@amd.com}
42611308Santhony.gutierrez@amd.com
42711308Santhony.gutierrez@amd.comtemplate <class Impl>
42811308Santhony.gutierrez@amd.comFault
42911308Santhony.gutierrez@amd.comLSQUnit<Impl>::executeStore(DynInstPtr &store_inst)
43011308Santhony.gutierrez@amd.com{
43111308Santhony.gutierrez@amd.com    using namespace TheISA;
43211308Santhony.gutierrez@amd.com    // Make sure that a store exists.
43311308Santhony.gutierrez@amd.com    assert(stores != 0);
43411308Santhony.gutierrez@amd.com
43511308Santhony.gutierrez@amd.com    int store_idx = store_inst->sqIdx;
43611308Santhony.gutierrez@amd.com
43711308Santhony.gutierrez@amd.com    DPRINTF(LSQUnit, "Executing store PC %#x [sn:%lli]\n",
43811308Santhony.gutierrez@amd.com            store_inst->readPC(), store_inst->seqNum);
43911308Santhony.gutierrez@amd.com
44011308Santhony.gutierrez@amd.com    // Check the recently completed loads to see if any match this store's
44111308Santhony.gutierrez@amd.com    // address.  If so, then we have a memory ordering violation.
44211308Santhony.gutierrez@amd.com    int load_idx = store_inst->lqIdx;
44311308Santhony.gutierrez@amd.com
44411308Santhony.gutierrez@amd.com    Fault store_fault = store_inst->initiateAcc();
44511308Santhony.gutierrez@amd.com//    Fault store_fault = store_inst->execute();
44611308Santhony.gutierrez@amd.com
44711308Santhony.gutierrez@amd.com    if (storeQueue[store_idx].size == 0) {
44812085Sspwilson2@wisc.edu        DPRINTF(LSQUnit,"Fault on Store PC %#x, [sn:%lli],Size = 0\n",
44911308Santhony.gutierrez@amd.com                store_inst->readPC(),store_inst->seqNum);
45011308Santhony.gutierrez@amd.com
45111308Santhony.gutierrez@amd.com        return store_fault;
45211308Santhony.gutierrez@amd.com    }
453
454    assert(store_fault == NoFault);
455
456    if (store_inst->isStoreConditional()) {
457        // Store conditionals need to set themselves as able to
458        // writeback if we haven't had a fault by here.
459        storeQueue[store_idx].canWB = true;
460
461        ++storesToWB;
462    }
463
464    if (!memDepViolator) {
465        while (load_idx != loadTail) {
466            // Really only need to check loads that have actually executed
467            // It's safe to check all loads because effAddr is set to
468            // InvalAddr when the dyn inst is created.
469
470            // @todo: For now this is extra conservative, detecting a
471            // violation if the addresses match assuming all accesses
472            // are quad word accesses.
473
474            // @todo: Fix this, magic number being used here
475            if ((loadQueue[load_idx]->effAddr >> 8) ==
476                (store_inst->effAddr >> 8)) {
477                // A load incorrectly passed this store.  Squash and refetch.
478                // For now return a fault to show that it was unsuccessful.
479                memDepViolator = loadQueue[load_idx];
480
481                return genMachineCheckFault();
482            }
483
484            incrLdIdx(load_idx);
485        }
486
487        // If we've reached this point, there was no violation.
488        memDepViolator = NULL;
489    }
490
491    return store_fault;
492}
493
494template <class Impl>
495void
496LSQUnit<Impl>::commitLoad()
497{
498    assert(loadQueue[loadHead]);
499
500    DPRINTF(LSQUnit, "Committing head load instruction, PC %#x\n",
501            loadQueue[loadHead]->readPC());
502
503
504    loadQueue[loadHead] = NULL;
505
506    incrLdIdx(loadHead);
507
508    --loads;
509}
510
511template <class Impl>
512void
513LSQUnit<Impl>::commitLoads(InstSeqNum &youngest_inst)
514{
515    assert(loads == 0 || loadQueue[loadHead]);
516
517    while (loads != 0 && loadQueue[loadHead]->seqNum <= youngest_inst) {
518        commitLoad();
519    }
520}
521
522template <class Impl>
523void
524LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst)
525{
526    assert(stores == 0 || storeQueue[storeHead].inst);
527
528    int store_idx = storeHead;
529
530    while (store_idx != storeTail) {
531        assert(storeQueue[store_idx].inst);
532        // Mark any stores that are now committed and have not yet
533        // been marked as able to write back.
534        if (!storeQueue[store_idx].canWB) {
535            if (storeQueue[store_idx].inst->seqNum > youngest_inst) {
536                break;
537            }
538            DPRINTF(LSQUnit, "Marking store as able to write back, PC "
539                    "%#x [sn:%lli]\n",
540                    storeQueue[store_idx].inst->readPC(),
541                    storeQueue[store_idx].inst->seqNum);
542
543            storeQueue[store_idx].canWB = true;
544
545            ++storesToWB;
546        }
547
548        incrStIdx(store_idx);
549    }
550}
551
552template <class Impl>
553void
554LSQUnit<Impl>::writebackStores()
555{
556    while (storesToWB > 0 &&
557           storeWBIdx != storeTail &&
558           storeQueue[storeWBIdx].inst &&
559           storeQueue[storeWBIdx].canWB &&
560           usedPorts < cachePorts) {
561
562        // Store didn't write any data so no need to write it back to
563        // memory.
564        if (storeQueue[storeWBIdx].size == 0) {
565            completeStore(storeWBIdx);
566
567            incrStIdx(storeWBIdx);
568
569            continue;
570        }
571/*
572        if (dcacheInterface && dcacheInterface->isBlocked()) {
573            DPRINTF(LSQUnit, "Unable to write back any more stores, cache"
574                    " is blocked!\n");
575            break;
576        }
577*/
578        ++usedPorts;
579
580        if (storeQueue[storeWBIdx].inst->isDataPrefetch()) {
581            incrStIdx(storeWBIdx);
582
583            continue;
584        }
585
586        assert(storeQueue[storeWBIdx].req);
587        assert(!storeQueue[storeWBIdx].committed);
588
589        DynInstPtr inst = storeQueue[storeWBIdx].inst;
590
591        Request *req = storeQueue[storeWBIdx].req;
592        storeQueue[storeWBIdx].committed = true;
593
594        assert(!inst->memData);
595        inst->memData = new uint8_t[64];
596        memcpy(inst->memData, (uint8_t *)&storeQueue[storeWBIdx].data, req->getSize());
597
598        PacketPtr data_pkt = new Packet(req, Packet::WriteReq, Packet::Broadcast);
599        data_pkt->dataStatic(inst->memData);
600
601        DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
602                "to Addr:%#x, data:%#x [sn:%lli]\n",
603                storeWBIdx, storeQueue[storeWBIdx].inst->readPC(),
604                req->getPaddr(), *(inst->memData),
605                storeQueue[storeWBIdx].inst->seqNum);
606
607        if (!dcachePort->sendTiming(data_pkt)) {
608            // Need to handle becoming blocked on a store.
609        } else {
610            /*
611            StoreCompletionEvent *store_event = new
612                StoreCompletionEvent(storeWBIdx, NULL, this);
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 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                    LdWritebackEvent(storeQueue[storeWBIdx].inst,
631                                     iewStage);
632                store_event->wbEvent = wb;
633            }
634*/
635            if (data_pkt->result != Packet::Success) {
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        }
657    }
658
659    // Not sure this should set it to 0.
660    usedPorts = 0;
661
662    assert(stores >= 0 && storesToWB >= 0);
663}
664
665/*template <class Impl>
666void
667LSQUnit<Impl>::removeMSHR(InstSeqNum seqNum)
668{
669    list<InstSeqNum>::iterator mshr_it = find(mshrSeqNums.begin(),
670                                              mshrSeqNums.end(),
671                                              seqNum);
672
673    if (mshr_it != mshrSeqNums.end()) {
674        mshrSeqNums.erase(mshr_it);
675        DPRINTF(LSQUnit, "Removing MSHR. count = %i\n",mshrSeqNums.size());
676    }
677}*/
678
679template <class Impl>
680void
681LSQUnit<Impl>::squash(const InstSeqNum &squashed_num)
682{
683    DPRINTF(LSQUnit, "Squashing until [sn:%lli]!"
684            "(Loads:%i Stores:%i)\n", squashed_num, loads, stores);
685
686    int load_idx = loadTail;
687    decrLdIdx(load_idx);
688
689    while (loads != 0 && loadQueue[load_idx]->seqNum > squashed_num) {
690        DPRINTF(LSQUnit,"Load Instruction PC %#x squashed, "
691                "[sn:%lli]\n",
692                loadQueue[load_idx]->readPC(),
693                loadQueue[load_idx]->seqNum);
694
695        if (isStalled() && load_idx == stallingLoadIdx) {
696            stalled = false;
697            stallingStoreIsn = 0;
698            stallingLoadIdx = 0;
699        }
700
701        // Clear the smart pointer to make sure it is decremented.
702        loadQueue[load_idx]->squashed = true;
703        loadQueue[load_idx] = NULL;
704        --loads;
705
706        // Inefficient!
707        loadTail = load_idx;
708
709        decrLdIdx(load_idx);
710    }
711
712    if (isLoadBlocked) {
713        if (squashed_num < blockedLoadSeqNum) {
714            isLoadBlocked = false;
715            loadBlockedHandled = false;
716            blockedLoadSeqNum = 0;
717        }
718    }
719
720    int store_idx = storeTail;
721    decrStIdx(store_idx);
722
723    while (stores != 0 &&
724           storeQueue[store_idx].inst->seqNum > squashed_num) {
725        // Instructions marked as can WB are already committed.
726        if (storeQueue[store_idx].canWB) {
727            break;
728        }
729
730        DPRINTF(LSQUnit,"Store Instruction PC %#x squashed, "
731                "idx:%i [sn:%lli]\n",
732                storeQueue[store_idx].inst->readPC(),
733                store_idx, storeQueue[store_idx].inst->seqNum);
734
735        // I don't think this can happen.  It should have been cleared
736        // by the stalling load.
737        if (isStalled() &&
738            storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
739            panic("Is stalled should have been cleared by stalling load!\n");
740            stalled = false;
741            stallingStoreIsn = 0;
742        }
743
744        // Clear the smart pointer to make sure it is decremented.
745        storeQueue[store_idx].inst->squashed = true;
746        storeQueue[store_idx].inst = NULL;
747        storeQueue[store_idx].canWB = 0;
748
749        storeQueue[store_idx].req = NULL;
750        --stores;
751
752        // Inefficient!
753        storeTail = store_idx;
754
755        decrStIdx(store_idx);
756    }
757}
758
759template <class Impl>
760void
761LSQUnit<Impl>::completeStore(int store_idx)
762{
763    assert(storeQueue[store_idx].inst);
764    storeQueue[store_idx].completed = true;
765    --storesToWB;
766    // A bit conservative because a store completion may not free up entries,
767    // but hopefully avoids two store completions in one cycle from making
768    // the CPU tick twice.
769    cpu->activityThisCycle();
770
771    if (store_idx == storeHead) {
772        do {
773            incrStIdx(storeHead);
774
775            --stores;
776        } while (storeQueue[storeHead].completed &&
777                 storeHead != storeTail);
778
779        iewStage->updateLSQNextCycle = true;
780    }
781
782    DPRINTF(LSQUnit, "Completing store [sn:%lli], idx:%i, store head "
783            "idx:%i\n",
784            storeQueue[store_idx].inst->seqNum, store_idx, storeHead);
785
786    if (isStalled() &&
787        storeQueue[store_idx].inst->seqNum == stallingStoreIsn) {
788        DPRINTF(LSQUnit, "Unstalling, stalling store [sn:%lli] "
789                "load idx:%i\n",
790                stallingStoreIsn, stallingLoadIdx);
791        stalled = false;
792        stallingStoreIsn = 0;
793        iewStage->replayMemInst(loadQueue[stallingLoadIdx]);
794    }
795
796    storeQueue[store_idx].inst->setCompleted();
797
798    // Tell the checker we've completed this instruction.  Some stores
799    // may get reported twice to the checker, but the checker can
800    // handle that case.
801    if (cpu->checker) {
802        cpu->checker->tick(storeQueue[store_idx].inst);
803    }
804}
805
806template <class Impl>
807inline void
808LSQUnit<Impl>::incrStIdx(int &store_idx)
809{
810    if (++store_idx >= SQEntries)
811        store_idx = 0;
812}
813
814template <class Impl>
815inline void
816LSQUnit<Impl>::decrStIdx(int &store_idx)
817{
818    if (--store_idx < 0)
819        store_idx += SQEntries;
820}
821
822template <class Impl>
823inline void
824LSQUnit<Impl>::incrLdIdx(int &load_idx)
825{
826    if (++load_idx >= LQEntries)
827        load_idx = 0;
828}
829
830template <class Impl>
831inline void
832LSQUnit<Impl>::decrLdIdx(int &load_idx)
833{
834    if (--load_idx < 0)
835        load_idx += LQEntries;
836}
837
838template <class Impl>
839void
840LSQUnit<Impl>::dumpInsts()
841{
842    cprintf("Load store queue: Dumping instructions.\n");
843    cprintf("Load queue size: %i\n", loads);
844    cprintf("Load queue: ");
845
846    int load_idx = loadHead;
847
848    while (load_idx != loadTail && loadQueue[load_idx]) {
849        cprintf("%#x ", loadQueue[load_idx]->readPC());
850
851        incrLdIdx(load_idx);
852    }
853
854    cprintf("Store queue size: %i\n", stores);
855    cprintf("Store queue: ");
856
857    int store_idx = storeHead;
858
859    while (store_idx != storeTail && storeQueue[store_idx].inst) {
860        cprintf("%#x ", storeQueue[store_idx].inst->readPC());
861
862        incrStIdx(store_idx);
863    }
864
865    cprintf("\n");
866}
867