lsq_unit.hh revision 2348
12292SN/A/*
212355Snikos.nikoleris@arm.com * Copyright (c) 2004-2006 The Regents of The University of Michigan
39444SAndreas.Sandberg@ARM.com * All rights reserved.
49444SAndreas.Sandberg@ARM.com *
59444SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without
69444SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are
79444SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright
89444SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer;
99444SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright
109444SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the
119444SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution;
129444SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its
139444SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from
142329SN/A * this software without specific prior written permission.
1510239Sbinhpham@cs.rutgers.edu *
162292SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182292SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192292SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202292SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212292SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222292SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232292SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242292SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252292SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262292SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272292SN/A */
282292SN/A
292292SN/A#ifndef __CPU_O3_LSQ_UNIT_HH__
302292SN/A#define __CPU_O3_LSQ_UNIT_HH__
312292SN/A
322292SN/A#include <algorithm>
332292SN/A#include <map>
342292SN/A#include <queue>
352292SN/A
362292SN/A#include "arch/faults.hh"
372292SN/A#include "config/full_system.hh"
382292SN/A#include "base/hashmap.hh"
392292SN/A#include "cpu/inst_seq.hh"
402689Sktlim@umich.edu#include "mem/mem_interface.hh"
412689Sktlim@umich.edu//#include "mem/page_table.hh"
422689Sktlim@umich.edu//#include "sim/debug.hh"
432292SN/A//#include "sim/sim_object.hh"
442292SN/A
452292SN/A/**
462292SN/A * Class that implements the actual LQ and SQ for each specific
472292SN/A * thread.  Both are circular queues; load entries are freed upon
482329SN/A * committing, while store entries are freed once they writeback. The
494395Ssaidi@eecs.umich.edu * LSQUnit tracks if there are memory ordering violations, and also
502292SN/A * detects partial load to store forwarding cases (a store only has
512292SN/A * part of a load's data) that requires the load to wait until the
522292SN/A * store writes back. In the former case it holds onto the instruction
538591Sgblack@eecs.umich.edu * until the dependence unit looks at it, and in the latter it stalls
548506Sgblack@eecs.umich.edu * the LSQ until the store writes back. At that point the load is
553326Sktlim@umich.edu * replayed.
568481Sgblack@eecs.umich.edu */
576658Snate@binkert.orgtemplate <class Impl>
582292SN/Aclass LSQUnit {
598230Snate@binkert.org  protected:
608232Snate@binkert.org    typedef TheISA::IntReg IntReg;
613348Sbinkertn@umich.edu  public:
622669Sktlim@umich.edu    typedef typename Impl::Params Params;
632292SN/A    typedef typename Impl::FullCPU FullCPU;
648737Skoansin.tan@gmail.com    typedef typename Impl::DynInstPtr DynInstPtr;
655529Snate@binkert.org    typedef typename Impl::CPUPol::IEW IEW;
662292SN/A    typedef typename Impl::CPUPol::IssueStruct IssueStruct;
672329SN/A
682329SN/A  private:
692329SN/A    class StoreCompletionEvent : public Event {
702329SN/A      public:
712329SN/A        /** Constructs a store completion event. */
722329SN/A        StoreCompletionEvent(int store_idx, Event *wb_event, LSQUnit *lsq_ptr);
732329SN/A
742329SN/A        /** Processes the store completion event. */
752329SN/A        void process();
762329SN/A
772292SN/A        /** Returns the description of this event. */
782292SN/A        const char *description();
792292SN/A
802292SN/A        /** The writeback event for the store.  Needed for store
812733Sktlim@umich.edu         * conditionals.
822292SN/A         */
832292SN/A        Event *wbEvent;
842907Sktlim@umich.edu
852292SN/A      private:
862292SN/A        /** The store index of the store being written back. */
872292SN/A        int storeIdx;
882292SN/A      private:
8913472Srekai.gonzalezalberquilla@arm.com        /** The pointer to the LSQ unit that issued the store. */
9013472Srekai.gonzalezalberquilla@arm.com        LSQUnit<Impl> *lsqPtr;
9113472Srekai.gonzalezalberquilla@arm.com    };
9213472Srekai.gonzalezalberquilla@arm.com
9313472Srekai.gonzalezalberquilla@arm.com  public:
9413472Srekai.gonzalezalberquilla@arm.com    /** Constructs an LSQ unit. init() must be called prior to use. */
9513472Srekai.gonzalezalberquilla@arm.com    LSQUnit();
962292SN/A
972292SN/A    /** Initializes the LSQ unit with the specified number of entries. */
985529Snate@binkert.org    void init(Params *params, unsigned maxLQEntries,
9913472Srekai.gonzalezalberquilla@arm.com              unsigned maxSQEntries, unsigned id);
1002292SN/A
1012292SN/A    /** Returns the name of the LSQ unit. */
1022292SN/A    std::string name() const;
1032292SN/A
1042727Sktlim@umich.edu    /** Sets the CPU pointer. */
1052727Sktlim@umich.edu    void setCPU(FullCPU *cpu_ptr)
1062727Sktlim@umich.edu    { cpu = cpu_ptr; }
1072907Sktlim@umich.edu
1088922Swilliam.wang@arm.com    /** Sets the IEW stage pointer. */
1092907Sktlim@umich.edu    void setIEW(IEW *iew_ptr)
1109444SAndreas.Sandberg@ARM.com    { iewStage = iew_ptr; }
1119444SAndreas.Sandberg@ARM.com
1122307SN/A    /** Sets the page table pointer. */
1132348SN/A//    void setPageTable(PageTable *pt_ptr);
1142307SN/A
1152307SN/A    /** Switches out LSQ unit. */
1162292SN/A    void switchOut();
1172292SN/A
1182292SN/A    /** Takes over from another CPU's thread. */
1192292SN/A    void takeOverFrom();
1202292SN/A
12111780Sarthur.perais@inria.fr    /** Returns if the LSQ is switched out. */
1222292SN/A    bool isSwitchedOut() { return switchedOut; }
1232292SN/A
12413429Srekai.gonzalezalberquilla@arm.com    /** Ticks the LSQ unit, which in this case only resets the number of
1252292SN/A     * used cache ports.
12613429Srekai.gonzalezalberquilla@arm.com     * @todo: Move the number of used ports up to the LSQ level so it can
1272292SN/A     * be shared by all LSQ units.
12813429Srekai.gonzalezalberquilla@arm.com     */
1292292SN/A    void tick() { usedPorts = 0; }
1308545Ssaidi@eecs.umich.edu
1318545Ssaidi@eecs.umich.edu    /** Inserts an instruction. */
1328545Ssaidi@eecs.umich.edu    void insert(DynInstPtr &inst);
1338199SAli.Saidi@ARM.com    /** Inserts a load instruction. */
1348199SAli.Saidi@ARM.com    void insertLoad(DynInstPtr &load_inst);
1358199SAli.Saidi@ARM.com    /** Inserts a store instruction. */
13613429Srekai.gonzalezalberquilla@arm.com    void insertStore(DynInstPtr &store_inst);
1378199SAli.Saidi@ARM.com
1388545Ssaidi@eecs.umich.edu    /** Executes a load instruction. */
1398545Ssaidi@eecs.umich.edu    Fault executeLoad(DynInstPtr &inst);
1408545Ssaidi@eecs.umich.edu
1418545Ssaidi@eecs.umich.edu    Fault executeLoad(int lq_idx) { panic("Not implemented"); return NoFault; }
1428545Ssaidi@eecs.umich.edu    /** Executes a store instruction. */
1438545Ssaidi@eecs.umich.edu    Fault executeStore(DynInstPtr &inst);
1442292SN/A
14513429Srekai.gonzalezalberquilla@arm.com    /** Commits the head load. */
1462292SN/A    void commitLoad();
1472329SN/A    /** Commits loads older than a specific sequence number. */
1482292SN/A    void commitLoads(InstSeqNum &youngest_inst);
14913429Srekai.gonzalezalberquilla@arm.com
1502292SN/A    /** Commits stores older than a specific sequence number. */
1512292SN/A    void commitStores(InstSeqNum &youngest_inst);
1522292SN/A
1532292SN/A    /** Writes back stores. */
1542292SN/A    void writebackStores();
1552292SN/A
1562292SN/A    // @todo: Include stats in the LSQ unit.
1572292SN/A    //void regStats();
1582292SN/A
1592292SN/A    /** Clears all the entries in the LQ. */
1602292SN/A    void clearLQ();
1612292SN/A
1622790Sktlim@umich.edu    /** Clears all the entries in the SQ. */
1632790Sktlim@umich.edu    void clearSQ();
1642669Sktlim@umich.edu
1652669Sktlim@umich.edu    /** Resizes the LQ to a given size. */
1662292SN/A    void resizeLQ(unsigned size);
1672292SN/A
1682292SN/A    /** Resizes the SQ to a given size. */
1692292SN/A    void resizeSQ(unsigned size);
1702292SN/A
1712292SN/A    /** Squashes all instructions younger than a specific sequence number. */
1722292SN/A    void squash(const InstSeqNum &squashed_num);
1732292SN/A
1742292SN/A    /** Returns if there is a memory ordering violation. Value is reset upon
1752292SN/A     * call to getMemDepViolator().
1762292SN/A     */
1772292SN/A    bool violation() { return memDepViolator; }
1782292SN/A
1792292SN/A    /** Returns the memory ordering violator. */
1802292SN/A    DynInstPtr getMemDepViolator();
1812292SN/A
1822292SN/A    /** Returns if a load became blocked due to the memory system. */
1832292SN/A    bool loadBlocked()
1842292SN/A    { return isLoadBlocked; }
1852292SN/A
1862292SN/A    /** Clears the signal that a load became blocked. */
1872292SN/A    void clearLoadBlocked()
1882292SN/A    { isLoadBlocked = false; }
18910239Sbinhpham@cs.rutgers.edu
19010239Sbinhpham@cs.rutgers.edu    /** Returns if the blocked load was handled. */
19110239Sbinhpham@cs.rutgers.edu    bool isLoadBlockedHandled()
19210239Sbinhpham@cs.rutgers.edu    { return loadBlockedHandled; }
19310239Sbinhpham@cs.rutgers.edu
1942292SN/A    /** Records the blocked load as being handled. */
1952292SN/A    void setLoadBlockedHandled()
1962292SN/A    { loadBlockedHandled = true; }
1972292SN/A
1982292SN/A    /** Returns the number of free entries (min of free LQ and SQ entries). */
1992292SN/A    unsigned numFreeEntries();
2002292SN/A
2012292SN/A    /** Returns the number of loads ready to execute. */
2022292SN/A    int numLoadsReady();
2032292SN/A
2049444SAndreas.Sandberg@ARM.com    /** Returns the number of loads in the LQ. */
2059444SAndreas.Sandberg@ARM.com    int numLoads() { return loads; }
2069444SAndreas.Sandberg@ARM.com
2072292SN/A    /** Returns the number of stores in the SQ. */
2082292SN/A    int numStores() { return stores; }
2092292SN/A
2102292SN/A    /** Returns if either the LQ or SQ is full. */
2112292SN/A    bool isFull() { return lqFull() || sqFull(); }
2122292SN/A
2139444SAndreas.Sandberg@ARM.com    /** Returns if the LQ is full. */
2149444SAndreas.Sandberg@ARM.com    bool lqFull() { return loads >= (LQEntries - 1); }
2159444SAndreas.Sandberg@ARM.com
2169444SAndreas.Sandberg@ARM.com    /** Returns if the SQ is full. */
2179444SAndreas.Sandberg@ARM.com    bool sqFull() { return stores >= (SQEntries - 1); }
2189444SAndreas.Sandberg@ARM.com
2192292SN/A    /** Returns the number of instructions in the LSQ. */
2202292SN/A    unsigned getCount() { return loads + stores; }
2212292SN/A
2222292SN/A    /** Returns if there are any stores to writeback. */
2232292SN/A    bool hasStoresToWB() { return storesToWB; }
2242292SN/A
2252292SN/A    /** Returns the number of stores to writeback. */
2262292SN/A    int numStoresToWB() { return storesToWB; }
2272292SN/A
2282292SN/A    /** Returns if the LSQ unit will writeback on this cycle. */
2292292SN/A    bool willWB() { return storeQueue[storeWBIdx].canWB &&
2302678Sktlim@umich.edu                        !storeQueue[storeWBIdx].completed &&
2312678Sktlim@umich.edu                        !dcacheInterface->isBlocked(); }
2322292SN/A
2332907Sktlim@umich.edu  private:
2342907Sktlim@umich.edu    /** Completes the store at the specified index. */
2352907Sktlim@umich.edu    void completeStore(int store_idx);
2362292SN/A
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). */
2402698Sktlim@umich.edu    inline void decrStIdx(int &store_idx);
24113429Srekai.gonzalezalberquilla@arm.com    /** Increments the given load index (circular queue). */
2422678Sktlim@umich.edu    inline void incrLdIdx(int &load_idx);
2436974Stjones1@inf.ed.ac.uk    /** Decrements the given load index (circular queue). */
2446974Stjones1@inf.ed.ac.uk    inline void decrLdIdx(int &load_idx);
2456974Stjones1@inf.ed.ac.uk
2462698Sktlim@umich.edu  public:
2473349Sbinkertn@umich.edu    /** Debugging function to dump instructions in the LSQ. */
2482693Sktlim@umich.edu    void dumpInsts();
2492292SN/A
2502292SN/A  private:
2512292SN/A    /** Pointer to the CPU. */
2526974Stjones1@inf.ed.ac.uk    FullCPU *cpu;
2536974Stjones1@inf.ed.ac.uk
2546974Stjones1@inf.ed.ac.uk    /** Pointer to the IEW stage. */
2552292SN/A    IEW *iewStage;
2569440SAndreas.Sandberg@ARM.com
2572292SN/A    /** Pointer to the D-cache. */
2589440SAndreas.Sandberg@ARM.com    MemInterface *dcacheInterface;
2592292SN/A
2609440SAndreas.Sandberg@ARM.com    /** Pointer to the page table. */
2612292SN/A//    PageTable *pTable;
2629440SAndreas.Sandberg@ARM.com
2632292SN/A  public:
2642329SN/A    struct SQEntry {
2652329SN/A        /** Constructs an empty store queue entry. */
2669440SAndreas.Sandberg@ARM.com        SQEntry()
2672329SN/A            : inst(NULL), req(NULL), size(0), data(0),
2682292SN/A              canWB(0), committed(0), completed(0)
2692292SN/A        { }
2702733Sktlim@umich.edu
2712292SN/A        /** Constructs a store queue entry for a given instruction. */
2722292SN/A        SQEntry(DynInstPtr &_inst)
2732292SN/A            : inst(_inst), req(NULL), size(0), data(0),
2742292SN/A              canWB(0), committed(0), completed(0)
2752907Sktlim@umich.edu        { }
2762907Sktlim@umich.edu
2772669Sktlim@umich.edu        /** The store instruction. */
2782907Sktlim@umich.edu        DynInstPtr inst;
2798922Swilliam.wang@arm.com        /** The memory request for the store. */
2802292SN/A        MemReqPtr req;
2812698Sktlim@umich.edu        /** The size of the store. */
2829044SAli.Saidi@ARM.com        int size;
2832678Sktlim@umich.edu        /** The store data. */
2842678Sktlim@umich.edu        IntReg data;
2852698Sktlim@umich.edu        /** Whether or not the store can writeback. */
2862678Sktlim@umich.edu        bool canWB;
28710537Sandreas.hansson@arm.com        /** Whether or not the store is committed. */
28810537Sandreas.hansson@arm.com        bool committed;
28910537Sandreas.hansson@arm.com        /** Whether or not the store is completed. */
2909046SAli.Saidi@ARM.com        bool completed;
2912678Sktlim@umich.edu    };
2922698Sktlim@umich.edu
2932678Sktlim@umich.edu  private:
2949046SAli.Saidi@ARM.com    /** The LSQUnit thread id. */
2959046SAli.Saidi@ARM.com    unsigned lsqID;
2969046SAli.Saidi@ARM.com
2979046SAli.Saidi@ARM.com    /** The store queue. */
2989046SAli.Saidi@ARM.com    std::vector<SQEntry> storeQueue;
2999046SAli.Saidi@ARM.com
3009046SAli.Saidi@ARM.com    /** The load queue. */
3019046SAli.Saidi@ARM.com    std::vector<DynInstPtr> loadQueue;
3022698Sktlim@umich.edu
3032678Sktlim@umich.edu    /** The number of LQ entries, plus a sentinel entry (circular queue).
3042698Sktlim@umich.edu     *  @todo: Consider having var that records the true number of LQ entries.
3052678Sktlim@umich.edu     */
3066974Stjones1@inf.ed.ac.uk    unsigned LQEntries;
3076974Stjones1@inf.ed.ac.uk    /** The number of SQ entries, plus a sentinel entry (circular queue).
3086974Stjones1@inf.ed.ac.uk     *  @todo: Consider having var that records the true number of SQ entries.
3096974Stjones1@inf.ed.ac.uk     */
31010333Smitch.hayenga@arm.com    unsigned SQEntries;
31110333Smitch.hayenga@arm.com
3126974Stjones1@inf.ed.ac.uk    /** The number of load instructions in the LQ. */
3136974Stjones1@inf.ed.ac.uk    int loads;
3146974Stjones1@inf.ed.ac.uk    /** The number of store instructions in the SQ. */
3152678Sktlim@umich.edu    int stores;
3162678Sktlim@umich.edu    /** The number of store instructions in the SQ waiting to writeback. */
3172698Sktlim@umich.edu    int storesToWB;
3182678Sktlim@umich.edu
3192678Sktlim@umich.edu    /** The index of the head instruction in the LQ. */
3202678Sktlim@umich.edu    int loadHead;
32113429Srekai.gonzalezalberquilla@arm.com    /** The index of the tail instruction in the LQ. */
32213429Srekai.gonzalezalberquilla@arm.com    int loadTail;
3232678Sktlim@umich.edu
3242678Sktlim@umich.edu    /** The index of the head instruction in the SQ. */
3252678Sktlim@umich.edu    int storeHead;
3262678Sktlim@umich.edu    /** The index of the first instruction that may be ready to be
3272678Sktlim@umich.edu     * written back, and has not yet been written back.
3285336Shines@cs.fsu.edu     */
3292678Sktlim@umich.edu    int storeWBIdx;
3302678Sktlim@umich.edu    /** The index of the tail instruction in the SQ. */
3312698Sktlim@umich.edu    int storeTail;
3322678Sktlim@umich.edu
3332678Sktlim@umich.edu    /// @todo Consider moving to a more advanced model with write vs read ports
3342698Sktlim@umich.edu    /** The number of cache ports available each cycle. */
3352678Sktlim@umich.edu    int cachePorts;
3362678Sktlim@umich.edu
3372678Sktlim@umich.edu    /** The number of used cache ports in this cycle. */
3382678Sktlim@umich.edu    int usedPorts;
3392678Sktlim@umich.edu
3402678Sktlim@umich.edu    /** Is the LSQ switched out. */
3412292SN/A    bool switchedOut;
3422292SN/A
3432292SN/A    //list<InstSeqNum> mshrSeqNums;
3442292SN/A
3454326Sgblack@eecs.umich.edu    /** Wire to read information from the issue stage time queue. */
3462292SN/A    typename TimeBuffer<IssueStruct>::wire fromIssue;
3474326Sgblack@eecs.umich.edu
3484395Ssaidi@eecs.umich.edu    /** Whether or not the LSQ is stalled. */
3494326Sgblack@eecs.umich.edu    bool stalled;
3502292SN/A    /** The store that causes the stall due to partial store to load
3519152Satgutier@umich.edu     * forwarding.
3529152Satgutier@umich.edu     */
3539152Satgutier@umich.edu    InstSeqNum stallingStoreIsn;
3549152Satgutier@umich.edu    /** The index of the above store. */
3559152Satgutier@umich.edu    int stallingLoadIdx;
3562292SN/A
35713429Srekai.gonzalezalberquilla@arm.com    /** Whether or not a load is blocked due to the memory system. */
3586974Stjones1@inf.ed.ac.uk    bool isLoadBlocked;
35910031SAli.Saidi@ARM.com
3604326Sgblack@eecs.umich.edu    /** Has the blocked load been handled. */
3614395Ssaidi@eecs.umich.edu    bool loadBlockedHandled;
3624326Sgblack@eecs.umich.edu
3639046SAli.Saidi@ARM.com    /** The sequence number of the blocked load. */
3649046SAli.Saidi@ARM.com    InstSeqNum blockedLoadSeqNum;
3652292SN/A
3662292SN/A    /** The oldest load that caused a memory ordering violation. */
3672669Sktlim@umich.edu    DynInstPtr memDepViolator;
3682669Sktlim@umich.edu
3696974Stjones1@inf.ed.ac.uk    // Will also need how many read/write ports the Dcache has.  Or keep track
3706974Stjones1@inf.ed.ac.uk    // of that in stage that is one level up, and only call executeLoad/Store
3716974Stjones1@inf.ed.ac.uk    // the appropriate number of times.
3722292SN/A/*
3739046SAli.Saidi@ARM.com    // total number of loads forwaded from LSQ stores
3746974Stjones1@inf.ed.ac.uk    Stats::Vector<> lsq_forw_loads;
3756974Stjones1@inf.ed.ac.uk
3762292SN/A    // total number of loads ignored due to invalid addresses
3772292SN/A    Stats::Vector<> inv_addr_loads;
3782292SN/A
3792292SN/A    // total number of software prefetches ignored due to invalid addresses
3802292SN/A    Stats::Vector<> inv_addr_swpfs;
3812292SN/A
38210031SAli.Saidi@ARM.com    // total non-speculative bogus addresses seen (debug var)
38310031SAli.Saidi@ARM.com    Counter sim_invalid_addrs;
38410031SAli.Saidi@ARM.com    Stats::Vector<> fu_busy;  //cumulative fu busy
38510031SAli.Saidi@ARM.com
38610031SAli.Saidi@ARM.com    // ready loads blocked due to memory disambiguation
3872292SN/A    Stats::Vector<> lsq_blocked_loads;
3882329SN/A
3892292SN/A    Stats::Scalar<> lsqInversion;
3902292SN/A*/
3916221Snate@binkert.org  public:
3922292SN/A    /** Executes the load at the given index. */
3932292SN/A    template <class T>
3942292SN/A    Fault read(MemReqPtr &req, T &data, int load_idx);
3952292SN/A
3962292SN/A    /** Executes the store at the given index. */
3972292SN/A    template <class T>
3982292SN/A    Fault write(MemReqPtr &req, T &data, int store_idx);
3992329SN/A
4002329SN/A    /** Returns the index of the head load instruction. */
4012329SN/A    int getLoadHead() { return loadHead; }
4022292SN/A    /** Returns the sequence number of the head load instruction. */
4032329SN/A    InstSeqNum getLoadHeadSeqNum()
4042329SN/A    {
4052329SN/A        if (loadQueue[loadHead]) {
4062292SN/A            return loadQueue[loadHead]->seqNum;
4072292SN/A        } else {
4088199SAli.Saidi@ARM.com            return 0;
4098199SAli.Saidi@ARM.com        }
4108199SAli.Saidi@ARM.com
4118199SAli.Saidi@ARM.com    }
4128199SAli.Saidi@ARM.com
4138199SAli.Saidi@ARM.com    /** Returns the index of the head store instruction. */
4148199SAli.Saidi@ARM.com    int getStoreHead() { return storeHead; }
4158199SAli.Saidi@ARM.com    /** Returns the sequence number of the head store instruction. */
4162292SN/A    InstSeqNum getStoreHeadSeqNum()
4172292SN/A    {
4182329SN/A        if (storeQueue[storeHead].inst) {
4192292SN/A            return storeQueue[storeHead].inst->seqNum;
4202292SN/A        } else {
4212292SN/A            return 0;
4222292SN/A        }
4232292SN/A
4242292SN/A    }
4252292SN/A
4262292SN/A    /** Returns whether or not the LSQ unit is stalled. */
4272292SN/A    bool isStalled()  { return stalled; }
4282292SN/A};
4292292SN/A
4302329SN/Atemplate <class Impl>
4312329SN/Atemplate <class T>
4322292SN/AFault
4332292SN/ALSQUnit<Impl>::read(MemReqPtr &req, T &data, int load_idx)
4342292SN/A{
4352292SN/A    assert(loadQueue[load_idx]);
4362292SN/A
4372292SN/A    assert(!loadQueue[load_idx]->isExecuted());
43811780Sarthur.perais@inria.fr
43911780Sarthur.perais@inria.fr    // Make sure this isn't an uncacheable access
4402292SN/A    // A bit of a hackish way to get uncached accesses to work only if they're
44111780Sarthur.perais@inria.fr    // at the head of the LSQ and are ready to commit (at the head of the ROB
44211780Sarthur.perais@inria.fr    // too).
4432292SN/A    if (req->flags & UNCACHEABLE &&
4442292SN/A        (load_idx != loadHead || !loadQueue[load_idx]->reachedCommit)) {
4452292SN/A        iewStage->rescheduleMemInst(loadQueue[load_idx]);
4468545Ssaidi@eecs.umich.edu        return TheISA::genMachineCheckFault();
4478545Ssaidi@eecs.umich.edu    }
4488545Ssaidi@eecs.umich.edu
4492292SN/A    // Check the SQ for any previous stores that might lead to forwarding
4502292SN/A    int store_idx = loadQueue[load_idx]->sqIdx;
4512292SN/A
4522292SN/A    int store_size = 0;
4532292SN/A
4542292SN/A    DPRINTF(LSQUnit, "Read called, load idx: %i, store idx: %i, "
4552292SN/A            "storeHead: %i addr: %#x\n",
4562292SN/A            load_idx, store_idx, storeHead, req->paddr);
4572292SN/A
4582292SN/A#if 0
4592292SN/A    if (req->flags & LOCKED) {
4602292SN/A        cpu->lockAddr = req->paddr;
4612698Sktlim@umich.edu        cpu->lockFlag = true;
4622698Sktlim@umich.edu    }
4632693Sktlim@umich.edu#endif
4642698Sktlim@umich.edu    req->cmd = Read;
4652678Sktlim@umich.edu    assert(!req->completionEvent);
4662678Sktlim@umich.edu    req->completionEvent = NULL;
4678727Snilay@cs.wisc.edu    req->time = curTick;
4688727Snilay@cs.wisc.edu
4698727Snilay@cs.wisc.edu    while (store_idx != -1) {
4702292SN/A        // End once we've reached the top of the LSQ
4712292SN/A        if (store_idx == storeWBIdx) {
4722292SN/A            break;
4736974Stjones1@inf.ed.ac.uk        }
4746974Stjones1@inf.ed.ac.uk
4756974Stjones1@inf.ed.ac.uk        // Move the index to one younger
4766974Stjones1@inf.ed.ac.uk        if (--store_idx < 0)
4776974Stjones1@inf.ed.ac.uk            store_idx += SQEntries;
4786974Stjones1@inf.ed.ac.uk
4796974Stjones1@inf.ed.ac.uk        assert(storeQueue[store_idx].inst);
4808727Snilay@cs.wisc.edu
4818727Snilay@cs.wisc.edu        store_size = storeQueue[store_idx].size;
4828727Snilay@cs.wisc.edu
4832292SN/A        if (store_size == 0)
4842292SN/A            continue;
4852292SN/A
4862727Sktlim@umich.edu        // Check if the store data is within the lower and upper bounds of
4875999Snate@binkert.org        // addresses that the request needs.
4882307SN/A        bool store_has_lower_limit =
4893126Sktlim@umich.edu            req->vaddr >= storeQueue[store_idx].inst->effAddr;
4905999Snate@binkert.org        bool store_has_upper_limit =
4913126Sktlim@umich.edu            (req->vaddr + req->size) <= (storeQueue[store_idx].inst->effAddr +
4923126Sktlim@umich.edu                                         store_size);
4935999Snate@binkert.org        bool lower_load_has_store_part =
4943126Sktlim@umich.edu            req->vaddr < (storeQueue[store_idx].inst->effAddr +
4953126Sktlim@umich.edu                           store_size);
4963126Sktlim@umich.edu        bool upper_load_has_store_part =
4975999Snate@binkert.org            (req->vaddr + req->size) > storeQueue[store_idx].inst->effAddr;
4983126Sktlim@umich.edu
4993126Sktlim@umich.edu        // If the store's data has all of the data needed, we can forward.
5005999Snate@binkert.org        if (store_has_lower_limit && store_has_upper_limit) {
5013126Sktlim@umich.edu            // Get shift amount for offset into the store's data.
5022727Sktlim@umich.edu            int shift_amt = req->vaddr & (store_size - 1);
5035999Snate@binkert.org            // @todo: Magic number, assumes byte addressing
5042727Sktlim@umich.edu            shift_amt = shift_amt << 3;
5052727Sktlim@umich.edu
5065999Snate@binkert.org            // Cast this to type T?
5072727Sktlim@umich.edu            data = storeQueue[store_idx].data >> shift_amt;
5082727Sktlim@umich.edu
5095999Snate@binkert.org            assert(!req->data);
5102727Sktlim@umich.edu            req->data = new uint8_t[64];
5112727Sktlim@umich.edu
5125999Snate@binkert.org            memcpy(req->data, &data, req->size);
5132727Sktlim@umich.edu
5142727Sktlim@umich.edu            DPRINTF(LSQUnit, "Forwarding from store idx %i to load to "
5155999Snate@binkert.org                    "addr %#x, data %#x\n",
5162727Sktlim@umich.edu                    store_idx, req->vaddr, *(req->data));
5172292SN/A
5182292SN/A            typename IEW::LdWritebackEvent *wb =
51912749Sgiacomo.travaglini@arm.com                new typename IEW::LdWritebackEvent(loadQueue[load_idx],
52012749Sgiacomo.travaglini@arm.com                                                   iewStage);
52111302Ssteve.reinhardt@amd.com
5222292SN/A            // We'll say this has a 1 cycle load-store forwarding latency
5232292SN/A            // for now.
52412749Sgiacomo.travaglini@arm.com            // @todo: Need to make this a parameter.
52512749Sgiacomo.travaglini@arm.com            wb->schedule(curTick);
5267520Sgblack@eecs.umich.edu
5272292SN/A            // Should keep track of stat for forwarded data
5282292SN/A            return NoFault;
5292292SN/A        } else if ((store_has_lower_limit && lower_load_has_store_part) ||
5302292SN/A                   (store_has_upper_limit && upper_load_has_store_part) ||
5312292SN/A                   (lower_load_has_store_part && upper_load_has_store_part)) {
5322292SN/A            // This is the partial store-load forwarding case where a store
5332292SN/A            // has only part of the load's data.
5342292SN/A
5352292SN/A            // If it's already been written back, then don't worry about
5362292SN/A            // stalling on it.
5372292SN/A            if (storeQueue[store_idx].completed) {
5382292SN/A                continue;
5392292SN/A            }
5402292SN/A
5412292SN/A            // Must stall load and force it to retry, so long as it's the oldest
5422292SN/A            // load that needs to do so.
5432292SN/A            if (!stalled ||
5442292SN/A                (stalled &&
5452292SN/A                 loadQueue[load_idx]->seqNum <
5462292SN/A                 loadQueue[stallingLoadIdx]->seqNum)) {
5472292SN/A                stalled = true;
5482292SN/A                stallingStoreIsn = storeQueue[store_idx].inst->seqNum;
5492292SN/A                stallingLoadIdx = load_idx;
5502292SN/A            }
5512292SN/A
5522292SN/A            // Tell IQ/mem dep unit that this instruction will need to be
5532292SN/A            // rescheduled eventually
5542292SN/A            iewStage->rescheduleMemInst(loadQueue[load_idx]);
5552292SN/A
5562292SN/A            // Do not generate a writeback event as this instruction is not
5572292SN/A            // complete.
5582292SN/A            DPRINTF(LSQUnit, "Load-store forwarding mis-match. "
5592292SN/A                    "Store idx %i to load addr %#x\n",
56012749Sgiacomo.travaglini@arm.com                    store_idx, req->vaddr);
56112749Sgiacomo.travaglini@arm.com
56211302Ssteve.reinhardt@amd.com            return NoFault;
5632292SN/A        }
5642669Sktlim@umich.edu    }
5652292SN/A
5662669Sktlim@umich.edu    // If there's no forwarding case, then go access memory
5672669Sktlim@umich.edu    DynInstPtr inst = loadQueue[load_idx];
5682669Sktlim@umich.edu
5692292SN/A    DPRINTF(LSQUnit, "Doing functional access for inst [sn:%lli] PC %#x\n",
57010824SAndreas.Sandberg@ARM.com            loadQueue[load_idx]->seqNum, loadQueue[load_idx]->readPC());
57110824SAndreas.Sandberg@ARM.com
57210824SAndreas.Sandberg@ARM.com    assert(!req->data);
57310824SAndreas.Sandberg@ARM.com    req->data = new uint8_t[64];
57410824SAndreas.Sandberg@ARM.com    Fault fault = cpu->read(req, data);
5752731Sktlim@umich.edu    memcpy(req->data, &data, sizeof(T));
5762669Sktlim@umich.edu
5772727Sktlim@umich.edu    ++usedPorts;
57810824SAndreas.Sandberg@ARM.com
5797720Sgblack@eecs.umich.edu    // if we have a cache, do cache access too
5804032Sktlim@umich.edu    if (fault == NoFault && dcacheInterface) {
58110474Sandreas.hansson@arm.com        if (dcacheInterface->isBlocked()) {
58210824SAndreas.Sandberg@ARM.com            // There's an older load that's already going to squash.
58310474Sandreas.hansson@arm.com            if (isLoadBlocked && blockedLoadSeqNum < inst->seqNum)
5842292SN/A                return NoFault;
5852292SN/A
5862292SN/A            // Record that the load was blocked due to memory.  This
5872669Sktlim@umich.edu            // load will squash all instructions after it, be
5882292SN/A            // refetched, and re-executed.
5892292SN/A            isLoadBlocked = true;
5902292SN/A            loadBlockedHandled = false;
5912292SN/A            blockedLoadSeqNum = inst->seqNum;
5926974Stjones1@inf.ed.ac.uk            // No fault occurred, even though the interface is blocked.
5936974Stjones1@inf.ed.ac.uk            return NoFault;
5946974Stjones1@inf.ed.ac.uk        }
5952292SN/A
5966102Sgblack@eecs.umich.edu        DPRINTF(LSQUnit, "Doing timing access for inst PC %#x\n",
5976974Stjones1@inf.ed.ac.uk                loadQueue[load_idx]->readPC());
5983326Sktlim@umich.edu
5993326Sktlim@umich.edu        assert(!req->completionEvent);
6003326Sktlim@umich.edu        req->completionEvent =
6019046SAli.Saidi@ARM.com            new typename IEW::LdWritebackEvent(loadQueue[load_idx], iewStage);
6023326Sktlim@umich.edu        MemAccessResult result = dcacheInterface->access(req);
6039046SAli.Saidi@ARM.com
6042292SN/A        assert(dcacheInterface->doEvents());
6052292SN/A
6068481Sgblack@eecs.umich.edu        if (result != MA_HIT) {
6078481Sgblack@eecs.umich.edu            DPRINTF(LSQUnit, "LSQUnit: D-cache miss!\n");
6088481Sgblack@eecs.umich.edu            DPRINTF(Activity, "Activity: ld accessing mem miss [sn:%lli]\n",
6098481Sgblack@eecs.umich.edu                    inst->seqNum);
6108481Sgblack@eecs.umich.edu        } else {
6119180Sandreas.hansson@arm.com            DPRINTF(LSQUnit, "LSQUnit: D-cache hit!\n");
6128949Sandreas.hansson@arm.com            DPRINTF(Activity, "Activity: ld accessing mem hit [sn:%lli]\n",
6138481Sgblack@eecs.umich.edu                    inst->seqNum);
61412171Smatthiashille8@gmail.com        }
6158481Sgblack@eecs.umich.edu    }
6168481Sgblack@eecs.umich.edu
6178481Sgblack@eecs.umich.edu    return fault;
6188481Sgblack@eecs.umich.edu}
6198949Sandreas.hansson@arm.com
6208949Sandreas.hansson@arm.comtemplate <class Impl>
6218481Sgblack@eecs.umich.edutemplate <class T>
6228481Sgblack@eecs.umich.eduFault
6238481Sgblack@eecs.umich.eduLSQUnit<Impl>::write(MemReqPtr &req, T &data, int store_idx)
6248481Sgblack@eecs.umich.edu{
6258481Sgblack@eecs.umich.edu    assert(storeQueue[store_idx].inst);
6269180Sandreas.hansson@arm.com
6278481Sgblack@eecs.umich.edu    DPRINTF(LSQUnit, "Doing write to store idx %i, addr %#x data %#x"
6288481Sgblack@eecs.umich.edu            " | storeHead:%i [sn:%i]\n",
6298481Sgblack@eecs.umich.edu            store_idx, req->paddr, data, storeHead,
6308481Sgblack@eecs.umich.edu            storeQueue[store_idx].inst->seqNum);
6318481Sgblack@eecs.umich.edu
6328481Sgblack@eecs.umich.edu    storeQueue[store_idx].req = req;
6338481Sgblack@eecs.umich.edu    storeQueue[store_idx].size = sizeof(T);
6349179Sandreas.hansson@arm.com    storeQueue[store_idx].data = data;
6358481Sgblack@eecs.umich.edu
6368481Sgblack@eecs.umich.edu    // This function only writes the data to the store queue, so no fault
6378481Sgblack@eecs.umich.edu    // can happen here.
6382292SN/A    return NoFault;
6392292SN/A}
6402292SN/A
6412292SN/A#endif // __CPU_O3_LSQ_UNIT_HH__
6422292SN/A