| /* |
| * Copyright (c) 2003-2005 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_STATIC_INST_HH__ |
| #define __CPU_STATIC_INST_HH__ |
| |
| #include <bitset> |
| #include <string> |
| |
| #include "base/hashmap.hh" |
| #include "base/refcnt.hh" |
| #include "encumbered/cpu/full/op_class.hh" |
| #include "sim/host.hh" |
| #include "targetarch/isa_traits.hh" |
| |
| // forward declarations |
| struct AlphaSimpleImpl; |
| class ExecContext; |
| class DynInst; |
| |
| template <class Impl> |
| class AlphaDynInst; |
| |
| class FastCPU; |
| class SimpleCPU; |
| class InorderCPU; |
| class SymbolTable; |
| |
| namespace Trace { |
| class InstRecord; |
| } |
| |
| /** |
| * Base, ISA-independent static instruction class. |
| * |
| * The main component of this class is the vector of flags and the |
| * associated methods for reading them. Any object that can rely |
| * solely on these flags can process instructions without being |
| * recompiled for multiple ISAs. |
| */ |
| class StaticInstBase : public RefCounted |
| { |
| protected: |
| |
| /// Set of boolean static instruction properties. |
| /// |
| /// Notes: |
| /// - The IsInteger and IsFloating flags are based on the class of |
| /// registers accessed by the instruction. Although most |
| /// instructions will have exactly one of these two flags set, it |
| /// is possible for an instruction to have neither (e.g., direct |
| /// unconditional branches, memory barriers) or both (e.g., an |
| /// FP/int conversion). |
| /// - If IsMemRef is set, then exactly one of IsLoad or IsStore |
| /// will be set. |
| /// - If IsControl is set, then exactly one of IsDirectControl or |
| /// IsIndirect Control will be set, and exactly one of |
| /// IsCondControl or IsUncondControl will be set. |
| /// - IsSerializing, IsMemBarrier, and IsWriteBarrier are |
| /// implemented as flags since in the current model there's no |
| /// other way for instructions to inject behavior into the |
| /// pipeline outside of fetch. Once we go to an exec-in-exec CPU |
| /// model we should be able to get rid of these flags and |
| /// implement this behavior via the execute() methods. |
| /// |
| enum Flags { |
| IsNop, ///< Is a no-op (no effect at all). |
| |
| IsInteger, ///< References integer regs. |
| IsFloating, ///< References FP regs. |
| |
| IsMemRef, ///< References memory (load, store, or prefetch). |
| IsLoad, ///< Reads from memory (load or prefetch). |
| IsStore, ///< Writes to memory. |
| IsInstPrefetch, ///< Instruction-cache prefetch. |
| IsDataPrefetch, ///< Data-cache prefetch. |
| IsCopy, ///< Fast Cache block copy |
| |
| IsControl, ///< Control transfer instruction. |
| IsDirectControl, ///< PC relative control transfer. |
| IsIndirectControl, ///< Register indirect control transfer. |
| IsCondControl, ///< Conditional control transfer. |
| IsUncondControl, ///< Unconditional control transfer. |
| IsCall, ///< Subroutine call. |
| IsReturn, ///< Subroutine return. |
| |
| IsThreadSync, ///< Thread synchronization operation. |
| |
| IsSerializing, ///< Serializes pipeline: won't execute until all |
| /// older instructions have committed. |
| IsMemBarrier, ///< Is a memory barrier |
| IsWriteBarrier, ///< Is a write barrier |
| |
| IsNonSpeculative, ///< Should not be executed speculatively |
| |
| NumFlags |
| }; |
| |
| /// Flag values for this instruction. |
| std::bitset<NumFlags> flags; |
| |
| /// See opClass(). |
| OpClass _opClass; |
| |
| /// See numSrcRegs(). |
| int8_t _numSrcRegs; |
| |
| /// See numDestRegs(). |
| int8_t _numDestRegs; |
| |
| /// The following are used to track physical register usage |
| /// for machines with separate int & FP reg files. |
| //@{ |
| int8_t _numFPDestRegs; |
| int8_t _numIntDestRegs; |
| //@} |
| |
| /// Constructor. |
| /// It's important to initialize everything here to a sane |
| /// default, since the decoder generally only overrides |
| /// the fields that are meaningful for the particular |
| /// instruction. |
| StaticInstBase(OpClass __opClass) |
| : _opClass(__opClass), _numSrcRegs(0), _numDestRegs(0), |
| _numFPDestRegs(0), _numIntDestRegs(0) |
| { |
| } |
| |
| public: |
| |
| /// @name Register information. |
| /// The sum of numFPDestRegs() and numIntDestRegs() equals |
| /// numDestRegs(). The former two functions are used to track |
| /// physical register usage for machines with separate int & FP |
| /// reg files. |
| //@{ |
| /// Number of source registers. |
| int8_t numSrcRegs() const { return _numSrcRegs; } |
| /// Number of destination registers. |
| int8_t numDestRegs() const { return _numDestRegs; } |
| /// Number of floating-point destination regs. |
| int8_t numFPDestRegs() const { return _numFPDestRegs; } |
| /// Number of integer destination regs. |
| int8_t numIntDestRegs() const { return _numIntDestRegs; } |
| //@} |
| |
| /// @name Flag accessors. |
| /// These functions are used to access the values of the various |
| /// instruction property flags. See StaticInstBase::Flags for descriptions |
| /// of the individual flags. |
| //@{ |
| |
| bool isNop() const { return flags[IsNop]; } |
| |
| bool isMemRef() const { return flags[IsMemRef]; } |
| bool isLoad() const { return flags[IsLoad]; } |
| bool isStore() const { return flags[IsStore]; } |
| bool isInstPrefetch() const { return flags[IsInstPrefetch]; } |
| bool isDataPrefetch() const { return flags[IsDataPrefetch]; } |
| bool isCopy() const { return flags[IsCopy];} |
| |
| bool isInteger() const { return flags[IsInteger]; } |
| bool isFloating() const { return flags[IsFloating]; } |
| |
| bool isControl() const { return flags[IsControl]; } |
| bool isCall() const { return flags[IsCall]; } |
| bool isReturn() const { return flags[IsReturn]; } |
| bool isDirectCtrl() const { return flags[IsDirectControl]; } |
| bool isIndirectCtrl() const { return flags[IsIndirectControl]; } |
| bool isCondCtrl() const { return flags[IsCondControl]; } |
| bool isUncondCtrl() const { return flags[IsUncondControl]; } |
| |
| bool isThreadSync() const { return flags[IsThreadSync]; } |
| bool isSerializing() const { return flags[IsSerializing]; } |
| bool isMemBarrier() const { return flags[IsMemBarrier]; } |
| bool isWriteBarrier() const { return flags[IsWriteBarrier]; } |
| bool isNonSpeculative() const { return flags[IsNonSpeculative]; } |
| //@} |
| |
| /// Operation class. Used to select appropriate function unit in issue. |
| OpClass opClass() const { return _opClass; } |
| }; |
| |
| |
| // forward declaration |
| template <class ISA> |
| class StaticInstPtr; |
| |
| /** |
| * Generic yet ISA-dependent static instruction class. |
| * |
| * This class builds on StaticInstBase, defining fields and interfaces |
| * that are generic across all ISAs but that differ in details |
| * according to the specific ISA being used. |
| */ |
| template <class ISA> |
| class StaticInst : public StaticInstBase |
| { |
| public: |
| |
| /// Binary machine instruction type. |
| typedef typename ISA::MachInst MachInst; |
| /// Memory address type. |
| typedef typename ISA::Addr Addr; |
| /// Logical register index type. |
| typedef typename ISA::RegIndex RegIndex; |
| |
| enum { |
| MaxInstSrcRegs = ISA::MaxInstSrcRegs, //< Max source regs |
| MaxInstDestRegs = ISA::MaxInstDestRegs, //< Max dest regs |
| }; |
| |
| |
| /// Return logical index (architectural reg num) of i'th destination reg. |
| /// Only the entries from 0 through numDestRegs()-1 are valid. |
| RegIndex destRegIdx(int i) const { return _destRegIdx[i]; } |
| |
| /// Return logical index (architectural reg num) of i'th source reg. |
| /// Only the entries from 0 through numSrcRegs()-1 are valid. |
| RegIndex srcRegIdx(int i) const { return _srcRegIdx[i]; } |
| |
| /// Pointer to a statically allocated "null" instruction object. |
| /// Used to give eaCompInst() and memAccInst() something to return |
| /// when called on non-memory instructions. |
| static StaticInstPtr<ISA> nullStaticInstPtr; |
| |
| /** |
| * Memory references only: returns "fake" instruction representing |
| * the effective address part of the memory operation. Used to |
| * obtain the dependence info (numSrcRegs and srcRegIdx[]) for |
| * just the EA computation. |
| */ |
| virtual const |
| StaticInstPtr<ISA> &eaCompInst() const { return nullStaticInstPtr; } |
| |
| /** |
| * Memory references only: returns "fake" instruction representing |
| * the memory access part of the memory operation. Used to |
| * obtain the dependence info (numSrcRegs and srcRegIdx[]) for |
| * just the memory access (not the EA computation). |
| */ |
| virtual const |
| StaticInstPtr<ISA> &memAccInst() const { return nullStaticInstPtr; } |
| |
| /// The binary machine instruction. |
| const MachInst machInst; |
| |
| protected: |
| |
| /// See destRegIdx(). |
| RegIndex _destRegIdx[MaxInstDestRegs]; |
| /// See srcRegIdx(). |
| RegIndex _srcRegIdx[MaxInstSrcRegs]; |
| |
| /** |
| * Base mnemonic (e.g., "add"). Used by generateDisassembly() |
| * methods. Also useful to readily identify instructions from |
| * within the debugger when #cachedDisassembly has not been |
| * initialized. |
| */ |
| const char *mnemonic; |
| |
| /** |
| * String representation of disassembly (lazily evaluated via |
| * disassemble()). |
| */ |
| mutable std::string *cachedDisassembly; |
| |
| /** |
| * Internal function to generate disassembly string. |
| */ |
| virtual std::string |
| generateDisassembly(Addr pc, const SymbolTable *symtab) const = 0; |
| |
| /// Constructor. |
| StaticInst(const char *_mnemonic, MachInst _machInst, OpClass __opClass) |
| : StaticInstBase(__opClass), |
| machInst(_machInst), mnemonic(_mnemonic), cachedDisassembly(0) |
| { |
| } |
| |
| public: |
| |
| virtual ~StaticInst() |
| { |
| if (cachedDisassembly) |
| delete cachedDisassembly; |
| } |
| |
| #include "static_inst_impl.hh" |
| |
| /** |
| * Return the target address for a PC-relative branch. |
| * Invalid if not a PC-relative branch (i.e. isDirectCtrl() |
| * should be true). |
| */ |
| virtual Addr branchTarget(Addr branchPC) const |
| { |
| panic("StaticInst::branchTarget() called on instruction " |
| "that is not a PC-relative branch."); |
| } |
| |
| /** |
| * Return the target address for an indirect branch (jump). The |
| * register value is read from the supplied execution context, so |
| * the result is valid only if the execution context is about to |
| * execute the branch in question. Invalid if not an indirect |
| * branch (i.e. isIndirectCtrl() should be true). |
| */ |
| virtual Addr branchTarget(ExecContext *xc) const |
| { |
| panic("StaticInst::branchTarget() called on instruction " |
| "that is not an indirect branch."); |
| } |
| |
| /** |
| * Return true if the instruction is a control transfer, and if so, |
| * return the target address as well. |
| */ |
| bool hasBranchTarget(Addr pc, ExecContext *xc, Addr &tgt) const; |
| |
| /** |
| * Return string representation of disassembled instruction. |
| * The default version of this function will call the internal |
| * virtual generateDisassembly() function to get the string, |
| * then cache it in #cachedDisassembly. If the disassembly |
| * should not be cached, this function should be overridden directly. |
| */ |
| virtual const std::string &disassemble(Addr pc, |
| const SymbolTable *symtab = 0) const |
| { |
| if (!cachedDisassembly) |
| cachedDisassembly = |
| new std::string(generateDisassembly(pc, symtab)); |
| |
| return *cachedDisassembly; |
| } |
| |
| /// Decoded instruction cache type. |
| /// For now we're using a generic hash_map; this seems to work |
| /// pretty well. |
| typedef m5::hash_map<MachInst, StaticInstPtr<ISA> > DecodeCache; |
| |
| /// A cache of decoded instruction objects. |
| static DecodeCache decodeCache; |
| |
| /** |
| * Dump some basic stats on the decode cache hash map. |
| * Only gets called if DECODE_CACHE_HASH_STATS is defined. |
| */ |
| static void dumpDecodeCacheStats(); |
| |
| /// Decode a machine instruction. |
| /// @param mach_inst The binary instruction to decode. |
| /// @retval A pointer to the corresponding StaticInst object. |
| static |
| StaticInstPtr<ISA> decode(MachInst mach_inst) |
| { |
| #ifdef DECODE_CACHE_HASH_STATS |
| // Simple stats on decode hash_map. Turns out the default |
| // hash function is as good as anything I could come up with. |
| const int dump_every_n = 10000000; |
| static int decodes_til_dump = dump_every_n; |
| |
| if (--decodes_til_dump == 0) { |
| dumpDecodeCacheStats(); |
| decodes_til_dump = dump_every_n; |
| } |
| #endif |
| |
| typename DecodeCache::iterator iter = decodeCache.find(mach_inst); |
| if (iter != decodeCache.end()) { |
| return iter->second; |
| } |
| |
| StaticInstPtr<ISA> si = ISA::decodeInst(mach_inst); |
| decodeCache[mach_inst] = si; |
| return si; |
| } |
| }; |
| |
| typedef RefCountingPtr<StaticInstBase> StaticInstBasePtr; |
| |
| /// Reference-counted pointer to a StaticInst object. |
| /// This type should be used instead of "StaticInst<ISA> *" so that |
| /// StaticInst objects can be properly reference-counted. |
| template <class ISA> |
| class StaticInstPtr : public RefCountingPtr<StaticInst<ISA> > |
| { |
| public: |
| /// Constructor. |
| StaticInstPtr() |
| : RefCountingPtr<StaticInst<ISA> >() |
| { |
| } |
| |
| /// Conversion from "StaticInst<ISA> *". |
| StaticInstPtr(StaticInst<ISA> *p) |
| : RefCountingPtr<StaticInst<ISA> >(p) |
| { |
| } |
| |
| /// Copy constructor. |
| StaticInstPtr(const StaticInstPtr &r) |
| : RefCountingPtr<StaticInst<ISA> >(r) |
| { |
| } |
| |
| /// Construct directly from machine instruction. |
| /// Calls StaticInst<ISA>::decode(). |
| StaticInstPtr(typename ISA::MachInst mach_inst) |
| : RefCountingPtr<StaticInst<ISA> >(StaticInst<ISA>::decode(mach_inst)) |
| { |
| } |
| |
| /// Convert to pointer to StaticInstBase class. |
| operator const StaticInstBasePtr() |
| { |
| return this->get(); |
| } |
| }; |
| |
| #endif // __CPU_STATIC_INST_HH__ |