xref: /netbsd-src/external/gpl3/binutils/dist/opcodes/microblaze-dis.c (revision cb63e24e8d6aae7ddac1859a9015f48b1d8bd90e)
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