lsq_unit.hh revision 2307
12810SN/A/*
28856Sandreas.hansson@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
38856Sandreas.hansson@arm.com * All rights reserved.
48856Sandreas.hansson@arm.com *
58856Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
68856Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
78856Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
88856Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
98856Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
108856Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
118856Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
128856Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its
138856Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from
142810SN/A * this software without specific prior written permission.
152810SN/A *
162810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272810SN/A */
282810SN/A
292810SN/A#ifndef __CPU_O3_LSQ_UNIT_HH__
302810SN/A#define __CPU_O3_LSQ_UNIT_HH__
312810SN/A
322810SN/A#include <map>
332810SN/A#include <queue>
342810SN/A#include <algorithm>
352810SN/A
362810SN/A#include "config/full_system.hh"
372810SN/A#include "base/hashmap.hh"
382810SN/A#include "cpu/inst_seq.hh"
392810SN/A#include "mem/mem_interface.hh"
402810SN/A//#include "mem/page_table.hh"
412810SN/A#include "sim/debug.hh"
422810SN/A#include "sim/sim_object.hh"
432810SN/A#include "arch/faults.hh"
442810SN/A
452810SN/A/**
462810SN/A * Class that implements the actual LQ and SQ for each specific thread.
472810SN/A * Both are circular queues; load entries are freed upon committing, while
483348SN/A * store entries are freed once they writeback. The LSQUnit tracks if there
493348SN/A * are memory ordering violations, and also detects partial load to store
508232Snate@binkert.org * forwarding cases (a store only has part of a load's data) that requires
515338Sstever@gmail.com * the load to wait until the store writes back. In the former case it
525338Sstever@gmail.com * holds onto the instruction until the dependence unit looks at it, and
538786Sgblack@eecs.umich.edu * in the latter it stalls the LSQ until the store writes back. At that
542810SN/A * point the load is replayed.
552810SN/A */
562810SN/Atemplate <class Impl>
578856Sandreas.hansson@arm.comclass LSQUnit {
588856Sandreas.hansson@arm.com  protected:
598856Sandreas.hansson@arm.com    typedef TheISA::IntReg IntReg;
608922Swilliam.wang@arm.com  public:
618914Sandreas.hansson@arm.com    typedef typename Impl::Params Params;
628856Sandreas.hansson@arm.com    typedef typename Impl::FullCPU FullCPU;
638856Sandreas.hansson@arm.com    typedef typename Impl::DynInstPtr DynInstPtr;
644475SN/A    typedef typename Impl::CPUPol::IEW IEW;
655034SN/A    typedef typename Impl::CPUPol::IssueStruct IssueStruct;
665034SN/A
675314SN/A  private:
685314SN/A    class StoreCompletionEvent : public Event {
694628SN/A      public:
705034SN/A        /** Constructs a store completion event. */
715034SN/A        StoreCompletionEvent(int store_idx, Event *wb_event, LSQUnit *lsq_ptr);
725034SN/A
736122SSteve.Reinhardt@amd.com        /** Processes the store completion event. */
748134SAli.Saidi@ARM.com        void process();
754626SN/A
764626SN/A        /** Returns the description of this event. */
775034SN/A        const char *description();
786122SSteve.Reinhardt@amd.com
798883SAli.Saidi@ARM.com      private:
808833Sdam.sunwoo@arm.com        /** The store index of the store being written back. */
814458SN/A        int storeIdx;
822810SN/A        /** The writeback event for the store.  Needed for store
832810SN/A         * conditionals.
843013SN/A         */
858856Sandreas.hansson@arm.com        Event *wbEvent;
862810SN/A        /** The pointer to the LSQ unit that issued the store. */
873013SN/A        LSQUnit<Impl> *lsqPtr;
888856Sandreas.hansson@arm.com    };
892810SN/A
902810SN/A    friend class StoreCompletionEvent;
912810SN/A
922810SN/A  public:
938856Sandreas.hansson@arm.com    /** Constructs an LSQ unit. init() must be called prior to use. */
942810SN/A    LSQUnit();
953013SN/A
968856Sandreas.hansson@arm.com    /** Initializes the LSQ unit with the specified number of entries. */
973013SN/A    void init(Params *params, unsigned maxLQEntries,
988856Sandreas.hansson@arm.com              unsigned maxSQEntries, unsigned id);
998856Sandreas.hansson@arm.com
1002897SN/A    /** Returns the name of the LSQ unit. */
1014666SN/A    std::string name() const;
1028922Swilliam.wang@arm.com
1032897SN/A    /** Sets the CPU pointer. */
1042810SN/A    void setCPU(FullCPU *cpu_ptr)
1052810SN/A    { cpu = cpu_ptr; }
1062844SN/A
1072810SN/A    /** Sets the IEW stage pointer. */
1082858SN/A    void setIEW(IEW *iew_ptr)
1092858SN/A    { iewStage = iew_ptr; }
1108856Sandreas.hansson@arm.com
1118922Swilliam.wang@arm.com    /** Sets the page table pointer. */
1128711Sandreas.hansson@arm.com//    void setPageTable(PageTable *pt_ptr);
1132858SN/A
1142858SN/A    void switchOut();
1158922Swilliam.wang@arm.com
1168922Swilliam.wang@arm.com    void takeOverFrom();
1178922Swilliam.wang@arm.com
1188922Swilliam.wang@arm.com    bool isSwitchedOut() { return switchedOut; }
1198922Swilliam.wang@arm.com
1208922Swilliam.wang@arm.com    /** Ticks the LSQ unit, which in this case only resets the number of
1218922Swilliam.wang@arm.com     * used cache ports.
1228922Swilliam.wang@arm.com     * @todo: Move the number of used ports up to the LSQ level so it can
1238922Swilliam.wang@arm.com     * be shared by all LSQ units.
1248922Swilliam.wang@arm.com     */
1258922Swilliam.wang@arm.com    void tick() { usedPorts = 0; }
1268922Swilliam.wang@arm.com
1278922Swilliam.wang@arm.com    /** Inserts an instruction. */
1288922Swilliam.wang@arm.com    void insert(DynInstPtr &inst);
1298922Swilliam.wang@arm.com    /** Inserts a load instruction. */
1308922Swilliam.wang@arm.com    void insertLoad(DynInstPtr &load_inst);
1318922Swilliam.wang@arm.com    /** Inserts a store instruction. */
1328922Swilliam.wang@arm.com    void insertStore(DynInstPtr &store_inst);
1338922Swilliam.wang@arm.com
1344628SN/A    /** Executes a load instruction. */
1352858SN/A    Fault executeLoad(DynInstPtr &inst);
1362810SN/A
1372810SN/A    Fault executeLoad(int lq_idx);
1382810SN/A    /** Executes a store instruction. */
1392810SN/A    Fault executeStore(DynInstPtr &inst);
1402810SN/A
1414022SN/A    /** Commits the head load. */
1424022SN/A    void commitLoad();
1434022SN/A    /** Commits a specific load, given by the sequence number. */
1442810SN/A    void commitLoad(InstSeqNum &inst);
1452810SN/A    /** Commits loads older than a specific sequence number. */
1468833Sdam.sunwoo@arm.com    void commitLoads(InstSeqNum &youngest_inst);
1472810SN/A
1482810SN/A    /** Commits stores older than a specific sequence number. */
1492810SN/A    void commitStores(InstSeqNum &youngest_inst);
1502810SN/A
1518833Sdam.sunwoo@arm.com    /** Writes back stores. */
1528833Sdam.sunwoo@arm.com    void writebackStores();
1538833Sdam.sunwoo@arm.com
1542810SN/A    // @todo: Include stats in the LSQ unit.
1552810SN/A    //void regStats();
1564871SN/A
1574871SN/A    /** Clears all the entries in the LQ. */
1584871SN/A    void clearLQ();
1594871SN/A
1604871SN/A    /** Clears all the entries in the SQ. */
1614871SN/A    void clearSQ();
1624871SN/A
1634871SN/A    /** Resizes the LQ to a given size. */
1644871SN/A    void resizeLQ(unsigned size);
1654871SN/A
1662810SN/A    /** Resizes the SQ to a given size. */
1672810SN/A    void resizeSQ(unsigned size);
1682810SN/A
1698833Sdam.sunwoo@arm.com    /** Squashes all instructions younger than a specific sequence number. */
1702810SN/A    void squash(const InstSeqNum &squashed_num);
1714871SN/A
1728833Sdam.sunwoo@arm.com    /** Returns if there is a memory ordering violation. Value is reset upon
1738833Sdam.sunwoo@arm.com     * call to getMemDepViolator().
1748833Sdam.sunwoo@arm.com     */
1752810SN/A    bool violation() { return memDepViolator; }
1762810SN/A
1772810SN/A    /** Returns the memory ordering violator. */
1782810SN/A    DynInstPtr getMemDepViolator();
1798833Sdam.sunwoo@arm.com
1802810SN/A    /** Returns if a load became blocked due to the memory system.  It clears
1814871SN/A     *  the bool's value upon this being called.
1828833Sdam.sunwoo@arm.com     */
1838833Sdam.sunwoo@arm.com    bool loadBlocked()
1848833Sdam.sunwoo@arm.com    { return isLoadBlocked; }
1852810SN/A
1862810SN/A    void clearLoadBlocked()
1874022SN/A    { isLoadBlocked = false; }
1884022SN/A
1894022SN/A    bool isLoadBlockedHandled()
1902810SN/A    { return loadBlockedHandled; }
1912810SN/A
1928833Sdam.sunwoo@arm.com    void setLoadBlockedHandled()
1932810SN/A    { loadBlockedHandled = true; }
1942810SN/A
1952810SN/A    /** Returns the number of free entries (min of free LQ and SQ entries). */
1962810SN/A    unsigned numFreeEntries();
1978833Sdam.sunwoo@arm.com
1988833Sdam.sunwoo@arm.com    /** Returns the number of loads ready to execute. */
1998833Sdam.sunwoo@arm.com    int numLoadsReady();
2002810SN/A
2012810SN/A    /** Returns the number of loads in the LQ. */
2022810SN/A    int numLoads() { return loads; }
2032810SN/A
2042810SN/A    /** Returns the number of stores in the SQ. */
2058833Sdam.sunwoo@arm.com    int numStores() { return stores; }
2062810SN/A
2074871SN/A    /** Returns if either the LQ or SQ is full. */
2088833Sdam.sunwoo@arm.com    bool isFull() { return lqFull() || sqFull(); }
2098833Sdam.sunwoo@arm.com
2108833Sdam.sunwoo@arm.com    /** Returns if the LQ is full. */
2112810SN/A    bool lqFull() { return loads >= (LQEntries - 1); }
2122810SN/A
2132810SN/A    /** Returns if the SQ is full. */
2142810SN/A    bool sqFull() { return stores >= (SQEntries - 1); }
2158833Sdam.sunwoo@arm.com
2162810SN/A    /** Debugging function to dump instructions in the LSQ. */
2174871SN/A    void dumpInsts();
2188833Sdam.sunwoo@arm.com
2198833Sdam.sunwoo@arm.com    /** Returns the number of instructions in the LSQ. */
2208833Sdam.sunwoo@arm.com    unsigned getCount() { return loads + stores; }
2212810SN/A
2222810SN/A    /** Returns if there are any stores to writeback. */
2234022SN/A    bool hasStoresToWB() { return storesToWB; }
2244022SN/A
2254022SN/A    /** Returns the number of stores to writeback. */
2262810SN/A    int numStoresToWB() { return storesToWB; }
2272810SN/A
2288833Sdam.sunwoo@arm.com    /** Returns if the LSQ unit will writeback on this cycle. */
2292810SN/A    bool willWB() { return storeQueue[storeWBIdx].canWB &&
2302810SN/A                        !storeQueue[storeWBIdx].completed &&
2312810SN/A                        !dcacheInterface->isBlocked(); }
2322810SN/A
2338833Sdam.sunwoo@arm.com  private:
2348833Sdam.sunwoo@arm.com    /** Completes the store at the specified index. */
2358833Sdam.sunwoo@arm.com    void completeStore(int store_idx);
2362810SN/A
2372810SN/A    /** Increments the given store index (circular queue). */
2382810SN/A    inline void incrStIdx(int &store_idx);
2392810SN/A    /** Decrements the given store index (circular queue). */
2402810SN/A    inline void decrStIdx(int &store_idx);
2418833Sdam.sunwoo@arm.com    /** Increments the given load index (circular queue). */
2422810SN/A    inline void incrLdIdx(int &load_idx);
2434871SN/A    /** Decrements the given load index (circular queue). */
2448833Sdam.sunwoo@arm.com    inline void decrLdIdx(int &load_idx);
2458833Sdam.sunwoo@arm.com
2468833Sdam.sunwoo@arm.com  private:
2472810SN/A    /** Pointer to the CPU. */
2482810SN/A    FullCPU *cpu;
2492810SN/A
2502810SN/A    /** Pointer to the IEW stage. */
2518833Sdam.sunwoo@arm.com    IEW *iewStage;
2522810SN/A
2534871SN/A    /** Pointer to the D-cache. */
2548833Sdam.sunwoo@arm.com    MemInterface *dcacheInterface;
2558833Sdam.sunwoo@arm.com
2568833Sdam.sunwoo@arm.com    /** Pointer to the page table. */
2572810SN/A//    PageTable *pTable;
2582810SN/A
2594022SN/A  public:
2604022SN/A    struct SQEntry {
2614022SN/A        /** Constructs an empty store queue entry. */
2622810SN/A        SQEntry()
2632810SN/A            : inst(NULL), req(NULL), size(0), data(0),
2642810SN/A              canWB(0), committed(0), completed(0)
2652810SN/A        { }
2662810SN/A
2672810SN/A        /** Constructs a store queue entry for a given instruction. */
2688833Sdam.sunwoo@arm.com        SQEntry(DynInstPtr &_inst)
2692810SN/A            : inst(_inst), req(NULL), size(0), data(0),
2708833Sdam.sunwoo@arm.com              canWB(0), committed(0), completed(0)
2718833Sdam.sunwoo@arm.com        { }
2728833Sdam.sunwoo@arm.com
2732810SN/A        /** The store instruction. */
2742810SN/A        DynInstPtr inst;
2752810SN/A        /** The memory request for the store. */
2762810SN/A        MemReqPtr req;
2772810SN/A        /** The size of the store. */
2788833Sdam.sunwoo@arm.com        int size;
2792810SN/A        /** The store data. */
2802810SN/A        IntReg data;
2818833Sdam.sunwoo@arm.com        /** Whether or not the store can writeback. */
2828833Sdam.sunwoo@arm.com        bool canWB;
2838833Sdam.sunwoo@arm.com        /** Whether or not the store is committed. */
2842810SN/A        bool committed;
2852810SN/A        /** Whether or not the store is completed. */
2862810SN/A        bool completed;
2872810SN/A    };
2888833Sdam.sunwoo@arm.com/*
2892810SN/A    enum Status {
2902810SN/A        Running,
2918833Sdam.sunwoo@arm.com        Idle,
2928833Sdam.sunwoo@arm.com        DcacheMissStall,
2938833Sdam.sunwoo@arm.com        DcacheMissSwitch
2942810SN/A    };
2952810SN/A*/
2964022SN/A  private:
2974022SN/A    /** The LSQUnit thread id. */
2984022SN/A    unsigned lsqID;
2992810SN/A
3002810SN/A    /** The status of the LSQ unit. */
3012810SN/A//    Status _status;
3022810SN/A
3032810SN/A    /** The store queue. */
3042810SN/A    std::vector<SQEntry> storeQueue;
3058833Sdam.sunwoo@arm.com
3062810SN/A    /** The load queue. */
3078833Sdam.sunwoo@arm.com    std::vector<DynInstPtr> loadQueue;
3088833Sdam.sunwoo@arm.com
3098833Sdam.sunwoo@arm.com    // Consider making these 16 bits
3102810SN/A    /** The number of LQ entries. */
3112810SN/A    unsigned LQEntries;
3122810SN/A    /** The number of SQ entries. */
3132810SN/A    unsigned SQEntries;
3142810SN/A
3158833Sdam.sunwoo@arm.com    /** The number of load instructions in the LQ. */
3162810SN/A    int loads;
3172810SN/A    /** The number of store instructions in the SQ (excludes those waiting to
3188833Sdam.sunwoo@arm.com     * writeback).
3198833Sdam.sunwoo@arm.com     */
3208833Sdam.sunwoo@arm.com    int stores;
3212810SN/A    /** The number of store instructions in the SQ waiting to writeback. */
3222810SN/A    int storesToWB;
3232810SN/A
3242810SN/A    /** The index of the head instruction in the LQ. */
3258833Sdam.sunwoo@arm.com    int loadHead;
3262810SN/A    /** The index of the tail instruction in the LQ. */
3272810SN/A    int loadTail;
3288833Sdam.sunwoo@arm.com
3298833Sdam.sunwoo@arm.com    /** The index of the head instruction in the SQ. */
3308833Sdam.sunwoo@arm.com    int storeHead;
3312810SN/A    /** The index of the first instruction that is ready to be written back,
3322810SN/A     * and has not yet been written back.
3334022SN/A     */
3344022SN/A    int storeWBIdx;
3354022SN/A    /** The index of the tail instruction in the SQ. */
3362810SN/A    int storeTail;
3372810SN/A
3382810SN/A    /// @todo Consider moving to a more advanced model with write vs read ports
3392810SN/A    /** The number of cache ports available each cycle. */
3402810SN/A    int cachePorts;
3412810SN/A
3422810SN/A    /** The number of used cache ports in this cycle. */
3432810SN/A    int usedPorts;
3448833Sdam.sunwoo@arm.com
3458833Sdam.sunwoo@arm.com    bool switchedOut;
3468833Sdam.sunwoo@arm.com
3478833Sdam.sunwoo@arm.com    //list<InstSeqNum> mshrSeqNums;
3482810SN/A
3492810SN/A     //Stats::Scalar<> dcacheStallCycles;
3502810SN/A    Counter lastDcacheStall;
3512810SN/A
3522810SN/A    /** Wire to read information from the issue stage time queue. */
3538833Sdam.sunwoo@arm.com    typename TimeBuffer<IssueStruct>::wire fromIssue;
3542810SN/A
3552810SN/A    // Make these per thread?
3568833Sdam.sunwoo@arm.com    /** Whether or not the LSQ is stalled. */
3578833Sdam.sunwoo@arm.com    bool stalled;
3588833Sdam.sunwoo@arm.com    /** The store that causes the stall due to partial store to load
3592810SN/A     * forwarding.
3602810SN/A     */
3612810SN/A    InstSeqNum stallingStoreIsn;
3622810SN/A    /** The index of the above store. */
3638833Sdam.sunwoo@arm.com    int stallingLoadIdx;
3642810SN/A
3652810SN/A    /** Whether or not a load is blocked due to the memory system.  It is
3668833Sdam.sunwoo@arm.com     *  cleared when this value is checked via loadBlocked().
3678833Sdam.sunwoo@arm.com     */
3688833Sdam.sunwoo@arm.com    bool isLoadBlocked;
3692810SN/A
3702810SN/A    bool loadBlockedHandled;
3712810SN/A
3722810SN/A    InstSeqNum blockedLoadSeqNum;
3732810SN/A
3742810SN/A    /** The oldest faulting load instruction. */
3752810SN/A    DynInstPtr loadFaultInst;
3762810SN/A    /** The oldest faulting store instruction. */
3772810SN/A    DynInstPtr storeFaultInst;
3782810SN/A
3792810SN/A    /** The oldest load that caused a memory ordering violation. */
3802810SN/A    DynInstPtr memDepViolator;
3812810SN/A
3822810SN/A    // Will also need how many read/write ports the Dcache has.  Or keep track
3832810SN/A    // of that in stage that is one level up, and only call executeLoad/Store
3842810SN/A    // the appropriate number of times.
3852810SN/A/*
3862810SN/A    // total number of loads forwaded from LSQ stores
3872810SN/A    Stats::Vector<> lsq_forw_loads;
3882810SN/A
3892810SN/A    // total number of loads ignored due to invalid addresses
3902810SN/A    Stats::Vector<> inv_addr_loads;
3912810SN/A
3922810SN/A    // total number of software prefetches ignored due to invalid addresses
3932810SN/A    Stats::Vector<> inv_addr_swpfs;
3942810SN/A
3952810SN/A    // total non-speculative bogus addresses seen (debug var)
3962810SN/A    Counter sim_invalid_addrs;
3972810SN/A    Stats::Vector<> fu_busy;  //cumulative fu busy
3982810SN/A
3992810SN/A    // ready loads blocked due to memory disambiguation
4002810SN/A    Stats::Vector<> lsq_blocked_loads;
4012810SN/A
4022810SN/A    Stats::Scalar<> lsqInversion;
4032810SN/A*/
4042810SN/A  public:
4052826SN/A    /** Executes the load at the given index. */
4064626SN/A    template <class T>
4078833Sdam.sunwoo@arm.com    Fault read(MemReqPtr &req, T &data, int load_idx);
4084626SN/A
4094626SN/A    /** Executes the store at the given index. */
4108833Sdam.sunwoo@arm.com    template <class T>
4114626SN/A    Fault write(MemReqPtr &req, T &data, int store_idx);
4128833Sdam.sunwoo@arm.com
4138833Sdam.sunwoo@arm.com    /** Returns the index of the head load instruction. */
4148833Sdam.sunwoo@arm.com    int getLoadHead() { return loadHead; }
4154626SN/A    /** Returns the sequence number of the head load instruction. */
4164626SN/A    InstSeqNum getLoadHeadSeqNum()
4174626SN/A    {
4184626SN/A        if (loadQueue[loadHead]) {
4194626SN/A            return loadQueue[loadHead]->seqNum;
4204626SN/A        } else {
4214626SN/A            return 0;
4224626SN/A        }
4238833Sdam.sunwoo@arm.com
4244626SN/A    }
4254626SN/A
4264626SN/A    /** Returns the index of the head store instruction. */
4274626SN/A    int getStoreHead() { return storeHead; }
4288833Sdam.sunwoo@arm.com    /** Returns the sequence number of the head store instruction. */
4298833Sdam.sunwoo@arm.com    InstSeqNum getStoreHeadSeqNum()
4308833Sdam.sunwoo@arm.com    {
4314626SN/A        if (storeQueue[storeHead].inst) {
4324626SN/A            return storeQueue[storeHead].inst->seqNum;
4334626SN/A        } else {
4344626SN/A            return 0;
4354626SN/A        }
4368833Sdam.sunwoo@arm.com
4374626SN/A    }
4384871SN/A
4398833Sdam.sunwoo@arm.com    /** Returns whether or not the LSQ unit is stalled. */
4408833Sdam.sunwoo@arm.com    bool isStalled()  { return stalled; }
4418833Sdam.sunwoo@arm.com};
4424626SN/A
4434626SN/Atemplate <class Impl>
4444626SN/Atemplate <class T>
4454626SN/AFault
4468833Sdam.sunwoo@arm.comLSQUnit<Impl>::read(MemReqPtr &req, T &data, int load_idx)
4474626SN/A{
4484871SN/A    //Depending on issue2execute delay a squashed load could
4498833Sdam.sunwoo@arm.com    //execute if it is found to be squashed in the same
4508833Sdam.sunwoo@arm.com    //cycle it is scheduled to execute
4518833Sdam.sunwoo@arm.com    assert(loadQueue[load_idx]);
4524626SN/A
4534626SN/A    if (loadQueue[load_idx]->isExecuted()) {
4544626SN/A        panic("Should not reach this point with split ops!");
4554626SN/A        memcpy(&data,req->data,req->size);
4564626SN/A
4574626SN/A        return NoFault;
4584626SN/A    }
4598833Sdam.sunwoo@arm.com
4604626SN/A    // Make sure this isn't an uncacheable access
4614626SN/A    // A bit of a hackish way to get uncached accesses to work only if they're
4624626SN/A    // at the head of the LSQ and are ready to commit (at the head of the ROB
4634626SN/A    // too).
4648833Sdam.sunwoo@arm.com    // @todo: Fix uncached accesses.
4658833Sdam.sunwoo@arm.com    if (req->flags & UNCACHEABLE &&
4668833Sdam.sunwoo@arm.com        (load_idx != loadHead || !loadQueue[load_idx]->reachedCommit)) {
4674626SN/A        iewStage->rescheduleMemInst(loadQueue[load_idx]);
4684626SN/A        return TheISA::genMachineCheckFault();
4694626SN/A    }
4704626SN/A
4714626SN/A    // Check the SQ for any previous stores that might lead to forwarding
4728833Sdam.sunwoo@arm.com    int store_idx = loadQueue[load_idx]->sqIdx;
4734626SN/A
4744871SN/A    int store_size = 0;
4758833Sdam.sunwoo@arm.com
4768833Sdam.sunwoo@arm.com    DPRINTF(LSQUnit, "Read called, load idx: %i, store idx: %i, "
4778833Sdam.sunwoo@arm.com            "storeHead: %i addr: %#x\n",
4784626SN/A            load_idx, store_idx, storeHead, req->paddr);
4794626SN/A
4804626SN/A#ifdef FULL_SYSTEM
4814626SN/A    if (req->flags & LOCKED) {
4828833Sdam.sunwoo@arm.com        cpu->lockAddr = req->paddr;
4834626SN/A        cpu->lockFlag = true;
4844871SN/A    }
4858833Sdam.sunwoo@arm.com#endif
4868833Sdam.sunwoo@arm.com
4878833Sdam.sunwoo@arm.com    while (store_idx != -1) {
4884626SN/A        // End once we've reached the top of the LSQ
4894626SN/A        if (store_idx == storeWBIdx) {
4904626SN/A            break;
4914626SN/A        }
4924626SN/A
4934626SN/A        // Move the index to one younger
4944626SN/A        if (--store_idx < 0)
4958833Sdam.sunwoo@arm.com            store_idx += SQEntries;
4964626SN/A
4974626SN/A        assert(storeQueue[store_idx].inst);
4984626SN/A
4994626SN/A        store_size = storeQueue[store_idx].size;
5008833Sdam.sunwoo@arm.com
5018833Sdam.sunwoo@arm.com        if (store_size == 0)
5028833Sdam.sunwoo@arm.com            continue;
5034626SN/A
5044626SN/A        // Check if the store data is within the lower and upper bounds of
5054626SN/A        // addresses that the request needs.
5064626SN/A        bool store_has_lower_limit =
5074626SN/A            req->vaddr >= storeQueue[store_idx].inst->effAddr;
5088833Sdam.sunwoo@arm.com        bool store_has_upper_limit =
5094626SN/A            (req->vaddr + req->size) <= (storeQueue[store_idx].inst->effAddr +
5104871SN/A                                         store_size);
5118833Sdam.sunwoo@arm.com        bool lower_load_has_store_part =
5128833Sdam.sunwoo@arm.com            req->vaddr < (storeQueue[store_idx].inst->effAddr +
5138833Sdam.sunwoo@arm.com                           store_size);
5144626SN/A        bool upper_load_has_store_part =
5154626SN/A            (req->vaddr + req->size) > storeQueue[store_idx].inst->effAddr;
5164626SN/A
5174626SN/A        // If the store's data has all of the data needed, we can forward.
5188833Sdam.sunwoo@arm.com        if (store_has_lower_limit && store_has_upper_limit) {
5194626SN/A
5204871SN/A            int shift_amt = req->vaddr & (store_size - 1);
5214871SN/A            // Assumes byte addressing
5228833Sdam.sunwoo@arm.com            shift_amt = shift_amt << 3;
5238833Sdam.sunwoo@arm.com
5248833Sdam.sunwoo@arm.com            // Cast this to type T?
5254626SN/A            data = storeQueue[store_idx].data >> shift_amt;
5264626SN/A
5274626SN/A            req->cmd = Read;
5284626SN/A            assert(!req->completionEvent);
5294626SN/A            req->completionEvent = NULL;
5304626SN/A            req->time = curTick;
5314626SN/A            assert(!req->data);
5328833Sdam.sunwoo@arm.com            req->data = new uint8_t[64];
5334626SN/A
5344626SN/A            memcpy(req->data, &data, req->size);
5354626SN/A
5364626SN/A            DPRINTF(LSQUnit, "Forwarding from store idx %i to load to "
5378833Sdam.sunwoo@arm.com                    "addr %#x, data %#x\n",
5388833Sdam.sunwoo@arm.com                    store_idx, req->vaddr, *(req->data));
5398833Sdam.sunwoo@arm.com
5404626SN/A            typename IEW::LdWritebackEvent *wb =
5414626SN/A                new typename IEW::LdWritebackEvent(loadQueue[load_idx],
5424626SN/A                                                   iewStage);
5434626SN/A
5444626SN/A            // We'll say this has a 1 cycle load-store forwarding latency
5458833Sdam.sunwoo@arm.com            // for now.
5464626SN/A            // @todo: Need to make this a parameter.
5474871SN/A            wb->schedule(curTick);
5484871SN/A
5498833Sdam.sunwoo@arm.com            // Should keep track of stat for forwarded data
5508833Sdam.sunwoo@arm.com            return NoFault;
5518833Sdam.sunwoo@arm.com        } else if ((store_has_lower_limit && lower_load_has_store_part) ||
5524626SN/A                   (store_has_upper_limit && upper_load_has_store_part) ||
5534626SN/A                   (lower_load_has_store_part && upper_load_has_store_part)) {
5544626SN/A            // This is the partial store-load forwarding case where a store
5554626SN/A            // has only part of the load's data.
5564626SN/A
5574626SN/A            // If it's already been written back, then don't worry about
5584626SN/A            // stalling on it.
5598833Sdam.sunwoo@arm.com            if (storeQueue[store_idx].completed) {
5604626SN/A                continue;
5614626SN/A            }
5624626SN/A
5634626SN/A            // Must stall load and force it to retry, so long as it's the oldest
5648833Sdam.sunwoo@arm.com            // load that needs to do so.
5658833Sdam.sunwoo@arm.com            if (!stalled ||
5668833Sdam.sunwoo@arm.com                (stalled &&
5674626SN/A                 loadQueue[load_idx]->seqNum <
5684626SN/A                 loadQueue[stallingLoadIdx]->seqNum)) {
5694626SN/A                stalled = true;
5704626SN/A                stallingStoreIsn = storeQueue[store_idx].inst->seqNum;
5714626SN/A                stallingLoadIdx = load_idx;
5728833Sdam.sunwoo@arm.com            }
5734626SN/A
5744871SN/A            // Tell IQ/mem dep unit that this instruction will need to be
5754871SN/A            // rescheduled eventually
5764871SN/A            iewStage->rescheduleMemInst(loadQueue[load_idx]);
5778833Sdam.sunwoo@arm.com
5788833Sdam.sunwoo@arm.com            // Do not generate a writeback event as this instruction is not
5798833Sdam.sunwoo@arm.com            // complete.
5804626SN/A
5814626SN/A            DPRINTF(LSQUnit, "Load-store forwarding mis-match. "
5824626SN/A                    "Store idx %i to load addr %#x\n",
5834626SN/A                    store_idx, req->vaddr);
5844626SN/A
5854626SN/A            return NoFault;
5864626SN/A        }
5874626SN/A    }
5884626SN/A
5894626SN/A
5904626SN/A    // If there's no forwarding case, then go access memory
5914626SN/A    DynInstPtr inst = loadQueue[load_idx];
5924626SN/A
5934626SN/A    DPRINTF(LSQUnit, "Doing functional access for inst PC %#x\n",
5944626SN/A            loadQueue[load_idx]->readPC());
5954626SN/A    assert(!req->data);
5964626SN/A    req->cmd = Read;
5974626SN/A    req->completionEvent = NULL;
5984626SN/A    req->time = curTick;
5994626SN/A    req->data = new uint8_t[64];
6004626SN/A    Fault fault = cpu->read(req, data);
6014626SN/A    memcpy(req->data, &data, sizeof(T));
6024626SN/A
6034626SN/A    ++usedPorts;
6044626SN/A
6054626SN/A    // if we have a cache, do cache access too
6064626SN/A    if (fault == NoFault && dcacheInterface) {
6074626SN/A        if (dcacheInterface->isBlocked()) {
6084626SN/A            // There's an older load that's already going to squash.
6094626SN/A            if (isLoadBlocked && blockedLoadSeqNum < inst->seqNum)
6104626SN/A                return NoFault;
6114626SN/A
6124626SN/A            isLoadBlocked = true;
6134626SN/A            loadBlockedHandled = false;
6144626SN/A            blockedLoadSeqNum = inst->seqNum;
6154626SN/A            // No fault occurred, even though the interface is blocked.
6164626SN/A            return NoFault;
6174626SN/A        }
6184626SN/A        DPRINTF(LSQUnit, "Doing timing access for inst PC %#x\n",
6194626SN/A                loadQueue[load_idx]->readPC());
6204626SN/A/*
6214626SN/A        Addr debug_addr = ULL(0xfffffc0000be81a8);
6224626SN/A        if (req->vaddr == debug_addr) {
6234626SN/A            debug_break();
6244626SN/A        }
6258833Sdam.sunwoo@arm.com*/
6268833Sdam.sunwoo@arm.com        assert(!req->completionEvent);
6278833Sdam.sunwoo@arm.com        req->completionEvent =
6288833Sdam.sunwoo@arm.com            new typename IEW::LdWritebackEvent(loadQueue[load_idx], iewStage);
6294626SN/A        MemAccessResult result = dcacheInterface->access(req);
6304626SN/A
6314626SN/A        assert(dcacheInterface->doEvents());
6324626SN/A
6334626SN/A        // Ugly hack to get an event scheduled *only* if the access is
6348833Sdam.sunwoo@arm.com        // a miss.  We really should add first-class support for this
6354626SN/A        // at some point.
6364626SN/A        if (result != MA_HIT) {
6378833Sdam.sunwoo@arm.com            DPRINTF(LSQUnit, "LSQUnit: D-cache miss!\n");
6388833Sdam.sunwoo@arm.com            DPRINTF(Activity, "Activity: ld accessing mem miss [sn:%lli]\n",
6398833Sdam.sunwoo@arm.com                    inst->seqNum);
6404626SN/A
6414626SN/A            lastDcacheStall = curTick;
6424626SN/A
6434626SN/A//            _status = DcacheMissStall;
6448833Sdam.sunwoo@arm.com
6454626SN/A        } else {
6464626SN/A            DPRINTF(Activity, "Activity: ld accessing mem hit [sn:%lli]\n",
6478833Sdam.sunwoo@arm.com                    inst->seqNum);
6488833Sdam.sunwoo@arm.com
6498833Sdam.sunwoo@arm.com            DPRINTF(LSQUnit, "LSQUnit: D-cache hit!\n");
6504626SN/A        }
6514626SN/A    }
6524626SN/A#if 0
6534626SN/A    // if we have a cache, do cache access too
6544626SN/A    if (dcacheInterface) {
6554626SN/A        if (dcacheInterface->isBlocked()) {
6564626SN/A            isLoadBlocked = true;
6574626SN/A            // No fault occurred, even though the interface is blocked.
6584626SN/A            return NoFault;
6594626SN/A        }
6604626SN/A
6614626SN/A        DPRINTF(LSQUnit, "LSQUnit: D-cache: PC:%#x reading from paddr:%#x "
6624626SN/A                "vaddr:%#x flags:%i\n",
6638833Sdam.sunwoo@arm.com                inst->readPC(), req->paddr, req->vaddr, req->flags);
6648833Sdam.sunwoo@arm.com
6658833Sdam.sunwoo@arm.com        // Setup MemReq pointer
6668833Sdam.sunwoo@arm.com        req->cmd = Read;
6674626SN/A        req->completionEvent = NULL;
6684626SN/A        req->time = curTick;
6694626SN/A        assert(!req->data);
6704626SN/A        req->data = new uint8_t[64];
6714626SN/A
6728833Sdam.sunwoo@arm.com        assert(!req->completionEvent);
6734626SN/A        req->completionEvent =
6744626SN/A            new typename IEW::LdWritebackEvent(loadQueue[load_idx], iewStage);
6758833Sdam.sunwoo@arm.com
6768833Sdam.sunwoo@arm.com        // Do Cache Access
6778833Sdam.sunwoo@arm.com        MemAccessResult result = dcacheInterface->access(req);
6784626SN/A
6794626SN/A        // Ugly hack to get an event scheduled *only* if the access is
6804626SN/A        // a miss.  We really should add first-class support for this
6814626SN/A        // at some point.
6828833Sdam.sunwoo@arm.com        // @todo: Probably should support having no events
6834626SN/A        if (result != MA_HIT) {
6844626SN/A            DPRINTF(LSQUnit, "LSQUnit: D-cache miss!\n");
6858833Sdam.sunwoo@arm.com            DPRINTF(Activity, "Activity: ld accessing mem miss [sn:%lli]\n",
6868833Sdam.sunwoo@arm.com                    inst->seqNum);
6878833Sdam.sunwoo@arm.com
6884626SN/A            lastDcacheStall = curTick;
6894626SN/A
6904626SN/A            _status = DcacheMissStall;
6914626SN/A
6924626SN/A        } else {
6934626SN/A            DPRINTF(Activity, "Activity: ld accessing mem hit [sn:%lli]\n",
6944626SN/A                    inst->seqNum);
6954626SN/A
6964626SN/A            DPRINTF(LSQUnit, "LSQUnit: D-cache hit!\n");
6974626SN/A        }
6984626SN/A    } else {
6994626SN/A        fatal("Must use D-cache with new memory system");
7004626SN/A    }
7018833Sdam.sunwoo@arm.com#endif
7028833Sdam.sunwoo@arm.com
7038833Sdam.sunwoo@arm.com    return fault;
7048833Sdam.sunwoo@arm.com}
7054626SN/A
7064626SN/Atemplate <class Impl>
7074626SN/Atemplate <class T>
7084626SN/AFault
7094626SN/ALSQUnit<Impl>::write(MemReqPtr &req, T &data, int store_idx)
7108833Sdam.sunwoo@arm.com{
7114626SN/A    assert(storeQueue[store_idx].inst);
7124626SN/A
7138833Sdam.sunwoo@arm.com    DPRINTF(LSQUnit, "Doing write to store idx %i, addr %#x data %#x"
7148833Sdam.sunwoo@arm.com            " | storeHead:%i [sn:%i]\n",
7158833Sdam.sunwoo@arm.com            store_idx, req->paddr, data, storeHead,
7164626SN/A            storeQueue[store_idx].inst->seqNum);
7174626SN/A/*
7188833Sdam.sunwoo@arm.com    if (req->flags & LOCKED) {
7194626SN/A        if (req->flags & UNCACHEABLE) {
7204626SN/A            req->result = 2;
7218833Sdam.sunwoo@arm.com        } else {
7224626SN/A            req->result = 1;
7238833Sdam.sunwoo@arm.com        }
7248833Sdam.sunwoo@arm.com    }
7258833Sdam.sunwoo@arm.com*/
7264626SN/A    storeQueue[store_idx].req = req;
7274626SN/A    storeQueue[store_idx].size = sizeof(T);
7284626SN/A    storeQueue[store_idx].data = data;
7298833Sdam.sunwoo@arm.com/*
7304626SN/A    Addr debug_addr = ULL(0xfffffc0000be81a8);
7314626SN/A    if (req->vaddr == debug_addr) {
7328833Sdam.sunwoo@arm.com        debug_break();
7334626SN/A    }
7348833Sdam.sunwoo@arm.com*/
7358833Sdam.sunwoo@arm.com    // This function only writes the data to the store queue, so no fault
7368833Sdam.sunwoo@arm.com    // can happen here.
7374626SN/A    return NoFault;
7384626SN/A}
7394626SN/A
7404626SN/A#endif // __CPU_O3_LSQ_UNIT_HH__
7414626SN/A