summaryrefslogtreecommitdiff
path: root/opcodes/tilegx-dis.c
blob: 0bb60a297ad38ca2968a1744f3b9f6d34196311c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* tilegx-dis.c.  Disassembly routines for the TILE-Gx architecture.
   Copyright (C) 2011-2016 Free Software Foundation, Inc.

   This file is part of the GNU opcodes library.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
   MA 02110-1301, USA.  */

#include "sysdep.h"
#include <stddef.h>
#include <assert.h>
#include "bfd.h"
#include "elf/tilegx.h"
#include "elf-bfd.h"
#include "dis-asm.h"
#include "opcode/tilegx.h"


int
print_insn_tilegx (bfd_vma memaddr, disassemble_info *info)
{
  struct tilegx_decoded_instruction
    decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE];
  bfd_byte opbuf[TILEGX_BUNDLE_SIZE_IN_BYTES];
  int status, i, num_instructions, num_printed;
  tilegx_mnemonic padding_mnemonic;

  status = (*info->read_memory_func) (memaddr, opbuf,
                                      TILEGX_BUNDLE_SIZE_IN_BYTES, info);
  if (status != 0)
    {
      (*info->memory_error_func) (status, memaddr, info);
      return -1;
    }

  info->bytes_per_line = TILEGX_BUNDLE_SIZE_IN_BYTES;
  info->bytes_per_chunk = TILEGX_BUNDLE_SIZE_IN_BYTES;
  info->octets_per_byte = 1;
  info->display_endian = BFD_ENDIAN_LITTLE;

  /* Parse the instructions in the bundle.  */
  num_instructions =
    parse_insn_tilegx (bfd_getl64 (opbuf), memaddr, decoded);

  /* Print the instructions in the bundle.  */
  info->fprintf_func (info->stream, "{ ");
  num_printed = 0;

  /* Determine which nop opcode is used for padding and should be skipped.  */
  padding_mnemonic = TILEGX_OPC_FNOP;
  for (i = 0; i < num_instructions; i++)
    {
      if (!decoded[i].opcode->can_bundle)
	{
	  /* Instructions that cannot be bundled are padded out with nops,
	     rather than fnops. Displaying them is always clutter. */
	  padding_mnemonic = TILEGX_OPC_NOP;
	  break;
	}
    }

  for (i = 0; i < num_instructions; i++)
    {
      const struct tilegx_opcode *opcode = decoded[i].opcode;
      const char *name;
      int j;

      /* Do not print out fnops, unless everything is an fnop, in
	 which case we will print out just the last one. */
      if (opcode->mnemonic == padding_mnemonic
	  && (num_printed > 0 || i + 1 < num_instructions))
	continue;

      if (num_printed > 0)
	info->fprintf_func (info->stream, " ; ");
      ++num_printed;

      name = opcode->name;
      if (name == NULL)
	name = "<invalid>";
      info->fprintf_func (info->stream, "%s", name);

      for (j = 0; j < opcode->num_operands; j++)
	{
	  bfd_vma num;
	  const struct tilegx_operand *op;
	  const char *spr_name;

	  if (j > 0)
	    info->fprintf_func (info->stream, ",");
	  info->fprintf_func (info->stream, " ");

	  num = decoded[i].operand_values[j];

	  op = decoded[i].operands[j];
	  switch (op->type)
	    {
	    case TILEGX_OP_TYPE_REGISTER:
	      info->fprintf_func (info->stream, "%s",
				  tilegx_register_names[(int) num]);
	      break;
	    case TILEGX_OP_TYPE_SPR:
	      spr_name = get_tilegx_spr_name (num);
	      if (spr_name != NULL)
		info->fprintf_func (info->stream, "%s", spr_name);
	      else
		info->fprintf_func (info->stream, "%d", (int)num);
	      break;
	    case TILEGX_OP_TYPE_IMMEDIATE:
	      info->fprintf_func (info->stream, "%d", (int)num);
	      break;
	    case TILEGX_OP_TYPE_ADDRESS:
	      info->print_address_func (num, info);
	      break;
	    default:
	      abort ();
	    }
	}
    }
  info->fprintf_func (info->stream, " }");

  return TILEGX_BUNDLE_SIZE_IN_BYTES;
}