branch.isa revision 7741
12391SN/A// Copyright (c) 2006-2007 The Regents of The University of Michigan
28931Sandreas.hansson@arm.com// All rights reserved.
37733SN/A//
47733SN/A// Redistribution and use in source and binary forms, with or without
57733SN/A// modification, are permitted provided that the following conditions are
67733SN/A// met: redistributions of source code must retain the above copyright
77733SN/A// notice, this list of conditions and the following disclaimer;
87733SN/A// redistributions in binary form must reproduce the above copyright
97733SN/A// notice, this list of conditions and the following disclaimer in the
107733SN/A// documentation and/or other materials provided with the distribution;
117733SN/A// neither the name of the copyright holders nor the names of its
127733SN/A// contributors may be used to endorse or promote products derived from
137733SN/A// this software without specific prior written permission.
142391SN/A//
152391SN/A// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
162391SN/A// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
172391SN/A// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
182391SN/A// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
192391SN/A// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
202391SN/A// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
212391SN/A// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
222391SN/A// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
232391SN/A// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
242391SN/A// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
252391SN/A// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
262391SN/A//
272391SN/A// Authors: Gabe Black
282391SN/A//          Steve Reinhardt
292391SN/A
302391SN/A////////////////////////////////////////////////////////////////////
312391SN/A//
322391SN/A// Branch instructions
332391SN/A//
342391SN/A
352391SN/Aoutput header {{
362391SN/A        /**
372391SN/A         * Base class for branch operations.
382391SN/A         */
392665SN/A        class Branch : public SparcStaticInst
402665SN/A        {
412914SN/A          protected:
428931Sandreas.hansson@arm.com            // Constructor
432391SN/A            Branch(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
442391SN/A                SparcStaticInst(mnem, _machInst, __opClass)
4510466Sandreas.hansson@arm.com            {
4610466Sandreas.hansson@arm.com            }
4710102Sali.saidi@arm.com
4810102Sali.saidi@arm.com            std::string generateDisassembly(Addr pc,
498232SN/A                    const SymbolTable *symtab) const;
508232SN/A        };
518931Sandreas.hansson@arm.com
523879SN/A        /**
539053Sdam.sunwoo@arm.com         * Base class for branch operations with an immediate displacement.
542394SN/A         */
552391SN/A        class BranchDisp : public Branch
562391SN/A        {
578931Sandreas.hansson@arm.com          protected:
588931Sandreas.hansson@arm.com            // Constructor
599053Sdam.sunwoo@arm.com            BranchDisp(const char *mnem, ExtMachInst _machInst,
609053Sdam.sunwoo@arm.com                    OpClass __opClass) :
612391SN/A                Branch(mnem, _machInst, __opClass)
6210466Sandreas.hansson@arm.com            {
6310466Sandreas.hansson@arm.com            }
6410466Sandreas.hansson@arm.com
6510466Sandreas.hansson@arm.com            std::string generateDisassembly(Addr pc,
6610466Sandreas.hansson@arm.com                    const SymbolTable *symtab) const;
6710466Sandreas.hansson@arm.com
6810466Sandreas.hansson@arm.com            int32_t disp;
6910466Sandreas.hansson@arm.com        };
702391SN/A
712391SN/A        /**
722391SN/A         * Base class for branches with n bit displacements.
739293Sandreas.hansson@arm.com         */
749293Sandreas.hansson@arm.com        template<int bits>
752391SN/A        class BranchNBits : public BranchDisp
769293Sandreas.hansson@arm.com        {
772391SN/A          protected:
782391SN/A            // Constructor
798719SN/A            BranchNBits(const char *mnem, ExtMachInst _machInst,
808931Sandreas.hansson@arm.com                    OpClass __opClass) :
818719SN/A                BranchDisp(mnem, _machInst, __opClass)
828719SN/A            {
838719SN/A                disp = sext<bits + 2>((_machInst & mask(bits)) << 2);
849053Sdam.sunwoo@arm.com            }
859053Sdam.sunwoo@arm.com        };
868719SN/A
879053Sdam.sunwoo@arm.com        /**
888719SN/A         * Base class for 16bit split displacements.
898719SN/A         */
909053Sdam.sunwoo@arm.com        class BranchSplit : public BranchDisp
918719SN/A        {
929053Sdam.sunwoo@arm.com          protected:
939053Sdam.sunwoo@arm.com            // Constructor
949053Sdam.sunwoo@arm.com            BranchSplit(const char *mnem, ExtMachInst _machInst,
958719SN/A                    OpClass __opClass) :
969053Sdam.sunwoo@arm.com                BranchDisp(mnem, _machInst, __opClass)
978719SN/A            {
988719SN/A                disp = sext<18>((D16HI << 16) | (D16LO << 2));
999053Sdam.sunwoo@arm.com            }
1008719SN/A        };
1019053Sdam.sunwoo@arm.com
1029053Sdam.sunwoo@arm.com        /**
1039053Sdam.sunwoo@arm.com         * Base class for branches that use an immediate and a register to
1048719SN/A         * compute their displacements.
1059053Sdam.sunwoo@arm.com         */
1068719SN/A        class BranchImm13 : public Branch
1078719SN/A        {
1089053Sdam.sunwoo@arm.com          protected:
1098719SN/A            // Constructor
1109053Sdam.sunwoo@arm.com            BranchImm13(const char *mnem, ExtMachInst _machInst, OpClass __opClass) :
1119053Sdam.sunwoo@arm.com                Branch(mnem, _machInst, __opClass), imm(sext<13>(SIMM13))
1129053Sdam.sunwoo@arm.com            {
1138719SN/A            }
1149053Sdam.sunwoo@arm.com
1158719SN/A            std::string generateDisassembly(Addr pc,
1168719SN/A                    const SymbolTable *symtab) const;
1179053Sdam.sunwoo@arm.com
1188719SN/A            int32_t imm;
1199053Sdam.sunwoo@arm.com        };
1209053Sdam.sunwoo@arm.com}};
1219053Sdam.sunwoo@arm.com
1228719SN/Aoutput decoder {{
1239053Sdam.sunwoo@arm.com
1248719SN/A        template class BranchNBits<19>;
1258719SN/A
1269053Sdam.sunwoo@arm.com        template class BranchNBits<22>;
1278719SN/A
1289053Sdam.sunwoo@arm.com        template class BranchNBits<30>;
1299053Sdam.sunwoo@arm.com
1309053Sdam.sunwoo@arm.com        std::string
1318719SN/A        Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
1329053Sdam.sunwoo@arm.com        {
1338719SN/A            std::stringstream response;
1348719SN/A
1359053Sdam.sunwoo@arm.com            printMnemonic(response, mnemonic);
1368719SN/A            printRegArray(response, _srcRegIdx, _numSrcRegs);
1379053Sdam.sunwoo@arm.com            if (_numDestRegs && _numSrcRegs)
1389053Sdam.sunwoo@arm.com                    response << ", ";
1399053Sdam.sunwoo@arm.com            printDestReg(response, 0);
1408719SN/A
1418719SN/A            return response.str();
1428719SN/A        }
1438719SN/A
1448719SN/A        std::string
1459053Sdam.sunwoo@arm.com        BranchImm13::generateDisassembly(Addr pc,
1468719SN/A                const SymbolTable *symtab) const
1479053Sdam.sunwoo@arm.com        {
1489053Sdam.sunwoo@arm.com            std::stringstream response;
1499053Sdam.sunwoo@arm.com
1509053Sdam.sunwoo@arm.com            printMnemonic(response, mnemonic);
1518719SN/A            printRegArray(response, _srcRegIdx, _numSrcRegs);
1528719SN/A            if (_numSrcRegs > 0)
1538719SN/A                response << ", ";
1548719SN/A            ccprintf(response, "0x%x", imm);
1558719SN/A            if (_numDestRegs > 0)
1569053Sdam.sunwoo@arm.com                response << ", ";
1578719SN/A            printDestReg(response, 0);
1589053Sdam.sunwoo@arm.com
1599053Sdam.sunwoo@arm.com            return response.str();
1609053Sdam.sunwoo@arm.com        }
1618719SN/A
1628719SN/A        std::string
1638719SN/A        BranchDisp::generateDisassembly(Addr pc,
1648719SN/A                const SymbolTable *symtab) const
1658719SN/A        {
1669053Sdam.sunwoo@arm.com            std::stringstream response;
1678719SN/A            std::string symbol;
1689053Sdam.sunwoo@arm.com            Addr symbolAddr;
1699053Sdam.sunwoo@arm.com
1709053Sdam.sunwoo@arm.com            Addr target = disp + pc;
1718719SN/A
1728719SN/A            printMnemonic(response, mnemonic);
1738719SN/A            ccprintf(response, "0x%x", target);
1748719SN/A
1758719SN/A            if (symtab &&
1769053Sdam.sunwoo@arm.com                    symtab->findNearestSymbol(target, symbol, symbolAddr)) {
1778719SN/A                ccprintf(response, " <%s", symbol);
1789053Sdam.sunwoo@arm.com                if (symbolAddr != target)
1799053Sdam.sunwoo@arm.com                    ccprintf(response, "+%d>", target - symbolAddr);
1809053Sdam.sunwoo@arm.com                else
1818719SN/A                    ccprintf(response, ">");
1828719SN/A            }
1838719SN/A
1848719SN/A            return response.str();
1858719SN/A        }
1868719SN/A}};
1879235Sandreas.hansson@arm.com
1889098Sandreas.hansson@arm.comdef template JumpExecute {{
1892408SN/A        Fault %(class_name)s::execute(%(CPU_exec_context)s *xc,
1908931Sandreas.hansson@arm.com                Trace::InstRecord *traceData) const
1912408SN/A        {
1922408SN/A            // Attempt to execute the instruction
1933170SN/A            Fault fault = NoFault;
1946076SN/A
1953170SN/A            %(op_decl)s;
1968931Sandreas.hansson@arm.com            %(op_rd)s;
1973170SN/A
1984626SN/A            PCS = PCS;
1993170SN/A            %(code)s;
2003170SN/A
2013170SN/A            if (fault == NoFault) {
2023170SN/A                // Write the resulting state to the execution context
2033170SN/A                %(op_wb)s;
2043170SN/A            }
2053170SN/A
2063170SN/A            return fault;
2073170SN/A        }
2085714SN/A}};
2095714SN/A
2103170SN/Adef template BranchExecute {{
2113170SN/A        Fault
2123170SN/A        %(class_name)s::execute(%(CPU_exec_context)s *xc,
2133170SN/A                Trace::InstRecord *traceData) const
2143170SN/A        {
2153170SN/A            // Attempt to execute the instruction
2165714SN/A            Fault fault = NoFault;
2175714SN/A
2183170SN/A            %(op_decl)s;
2193170SN/A            %(op_rd)s;
2203170SN/A
2213170SN/A            if (%(cond)s) {
2223170SN/A                %(code)s;
2233170SN/A            } else {
2243170SN/A                %(fail)s;
2253170SN/A            }
2263170SN/A
2278931Sandreas.hansson@arm.com            if (fault == NoFault) {
2283170SN/A                // Write the resulting state to the execution context
2294626SN/A                %(op_wb)s;
2303170SN/A            }
2316102SN/A
2323170SN/A            return fault;
2333170SN/A        }
2343170SN/A}};
2353170SN/A
2369080Smatt.evans@arm.comdef template BranchDecode {{
2373170SN/A    if (A)
2389080Smatt.evans@arm.com        return new %(class_name)sAnnul("%(mnemonic)s,a", machInst);
2399080Smatt.evans@arm.com    else
2409080Smatt.evans@arm.com        return new %(class_name)s("%(mnemonic)s", machInst);
2419080Smatt.evans@arm.com}};
2429080Smatt.evans@arm.com
2433170SN/A// Primary format for branch instructions:
2443170SN/Adef format Branch(code, *opt_flags) {{
2459080Smatt.evans@arm.com    (usesImm, code, immCode,
2469080Smatt.evans@arm.com     rString, iString) = splitOutImm(code)
2479080Smatt.evans@arm.com    iop = InstObjParams(name, Name, 'Branch', code, opt_flags)
2489080Smatt.evans@arm.com    header_output = BasicDeclare.subst(iop)
2499080Smatt.evans@arm.com    decoder_output = BasicConstructor.subst(iop)
2505714SN/A    exec_output = JumpExecute.subst(iop)
2515714SN/A    if usesImm:
2529080Smatt.evans@arm.com        imm_iop = InstObjParams(name, Name + 'Imm', 'BranchImm' + iString,
2539080Smatt.evans@arm.com                immCode, opt_flags)
2543170SN/A        header_output += BasicDeclare.subst(imm_iop)
2559080Smatt.evans@arm.com        decoder_output += BasicConstructor.subst(imm_iop)
2569080Smatt.evans@arm.com        exec_output += JumpExecute.subst(imm_iop)
2579080Smatt.evans@arm.com        decode_block = ROrImmDecode.subst(iop)
2589080Smatt.evans@arm.com    else:
2593170SN/A        decode_block = BasicDecode.subst(iop)
2609080Smatt.evans@arm.com}};
2619080Smatt.evans@arm.com
2629080Smatt.evans@arm.comlet {{
2639080Smatt.evans@arm.com    def doBranch(name, Name, base, cond,
2649080Smatt.evans@arm.com            code, annul_code, fail, annul_fail, opt_flags):
2659080Smatt.evans@arm.com        iop = InstObjParams(name, Name, base,
2669080Smatt.evans@arm.com                {"code": code,
2679080Smatt.evans@arm.com                 "fail": fail,
2689080Smatt.evans@arm.com                 "cond": cond
2699080Smatt.evans@arm.com                },
2709080Smatt.evans@arm.com                opt_flags)
2719080Smatt.evans@arm.com        header_output = BasicDeclareWithMnemonic.subst(iop)
27210102Sali.saidi@arm.com        decoder_output = BasicConstructorWithMnemonic.subst(iop)
27310102Sali.saidi@arm.com        exec_output = BranchExecute.subst(iop)
27410102Sali.saidi@arm.com        if annul_code == "None":
27510102Sali.saidi@arm.com            decode_block = BasicDecodeWithMnemonic.subst(iop)
27610102Sali.saidi@arm.com        else:
27710102Sali.saidi@arm.com            decode_block = BranchDecode.subst(iop)
2789080Smatt.evans@arm.com
2799080Smatt.evans@arm.com        if annul_code != "None":
2809080Smatt.evans@arm.com            iop = InstObjParams(name + ',a', Name + 'Annul', base,
2819080Smatt.evans@arm.com                    {"code": annul_code,
2823170SN/A                     "fail": annul_fail,
2833170SN/A                     "cond": cond
2843170SN/A                    },
2859080Smatt.evans@arm.com                    opt_flags)
2863170SN/A            header_output += BasicDeclareWithMnemonic.subst(iop)
2873170SN/A            decoder_output += BasicConstructorWithMnemonic.subst(iop)
2884626SN/A            exec_output += BranchExecute.subst(iop)
2894626SN/A        return (header_output, decoder_output, exec_output, decode_block)
2904626SN/A
2919931SAli.Saidi@ARM.com    def doCondBranch(name, Name, base, cond, code, opt_flags):
2929931SAli.Saidi@ARM.com        return doBranch(name, Name, base, cond, code, code,
2939931SAli.Saidi@ARM.com                'PCS = PCS;',
2949931SAli.Saidi@ARM.com                '''
2959931SAli.Saidi@ARM.com                SparcISA::PCState pc = PCS;
2969931SAli.Saidi@ARM.com                pc.nnpc(pc.npc() + 8);
2974626SN/A                pc.npc(pc.npc() + 4);
2984626SN/A                PCS = pc;
2994626SN/A                ''',
3004626SN/A                opt_flags)
3014626SN/A
3024626SN/A    def doUncondBranch(name, Name, base, code, annul_code, opt_flags):
3034626SN/A        return doBranch(name, Name, base, "true", code, annul_code,
3044626SN/A                ";", ";", opt_flags)
3054626SN/A
3064626SN/A    default_branch_code = '''
3074626SN/A    SparcISA::PCState pc = PCS;
3089931SAli.Saidi@ARM.com    pc.nnpc(pc.pc() + disp);
3099931SAli.Saidi@ARM.com    PCS = pc;
3109931SAli.Saidi@ARM.com    '''
3119931SAli.Saidi@ARM.com}};
31210563Sandreas.hansson@arm.com
3139931SAli.Saidi@ARM.com// Format for branch instructions with n bit displacements:
3144626SN/Adef format BranchN(bits, code=default_branch_code,
3154626SN/A        test=None, annul_code=None, *opt_flags) {{
3164626SN/A    if code == "default_branch_code":
3174626SN/A        code = default_branch_code
3184626SN/A    if test != "None":
3194626SN/A        (header_output,
3204626SN/A         decoder_output,
3214626SN/A         exec_output,
3228931Sandreas.hansson@arm.com         decode_block) = doCondBranch(name, Name,
3238931Sandreas.hansson@arm.com             "BranchNBits<%d>" % bits, test, code, opt_flags)
3242413SN/A    else:
3259405Sandreas.hansson@arm.com        (header_output,
3269405Sandreas.hansson@arm.com         decoder_output,
3272414SN/A         exec_output,
3284626SN/A         decode_block) = doUncondBranch(name, Name,
3294626SN/A             "BranchNBits<%d>" % bits, code, annul_code, opt_flags)
3304626SN/A}};
3318931Sandreas.hansson@arm.com
3323175SN/A// Format for branch instructions with split displacements:
3334626SN/Adef format BranchSplit(code=default_branch_code,
3349405Sandreas.hansson@arm.com        test=None, annul_code=None, *opt_flags) {{
3354626SN/A    if code == "default_branch_code":
3364626SN/A        code = default_branch_code
33710466Sandreas.hansson@arm.com    if test != "None":
3384040SN/A        (header_output,
3394040SN/A         decoder_output,
3404040SN/A         exec_output,
3415477SN/A         decode_block) = doCondBranch(name, Name,
3425477SN/A             "BranchSplit", test, code, opt_flags)
3434040SN/A    else:
34410466Sandreas.hansson@arm.com        (header_output,
3454040SN/A         decoder_output,
3464040SN/A         exec_output,
34710563Sandreas.hansson@arm.com         decode_block) = doUncondBranch(name, Name,
34810563Sandreas.hansson@arm.com             "BranchSplit", code, annul_code, opt_flags)
3494626SN/A}};
3504040SN/A
3514040SN/A