12100SN/A// -*- mode:c++ -*-
22083SN/A
35268Sksewell@umich.edu// Copyright (c) 2007 MIPS Technologies, Inc.
45268Sksewell@umich.edu// All rights reserved.
55268Sksewell@umich.edu//
65268Sksewell@umich.edu// Redistribution and use in source and binary forms, with or without
75268Sksewell@umich.edu// modification, are permitted provided that the following conditions are
85268Sksewell@umich.edu// met: redistributions of source code must retain the above copyright
95268Sksewell@umich.edu// notice, this list of conditions and the following disclaimer;
105268Sksewell@umich.edu// redistributions in binary form must reproduce the above copyright
115268Sksewell@umich.edu// notice, this list of conditions and the following disclaimer in the
125268Sksewell@umich.edu// documentation and/or other materials provided with the distribution;
135268Sksewell@umich.edu// neither the name of the copyright holders nor the names of its
145268Sksewell@umich.edu// contributors may be used to endorse or promote products derived from
155268Sksewell@umich.edu// this software without specific prior written permission.
165268Sksewell@umich.edu//
175268Sksewell@umich.edu// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
185268Sksewell@umich.edu// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
195268Sksewell@umich.edu// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
205268Sksewell@umich.edu// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
215268Sksewell@umich.edu// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
225268Sksewell@umich.edu// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
235268Sksewell@umich.edu// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
245268Sksewell@umich.edu// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
255268Sksewell@umich.edu// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
265268Sksewell@umich.edu// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
275268Sksewell@umich.edu// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
285268Sksewell@umich.edu//
295268Sksewell@umich.edu// Authors: Korey Sewell
302706Sksewell@umich.edu
312089SN/A////////////////////////////////////////////////////////////////////
322022SN/A//
332089SN/A// Control transfer instructions
342022SN/A//
352022SN/A
362022SN/Aoutput header {{
372083SN/A
382239SN/A#include <iostream>
394661Sksewell@umich.edu    using namespace std;
402239SN/A
412083SN/A    /**
422083SN/A     * Base class for instructions whose disassembly is not purely a
432083SN/A     * function of the machine instruction (i.e., it depends on the
442083SN/A     * PC).  This class overrides the disassemble() method to check
452083SN/A     * the PC and symbol table values before re-using a cached
462083SN/A     * disassembly string.  This is necessary for branches and jumps,
472083SN/A     * where the disassembly string includes the target address (which
482083SN/A     * may depend on the PC and/or symbol table).
492083SN/A     */
502089SN/A    class PCDependentDisassembly : public MipsStaticInst
512083SN/A    {
522083SN/A      protected:
532083SN/A        /// Cached program counter from last disassembly
542083SN/A        mutable Addr cachedPC;
552089SN/A
562083SN/A        /// Cached symbol table pointer from last disassembly
572083SN/A        mutable const SymbolTable *cachedSymtab;
582083SN/A
592083SN/A        /// Constructor
602083SN/A        PCDependentDisassembly(const char *mnem, MachInst _machInst,
612083SN/A                               OpClass __opClass)
622089SN/A            : MipsStaticInst(mnem, _machInst, __opClass),
632083SN/A              cachedPC(0), cachedSymtab(0)
642022SN/A        {
652083SN/A        }
662022SN/A
672083SN/A        const std::string &
682083SN/A        disassemble(Addr pc, const SymbolTable *symtab) const;
692083SN/A    };
702022SN/A
712083SN/A    /**
722083SN/A     * Base class for branches (PC-relative control transfers),
732083SN/A     * conditional or unconditional.
742083SN/A     */
752083SN/A    class Branch : public PCDependentDisassembly
762083SN/A    {
772083SN/A      protected:
782089SN/A        /// target address (signed) Displacement .
792104SN/A        int32_t disp;
802083SN/A
812083SN/A        /// Constructor.
822083SN/A        Branch(const char *mnem, MachInst _machInst, OpClass __opClass)
832083SN/A            : PCDependentDisassembly(mnem, _machInst, __opClass),
842104SN/A              disp(OFFSET << 2)
852089SN/A        {
862239SN/A            //If Bit 17 is 1 then Sign Extend
872239SN/A            if ( (disp & 0x00020000) > 0  ) {
882239SN/A                disp |= 0xFFFE0000;
892239SN/A            }
902089SN/A        }
912089SN/A
9212616Sgabeblack@google.com        MipsISA::PCState branchTarget(
9312616Sgabeblack@google.com                const MipsISA::PCState &branchPC) const override;
942089SN/A
959552Sandreas.hansson@arm.com        /// Explicitly import the otherwise hidden branchTarget
969552Sandreas.hansson@arm.com        using StaticInst::branchTarget;
979552Sandreas.hansson@arm.com
9812616Sgabeblack@google.com        std::string generateDisassembly(
9912616Sgabeblack@google.com                Addr pc, const SymbolTable *symtab) const override;
1002089SN/A    };
1012089SN/A
1022089SN/A    /**
1032083SN/A     * Base class for jumps (register-indirect control transfers).  In
1042089SN/A     * the Mips ISA, these are always unconditional.
1052083SN/A     */
1062083SN/A    class Jump : public PCDependentDisassembly
1072083SN/A    {
1082083SN/A      protected:
1092083SN/A
1102083SN/A        /// Displacement to target address (signed).
1112083SN/A        int32_t disp;
1122083SN/A
1132239SN/A        uint32_t target;
1142239SN/A
1152083SN/A      public:
1162083SN/A        /// Constructor
1172083SN/A        Jump(const char *mnem, MachInst _machInst, OpClass __opClass)
1182083SN/A            : PCDependentDisassembly(mnem, _machInst, __opClass),
1192239SN/A              disp(JMPTARG << 2)
1202083SN/A        {
1212083SN/A        }
1222083SN/A
12312616Sgabeblack@google.com        MipsISA::PCState branchTarget(ThreadContext *tc) const override;
1242083SN/A
1259552Sandreas.hansson@arm.com        /// Explicitly import the otherwise hidden branchTarget
1269552Sandreas.hansson@arm.com        using StaticInst::branchTarget;
1279552Sandreas.hansson@arm.com
12812616Sgabeblack@google.com        std::string generateDisassembly(
12912616Sgabeblack@google.com                Addr pc, const SymbolTable *symtab) const override;
1302083SN/A    };
1312022SN/A}};
1322022SN/A
1332022SN/Aoutput decoder {{
1347720Sgblack@eecs.umich.edu    MipsISA::PCState
1357720Sgblack@eecs.umich.edu    Branch::branchTarget(const MipsISA::PCState &branchPC) const
1362083SN/A    {
1377720Sgblack@eecs.umich.edu        MipsISA::PCState target = branchPC;
1387720Sgblack@eecs.umich.edu        target.advance();
1397720Sgblack@eecs.umich.edu        target.npc(branchPC.pc() + sizeof(MachInst) + disp);
1407720Sgblack@eecs.umich.edu        target.nnpc(target.npc() + sizeof(MachInst));
1417720Sgblack@eecs.umich.edu        return target;
1422083SN/A    }
1432083SN/A
1447720Sgblack@eecs.umich.edu    MipsISA::PCState
1452687Sksewell@umich.edu    Jump::branchTarget(ThreadContext *tc) const
1462083SN/A    {
1477720Sgblack@eecs.umich.edu        MipsISA::PCState target = tc->pcState();
1487720Sgblack@eecs.umich.edu        Addr pc = target.pc();
1497720Sgblack@eecs.umich.edu        target.advance();
1507720Sgblack@eecs.umich.edu        target.npc((pc & 0xF0000000) | disp);
1517720Sgblack@eecs.umich.edu        target.nnpc(target.npc() + sizeof(MachInst));
1527720Sgblack@eecs.umich.edu        return target;
1532083SN/A    }
1542083SN/A
1552083SN/A    const std::string &
1562083SN/A    PCDependentDisassembly::disassemble(Addr pc,
1572083SN/A                                        const SymbolTable *symtab) const
1582083SN/A    {
1592083SN/A        if (!cachedDisassembly ||
1602083SN/A            pc != cachedPC || symtab != cachedSymtab)
1612022SN/A        {
1622083SN/A            if (cachedDisassembly)
1632083SN/A                delete cachedDisassembly;
1642083SN/A
1652083SN/A            cachedDisassembly =
1662083SN/A                new std::string(generateDisassembly(pc, symtab));
1672083SN/A            cachedPC = pc;
1682083SN/A            cachedSymtab = symtab;
1692022SN/A        }
1702083SN/A
1712083SN/A        return *cachedDisassembly;
1722083SN/A    }
1732083SN/A
1742083SN/A    std::string
1752083SN/A    Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
1762083SN/A    {
1772083SN/A        std::stringstream ss;
1782083SN/A
1792083SN/A        ccprintf(ss, "%-10s ", mnemonic);
1802083SN/A
1812083SN/A        // There's only one register arg (RA), but it could be
1822083SN/A        // either a source (the condition for conditional
1832083SN/A        // branches) or a destination (the link reg for
1842083SN/A        // unconditional branches)
1852239SN/A        if (_numSrcRegs == 1) {
1862083SN/A            printReg(ss, _srcRegIdx[0]);
1872686Sksewell@umich.edu            ss << ", ";
1882239SN/A        } else if(_numSrcRegs == 2) {
1892239SN/A            printReg(ss, _srcRegIdx[0]);
1902686Sksewell@umich.edu            ss << ", ";
1912239SN/A            printReg(ss, _srcRegIdx[1]);
1922686Sksewell@umich.edu            ss << ", ";
1932103SN/A        }
1942103SN/A
1952103SN/A        Addr target = pc + 4 + disp;
1962103SN/A
1972103SN/A        std::string str;
1982103SN/A        if (symtab && symtab->findSymbol(target, str))
1992103SN/A            ss << str;
2002103SN/A        else
2012103SN/A            ccprintf(ss, "0x%x", target);
2022103SN/A
2032103SN/A        return ss.str();
2042103SN/A    }
2052103SN/A
2062103SN/A    std::string
2072083SN/A    Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
2082083SN/A    {
2092083SN/A        std::stringstream ss;
2102083SN/A
2112083SN/A        ccprintf(ss, "%-10s ", mnemonic);
2122083SN/A
2135269Sksewell@umich.edu        if ( strcmp(mnemonic,"jal") == 0 ) {
2142239SN/A            Addr npc = pc + 4;
2152239SN/A            ccprintf(ss,"0x%x",(npc & 0xF0000000) | disp);
2162239SN/A        } else if (_numSrcRegs == 0) {
2172239SN/A            std::string str;
2182239SN/A            if (symtab && symtab->findSymbol(disp, str))
2192239SN/A                ss << str;
2202239SN/A            else
2212239SN/A                ccprintf(ss, "0x%x", disp);
2222239SN/A        } else if (_numSrcRegs == 1) {
2232239SN/A             printReg(ss, _srcRegIdx[0]);
2242239SN/A        } else if(_numSrcRegs == 2) {
2252239SN/A            printReg(ss, _srcRegIdx[0]);
2262686Sksewell@umich.edu            ss << ", ";
2272239SN/A            printReg(ss, _srcRegIdx[1]);
2282083SN/A        }
2292083SN/A
2302083SN/A        return ss.str();
2312083SN/A    }
2322022SN/A}};
2332022SN/A
2344661Sksewell@umich.edudef format Branch(code, *opt_flags) {{
2357792Sgblack@eecs.umich.edu    not_taken_code = 'NNPC = NNPC; NPC = NPC;'
2362686Sksewell@umich.edu
2372686Sksewell@umich.edu    #Build Instruction Flags
2382686Sksewell@umich.edu    #Use Link & Likely Flags to Add Link/Condition Code
2392686Sksewell@umich.edu    inst_flags = ('IsDirectControl', )
2402686Sksewell@umich.edu    for x in opt_flags:
2412686Sksewell@umich.edu        if x == 'Link':
2427792Sgblack@eecs.umich.edu            code += 'R31 = NNPC;\n'
2432686Sksewell@umich.edu        elif x == 'Likely':
2447792Sgblack@eecs.umich.edu            not_taken_code = 'NNPC = NPC; NPC = PC;'
2454661Sksewell@umich.edu            inst_flags += ('IsCondDelaySlot', )
2462686Sksewell@umich.edu        else:
2472686Sksewell@umich.edu            inst_flags += (x, )
2482686Sksewell@umich.edu
2492935Sksewell@umich.edu    #Take into account uncond. branch instruction
2504661Sksewell@umich.edu    if 'cond = 1' in code:
2514661Sksewell@umich.edu         inst_flags += ('IsUncondControl', )
2522935Sksewell@umich.edu    else:
2532686Sksewell@umich.edu         inst_flags += ('IsCondControl', )
2542101SN/A
2552123SN/A    #Condition code
2567720Sgblack@eecs.umich.edu    code = '''
2577720Sgblack@eecs.umich.edu    bool cond;
2587720Sgblack@eecs.umich.edu    %(code)s
2597720Sgblack@eecs.umich.edu    if (cond) {
2607792Sgblack@eecs.umich.edu        NNPC = NPC + disp;
2617720Sgblack@eecs.umich.edu    } else {
2627720Sgblack@eecs.umich.edu        %(not_taken_code)s
2637720Sgblack@eecs.umich.edu    }
2647720Sgblack@eecs.umich.edu    ''' % { "code" : code, "not_taken_code" : not_taken_code }
2652101SN/A
2663951Sgblack@eecs.umich.edu    iop = InstObjParams(name, Name, 'Branch', code, inst_flags)
2672047SN/A    header_output = BasicDeclare.subst(iop)
2682047SN/A    decoder_output = BasicConstructor.subst(iop)
2692047SN/A    decode_block = BasicDecode.subst(iop)
2702047SN/A    exec_output = BasicExecute.subst(iop)
2712022SN/A}};
2722047SN/A
2734661Sksewell@umich.edudef format DspBranch(code, *opt_flags) {{
2747792Sgblack@eecs.umich.edu    not_taken_code = 'NNPC = NNPC; NPC = NPC;'
2754661Sksewell@umich.edu
2764661Sksewell@umich.edu    #Build Instruction Flags
2774661Sksewell@umich.edu    #Use Link & Likely Flags to Add Link/Condition Code
2784661Sksewell@umich.edu    inst_flags = ('IsDirectControl', )
2794661Sksewell@umich.edu    for x in opt_flags:
2804661Sksewell@umich.edu        if x == 'Link':
2817792Sgblack@eecs.umich.edu            code += 'R32 = NNPC;'
2824661Sksewell@umich.edu        elif x == 'Likely':
2837792Sgblack@eecs.umich.edu            not_taken_code = 'NNPC = NPC, NPC = PC;'
2844661Sksewell@umich.edu            inst_flags += ('IsCondDelaySlot', )
2854661Sksewell@umich.edu        else:
2864661Sksewell@umich.edu            inst_flags += (x, )
2874661Sksewell@umich.edu
2884661Sksewell@umich.edu    #Take into account uncond. branch instruction
2894661Sksewell@umich.edu    if 'cond = 1' in code:
2904661Sksewell@umich.edu         inst_flags += ('IsUncondControl', )
2914661Sksewell@umich.edu    else:
2924661Sksewell@umich.edu         inst_flags += ('IsCondControl', )
2934661Sksewell@umich.edu
2944661Sksewell@umich.edu    #Condition code
2957720Sgblack@eecs.umich.edu    code = '''
2967720Sgblack@eecs.umich.edu    bool cond;
2977720Sgblack@eecs.umich.edu    uint32_t dspctl = DSPControl;
2987720Sgblack@eecs.umich.edu    %(code)s
2997720Sgblack@eecs.umich.edu    if (cond) {
3007792Sgblack@eecs.umich.edu        NNPC = NPC + disp;
3017720Sgblack@eecs.umich.edu    } else {
3027720Sgblack@eecs.umich.edu        %(not_taken_code)s
3037720Sgblack@eecs.umich.edu    }
3047720Sgblack@eecs.umich.edu    ''' % { "code" : code, "not_taken_code" : not_taken_code }
3054661Sksewell@umich.edu
3064661Sksewell@umich.edu    iop = InstObjParams(name, Name, 'Branch', code, inst_flags)
3074661Sksewell@umich.edu    header_output = BasicDeclare.subst(iop)
3084661Sksewell@umich.edu    decoder_output = BasicConstructor.subst(iop)
3094661Sksewell@umich.edu    decode_block = BasicDecode.subst(iop)
3104661Sksewell@umich.edu    exec_output = BasicExecute.subst(iop)
3114661Sksewell@umich.edu}};
3124661Sksewell@umich.edu
3132686Sksewell@umich.edudef format Jump(code, *opt_flags) {{
3142686Sksewell@umich.edu    #Build Instruction Flags
3152686Sksewell@umich.edu    #Use Link Flag to Add Link Code
3162686Sksewell@umich.edu    inst_flags = ('IsIndirectControl', 'IsUncondControl')
3172686Sksewell@umich.edu    for x in opt_flags:
3182686Sksewell@umich.edu        if x == 'Link':
3197720Sgblack@eecs.umich.edu            code = '''
3207792Sgblack@eecs.umich.edu            R31 = NNPC;
3217720Sgblack@eecs.umich.edu            ''' + code
3222686Sksewell@umich.edu        elif x == 'ClearHazards':
3232686Sksewell@umich.edu            code += '/* Code Needed to Clear Execute & Inst Hazards */\n'
3242686Sksewell@umich.edu        else:
3252686Sksewell@umich.edu            inst_flags += (x, )
3262104SN/A
3273951Sgblack@eecs.umich.edu    iop = InstObjParams(name, Name, 'Jump', code, inst_flags)
3282089SN/A    header_output = BasicDeclare.subst(iop)
3292089SN/A    decoder_output = BasicConstructor.subst(iop)
3302089SN/A    decode_block = BasicDecode.subst(iop)
3312089SN/A    exec_output = BasicExecute.subst(iop)
3322089SN/A}};
3332083SN/A
3342239SN/A
3352123SN/A
3362123SN/A
337