branch.isa revision 2687
12100SN/A// -*- mode:c++ -*-
22083SN/A
32089SN/A////////////////////////////////////////////////////////////////////
42022SN/A//
52089SN/A// Control transfer instructions
62022SN/A//
72022SN/A
82022SN/Aoutput header {{
92083SN/A
102239SN/A#include <iostream>
112239SN/A    using namespace std;
122239SN/A
132083SN/A    /**
142083SN/A     * Base class for instructions whose disassembly is not purely a
152083SN/A     * function of the machine instruction (i.e., it depends on the
162083SN/A     * PC).  This class overrides the disassemble() method to check
172083SN/A     * the PC and symbol table values before re-using a cached
182083SN/A     * disassembly string.  This is necessary for branches and jumps,
192083SN/A     * where the disassembly string includes the target address (which
202083SN/A     * may depend on the PC and/or symbol table).
212083SN/A     */
222089SN/A    class PCDependentDisassembly : public MipsStaticInst
232083SN/A    {
242083SN/A      protected:
252083SN/A        /// Cached program counter from last disassembly
262083SN/A        mutable Addr cachedPC;
272089SN/A
282083SN/A        /// Cached symbol table pointer from last disassembly
292083SN/A        mutable const SymbolTable *cachedSymtab;
302083SN/A
312083SN/A        /// Constructor
322083SN/A        PCDependentDisassembly(const char *mnem, MachInst _machInst,
332083SN/A                               OpClass __opClass)
342089SN/A            : MipsStaticInst(mnem, _machInst, __opClass),
352083SN/A              cachedPC(0), cachedSymtab(0)
362022SN/A        {
372083SN/A        }
382022SN/A
392083SN/A        const std::string &
402083SN/A        disassemble(Addr pc, const SymbolTable *symtab) const;
412083SN/A    };
422022SN/A
432083SN/A    /**
442083SN/A     * Base class for branches (PC-relative control transfers),
452083SN/A     * conditional or unconditional.
462083SN/A     */
472083SN/A    class Branch : public PCDependentDisassembly
482083SN/A    {
492083SN/A      protected:
502089SN/A        /// target address (signed) Displacement .
512104SN/A        int32_t disp;
522083SN/A
532083SN/A        /// Constructor.
542083SN/A        Branch(const char *mnem, MachInst _machInst, OpClass __opClass)
552083SN/A            : PCDependentDisassembly(mnem, _machInst, __opClass),
562104SN/A              disp(OFFSET << 2)
572089SN/A        {
582239SN/A            //If Bit 17 is 1 then Sign Extend
592239SN/A            if ( (disp & 0x00020000) > 0  ) {
602239SN/A                disp |= 0xFFFE0000;
612239SN/A            }
622089SN/A        }
632089SN/A
642089SN/A        Addr branchTarget(Addr branchPC) const;
652089SN/A
662089SN/A        std::string
672089SN/A        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
682089SN/A    };
692089SN/A
702089SN/A    /**
712083SN/A     * Base class for jumps (register-indirect control transfers).  In
722089SN/A     * the Mips ISA, these are always unconditional.
732083SN/A     */
742083SN/A    class Jump : public PCDependentDisassembly
752083SN/A    {
762083SN/A      protected:
772083SN/A
782083SN/A        /// Displacement to target address (signed).
792083SN/A        int32_t disp;
802083SN/A
812239SN/A        uint32_t target;
822239SN/A
832083SN/A      public:
842083SN/A        /// Constructor
852083SN/A        Jump(const char *mnem, MachInst _machInst, OpClass __opClass)
862083SN/A            : PCDependentDisassembly(mnem, _machInst, __opClass),
872239SN/A              disp(JMPTARG << 2)
882083SN/A        {
892083SN/A        }
902083SN/A
912687Sksewell@umich.edu        Addr branchTarget(ThreadContext *tc) const;
922083SN/A
932083SN/A        std::string
942083SN/A        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
952083SN/A    };
962022SN/A}};
972022SN/A
982022SN/Aoutput decoder {{
992083SN/A    Addr
1002083SN/A    Branch::branchTarget(Addr branchPC) const
1012083SN/A    {
1022083SN/A        return branchPC + 4 + disp;
1032083SN/A    }
1042083SN/A
1052083SN/A    Addr
1062687Sksewell@umich.edu    Jump::branchTarget(ThreadContext *tc) const
1072083SN/A    {
1082687Sksewell@umich.edu        Addr NPC = tc->readPC() + 4;
1092687Sksewell@umich.edu        uint64_t Rb = tc->readIntReg(_srcRegIdx[0]);
1102083SN/A        return (Rb & ~3) | (NPC & 1);
1112083SN/A    }
1122083SN/A
1132083SN/A    const std::string &
1142083SN/A    PCDependentDisassembly::disassemble(Addr pc,
1152083SN/A                                        const SymbolTable *symtab) const
1162083SN/A    {
1172083SN/A        if (!cachedDisassembly ||
1182083SN/A            pc != cachedPC || symtab != cachedSymtab)
1192022SN/A        {
1202083SN/A            if (cachedDisassembly)
1212083SN/A                delete cachedDisassembly;
1222083SN/A
1232083SN/A            cachedDisassembly =
1242083SN/A                new std::string(generateDisassembly(pc, symtab));
1252083SN/A            cachedPC = pc;
1262083SN/A            cachedSymtab = symtab;
1272022SN/A        }
1282083SN/A
1292083SN/A        return *cachedDisassembly;
1302083SN/A    }
1312083SN/A
1322083SN/A    std::string
1332083SN/A    Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
1342083SN/A    {
1352083SN/A        std::stringstream ss;
1362083SN/A
1372083SN/A        ccprintf(ss, "%-10s ", mnemonic);
1382083SN/A
1392083SN/A        // There's only one register arg (RA), but it could be
1402083SN/A        // either a source (the condition for conditional
1412083SN/A        // branches) or a destination (the link reg for
1422083SN/A        // unconditional branches)
1432239SN/A        if (_numSrcRegs == 1) {
1442083SN/A            printReg(ss, _srcRegIdx[0]);
1452686Sksewell@umich.edu            ss << ", ";
1462239SN/A        } else if(_numSrcRegs == 2) {
1472239SN/A            printReg(ss, _srcRegIdx[0]);
1482686Sksewell@umich.edu            ss << ", ";
1492239SN/A            printReg(ss, _srcRegIdx[1]);
1502686Sksewell@umich.edu            ss << ", ";
1512103SN/A        }
1522103SN/A
1532103SN/A        Addr target = pc + 4 + disp;
1542103SN/A
1552103SN/A        std::string str;
1562103SN/A        if (symtab && symtab->findSymbol(target, str))
1572103SN/A            ss << str;
1582103SN/A        else
1592103SN/A            ccprintf(ss, "0x%x", target);
1602103SN/A
1612103SN/A        return ss.str();
1622103SN/A    }
1632103SN/A
1642103SN/A    std::string
1652083SN/A    Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
1662083SN/A    {
1672083SN/A        std::stringstream ss;
1682083SN/A
1692083SN/A        ccprintf(ss, "%-10s ", mnemonic);
1702083SN/A
1712239SN/A        if ( mnemonic == "jal" ) {
1722239SN/A            Addr npc = pc + 4;
1732239SN/A            ccprintf(ss,"0x%x",(npc & 0xF0000000) | disp);
1742239SN/A        } else if (_numSrcRegs == 0) {
1752239SN/A            std::string str;
1762239SN/A            if (symtab && symtab->findSymbol(disp, str))
1772239SN/A                ss << str;
1782239SN/A            else
1792239SN/A                ccprintf(ss, "0x%x", disp);
1802239SN/A        } else if (_numSrcRegs == 1) {
1812239SN/A             printReg(ss, _srcRegIdx[0]);
1822239SN/A        } else if(_numSrcRegs == 2) {
1832239SN/A            printReg(ss, _srcRegIdx[0]);
1842686Sksewell@umich.edu            ss << ", ";
1852239SN/A            printReg(ss, _srcRegIdx[1]);
1862083SN/A        }
1872083SN/A
1882083SN/A        return ss.str();
1892083SN/A    }
1902022SN/A}};
1912022SN/A
1922686Sksewell@umich.edudef format Branch(code,*opt_flags) {{
1932686Sksewell@umich.edu    not_taken_code = '  NNPC = NNPC;\n'
1942686Sksewell@umich.edu    not_taken_code += '} \n'
1952686Sksewell@umich.edu
1962686Sksewell@umich.edu    #Build Instruction Flags
1972686Sksewell@umich.edu    #Use Link & Likely Flags to Add Link/Condition Code
1982686Sksewell@umich.edu    inst_flags = ('IsDirectControl', )
1992686Sksewell@umich.edu    for x in opt_flags:
2002686Sksewell@umich.edu        if x == 'Link':
2012686Sksewell@umich.edu            code += 'R31 = NNPC;\n'
2022686Sksewell@umich.edu        elif x == 'Likely':
2032686Sksewell@umich.edu            not_taken_code = '  NPC = NNPC;\n'
2042686Sksewell@umich.edu            not_taken_code += '  NNPC = NNPC + 4;\n'
2052686Sksewell@umich.edu            not_taken_code += '} \n'
2062686Sksewell@umich.edu            inst_flags = ('IsCondDelaySlot', )
2072686Sksewell@umich.edu        else:
2082686Sksewell@umich.edu            inst_flags += (x, )
2092686Sksewell@umich.edu
2102686Sksewell@umich.edu    if 'cond == 1' in code:
2112686Sksewell@umich.edu         inst_flags += ('IsCondControl', )
2122686Sksewell@umich.edu    else:
2132686Sksewell@umich.edu         inst_flags += ('IsUncondControl', )
2142101SN/A
2152123SN/A    #Condition code
2162123SN/A    code = 'bool cond;\n' + code
2172123SN/A    code += 'if (cond) {\n'
2182123SN/A    code += '  NNPC = NPC + disp;\n'
2192239SN/A    code += '} else {\n'
2202686Sksewell@umich.edu    code += not_taken_code
2212101SN/A
2222686Sksewell@umich.edu    iop = InstObjParams(name, Name, 'Branch', CodeBlock(code), inst_flags)
2232047SN/A    header_output = BasicDeclare.subst(iop)
2242047SN/A    decoder_output = BasicConstructor.subst(iop)
2252047SN/A    decode_block = BasicDecode.subst(iop)
2262047SN/A    exec_output = BasicExecute.subst(iop)
2272022SN/A}};
2282047SN/A
2292686Sksewell@umich.edudef format Jump(code, *opt_flags) {{
2302686Sksewell@umich.edu    #Build Instruction Flags
2312686Sksewell@umich.edu    #Use Link Flag to Add Link Code
2322686Sksewell@umich.edu    inst_flags = ('IsIndirectControl', 'IsUncondControl')
2332686Sksewell@umich.edu    for x in opt_flags:
2342686Sksewell@umich.edu        if x == 'Link':
2352686Sksewell@umich.edu            code = 'R31 = NNPC;\n' + code
2362686Sksewell@umich.edu        elif x == 'ClearHazards':
2372686Sksewell@umich.edu            code += '/* Code Needed to Clear Execute & Inst Hazards */\n'
2382686Sksewell@umich.edu        else:
2392686Sksewell@umich.edu            inst_flags += (x, )
2402104SN/A
2412686Sksewell@umich.edu    iop = InstObjParams(name, Name, 'Jump', CodeBlock(code), inst_flags)
2422089SN/A    header_output = BasicDeclare.subst(iop)
2432089SN/A    decoder_output = BasicConstructor.subst(iop)
2442089SN/A    decode_block = BasicDecode.subst(iop)
2452089SN/A    exec_output = BasicExecute.subst(iop)
2462089SN/A}};
2472083SN/A
2482239SN/A
2492123SN/A
2502123SN/A
251