lsq_unit.hh revision 2307
11689SN/A/*
212109SRekai.GonzalezAlberquilla@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
39919Ssteve.reinhardt@amd.com * All rights reserved.
48707Sandreas.hansson@arm.com *
58707Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
68707Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
78707Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
88707Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
98707Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
108707Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
118707Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
128707Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its
138707Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from
148707Sandreas.hansson@arm.com * this software without specific prior written permission.
151689SN/A *
167897Shestness@cs.utexas.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171689SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181689SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191689SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201689SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211689SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221689SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231689SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241689SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251689SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261689SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
271689SN/A */
281689SN/A
291689SN/A#ifndef __CPU_O3_LSQ_UNIT_HH__
301689SN/A#define __CPU_O3_LSQ_UNIT_HH__
311689SN/A
321689SN/A#include <map>
331689SN/A#include <queue>
341689SN/A#include <algorithm>
351689SN/A
361689SN/A#include "config/full_system.hh"
371689SN/A#include "base/hashmap.hh"
381689SN/A#include "cpu/inst_seq.hh"
391689SN/A#include "mem/mem_interface.hh"
401689SN/A//#include "mem/page_table.hh"
412665Ssaidi@eecs.umich.edu#include "sim/debug.hh"
422665Ssaidi@eecs.umich.edu#include "sim/sim_object.hh"
432756Sksewell@umich.edu#include "arch/faults.hh"
447897Shestness@cs.utexas.edu
451689SN/A/**
461689SN/A * Class that implements the actual LQ and SQ for each specific thread.
472325SN/A * Both are circular queues; load entries are freed upon committing, while
482325SN/A * store entries are freed once they writeback. The LSQUnit tracks if there
491060SN/A * are memory ordering violations, and also detects partial load to store
501060SN/A * forwarding cases (a store only has part of a load's data) that requires
511060SN/A * the load to wait until the store writes back. In the former case it
522292SN/A * holds onto the instruction until the dependence unit looks at it, and
532292SN/A * in the latter it stalls the LSQ until the store writes back. At that
541681SN/A * point the load is replayed.
551060SN/A */
5612109SRekai.GonzalezAlberquilla@arm.comtemplate <class Impl>
572980Sgblack@eecs.umich.educlass LSQUnit {
581060SN/A  protected:
596658Snate@binkert.org    typedef TheISA::IntReg IntReg;
601717SN/A  public:
611717SN/A    typedef typename Impl::Params Params;
622292SN/A    typedef typename Impl::FullCPU FullCPU;
632292SN/A    typedef typename Impl::DynInstPtr DynInstPtr;
648229Snate@binkert.org    typedef typename Impl::CPUPol::IEW IEW;
658229Snate@binkert.org    typedef typename Impl::CPUPol::IssueStruct IssueStruct;
668229Snate@binkert.org
678229Snate@binkert.org  private:
682817Sksewell@umich.edu    class StoreCompletionEvent : public Event {
698229Snate@binkert.org      public:
701060SN/A        /** Constructs a store completion event. */
711060SN/A        StoreCompletionEvent(int store_idx, Event *wb_event, LSQUnit *lsq_ptr);
722316SN/A
732316SN/A        /** Processes the store completion event. */
742680Sktlim@umich.edu        void process();
752817Sksewell@umich.edu
762817Sksewell@umich.edu        /** Returns the description of this event. */
772843Sktlim@umich.edu        const char *description();
782843Sktlim@umich.edu
792669Sktlim@umich.edu      private:
801060SN/A        /** The store index of the store being written back. */
811060SN/A        int storeIdx;
828737Skoansin.tan@gmail.com        /** The writeback event for the store.  Needed for store
835529Snate@binkert.org         * conditionals.
842733Sktlim@umich.edu         */
851060SN/A        Event *wbEvent;
861060SN/A        /** The pointer to the LSQ unit that issued the store. */
871060SN/A        LSQUnit<Impl> *lsqPtr;
885529Snate@binkert.org    };
892292SN/A
902292SN/A    friend class StoreCompletionEvent;
911060SN/A
921060SN/A  public:
932348SN/A    /** Constructs an LSQ unit. init() must be called prior to use. */
942348SN/A    LSQUnit();
952348SN/A
962348SN/A    /** Initializes the LSQ unit with the specified number of entries. */
972348SN/A    void init(Params *params, unsigned maxLQEntries,
981060SN/A              unsigned maxSQEntries, unsigned id);
992733Sktlim@umich.edu
1001060SN/A    /** Returns the name of the LSQ unit. */
1011060SN/A    std::string name() const;
1022325SN/A
1031060SN/A    /** Sets the CPU pointer. */
1041061SN/A    void setCPU(FullCPU *cpu_ptr)
1054329Sktlim@umich.edu    { cpu = cpu_ptr; }
1061060SN/A
10712109SRekai.GonzalezAlberquilla@arm.com    /** Sets the IEW stage pointer. */
10812109SRekai.GonzalezAlberquilla@arm.com    void setIEW(IEW *iew_ptr)
10912109SRekai.GonzalezAlberquilla@arm.com    { iewStage = iew_ptr; }
1105595Sgblack@eecs.umich.edu
1112292SN/A    /** Sets the page table pointer. */
1122292SN/A//    void setPageTable(PageTable *pt_ptr);
1132292SN/A
1142292SN/A    void switchOut();
1152817Sksewell@umich.edu
1162829Sksewell@umich.edu    void takeOverFrom();
1171060SN/A
1181060SN/A    bool isSwitchedOut() { return switchedOut; }
1191060SN/A
1201060SN/A    /** Ticks the LSQ unit, which in this case only resets the number of
1211060SN/A     * used cache ports.
1222307SN/A     * @todo: Move the number of used ports up to the LSQ level so it can
1232307SN/A     * be shared by all LSQ units.
1241060SN/A     */
1251060SN/A    void tick() { usedPorts = 0; }
1266022Sgblack@eecs.umich.edu
1276022Sgblack@eecs.umich.edu    /** Inserts an instruction. */
1283781Sgblack@eecs.umich.edu    void insert(DynInstPtr &inst);
1292292SN/A    /** Inserts a load instruction. */
1301060SN/A    void insertLoad(DynInstPtr &load_inst);
1311060SN/A    /** Inserts a store instruction. */
1321060SN/A    void insertStore(DynInstPtr &store_inst);
1338707Sandreas.hansson@arm.com
1348707Sandreas.hansson@arm.com    /** Executes a load instruction. */
1358707Sandreas.hansson@arm.com    Fault executeLoad(DynInstPtr &inst);
1368707Sandreas.hansson@arm.com
1379608Sandreas.hansson@arm.com    Fault executeLoad(int lq_idx);
1388707Sandreas.hansson@arm.com    /** Executes a store instruction. */
1398707Sandreas.hansson@arm.com    Fault executeStore(DynInstPtr &inst);
1408707Sandreas.hansson@arm.com
1418707Sandreas.hansson@arm.com    /** Commits the head load. */
1428707Sandreas.hansson@arm.com    void commitLoad();
1438707Sandreas.hansson@arm.com    /** Commits a specific load, given by the sequence number. */
1448707Sandreas.hansson@arm.com    void commitLoad(InstSeqNum &inst);
1458707Sandreas.hansson@arm.com    /** Commits loads older than a specific sequence number. */
1469608Sandreas.hansson@arm.com    void commitLoads(InstSeqNum &youngest_inst);
1478707Sandreas.hansson@arm.com
1488707Sandreas.hansson@arm.com    /** Commits stores older than a specific sequence number. */
1498707Sandreas.hansson@arm.com    void commitStores(InstSeqNum &youngest_inst);
1508707Sandreas.hansson@arm.com
1518707Sandreas.hansson@arm.com    /** Writes back stores. */
1528707Sandreas.hansson@arm.com    void writebackStores();
1538975Sandreas.hansson@arm.com
1548707Sandreas.hansson@arm.com    // @todo: Include stats in the LSQ unit.
1558707Sandreas.hansson@arm.com    //void regStats();
15610713Sandreas.hansson@arm.com
1578707Sandreas.hansson@arm.com    /** Clears all the entries in the LQ. */
1588707Sandreas.hansson@arm.com    void clearLQ();
1598707Sandreas.hansson@arm.com
1608707Sandreas.hansson@arm.com    /** Clears all the entries in the SQ. */
1618707Sandreas.hansson@arm.com    void clearSQ();
1629608Sandreas.hansson@arm.com
1638707Sandreas.hansson@arm.com    /** Resizes the LQ to a given size. */
1648707Sandreas.hansson@arm.com    void resizeLQ(unsigned size);
1658707Sandreas.hansson@arm.com
1668707Sandreas.hansson@arm.com    /** Resizes the SQ to a given size. */
1678707Sandreas.hansson@arm.com    void resizeSQ(unsigned size);
16810529Smorr@cs.wisc.edu
1698707Sandreas.hansson@arm.com    /** Squashes all instructions younger than a specific sequence number. */
1708707Sandreas.hansson@arm.com    void squash(const InstSeqNum &squashed_num);
1718707Sandreas.hansson@arm.com
1728707Sandreas.hansson@arm.com    /** Returns if there is a memory ordering violation. Value is reset upon
17310529Smorr@cs.wisc.edu     * call to getMemDepViolator().
17410529Smorr@cs.wisc.edu     */
1758707Sandreas.hansson@arm.com    bool violation() { return memDepViolator; }
1768707Sandreas.hansson@arm.com
1778707Sandreas.hansson@arm.com    /** Returns the memory ordering violator. */
1788707Sandreas.hansson@arm.com    DynInstPtr getMemDepViolator();
1798707Sandreas.hansson@arm.com
1808707Sandreas.hansson@arm.com    /** Returns if a load became blocked due to the memory system.  It clears
1818707Sandreas.hansson@arm.com     *  the bool's value upon this being called.
1828975Sandreas.hansson@arm.com     */
1838975Sandreas.hansson@arm.com    bool loadBlocked()
1848707Sandreas.hansson@arm.com    { return isLoadBlocked; }
1859608Sandreas.hansson@arm.com
1869608Sandreas.hansson@arm.com    void clearLoadBlocked()
1879608Sandreas.hansson@arm.com    { isLoadBlocked = false; }
1889608Sandreas.hansson@arm.com
1899608Sandreas.hansson@arm.com    bool isLoadBlockedHandled()
1908707Sandreas.hansson@arm.com    { return loadBlockedHandled; }
19110713Sandreas.hansson@arm.com
1928707Sandreas.hansson@arm.com    void setLoadBlockedHandled()
1938707Sandreas.hansson@arm.com    { loadBlockedHandled = true; }
1948707Sandreas.hansson@arm.com
1958707Sandreas.hansson@arm.com    /** Returns the number of free entries (min of free LQ and SQ entries). */
1968707Sandreas.hansson@arm.com    unsigned numFreeEntries();
1978711Sandreas.hansson@arm.com
1988707Sandreas.hansson@arm.com    /** Returns the number of loads ready to execute. */
1998922Swilliam.wang@arm.com    int numLoadsReady();
2008707Sandreas.hansson@arm.com
2018707Sandreas.hansson@arm.com    /** Returns the number of loads in the LQ. */
2022292SN/A    int numLoads() { return loads; }
20312127Sspwilson2@wisc.edu
2041060SN/A    /** Returns the number of stores in the SQ. */
2052292SN/A    int numStores() { return stores; }
2069180Sandreas.hansson@arm.com
2071060SN/A    /** Returns if either the LQ or SQ is full. */
2081060SN/A    bool isFull() { return lqFull() || sqFull(); }
2099179Sandreas.hansson@arm.com
2101060SN/A    /** Returns if the LQ is full. */
2119179Sandreas.hansson@arm.com    bool lqFull() { return loads >= (LQEntries - 1); }
2121060SN/A
2131060SN/A    /** Returns if the SQ is full. */
2142292SN/A    bool sqFull() { return stores >= (SQEntries - 1); }
2151060SN/A
2161060SN/A    /** Debugging function to dump instructions in the LSQ. */
2171060SN/A    void dumpInsts();
2181060SN/A
2191060SN/A    /** Returns the number of instructions in the LSQ. */
2201060SN/A    unsigned getCount() { return loads + stores; }
2219444SAndreas.Sandberg@ARM.com
22210913Sandreas.sandberg@arm.com    /** Returns if there are any stores to writeback. */
2239444SAndreas.Sandberg@ARM.com    bool hasStoresToWB() { return storesToWB; }
2249444SAndreas.Sandberg@ARM.com
2259444SAndreas.Sandberg@ARM.com    /** Returns the number of stores to writeback. */
2269444SAndreas.Sandberg@ARM.com    int numStoresToWB() { return storesToWB; }
2279444SAndreas.Sandberg@ARM.com
2289444SAndreas.Sandberg@ARM.com    /** Returns if the LSQ unit will writeback on this cycle. */
2299444SAndreas.Sandberg@ARM.com    bool willWB() { return storeQueue[storeWBIdx].canWB &&
2309444SAndreas.Sandberg@ARM.com                        !storeQueue[storeWBIdx].completed &&
2319444SAndreas.Sandberg@ARM.com                        !dcacheInterface->isBlocked(); }
2329444SAndreas.Sandberg@ARM.com
2339444SAndreas.Sandberg@ARM.com  private:
2349444SAndreas.Sandberg@ARM.com    /** Completes the store at the specified index. */
2359444SAndreas.Sandberg@ARM.com    void completeStore(int store_idx);
2369444SAndreas.Sandberg@ARM.com
2379444SAndreas.Sandberg@ARM.com    /** Increments the given store index (circular queue). */
2389444SAndreas.Sandberg@ARM.com    inline void incrStIdx(int &store_idx);
2399444SAndreas.Sandberg@ARM.com    /** Decrements the given store index (circular queue). */
2409444SAndreas.Sandberg@ARM.com    inline void decrStIdx(int &store_idx);
2419444SAndreas.Sandberg@ARM.com    /** Increments the given load index (circular queue). */
2429444SAndreas.Sandberg@ARM.com    inline void incrLdIdx(int &load_idx);
2439444SAndreas.Sandberg@ARM.com    /** Decrements the given load index (circular queue). */
2449444SAndreas.Sandberg@ARM.com    inline void decrLdIdx(int &load_idx);
2459444SAndreas.Sandberg@ARM.com
2469444SAndreas.Sandberg@ARM.com  private:
2479444SAndreas.Sandberg@ARM.com    /** Pointer to the CPU. */
2481060SN/A    FullCPU *cpu;
2492292SN/A
2505595Sgblack@eecs.umich.edu    /** Pointer to the IEW stage. */
2512292SN/A    IEW *iewStage;
2521755SN/A
2531060SN/A    /** Pointer to the D-cache. */
2542292SN/A    MemInterface *dcacheInterface;
25511169Sandreas.hansson@arm.com
2561684SN/A    /** Pointer to the page table. */
25710023Smatt.horsnell@ARM.com//    PageTable *pTable;
25810023Smatt.horsnell@ARM.com
25910023Smatt.horsnell@ARM.com  public:
26010023Smatt.horsnell@ARM.com    struct SQEntry {
26111169Sandreas.hansson@arm.com        /** Constructs an empty store queue entry. */
26210023Smatt.horsnell@ARM.com        SQEntry()
2635358Sgblack@eecs.umich.edu            : inst(NULL), req(NULL), size(0), data(0),
2645358Sgblack@eecs.umich.edu              canWB(0), committed(0), completed(0)
2655358Sgblack@eecs.umich.edu        { }
2665358Sgblack@eecs.umich.edu
2675358Sgblack@eecs.umich.edu        /** Constructs a store queue entry for a given instruction. */
2685358Sgblack@eecs.umich.edu        SQEntry(DynInstPtr &_inst)
2695358Sgblack@eecs.umich.edu            : inst(_inst), req(NULL), size(0), data(0),
2705358Sgblack@eecs.umich.edu              canWB(0), committed(0), completed(0)
2715358Sgblack@eecs.umich.edu        { }
2725358Sgblack@eecs.umich.edu
2735358Sgblack@eecs.umich.edu        /** The store instruction. */
2745358Sgblack@eecs.umich.edu        DynInstPtr inst;
2755358Sgblack@eecs.umich.edu        /** The memory request for the store. */
2765358Sgblack@eecs.umich.edu        MemReqPtr req;
2775358Sgblack@eecs.umich.edu        /** The size of the store. */
2785358Sgblack@eecs.umich.edu        int size;
2792292SN/A        /** The store data. */
2802292SN/A        IntReg data;
2812292SN/A        /** Whether or not the store can writeback. */
2821684SN/A        bool canWB;
2831684SN/A        /** Whether or not the store is committed. */
2842292SN/A        bool committed;
28511169Sandreas.hansson@arm.com        /** Whether or not the store is completed. */
2861060SN/A        bool completed;
28711169Sandreas.hansson@arm.com    };
2889427SAndreas.Sandberg@ARM.com/*
2892834Sksewell@umich.edu    enum Status {
2902834Sksewell@umich.edu        Running,
2912834Sksewell@umich.edu        Idle,
2922834Sksewell@umich.edu        DcacheMissStall,
2932829Sksewell@umich.edu        DcacheMissSwitch
2946221Snate@binkert.org    };
2952875Sksewell@umich.edu*/
2962875Sksewell@umich.edu  private:
2976221Snate@binkert.org    /** The LSQUnit thread id. */
2982829Sksewell@umich.edu    unsigned lsqID;
2992292SN/A
3006221Snate@binkert.org    /** The status of the LSQ unit. */
3011060SN/A//    Status _status;
3022292SN/A
3036221Snate@binkert.org    /** The store queue. */
3042292SN/A    std::vector<SQEntry> storeQueue;
3052292SN/A
30611169Sandreas.hansson@arm.com    /** The load queue. */
3078834Satgutier@umich.edu    std::vector<DynInstPtr> loadQueue;
3088834Satgutier@umich.edu
30911169Sandreas.hansson@arm.com    // Consider making these 16 bits
3102292SN/A    /** The number of LQ entries. */
3112292SN/A    unsigned LQEntries;
31211169Sandreas.hansson@arm.com    /** The number of SQ entries. */
3132292SN/A    unsigned SQEntries;
3142292SN/A
31511169Sandreas.hansson@arm.com    /** The number of load instructions in the LQ. */
3162292SN/A    int loads;
3172292SN/A    /** The number of store instructions in the SQ (excludes those waiting to
3182292SN/A     * writeback).
3192292SN/A     */
32011169Sandreas.hansson@arm.com    int stores;
3212292SN/A    /** The number of store instructions in the SQ waiting to writeback. */
3222292SN/A    int storesToWB;
3232292SN/A
3242292SN/A    /** The index of the head instruction in the LQ. */
3259444SAndreas.Sandberg@ARM.com    int loadHead;
32610913Sandreas.sandberg@arm.com    /** The index of the tail instruction in the LQ. */
3279444SAndreas.Sandberg@ARM.com    int loadTail;
32811168Sandreas.hansson@arm.com
32911168Sandreas.hansson@arm.com    /** The index of the head instruction in the SQ. */
3302864Sktlim@umich.edu    int storeHead;
3312864Sktlim@umich.edu    /** The index of the first instruction that is ready to be written back,
3325595Sgblack@eecs.umich.edu     * and has not yet been written back.
3335595Sgblack@eecs.umich.edu     */
3342292SN/A    int storeWBIdx;
33511877Sbrandon.potter@amd.com    /** The index of the tail instruction in the SQ. */
3362292SN/A    int storeTail;
3372843Sktlim@umich.edu
3382843Sktlim@umich.edu    /// @todo Consider moving to a more advanced model with write vs read ports
33911168Sandreas.hansson@arm.com    /** The number of cache ports available each cycle. */
3402843Sktlim@umich.edu    int cachePorts;
3412843Sktlim@umich.edu
34211168Sandreas.hansson@arm.com    /** The number of used cache ports in this cycle. */
3432292SN/A    int usedPorts;
3449444SAndreas.Sandberg@ARM.com
3459444SAndreas.Sandberg@ARM.com    bool switchedOut;
3469444SAndreas.Sandberg@ARM.com
3479444SAndreas.Sandberg@ARM.com    //list<InstSeqNum> mshrSeqNums;
3489444SAndreas.Sandberg@ARM.com
3499444SAndreas.Sandberg@ARM.com     //Stats::Scalar<> dcacheStallCycles;
3509444SAndreas.Sandberg@ARM.com    Counter lastDcacheStall;
3519444SAndreas.Sandberg@ARM.com
3522843Sktlim@umich.edu    /** Wire to read information from the issue stage time queue. */
3532843Sktlim@umich.edu    typename TimeBuffer<IssueStruct>::wire fromIssue;
35411169Sandreas.hansson@arm.com
3552316SN/A    // Make these per thread?
3562348SN/A    /** Whether or not the LSQ is stalled. */
35711169Sandreas.hansson@arm.com    bool stalled;
3581060SN/A    /** The store that causes the stall due to partial store to load
35911169Sandreas.hansson@arm.com     * forwarding.
3609523SAndreas.Sandberg@ARM.com     */
3611060SN/A    InstSeqNum stallingStoreIsn;
3622316SN/A    /** The index of the above store. */
3632316SN/A    int stallingLoadIdx;
3641060SN/A
3655595Sgblack@eecs.umich.edu    /** Whether or not a load is blocked due to the memory system.  It is
36610417Sandreas.hansson@arm.com     *  cleared when this value is checked via loadBlocked().
3675595Sgblack@eecs.umich.edu     */
3685702Ssaidi@eecs.umich.edu    bool isLoadBlocked;
3696221Snate@binkert.org
3705702Ssaidi@eecs.umich.edu    bool loadBlockedHandled;
3716221Snate@binkert.org
3725702Ssaidi@eecs.umich.edu    InstSeqNum blockedLoadSeqNum;
3735595Sgblack@eecs.umich.edu
3745595Sgblack@eecs.umich.edu    /** The oldest faulting load instruction. */
3755595Sgblack@eecs.umich.edu    DynInstPtr loadFaultInst;
3765595Sgblack@eecs.umich.edu    /** The oldest faulting store instruction. */
37710379Sandreas.hansson@arm.com    DynInstPtr storeFaultInst;
3785595Sgblack@eecs.umich.edu
3795595Sgblack@eecs.umich.edu    /** The oldest load that caused a memory ordering violation. */
3805595Sgblack@eecs.umich.edu    DynInstPtr memDepViolator;
3815595Sgblack@eecs.umich.edu
3822348SN/A    // Will also need how many read/write ports the Dcache has.  Or keep track
3835595Sgblack@eecs.umich.edu    // of that in stage that is one level up, and only call executeLoad/Store
3845595Sgblack@eecs.umich.edu    // the appropriate number of times.
38510698Sandreas.hansson@arm.com/*
3865595Sgblack@eecs.umich.edu    // total number of loads forwaded from LSQ stores
3875595Sgblack@eecs.umich.edu    Stats::Vector<> lsq_forw_loads;
3885595Sgblack@eecs.umich.edu
3895595Sgblack@eecs.umich.edu    // total number of loads ignored due to invalid addresses
3906221Snate@binkert.org    Stats::Vector<> inv_addr_loads;
3915595Sgblack@eecs.umich.edu
3925595Sgblack@eecs.umich.edu    // total number of software prefetches ignored due to invalid addresses
3936221Snate@binkert.org    Stats::Vector<> inv_addr_swpfs;
3946221Snate@binkert.org
3955595Sgblack@eecs.umich.edu    // total non-speculative bogus addresses seen (debug var)
3965595Sgblack@eecs.umich.edu    Counter sim_invalid_addrs;
3975595Sgblack@eecs.umich.edu    Stats::Vector<> fu_busy;  //cumulative fu busy
3985595Sgblack@eecs.umich.edu
3995595Sgblack@eecs.umich.edu    // ready loads blocked due to memory disambiguation
4006221Snate@binkert.org    Stats::Vector<> lsq_blocked_loads;
4015595Sgblack@eecs.umich.edu
40212105Snathanael.premillieu@arm.com    Stats::Scalar<> lsqInversion;
4031060SN/A*/
40412105Snathanael.premillieu@arm.com  public:
4051060SN/A    /** Executes the load at the given index. */
40612105Snathanael.premillieu@arm.com    template <class T>
4072455SN/A    Fault read(MemReqPtr &req, T &data, int load_idx);
40812109SRekai.GonzalezAlberquilla@arm.com
40912109SRekai.GonzalezAlberquilla@arm.com    /** Executes the store at the given index. */
41012109SRekai.GonzalezAlberquilla@arm.com    template <class T>
41112109SRekai.GonzalezAlberquilla@arm.com    Fault write(MemReqPtr &req, T &data, int store_idx);
41212109SRekai.GonzalezAlberquilla@arm.com
41312109SRekai.GonzalezAlberquilla@arm.com    /** Returns the index of the head load instruction. */
41412109SRekai.GonzalezAlberquilla@arm.com    int getLoadHead() { return loadHead; }
41512109SRekai.GonzalezAlberquilla@arm.com    /** Returns the sequence number of the head load instruction. */
41612109SRekai.GonzalezAlberquilla@arm.com    InstSeqNum getLoadHeadSeqNum()
41712109SRekai.GonzalezAlberquilla@arm.com    {
41812109SRekai.GonzalezAlberquilla@arm.com        if (loadQueue[loadHead]) {
41912109SRekai.GonzalezAlberquilla@arm.com            return loadQueue[loadHead]->seqNum;
42012109SRekai.GonzalezAlberquilla@arm.com        } else {
42112109SRekai.GonzalezAlberquilla@arm.com            return 0;
42212109SRekai.GonzalezAlberquilla@arm.com        }
42312109SRekai.GonzalezAlberquilla@arm.com
42412109SRekai.GonzalezAlberquilla@arm.com    }
42512109SRekai.GonzalezAlberquilla@arm.com
42612109SRekai.GonzalezAlberquilla@arm.com    /** Returns the index of the head store instruction. */
42712109SRekai.GonzalezAlberquilla@arm.com    int getStoreHead() { return storeHead; }
42812109SRekai.GonzalezAlberquilla@arm.com    /** Returns the sequence number of the head store instruction. */
42912109SRekai.GonzalezAlberquilla@arm.com    InstSeqNum getStoreHeadSeqNum()
43012109SRekai.GonzalezAlberquilla@arm.com    {
43112109SRekai.GonzalezAlberquilla@arm.com        if (storeQueue[storeHead].inst) {
43212109SRekai.GonzalezAlberquilla@arm.com            return storeQueue[storeHead].inst->seqNum;
43312109SRekai.GonzalezAlberquilla@arm.com        } else {
43412109SRekai.GonzalezAlberquilla@arm.com            return 0;
43512109SRekai.GonzalezAlberquilla@arm.com        }
43612109SRekai.GonzalezAlberquilla@arm.com
43712109SRekai.GonzalezAlberquilla@arm.com    }
43812109SRekai.GonzalezAlberquilla@arm.com
43912109SRekai.GonzalezAlberquilla@arm.com    /** Returns whether or not the LSQ unit is stalled. */
44012109SRekai.GonzalezAlberquilla@arm.com    bool isStalled()  { return stalled; }
44112109SRekai.GonzalezAlberquilla@arm.com};
44212109SRekai.GonzalezAlberquilla@arm.com
44312109SRekai.GonzalezAlberquilla@arm.comtemplate <class Impl>
44412109SRekai.GonzalezAlberquilla@arm.comtemplate <class T>
44512109SRekai.GonzalezAlberquilla@arm.comFault
44612109SRekai.GonzalezAlberquilla@arm.comLSQUnit<Impl>::read(MemReqPtr &req, T &data, int load_idx)
44712109SRekai.GonzalezAlberquilla@arm.com{
44812105Snathanael.premillieu@arm.com    //Depending on issue2execute delay a squashed load could
4499920Syasuko.eckert@amd.com    //execute if it is found to be squashed in the same
45012105Snathanael.premillieu@arm.com    //cycle it is scheduled to execute
4511060SN/A    assert(loadQueue[load_idx]);
45212105Snathanael.premillieu@arm.com
4531060SN/A    if (loadQueue[load_idx]->isExecuted()) {
45412105Snathanael.premillieu@arm.com        panic("Should not reach this point with split ops!");
4552455SN/A        memcpy(&data,req->data,req->size);
45612109SRekai.GonzalezAlberquilla@arm.com
45712109SRekai.GonzalezAlberquilla@arm.com        return NoFault;
45812109SRekai.GonzalezAlberquilla@arm.com    }
45912109SRekai.GonzalezAlberquilla@arm.com
46012105Snathanael.premillieu@arm.com    // Make sure this isn't an uncacheable access
4619920Syasuko.eckert@amd.com    // A bit of a hackish way to get uncached accesses to work only if they're
4626221Snate@binkert.org    // at the head of the LSQ and are ready to commit (at the head of the ROB
4631060SN/A    // too).
4646314Sgblack@eecs.umich.edu    // @todo: Fix uncached accesses.
4652292SN/A    if (req->flags & UNCACHEABLE &&
4666221Snate@binkert.org        (load_idx != loadHead || !loadQueue[load_idx]->reachedCommit)) {
4672292SN/A        iewStage->rescheduleMemInst(loadQueue[load_idx]);
46812109SRekai.GonzalezAlberquilla@arm.com        return TheISA::genMachineCheckFault();
46912109SRekai.GonzalezAlberquilla@arm.com    }
47012109SRekai.GonzalezAlberquilla@arm.com
47112109SRekai.GonzalezAlberquilla@arm.com    // Check the SQ for any previous stores that might lead to forwarding
47212109SRekai.GonzalezAlberquilla@arm.com    int store_idx = loadQueue[load_idx]->sqIdx;
47312109SRekai.GonzalezAlberquilla@arm.com
47412109SRekai.GonzalezAlberquilla@arm.com    int store_size = 0;
47512109SRekai.GonzalezAlberquilla@arm.com
47612109SRekai.GonzalezAlberquilla@arm.com    DPRINTF(LSQUnit, "Read called, load idx: %i, store idx: %i, "
47712109SRekai.GonzalezAlberquilla@arm.com            "storeHead: %i addr: %#x\n",
47812109SRekai.GonzalezAlberquilla@arm.com            load_idx, store_idx, storeHead, req->paddr);
47912109SRekai.GonzalezAlberquilla@arm.com
48012109SRekai.GonzalezAlberquilla@arm.com#ifdef FULL_SYSTEM
48112109SRekai.GonzalezAlberquilla@arm.com    if (req->flags & LOCKED) {
48212109SRekai.GonzalezAlberquilla@arm.com        cpu->lockAddr = req->paddr;
48312109SRekai.GonzalezAlberquilla@arm.com        cpu->lockFlag = true;
48412109SRekai.GonzalezAlberquilla@arm.com    }
48512109SRekai.GonzalezAlberquilla@arm.com#endif
48612109SRekai.GonzalezAlberquilla@arm.com
48712109SRekai.GonzalezAlberquilla@arm.com    while (store_idx != -1) {
48812109SRekai.GonzalezAlberquilla@arm.com        // End once we've reached the top of the LSQ
48912109SRekai.GonzalezAlberquilla@arm.com        if (store_idx == storeWBIdx) {
49012109SRekai.GonzalezAlberquilla@arm.com            break;
49112109SRekai.GonzalezAlberquilla@arm.com        }
49212109SRekai.GonzalezAlberquilla@arm.com
49312109SRekai.GonzalezAlberquilla@arm.com        // Move the index to one younger
49412109SRekai.GonzalezAlberquilla@arm.com        if (--store_idx < 0)
49512109SRekai.GonzalezAlberquilla@arm.com            store_idx += SQEntries;
4969920Syasuko.eckert@amd.com
4979920Syasuko.eckert@amd.com        assert(storeQueue[store_idx].inst);
4982348SN/A
4992348SN/A        store_size = storeQueue[store_idx].size;
5002348SN/A
5012348SN/A        if (store_size == 0)
5022348SN/A            continue;
5036221Snate@binkert.org
5042292SN/A        // Check if the store data is within the lower and upper bounds of
5056314Sgblack@eecs.umich.edu        // addresses that the request needs.
5062292SN/A        bool store_has_lower_limit =
5076221Snate@binkert.org            req->vaddr >= storeQueue[store_idx].inst->effAddr;
5082292SN/A        bool store_has_upper_limit =
50912109SRekai.GonzalezAlberquilla@arm.com            (req->vaddr + req->size) <= (storeQueue[store_idx].inst->effAddr +
51012109SRekai.GonzalezAlberquilla@arm.com                                         store_size);
51112109SRekai.GonzalezAlberquilla@arm.com        bool lower_load_has_store_part =
51212109SRekai.GonzalezAlberquilla@arm.com            req->vaddr < (storeQueue[store_idx].inst->effAddr +
51312109SRekai.GonzalezAlberquilla@arm.com                           store_size);
5149920Syasuko.eckert@amd.com        bool upper_load_has_store_part =
5159920Syasuko.eckert@amd.com            (req->vaddr + req->size) > storeQueue[store_idx].inst->effAddr;
5167720Sgblack@eecs.umich.edu
5177720Sgblack@eecs.umich.edu        // If the store's data has all of the data needed, we can forward.
5187720Sgblack@eecs.umich.edu        if (store_has_lower_limit && store_has_upper_limit) {
5197720Sgblack@eecs.umich.edu
5207720Sgblack@eecs.umich.edu            int shift_amt = req->vaddr & (store_size - 1);
5217720Sgblack@eecs.umich.edu            // Assumes byte addressing
5222348SN/A            shift_amt = shift_amt << 3;
5237720Sgblack@eecs.umich.edu
5242292SN/A            // Cast this to type T?
5254636Sgblack@eecs.umich.edu            data = storeQueue[store_idx].data >> shift_amt;
5267720Sgblack@eecs.umich.edu
5274636Sgblack@eecs.umich.edu            req->cmd = Read;
5282348SN/A            assert(!req->completionEvent);
5297720Sgblack@eecs.umich.edu            req->completionEvent = NULL;
5302756Sksewell@umich.edu            req->time = curTick;
5315595Sgblack@eecs.umich.edu            assert(!req->data);
5325595Sgblack@eecs.umich.edu            req->data = new uint8_t[64];
5335595Sgblack@eecs.umich.edu
5345595Sgblack@eecs.umich.edu            memcpy(req->data, &data, req->size);
5356221Snate@binkert.org
5365595Sgblack@eecs.umich.edu            DPRINTF(LSQUnit, "Forwarding from store idx %i to load to "
5371060SN/A                    "addr %#x, data %#x\n",
5381060SN/A                    store_idx, req->vaddr, *(req->data));
5391060SN/A
5402292SN/A            typename IEW::LdWritebackEvent *wb =
5411060SN/A                new typename IEW::LdWritebackEvent(loadQueue[load_idx],
5421060SN/A                                                   iewStage);
5438834Satgutier@umich.edu
5441060SN/A            // We'll say this has a 1 cycle load-store forwarding latency
5452325SN/A            // for now.
5462325SN/A            // @todo: Need to make this a parameter.
5471060SN/A            wb->schedule(curTick);
5481061SN/A
5491060SN/A            // Should keep track of stat for forwarded data
5502935Sksewell@umich.edu            return NoFault;
5512935Sksewell@umich.edu        } else if ((store_has_lower_limit && lower_load_has_store_part) ||
5526221Snate@binkert.org                   (store_has_upper_limit && upper_load_has_store_part) ||
5531060SN/A                   (lower_load_has_store_part && upper_load_has_store_part)) {
5541062SN/A            // This is the partial store-load forwarding case where a store
5556221Snate@binkert.org            // has only part of the load's data.
5562292SN/A
5572348SN/A            // If it's already been written back, then don't worry about
5586221Snate@binkert.org            // stalling on it.
5592292SN/A            if (storeQueue[store_idx].completed) {
5602348SN/A                continue;
5612292SN/A            }
5621062SN/A
5632348SN/A            // Must stall load and force it to retry, so long as it's the oldest
5641060SN/A            // load that needs to do so.
5651060SN/A            if (!stalled ||
5661060SN/A                (stalled &&
5675737Scws3k@cs.virginia.edu                 loadQueue[load_idx]->seqNum <
5685737Scws3k@cs.virginia.edu                 loadQueue[stallingLoadIdx]->seqNum)) {
5695737Scws3k@cs.virginia.edu                stalled = true;
5705737Scws3k@cs.virginia.edu                stallingStoreIsn = storeQueue[store_idx].inst->seqNum;
5715737Scws3k@cs.virginia.edu                stallingLoadIdx = load_idx;
5721060SN/A            }
5732292SN/A
5741060SN/A            // Tell IQ/mem dep unit that this instruction will need to be
5752292SN/A            // rescheduled eventually
5762292SN/A            iewStage->rescheduleMemInst(loadQueue[load_idx]);
5772292SN/A
5782292SN/A            // Do not generate a writeback event as this instruction is not
5792292SN/A            // complete.
5802325SN/A
5812348SN/A            DPRINTF(LSQUnit, "Load-store forwarding mis-match. "
5822348SN/A                    "Store idx %i to load addr %#x\n",
5832348SN/A                    store_idx, req->vaddr);
5842292SN/A
5852325SN/A            return NoFault;
5862292SN/A        }
5872325SN/A    }
5882325SN/A
5892292SN/A
5902292SN/A    // If there's no forwarding case, then go access memory
5912292SN/A    DynInstPtr inst = loadQueue[load_idx];
5921060SN/A
5931060SN/A    DPRINTF(LSQUnit, "Doing functional access for inst PC %#x\n",
5941060SN/A            loadQueue[load_idx]->readPC());
5951060SN/A    assert(!req->data);
5961060SN/A    req->cmd = Read;
5971060SN/A    req->completionEvent = NULL;
5981060SN/A    req->time = curTick;
5991060SN/A    req->data = new uint8_t[64];
6001060SN/A    Fault fault = cpu->read(req, data);
6011060SN/A    memcpy(req->data, &data, sizeof(T));
6021060SN/A
6031060SN/A    ++usedPorts;
6041060SN/A
6051060SN/A    // if we have a cache, do cache access too
6061060SN/A    if (fault == NoFault && dcacheInterface) {
6071060SN/A        if (dcacheInterface->isBlocked()) {
60812109SRekai.GonzalezAlberquilla@arm.com            // There's an older load that's already going to squash.
60912109SRekai.GonzalezAlberquilla@arm.com            if (isLoadBlocked && blockedLoadSeqNum < inst->seqNum)
61012109SRekai.GonzalezAlberquilla@arm.com                return NoFault;
6111060SN/A
6129919Ssteve.reinhardt@amd.com            isLoadBlocked = true;
6131060SN/A            loadBlockedHandled = false;
6141060SN/A            blockedLoadSeqNum = inst->seqNum;
6151060SN/A            // No fault occurred, even though the interface is blocked.
6161060SN/A            return NoFault;
6171060SN/A        }
6182292SN/A        DPRINTF(LSQUnit, "Doing timing access for inst PC %#x\n",
6192292SN/A                loadQueue[load_idx]->readPC());
6202292SN/A/*
6212292SN/A        Addr debug_addr = ULL(0xfffffc0000be81a8);
6221060SN/A        if (req->vaddr == debug_addr) {
6231060SN/A            debug_break();
6241060SN/A        }
6251060SN/A*/
6262292SN/A        assert(!req->completionEvent);
6276221Snate@binkert.org        req->completionEvent =
6282292SN/A            new typename IEW::LdWritebackEvent(loadQueue[load_idx], iewStage);
6292292SN/A        MemAccessResult result = dcacheInterface->access(req);
6302292SN/A
6312292SN/A        assert(dcacheInterface->doEvents());
6329384SAndreas.Sandberg@arm.com
6336313Sgblack@eecs.umich.edu        // Ugly hack to get an event scheduled *only* if the access is
6348707Sandreas.hansson@arm.com        // a miss.  We really should add first-class support for this
6358707Sandreas.hansson@arm.com        // at some point.
6368707Sandreas.hansson@arm.com        if (result != MA_HIT) {
6378707Sandreas.hansson@arm.com            DPRINTF(LSQUnit, "LSQUnit: D-cache miss!\n");
6388707Sandreas.hansson@arm.com            DPRINTF(Activity, "Activity: ld accessing mem miss [sn:%lli]\n",
6398707Sandreas.hansson@arm.com                    inst->seqNum);
6401060SN/A
6412292SN/A            lastDcacheStall = curTick;
6422292SN/A
6432292SN/A//            _status = DcacheMissStall;
6442292SN/A
6452292SN/A        } else {
6462292SN/A            DPRINTF(Activity, "Activity: ld accessing mem hit [sn:%lli]\n",
6472292SN/A                    inst->seqNum);
6482292SN/A
6492292SN/A            DPRINTF(LSQUnit, "LSQUnit: D-cache hit!\n");
6502292SN/A        }
6512292SN/A    }
6522292SN/A#if 0
6531060SN/A    // if we have a cache, do cache access too
6541060SN/A    if (dcacheInterface) {
6551060SN/A        if (dcacheInterface->isBlocked()) {
6561061SN/A            isLoadBlocked = true;
6571060SN/A            // No fault occurred, even though the interface is blocked.
6581061SN/A            return NoFault;
6591060SN/A        }
6601061SN/A
6611060SN/A        DPRINTF(LSQUnit, "LSQUnit: D-cache: PC:%#x reading from paddr:%#x "
6621061SN/A                "vaddr:%#x flags:%i\n",
6631060SN/A                inst->readPC(), req->paddr, req->vaddr, req->flags);
6641061SN/A
6651060SN/A        // Setup MemReq pointer
6661060SN/A        req->cmd = Read;
6671060SN/A        req->completionEvent = NULL;
6681060SN/A        req->time = curTick;
6691060SN/A        assert(!req->data);
6701060SN/A        req->data = new uint8_t[64];
6711060SN/A
6721060SN/A        assert(!req->completionEvent);
6731060SN/A        req->completionEvent =
6741060SN/A            new typename IEW::LdWritebackEvent(loadQueue[load_idx], iewStage);
6751060SN/A
6761060SN/A        // Do Cache Access
6771060SN/A        MemAccessResult result = dcacheInterface->access(req);
6781060SN/A
6791060SN/A        // Ugly hack to get an event scheduled *only* if the access is
6801060SN/A        // a miss.  We really should add first-class support for this
6812348SN/A        // at some point.
6822348SN/A        // @todo: Probably should support having no events
6832348SN/A        if (result != MA_HIT) {
6842348SN/A            DPRINTF(LSQUnit, "LSQUnit: D-cache miss!\n");
6852348SN/A            DPRINTF(Activity, "Activity: ld accessing mem miss [sn:%lli]\n",
6862325SN/A                    inst->seqNum);
6871060SN/A
6882348SN/A            lastDcacheStall = curTick;
6892348SN/A
6902325SN/A            _status = DcacheMissStall;
6912292SN/A
6922348SN/A        } else {
6932325SN/A            DPRINTF(Activity, "Activity: ld accessing mem hit [sn:%lli]\n",
6942325SN/A                    inst->seqNum);
6952292SN/A
6962348SN/A            DPRINTF(LSQUnit, "LSQUnit: D-cache hit!\n");
6972325SN/A        }
6982325SN/A    } else {
6992292SN/A        fatal("Must use D-cache with new memory system");
7002292SN/A    }
7012292SN/A#endif
7022260SN/A
70311168Sandreas.hansson@arm.com    return fault;
7045807Snate@binkert.org}
7052292SN/A
7066221Snate@binkert.orgtemplate <class Impl>
7072292SN/Atemplate <class T>
7082292SN/AFault
7092680Sktlim@umich.eduLSQUnit<Impl>::write(MemReqPtr &req, T &data, int store_idx)
7106221Snate@binkert.org{
7116221Snate@binkert.org    assert(storeQueue[store_idx].inst);
7121681SN/A
7132680Sktlim@umich.edu    DPRINTF(LSQUnit, "Doing write to store idx %i, addr %#x data %#x"
7142190SN/A            " | storeHead:%i [sn:%i]\n",
7152190SN/A            store_idx, req->paddr, data, storeHead,
7162292SN/A            storeQueue[store_idx].inst->seqNum);
7173093Sksewell@umich.edu/*
7181060SN/A    if (req->flags & LOCKED) {
7192348SN/A        if (req->flags & UNCACHEABLE) {
7202348SN/A            req->result = 2;
7212348SN/A        } else {
7222348SN/A            req->result = 1;
7238733Sgeoffrey.blake@arm.com        }
7242316SN/A    }
7252292SN/A*/
7261060SN/A    storeQueue[store_idx].req = req;
7271060SN/A    storeQueue[store_idx].size = sizeof(T);
7282348SN/A    storeQueue[store_idx].data = data;
7292292SN/A/*
7302260SN/A    Addr debug_addr = ULL(0xfffffc0000be81a8);
7312292SN/A    if (req->vaddr == debug_addr) {
7322292SN/A        debug_break();
7332292SN/A    }
7342292SN/A*/
7359180Sandreas.hansson@arm.com    // This function only writes the data to the store queue, so no fault
7362292SN/A    // can happen here.
7372829Sksewell@umich.edu    return NoFault;
7382829Sksewell@umich.edu}
7392829Sksewell@umich.edu
7402292SN/A#endif // __CPU_O3_LSQ_UNIT_HH__
7416221Snate@binkert.org