branch.isa revision 2123
111308Santhony.gutierrez@amd.com// -*- mode:c++ -*-
211308Santhony.gutierrez@amd.com
311308Santhony.gutierrez@amd.com////////////////////////////////////////////////////////////////////
411308Santhony.gutierrez@amd.com//
511308Santhony.gutierrez@amd.com// Control transfer instructions
611308Santhony.gutierrez@amd.com//
711308Santhony.gutierrez@amd.com
811308Santhony.gutierrez@amd.comoutput header {{
911308Santhony.gutierrez@amd.com
1011308Santhony.gutierrez@amd.com    /**
1111308Santhony.gutierrez@amd.com     * Base class for instructions whose disassembly is not purely a
1211308Santhony.gutierrez@amd.com     * function of the machine instruction (i.e., it depends on the
1311308Santhony.gutierrez@amd.com     * PC).  This class overrides the disassemble() method to check
1411308Santhony.gutierrez@amd.com     * the PC and symbol table values before re-using a cached
1511308Santhony.gutierrez@amd.com     * disassembly string.  This is necessary for branches and jumps,
1611308Santhony.gutierrez@amd.com     * where the disassembly string includes the target address (which
1711308Santhony.gutierrez@amd.com     * may depend on the PC and/or symbol table).
1811308Santhony.gutierrez@amd.com     */
1911308Santhony.gutierrez@amd.com    class PCDependentDisassembly : public MipsStaticInst
2011308Santhony.gutierrez@amd.com    {
2111308Santhony.gutierrez@amd.com      protected:
2211308Santhony.gutierrez@amd.com        /// Cached program counter from last disassembly
2311308Santhony.gutierrez@amd.com        mutable Addr cachedPC;
2411308Santhony.gutierrez@amd.com
2511308Santhony.gutierrez@amd.com        /// Cached symbol table pointer from last disassembly
2611308Santhony.gutierrez@amd.com        mutable const SymbolTable *cachedSymtab;
2711308Santhony.gutierrez@amd.com
2811308Santhony.gutierrez@amd.com        /// Constructor
2911308Santhony.gutierrez@amd.com        PCDependentDisassembly(const char *mnem, MachInst _machInst,
3011308Santhony.gutierrez@amd.com                               OpClass __opClass)
3111308Santhony.gutierrez@amd.com            : MipsStaticInst(mnem, _machInst, __opClass),
3211308Santhony.gutierrez@amd.com              cachedPC(0), cachedSymtab(0)
3311308Santhony.gutierrez@amd.com        {
3411308Santhony.gutierrez@amd.com        }
3511308Santhony.gutierrez@amd.com
3611308Santhony.gutierrez@amd.com        const std::string &
3711308Santhony.gutierrez@amd.com        disassemble(Addr pc, const SymbolTable *symtab) const;
3811308Santhony.gutierrez@amd.com    };
3911308Santhony.gutierrez@amd.com
4011308Santhony.gutierrez@amd.com    /**
4111308Santhony.gutierrez@amd.com     * Base class for branches (PC-relative control transfers),
4211308Santhony.gutierrez@amd.com     * conditional or unconditional.
4311308Santhony.gutierrez@amd.com     */
4411308Santhony.gutierrez@amd.com    class Branch : public PCDependentDisassembly
4511308Santhony.gutierrez@amd.com    {
4611308Santhony.gutierrez@amd.com      protected:
4711308Santhony.gutierrez@amd.com        /// target address (signed) Displacement .
4811308Santhony.gutierrez@amd.com        int32_t disp;
4911308Santhony.gutierrez@amd.com
5011308Santhony.gutierrez@amd.com        /// Constructor.
5111308Santhony.gutierrez@amd.com        Branch(const char *mnem, MachInst _machInst, OpClass __opClass)
5211308Santhony.gutierrez@amd.com            : PCDependentDisassembly(mnem, _machInst, __opClass),
5311308Santhony.gutierrez@amd.com              disp(OFFSET << 2)
5411308Santhony.gutierrez@amd.com        {
5511641Salexandru.dutu@amd.com        }
5611641Salexandru.dutu@amd.com
5711641Salexandru.dutu@amd.com        Addr branchTarget(Addr branchPC) const;
5811641Salexandru.dutu@amd.com
5911641Salexandru.dutu@amd.com        std::string
6011641Salexandru.dutu@amd.com        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
6111641Salexandru.dutu@amd.com    };
6211641Salexandru.dutu@amd.com
6311641Salexandru.dutu@amd.com    /**
6411641Salexandru.dutu@amd.com     * Base class for branch likely branches (PC-relative control transfers),
6511641Salexandru.dutu@amd.com     */
6611641Salexandru.dutu@amd.com    class BranchLikely : public PCDependentDisassembly
6711641Salexandru.dutu@amd.com    {
6811641Salexandru.dutu@amd.com      protected:
6911641Salexandru.dutu@amd.com        /// target address (signed) Displacement .
7011641Salexandru.dutu@amd.com        int32_t disp;
7111641Salexandru.dutu@amd.com
7211641Salexandru.dutu@amd.com        /// Constructor.
7311641Salexandru.dutu@amd.com        Branch(const char *mnem, MachInst _machInst, OpClass __opClass)
7411641Salexandru.dutu@amd.com            : PCDependentDisassembly(mnem, _machInst, __opClass),
7511641Salexandru.dutu@amd.com              disp(OFFSET << 2)
7611308Santhony.gutierrez@amd.com        {
7711308Santhony.gutierrez@amd.com        }
7811308Santhony.gutierrez@amd.com
7911308Santhony.gutierrez@amd.com        Addr branchTarget(Addr branchPC) const;
8011308Santhony.gutierrez@amd.com
8111308Santhony.gutierrez@amd.com        std::string
8211308Santhony.gutierrez@amd.com        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
8311308Santhony.gutierrez@amd.com    };
8411308Santhony.gutierrez@amd.com
8511308Santhony.gutierrez@amd.com    /**
8611308Santhony.gutierrez@amd.com     * Base class for jumps (register-indirect control transfers).  In
8711308Santhony.gutierrez@amd.com     * the Mips ISA, these are always unconditional.
8811308Santhony.gutierrez@amd.com     */
8911308Santhony.gutierrez@amd.com    class Jump : public PCDependentDisassembly
9011308Santhony.gutierrez@amd.com    {
9111308Santhony.gutierrez@amd.com      protected:
9211308Santhony.gutierrez@amd.com
9311308Santhony.gutierrez@amd.com        /// Displacement to target address (signed).
9411308Santhony.gutierrez@amd.com        int32_t disp;
9511308Santhony.gutierrez@amd.com
9611308Santhony.gutierrez@amd.com      public:
9711308Santhony.gutierrez@amd.com        /// Constructor
9811308Santhony.gutierrez@amd.com        Jump(const char *mnem, MachInst _machInst, OpClass __opClass)
9911308Santhony.gutierrez@amd.com            : PCDependentDisassembly(mnem, _machInst, __opClass),
10011308Santhony.gutierrez@amd.com              disp(OFFSET)
10111308Santhony.gutierrez@amd.com        {
10211308Santhony.gutierrez@amd.com        }
10311308Santhony.gutierrez@amd.com
10411308Santhony.gutierrez@amd.com        Addr branchTarget(ExecContext *xc) const;
10511308Santhony.gutierrez@amd.com
10611308Santhony.gutierrez@amd.com        std::string
10711534Sjohn.kalamatianos@amd.com        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
10811308Santhony.gutierrez@amd.com    };
10911308Santhony.gutierrez@amd.com}};
11011308Santhony.gutierrez@amd.com
11111308Santhony.gutierrez@amd.comoutput decoder {{
11211308Santhony.gutierrez@amd.com    Addr
11311308Santhony.gutierrez@amd.com    Branch::branchTarget(Addr branchPC) const
11411308Santhony.gutierrez@amd.com    {
11511534Sjohn.kalamatianos@amd.com        return branchPC + 4 + disp;
11611308Santhony.gutierrez@amd.com    }
11711308Santhony.gutierrez@amd.com
11811534Sjohn.kalamatianos@amd.com    Addr
11911534Sjohn.kalamatianos@amd.com    BranchLikely::branchTarget(Addr branchPC) const
12011308Santhony.gutierrez@amd.com    {
12111534Sjohn.kalamatianos@amd.com        return branchPC + 4 + disp;
12211308Santhony.gutierrez@amd.com    }
12311308Santhony.gutierrez@amd.com
12411308Santhony.gutierrez@amd.com    Addr
12511308Santhony.gutierrez@amd.com    Jump::branchTarget(ExecContext *xc) const
12611308Santhony.gutierrez@amd.com    {
12711308Santhony.gutierrez@amd.com        Addr NPC = xc->readPC() + 4;
12811308Santhony.gutierrez@amd.com        uint64_t Rb = xc->readIntReg(_srcRegIdx[0]);
12911308Santhony.gutierrez@amd.com        return (Rb & ~3) | (NPC & 1);
13011308Santhony.gutierrez@amd.com    }
13111308Santhony.gutierrez@amd.com
13211308Santhony.gutierrez@amd.com    const std::string &
13311308Santhony.gutierrez@amd.com    PCDependentDisassembly::disassemble(Addr pc,
13411308Santhony.gutierrez@amd.com                                        const SymbolTable *symtab) const
13511308Santhony.gutierrez@amd.com    {
13611308Santhony.gutierrez@amd.com        if (!cachedDisassembly ||
13711308Santhony.gutierrez@amd.com            pc != cachedPC || symtab != cachedSymtab)
13811308Santhony.gutierrez@amd.com        {
13911308Santhony.gutierrez@amd.com            if (cachedDisassembly)
14011308Santhony.gutierrez@amd.com                delete cachedDisassembly;
14111308Santhony.gutierrez@amd.com
14211308Santhony.gutierrez@amd.com            cachedDisassembly =
14311308Santhony.gutierrez@amd.com                new std::string(generateDisassembly(pc, symtab));
14411308Santhony.gutierrez@amd.com            cachedPC = pc;
14511308Santhony.gutierrez@amd.com            cachedSymtab = symtab;
14611308Santhony.gutierrez@amd.com        }
14711308Santhony.gutierrez@amd.com
14811308Santhony.gutierrez@amd.com        return *cachedDisassembly;
14911308Santhony.gutierrez@amd.com    }
15011308Santhony.gutierrez@amd.com
15111639Salexandru.dutu@amd.com    std::string
15211308Santhony.gutierrez@amd.com    Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
15311639Salexandru.dutu@amd.com    {
15411639Salexandru.dutu@amd.com        std::stringstream ss;
15511639Salexandru.dutu@amd.com
15611639Salexandru.dutu@amd.com        ccprintf(ss, "%-10s ", mnemonic);
15711308Santhony.gutierrez@amd.com
15811308Santhony.gutierrez@amd.com        // There's only one register arg (RA), but it could be
15911308Santhony.gutierrez@amd.com        // either a source (the condition for conditional
16011639Salexandru.dutu@amd.com        // branches) or a destination (the link reg for
16111308Santhony.gutierrez@amd.com        // unconditional branches)
16211308Santhony.gutierrez@amd.com        if (_numSrcRegs > 0) {
16311308Santhony.gutierrez@amd.com            printReg(ss, _srcRegIdx[0]);
16411308Santhony.gutierrez@amd.com            ss << ",";
16511308Santhony.gutierrez@amd.com        }
16611308Santhony.gutierrez@amd.com        else if (_numDestRegs > 0) {
16711308Santhony.gutierrez@amd.com            printReg(ss, _destRegIdx[0]);
16811308Santhony.gutierrez@amd.com            ss << ",";
16911308Santhony.gutierrez@amd.com        }
17011308Santhony.gutierrez@amd.com
17111308Santhony.gutierrez@amd.com#ifdef SS_COMPATIBLE_DISASSEMBLY
17211308Santhony.gutierrez@amd.com        if (_numSrcRegs == 0 && _numDestRegs == 0) {
17311308Santhony.gutierrez@amd.com            printReg(ss, 31);
17411308Santhony.gutierrez@amd.com            ss << ",";
17511308Santhony.gutierrez@amd.com        }
17611308Santhony.gutierrez@amd.com#endif
17711308Santhony.gutierrez@amd.com
17811308Santhony.gutierrez@amd.com        Addr target = pc + 4 + disp;
17911308Santhony.gutierrez@amd.com
18011308Santhony.gutierrez@amd.com        std::string str;
18111308Santhony.gutierrez@amd.com        if (symtab && symtab->findSymbol(target, str))
18211308Santhony.gutierrez@amd.com            ss << str;
18311308Santhony.gutierrez@amd.com        else
18411308Santhony.gutierrez@amd.com            ccprintf(ss, "0x%x", target);
18511308Santhony.gutierrez@amd.com
18611308Santhony.gutierrez@amd.com        return ss.str();
18711308Santhony.gutierrez@amd.com    }
18811308Santhony.gutierrez@amd.com
18911639Salexandru.dutu@amd.com    std::string
19011639Salexandru.dutu@amd.com    BranchLikely::generateDisassembly(Addr pc, const SymbolTable *symtab) const
19111639Salexandru.dutu@amd.com    {
19211639Salexandru.dutu@amd.com        std::stringstream ss;
19311639Salexandru.dutu@amd.com
19411639Salexandru.dutu@amd.com        ccprintf(ss, "%-10s ", mnemonic);
19511639Salexandru.dutu@amd.com
19611639Salexandru.dutu@amd.com        // There's only one register arg (RA), but it could be
19711639Salexandru.dutu@amd.com        // either a source (the condition for conditional
19811639Salexandru.dutu@amd.com        // branches) or a destination (the link reg for
19911639Salexandru.dutu@amd.com        // unconditional branches)
20011308Santhony.gutierrez@amd.com        if (_numSrcRegs > 0) {
20111639Salexandru.dutu@amd.com            printReg(ss, _srcRegIdx[0]);
20211308Santhony.gutierrez@amd.com            ss << ",";
20311308Santhony.gutierrez@amd.com        }
20411639Salexandru.dutu@amd.com        else if (_numDestRegs > 0) {
20511308Santhony.gutierrez@amd.com            printReg(ss, _destRegIdx[0]);
20611639Salexandru.dutu@amd.com            ss << ",";
20711308Santhony.gutierrez@amd.com        }
20811639Salexandru.dutu@amd.com
20911308Santhony.gutierrez@amd.com#ifdef SS_COMPATIBLE_DISASSEMBLY
21011639Salexandru.dutu@amd.com        if (_numSrcRegs == 0 && _numDestRegs == 0) {
21111308Santhony.gutierrez@amd.com            printReg(ss, 31);
21211639Salexandru.dutu@amd.com            ss << ",";
21311639Salexandru.dutu@amd.com        }
21411639Salexandru.dutu@amd.com#endif
21511639Salexandru.dutu@amd.com
21611639Salexandru.dutu@amd.com        Addr target = pc + 4 + disp;
21711308Santhony.gutierrez@amd.com
21811639Salexandru.dutu@amd.com        std::string str;
21911639Salexandru.dutu@amd.com        if (symtab && symtab->findSymbol(target, str))
22011308Santhony.gutierrez@amd.com            ss << str;
22111308Santhony.gutierrez@amd.com        else
22211308Santhony.gutierrez@amd.com            ccprintf(ss, "0x%x", target);
22311308Santhony.gutierrez@amd.com
22411308Santhony.gutierrez@amd.com        return ss.str();
22511308Santhony.gutierrez@amd.com    }
22611308Santhony.gutierrez@amd.com
22711639Salexandru.dutu@amd.com    std::string
22811308Santhony.gutierrez@amd.com    Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
22911639Salexandru.dutu@amd.com    {
23011308Santhony.gutierrez@amd.com        std::stringstream ss;
23111639Salexandru.dutu@amd.com
23211308Santhony.gutierrez@amd.com        ccprintf(ss, "%-10s ", mnemonic);
23311308Santhony.gutierrez@amd.com
23411639Salexandru.dutu@amd.com#ifdef SS_COMPATIBLE_DISASSEMBLY
23511308Santhony.gutierrez@amd.com        if (_numDestRegs == 0) {
23611639Salexandru.dutu@amd.com            printReg(ss, 31);
23711308Santhony.gutierrez@amd.com            ss << ",";
23811639Salexandru.dutu@amd.com        }
23911308Santhony.gutierrez@amd.com#endif
24011308Santhony.gutierrez@amd.com
24111639Salexandru.dutu@amd.com        if (_numDestRegs > 0) {
24211308Santhony.gutierrez@amd.com            printReg(ss, _destRegIdx[0]);
24311308Santhony.gutierrez@amd.com            ss << ",";
24411639Salexandru.dutu@amd.com        }
24511639Salexandru.dutu@amd.com
24611308Santhony.gutierrez@amd.com        ccprintf(ss, "(r%d)", RB);
24711308Santhony.gutierrez@amd.com
24811308Santhony.gutierrez@amd.com        return ss.str();
24911308Santhony.gutierrez@amd.com    }
25011308Santhony.gutierrez@amd.com}};
25111308Santhony.gutierrez@amd.com
25211308Santhony.gutierrez@amd.comdef format Branch(code,*flags) {{
25311308Santhony.gutierrez@amd.com    #Add Link Code if Link instruction
25411308Santhony.gutierrez@amd.com    strlen = len(name)
25511308Santhony.gutierrez@amd.com    if name[strlen-2:] == 'al':
25611308Santhony.gutierrez@amd.com        code += 'R31 = NNPC;\n'
25711308Santhony.gutierrez@amd.com
25811308Santhony.gutierrez@amd.com    #Condition code
25911308Santhony.gutierrez@amd.com    code = 'bool cond;\n' + code
26011308Santhony.gutierrez@amd.com    code += 'if (cond) {\n'
26111308Santhony.gutierrez@amd.com    #code += '//NPC=NPC: just placeholder to force parser to writeback NPC\n'
26211308Santhony.gutierrez@amd.com    #code += '  NPC = NPC; \n'
26311308Santhony.gutierrez@amd.com    code += '  NNPC = NPC + disp;\n'
26411308Santhony.gutierrez@amd.com    code += '} \n'
26511308Santhony.gutierrez@amd.com
26611308Santhony.gutierrez@amd.com    iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
26711308Santhony.gutierrez@amd.com                        ('IsDirectControl', 'IsCondControl'))
26811308Santhony.gutierrez@amd.com
26911308Santhony.gutierrez@amd.com    header_output = BasicDeclare.subst(iop)
27011308Santhony.gutierrez@amd.com    decoder_output = BasicConstructor.subst(iop)
27111308Santhony.gutierrez@amd.com    decode_block = BasicDecode.subst(iop)
27211308Santhony.gutierrez@amd.com    exec_output = BasicExecute.subst(iop)
27311308Santhony.gutierrez@amd.com}};
27411308Santhony.gutierrez@amd.com
27511308Santhony.gutierrez@amd.com
27611308Santhony.gutierrez@amd.comdef format BranchLikely(code,*flags) {{
27711308Santhony.gutierrez@amd.com    #Add Link Code if Link instruction
27811308Santhony.gutierrez@amd.com    strlen = len(name)
27911308Santhony.gutierrez@amd.com    if name[strlen-3:] == 'all':
28011308Santhony.gutierrez@amd.com        code += 'R31 = NNPC;\n'
28111308Santhony.gutierrez@amd.com
28211308Santhony.gutierrez@amd.com    #Condition code
28311308Santhony.gutierrez@amd.com    code = 'bool cond;\n' + code
28411308Santhony.gutierrez@amd.com    code += 'if (cond) {'
28511308Santhony.gutierrez@amd.com    #code += '//NPC=NPC: just placeholder to force parser to writeback NPC\n'
28611308Santhony.gutierrez@amd.com    #code += 'NPC = NPC; \n'
28711308Santhony.gutierrez@amd.com    code += 'NNPC = NPC + disp;\n'
28811308Santhony.gutierrez@amd.com    code += '} \n'
28911308Santhony.gutierrez@amd.com
29011308Santhony.gutierrez@amd.com
29111308Santhony.gutierrez@amd.com    iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
29211308Santhony.gutierrez@amd.com                        ('IsDirectControl', 'IsCondControl','IsCondDelaySlot'))
29311534Sjohn.kalamatianos@amd.com
29411308Santhony.gutierrez@amd.com    header_output = BasicDeclare.subst(iop)
29511534Sjohn.kalamatianos@amd.com    decoder_output = BasicConstructor.subst(iop)
29611308Santhony.gutierrez@amd.com    decode_block = BasicDecode.subst(iop)
29711308Santhony.gutierrez@amd.com    exec_output = BasicExecute.subst(iop)
29811308Santhony.gutierrez@amd.com}};
29911308Santhony.gutierrez@amd.com
30011308Santhony.gutierrez@amd.comdef format Jump(code,*flags) {{
30111308Santhony.gutierrez@amd.com    #Add Link Code if Link instruction
30211308Santhony.gutierrez@amd.com    strlen = len(name)
30311308Santhony.gutierrez@amd.com    if strlen >= 3 and name[2:3] == 'al':
30411308Santhony.gutierrez@amd.com            code = 'R31 = NNPC;\n' + code
30511308Santhony.gutierrez@amd.com
30611308Santhony.gutierrez@amd.com    iop = InstObjParams(name, Name, 'Jump', CodeBlock(code),\
30711308Santhony.gutierrez@amd.com                        ('IsIndirectControl', 'IsUncondControl'))
30811308Santhony.gutierrez@amd.com
30911308Santhony.gutierrez@amd.com    header_output = BasicDeclare.subst(iop)
31011308Santhony.gutierrez@amd.com    decoder_output = BasicConstructor.subst(iop)
31111308Santhony.gutierrez@amd.com    decode_block = BasicDecode.subst(iop)
31211308Santhony.gutierrez@amd.com    exec_output = BasicExecute.subst(iop)
31311308Santhony.gutierrez@amd.com}};
31411308Santhony.gutierrez@amd.com
31511308Santhony.gutierrez@amd.com
31611308Santhony.gutierrez@amd.com
31711308Santhony.gutierrez@amd.com
31811308Santhony.gutierrez@amd.com