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