12068SN/A// -*- mode:c++ -*-
22068SN/A
32068SN/A// Copyright (c) 2003-2005 The Regents of The University of Michigan
42068SN/A// All rights reserved.
52068SN/A//
62068SN/A// Redistribution and use in source and binary forms, with or without
72068SN/A// modification, are permitted provided that the following conditions are
82068SN/A// met: redistributions of source code must retain the above copyright
92068SN/A// notice, this list of conditions and the following disclaimer;
102068SN/A// redistributions in binary form must reproduce the above copyright
112068SN/A// notice, this list of conditions and the following disclaimer in the
122068SN/A// documentation and/or other materials provided with the distribution;
132068SN/A// neither the name of the copyright holders nor the names of its
142068SN/A// contributors may be used to endorse or promote products derived from
152068SN/A// this software without specific prior written permission.
162068SN/A//
172068SN/A// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
182068SN/A// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
192068SN/A// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
202068SN/A// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
212068SN/A// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
222068SN/A// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
232068SN/A// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
242068SN/A// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
252068SN/A// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
262068SN/A// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
272068SN/A// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
282665Ssaidi@eecs.umich.edu//
292665Ssaidi@eecs.umich.edu// Authors: Steve Reinhardt
302068SN/A
312649Ssaidi@eecs.umich.edu////////////////////////////////////////////////////////////////////
322649Ssaidi@eecs.umich.edu//
332649Ssaidi@eecs.umich.edu// Control transfer instructions
342649Ssaidi@eecs.umich.edu//
352649Ssaidi@eecs.umich.edu
362068SN/Aoutput header {{
372068SN/A
382068SN/A    /**
392068SN/A     * Base class for instructions whose disassembly is not purely a
402068SN/A     * function of the machine instruction (i.e., it depends on the
412068SN/A     * PC).  This class overrides the disassemble() method to check
422068SN/A     * the PC and symbol table values before re-using a cached
432068SN/A     * disassembly string.  This is necessary for branches and jumps,
442068SN/A     * where the disassembly string includes the target address (which
452068SN/A     * may depend on the PC and/or symbol table).
462068SN/A     */
472068SN/A    class PCDependentDisassembly : public AlphaStaticInst
482068SN/A    {
492068SN/A      protected:
502068SN/A        /// Cached program counter from last disassembly
512068SN/A        mutable Addr cachedPC;
522068SN/A        /// Cached symbol table pointer from last disassembly
532068SN/A        mutable const SymbolTable *cachedSymtab;
542068SN/A
552068SN/A        /// Constructor
562227SN/A        PCDependentDisassembly(const char *mnem, ExtMachInst _machInst,
572068SN/A                               OpClass __opClass)
582068SN/A            : AlphaStaticInst(mnem, _machInst, __opClass),
592068SN/A              cachedPC(0), cachedSymtab(0)
602068SN/A        {
612068SN/A        }
622068SN/A
632068SN/A        const std::string &
642068SN/A        disassemble(Addr pc, const SymbolTable *symtab) const;
652068SN/A    };
662068SN/A
672068SN/A    /**
682068SN/A     * Base class for branches (PC-relative control transfers),
692068SN/A     * conditional or unconditional.
702068SN/A     */
712068SN/A    class Branch : public PCDependentDisassembly
722068SN/A    {
732068SN/A      protected:
742068SN/A        /// Displacement to target address (signed).
752068SN/A        int32_t disp;
762068SN/A
772068SN/A        /// Constructor.
782227SN/A        Branch(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
792068SN/A            : PCDependentDisassembly(mnem, _machInst, __opClass),
802068SN/A              disp(BRDISP << 2)
812068SN/A        {
822068SN/A        }
832068SN/A
8412616Sgabeblack@google.com        AlphaISA::PCState branchTarget(
8512616Sgabeblack@google.com                const AlphaISA::PCState &branchPC) const override;
862068SN/A
879552Sandreas.hansson@arm.com        /// Explicitly import the otherwise hidden branchTarget
889552Sandreas.hansson@arm.com        using StaticInst::branchTarget;
899552Sandreas.hansson@arm.com
9012616Sgabeblack@google.com        std::string generateDisassembly(
9112616Sgabeblack@google.com                Addr pc, const SymbolTable *symtab) const override;
922068SN/A    };
932068SN/A
942068SN/A    /**
952068SN/A     * Base class for jumps (register-indirect control transfers).  In
962068SN/A     * the Alpha ISA, these are always unconditional.
972068SN/A     */
982068SN/A    class Jump : public PCDependentDisassembly
992068SN/A    {
1002068SN/A      protected:
1012068SN/A
1022068SN/A        /// Displacement to target address (signed).
1032068SN/A        int32_t disp;
1042068SN/A
1052068SN/A      public:
1062068SN/A        /// Constructor
1072227SN/A        Jump(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
1082068SN/A            : PCDependentDisassembly(mnem, _machInst, __opClass),
1092068SN/A              disp(BRDISP)
1102068SN/A        {
1112068SN/A        }
1122068SN/A
11312616Sgabeblack@google.com        AlphaISA::PCState branchTarget(ThreadContext *tc) const override;
1142068SN/A
1159552Sandreas.hansson@arm.com        /// Explicitly import the otherwise hidden branchTarget
1169552Sandreas.hansson@arm.com        using StaticInst::branchTarget;
1179552Sandreas.hansson@arm.com
11812616Sgabeblack@google.com        std::string generateDisassembly(
11912616Sgabeblack@google.com                Addr pc, const SymbolTable *symtab) const override;
1202068SN/A    };
1212068SN/A}};
1222068SN/A
1232068SN/Aoutput decoder {{
1247720Sgblack@eecs.umich.edu    AlphaISA::PCState
1257720Sgblack@eecs.umich.edu    Branch::branchTarget(const AlphaISA::PCState &branchPC) const
1262068SN/A    {
1277720Sgblack@eecs.umich.edu        return branchPC.pc() + 4 + disp;
1282068SN/A    }
1292068SN/A
1307720Sgblack@eecs.umich.edu    AlphaISA::PCState
1312680Sktlim@umich.edu    Jump::branchTarget(ThreadContext *tc) const
1322068SN/A    {
1337720Sgblack@eecs.umich.edu        PCState pc = tc->pcState();
13412106SRekai.GonzalezAlberquilla@arm.com        uint64_t Rb = tc->readIntReg(_srcRegIdx[0].index());
1357720Sgblack@eecs.umich.edu        pc.set((Rb & ~3) | (pc.pc() & 1));
1367720Sgblack@eecs.umich.edu        return pc;
1372068SN/A    }
1382068SN/A
1392068SN/A    const std::string &
1402068SN/A    PCDependentDisassembly::disassemble(Addr pc,
1412068SN/A                                        const SymbolTable *symtab) const
1422068SN/A    {
1432068SN/A        if (!cachedDisassembly ||
1442068SN/A            pc != cachedPC || symtab != cachedSymtab)
1452068SN/A        {
1462068SN/A            if (cachedDisassembly)
1472068SN/A                delete cachedDisassembly;
1482068SN/A
1492068SN/A            cachedDisassembly =
1502068SN/A                new std::string(generateDisassembly(pc, symtab));
1512068SN/A            cachedPC = pc;
1522068SN/A            cachedSymtab = symtab;
1532068SN/A        }
1542068SN/A
1552068SN/A        return *cachedDisassembly;
1562068SN/A    }
1572068SN/A
1582068SN/A    std::string
1592068SN/A    Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
1602068SN/A    {
1612068SN/A        std::stringstream ss;
1622068SN/A
1632068SN/A        ccprintf(ss, "%-10s ", mnemonic);
1642068SN/A
1652068SN/A        // There's only one register arg (RA), but it could be
1662068SN/A        // either a source (the condition for conditional
1672068SN/A        // branches) or a destination (the link reg for
1682068SN/A        // unconditional branches)
1692068SN/A        if (_numSrcRegs > 0) {
1702068SN/A            printReg(ss, _srcRegIdx[0]);
1712068SN/A            ss << ",";
1722068SN/A        }
1732068SN/A        else if (_numDestRegs > 0) {
1742068SN/A            printReg(ss, _destRegIdx[0]);
1752068SN/A            ss << ",";
1762068SN/A        }
1772068SN/A
1782068SN/A#ifdef SS_COMPATIBLE_DISASSEMBLY
1792068SN/A        if (_numSrcRegs == 0 && _numDestRegs == 0) {
1802068SN/A            printReg(ss, 31);
1812068SN/A            ss << ",";
1822068SN/A        }
1832068SN/A#endif
1842068SN/A
1852068SN/A        Addr target = pc + 4 + disp;
1862068SN/A
1872068SN/A        std::string str;
1882068SN/A        if (symtab && symtab->findSymbol(target, str))
1892068SN/A            ss << str;
1902068SN/A        else
1912068SN/A            ccprintf(ss, "0x%x", target);
1922068SN/A
1932068SN/A        return ss.str();
1942068SN/A    }
1952068SN/A
1962068SN/A    std::string
1972068SN/A    Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
1982068SN/A    {
1992068SN/A        std::stringstream ss;
2002068SN/A
2012068SN/A        ccprintf(ss, "%-10s ", mnemonic);
2022068SN/A
2032068SN/A#ifdef SS_COMPATIBLE_DISASSEMBLY
2042068SN/A        if (_numDestRegs == 0) {
2052068SN/A            printReg(ss, 31);
2062068SN/A            ss << ",";
2072068SN/A        }
2082068SN/A#endif
2092068SN/A
2102068SN/A        if (_numDestRegs > 0) {
2112068SN/A            printReg(ss, _destRegIdx[0]);
2122068SN/A            ss << ",";
2132068SN/A        }
2142068SN/A
2152068SN/A        ccprintf(ss, "(r%d)", RB);
2162068SN/A
2172068SN/A        return ss.str();
2182068SN/A    }
2192068SN/A}};
2202068SN/A
2212068SN/Adef template JumpOrBranchDecode {{
2222068SN/A    return (RA == 31)
2232107SN/A        ? (StaticInst *)new %(class_name)s(machInst)
2242107SN/A        : (StaticInst *)new %(class_name)sAndLink(machInst);
2252068SN/A}};
2262068SN/A
2272068SN/Adef format CondBranch(code) {{
2287720Sgblack@eecs.umich.edu    code = '''
2297720Sgblack@eecs.umich.edu        bool cond;
2307720Sgblack@eecs.umich.edu        %(code)s;
2317720Sgblack@eecs.umich.edu        if (cond)
2327794Sgblack@eecs.umich.edu            NPC = NPC + disp;
2337794Sgblack@eecs.umich.edu        else
2347794Sgblack@eecs.umich.edu            NPC = NPC;
2357720Sgblack@eecs.umich.edu    ''' % { "code" : code }
2363953Sstever@eecs.umich.edu    iop = InstObjParams(name, Name, 'Branch', code,
2372068SN/A                        ('IsDirectControl', 'IsCondControl'))
2382068SN/A    header_output = BasicDeclare.subst(iop)
2392068SN/A    decoder_output = BasicConstructor.subst(iop)
2402068SN/A    decode_block = BasicDecode.subst(iop)
2412068SN/A    exec_output = BasicExecute.subst(iop)
2422068SN/A}};
2432068SN/A
2442068SN/Alet {{
2452068SN/Adef UncondCtrlBase(name, Name, base_class, npc_expr, flags):
2462068SN/A    # Declare basic control transfer w/o link (i.e. link reg is R31)
2477794Sgblack@eecs.umich.edu    nolink_code = 'NPC = %s;\n' % npc_expr
2487720Sgblack@eecs.umich.edu    nolink_iop = InstObjParams(name, Name, base_class,
2497794Sgblack@eecs.umich.edu                               nolink_code, flags)
2502068SN/A    header_output = BasicDeclare.subst(nolink_iop)
2512068SN/A    decoder_output = BasicConstructor.subst(nolink_iop)
2522068SN/A    exec_output = BasicExecute.subst(nolink_iop)
2532068SN/A
2542068SN/A    # Generate declaration of '*AndLink' version, append to decls
2557794Sgblack@eecs.umich.edu    link_code = 'Ra = NPC & ~3;\n' + nolink_code
2562068SN/A    link_iop = InstObjParams(name, Name + 'AndLink', base_class,
2577794Sgblack@eecs.umich.edu                             link_code, flags)
2582068SN/A    header_output += BasicDeclare.subst(link_iop)
2592068SN/A    decoder_output += BasicConstructor.subst(link_iop)
2602068SN/A    exec_output += BasicExecute.subst(link_iop)
2612068SN/A
2622068SN/A    # need to use link_iop for the decode template since it is expecting
2632068SN/A    # the shorter version of class_name (w/o "AndLink")
2642068SN/A
2652068SN/A    return (header_output, decoder_output,
2662068SN/A            JumpOrBranchDecode.subst(nolink_iop), exec_output)
2672068SN/A}};
2682068SN/A
2692068SN/Adef format UncondBranch(*flags) {{
2702068SN/A    flags += ('IsUncondControl', 'IsDirectControl')
2712068SN/A    (header_output, decoder_output, decode_block, exec_output) = \
2727794Sgblack@eecs.umich.edu        UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags)
2732068SN/A}};
2742068SN/A
2752068SN/Adef format Jump(*flags) {{
2762068SN/A    flags += ('IsUncondControl', 'IsIndirectControl')
2772068SN/A    (header_output, decoder_output, decode_block, exec_output) = \
2787794Sgblack@eecs.umich.edu        UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags)
2792068SN/A}};
2802068SN/A
2812068SN/A
282