aboutsummaryrefslogtreecommitdiff
path: root/opcodes/ft32-dis.c
blob: 6c68dea9bc8b357e6e35abc8c1393f5e7780ea72 (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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/* Disassemble ft32 instructions.
   Copyright (C) 2013-2021 Free Software Foundation, Inc.
   Contributed by FTDI (support@ftdichip.com)

   This file is part of the GNU opcodes library.

   This library 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, or (at your option)
   any later version.

   It 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 <stdio.h>
#define STATIC_TABLE
#define DEFINE_TABLE

#include "opcode/ft32.h"
#include "disassemble.h"

extern const ft32_opc_info_t ft32_opc_info[128];

static fprintf_ftype fpr;
static void *stream;

static int
sign_extend (int bit, int value)
{
  int onebit = (1 << bit);
  return (value & (onebit - 1)) - (value & onebit);
}

static void
ft32_opcode1 (unsigned int iword,
	      struct disassemble_info *info)
{
  const ft32_opc_info_t *oo;

  for (oo = ft32_opc_info; oo->name; oo++)
    if ((iword & oo->mask) == oo->bits)
      break;

  if (oo->name)
    {
      int f = oo->fields;
      int imm;

      fpr (stream, "%s", oo->name);
      if (oo->dw)
	fpr (stream, ".%c ", "bsl"[(iword >> FT32_FLD_DW_BIT) & 3]);
      else
	fpr (stream, " ");

      while (f)
	{
	  int lobit = f & -f;
	  if (f & lobit)
	    {
	      switch (lobit)
		{
		case  FT32_FLD_CBCRCV:
		  /* imm is {CB, CV}  */
		  imm = ((iword >> FT32_FLD_CB_BIT) & ((1 << FT32_FLD_CB_SIZ) - 1)) << 4;
		  imm |= ((iword >> FT32_FLD_CV_BIT) & ((1 << FT32_FLD_CV_SIZ) - 1));
		  switch (imm)
		    {
		    case 0x00: fpr (stream, "nz");  break;
		    case 0x01: fpr (stream, "z");   break;
		    case 0x10: fpr (stream, "ae");  break;
		    case 0x11: fpr (stream, "b");   break;
		    case 0x20: fpr (stream, "no");  break;
		    case 0x21: fpr (stream, "o");   break;
		    case 0x30: fpr (stream, "ns");  break;
		    case 0x31: fpr (stream, "s");   break;
		    case 0x40: fpr (stream, "lt");  break;
		    case 0x41: fpr (stream, "gte"); break;
		    case 0x50: fpr (stream, "lte"); break;
		    case 0x51: fpr (stream, "gt");  break;
		    case 0x60: fpr (stream, "be");  break;
		    case 0x61: fpr (stream, "a");   break;
		    default:
		      fpr (stream, "%d,$r30,%d", (imm >> 4), (imm & 1));
		      break;
		    }
		  break;
		case  FT32_FLD_CB:
		  imm = (iword >> FT32_FLD_CB_BIT) & ((1 << FT32_FLD_CB_SIZ) - 1);
		  fpr (stream, "%d", imm);
		  break;
		case  FT32_FLD_R_D:
		  fpr (stream, "$r%d", (iword >> FT32_FLD_R_D_BIT) & 0x1f);
		  break;
		case  FT32_FLD_CR:
		  imm = (iword >> FT32_FLD_CR_BIT) & ((1 << FT32_FLD_CR_SIZ) - 1);
		  fpr (stream, "$r%d", 28 + imm);
		  break;
		case  FT32_FLD_CV:
		  imm = (iword >> FT32_FLD_CV_BIT) & ((1 << FT32_FLD_CV_SIZ) - 1);
		  fpr (stream, "%d", imm);
		  break;
		case  FT32_FLD_R_1:
		  fpr (stream, "$r%d", (iword >> FT32_FLD_R_1_BIT) & 0x1f);
		  break;
		case  FT32_FLD_RIMM:
		  imm = (iword >> FT32_FLD_RIMM_BIT) & ((1 << FT32_FLD_RIMM_SIZ) - 1);
		  if (imm & 0x400)
		    fpr (stream, "%d", sign_extend (9, imm));
		  else
		    fpr (stream, "$r%d", imm & 0x1f);
		  break;
		case  FT32_FLD_R_2:
		  fpr (stream, "$r%d", (iword >> FT32_FLD_R_2_BIT) & 0x1f);
		  break;
		case  FT32_FLD_K20:
		  imm = iword & ((1 << FT32_FLD_K20_SIZ) - 1);
		  fpr (stream, "%d", sign_extend (19, imm));
		  break;
		case  FT32_FLD_PA:
		  imm = (iword & ((1 << FT32_FLD_PA_SIZ) - 1)) << 2;
		  info->print_address_func ((bfd_vma) imm, info);
		  break;
		case  FT32_FLD_AA:
		  imm = iword & ((1 << FT32_FLD_AA_SIZ) - 1);
		  info->print_address_func ((1 << 23) | (bfd_vma) imm, info);
		  break;
		case  FT32_FLD_K16:
		  imm = iword & ((1 << FT32_FLD_K16_SIZ) - 1);
		  fpr (stream, "%d", imm);
		  break;
		case  FT32_FLD_K15:
		  imm = iword & ((1 << FT32_FLD_K15_SIZ) - 1);
		  fpr (stream, "%d", sign_extend (14, imm));
		  break;
		case  FT32_FLD_R_D_POST:
		  fpr (stream, "$r%d", (iword >> FT32_FLD_R_D_BIT) & 0x1f);
		  break;
		case  FT32_FLD_R_1_POST:
		  fpr (stream, "$r%d", (iword >> FT32_FLD_R_1_BIT) & 0x1f);
		  break;
		default:
		  break;
		}
	      f &= ~lobit;
	      if (f)
		fpr (stream, ",");
	    }
	}
    }
  else
    fpr (stream, "!");
}

static void
ft32_opcode (bfd_vma addr ATTRIBUTE_UNUSED,
	     unsigned int iword,
	     struct disassemble_info *info)
{
  unsigned int sc[2];
  if (ft32_decode_shortcode ((unsigned int) addr, iword, sc))
    {
      ft32_opcode1 (sc[0], info);
      fpr (stream, " ; ");
      ft32_opcode1 (sc[1], info);
    }
  else
    ft32_opcode1 (iword, info);
}

int
print_insn_ft32 (bfd_vma addr, struct disassemble_info *info)
{
  int status;
  stream = info->stream;
  bfd_byte buffer[4];
  unsigned int iword;

  fpr = info->fprintf_func;

  if ((status = info->read_memory_func (addr, buffer, 4, info)))
    goto fail;

  iword = bfd_getl32 (buffer);

  fpr (stream, "%08x ", iword);

  ft32_opcode (addr, iword, info);

  return 4;

 fail:
  info->memory_error_func (status, addr, info);
  return -1;
}