branch.isa revision 2227
12929Sktlim@umich.edu// -*- mode:c++ -*-
22929Sktlim@umich.edu
32932Sktlim@umich.edu// Copyright (c) 2003-2005 The Regents of The University of Michigan
42929Sktlim@umich.edu// All rights reserved.
52929Sktlim@umich.edu//
62929Sktlim@umich.edu// Redistribution and use in source and binary forms, with or without
72929Sktlim@umich.edu// modification, are permitted provided that the following conditions are
82929Sktlim@umich.edu// met: redistributions of source code must retain the above copyright
92929Sktlim@umich.edu// notice, this list of conditions and the following disclaimer;
102929Sktlim@umich.edu// redistributions in binary form must reproduce the above copyright
112929Sktlim@umich.edu// notice, this list of conditions and the following disclaimer in the
122929Sktlim@umich.edu// documentation and/or other materials provided with the distribution;
132929Sktlim@umich.edu// neither the name of the copyright holders nor the names of its
142929Sktlim@umich.edu// contributors may be used to endorse or promote products derived from
152929Sktlim@umich.edu// this software without specific prior written permission.
162929Sktlim@umich.edu//
172929Sktlim@umich.edu// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
182929Sktlim@umich.edu// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
192929Sktlim@umich.edu// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
202929Sktlim@umich.edu// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
212929Sktlim@umich.edu// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
222929Sktlim@umich.edu// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
232929Sktlim@umich.edu// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
242929Sktlim@umich.edu// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
252929Sktlim@umich.edu// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
262929Sktlim@umich.edu// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
272929Sktlim@umich.edu// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
282932Sktlim@umich.edu
292932Sktlim@umich.eduoutput header {{
302932Sktlim@umich.edu
312929Sktlim@umich.edu    /**
326007Ssteve.reinhardt@amd.com     * Base class for instructions whose disassembly is not purely a
337735SAli.Saidi@ARM.com     * function of the machine instruction (i.e., it depends on the
342929Sktlim@umich.edu     * PC).  This class overrides the disassemble() method to check
352929Sktlim@umich.edu     * the PC and symbol table values before re-using a cached
362929Sktlim@umich.edu     * disassembly string.  This is necessary for branches and jumps,
372929Sktlim@umich.edu     * where the disassembly string includes the target address (which
382929Sktlim@umich.edu     * may depend on the PC and/or symbol table).
392929Sktlim@umich.edu     */
402929Sktlim@umich.edu    class PCDependentDisassembly : public AlphaStaticInst
418947Sandreas.hansson@arm.com    {
428947Sandreas.hansson@arm.com      protected:
438947Sandreas.hansson@arm.com        /// Cached program counter from last disassembly
442929Sktlim@umich.edu        mutable Addr cachedPC;
452929Sktlim@umich.edu        /// Cached symbol table pointer from last disassembly
462929Sktlim@umich.edu        mutable const SymbolTable *cachedSymtab;
472929Sktlim@umich.edu
482929Sktlim@umich.edu        /// Constructor
492929Sktlim@umich.edu        PCDependentDisassembly(const char *mnem, ExtMachInst _machInst,
506007Ssteve.reinhardt@amd.com                               OpClass __opClass)
516007Ssteve.reinhardt@amd.com            : AlphaStaticInst(mnem, _machInst, __opClass),
526007Ssteve.reinhardt@amd.com              cachedPC(0), cachedSymtab(0)
536007Ssteve.reinhardt@amd.com        {
546007Ssteve.reinhardt@amd.com        }
556007Ssteve.reinhardt@amd.com
566007Ssteve.reinhardt@amd.com        const std::string &
576007Ssteve.reinhardt@amd.com        disassemble(Addr pc, const SymbolTable *symtab) const;
586007Ssteve.reinhardt@amd.com    };
596007Ssteve.reinhardt@amd.com
606007Ssteve.reinhardt@amd.com    /**
616007Ssteve.reinhardt@amd.com     * Base class for branches (PC-relative control transfers),
626007Ssteve.reinhardt@amd.com     * conditional or unconditional.
636007Ssteve.reinhardt@amd.com     */
646007Ssteve.reinhardt@amd.com    class Branch : public PCDependentDisassembly
656007Ssteve.reinhardt@amd.com    {
669435SAndreas.Sandberg@ARM.com      protected:
679435SAndreas.Sandberg@ARM.com        /// Displacement to target address (signed).
689435SAndreas.Sandberg@ARM.com        int32_t disp;
696007Ssteve.reinhardt@amd.com
706007Ssteve.reinhardt@amd.com        /// Constructor.
716007Ssteve.reinhardt@amd.com        Branch(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
726007Ssteve.reinhardt@amd.com            : PCDependentDisassembly(mnem, _machInst, __opClass),
736007Ssteve.reinhardt@amd.com              disp(BRDISP << 2)
746007Ssteve.reinhardt@amd.com        {
756007Ssteve.reinhardt@amd.com        }
766007Ssteve.reinhardt@amd.com
776007Ssteve.reinhardt@amd.com        Addr branchTarget(Addr branchPC) const;
786007Ssteve.reinhardt@amd.com
792929Sktlim@umich.edu        std::string
802929Sktlim@umich.edu        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
812929Sktlim@umich.edu    };
826007Ssteve.reinhardt@amd.com
836007Ssteve.reinhardt@amd.com    /**
846007Ssteve.reinhardt@amd.com     * Base class for jumps (register-indirect control transfers).  In
859781Sandreas.hansson@arm.com     * the Alpha ISA, these are always unconditional.
866007Ssteve.reinhardt@amd.com     */
876007Ssteve.reinhardt@amd.com    class Jump : public PCDependentDisassembly
882929Sktlim@umich.edu    {
892929Sktlim@umich.edu      protected:
902929Sktlim@umich.edu
912929Sktlim@umich.edu        /// Displacement to target address (signed).
922929Sktlim@umich.edu        int32_t disp;
936011Ssteve.reinhardt@amd.com
946007Ssteve.reinhardt@amd.com      public:
956007Ssteve.reinhardt@amd.com        /// Constructor
966007Ssteve.reinhardt@amd.com        Jump(const char *mnem, ExtMachInst _machInst, OpClass __opClass)
976007Ssteve.reinhardt@amd.com            : PCDependentDisassembly(mnem, _machInst, __opClass),
986007Ssteve.reinhardt@amd.com              disp(BRDISP)
996007Ssteve.reinhardt@amd.com        {
1006007Ssteve.reinhardt@amd.com        }
1016007Ssteve.reinhardt@amd.com
1026007Ssteve.reinhardt@amd.com        Addr branchTarget(ExecContext *xc) const;
1036007Ssteve.reinhardt@amd.com
1046007Ssteve.reinhardt@amd.com        std::string
1056007Ssteve.reinhardt@amd.com        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
1066007Ssteve.reinhardt@amd.com    };
10710384SCurtis.Dunham@arm.com}};
10810384SCurtis.Dunham@arm.com
10910384SCurtis.Dunham@arm.comoutput decoder {{
11010384SCurtis.Dunham@arm.com    Addr
1116007Ssteve.reinhardt@amd.com    Branch::branchTarget(Addr branchPC) const
1129781Sandreas.hansson@arm.com    {
1139781Sandreas.hansson@arm.com        return branchPC + 4 + disp;
1149781Sandreas.hansson@arm.com    }
1159781Sandreas.hansson@arm.com
1167735SAli.Saidi@ARM.com    Addr
1176011Ssteve.reinhardt@amd.com    Jump::branchTarget(ExecContext *xc) const
1186007Ssteve.reinhardt@amd.com    {
1199781Sandreas.hansson@arm.com        Addr NPC = xc->readPC() + 4;
1206007Ssteve.reinhardt@amd.com        uint64_t Rb = xc->readIntReg(_srcRegIdx[0]);
1216007Ssteve.reinhardt@amd.com        return (Rb & ~3) | (NPC & 1);
1227735SAli.Saidi@ARM.com    }
1237735SAli.Saidi@ARM.com
1247735SAli.Saidi@ARM.com    const std::string &
1257735SAli.Saidi@ARM.com    PCDependentDisassembly::disassemble(Addr pc,
1267735SAli.Saidi@ARM.com                                        const SymbolTable *symtab) const
1277735SAli.Saidi@ARM.com    {
1287735SAli.Saidi@ARM.com        if (!cachedDisassembly ||
1297735SAli.Saidi@ARM.com            pc != cachedPC || symtab != cachedSymtab)
1307735SAli.Saidi@ARM.com        {
1317735SAli.Saidi@ARM.com            if (cachedDisassembly)
1327735SAli.Saidi@ARM.com                delete cachedDisassembly;
1337735SAli.Saidi@ARM.com
1347735SAli.Saidi@ARM.com            cachedDisassembly =
1357735SAli.Saidi@ARM.com                new std::string(generateDisassembly(pc, symtab));
1366007Ssteve.reinhardt@amd.com            cachedPC = pc;
1378599Ssteve.reinhardt@amd.com            cachedSymtab = symtab;
1388599Ssteve.reinhardt@amd.com        }
1398599Ssteve.reinhardt@amd.com
1406007Ssteve.reinhardt@amd.com        return *cachedDisassembly;
1416011Ssteve.reinhardt@amd.com    }
1426007Ssteve.reinhardt@amd.com
1436007Ssteve.reinhardt@amd.com    std::string
1446007Ssteve.reinhardt@amd.com    Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
1456007Ssteve.reinhardt@amd.com    {
1466007Ssteve.reinhardt@amd.com        std::stringstream ss;
1476007Ssteve.reinhardt@amd.com
1489781Sandreas.hansson@arm.com        ccprintf(ss, "%-10s ", mnemonic);
1499781Sandreas.hansson@arm.com
1509781Sandreas.hansson@arm.com        // There's only one register arg (RA), but it could be
1519781Sandreas.hansson@arm.com        // either a source (the condition for conditional
1526007Ssteve.reinhardt@amd.com        // branches) or a destination (the link reg for
1536007Ssteve.reinhardt@amd.com        // unconditional branches)
1546007Ssteve.reinhardt@amd.com        if (_numSrcRegs > 0) {
1559781Sandreas.hansson@arm.com            printReg(ss, _srcRegIdx[0]);
1569781Sandreas.hansson@arm.com            ss << ",";
1579781Sandreas.hansson@arm.com        }
1589781Sandreas.hansson@arm.com        else if (_numDestRegs > 0) {
15910384SCurtis.Dunham@arm.com            printReg(ss, _destRegIdx[0]);
16010384SCurtis.Dunham@arm.com            ss << ",";
16110384SCurtis.Dunham@arm.com        }
1629781Sandreas.hansson@arm.com
1636008Ssteve.reinhardt@amd.com#ifdef SS_COMPATIBLE_DISASSEMBLY
1646008Ssteve.reinhardt@amd.com        if (_numSrcRegs == 0 && _numDestRegs == 0) {
1656008Ssteve.reinhardt@amd.com            printReg(ss, 31);
1666008Ssteve.reinhardt@amd.com            ss << ",";
1676008Ssteve.reinhardt@amd.com        }
1689401SAndreas.Sandberg@ARM.com#endif
1699781Sandreas.hansson@arm.com
1709781Sandreas.hansson@arm.com        Addr target = pc + 4 + disp;
1716008Ssteve.reinhardt@amd.com
1729781Sandreas.hansson@arm.com        std::string str;
1736007Ssteve.reinhardt@amd.com        if (symtab && symtab->findSymbol(target, str))
1746007Ssteve.reinhardt@amd.com            ss << str;
1756007Ssteve.reinhardt@amd.com        else
1766007Ssteve.reinhardt@amd.com            ccprintf(ss, "0x%x", target);
1779781Sandreas.hansson@arm.com
1786007Ssteve.reinhardt@amd.com        return ss.str();
1796007Ssteve.reinhardt@amd.com    }
1802929Sktlim@umich.edu
1812929Sktlim@umich.edu    std::string
1822929Sktlim@umich.edu    Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
1832929Sktlim@umich.edu    {
1846007Ssteve.reinhardt@amd.com        std::stringstream ss;
1856007Ssteve.reinhardt@amd.com
1862929Sktlim@umich.edu        ccprintf(ss, "%-10s ", mnemonic);
1872929Sktlim@umich.edu
1886007Ssteve.reinhardt@amd.com#ifdef SS_COMPATIBLE_DISASSEMBLY
1892929Sktlim@umich.edu        if (_numDestRegs == 0) {
1902929Sktlim@umich.edu            printReg(ss, 31);
1918947Sandreas.hansson@arm.com            ss << ",";
1928947Sandreas.hansson@arm.com        }
1938947Sandreas.hansson@arm.com#endif
1948947Sandreas.hansson@arm.com
1958947Sandreas.hansson@arm.com        if (_numDestRegs > 0) {
1968947Sandreas.hansson@arm.com            printReg(ss, _destRegIdx[0]);
1978947Sandreas.hansson@arm.com            ss << ",";
1988947Sandreas.hansson@arm.com        }
1998947Sandreas.hansson@arm.com
2008947Sandreas.hansson@arm.com        ccprintf(ss, "(r%d)", RB);
20110384SCurtis.Dunham@arm.com
2028947Sandreas.hansson@arm.com        return ss.str();
2039781Sandreas.hansson@arm.com    }
2049781Sandreas.hansson@arm.com}};
2058947Sandreas.hansson@arm.com
2068947Sandreas.hansson@arm.comdef template JumpOrBranchDecode {{
2079401SAndreas.Sandberg@ARM.com    return (RA == 31)
2089781Sandreas.hansson@arm.com        ? (StaticInst *)new %(class_name)s(machInst)
2098947Sandreas.hansson@arm.com        : (StaticInst *)new %(class_name)sAndLink(machInst);
2108947Sandreas.hansson@arm.com}};
2118947Sandreas.hansson@arm.com
2128947Sandreas.hansson@arm.comdef format CondBranch(code) {{
2138947Sandreas.hansson@arm.com    code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n';
2148947Sandreas.hansson@arm.com    iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
2152929Sktlim@umich.edu                        ('IsDirectControl', 'IsCondControl'))
2162929Sktlim@umich.edu    header_output = BasicDeclare.subst(iop)
2172929Sktlim@umich.edu    decoder_output = BasicConstructor.subst(iop)
2182929Sktlim@umich.edu    decode_block = BasicDecode.subst(iop)
2194937Sstever@gmail.com    exec_output = BasicExecute.subst(iop)
2204937Sstever@gmail.com}};
2214937Sstever@gmail.com
2224937Sstever@gmail.comlet {{
2238120Sgblack@eecs.umich.edudef UncondCtrlBase(name, Name, base_class, npc_expr, flags):
2244937Sstever@gmail.com    # Declare basic control transfer w/o link (i.e. link reg is R31)
2254937Sstever@gmail.com    nolink_code = 'NPC = %s;\n' % npc_expr
2264937Sstever@gmail.com    nolink_iop = InstObjParams(name, Name, base_class,
2274937Sstever@gmail.com                               CodeBlock(nolink_code), flags)
2285773Snate@binkert.org    header_output = BasicDeclare.subst(nolink_iop)
2294937Sstever@gmail.com    decoder_output = BasicConstructor.subst(nolink_iop)
2304937Sstever@gmail.com    exec_output = BasicExecute.subst(nolink_iop)
2314937Sstever@gmail.com
2322929Sktlim@umich.edu    # Generate declaration of '*AndLink' version, append to decls
2332929Sktlim@umich.edu    link_code = 'Ra = NPC & ~3;\n' + nolink_code
2342929Sktlim@umich.edu    link_iop = InstObjParams(name, Name + 'AndLink', base_class,
2355773Snate@binkert.org                             CodeBlock(link_code), flags)
2362929Sktlim@umich.edu    header_output += BasicDeclare.subst(link_iop)
2372929Sktlim@umich.edu    decoder_output += BasicConstructor.subst(link_iop)
2382929Sktlim@umich.edu    exec_output += BasicExecute.subst(link_iop)
2392929Sktlim@umich.edu
2402929Sktlim@umich.edu    # need to use link_iop for the decode template since it is expecting
2412929Sktlim@umich.edu    # the shorter version of class_name (w/o "AndLink")
2424937Sstever@gmail.com
2434937Sstever@gmail.com    return (header_output, decoder_output,
2444937Sstever@gmail.com            JumpOrBranchDecode.subst(nolink_iop), exec_output)
2454937Sstever@gmail.com}};
2464937Sstever@gmail.com
2474937Sstever@gmail.comdef format UncondBranch(*flags) {{
2484937Sstever@gmail.com    flags += ('IsUncondControl', 'IsDirectControl')
2494937Sstever@gmail.com    (header_output, decoder_output, decode_block, exec_output) = \
2504937Sstever@gmail.com        UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags)
2514937Sstever@gmail.com}};
2524937Sstever@gmail.com
2534937Sstever@gmail.comdef format Jump(*flags) {{
2544937Sstever@gmail.com    flags += ('IsUncondControl', 'IsIndirectControl')
2554937Sstever@gmail.com    (header_output, decoder_output, decode_block, exec_output) = \
2564937Sstever@gmail.com        UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags)
2572929Sktlim@umich.edu}};
2582929Sktlim@umich.edu
2592929Sktlim@umich.edu
2602929Sktlim@umich.edu