| /* |
| * Copyright (c) 2012, 2014, 2020 ARM Limited |
| * All rights reserved |
| * |
| * The license below extends only to copyright in the software and shall |
| * not be construed as granting a license to any other intellectual |
| * property including but not limited to intellectual property relating |
| * to a hardware implementation of the functionality of the software |
| * licensed hereunder. You may use the software subject to the license |
| * terms below provided that you ensure that this notice is replicated |
| * unmodified and in its entirety in all distributions of the software, |
| * modified or unmodified, in source code or in binary form. |
| * |
| * Copyright (c) 2004-2006 The Regents of The University of Michigan |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer; |
| * redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution; |
| * neither the name of the copyright holders nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #ifndef __CPU_O3_MEM_DEP_UNIT_HH__ |
| #define __CPU_O3_MEM_DEP_UNIT_HH__ |
| |
| #include <list> |
| #include <memory> |
| #include <set> |
| #include <unordered_map> |
| #include <unordered_set> |
| |
| #include "base/statistics.hh" |
| #include "cpu/inst_seq.hh" |
| #include "debug/MemDepUnit.hh" |
| |
| struct SNHash { |
| size_t operator() (const InstSeqNum &seq_num) const { |
| unsigned a = (unsigned)seq_num; |
| unsigned hash = (((a >> 14) ^ ((a >> 2) & 0xffff))) & 0x7FFFFFFF; |
| |
| return hash; |
| } |
| }; |
| |
| struct DerivO3CPUParams; |
| |
| template <class Impl> |
| class InstructionQueue; |
| |
| /** |
| * Memory dependency unit class. This holds the memory dependence predictor. |
| * As memory operations are issued to the IQ, they are also issued to this |
| * unit, which then looks up the prediction as to what they are dependent |
| * upon. This unit must be checked prior to a memory operation being able |
| * to issue. Although this is templated, it's somewhat hard to make a generic |
| * memory dependence unit. This one is mostly for store sets; it will be |
| * quite limited in what other memory dependence predictions it can also |
| * utilize. Thus this class should be most likely be rewritten for other |
| * dependence prediction schemes. |
| */ |
| template <class MemDepPred, class Impl> |
| class MemDepUnit |
| { |
| protected: |
| std::string _name; |
| |
| public: |
| typedef typename Impl::DynInstPtr DynInstPtr; |
| typedef typename Impl::DynInstConstPtr DynInstConstPtr; |
| typedef typename Impl::O3CPU O3CPU; |
| |
| /** Empty constructor. Must call init() prior to using in this case. */ |
| MemDepUnit(); |
| |
| /** Constructs a MemDepUnit with given parameters. */ |
| MemDepUnit(const DerivO3CPUParams ¶ms); |
| |
| /** Frees up any memory allocated. */ |
| ~MemDepUnit(); |
| |
| /** Returns the name of the memory dependence unit. */ |
| std::string name() const { return _name; } |
| |
| /** Initializes the unit with parameters and a thread id. */ |
| void init(const DerivO3CPUParams ¶ms, ThreadID tid, O3CPU *cpu); |
| |
| /** Determine if we are drained. */ |
| bool isDrained() const; |
| |
| /** Perform sanity checks after a drain. */ |
| void drainSanityCheck() const; |
| |
| /** Takes over from another CPU's thread. */ |
| void takeOverFrom(); |
| |
| /** Sets the pointer to the IQ. */ |
| void setIQ(InstructionQueue<Impl> *iq_ptr); |
| |
| /** Inserts a memory instruction. */ |
| void insert(const DynInstPtr &inst); |
| |
| /** Inserts a non-speculative memory instruction. */ |
| void insertNonSpec(const DynInstPtr &inst); |
| |
| /** Inserts a barrier instruction. */ |
| void insertBarrier(const DynInstPtr &barr_inst); |
| |
| /** Indicate that an instruction has its registers ready. */ |
| void regsReady(const DynInstPtr &inst); |
| |
| /** Indicate that a non-speculative instruction is ready. */ |
| void nonSpecInstReady(const DynInstPtr &inst); |
| |
| /** Reschedules an instruction to be re-executed. */ |
| void reschedule(const DynInstPtr &inst); |
| |
| /** Replays all instructions that have been rescheduled by moving them to |
| * the ready list. |
| */ |
| void replay(); |
| |
| /** Notifies completion of an instruction. */ |
| void completeInst(const DynInstPtr &inst); |
| |
| /** Squashes all instructions up until a given sequence number for a |
| * specific thread. |
| */ |
| void squash(const InstSeqNum &squashed_num, ThreadID tid); |
| |
| /** Indicates an ordering violation between a store and a younger load. */ |
| void violation(const DynInstPtr &store_inst, |
| const DynInstPtr &violating_load); |
| |
| /** Issues the given instruction */ |
| void issue(const DynInstPtr &inst); |
| |
| /** Debugging function to dump the lists of instructions. */ |
| void dumpLists(); |
| |
| private: |
| |
| /** Completes a memory instruction. */ |
| void completed(const DynInstPtr &inst); |
| |
| /** Wakes any dependents of a memory instruction. */ |
| void wakeDependents(const DynInstPtr &inst); |
| |
| typedef typename std::list<DynInstPtr>::iterator ListIt; |
| |
| class MemDepEntry; |
| |
| typedef std::shared_ptr<MemDepEntry> MemDepEntryPtr; |
| |
| /** Memory dependence entries that track memory operations, marking |
| * when the instruction is ready to execute and what instructions depend |
| * upon it. |
| */ |
| class MemDepEntry { |
| public: |
| /** Constructs a memory dependence entry. */ |
| MemDepEntry(const DynInstPtr &new_inst) |
| : inst(new_inst), regsReady(false), memDeps(0), |
| completed(false), squashed(false) |
| { |
| #ifdef DEBUG |
| ++memdep_count; |
| |
| DPRINTF(MemDepUnit, "Memory dependency entry created. " |
| "memdep_count=%i %s\n", memdep_count, inst->pcState()); |
| #endif |
| } |
| |
| /** Frees any pointers. */ |
| ~MemDepEntry() |
| { |
| for (int i = 0; i < dependInsts.size(); ++i) { |
| dependInsts[i] = NULL; |
| } |
| #ifdef DEBUG |
| --memdep_count; |
| |
| DPRINTF(MemDepUnit, "Memory dependency entry deleted. " |
| "memdep_count=%i %s\n", memdep_count, inst->pcState()); |
| #endif |
| } |
| |
| /** Returns the name of the memory dependence entry. */ |
| std::string name() const { return "memdepentry"; } |
| |
| /** The instruction being tracked. */ |
| DynInstPtr inst; |
| |
| /** The iterator to the instruction's location inside the list. */ |
| ListIt listIt; |
| |
| /** A vector of any dependent instructions. */ |
| std::vector<MemDepEntryPtr> dependInsts; |
| |
| /** If the registers are ready or not. */ |
| bool regsReady; |
| /** Number of memory dependencies that need to be satisfied. */ |
| int memDeps; |
| /** If the instruction is completed. */ |
| bool completed; |
| /** If the instruction is squashed. */ |
| bool squashed; |
| |
| /** For debugging. */ |
| #ifdef DEBUG |
| static int memdep_count; |
| static int memdep_insert; |
| static int memdep_erase; |
| #endif |
| }; |
| |
| /** Finds the memory dependence entry in the hash map. */ |
| inline MemDepEntryPtr &findInHash(const DynInstConstPtr& inst); |
| |
| /** Moves an entry to the ready list. */ |
| inline void moveToReady(MemDepEntryPtr &ready_inst_entry); |
| |
| typedef std::unordered_map<InstSeqNum, MemDepEntryPtr, SNHash> MemDepHash; |
| |
| typedef typename MemDepHash::iterator MemDepHashIt; |
| |
| /** A hash map of all memory dependence entries. */ |
| MemDepHash memDepHash; |
| |
| /** A list of all instructions in the memory dependence unit. */ |
| std::list<DynInstPtr> instList[Impl::MaxThreads]; |
| |
| /** A list of all instructions that are going to be replayed. */ |
| std::list<DynInstPtr> instsToReplay; |
| |
| /** The memory dependence predictor. It is accessed upon new |
| * instructions being added to the IQ, and responds by telling |
| * this unit what instruction the newly added instruction is dependent |
| * upon. |
| */ |
| MemDepPred depPred; |
| |
| /** Sequence numbers of outstanding load barriers. */ |
| std::unordered_set<InstSeqNum> loadBarrierSNs; |
| |
| /** Sequence numbers of outstanding store barriers. */ |
| std::unordered_set<InstSeqNum> storeBarrierSNs; |
| |
| /** Is there an outstanding load barrier that loads must wait on. */ |
| bool hasLoadBarrier() const { return !loadBarrierSNs.empty(); } |
| |
| /** Is there an outstanding store barrier that loads must wait on. */ |
| bool hasStoreBarrier() const { return !storeBarrierSNs.empty(); } |
| |
| /** Inserts the SN of a barrier inst. to the list of tracked barriers */ |
| void insertBarrierSN(const DynInstPtr &barr_inst); |
| |
| /** Pointer to the IQ. */ |
| InstructionQueue<Impl> *iqPtr; |
| |
| /** The thread id of this memory dependence unit. */ |
| int id; |
| struct MemDepUnitStats : public Stats::Group |
| { |
| MemDepUnitStats(Stats::Group *parent); |
| /** Stat for number of inserted loads. */ |
| Stats::Scalar insertedLoads; |
| /** Stat for number of inserted stores. */ |
| Stats::Scalar insertedStores; |
| /** Stat for number of conflicting loads that had to wait for a |
| * store. */ |
| Stats::Scalar conflictingLoads; |
| /** Stat for number of conflicting stores that had to wait for a |
| * store. */ |
| Stats::Scalar conflictingStores; |
| } stats; |
| }; |
| |
| #endif // __CPU_O3_MEM_DEP_UNIT_HH__ |