branch.isa revision 2701:38218635db4c
19243SN/A// -*- mode:c++ -*-
211675Swendy.elsasser@arm.com
39243SN/A////////////////////////////////////////////////////////////////////
49243SN/A//
59243SN/A// Control transfer instructions
69243SN/A//
79243SN/A
89243SN/Aoutput header {{
99243SN/A
109243SN/A#include <iostream>
119243SN/A    using namespace std;
129243SN/A
139243SN/A    /**
149831SN/A     * Base class for instructions whose disassembly is not purely a
159831SN/A     * function of the machine instruction (i.e., it depends on the
169831SN/A     * PC).  This class overrides the disassemble() method to check
179243SN/A     * the PC and symbol table values before re-using a cached
189243SN/A     * disassembly string.  This is necessary for branches and jumps,
199243SN/A     * where the disassembly string includes the target address (which
209243SN/A     * may depend on the PC and/or symbol table).
219243SN/A     */
229243SN/A    class PCDependentDisassembly : public MipsStaticInst
239243SN/A    {
249243SN/A      protected:
259243SN/A        /// Cached program counter from last disassembly
269243SN/A        mutable Addr cachedPC;
279243SN/A
289243SN/A        /// Cached symbol table pointer from last disassembly
299243SN/A        mutable const SymbolTable *cachedSymtab;
309243SN/A
319243SN/A        /// Constructor
329243SN/A        PCDependentDisassembly(const char *mnem, MachInst _machInst,
339243SN/A                               OpClass __opClass)
349243SN/A            : MipsStaticInst(mnem, _machInst, __opClass),
359243SN/A              cachedPC(0), cachedSymtab(0)
369243SN/A        {
379243SN/A        }
389243SN/A
399243SN/A        const std::string &
409243SN/A        disassemble(Addr pc, const SymbolTable *symtab) const;
419243SN/A    };
429967SN/A
4310618SOmar.Naji@arm.com    /**
4411678Swendy.elsasser@arm.com     * Base class for branches (PC-relative control transfers),
459243SN/A     * conditional or unconditional.
469243SN/A     */
4710146Sandreas.hansson@arm.com    class Branch : public PCDependentDisassembly
489356SN/A    {
4910146Sandreas.hansson@arm.com      protected:
5010247Sandreas.hansson@arm.com        /// target address (signed) Displacement .
5110208Sandreas.hansson@arm.com        int32_t disp;
529352SN/A
5310146Sandreas.hansson@arm.com        /// Constructor.
549814SN/A        Branch(const char *mnem, MachInst _machInst, OpClass __opClass)
559243SN/A            : PCDependentDisassembly(mnem, _machInst, __opClass),
569243SN/A              disp(OFFSET << 2)
5710432SOmar.Naji@arm.com        {
589243SN/A            //If Bit 17 is 1 then Sign Extend
5910146Sandreas.hansson@arm.com            if ( (disp & 0x00020000) > 0  ) {
609243SN/A                disp |= 0xFFFE0000;
6110619Sandreas.hansson@arm.com            }
629243SN/A        }
6310211Sandreas.hansson@arm.com
6411678Swendy.elsasser@arm.com        Addr branchTarget(Addr branchPC) const;
6510618SOmar.Naji@arm.com
6610489SOmar.Naji@arm.com        std::string
679831SN/A        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
689831SN/A    };
699831SN/A
709831SN/A    /**
719831SN/A     * Base class for branch likely branches (PC-relative control transfers),
7210140SN/A     */
7310646Sandreas.hansson@arm.com    class BranchLikely : public PCDependentDisassembly
749243SN/A    {
7510394Swendy.elsasser@arm.com      protected:
7610394Swendy.elsasser@arm.com        /// target address (signed) Displacement .
779566SN/A        int32_t disp;
789243SN/A
799243SN/A        /// Constructor.
8010140SN/A        BranchLikely(const char *mnem, MachInst _machInst, OpClass __opClass)
8110140SN/A            : PCDependentDisassembly(mnem, _machInst, __opClass),
8210147Sandreas.hansson@arm.com              disp(OFFSET << 2)
8310147Sandreas.hansson@arm.com        {
8410393Swendy.elsasser@arm.com
8510394Swendy.elsasser@arm.com        }
8610394Swendy.elsasser@arm.com
8711673SOmar.Naji@arm.com        Addr branchTarget(Addr branchPC) const;
8811673SOmar.Naji@arm.com
899243SN/A        std::string
909243SN/A        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
9110141SN/A    };
929726SN/A
939726SN/A    /**
9410618SOmar.Naji@arm.com     * Base class for jumps (register-indirect control transfers).  In
9510618SOmar.Naji@arm.com     * the Mips ISA, these are always unconditional.
969243SN/A     */
9710620Sandreas.hansson@arm.com    class Jump : public PCDependentDisassembly
9810620Sandreas.hansson@arm.com    {
9910620Sandreas.hansson@arm.com      protected:
10010620Sandreas.hansson@arm.com
10110620Sandreas.hansson@arm.com        /// Displacement to target address (signed).
10210889Sandreas.hansson@arm.com        int32_t disp;
10310889Sandreas.hansson@arm.com
10410889Sandreas.hansson@arm.com        uint32_t target;
10510618SOmar.Naji@arm.com
10610618SOmar.Naji@arm.com      public:
10710618SOmar.Naji@arm.com        /// Constructor
10810432SOmar.Naji@arm.com        Jump(const char *mnem, MachInst _machInst, OpClass __opClass)
10910618SOmar.Naji@arm.com            : PCDependentDisassembly(mnem, _machInst, __opClass),
11010618SOmar.Naji@arm.com              disp(JMPTARG << 2)
11110618SOmar.Naji@arm.com        {
11210432SOmar.Naji@arm.com        }
11310246Sandreas.hansson@arm.com
11410618SOmar.Naji@arm.com        Addr branchTarget(ThreadContext *tc) const;
11510561SOmar.Naji@arm.com
11610561SOmar.Naji@arm.com        std::string
11710561SOmar.Naji@arm.com        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
11810394Swendy.elsasser@arm.com    };
11910394Swendy.elsasser@arm.com}};
12010394Swendy.elsasser@arm.com
12110394Swendy.elsasser@arm.comoutput decoder {{
12210394Swendy.elsasser@arm.com    Addr
12310394Swendy.elsasser@arm.com    Branch::branchTarget(Addr branchPC) const
12410394Swendy.elsasser@arm.com    {
12510394Swendy.elsasser@arm.com        return branchPC + 4 + disp;
12610618SOmar.Naji@arm.com    }
12710394Swendy.elsasser@arm.com
12810394Swendy.elsasser@arm.com    Addr
12910618SOmar.Naji@arm.com    BranchLikely::branchTarget(Addr branchPC) const
13010394Swendy.elsasser@arm.com    {
13110246Sandreas.hansson@arm.com        return branchPC + 4 + disp;
13210246Sandreas.hansson@arm.com    }
13310246Sandreas.hansson@arm.com
13410140SN/A    Addr
13510140SN/A    Jump::branchTarget(ThreadContext *tc) const
13610140SN/A    {
13710140SN/A        Addr NPC = tc->readPC() + 4;
13810140SN/A        uint64_t Rb = tc->readIntReg(_srcRegIdx[0]);
1399243SN/A        return (Rb & ~3) | (NPC & 1);
1409243SN/A    }
1419567SN/A
1429243SN/A    const std::string &
14310489SOmar.Naji@arm.com    PCDependentDisassembly::disassemble(Addr pc,
14410489SOmar.Naji@arm.com                                        const SymbolTable *symtab) const
14510489SOmar.Naji@arm.com    {
14610489SOmar.Naji@arm.com        if (!cachedDisassembly ||
14710489SOmar.Naji@arm.com            pc != cachedPC || symtab != cachedSymtab)
14810489SOmar.Naji@arm.com        {
14910489SOmar.Naji@arm.com            if (cachedDisassembly)
15010489SOmar.Naji@arm.com                delete cachedDisassembly;
15110489SOmar.Naji@arm.com
15210489SOmar.Naji@arm.com            cachedDisassembly =
1539243SN/A                new std::string(generateDisassembly(pc, symtab));
1549243SN/A            cachedPC = pc;
1559831SN/A            cachedSymtab = symtab;
1569831SN/A        }
1579831SN/A
1589831SN/A        return *cachedDisassembly;
1599831SN/A    }
1609243SN/A
16110207Sandreas.hansson@arm.com    std::string
16210207Sandreas.hansson@arm.com    Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
16310207Sandreas.hansson@arm.com    {
16410207Sandreas.hansson@arm.com        std::stringstream ss;
16510207Sandreas.hansson@arm.com
16610394Swendy.elsasser@arm.com        ccprintf(ss, "%-10s ", mnemonic);
16710394Swendy.elsasser@arm.com
16810394Swendy.elsasser@arm.com        // There's only one register arg (RA), but it could be
16910394Swendy.elsasser@arm.com        // either a source (the condition for conditional
17010394Swendy.elsasser@arm.com        // branches) or a destination (the link reg for
17110394Swendy.elsasser@arm.com        // unconditional branches)
17210394Swendy.elsasser@arm.com        if (_numSrcRegs == 1) {
17310394Swendy.elsasser@arm.com            printReg(ss, _srcRegIdx[0]);
17410394Swendy.elsasser@arm.com            ss << ",";
17510394Swendy.elsasser@arm.com        } else if(_numSrcRegs == 2) {
17610394Swendy.elsasser@arm.com            printReg(ss, _srcRegIdx[0]);
17710394Swendy.elsasser@arm.com            ss << ",";
17810394Swendy.elsasser@arm.com            printReg(ss, _srcRegIdx[1]);
17910394Swendy.elsasser@arm.com            ss << ",";
18010394Swendy.elsasser@arm.com        }
18110394Swendy.elsasser@arm.com
18210394Swendy.elsasser@arm.com        Addr target = pc + 4 + disp;
18310394Swendy.elsasser@arm.com
18410394Swendy.elsasser@arm.com        std::string str;
18510394Swendy.elsasser@arm.com        if (symtab && symtab->findSymbol(target, str))
18610394Swendy.elsasser@arm.com            ss << str;
18710394Swendy.elsasser@arm.com        else
18810561SOmar.Naji@arm.com            ccprintf(ss, "0x%x", target);
18910561SOmar.Naji@arm.com
19010394Swendy.elsasser@arm.com        string inst_name = mnemonic;
19110394Swendy.elsasser@arm.com
19210394Swendy.elsasser@arm.com        if (inst_name.substr(inst_name.length()-2,inst_name.length()) == "al"){
19310394Swendy.elsasser@arm.com            ccprintf(ss, " (r31=0x%x)",pc+8);
19410394Swendy.elsasser@arm.com        }
19510394Swendy.elsasser@arm.com
1969243SN/A        return ss.str();
1979243SN/A    }
1989243SN/A
19910146Sandreas.hansson@arm.com    std::string
20010140SN/A    BranchLikely::generateDisassembly(Addr pc, const SymbolTable *symtab) const
20110466Sandreas.hansson@arm.com    {
20210466Sandreas.hansson@arm.com        std::stringstream ss;
20310466Sandreas.hansson@arm.com
20410146Sandreas.hansson@arm.com        ccprintf(ss, "%-10s ", mnemonic);
20510140SN/A
20610140SN/A        // There's only one register arg (RA), but it could be
20710140SN/A        // either a source (the condition for conditional
20810646Sandreas.hansson@arm.com        // branches) or a destination (the link reg for
20910646Sandreas.hansson@arm.com        // unconditional branches)
21010646Sandreas.hansson@arm.com        if (_numSrcRegs > 0) {
21110646Sandreas.hansson@arm.com            printReg(ss, _srcRegIdx[0]);
21210646Sandreas.hansson@arm.com            ss << ",";
21310646Sandreas.hansson@arm.com        }
21410646Sandreas.hansson@arm.com        else if (_numDestRegs > 0) {
21510646Sandreas.hansson@arm.com            printReg(ss, _destRegIdx[0]);
21610646Sandreas.hansson@arm.com            ss << ",";
21710646Sandreas.hansson@arm.com        }
21810646Sandreas.hansson@arm.com
21910646Sandreas.hansson@arm.com        Addr target = pc + 4 + disp;
22010646Sandreas.hansson@arm.com
22110646Sandreas.hansson@arm.com        std::string str;
22210646Sandreas.hansson@arm.com        if (symtab && symtab->findSymbol(target, str))
22310646Sandreas.hansson@arm.com            ss << str;
22410646Sandreas.hansson@arm.com        else
22510646Sandreas.hansson@arm.com            ccprintf(ss, "0x%x", target);
22610646Sandreas.hansson@arm.com
22710646Sandreas.hansson@arm.com        return ss.str();
22810646Sandreas.hansson@arm.com    }
22910646Sandreas.hansson@arm.com
23010646Sandreas.hansson@arm.com    std::string
23110646Sandreas.hansson@arm.com    Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
23210646Sandreas.hansson@arm.com    {
23310646Sandreas.hansson@arm.com        std::stringstream ss;
23410646Sandreas.hansson@arm.com
23510646Sandreas.hansson@arm.com        ccprintf(ss, "%-10s ", mnemonic);
23610646Sandreas.hansson@arm.com
23710646Sandreas.hansson@arm.com        if ( mnemonic == "jal" ) {
23810646Sandreas.hansson@arm.com            Addr npc = pc + 4;
23910646Sandreas.hansson@arm.com            ccprintf(ss,"0x%x",(npc & 0xF0000000) | disp);
24010646Sandreas.hansson@arm.com        } else if (_numSrcRegs == 0) {
24110646Sandreas.hansson@arm.com            std::string str;
24210646Sandreas.hansson@arm.com            if (symtab && symtab->findSymbol(disp, str))
24310646Sandreas.hansson@arm.com                ss << str;
24410646Sandreas.hansson@arm.com            else
24510646Sandreas.hansson@arm.com                ccprintf(ss, "0x%x", disp);
24610646Sandreas.hansson@arm.com        } else if (_numSrcRegs == 1) {
24710646Sandreas.hansson@arm.com             printReg(ss, _srcRegIdx[0]);
24810140SN/A        } else if(_numSrcRegs == 2) {
24910140SN/A            printReg(ss, _srcRegIdx[0]);
25010140SN/A            ss << ",";
25110146Sandreas.hansson@arm.com            printReg(ss, _srcRegIdx[1]);
2529243SN/A        } else {
25310619Sandreas.hansson@arm.com            panic(">= 3 Source Registers!!!");
25410619Sandreas.hansson@arm.com        }
25510618SOmar.Naji@arm.com
25610619Sandreas.hansson@arm.com        return ss.str();
25710619Sandreas.hansson@arm.com    }
25810619Sandreas.hansson@arm.com}};
25910619Sandreas.hansson@arm.com
26010619Sandreas.hansson@arm.comdef format Branch(code,*flags) {{
26110619Sandreas.hansson@arm.com    #Add Link Code if Link instruction
26210619Sandreas.hansson@arm.com    strlen = len(name)
26310619Sandreas.hansson@arm.com    if name[strlen-2:] == 'al':
26410619Sandreas.hansson@arm.com        code += 'R31 = NNPC;\n'
26510619Sandreas.hansson@arm.com
26610619Sandreas.hansson@arm.com    #Condition code
26710619Sandreas.hansson@arm.com    code = 'bool cond;\n' + code
26810619Sandreas.hansson@arm.com    code += 'if (cond) {\n'
26910619Sandreas.hansson@arm.com    code += '  NNPC = NPC + disp;\n'
27010619Sandreas.hansson@arm.com    code += '} else {\n'
27110618SOmar.Naji@arm.com    code += '  NNPC = NNPC;\n'
2729243SN/A    code += '} \n'
2739243SN/A
2749243SN/A    iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
27510146Sandreas.hansson@arm.com                        ('IsDirectControl', 'IsCondControl'))
2769243SN/A
2779243SN/A    header_output = BasicDeclare.subst(iop)
2789243SN/A    decoder_output = BasicConstructor.subst(iop)
27911334Sandreas.hansson@arm.com    decode_block = BasicDecode.subst(iop)
28011334Sandreas.hansson@arm.com    exec_output = BasicExecute.subst(iop)
28111334Sandreas.hansson@arm.com}};
2829243SN/A
2839243SN/A
2849243SN/Adef format BranchLikely(code,*flags) {{
2859243SN/A    #Add Link Code if Link instruction
28611334Sandreas.hansson@arm.com    strlen = len(name)
2879243SN/A    if name[strlen-3:] == 'all':
2889243SN/A        code += 'R31 = NNPC;\n'
2899243SN/A
2909243SN/A    #Condition code
2919243SN/A    code = 'bool cond;\n' + code
2929243SN/A    code += 'if (cond) {'
2939243SN/A    code += 'NNPC = NPC + disp;\n'
2949243SN/A    code += '} \n'
29510146Sandreas.hansson@arm.com
2969243SN/A
2979831SN/A    iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
2989831SN/A                        ('IsDirectControl', 'IsCondControl','IsCondDelaySlot'))
2999831SN/A
3009243SN/A    header_output = BasicDeclare.subst(iop)
3019831SN/A    decoder_output = BasicConstructor.subst(iop)
3029831SN/A    decode_block = BasicDecode.subst(iop)
3039243SN/A    exec_output = BasicExecute.subst(iop)
3049243SN/A}};
3059243SN/A
30610146Sandreas.hansson@arm.comdef format Jump(code,*flags) {{
3079243SN/A    #Add Link Code if Link instruction
3089831SN/A    strlen = len(name)
3099831SN/A    if strlen > 1 and name[1:] == 'al':
3109831SN/A            code = 'R31 = NNPC;\n' + code
3119243SN/A
3129243SN/A
31310146Sandreas.hansson@arm.com    iop = InstObjParams(name, Name, 'Jump', CodeBlock(code),\
31410146Sandreas.hansson@arm.com                        ('IsIndirectControl', 'IsUncondControl'))
31510143SN/A
3169243SN/A    header_output = BasicDeclare.subst(iop)
3179669SN/A    decoder_output = BasicConstructor.subst(iop)
31810136SN/A    decode_block = BasicDecode.subst(iop)
31910136SN/A    exec_output = BasicExecute.subst(iop)
3209243SN/A}};
3219967SN/A
32210245Sandreas.hansson@arm.com
32310245Sandreas.hansson@arm.com
32410245Sandreas.hansson@arm.com
3259243SN/A