1ed0d50c3Schristos /* xtensa-dis.c.  Disassembly functions for Xtensa.
2*b88e3e88Schristos    Copyright (C) 2003-2020 Free Software Foundation, Inc.
3ed0d50c3Schristos    Contributed by Bob Wilson at Tensilica, Inc. (bwilson@tensilica.com)
4ed0d50c3Schristos 
5ed0d50c3Schristos    This file is part of the GNU opcodes library.
6ed0d50c3Schristos 
7ed0d50c3Schristos    This library is free software; you can redistribute it and/or modify
8ed0d50c3Schristos    it under the terms of the GNU General Public License as published by
9ed0d50c3Schristos    the Free Software Foundation; either version 3, or (at your option)
10ed0d50c3Schristos    any later version.
11ed0d50c3Schristos 
12ed0d50c3Schristos    It is distributed in the hope that it will be useful, but WITHOUT
13ed0d50c3Schristos    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14ed0d50c3Schristos    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15ed0d50c3Schristos    License for more details.
16ed0d50c3Schristos 
17ed0d50c3Schristos    You should have received a copy of the GNU General Public License
18ed0d50c3Schristos    along with this file; see the file COPYING.  If not, write to the
19ed0d50c3Schristos    Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston,
20ed0d50c3Schristos    MA 02110-1301, USA.  */
21ed0d50c3Schristos 
22ed0d50c3Schristos #include "sysdep.h"
23ed0d50c3Schristos #include <stdlib.h>
24ed0d50c3Schristos #include <stdio.h>
25ed0d50c3Schristos #include <sys/types.h>
26ed0d50c3Schristos #include <string.h>
27ed0d50c3Schristos #include "xtensa-isa.h"
28ed0d50c3Schristos #include "ansidecl.h"
29ed0d50c3Schristos #include "libiberty.h"
3006324dcfSchristos #include "bfd.h"
3106324dcfSchristos #include "elf/xtensa.h"
3206324dcfSchristos #include "disassemble.h"
33ed0d50c3Schristos 
34ed0d50c3Schristos #include <setjmp.h>
35ed0d50c3Schristos 
36ed0d50c3Schristos extern xtensa_isa xtensa_default_isa;
37ed0d50c3Schristos 
38ed0d50c3Schristos #ifndef MAX
39ed0d50c3Schristos #define MAX(a,b) (a > b ? a : b)
40ed0d50c3Schristos #endif
41ed0d50c3Schristos 
42ed0d50c3Schristos int show_raw_fields;
43ed0d50c3Schristos 
44ed0d50c3Schristos struct dis_private
45ed0d50c3Schristos {
46ed0d50c3Schristos   bfd_byte *byte_buf;
47ed0d50c3Schristos   OPCODES_SIGJMP_BUF bailout;
4806324dcfSchristos   /* Persistent fields, valid for last_section only.  */
4906324dcfSchristos   asection *last_section;
5006324dcfSchristos   property_table_entry *insn_table_entries;
5106324dcfSchristos   int insn_table_entry_count;
5206324dcfSchristos   /* Cached property table search position.  */
5306324dcfSchristos   bfd_vma insn_table_cur_addr;
5406324dcfSchristos   int insn_table_cur_idx;
55ed0d50c3Schristos };
56ed0d50c3Schristos 
5706324dcfSchristos static void
xtensa_coalesce_insn_tables(struct dis_private * priv)5806324dcfSchristos xtensa_coalesce_insn_tables (struct dis_private *priv)
5906324dcfSchristos {
6006324dcfSchristos   const int mask = ~(XTENSA_PROP_DATA | XTENSA_PROP_NO_TRANSFORM);
6106324dcfSchristos   int count = priv->insn_table_entry_count;
6206324dcfSchristos   int i, j;
6306324dcfSchristos 
6406324dcfSchristos   /* Loop over all entries, combining adjacent ones that differ only in
6506324dcfSchristos      the flag bits XTENSA_PROP_DATA and XTENSA_PROP_NO_TRANSFORM.  */
6606324dcfSchristos 
6706324dcfSchristos   for (i = j = 0; j < count; ++i)
6806324dcfSchristos     {
6906324dcfSchristos       property_table_entry *entry = priv->insn_table_entries + i;
7006324dcfSchristos 
7106324dcfSchristos       *entry = priv->insn_table_entries[j];
7206324dcfSchristos 
7306324dcfSchristos       for (++j; j < count; ++j)
7406324dcfSchristos 	{
7506324dcfSchristos 	  property_table_entry *next = priv->insn_table_entries + j;
7606324dcfSchristos 	  int fill = xtensa_compute_fill_extra_space (entry);
7706324dcfSchristos 	  int size = entry->size + fill;
7806324dcfSchristos 
7906324dcfSchristos 	  if (entry->address + size == next->address)
8006324dcfSchristos 	    {
8106324dcfSchristos 	      int entry_flags = entry->flags & mask;
8206324dcfSchristos 	      int next_flags = next->flags & mask;
8306324dcfSchristos 
8406324dcfSchristos 	      if (next_flags == entry_flags)
8506324dcfSchristos 		entry->size = next->address - entry->address + next->size;
8606324dcfSchristos 	      else
8706324dcfSchristos 		break;
8806324dcfSchristos 	    }
8906324dcfSchristos 	  else
9006324dcfSchristos 	    {
9106324dcfSchristos 	      break;
9206324dcfSchristos 	    }
9306324dcfSchristos 	}
9406324dcfSchristos     }
9506324dcfSchristos   priv->insn_table_entry_count = i;
9606324dcfSchristos }
9706324dcfSchristos 
9806324dcfSchristos static property_table_entry *
xtensa_find_table_entry(bfd_vma memaddr,struct disassemble_info * info)9906324dcfSchristos xtensa_find_table_entry (bfd_vma memaddr, struct disassemble_info *info)
10006324dcfSchristos {
10106324dcfSchristos   struct dis_private *priv = (struct dis_private *) info->private_data;
10206324dcfSchristos   int i;
10306324dcfSchristos 
10406324dcfSchristos   if (priv->insn_table_entries == NULL
10506324dcfSchristos       || priv->insn_table_entry_count < 0)
10606324dcfSchristos     return NULL;
10706324dcfSchristos 
10806324dcfSchristos   if (memaddr < priv->insn_table_cur_addr)
10906324dcfSchristos     priv->insn_table_cur_idx = 0;
11006324dcfSchristos 
11106324dcfSchristos   for (i = priv->insn_table_cur_idx; i < priv->insn_table_entry_count; ++i)
11206324dcfSchristos     {
11306324dcfSchristos       property_table_entry *block = priv->insn_table_entries + i;
11406324dcfSchristos 
11506324dcfSchristos       if (block->size != 0)
11606324dcfSchristos 	{
11706324dcfSchristos 	  if ((memaddr >= block->address
11806324dcfSchristos 	       && memaddr < block->address + block->size)
11906324dcfSchristos 	      || memaddr < block->address)
12006324dcfSchristos 	    {
12106324dcfSchristos 	      priv->insn_table_cur_addr = memaddr;
12206324dcfSchristos 	      priv->insn_table_cur_idx = i;
12306324dcfSchristos 	      return block;
12406324dcfSchristos 	    }
12506324dcfSchristos 	}
12606324dcfSchristos     }
12706324dcfSchristos   return NULL;
12806324dcfSchristos }
12906324dcfSchristos 
13006324dcfSchristos /* Check whether an instruction crosses an instruction block boundary
13106324dcfSchristos    (according to property tables).
13206324dcfSchristos    If it does, return 0 (doesn't fit), else return 1.  */
13306324dcfSchristos 
13406324dcfSchristos static int
xtensa_instruction_fits(bfd_vma memaddr,int size,property_table_entry * insn_block)13506324dcfSchristos xtensa_instruction_fits (bfd_vma memaddr, int size,
13606324dcfSchristos 			 property_table_entry *insn_block)
13706324dcfSchristos {
13806324dcfSchristos   unsigned max_size;
13906324dcfSchristos 
14006324dcfSchristos   /* If no property table info, assume it fits.  */
14106324dcfSchristos   if (insn_block == NULL || size <= 0)
14206324dcfSchristos     return 1;
14306324dcfSchristos 
14406324dcfSchristos   /* If too high, limit nextstop by the next insn address.  */
14506324dcfSchristos   if (insn_block->address > memaddr)
14606324dcfSchristos     {
14706324dcfSchristos       /* memaddr is not in an instruction block, but is followed by one.  */
14806324dcfSchristos       max_size = insn_block->address - memaddr;
14906324dcfSchristos     }
15006324dcfSchristos   else
15106324dcfSchristos     {
15206324dcfSchristos       /* memaddr is in an instruction block, go no further than the end.  */
15306324dcfSchristos       max_size = insn_block->address + insn_block->size - memaddr;
15406324dcfSchristos     }
15506324dcfSchristos 
15606324dcfSchristos   /* Crossing a boundary, doesn't "fit".  */
15706324dcfSchristos   if ((unsigned)size > max_size)
15806324dcfSchristos     return 0;
15906324dcfSchristos   return 1;
16006324dcfSchristos }
161ed0d50c3Schristos 
162ed0d50c3Schristos static int
fetch_data(struct disassemble_info * info,bfd_vma memaddr)163ed0d50c3Schristos fetch_data (struct disassemble_info *info, bfd_vma memaddr)
164ed0d50c3Schristos {
165ed0d50c3Schristos   int length, status = 0;
166ed0d50c3Schristos   struct dis_private *priv = (struct dis_private *) info->private_data;
167ed0d50c3Schristos   int insn_size = xtensa_isa_maxlength (xtensa_default_isa);
168ed0d50c3Schristos 
16906324dcfSchristos   insn_size = MAX (insn_size, 4);
17006324dcfSchristos 
171ed0d50c3Schristos   /* Read the maximum instruction size, padding with zeros if we go past
172ed0d50c3Schristos      the end of the text section.  This code will automatically adjust
173ed0d50c3Schristos      length when we hit the end of the buffer.  */
174ed0d50c3Schristos 
175ed0d50c3Schristos   memset (priv->byte_buf, 0, insn_size);
176ed0d50c3Schristos   for (length = insn_size; length > 0; length--)
177ed0d50c3Schristos     {
178ed0d50c3Schristos       status = (*info->read_memory_func) (memaddr, priv->byte_buf, length,
179ed0d50c3Schristos 					  info);
180ed0d50c3Schristos       if (status == 0)
181ed0d50c3Schristos 	return length;
182ed0d50c3Schristos     }
183ed0d50c3Schristos   (*info->memory_error_func) (status, memaddr, info);
184ed0d50c3Schristos   OPCODES_SIGLONGJMP (priv->bailout, 1);
185ed0d50c3Schristos   /*NOTREACHED*/
186ed0d50c3Schristos }
187ed0d50c3Schristos 
188ed0d50c3Schristos 
189ed0d50c3Schristos static void
print_xtensa_operand(bfd_vma memaddr,struct disassemble_info * info,xtensa_opcode opc,int opnd,unsigned operand_val)190ed0d50c3Schristos print_xtensa_operand (bfd_vma memaddr,
191ed0d50c3Schristos 		      struct disassemble_info *info,
192ed0d50c3Schristos 		      xtensa_opcode opc,
193ed0d50c3Schristos 		      int opnd,
194ed0d50c3Schristos 		      unsigned operand_val)
195ed0d50c3Schristos {
196ed0d50c3Schristos   xtensa_isa isa = xtensa_default_isa;
197ed0d50c3Schristos   int signed_operand_val;
198ed0d50c3Schristos 
199ed0d50c3Schristos   if (show_raw_fields)
200ed0d50c3Schristos     {
201ed0d50c3Schristos       if (operand_val < 0xa)
202ed0d50c3Schristos 	(*info->fprintf_func) (info->stream, "%u", operand_val);
203ed0d50c3Schristos       else
204ed0d50c3Schristos 	(*info->fprintf_func) (info->stream, "0x%x", operand_val);
205ed0d50c3Schristos       return;
206ed0d50c3Schristos     }
207ed0d50c3Schristos 
208ed0d50c3Schristos   (void) xtensa_operand_decode (isa, opc, opnd, &operand_val);
209ed0d50c3Schristos   signed_operand_val = (int) operand_val;
210ed0d50c3Schristos 
211ed0d50c3Schristos   if (xtensa_operand_is_register (isa, opc, opnd) == 0)
212ed0d50c3Schristos     {
213ed0d50c3Schristos       if (xtensa_operand_is_PCrelative (isa, opc, opnd) == 1)
214ed0d50c3Schristos 	{
215ed0d50c3Schristos 	  (void) xtensa_operand_undo_reloc (isa, opc, opnd,
216ed0d50c3Schristos 					    &operand_val, memaddr);
217ed0d50c3Schristos 	  info->target = operand_val;
218ed0d50c3Schristos 	  (*info->print_address_func) (info->target, info);
219ed0d50c3Schristos 	}
220ed0d50c3Schristos       else
221ed0d50c3Schristos 	{
222ed0d50c3Schristos 	  if ((signed_operand_val > -256) && (signed_operand_val < 256))
223ed0d50c3Schristos 	    (*info->fprintf_func) (info->stream, "%d", signed_operand_val);
224ed0d50c3Schristos 	  else
225ed0d50c3Schristos 	    (*info->fprintf_func) (info->stream, "0x%x", signed_operand_val);
226ed0d50c3Schristos 	}
227ed0d50c3Schristos     }
228ed0d50c3Schristos   else
229ed0d50c3Schristos     {
230ed0d50c3Schristos       int i = 1;
231ed0d50c3Schristos       xtensa_regfile opnd_rf = xtensa_operand_regfile (isa, opc, opnd);
232ed0d50c3Schristos       (*info->fprintf_func) (info->stream, "%s%u",
233ed0d50c3Schristos 			     xtensa_regfile_shortname (isa, opnd_rf),
234ed0d50c3Schristos 			     operand_val);
235ed0d50c3Schristos       while (i < xtensa_operand_num_regs (isa, opc, opnd))
236ed0d50c3Schristos 	{
237ed0d50c3Schristos 	  operand_val++;
238ed0d50c3Schristos 	  (*info->fprintf_func) (info->stream, ":%s%u",
239ed0d50c3Schristos 				 xtensa_regfile_shortname (isa, opnd_rf),
240ed0d50c3Schristos 				 operand_val);
241ed0d50c3Schristos 	  i++;
242ed0d50c3Schristos 	}
243ed0d50c3Schristos     }
244ed0d50c3Schristos }
245ed0d50c3Schristos 
246ed0d50c3Schristos 
247ed0d50c3Schristos /* Print the Xtensa instruction at address MEMADDR on info->stream.
248ed0d50c3Schristos    Returns length of the instruction in bytes.  */
249ed0d50c3Schristos 
250ed0d50c3Schristos int
print_insn_xtensa(bfd_vma memaddr,struct disassemble_info * info)251ed0d50c3Schristos print_insn_xtensa (bfd_vma memaddr, struct disassemble_info *info)
252ed0d50c3Schristos {
253ed0d50c3Schristos   unsigned operand_val;
254ed0d50c3Schristos   int bytes_fetched, size, maxsize, i, n, noperands, nslots;
255ed0d50c3Schristos   xtensa_isa isa;
256ed0d50c3Schristos   xtensa_opcode opc;
257ed0d50c3Schristos   xtensa_format fmt;
25806324dcfSchristos   static struct dis_private priv;
259ed0d50c3Schristos   static bfd_byte *byte_buf = NULL;
260ed0d50c3Schristos   static xtensa_insnbuf insn_buffer = NULL;
261ed0d50c3Schristos   static xtensa_insnbuf slot_buffer = NULL;
262ed0d50c3Schristos   int first, first_slot, valid_insn;
26306324dcfSchristos   property_table_entry *insn_block;
264ed0d50c3Schristos 
265ed0d50c3Schristos   if (!xtensa_default_isa)
266ed0d50c3Schristos     xtensa_default_isa = xtensa_isa_init (0, 0);
267ed0d50c3Schristos 
268ed0d50c3Schristos   info->target = 0;
269ed0d50c3Schristos   maxsize = xtensa_isa_maxlength (xtensa_default_isa);
270ed0d50c3Schristos 
271ed0d50c3Schristos   /* Set bytes_per_line to control the amount of whitespace between the hex
272ed0d50c3Schristos      values and the opcode.  For Xtensa, we always print one "chunk" and we
273ed0d50c3Schristos      vary bytes_per_chunk to determine how many bytes to print.  (objdump
274ed0d50c3Schristos      would apparently prefer that we set bytes_per_chunk to 1 and vary
275ed0d50c3Schristos      bytes_per_line but that makes it hard to fit 64-bit instructions on
276ed0d50c3Schristos      an 80-column screen.)  The value of bytes_per_line here is not exactly
277ed0d50c3Schristos      right, because objdump adds an extra space for each chunk so that the
278ed0d50c3Schristos      amount of whitespace depends on the chunk size.  Oh well, it's good
279ed0d50c3Schristos      enough....  Note that we set the minimum size to 4 to accomodate
280ed0d50c3Schristos      literal pools.  */
281ed0d50c3Schristos   info->bytes_per_line = MAX (maxsize, 4);
282ed0d50c3Schristos 
283ed0d50c3Schristos   /* Allocate buffers the first time through.  */
284ed0d50c3Schristos   if (!insn_buffer)
285ed0d50c3Schristos     {
286ed0d50c3Schristos       insn_buffer = xtensa_insnbuf_alloc (xtensa_default_isa);
287ed0d50c3Schristos       slot_buffer = xtensa_insnbuf_alloc (xtensa_default_isa);
288ed0d50c3Schristos       byte_buf = (bfd_byte *) xmalloc (MAX (maxsize, 4));
289ed0d50c3Schristos     }
290ed0d50c3Schristos 
291ed0d50c3Schristos   priv.byte_buf = byte_buf;
292ed0d50c3Schristos 
293ed0d50c3Schristos   info->private_data = (void *) &priv;
29406324dcfSchristos 
29506324dcfSchristos   /* Prepare instruction tables.  */
29606324dcfSchristos 
29706324dcfSchristos   if (info->section != NULL)
29806324dcfSchristos     {
29906324dcfSchristos       asection *section = info->section;
30006324dcfSchristos 
30106324dcfSchristos       if (priv.last_section != section)
30206324dcfSchristos 	{
30306324dcfSchristos 	  bfd *abfd = section->owner;
30406324dcfSchristos 
30506324dcfSchristos 	  if (priv.last_section != NULL)
30606324dcfSchristos 	    {
30706324dcfSchristos 	      /* Reset insn_table_entries.  */
30806324dcfSchristos 	      priv.insn_table_entry_count = 0;
30906324dcfSchristos 	      if (priv.insn_table_entries)
31006324dcfSchristos 		free (priv.insn_table_entries);
31106324dcfSchristos 	      priv.insn_table_entries = NULL;
31206324dcfSchristos 	    }
31306324dcfSchristos 	  priv.last_section = section;
31406324dcfSchristos 
31506324dcfSchristos 	  /* Read insn_table_entries.  */
31606324dcfSchristos 	  priv.insn_table_entry_count =
31706324dcfSchristos 	    xtensa_read_table_entries (abfd, section,
31806324dcfSchristos 				       &priv.insn_table_entries,
31906324dcfSchristos 				       XTENSA_PROP_SEC_NAME, FALSE);
32006324dcfSchristos 	  if (priv.insn_table_entry_count == 0)
32106324dcfSchristos 	    {
32206324dcfSchristos 	      if (priv.insn_table_entries)
32306324dcfSchristos 		free (priv.insn_table_entries);
32406324dcfSchristos 	      priv.insn_table_entries = NULL;
32506324dcfSchristos 	      /* Backwards compatibility support.  */
32606324dcfSchristos 	      priv.insn_table_entry_count =
32706324dcfSchristos 		xtensa_read_table_entries (abfd, section,
32806324dcfSchristos 					   &priv.insn_table_entries,
32906324dcfSchristos 					   XTENSA_INSN_SEC_NAME, FALSE);
33006324dcfSchristos 	    }
33106324dcfSchristos 	  priv.insn_table_cur_idx = 0;
33206324dcfSchristos 	  xtensa_coalesce_insn_tables (&priv);
33306324dcfSchristos 	}
33406324dcfSchristos       /* Else nothing to do, same section as last time.  */
33506324dcfSchristos     }
33606324dcfSchristos 
337ed0d50c3Schristos   if (OPCODES_SIGSETJMP (priv.bailout) != 0)
338ed0d50c3Schristos       /* Error return.  */
339ed0d50c3Schristos       return -1;
340ed0d50c3Schristos 
34106324dcfSchristos   /* Fetch the maximum size instruction.  */
34206324dcfSchristos   bytes_fetched = fetch_data (info, memaddr);
34306324dcfSchristos 
34406324dcfSchristos   insn_block = xtensa_find_table_entry (memaddr, info);
34506324dcfSchristos 
346ed0d50c3Schristos   /* Don't set "isa" before the setjmp to keep the compiler from griping.  */
347ed0d50c3Schristos   isa = xtensa_default_isa;
348ed0d50c3Schristos   size = 0;
349ed0d50c3Schristos   nslots = 0;
35006324dcfSchristos   valid_insn = 0;
35106324dcfSchristos   fmt = 0;
35206324dcfSchristos   if (!insn_block || (insn_block->flags & XTENSA_PROP_INSN))
35306324dcfSchristos     {
354ed0d50c3Schristos       /* Copy the bytes into the decode buffer.  */
355ed0d50c3Schristos       memset (insn_buffer, 0, (xtensa_insnbuf_size (isa) *
356ed0d50c3Schristos 			       sizeof (xtensa_insnbuf_word)));
35706324dcfSchristos       xtensa_insnbuf_from_chars (isa, insn_buffer, priv.byte_buf,
35806324dcfSchristos 				 bytes_fetched);
359ed0d50c3Schristos 
360ed0d50c3Schristos       fmt = xtensa_format_decode (isa, insn_buffer);
36106324dcfSchristos       if (fmt != XTENSA_UNDEFINED
36206324dcfSchristos 	  && ((size = xtensa_format_length (isa, fmt)) <= bytes_fetched)
36306324dcfSchristos 	  && xtensa_instruction_fits (memaddr, size, insn_block))
364ed0d50c3Schristos 	{
365ed0d50c3Schristos 	  /* Make sure all the opcodes are valid.  */
366ed0d50c3Schristos 	  valid_insn = 1;
367ed0d50c3Schristos 	  nslots = xtensa_format_num_slots (isa, fmt);
368ed0d50c3Schristos 	  for (n = 0; n < nslots; n++)
369ed0d50c3Schristos 	    {
370ed0d50c3Schristos 	      xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer);
371ed0d50c3Schristos 	      if (xtensa_opcode_decode (isa, fmt, n, slot_buffer)
372ed0d50c3Schristos 		  == XTENSA_UNDEFINED)
373ed0d50c3Schristos 		{
374ed0d50c3Schristos 		  valid_insn = 0;
375ed0d50c3Schristos 		  break;
376ed0d50c3Schristos 		}
377ed0d50c3Schristos 	    }
378ed0d50c3Schristos 	}
37906324dcfSchristos     }
380ed0d50c3Schristos 
381ed0d50c3Schristos   if (!valid_insn)
382ed0d50c3Schristos     {
38306324dcfSchristos       if (insn_block && (insn_block->flags & XTENSA_PROP_LITERAL)
38406324dcfSchristos 	  && (memaddr & 3) == 0 && bytes_fetched >= 4)
38506324dcfSchristos 	{
38606324dcfSchristos 	  return 4;
38706324dcfSchristos 	}
38806324dcfSchristos       else
38906324dcfSchristos 	{
390ed0d50c3Schristos 	  (*info->fprintf_func) (info->stream, ".byte %#02x", priv.byte_buf[0]);
391ed0d50c3Schristos 	  return 1;
392ed0d50c3Schristos 	}
39306324dcfSchristos     }
394ed0d50c3Schristos 
395ed0d50c3Schristos   if (nslots > 1)
396ed0d50c3Schristos     (*info->fprintf_func) (info->stream, "{ ");
397ed0d50c3Schristos 
398ed0d50c3Schristos   first_slot = 1;
399ed0d50c3Schristos   for (n = 0; n < nslots; n++)
400ed0d50c3Schristos     {
401ed0d50c3Schristos       if (first_slot)
402ed0d50c3Schristos 	first_slot = 0;
403ed0d50c3Schristos       else
404ed0d50c3Schristos 	(*info->fprintf_func) (info->stream, "; ");
405ed0d50c3Schristos 
406ed0d50c3Schristos       xtensa_format_get_slot (isa, fmt, n, insn_buffer, slot_buffer);
407ed0d50c3Schristos       opc = xtensa_opcode_decode (isa, fmt, n, slot_buffer);
408ed0d50c3Schristos       (*info->fprintf_func) (info->stream, "%s",
409ed0d50c3Schristos 			     xtensa_opcode_name (isa, opc));
410ed0d50c3Schristos 
411ed0d50c3Schristos       /* Print the operands (if any).  */
412ed0d50c3Schristos       noperands = xtensa_opcode_num_operands (isa, opc);
413ed0d50c3Schristos       first = 1;
414ed0d50c3Schristos       for (i = 0; i < noperands; i++)
415ed0d50c3Schristos 	{
416ed0d50c3Schristos 	  if (xtensa_operand_is_visible (isa, opc, i) == 0)
417ed0d50c3Schristos 	    continue;
418ed0d50c3Schristos 	  if (first)
419ed0d50c3Schristos 	    {
420ed0d50c3Schristos 	      (*info->fprintf_func) (info->stream, "\t");
421ed0d50c3Schristos 	      first = 0;
422ed0d50c3Schristos 	    }
423ed0d50c3Schristos 	  else
424ed0d50c3Schristos 	    (*info->fprintf_func) (info->stream, ", ");
425ed0d50c3Schristos 	  (void) xtensa_operand_get_field (isa, opc, i, fmt, n,
426ed0d50c3Schristos 					   slot_buffer, &operand_val);
427ed0d50c3Schristos 
428ed0d50c3Schristos 	  print_xtensa_operand (memaddr, info, opc, i, operand_val);
429ed0d50c3Schristos 	}
430ed0d50c3Schristos     }
431ed0d50c3Schristos 
432ed0d50c3Schristos   if (nslots > 1)
433ed0d50c3Schristos     (*info->fprintf_func) (info->stream, " }");
434ed0d50c3Schristos 
435ed0d50c3Schristos   info->bytes_per_chunk = size;
436ed0d50c3Schristos   info->display_endian = info->endian;
437ed0d50c3Schristos 
438ed0d50c3Schristos   return size;
439ed0d50c3Schristos }
440ed0d50c3Schristos 
441