branch.isa revision 2103
112218Snikos.nikoleris@arm.com// -*- mode:c++ -*-
212218Snikos.nikoleris@arm.com
312218Snikos.nikoleris@arm.com////////////////////////////////////////////////////////////////////
412218Snikos.nikoleris@arm.com//
512218Snikos.nikoleris@arm.com// Control transfer instructions
612218Snikos.nikoleris@arm.com//
712218Snikos.nikoleris@arm.com
812218Snikos.nikoleris@arm.comoutput header {{
912218Snikos.nikoleris@arm.com
1012218Snikos.nikoleris@arm.com    /**
1112218Snikos.nikoleris@arm.com     * Base class for instructions whose disassembly is not purely a
1212218Snikos.nikoleris@arm.com     * function of the machine instruction (i.e., it depends on the
1312218Snikos.nikoleris@arm.com     * PC).  This class overrides the disassemble() method to check
1412218Snikos.nikoleris@arm.com     * the PC and symbol table values before re-using a cached
1512218Snikos.nikoleris@arm.com     * disassembly string.  This is necessary for branches and jumps,
1612218Snikos.nikoleris@arm.com     * where the disassembly string includes the target address (which
1712218Snikos.nikoleris@arm.com     * may depend on the PC and/or symbol table).
1812218Snikos.nikoleris@arm.com     */
1912218Snikos.nikoleris@arm.com    class PCDependentDisassembly : public MipsStaticInst
2012218Snikos.nikoleris@arm.com    {
2112218Snikos.nikoleris@arm.com      protected:
2212218Snikos.nikoleris@arm.com        /// Cached program counter from last disassembly
2312218Snikos.nikoleris@arm.com        mutable Addr cachedPC;
2412218Snikos.nikoleris@arm.com
2512218Snikos.nikoleris@arm.com        /// Cached symbol table pointer from last disassembly
2612218Snikos.nikoleris@arm.com        mutable const SymbolTable *cachedSymtab;
2712218Snikos.nikoleris@arm.com
2812218Snikos.nikoleris@arm.com        /// Constructor
2912218Snikos.nikoleris@arm.com        PCDependentDisassembly(const char *mnem, MachInst _machInst,
3012218Snikos.nikoleris@arm.com                               OpClass __opClass)
3112218Snikos.nikoleris@arm.com            : MipsStaticInst(mnem, _machInst, __opClass),
3212218Snikos.nikoleris@arm.com              cachedPC(0), cachedSymtab(0)
3312218Snikos.nikoleris@arm.com        {
3412218Snikos.nikoleris@arm.com        }
3512218Snikos.nikoleris@arm.com
3612218Snikos.nikoleris@arm.com        const std::string &
3712218Snikos.nikoleris@arm.com        disassemble(Addr pc, const SymbolTable *symtab) const;
3812218Snikos.nikoleris@arm.com    };
3912218Snikos.nikoleris@arm.com
4012218Snikos.nikoleris@arm.com    /**
4112218Snikos.nikoleris@arm.com     * Base class for branches (PC-relative control transfers),
4212218Snikos.nikoleris@arm.com     * conditional or unconditional.
4312218Snikos.nikoleris@arm.com     */
4412218Snikos.nikoleris@arm.com    class Branch : public PCDependentDisassembly
4512218Snikos.nikoleris@arm.com    {
4612218Snikos.nikoleris@arm.com      protected:
4712218Snikos.nikoleris@arm.com        /// target address (signed) Displacement .
4812218Snikos.nikoleris@arm.com        int32_t targetOffset;
4912218Snikos.nikoleris@arm.com
5012218Snikos.nikoleris@arm.com        /// Constructor.
5112218Snikos.nikoleris@arm.com        Branch(const char *mnem, MachInst _machInst, OpClass __opClass)
5212218Snikos.nikoleris@arm.com            : PCDependentDisassembly(mnem, _machInst, __opClass),
5312218Snikos.nikoleris@arm.com              targetOffset(OFFSET << 2)
5412218Snikos.nikoleris@arm.com        {
5512218Snikos.nikoleris@arm.com        }
5612218Snikos.nikoleris@arm.com
5712218Snikos.nikoleris@arm.com        Addr branchTarget(Addr branchPC) const;
5812218Snikos.nikoleris@arm.com
5912218Snikos.nikoleris@arm.com        std::string
6012218Snikos.nikoleris@arm.com        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
6112218Snikos.nikoleris@arm.com    };
6212218Snikos.nikoleris@arm.com
6312218Snikos.nikoleris@arm.com    /**
6412218Snikos.nikoleris@arm.com     * Base class for branch likely branches (PC-relative control transfers),
6512218Snikos.nikoleris@arm.com     */
6612749Sgiacomo.travaglini@arm.com    class BranchLikely : public PCDependentDisassembly
6712218Snikos.nikoleris@arm.com    {
6812218Snikos.nikoleris@arm.com      protected:
6912218Snikos.nikoleris@arm.com        /// target address (signed) Displacement .
7012218Snikos.nikoleris@arm.com        int32_t targetOffset;
7112218Snikos.nikoleris@arm.com
7212218Snikos.nikoleris@arm.com        /// Constructor.
7312218Snikos.nikoleris@arm.com        Branch(const char *mnem, MachInst _machInst, OpClass __opClass)
7412218Snikos.nikoleris@arm.com            : PCDependentDisassembly(mnem, _machInst, __opClass),
7512218Snikos.nikoleris@arm.com              targetOffset(OFFSET << 2)
7612218Snikos.nikoleris@arm.com        {
7712218Snikos.nikoleris@arm.com        }
7812218Snikos.nikoleris@arm.com
7912749Sgiacomo.travaglini@arm.com        Addr branchTarget(Addr branchPC) const;
8012218Snikos.nikoleris@arm.com
8112218Snikos.nikoleris@arm.com        std::string
8212218Snikos.nikoleris@arm.com        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
8312218Snikos.nikoleris@arm.com    };
8412218Snikos.nikoleris@arm.com
8512218Snikos.nikoleris@arm.com    /**
8612218Snikos.nikoleris@arm.com     * Base class for jumps (register-indirect control transfers).  In
8712218Snikos.nikoleris@arm.com     * the Mips ISA, these are always unconditional.
8812218Snikos.nikoleris@arm.com     */
8912218Snikos.nikoleris@arm.com    class Jump : public PCDependentDisassembly
9012218Snikos.nikoleris@arm.com    {
9112218Snikos.nikoleris@arm.com      protected:
9212218Snikos.nikoleris@arm.com
93        /// Displacement to target address (signed).
94        int32_t disp;
95
96      public:
97        /// Constructor
98        Jump(const char *mnem, MachInst _machInst, OpClass __opClass)
99            : PCDependentDisassembly(mnem, _machInst, __opClass),
100              disp(OFFSET)
101        {
102        }
103
104        Addr branchTarget(ExecContext *xc) const;
105
106        std::string
107        generateDisassembly(Addr pc, const SymbolTable *symtab) const;
108    };
109}};
110
111output decoder {{
112    Addr
113    Branch::branchTarget(Addr branchPC) const
114    {
115        return branchPC + 4 + disp;
116    }
117
118    Addr
119    BranchLikely::branchTarget(Addr branchPC) const
120    {
121        return branchPC + 4 + disp;
122    }
123
124    Addr
125    Jump::branchTarget(ExecContext *xc) const
126    {
127        Addr NPC = xc->readPC() + 4;
128        uint64_t Rb = xc->readIntReg(_srcRegIdx[0]);
129        return (Rb & ~3) | (NPC & 1);
130    }
131
132    const std::string &
133    PCDependentDisassembly::disassemble(Addr pc,
134                                        const SymbolTable *symtab) const
135    {
136        if (!cachedDisassembly ||
137            pc != cachedPC || symtab != cachedSymtab)
138        {
139            if (cachedDisassembly)
140                delete cachedDisassembly;
141
142            cachedDisassembly =
143                new std::string(generateDisassembly(pc, symtab));
144            cachedPC = pc;
145            cachedSymtab = symtab;
146        }
147
148        return *cachedDisassembly;
149    }
150
151    std::string
152    Branch::generateDisassembly(Addr pc, const SymbolTable *symtab) const
153    {
154        std::stringstream ss;
155
156        ccprintf(ss, "%-10s ", mnemonic);
157
158        // There's only one register arg (RA), but it could be
159        // either a source (the condition for conditional
160        // branches) or a destination (the link reg for
161        // unconditional branches)
162        if (_numSrcRegs > 0) {
163            printReg(ss, _srcRegIdx[0]);
164            ss << ",";
165        }
166        else if (_numDestRegs > 0) {
167            printReg(ss, _destRegIdx[0]);
168            ss << ",";
169        }
170
171#ifdef SS_COMPATIBLE_DISASSEMBLY
172        if (_numSrcRegs == 0 && _numDestRegs == 0) {
173            printReg(ss, 31);
174            ss << ",";
175        }
176#endif
177
178        Addr target = pc + 4 + disp;
179
180        std::string str;
181        if (symtab && symtab->findSymbol(target, str))
182            ss << str;
183        else
184            ccprintf(ss, "0x%x", target);
185
186        return ss.str();
187    }
188
189    std::string
190    BranchLikely::generateDisassembly(Addr pc, const SymbolTable *symtab) const
191    {
192        std::stringstream ss;
193
194        ccprintf(ss, "%-10s ", mnemonic);
195
196        // There's only one register arg (RA), but it could be
197        // either a source (the condition for conditional
198        // branches) or a destination (the link reg for
199        // unconditional branches)
200        if (_numSrcRegs > 0) {
201            printReg(ss, _srcRegIdx[0]);
202            ss << ",";
203        }
204        else if (_numDestRegs > 0) {
205            printReg(ss, _destRegIdx[0]);
206            ss << ",";
207        }
208
209#ifdef SS_COMPATIBLE_DISASSEMBLY
210        if (_numSrcRegs == 0 && _numDestRegs == 0) {
211            printReg(ss, 31);
212            ss << ",";
213        }
214#endif
215
216        Addr target = pc + 4 + disp;
217
218        std::string str;
219        if (symtab && symtab->findSymbol(target, str))
220            ss << str;
221        else
222            ccprintf(ss, "0x%x", target);
223
224        return ss.str();
225    }
226
227    std::string
228    Jump::generateDisassembly(Addr pc, const SymbolTable *symtab) const
229    {
230        std::stringstream ss;
231
232        ccprintf(ss, "%-10s ", mnemonic);
233
234#ifdef SS_COMPATIBLE_DISASSEMBLY
235        if (_numDestRegs == 0) {
236            printReg(ss, 31);
237            ss << ",";
238        }
239#endif
240
241        if (_numDestRegs > 0) {
242            printReg(ss, _destRegIdx[0]);
243            ss << ",";
244        }
245
246        ccprintf(ss, "(r%d)", RB);
247
248        return ss.str();
249    }
250}};
251
252def format Branch(code,*flags) {{
253    code = 'bool cond;\n\t' + code + '\n'
254
255    #Add Link Code if Link instruction
256    strlen = len(name)
257    if name[strlen-2:] == 'al':
258        code += 'R31 = NPC + 8;\n'
259
260    code += '\nif (cond) NPC = NPC + disp;\n';
261
262    iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
263                        ('IsDirectControl', 'IsCondControl'))
264    header_output = BasicDeclare.subst(iop)
265    decoder_output = BasicConstructor.subst(iop)
266    decode_block = BasicDecode.subst(iop)
267    exec_output = BasicExecute.subst(iop)
268}};
269
270def format BranchLikely(code,*flags) {{
271    code = 'bool cond;\n\t\t\t' + code
272
273    #Add Link Code if Link instruction
274    strlen = len(name)
275    if name[strlen-3:] == 'all':
276        code += 'R31 = NPC + 8;\n'
277
278    code = '\t\t\tif (cond) NPC = NPC + disp;\n';
279
280    iop = InstObjParams(name, Name, 'Branch', CodeBlock(code),
281                        ('IsDirectControl', 'IsCondControl','IsCondDelaySlot'))
282    header_output = BasicDeclare.subst(iop)
283    decoder_output = BasicConstructor.subst(iop)
284    decode_block = BasicDecode.subst(iop)
285    exec_output = BasicExecute.subst(iop)
286}};
287
288def format Unconditional(code,*flags) {{
289    iop = InstObjParams(name, Name, 'Jump', CodeBlock(code),
290                        ('IsIndirectControl', 'IsUncondControl'))
291    header_output = BasicDeclare.subst(iop)
292    decoder_output = BasicConstructor.subst(iop)
293    decode_block = BasicDecode.subst(iop)
294    exec_output = BasicExecute.subst(iop)
295}};
296
297
298
299
300