1be9ac0eaSchristos /* Disassemble Xilinx microblaze instructions.
2be9ac0eaSchristos
3*cb63e24eSchristos Copyright (C) 2009-2024 Free Software Foundation, Inc.
4be9ac0eaSchristos
5be9ac0eaSchristos This file is part of the GNU opcodes library.
6be9ac0eaSchristos
7be9ac0eaSchristos This library is free software; you can redistribute it and/or modify
8be9ac0eaSchristos it under the terms of the GNU General Public License as published by
9be9ac0eaSchristos the Free Software Foundation; either version 3, or (at your option)
10be9ac0eaSchristos any later version.
11be9ac0eaSchristos
12be9ac0eaSchristos It is distributed in the hope that it will be useful, but WITHOUT
13be9ac0eaSchristos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14be9ac0eaSchristos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15be9ac0eaSchristos License for more details.
16be9ac0eaSchristos
17be9ac0eaSchristos You should have received a copy of the GNU General Public License
18be9ac0eaSchristos along with this file; see the file COPYING. If not, write to the
19be9ac0eaSchristos Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
20be9ac0eaSchristos MA 02110-1301, USA. */
21be9ac0eaSchristos
22be9ac0eaSchristos
23be9ac0eaSchristos #include "sysdep.h"
24be9ac0eaSchristos #define STATIC_TABLE
25be9ac0eaSchristos #define DEFINE_TABLE
26be9ac0eaSchristos
27fc4f4269Schristos #include "disassemble.h"
28be9ac0eaSchristos #include <strings.h>
29be9ac0eaSchristos #include "microblaze-opc.h"
30be9ac0eaSchristos #include "microblaze-dis.h"
31be9ac0eaSchristos
326f4ced0bSchristos #define get_field_rd(buf, instr) get_field (buf, instr, RD_MASK, RD_LOW)
336f4ced0bSchristos #define get_field_r1(buf, instr) get_field (buf, instr, RA_MASK, RA_LOW)
346f4ced0bSchristos #define get_field_r2(buf, instr) get_field (buf, instr, RB_MASK, RB_LOW)
35be9ac0eaSchristos #define get_int_field_imm(instr) ((instr & IMM_MASK) >> IMM_LOW)
36be9ac0eaSchristos #define get_int_field_r1(instr) ((instr & RA_MASK) >> RA_LOW)
37be9ac0eaSchristos
38*cb63e24eSchristos #define NUM_STRBUFS 4
396f4ced0bSchristos #define STRBUF_SIZE 25
40be9ac0eaSchristos
416f4ced0bSchristos struct string_buf
42be9ac0eaSchristos {
436f4ced0bSchristos unsigned int which;
446f4ced0bSchristos char str[NUM_STRBUFS][STRBUF_SIZE];
456f4ced0bSchristos };
46be9ac0eaSchristos
476f4ced0bSchristos static inline char *
strbuf(struct string_buf * buf)486f4ced0bSchristos strbuf (struct string_buf *buf)
496f4ced0bSchristos {
506f4ced0bSchristos #ifdef ENABLE_CHECKING
516f4ced0bSchristos if (buf->which >= NUM_STRBUFS)
526f4ced0bSchristos abort ();
536f4ced0bSchristos #endif
546f4ced0bSchristos return buf->str[buf->which++];
55be9ac0eaSchristos }
56be9ac0eaSchristos
57be9ac0eaSchristos static char *
get_field(struct string_buf * buf,long instr,long mask,unsigned short low)586f4ced0bSchristos get_field (struct string_buf *buf, long instr, long mask, unsigned short low)
59be9ac0eaSchristos {
606f4ced0bSchristos char *p = strbuf (buf);
61be9ac0eaSchristos
626f4ced0bSchristos sprintf (p, "%s%d", register_prefix, (int)((instr & mask) >> low));
636f4ced0bSchristos return p;
64be9ac0eaSchristos }
65be9ac0eaSchristos
66be9ac0eaSchristos static char *
get_field_imm(struct string_buf * buf,long instr)676f4ced0bSchristos get_field_imm (struct string_buf *buf, long instr)
68be9ac0eaSchristos {
696f4ced0bSchristos char *p = strbuf (buf);
70be9ac0eaSchristos
716f4ced0bSchristos sprintf (p, "%d", (short)((instr & IMM_MASK) >> IMM_LOW));
726f4ced0bSchristos return p;
73be9ac0eaSchristos }
74be9ac0eaSchristos
75be9ac0eaSchristos static char *
get_field_imm5(struct string_buf * buf,long instr)766f4ced0bSchristos get_field_imm5 (struct string_buf *buf, long instr)
779573673dSchristos {
786f4ced0bSchristos char *p = strbuf (buf);
799573673dSchristos
806f4ced0bSchristos sprintf (p, "%d", (short)((instr & IMM5_MASK) >> IMM_LOW));
816f4ced0bSchristos return p;
829573673dSchristos }
839573673dSchristos
849573673dSchristos static char *
get_field_imm5_mbar(struct string_buf * buf,long instr)856f4ced0bSchristos get_field_imm5_mbar (struct string_buf *buf, long instr)
86be9ac0eaSchristos {
876f4ced0bSchristos char *p = strbuf (buf);
88be9ac0eaSchristos
896f4ced0bSchristos sprintf (p, "%d", (short)((instr & IMM5_MBAR_MASK) >> IMM_MBAR));
906f4ced0bSchristos return p;
916f4ced0bSchristos }
926f4ced0bSchristos
936f4ced0bSchristos static char *
get_field_immw(struct string_buf * buf,long instr)94*cb63e24eSchristos get_field_immw (struct string_buf *buf, long instr)
95*cb63e24eSchristos {
96*cb63e24eSchristos char *p = strbuf (buf);
97*cb63e24eSchristos
98*cb63e24eSchristos if (instr & 0x00004000)
99*cb63e24eSchristos sprintf (p, "%d", (short)(((instr & IMM5_WIDTH_MASK)
100*cb63e24eSchristos >> IMM_WIDTH_LOW))); /* bsefi */
101*cb63e24eSchristos else
102*cb63e24eSchristos sprintf (p, "%d", (short)(((instr & IMM5_WIDTH_MASK) >>
103*cb63e24eSchristos IMM_WIDTH_LOW) - ((instr & IMM5_MASK) >>
104*cb63e24eSchristos IMM_LOW) + 1)); /* bsifi */
105*cb63e24eSchristos return p;
106*cb63e24eSchristos }
107*cb63e24eSchristos
108*cb63e24eSchristos static char *
get_field_rfsl(struct string_buf * buf,long instr)1096f4ced0bSchristos get_field_rfsl (struct string_buf *buf, long instr)
1106f4ced0bSchristos {
1116f4ced0bSchristos char *p = strbuf (buf);
1126f4ced0bSchristos
1136f4ced0bSchristos sprintf (p, "%s%d", fsl_register_prefix,
114be9ac0eaSchristos (short)((instr & RFSL_MASK) >> IMM_LOW));
1156f4ced0bSchristos return p;
116be9ac0eaSchristos }
117be9ac0eaSchristos
118be9ac0eaSchristos static char *
get_field_imm15(struct string_buf * buf,long instr)1196f4ced0bSchristos get_field_imm15 (struct string_buf *buf, long instr)
120be9ac0eaSchristos {
1216f4ced0bSchristos char *p = strbuf (buf);
122be9ac0eaSchristos
1236f4ced0bSchristos sprintf (p, "%d", (short)((instr & IMM15_MASK) >> IMM_LOW));
1246f4ced0bSchristos return p;
125be9ac0eaSchristos }
126be9ac0eaSchristos
127be9ac0eaSchristos static char *
get_field_special(struct string_buf * buf,long instr,const struct op_code_struct * op)1286f4ced0bSchristos get_field_special (struct string_buf *buf, long instr,
1294f645668Schristos const struct op_code_struct *op)
130be9ac0eaSchristos {
1316f4ced0bSchristos char *p = strbuf (buf);
1326f4ced0bSchristos char *spr;
133be9ac0eaSchristos
134be9ac0eaSchristos switch ((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask))
135be9ac0eaSchristos {
136be9ac0eaSchristos case REG_MSR_MASK :
1376f4ced0bSchristos spr = "msr";
138be9ac0eaSchristos break;
139be9ac0eaSchristos case REG_PC_MASK :
1406f4ced0bSchristos spr = "pc";
141be9ac0eaSchristos break;
142be9ac0eaSchristos case REG_EAR_MASK :
1436f4ced0bSchristos spr = "ear";
144be9ac0eaSchristos break;
145be9ac0eaSchristos case REG_ESR_MASK :
1466f4ced0bSchristos spr = "esr";
147be9ac0eaSchristos break;
148be9ac0eaSchristos case REG_FSR_MASK :
1496f4ced0bSchristos spr = "fsr";
150be9ac0eaSchristos break;
151be9ac0eaSchristos case REG_BTR_MASK :
1526f4ced0bSchristos spr = "btr";
153be9ac0eaSchristos break;
154be9ac0eaSchristos case REG_EDR_MASK :
1556f4ced0bSchristos spr = "edr";
156be9ac0eaSchristos break;
157be9ac0eaSchristos case REG_PID_MASK :
1586f4ced0bSchristos spr = "pid";
159be9ac0eaSchristos break;
160be9ac0eaSchristos case REG_ZPR_MASK :
1616f4ced0bSchristos spr = "zpr";
162be9ac0eaSchristos break;
163be9ac0eaSchristos case REG_TLBX_MASK :
1646f4ced0bSchristos spr = "tlbx";
165be9ac0eaSchristos break;
166be9ac0eaSchristos case REG_TLBLO_MASK :
1676f4ced0bSchristos spr = "tlblo";
168be9ac0eaSchristos break;
169be9ac0eaSchristos case REG_TLBHI_MASK :
1706f4ced0bSchristos spr = "tlbhi";
171be9ac0eaSchristos break;
172be9ac0eaSchristos case REG_TLBSX_MASK :
1736f4ced0bSchristos spr = "tlbsx";
174be9ac0eaSchristos break;
1759573673dSchristos case REG_SHR_MASK :
1766f4ced0bSchristos spr = "shr";
1779573673dSchristos break;
1789573673dSchristos case REG_SLR_MASK :
1796f4ced0bSchristos spr = "slr";
1809573673dSchristos break;
181be9ac0eaSchristos default :
182be9ac0eaSchristos if (((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) & 0xE000)
183be9ac0eaSchristos == REG_PVR_MASK)
184be9ac0eaSchristos {
1856f4ced0bSchristos sprintf (p, "%spvr%d", register_prefix,
186be9ac0eaSchristos (unsigned short)(((instr & IMM_MASK) >> IMM_LOW)
187be9ac0eaSchristos ^ op->immval_mask) ^ REG_PVR_MASK);
1886f4ced0bSchristos return p;
189be9ac0eaSchristos }
190be9ac0eaSchristos else
1916f4ced0bSchristos spr = "pc";
192be9ac0eaSchristos break;
193be9ac0eaSchristos }
194be9ac0eaSchristos
1956f4ced0bSchristos sprintf (p, "%s%s", register_prefix, spr);
1966f4ced0bSchristos return p;
197be9ac0eaSchristos }
198be9ac0eaSchristos
199be9ac0eaSchristos static unsigned long
read_insn_microblaze(bfd_vma memaddr,struct disassemble_info * info,const struct op_code_struct ** opr)200be9ac0eaSchristos read_insn_microblaze (bfd_vma memaddr,
201be9ac0eaSchristos struct disassemble_info *info,
2024f645668Schristos const struct op_code_struct **opr)
203be9ac0eaSchristos {
204be9ac0eaSchristos unsigned char ibytes[4];
205be9ac0eaSchristos int status;
2064f645668Schristos const struct op_code_struct *op;
207be9ac0eaSchristos unsigned long inst;
208be9ac0eaSchristos
209be9ac0eaSchristos status = info->read_memory_func (memaddr, ibytes, 4, info);
210be9ac0eaSchristos
211be9ac0eaSchristos if (status != 0)
212be9ac0eaSchristos {
213be9ac0eaSchristos info->memory_error_func (status, memaddr, info);
214be9ac0eaSchristos return 0;
215be9ac0eaSchristos }
216be9ac0eaSchristos
217be9ac0eaSchristos if (info->endian == BFD_ENDIAN_BIG)
2186f4ced0bSchristos inst = (((unsigned) ibytes[0] << 24) | (ibytes[1] << 16)
2196f4ced0bSchristos | (ibytes[2] << 8) | ibytes[3]);
220be9ac0eaSchristos else if (info->endian == BFD_ENDIAN_LITTLE)
2216f4ced0bSchristos inst = (((unsigned) ibytes[3] << 24) | (ibytes[2] << 16)
2226f4ced0bSchristos | (ibytes[1] << 8) | ibytes[0]);
223be9ac0eaSchristos else
224be9ac0eaSchristos abort ();
225be9ac0eaSchristos
226be9ac0eaSchristos /* Just a linear search of the table. */
2274f645668Schristos for (op = microblaze_opcodes; op->name != 0; op ++)
228be9ac0eaSchristos if (op->bit_sequence == (inst & op->opcode_mask))
229be9ac0eaSchristos break;
230be9ac0eaSchristos
231be9ac0eaSchristos *opr = op;
232be9ac0eaSchristos return inst;
233be9ac0eaSchristos }
234be9ac0eaSchristos
235be9ac0eaSchristos
236be9ac0eaSchristos int
print_insn_microblaze(bfd_vma memaddr,struct disassemble_info * info)237be9ac0eaSchristos print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info)
238be9ac0eaSchristos {
239be9ac0eaSchristos fprintf_ftype print_func = info->fprintf_func;
240be9ac0eaSchristos void *stream = info->stream;
241be9ac0eaSchristos unsigned long inst, prev_inst;
2424f645668Schristos const struct op_code_struct *op, *pop;
243be9ac0eaSchristos int immval = 0;
2444f645668Schristos bool immfound = false;
245be9ac0eaSchristos static bfd_vma prev_insn_addr = -1; /* Init the prev insn addr. */
246be9ac0eaSchristos static int prev_insn_vma = -1; /* Init the prev insn vma. */
247be9ac0eaSchristos int curr_insn_vma = info->buffer_vma;
2486f4ced0bSchristos struct string_buf buf;
249be9ac0eaSchristos
2506f4ced0bSchristos buf.which = 0;
251be9ac0eaSchristos info->bytes_per_chunk = 4;
252be9ac0eaSchristos
253be9ac0eaSchristos inst = read_insn_microblaze (memaddr, info, &op);
254be9ac0eaSchristos if (inst == 0)
255be9ac0eaSchristos return -1;
256be9ac0eaSchristos
257be9ac0eaSchristos if (prev_insn_vma == curr_insn_vma)
258be9ac0eaSchristos {
259be9ac0eaSchristos if (memaddr-(info->bytes_per_chunk) == prev_insn_addr)
260be9ac0eaSchristos {
261be9ac0eaSchristos prev_inst = read_insn_microblaze (prev_insn_addr, info, &pop);
262be9ac0eaSchristos if (prev_inst == 0)
263be9ac0eaSchristos return -1;
264be9ac0eaSchristos if (pop->instr == imm)
265be9ac0eaSchristos {
266be9ac0eaSchristos immval = (get_int_field_imm (prev_inst) << 16) & 0xffff0000;
2674f645668Schristos immfound = true;
268be9ac0eaSchristos }
269be9ac0eaSchristos else
270be9ac0eaSchristos {
271be9ac0eaSchristos immval = 0;
2724f645668Schristos immfound = false;
273be9ac0eaSchristos }
274be9ac0eaSchristos }
275be9ac0eaSchristos }
276be9ac0eaSchristos
277be9ac0eaSchristos /* Make curr insn as prev insn. */
278be9ac0eaSchristos prev_insn_addr = memaddr;
279be9ac0eaSchristos prev_insn_vma = curr_insn_vma;
280be9ac0eaSchristos
281be9ac0eaSchristos if (op->name == NULL)
282*cb63e24eSchristos print_func (stream, ".long 0x%04x", (unsigned int) inst);
283be9ac0eaSchristos else
284be9ac0eaSchristos {
285be9ac0eaSchristos print_func (stream, "%s", op->name);
286be9ac0eaSchristos
287be9ac0eaSchristos switch (op->inst_type)
288be9ac0eaSchristos {
289be9ac0eaSchristos case INST_TYPE_RD_R1_R2:
2906f4ced0bSchristos print_func (stream, "\t%s, %s, %s", get_field_rd (&buf, inst),
2916f4ced0bSchristos get_field_r1 (&buf, inst), get_field_r2 (&buf, inst));
292be9ac0eaSchristos break;
293be9ac0eaSchristos case INST_TYPE_RD_R1_IMM:
2946f4ced0bSchristos print_func (stream, "\t%s, %s, %s", get_field_rd (&buf, inst),
2956f4ced0bSchristos get_field_r1 (&buf, inst), get_field_imm (&buf, inst));
296be9ac0eaSchristos if (info->print_address_func && get_int_field_r1 (inst) == 0
297be9ac0eaSchristos && info->symbol_at_address_func)
298be9ac0eaSchristos {
299be9ac0eaSchristos if (immfound)
300be9ac0eaSchristos immval |= (get_int_field_imm (inst) & 0x0000ffff);
301be9ac0eaSchristos else
302be9ac0eaSchristos {
303be9ac0eaSchristos immval = get_int_field_imm (inst);
304be9ac0eaSchristos if (immval & 0x8000)
305be9ac0eaSchristos immval |= 0xFFFF0000;
306be9ac0eaSchristos }
307be9ac0eaSchristos if (immval > 0 && info->symbol_at_address_func (immval, info))
308be9ac0eaSchristos {
309be9ac0eaSchristos print_func (stream, "\t// ");
310be9ac0eaSchristos info->print_address_func (immval, info);
311be9ac0eaSchristos }
312be9ac0eaSchristos }
313be9ac0eaSchristos break;
314be9ac0eaSchristos case INST_TYPE_RD_R1_IMM5:
3156f4ced0bSchristos print_func (stream, "\t%s, %s, %s", get_field_rd (&buf, inst),
3166f4ced0bSchristos get_field_r1 (&buf, inst), get_field_imm5 (&buf, inst));
317be9ac0eaSchristos break;
318be9ac0eaSchristos case INST_TYPE_RD_RFSL:
3196f4ced0bSchristos print_func (stream, "\t%s, %s", get_field_rd (&buf, inst),
3206f4ced0bSchristos get_field_rfsl (&buf, inst));
321be9ac0eaSchristos break;
322be9ac0eaSchristos case INST_TYPE_R1_RFSL:
3236f4ced0bSchristos print_func (stream, "\t%s, %s", get_field_r1 (&buf, inst),
3246f4ced0bSchristos get_field_rfsl (&buf, inst));
325be9ac0eaSchristos break;
326be9ac0eaSchristos case INST_TYPE_RD_SPECIAL:
3276f4ced0bSchristos print_func (stream, "\t%s, %s", get_field_rd (&buf, inst),
3286f4ced0bSchristos get_field_special (&buf, inst, op));
329be9ac0eaSchristos break;
330be9ac0eaSchristos case INST_TYPE_SPECIAL_R1:
3316f4ced0bSchristos print_func (stream, "\t%s, %s", get_field_special (&buf, inst, op),
3326f4ced0bSchristos get_field_r1 (&buf, inst));
333be9ac0eaSchristos break;
334be9ac0eaSchristos case INST_TYPE_RD_R1:
3356f4ced0bSchristos print_func (stream, "\t%s, %s", get_field_rd (&buf, inst),
3366f4ced0bSchristos get_field_r1 (&buf, inst));
337be9ac0eaSchristos break;
338be9ac0eaSchristos case INST_TYPE_R1_R2:
3396f4ced0bSchristos print_func (stream, "\t%s, %s", get_field_r1 (&buf, inst),
3406f4ced0bSchristos get_field_r2 (&buf, inst));
341be9ac0eaSchristos break;
342be9ac0eaSchristos case INST_TYPE_R1_IMM:
3436f4ced0bSchristos print_func (stream, "\t%s, %s", get_field_r1 (&buf, inst),
3446f4ced0bSchristos get_field_imm (&buf, inst));
345be9ac0eaSchristos /* The non-pc relative instructions are returns, which shouldn't
346be9ac0eaSchristos have a label printed. */
347be9ac0eaSchristos if (info->print_address_func && op->inst_offset_type == INST_PC_OFFSET
348be9ac0eaSchristos && info->symbol_at_address_func)
349be9ac0eaSchristos {
350be9ac0eaSchristos if (immfound)
351be9ac0eaSchristos immval |= (get_int_field_imm (inst) & 0x0000ffff);
352be9ac0eaSchristos else
353be9ac0eaSchristos {
354be9ac0eaSchristos immval = get_int_field_imm (inst);
355be9ac0eaSchristos if (immval & 0x8000)
356be9ac0eaSchristos immval |= 0xFFFF0000;
357be9ac0eaSchristos }
358be9ac0eaSchristos immval += memaddr;
359be9ac0eaSchristos if (immval > 0 && info->symbol_at_address_func (immval, info))
360be9ac0eaSchristos {
361be9ac0eaSchristos print_func (stream, "\t// ");
362be9ac0eaSchristos info->print_address_func (immval, info);
363be9ac0eaSchristos }
364be9ac0eaSchristos else
365be9ac0eaSchristos {
366be9ac0eaSchristos print_func (stream, "\t\t// ");
367be9ac0eaSchristos print_func (stream, "%x", immval);
368be9ac0eaSchristos }
369be9ac0eaSchristos }
370be9ac0eaSchristos break;
371be9ac0eaSchristos case INST_TYPE_RD_IMM:
3726f4ced0bSchristos print_func (stream, "\t%s, %s", get_field_rd (&buf, inst),
3736f4ced0bSchristos get_field_imm (&buf, inst));
374be9ac0eaSchristos if (info->print_address_func && info->symbol_at_address_func)
375be9ac0eaSchristos {
376be9ac0eaSchristos if (immfound)
377be9ac0eaSchristos immval |= (get_int_field_imm (inst) & 0x0000ffff);
378be9ac0eaSchristos else
379be9ac0eaSchristos {
380be9ac0eaSchristos immval = get_int_field_imm (inst);
381be9ac0eaSchristos if (immval & 0x8000)
382be9ac0eaSchristos immval |= 0xFFFF0000;
383be9ac0eaSchristos }
384be9ac0eaSchristos if (op->inst_offset_type == INST_PC_OFFSET)
385be9ac0eaSchristos immval += (int) memaddr;
386be9ac0eaSchristos if (info->symbol_at_address_func (immval, info))
387be9ac0eaSchristos {
388be9ac0eaSchristos print_func (stream, "\t// ");
389be9ac0eaSchristos info->print_address_func (immval, info);
390be9ac0eaSchristos }
391be9ac0eaSchristos }
392be9ac0eaSchristos break;
393be9ac0eaSchristos case INST_TYPE_IMM:
3946f4ced0bSchristos print_func (stream, "\t%s", get_field_imm (&buf, inst));
395be9ac0eaSchristos if (info->print_address_func && info->symbol_at_address_func
396be9ac0eaSchristos && op->instr != imm)
397be9ac0eaSchristos {
398be9ac0eaSchristos if (immfound)
399be9ac0eaSchristos immval |= (get_int_field_imm (inst) & 0x0000ffff);
400be9ac0eaSchristos else
401be9ac0eaSchristos {
402be9ac0eaSchristos immval = get_int_field_imm (inst);
403be9ac0eaSchristos if (immval & 0x8000)
404be9ac0eaSchristos immval |= 0xFFFF0000;
405be9ac0eaSchristos }
406be9ac0eaSchristos if (op->inst_offset_type == INST_PC_OFFSET)
407be9ac0eaSchristos immval += (int) memaddr;
408be9ac0eaSchristos if (immval > 0 && info->symbol_at_address_func (immval, info))
409be9ac0eaSchristos {
410be9ac0eaSchristos print_func (stream, "\t// ");
411be9ac0eaSchristos info->print_address_func (immval, info);
412be9ac0eaSchristos }
413be9ac0eaSchristos else if (op->inst_offset_type == INST_PC_OFFSET)
414be9ac0eaSchristos {
415be9ac0eaSchristos print_func (stream, "\t\t// ");
416be9ac0eaSchristos print_func (stream, "%x", immval);
417be9ac0eaSchristos }
418be9ac0eaSchristos }
419be9ac0eaSchristos break;
420be9ac0eaSchristos case INST_TYPE_RD_R2:
4216f4ced0bSchristos print_func (stream, "\t%s, %s", get_field_rd (&buf, inst),
4226f4ced0bSchristos get_field_r2 (&buf, inst));
423be9ac0eaSchristos break;
424be9ac0eaSchristos case INST_TYPE_R2:
4256f4ced0bSchristos print_func (stream, "\t%s", get_field_r2 (&buf, inst));
426be9ac0eaSchristos break;
427be9ac0eaSchristos case INST_TYPE_R1:
4286f4ced0bSchristos print_func (stream, "\t%s", get_field_r1 (&buf, inst));
429be9ac0eaSchristos break;
4309573673dSchristos case INST_TYPE_R1_R2_SPECIAL:
4316f4ced0bSchristos print_func (stream, "\t%s, %s", get_field_r1 (&buf, inst),
4326f4ced0bSchristos get_field_r2 (&buf, inst));
433be9ac0eaSchristos break;
434be9ac0eaSchristos case INST_TYPE_RD_IMM15:
4356f4ced0bSchristos print_func (stream, "\t%s, %s", get_field_rd (&buf, inst),
4366f4ced0bSchristos get_field_imm15 (&buf, inst));
437be9ac0eaSchristos break;
4389573673dSchristos /* For mbar insn. */
4399573673dSchristos case INST_TYPE_IMM5:
4406f4ced0bSchristos print_func (stream, "\t%s", get_field_imm5_mbar (&buf, inst));
4419573673dSchristos break;
4429573673dSchristos /* For mbar 16 or sleep insn. */
4439573673dSchristos case INST_TYPE_NONE:
4449573673dSchristos break;
445*cb63e24eSchristos /* For bit field insns. */
446*cb63e24eSchristos case INST_TYPE_RD_R1_IMMW_IMMS:
447*cb63e24eSchristos print_func (stream, "\t%s, %s, %s, %s",
448*cb63e24eSchristos get_field_rd (&buf, inst),
449*cb63e24eSchristos get_field_r1 (&buf, inst),
450*cb63e24eSchristos get_field_immw (&buf, inst),
451*cb63e24eSchristos get_field_imm5 (&buf, inst));
452*cb63e24eSchristos break;
453be9ac0eaSchristos /* For tuqula instruction */
454be9ac0eaSchristos case INST_TYPE_RD:
4556f4ced0bSchristos print_func (stream, "\t%s", get_field_rd (&buf, inst));
456be9ac0eaSchristos break;
457be9ac0eaSchristos case INST_TYPE_RFSL:
4586f4ced0bSchristos print_func (stream, "\t%s", get_field_rfsl (&buf, inst));
459be9ac0eaSchristos break;
460be9ac0eaSchristos default:
461be9ac0eaSchristos /* If the disassembler lags the instruction set. */
4626f4ced0bSchristos print_func (stream, "\tundecoded operands, inst is 0x%04x",
4636f4ced0bSchristos (unsigned int) inst);
464be9ac0eaSchristos break;
465be9ac0eaSchristos }
466be9ac0eaSchristos }
467be9ac0eaSchristos
468be9ac0eaSchristos /* Say how many bytes we consumed. */
469be9ac0eaSchristos return 4;
470be9ac0eaSchristos }
471be9ac0eaSchristos
472be9ac0eaSchristos enum microblaze_instr
get_insn_microblaze(long inst,bool * isunsignedimm,enum microblaze_instr_type * insn_type,short * delay_slots)473be9ac0eaSchristos get_insn_microblaze (long inst,
4744f645668Schristos bool *isunsignedimm,
475be9ac0eaSchristos enum microblaze_instr_type *insn_type,
476be9ac0eaSchristos short *delay_slots)
477be9ac0eaSchristos {
4784f645668Schristos const struct op_code_struct *op;
4794f645668Schristos *isunsignedimm = false;
480be9ac0eaSchristos
481be9ac0eaSchristos /* Just a linear search of the table. */
4824f645668Schristos for (op = microblaze_opcodes; op->name != 0; op ++)
483be9ac0eaSchristos if (op->bit_sequence == (inst & op->opcode_mask))
484be9ac0eaSchristos break;
485be9ac0eaSchristos
486be9ac0eaSchristos if (op->name == 0)
487be9ac0eaSchristos return invalid_inst;
488be9ac0eaSchristos else
489be9ac0eaSchristos {
490be9ac0eaSchristos *isunsignedimm = (op->inst_type == INST_TYPE_RD_R1_UNSIGNED_IMM);
491be9ac0eaSchristos *insn_type = op->instr_type;
492be9ac0eaSchristos *delay_slots = op->delay_slots;
493be9ac0eaSchristos return op->instr;
494be9ac0eaSchristos }
495be9ac0eaSchristos }
496be9ac0eaSchristos
497be9ac0eaSchristos enum microblaze_instr
microblaze_decode_insn(long insn,int * rd,int * ra,int * rb,int * immed)498be9ac0eaSchristos microblaze_decode_insn (long insn, int *rd, int *ra, int *rb, int *immed)
499be9ac0eaSchristos {
500be9ac0eaSchristos enum microblaze_instr op;
5014f645668Schristos bool t1;
502be9ac0eaSchristos enum microblaze_instr_type t2;
503be9ac0eaSchristos short t3;
504be9ac0eaSchristos
505be9ac0eaSchristos op = get_insn_microblaze (insn, &t1, &t2, &t3);
506be9ac0eaSchristos *rd = (insn & RD_MASK) >> RD_LOW;
507be9ac0eaSchristos *ra = (insn & RA_MASK) >> RA_LOW;
508be9ac0eaSchristos *rb = (insn & RB_MASK) >> RB_LOW;
509be9ac0eaSchristos t3 = (insn & IMM_MASK) >> IMM_LOW;
510be9ac0eaSchristos *immed = (int) t3;
511be9ac0eaSchristos return (op);
512be9ac0eaSchristos }
513be9ac0eaSchristos
514be9ac0eaSchristos unsigned long
microblaze_get_target_address(long inst,bool immfound,int immval,long pcval,long r1val,long r2val,bool * targetvalid,bool * unconditionalbranch)5154f645668Schristos microblaze_get_target_address (long inst, bool immfound, int immval,
516be9ac0eaSchristos long pcval, long r1val, long r2val,
5174f645668Schristos bool *targetvalid,
5184f645668Schristos bool *unconditionalbranch)
519be9ac0eaSchristos {
5204f645668Schristos const struct op_code_struct *op;
521be9ac0eaSchristos long targetaddr = 0;
522be9ac0eaSchristos
5234f645668Schristos *unconditionalbranch = false;
524be9ac0eaSchristos /* Just a linear search of the table. */
5254f645668Schristos for (op = microblaze_opcodes; op->name != 0; op ++)
526be9ac0eaSchristos if (op->bit_sequence == (inst & op->opcode_mask))
527be9ac0eaSchristos break;
528be9ac0eaSchristos
529be9ac0eaSchristos if (op->name == 0)
530be9ac0eaSchristos {
5314f645668Schristos *targetvalid = false;
532be9ac0eaSchristos }
533be9ac0eaSchristos else if (op->instr_type == branch_inst)
534be9ac0eaSchristos {
535be9ac0eaSchristos switch (op->inst_type)
536be9ac0eaSchristos {
537be9ac0eaSchristos case INST_TYPE_R2:
5384f645668Schristos *unconditionalbranch = true;
539be9ac0eaSchristos /* Fall through. */
540be9ac0eaSchristos case INST_TYPE_RD_R2:
541be9ac0eaSchristos case INST_TYPE_R1_R2:
542be9ac0eaSchristos targetaddr = r2val;
5434f645668Schristos *targetvalid = true;
544be9ac0eaSchristos if (op->inst_offset_type == INST_PC_OFFSET)
545be9ac0eaSchristos targetaddr += pcval;
546be9ac0eaSchristos break;
547be9ac0eaSchristos case INST_TYPE_IMM:
5484f645668Schristos *unconditionalbranch = true;
549be9ac0eaSchristos /* Fall through. */
550be9ac0eaSchristos case INST_TYPE_RD_IMM:
551be9ac0eaSchristos case INST_TYPE_R1_IMM:
552be9ac0eaSchristos if (immfound)
553be9ac0eaSchristos {
554be9ac0eaSchristos targetaddr = (immval << 16) & 0xffff0000;
555be9ac0eaSchristos targetaddr |= (get_int_field_imm (inst) & 0x0000ffff);
556be9ac0eaSchristos }
557be9ac0eaSchristos else
558be9ac0eaSchristos {
559be9ac0eaSchristos targetaddr = get_int_field_imm (inst);
560be9ac0eaSchristos if (targetaddr & 0x8000)
561be9ac0eaSchristos targetaddr |= 0xFFFF0000;
562be9ac0eaSchristos }
563be9ac0eaSchristos if (op->inst_offset_type == INST_PC_OFFSET)
564be9ac0eaSchristos targetaddr += pcval;
5654f645668Schristos *targetvalid = true;
566be9ac0eaSchristos break;
567be9ac0eaSchristos default:
5684f645668Schristos *targetvalid = false;
569be9ac0eaSchristos break;
570be9ac0eaSchristos }
571be9ac0eaSchristos }
572be9ac0eaSchristos else if (op->instr_type == return_inst)
573be9ac0eaSchristos {
574be9ac0eaSchristos if (immfound)
575be9ac0eaSchristos {
576be9ac0eaSchristos targetaddr = (immval << 16) & 0xffff0000;
577be9ac0eaSchristos targetaddr |= (get_int_field_imm (inst) & 0x0000ffff);
578be9ac0eaSchristos }
579be9ac0eaSchristos else
580be9ac0eaSchristos {
581be9ac0eaSchristos targetaddr = get_int_field_imm (inst);
582be9ac0eaSchristos if (targetaddr & 0x8000)
583be9ac0eaSchristos targetaddr |= 0xFFFF0000;
584be9ac0eaSchristos }
585be9ac0eaSchristos targetaddr += r1val;
5864f645668Schristos *targetvalid = true;
587be9ac0eaSchristos }
588be9ac0eaSchristos else
5894f645668Schristos *targetvalid = false;
590be9ac0eaSchristos return targetaddr;
591be9ac0eaSchristos }
592