branch.isa revision 2649
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.
282068SN/A
292649Ssaidi@eecs.umich.edu////////////////////////////////////////////////////////////////////
302649Ssaidi@eecs.umich.edu//
312649Ssaidi@eecs.umich.edu// Control transfer instructions
322649Ssaidi@eecs.umich.edu//
332649Ssaidi@eecs.umich.edu
342068SN/Aoutput header {{
352068SN/A
362068SN/A    /**
372068SN/A     * Base class for instructions whose disassembly is not purely a
382068SN/A     * function of the machine instruction (i.e., it depends on the
392068SN/A     * PC).  This class overrides the disassemble() method to check
402068SN/A     * the PC and symbol table values before re-using a cached
412068SN/A     * disassembly string.  This is necessary for branches and jumps,
422068SN/A     * where the disassembly string includes the target address (which
432068SN/A     * may depend on the PC and/or symbol table).
442068SN/A     */
452068SN/A    class PCDependentDisassembly : public AlphaStaticInst
462068SN/A    {
472068SN/A      protected:
482068SN/A        /// Cached program counter from last disassembly
492068SN/A        mutable Addr cachedPC;
502068SN/A        /// Cached symbol table pointer from last disassembly
512068SN/A        mutable const SymbolTable *cachedSymtab;
522068SN/A
532068SN/A        /// Constructor
542227SN/A        PCDependentDisassembly(const char *mnem, ExtMachInst _machInst,
552068SN/A                               OpClass __opClass)
562068SN/A            : AlphaStaticInst(mnem, _machInst, __opClass),
572068SN/A              cachedPC(0), cachedSymtab(0)
582068SN/A        {
592068SN/A        }
602068SN/A
612068SN/A        const std::string &
622068SN/A        disassemble(Addr pc, const SymbolTable *symtab) const;
632068SN/A    };
642068SN/A
652068SN/A    /**
662068SN/A     * Base class for branches (PC-relative control transfers),
672068SN/A     * conditional or unconditional.
682068SN/A     */
692068SN/A    class Branch : public PCDependentDisassembly
702068SN/A    {
712068SN/A      protected:
722068SN/A        /// Displacement to target address (signed).
732068SN/A        int32_t disp;
742068SN/A
752068SN/A        /// Constructor.
762227SN/A        Branch(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
772068SN/A            : PCDependentDisassembly(mnem, _machInst, __opClass),
782068SN/A              disp(BRDISP << 2)
792068SN/A        {
802068SN/A        }
812068SN/A
822068SN/A        Addr branchTarget(Addr branchPC) const;
832068SN/A
842068SN/A        std::string
852068SN/A        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
862068SN/A    };
872068SN/A
882068SN/A    /**
892068SN/A     * Base class for jumps (register-indirect control transfers).  In
902068SN/A     * the Alpha ISA, these are always unconditional.
912068SN/A     */
922068SN/A    class Jump : public PCDependentDisassembly
932068SN/A    {
942068SN/A      protected:
952068SN/A
962068SN/A        /// Displacement to target address (signed).
972068SN/A        int32_t disp;
982068SN/A
992068SN/A      public:
1002068SN/A        /// Constructor
1012227SN/A        Jump(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
1022068SN/A            : PCDependentDisassembly(mnem, _machInst, __opClass),
1032068SN/A              disp(BRDISP)
1042068SN/A        {
1052068SN/A        }
1062068SN/A
1072068SN/A        Addr branchTarget(ExecContext *xc) const;
1082068SN/A
1092068SN/A        std::string
1102068SN/A        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
1112068SN/A    };
1122068SN/A}};
1132068SN/A
1142068SN/Aoutput decoder {{
1152068SN/A    Addr
1162068SN/A    Branch::branchTarget(Addr branchPC) const
1172068SN/A    {
1182068SN/A        return branchPC + 4 + disp;
1192068SN/A    }
1202068SN/A
1212068SN/A    Addr
1222068SN/A    Jump::branchTarget(ExecContext *xc) const
1232068SN/A    {
1242068SN/A        Addr NPC = xc->readPC() + 4;
1252068SN/A        uint64_t Rb = xc->readIntReg(_srcRegIdx[0]);
1262068SN/A        return (Rb & ~3) | (NPC & 1);
1272068SN/A    }
1282068SN/A
1292068SN/A    const std::string &
1302068SN/A    PCDependentDisassembly::disassemble(Addr pc,
1312068SN/A                                        const SymbolTable *symtab) const
1322068SN/A    {
1332068SN/A        if (!cachedDisassembly ||
1342068SN/A            pc != cachedPC || symtab != cachedSymtab)
1352068SN/A        {
1362068SN/A            if (cachedDisassembly)
1372068SN/A                delete cachedDisassembly;
1382068SN/A
1392068SN/A            cachedDisassembly =
1402068SN/A                new std::string(generateDisassembly(pc, symtab));
1412068SN/A            cachedPC = pc;
1422068SN/A            cachedSymtab = symtab;
1432068SN/A        }
1442068SN/A
1452068SN/A        return *cachedDisassembly;
1462068SN/A    }
1472068SN/A
1482068SN/A    std::string
1492068SN/A    Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
1502068SN/A    {
1512068SN/A        std::stringstream ss;
1522068SN/A
1532068SN/A        ccprintf(ss, "%-10s ", mnemonic);
1542068SN/A
1552068SN/A        // There's only one register arg (RA), but it could be
1562068SN/A        // either a source (the condition for conditional
1572068SN/A        // branches) or a destination (the link reg for
1582068SN/A        // unconditional branches)
1592068SN/A        if (_numSrcRegs > 0) {
1602068SN/A            printReg(ss, _srcRegIdx[0]);
1612068SN/A            ss << ",";
1622068SN/A        }
1632068SN/A        else if (_numDestRegs > 0) {
1642068SN/A            printReg(ss, _destRegIdx[0]);
1652068SN/A            ss << ",";
1662068SN/A        }
1672068SN/A
1682068SN/A#ifdef SS_COMPATIBLE_DISASSEMBLY
1692068SN/A        if (_numSrcRegs == 0 && _numDestRegs == 0) {
1702068SN/A            printReg(ss, 31);
1712068SN/A            ss << ",";
1722068SN/A        }
1732068SN/A#endif
1742068SN/A
1752068SN/A        Addr target = pc + 4 + disp;
1762068SN/A
1772068SN/A        std::string str;
1782068SN/A        if (symtab && symtab->findSymbol(target, str))
1792068SN/A            ss << str;
1802068SN/A        else
1812068SN/A            ccprintf(ss, "0x%x", target);
1822068SN/A
1832068SN/A        return ss.str();
1842068SN/A    }
1852068SN/A
1862068SN/A    std::string
1872068SN/A    Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
1882068SN/A    {
1892068SN/A        std::stringstream ss;
1902068SN/A
1912068SN/A        ccprintf(ss, "%-10s ", mnemonic);
1922068SN/A
1932068SN/A#ifdef SS_COMPATIBLE_DISASSEMBLY
1942068SN/A        if (_numDestRegs == 0) {
1952068SN/A            printReg(ss, 31);
1962068SN/A            ss << ",";
1972068SN/A        }
1982068SN/A#endif
1992068SN/A
2002068SN/A        if (_numDestRegs > 0) {
2012068SN/A            printReg(ss, _destRegIdx[0]);
2022068SN/A            ss << ",";
2032068SN/A        }
2042068SN/A
2052068SN/A        ccprintf(ss, "(r%d)", RB);
2062068SN/A
2072068SN/A        return ss.str();
2082068SN/A    }
2092068SN/A}};
2102068SN/A
2112068SN/Adef template JumpOrBranchDecode {{
2122068SN/A    return (RA == 31)
2132107SN/A        ? (StaticInst *)new %(class_name)s(machInst)
2142107SN/A        : (StaticInst *)new %(class_name)sAndLink(machInst);
2152068SN/A}};
2162068SN/A
2172068SN/Adef format CondBranch(code) {{
2182068SN/A    code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n';
2192068SN/A    iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
2202068SN/A                        ('IsDirectControl', 'IsCondControl'))
2212068SN/A    header_output = BasicDeclare.subst(iop)
2222068SN/A    decoder_output = BasicConstructor.subst(iop)
2232068SN/A    decode_block = BasicDecode.subst(iop)
2242068SN/A    exec_output = BasicExecute.subst(iop)
2252068SN/A}};
2262068SN/A
2272068SN/Alet {{
2282068SN/Adef UncondCtrlBase(name, Name, base_class, npc_expr, flags):
2292068SN/A    # Declare basic control transfer w/o link (i.e. link reg is R31)
2302068SN/A    nolink_code = 'NPC = %s;\n' % npc_expr
2312068SN/A    nolink_iop = InstObjParams(name, Name, base_class,
2322068SN/A                               CodeBlock(nolink_code), flags)
2332068SN/A    header_output = BasicDeclare.subst(nolink_iop)
2342068SN/A    decoder_output = BasicConstructor.subst(nolink_iop)
2352068SN/A    exec_output = BasicExecute.subst(nolink_iop)
2362068SN/A
2372068SN/A    # Generate declaration of '*AndLink' version, append to decls
2382068SN/A    link_code = 'Ra = NPC & ~3;\n' + nolink_code
2392068SN/A    link_iop = InstObjParams(name, Name + 'AndLink', base_class,
2402068SN/A                             CodeBlock(link_code), flags)
2412068SN/A    header_output += BasicDeclare.subst(link_iop)
2422068SN/A    decoder_output += BasicConstructor.subst(link_iop)
2432068SN/A    exec_output += BasicExecute.subst(link_iop)
2442068SN/A
2452068SN/A    # need to use link_iop for the decode template since it is expecting
2462068SN/A    # the shorter version of class_name (w/o "AndLink")
2472068SN/A
2482068SN/A    return (header_output, decoder_output,
2492068SN/A            JumpOrBranchDecode.subst(nolink_iop), exec_output)
2502068SN/A}};
2512068SN/A
2522068SN/Adef format UncondBranch(*flags) {{
2532068SN/A    flags += ('IsUncondControl', 'IsDirectControl')
2542068SN/A    (header_output, decoder_output, decode_block, exec_output) = \
2552068SN/A        UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags)
2562068SN/A}};
2572068SN/A
2582068SN/Adef format Jump(*flags) {{
2592068SN/A    flags += ('IsUncondControl', 'IsIndirectControl')
2602068SN/A    (header_output, decoder_output, decode_block, exec_output) = \
2612068SN/A        UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags)
2622068SN/A}};
2632068SN/A
2642068SN/A
265