branch.isa revision 2089
12497SN/Ae// -*- mode:c++ -*-
212780Snikos.nikoleris@arm.com
38711SN/A////////////////////////////////////////////////////////////////////
48711SN/A//
58711SN/A// Control transfer instructions
68711SN/A//
78711SN/A
88711SN/Aoutput header {{
98711SN/A
108711SN/A    /**
118711SN/A     * Base class for instructions whose disassembly is not purely a
128711SN/A     * function of the machine instruction (i.e., it depends on the
138711SN/A     * PC).  This class overrides the disassemble() method to check
142497SN/A     * the PC and symbol table values before re-using a cached
152497SN/A     * disassembly string.  This is necessary for branches and jumps,
162497SN/A     * where the disassembly string includes the target address (which
172497SN/A     * may depend on the PC and/or symbol table).
182497SN/A     */
192497SN/A    class PCDependentDisassembly : public MipsStaticInst
202497SN/A    {
212497SN/A      protected:
222497SN/A        /// Cached program counter from last disassembly
232497SN/A        mutable Addr cachedPC;
242497SN/A
252497SN/A        /// Cached symbol table pointer from last disassembly
262497SN/A        mutable const SymbolTable *cachedSymtab;
272497SN/A
282497SN/A        /// Constructor
292497SN/A        PCDependentDisassembly(const char *mnem, MachInst _machInst,
302497SN/A                               OpClass __opClass)
312497SN/A            : MipsStaticInst(mnem, _machInst, __opClass),
322497SN/A              cachedPC(0), cachedSymtab(0)
332497SN/A        {
342497SN/A        }
352497SN/A
362497SN/A        const std::string &
372497SN/A        disassemble(Addr pc, const SymbolTable *symtab) const;
382497SN/A    };
392665SN/A
402665SN/A    /**
418715SN/A     * Base class for branches (PC-relative control transfers),
428922SN/A     * conditional or unconditional.
4312351Snikos.nikoleris@arm.com     */
442497SN/A    class Branch : public PCDependentDisassembly
452497SN/A    {
462497SN/A      protected:
472982SN/A        /// target address (signed) Displacement .
4810405Sandreas.hansson@arm.com        int32_t targetOffset;
492497SN/A
502497SN/A        /// Constructor.
5111793Sbrandon.potter@amd.com        Branch(const char *mnem, MachInst _machInst, OpClass __opClass)
5211793Sbrandon.potter@amd.com            : PCDependentDisassembly(mnem, _machInst, __opClass),
5312334Sgabeblack@google.com              targetOffset(OFFSET << 2)
542548SN/A        {
5510405Sandreas.hansson@arm.com        }
5610405Sandreas.hansson@arm.com
579524SN/A        Addr branchTarget(Addr branchPC) const;
582497SN/A
5910405Sandreas.hansson@arm.com        std::string
6010719SMarco.Balboni@ARM.com        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
6111334Sandreas.hansson@arm.com    };
6212341Snikos.nikoleris@arm.com
6312341Snikos.nikoleris@arm.com    /**
647523SN/A     * Base class for branches (PC-relative control transfers),
658851SN/A     * conditional or unconditional.
668948SN/A     */
678948SN/A    class BranchLikely : public PCDependentDisassembly
688851SN/A    {
699095SN/A      protected:
7010405Sandreas.hansson@arm.com        /// target address (signed) Displacement .
718922SN/A        int32_t targetOffset;
729715SN/A
739715SN/A        /// Constructor.
7410713Sandreas.hansson@arm.com        Branch(const char *mnem, MachInst _machInst, OpClass __opClass)
7510713Sandreas.hansson@arm.com            : PCDependentDisassembly(mnem, _machInst, __opClass),
768851SN/A              targetOffset(OFFSET << 2)
778851SN/A        {
788948SN/A        }
798948SN/A
808915SN/A        Addr branchTarget(Addr branchPC) const;
819031SN/A
829095SN/A        std::string
8310405Sandreas.hansson@arm.com        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
849036SN/A    };
858922SN/A
869715SN/A    /**
879715SN/A     * Base class for jumps (register-indirect control transfers).  In
8810713Sandreas.hansson@arm.com     * the Mips ISA, these are always unconditional.
8910713Sandreas.hansson@arm.com     */
9010713Sandreas.hansson@arm.com    class Jump : public PCDependentDisassembly
918915SN/A    {
928915SN/A      protected:
938948SN/A
948851SN/A        /// Displacement to target address (signed).
959095SN/A        int32_t disp;
9610888Sandreas.hansson@arm.com
978922SN/A      public:
989715SN/A        /// Constructor
999715SN/A        Jump(const char *mnem, MachInst _machInst, OpClass __opClass)
1009716SN/A            : PCDependentDisassembly(mnem, _machInst, __opClass),
1018851SN/A              disp(OFFSET)
1027523SN/A        {
1037523SN/A        }
10410405Sandreas.hansson@arm.com
1059715SN/A        Addr branchTarget(ExecContext *xc) const;
10610405Sandreas.hansson@arm.com
10710405Sandreas.hansson@arm.com        std::string
10810405Sandreas.hansson@arm.com        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
10910405Sandreas.hansson@arm.com    };
11010405Sandreas.hansson@arm.com}};
11110405Sandreas.hansson@arm.com
11210405Sandreas.hansson@arm.comoutput decoder {{
11310405Sandreas.hansson@arm.com    Addr
1149715SN/A    Branch::branchTarget(Addr branchPC) const
1159715SN/A    {
1162568SN/A        return branchPC + 4 + disp;
11710405Sandreas.hansson@arm.com    }
1182568SN/A
11910405Sandreas.hansson@arm.com    Addr
1209278SN/A    Jump::branchTarget(ExecContext *xc) const
1218948SN/A    {
1228948SN/A        Addr NPC = xc->readPC() + 4;
12310405Sandreas.hansson@arm.com        uint64_t Rb = xc->readIntReg(_srcRegIdx[0]);
1249088SN/A        return (Rb & ~3) | (NPC & 1);
12510405Sandreas.hansson@arm.com    }
12610405Sandreas.hansson@arm.com
12710405Sandreas.hansson@arm.com    const std::string &
12810405Sandreas.hansson@arm.com    PCDependentDisassembly::disassemble(Addr pc,
1298711SN/A                                        const SymbolTable *symtab) const
1308711SN/A    {
1312568SN/A        if (!cachedDisassembly ||
1329036SN/A            pc != cachedPC || symtab != cachedSymtab)
13310405Sandreas.hansson@arm.com        {
13411133Sandreas.hansson@arm.com            if (cachedDisassembly)
13511133Sandreas.hansson@arm.com                delete cachedDisassembly;
13611133Sandreas.hansson@arm.com
13711133Sandreas.hansson@arm.com            cachedDisassembly =
13811133Sandreas.hansson@arm.com                new std::string(generateDisassembly(pc, symtab));
1393244SN/A            cachedPC = pc;
1403244SN/A            cachedSymtab = symtab;
1418948SN/A        }
14210405Sandreas.hansson@arm.com
1433244SN/A        return *cachedDisassembly;
1448975SN/A    }
1459032SN/A
1463244SN/A    std::string
1479091SN/A    Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
1489091SN/A    {
14911284Sandreas.hansson@arm.com        std::stringstream ss;
15010656Sandreas.hansson@arm.com
15111284Sandreas.hansson@arm.com        ccprintf(ss, "%-10s ", mnemonic);
15211284Sandreas.hansson@arm.com
1539091SN/A        // There's only one register arg (RA), but it could be
15412780Snikos.nikoleris@arm.com        // either a source (the condition for conditional
15512780Snikos.nikoleris@arm.com        // branches) or a destination (the link reg for
15612780Snikos.nikoleris@arm.com        // unconditional branches)
1579612SN/A        if (_numSrcRegs > 0) {
15810405Sandreas.hansson@arm.com            printReg(ss, _srcRegIdx[0]);
1599033SN/A            ss << ",";
1609715SN/A        }
16111744Snikos.nikoleris@arm.com        else if (_numDestRegs > 0) {
16211744Snikos.nikoleris@arm.com            printReg(ss, _destRegIdx[0]);
1633244SN/A            ss << ",";
1643244SN/A        }
1653244SN/A
16611744Snikos.nikoleris@arm.com#ifdef SS_COMPATIBLE_DISASSEMBLY
16711744Snikos.nikoleris@arm.com        if (_numSrcRegs == 0 && _numDestRegs == 0) {
1685197SN/A            printReg(ss, 31);
1699712SN/A            ss << ",";
1709712SN/A        }
1719712SN/A#endif
1729712SN/A
1739712SN/A        Addr target = pc + 4 + disp;
17410719SMarco.Balboni@ARM.com
17510719SMarco.Balboni@ARM.com        std::string str;
17610719SMarco.Balboni@ARM.com        if (symtab && symtab->findSymbol(target, str))
17710719SMarco.Balboni@ARM.com            ss << str;
17810719SMarco.Balboni@ARM.com        else
17910719SMarco.Balboni@ARM.com            ccprintf(ss, "0x%x", target);
18010719SMarco.Balboni@ARM.com
18110719SMarco.Balboni@ARM.com        return ss.str();
18210719SMarco.Balboni@ARM.com    }
18310719SMarco.Balboni@ARM.com
18410719SMarco.Balboni@ARM.com    std::string
1854912SN/A    Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
18612346Snikos.nikoleris@arm.com    {
18712346Snikos.nikoleris@arm.com        std::stringstream ss;
18812346Snikos.nikoleris@arm.com
18912346Snikos.nikoleris@arm.com        ccprintf(ss, "%-10s ", mnemonic);
19012346Snikos.nikoleris@arm.com
19112346Snikos.nikoleris@arm.com#ifdef SS_COMPATIBLE_DISASSEMBLY
19212345Snikos.nikoleris@arm.com        if (_numDestRegs == 0) {
19312345Snikos.nikoleris@arm.com            printReg(ss, 31);
19412345Snikos.nikoleris@arm.com            ss << ",";
19511127Sandreas.hansson@arm.com        }
19611127Sandreas.hansson@arm.com#endif
19712351Snikos.nikoleris@arm.com
19812351Snikos.nikoleris@arm.com        if (_numDestRegs > 0) {
19912351Snikos.nikoleris@arm.com            printReg(ss, _destRegIdx[0]);
20012351Snikos.nikoleris@arm.com            ss << ",";
20112351Snikos.nikoleris@arm.com        }
20212351Snikos.nikoleris@arm.com
20312351Snikos.nikoleris@arm.com        ccprintf(ss, "(r%d)", RB);
20412351Snikos.nikoleris@arm.com
20512351Snikos.nikoleris@arm.com        return ss.str();
20612351Snikos.nikoleris@arm.com    }
20712351Snikos.nikoleris@arm.com}};
20812351Snikos.nikoleris@arm.com
20912351Snikos.nikoleris@arm.comdef template JumpOrBranchDecode {{
21012351Snikos.nikoleris@arm.com    return (RD == 0)
21112351Snikos.nikoleris@arm.com        ? (StaticInst<MipsISA> *)new %(class_name)s(machInst)
21212351Snikos.nikoleris@arm.com        : (StaticInst<MipsISA> *)new %(class_name)sAndLink(machInst);
2138979SN/A}};
2148979SN/A
21510402SN/Adef format Branch(code) {{
21610402SN/A    code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n';
21710402SN/A    iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
21811126Sandreas.hansson@arm.com                        ('IsDirectControl', 'IsCondControl'))
21911126Sandreas.hansson@arm.com    header_output = BasicDeclare.subst(iop)
22011126Sandreas.hansson@arm.com    decoder_output = BasicConstructor.subst(iop)
22110719SMarco.Balboni@ARM.com    decode_block = BasicDecode.subst(iop)
22211744Snikos.nikoleris@arm.com    exec_output = BasicExecute.subst(iop)
22311744Snikos.nikoleris@arm.com}};
22411744Snikos.nikoleris@arm.com
22511196Sali.jafri@arm.com
22611199Sandreas.hansson@arm.comdef format BranchLikely(code) {{
22711196Sali.jafri@arm.com    code = 'bool cond;\n' + code + '\nif (cond) NPC = NPC + disp;\n';
22811196Sali.jafri@arm.com    iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
22911196Sali.jafri@arm.com                        ('IsDirectControl', 'IsCondControl'))
23011196Sali.jafri@arm.com    header_output = BasicDeclare.subst(iop)
23111196Sali.jafri@arm.com    decoder_output = BasicConstructor.subst(iop)
23211196Sali.jafri@arm.com    decode_block = BasicDecode.subst(iop)
23311196Sali.jafri@arm.com    exec_output = BasicExecute.subst(iop)
23411196Sali.jafri@arm.com}};
23511196Sali.jafri@arm.com
23611196Sali.jafri@arm.com
23710402SN/Adef format UncondBranch(*flags) {{
23810402SN/A    flags += ('IsUncondControl', 'IsDirectControl')
23910402SN/A    (header_output, decoder_output, decode_block, exec_output) = \
24011127Sandreas.hansson@arm.com        UncondCtrlBase(name, Name, 'Branch', 'NPC + disp', flags)
24111127Sandreas.hansson@arm.com}};
24211127Sandreas.hansson@arm.com
24311127Sandreas.hansson@arm.comdef format Jump(*flags) {{
2448979SN/A    flags += ('IsUncondControl', 'IsIndirectControl')
2458948SN/A    (header_output, decoder_output, decode_block, exec_output) = \
24611334Sandreas.hansson@arm.com        UncondCtrlBase(name, Name, 'Jump', '(Rb & ~3) | (NPC & 1)', flags)
24711334Sandreas.hansson@arm.com}};
24810883Sali.jafri@arm.com
24911284Sandreas.hansson@arm.com
25011284Sandreas.hansson@arm.com