1230025Sed/* tilepro-dis.c.  Disassembly routines for the TILEPro architecture.
2230025Sed   Copyright (C) 2011-2022 Free Software Foundation, Inc.
3230025Sed
4230025Sed   This file is part of the GNU opcodes library.
5230025Sed
6230025Sed   This program is free software; you can redistribute it and/or modify
7230025Sed   it under the terms of the GNU General Public License as published by
8230025Sed   the Free Software Foundation; either version 3 of the License, or
9230025Sed   (at your option) any later version.
10230025Sed
11230025Sed   This program is distributed in the hope that it will be useful,
12230025Sed   but WITHOUT ANY WARRANTY; without even the implied warranty of
13230025Sed   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14230025Sed   GNU General Public License for more details.
15230025Sed
16230025Sed   You should have received a copy of the GNU General Public License
17230025Sed   along with this program; if not, write to the Free Software
18230025Sed   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19230025Sed   MA 02110-1301, USA.  */
20230025Sed
21230025Sed#include "sysdep.h"
22230025Sed#include <stddef.h>
23230025Sed#include <assert.h>
24230025Sed#include "bfd.h"
25230025Sed#include "elf/tilepro.h"
26230025Sed#include "elf-bfd.h"
27230025Sed#include "disassemble.h"
28230025Sed#include "opcode/tilepro.h"
29230025Sed
30230025Sed
31230025Sed#define TREG_ZERO 63
32230025Sed
33230025Sedstatic int
34230025Sedcontains_insn (tilepro_mnemonic expected_mnemonic,
35230025Sed	       int expected_first_operand,
36230025Sed	       int expected_second_operand,
37230025Sed	       bfd_vma memaddr,
38230025Sed	       int *last_operand_ret,
39230025Sed	       disassemble_info *info)
40230025Sed{
41230025Sed  struct tilepro_decoded_instruction
42230025Sed    decoded[TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE];
43230025Sed  bfd_byte opbuf[TILEPRO_BUNDLE_SIZE_IN_BYTES];
44230025Sed  int i, num_instructions;
45230025Sed
46230025Sed  if ((*info->read_memory_func) (memaddr, opbuf,
47230025Sed				 TILEPRO_BUNDLE_SIZE_IN_BYTES, info) != 0)
48230025Sed    /* If we cannot even read the memory, it obviously does not have the
49230025Sed       instruction for which we are looking. */
50235389Smarius    return 0;
51230025Sed
52230025Sed  /* Parse the instructions in the bundle. */
53230025Sed  num_instructions = parse_insn_tilepro (bfd_getl64 (opbuf), memaddr, decoded);
54235389Smarius
55235389Smarius  for (i = 0; i < num_instructions; i++)
56230025Sed    {
57230025Sed      const struct tilepro_opcode *opcode = decoded[i].opcode;
58230025Sed
59230025Sed      if (opcode->mnemonic != expected_mnemonic)
60230025Sed	continue;
61230025Sed
62230025Sed      if (expected_first_operand != -1
63230025Sed	  && decoded[i].operand_values[0] != expected_first_operand)
64230025Sed	continue;
65230025Sed
66230025Sed      if (expected_second_operand != -1
67230025Sed	  && decoded[i].operand_values[1] != expected_second_operand)
68230025Sed	continue;
69230025Sed
70230025Sed      *last_operand_ret = decoded[i].operand_values[opcode->num_operands - 1];
71230025Sed      return 1;
72230025Sed    }
73230025Sed
74230025Sed  /* No match. */
75230025Sed  return 0;
76230025Sed}
77230025Sed
78230025Sed
79230025Sedint
80230025Sedprint_insn_tilepro (bfd_vma memaddr, disassemble_info *info)
81230025Sed{
82230025Sed  struct tilepro_decoded_instruction
83230025Sed    decoded[TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE];
84230025Sed  bfd_byte opbuf[TILEPRO_BUNDLE_SIZE_IN_BYTES];
85230025Sed  int status, i, num_instructions, num_printed;
86230025Sed  tilepro_mnemonic padding_mnemonic;
87230025Sed
88230025Sed  status = (*info->read_memory_func) (memaddr, opbuf,
89230025Sed                                      TILEPRO_BUNDLE_SIZE_IN_BYTES, info);
90230025Sed  if (status != 0)
91230025Sed    {
92230025Sed      (*info->memory_error_func) (status, memaddr, info);
93230025Sed      return -1;
94230025Sed    }
95230025Sed
96230025Sed  info->bytes_per_line = TILEPRO_BUNDLE_SIZE_IN_BYTES;
97230025Sed  info->bytes_per_chunk = TILEPRO_BUNDLE_SIZE_IN_BYTES;
98230025Sed  info->octets_per_byte = 1;
99230025Sed  info->display_endian = BFD_ENDIAN_LITTLE;
100230025Sed
101230025Sed  /* Parse the instructions in the bundle.  */
102230025Sed  num_instructions = parse_insn_tilepro (bfd_getl64 (opbuf), memaddr, decoded);
103230025Sed
104230025Sed  /* Print the instructions in the bundle.  */
105230025Sed  info->fprintf_func (info->stream, "{ ");
106230025Sed  num_printed = 0;
107230025Sed
108230025Sed  /* Determine which nop opcode is used for padding and should be skipped.  */
109230025Sed  padding_mnemonic = TILEPRO_OPC_FNOP;
110230025Sed  for (i = 0; i < num_instructions; i++)
111230025Sed    {
112230025Sed      if (!decoded[i].opcode->can_bundle)
113230025Sed	{
114230025Sed	  /* Instructions that cannot be bundled are padded out with nops,
115230025Sed	     rather than fnops. Displaying them is always clutter.  */
116230025Sed	  padding_mnemonic = TILEPRO_OPC_NOP;
117230025Sed	  break;
118230025Sed	}
119230025Sed    }
120230025Sed
121230025Sed  for (i = 0; i < num_instructions; i++)
122230025Sed    {
123230025Sed      const struct tilepro_opcode *opcode = decoded[i].opcode;
124230025Sed      const char *name;
125230025Sed      int j;
126230025Sed
127230025Sed      /* Do not print out fnops, unless everything is an fnop, in
128230025Sed	 which case we will print out just the last one.  */
129235389Smarius      if (opcode->mnemonic == padding_mnemonic
130235389Smarius	  && (num_printed > 0 || i + 1 < num_instructions))
131230025Sed	continue;
132230025Sed
133230025Sed      if (num_printed > 0)
134230025Sed	info->fprintf_func (info->stream, " ; ");
135230025Sed      ++num_printed;
136230025Sed
137230025Sed      name = opcode->name;
138230025Sed      if (name == NULL)
139230025Sed	name = "<invalid>";
140230025Sed      info->fprintf_func (info->stream, "%s", name);
141230025Sed
142230025Sed      for (j = 0; j < opcode->num_operands; j++)
143230025Sed	{
144230025Sed	  int num;
145230025Sed	  const struct tilepro_operand *op;
146230025Sed	  const char *spr_name;
147235389Smarius
148235389Smarius	  if (j > 0)
149230025Sed	    info->fprintf_func (info->stream, ",");
150230025Sed	  info->fprintf_func (info->stream, " ");
151230025Sed
152230025Sed	  num = decoded[i].operand_values[j];
153230025Sed
154230025Sed	  op = decoded[i].operands[j];
155230025Sed	  switch (op->type)
156230025Sed	    {
157230025Sed	    case TILEPRO_OP_TYPE_REGISTER:
158230025Sed	      info->fprintf_func (info->stream, "%s",
159230025Sed				  tilepro_register_names[num]);
160230025Sed	      break;
161230025Sed
162230025Sed	    case TILEPRO_OP_TYPE_SPR:
163230025Sed	      spr_name = get_tilepro_spr_name(num);
164230025Sed	      if (spr_name != NULL)
165230025Sed		info->fprintf_func (info->stream, "%s", spr_name);
166230025Sed	      else
167230025Sed		info->fprintf_func (info->stream, "%d", num);
168230025Sed	      break;
169230025Sed
170230025Sed	    case TILEPRO_OP_TYPE_IMMEDIATE:
171230025Sed	      {
172230025Sed		bfd_vma addr = 0;
173230025Sed		int found_addr = 0;
174230025Sed		int addr_piece;
175230025Sed
176230025Sed		switch (opcode->mnemonic)
177230025Sed		  {
178230025Sed		  case TILEPRO_OPC_ADDLI:
179230025Sed		    if (contains_insn (TILEPRO_OPC_AULI,
180230025Sed				       decoded[i].operand_values[1],
181230025Sed				       TREG_ZERO,
182230025Sed				       memaddr - TILEPRO_BUNDLE_SIZE_IN_BYTES,
183230025Sed				       &addr_piece,
184230025Sed				       info))
185230025Sed		      {
186230025Sed			addr = num + (addr_piece << 16);
187230025Sed			found_addr = 1;
188230025Sed		      }
189230025Sed		    break;
190230025Sed
191230025Sed		  case TILEPRO_OPC_AULI:
192230025Sed		    if (contains_insn (TILEPRO_OPC_MOVELI,
193230025Sed				       decoded[i].operand_values[1],
194230025Sed				       -1,
195230025Sed				       memaddr - TILEPRO_BUNDLE_SIZE_IN_BYTES,
196230025Sed				       &addr_piece,
197230025Sed				       info))
198230025Sed		      {
199230025Sed			addr = (num << 16) + addr_piece;
200230025Sed			found_addr = 1;
201230025Sed		      }
202230025Sed		    break;
203230025Sed
204230025Sed		  default:
205230025Sed		    /* Operand does not look like a constructed address.  */
206230025Sed		    break;
207230025Sed		  }
208230025Sed
209230025Sed		info->fprintf_func (info->stream, "%d", num);
210230025Sed
211230025Sed		if (found_addr)
212230025Sed		  {
213230025Sed		    info->fprintf_func (info->stream, " /* ");
214230025Sed		    info->print_address_func (addr, info);
215230025Sed		    info->fprintf_func (info->stream, " */");
216230025Sed		  }
217230025Sed	      }
218230025Sed	      break;
219230025Sed
220230025Sed	    case TILEPRO_OP_TYPE_ADDRESS:
221230025Sed	      info->print_address_func ((bfd_vma)(unsigned int) num, info);
222230025Sed	      break;
223230025Sed
224230025Sed	    default:
225230025Sed	      abort ();
226230025Sed	    }
227230025Sed	}
228230025Sed    }
229230025Sed  info->fprintf_func (info->stream, " }");
230230025Sed
231230025Sed  return TILEPRO_BUNDLE_SIZE_IN_BYTES;
232230025Sed}
233230025Sed