1/* Disassembler code for Renesas RX.
2   Copyright (C) 2008-2022 Free Software Foundation, Inc.
3   Contributed by Red Hat.
4   Written by DJ Delorie.
5
6   This file is part of the GNU opcodes library.
7
8   This library is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 3, or (at your option)
11   any later version.
12
13   It is distributed in the hope that it will be useful, but WITHOUT
14   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
16   License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
21   MA 02110-1301, USA.  */
22
23#include "sysdep.h"
24#include <stdio.h>
25
26#include "bfd.h"
27#include "dis-asm.h"
28#include "opcode/rx.h"
29#include "libiberty.h"
30#include "opintl.h"
31
32#include <setjmp.h>
33
34typedef struct
35{
36  bfd_vma pc;
37  disassemble_info * dis;
38} RX_Data;
39
40struct private
41{
42  OPCODES_SIGJMP_BUF bailout;
43};
44
45static int
46rx_get_byte (void * vdata)
47{
48  bfd_byte buf[1];
49  RX_Data *rx_data = (RX_Data *) vdata;
50  int status;
51
52  status = rx_data->dis->read_memory_func (rx_data->pc,
53					   buf,
54					   1,
55					   rx_data->dis);
56  if (status != 0)
57    {
58      struct private *priv = (struct private *) rx_data->dis->private_data;
59
60      rx_data->dis->memory_error_func (status, rx_data->pc,
61				       rx_data->dis);
62       OPCODES_SIGLONGJMP (priv->bailout, 1);
63    }
64
65  rx_data->pc ++;
66  return buf[0];
67}
68
69static char const * size_names[RX_MAX_SIZE] =
70{
71  "", ".b", ".ub", ".b", ".w", ".uw", ".w", ".a", ".l", "", "<error>"
72};
73
74static char const * opsize_names[RX_MAX_SIZE] =
75{
76  "", ".b", ".b", ".b", ".w", ".w", ".w", ".a", ".l", ".d", "<error>"
77};
78
79static char const * register_names[] =
80{
81  /* General registers.  */
82  "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
83  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
84  /* Control registers.  */
85  "psw", "pc", "usp", "fpsw", NULL, NULL, NULL, NULL,
86  "bpsw", "bpc", "isp", "fintv", "intb", "extb", NULL, NULL,
87  "a0", "a1", NULL, NULL, NULL, NULL, NULL, NULL,
88  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
89};
90
91static char const * condition_names[] =
92{
93  /* Condition codes.  */
94  "eq", "ne", "c", "nc", "gtu", "leu", "pz", "n",
95  "ge", "lt", "gt", "le", "o", "no", "<invalid>", "<invalid>"
96};
97
98static const char * flag_names[] =
99{
100  "c", "z", "s", "o", "", "", "", "",
101  "", "", "", "", "", "", "", "",
102  "i", "u", "", "", "", "", "", "",
103  "", "", "", "", "", "", "", ""
104};
105
106static const char * double_register_names[] =
107{
108  "dr0", "dr1", "dr2", "dr3", "dr4", "dr5", "dr6", "dr7",
109  "dr8", "dr9", "dr10", "dr11", "dr12", "dr13", "dr14", "dr15"
110};
111
112static const char * double_register_high_names[] =
113{
114  "drh0", "drh1", "drh2", "drh3", "drh4", "drh5", "drh6", "drh7",
115  "drh8", "drh9", "drh10", "drh11", "drh12", "drh13", "drh14", "drh15"
116};
117
118static const char * double_register_low_names[] =
119{
120  "drl0", "drl1", "drl2", "drl3", "drl4", "drl5", "drl6", "drl7",
121  "drl8", "drl9", "drl10", "drl11", "drl12", "drl13", "drl14", "drl15"
122};
123
124static const char * double_control_register_names[] =
125{
126  "dpsw", "dcmr", "decnt", "depc"
127};
128
129static const char * double_condition_names[] =
130{
131  "", "un", "eq", "", "lt", "", "le"
132};
133
134static inline const char *
135get_register_name (unsigned int reg)
136{
137  if (reg < ARRAY_SIZE (register_names))
138    return register_names[reg];
139  return _("<invalid register number>");
140}
141
142static inline const char *
143get_condition_name (unsigned int cond)
144{
145  if (cond < ARRAY_SIZE (condition_names))
146    return condition_names[cond];
147  return _("<invalid condition code>");
148}
149
150static inline const char *
151get_flag_name (unsigned int flag)
152{
153  if (flag < ARRAY_SIZE (flag_names))
154    return flag_names[flag];
155  return _("<invalid flag>");
156}
157
158static inline const char *
159get_double_register_name (unsigned int reg)
160{
161  if (reg < ARRAY_SIZE (double_register_names))
162    return double_register_names[reg];
163  return _("<invalid register number>");
164}
165
166static inline const char *
167get_double_register_high_name (unsigned int reg)
168{
169  if (reg < ARRAY_SIZE (double_register_high_names))
170    return double_register_high_names[reg];
171  return _("<invalid register number>");
172}
173
174static inline const char *
175get_double_register_low_name (unsigned int reg)
176{
177  if (reg < ARRAY_SIZE (double_register_low_names))
178    return double_register_low_names[reg];
179  return _("<invalid register number>");
180}
181
182static inline const char *
183get_double_control_register_name (unsigned int reg)
184{
185  if (reg < ARRAY_SIZE (double_control_register_names))
186    return double_control_register_names[reg];
187  return _("<invalid register number>");
188}
189
190static inline const char *
191get_double_condition_name (unsigned int cond)
192{
193  if (cond < ARRAY_SIZE (double_condition_names))
194    return double_condition_names[cond];
195  return _("<invalid condition code>");
196}
197
198static inline const char *
199get_opsize_name (unsigned int opsize)
200{
201  if (opsize < ARRAY_SIZE (opsize_names))
202    return opsize_names[opsize];
203  return _("<invalid opsize>");
204}
205
206static inline const char *
207get_size_name (unsigned int size)
208{
209  if (size < ARRAY_SIZE (size_names))
210    return size_names[size];
211  return _("<invalid size>");
212}
213
214
215int
216print_insn_rx (bfd_vma addr, disassemble_info * dis)
217{
218  int rv;
219  RX_Data rx_data;
220  RX_Opcode_Decoded opcode;
221  const char * s;
222  struct private priv;
223
224  dis->private_data = &priv;
225  rx_data.pc = addr;
226  rx_data.dis = dis;
227
228  if (OPCODES_SIGSETJMP (priv.bailout) != 0)
229    {
230      /* Error return.  */
231      return -1;
232    }
233
234  rv = rx_decode_opcode (addr, &opcode, rx_get_byte, &rx_data);
235
236  dis->bytes_per_line = 10;
237
238#define PR (dis->fprintf_func)
239#define PS (dis->stream)
240#define PC(c) PR (PS, "%c", c)
241
242  /* Detect illegal instructions.  */
243  if (opcode.op[0].size == RX_Bad_Size
244      || register_names [opcode.op[0].reg] == NULL
245      || register_names [opcode.op[1].reg] == NULL
246      || register_names [opcode.op[2].reg] == NULL)
247    {
248      bfd_byte buf[10];
249      int i;
250
251      PR (PS, ".byte ");
252      rx_data.dis->read_memory_func (rx_data.pc - rv, buf, rv, rx_data.dis);
253
254      for (i = 0 ; i < rv; i++)
255	PR (PS, "0x%02x ", buf[i]);
256      return rv;
257    }
258
259  for (s = opcode.syntax; *s; s++)
260    {
261      if (*s != '%')
262	{
263	  PC (*s);
264	}
265      else
266	{
267	  RX_Opcode_Operand * oper;
268	  int do_size = 0;
269	  int do_hex = 0;
270	  int do_addr = 0;
271
272	  s ++;
273
274	  if (*s == 'S')
275	    {
276	      do_size = 1;
277	      s++;
278	    }
279	  if (*s == 'x')
280	    {
281	      do_hex = 1;
282	      s++;
283	    }
284	  if (*s == 'a')
285	    {
286	      do_addr = 1;
287	      s++;
288	    }
289
290	  switch (*s)
291	    {
292	    case '%':
293	      PC ('%');
294	      break;
295
296	    case 's':
297	      PR (PS, "%s", get_opsize_name (opcode.size));
298	      break;
299
300	    case 'b':
301	      s ++;
302	      if (*s == 'f')
303		{
304		  int imm = opcode.op[2].addend;
305		  int slsb, dlsb, width;
306
307		  dlsb = (imm >> 5) & 0x1f;
308		  slsb = (imm & 0x1f);
309		  slsb = (slsb >= 0x10?(slsb ^ 0x1f) + 1:slsb);
310		  slsb = dlsb - slsb;
311		  slsb = (slsb < 0?-slsb:slsb);
312		  width = ((imm >> 10) & 0x1f) - dlsb;
313		  PR (PS, "#%d, #%d, #%d, %s, %s",
314		      slsb, dlsb, width,
315		      get_register_name (opcode.op[1].reg),
316		      get_register_name (opcode.op[0].reg));
317		}
318	      break;
319	    case '0':
320	    case '1':
321	    case '2':
322	      oper = opcode.op + (*s - '0');
323	      if (do_size)
324		{
325		  if (oper->type == RX_Operand_Indirect || oper->type == RX_Operand_Zero_Indirect)
326		    PR (PS, "%s", get_size_name (oper->size));
327		}
328	      else
329		switch (oper->type)
330		  {
331		  case RX_Operand_Immediate:
332		    if (do_addr)
333		      dis->print_address_func (oper->addend, dis);
334		    else if (do_hex
335			     || oper->addend > 999
336			     || oper->addend < -999)
337		      PR (PS, "%#x", oper->addend);
338		    else
339		      PR (PS, "%d", oper->addend);
340		    break;
341		  case RX_Operand_Register:
342		  case RX_Operand_TwoReg:
343		    PR (PS, "%s", get_register_name (oper->reg));
344		    break;
345		  case RX_Operand_Indirect:
346		    PR (PS, "%d[%s]", oper->addend, get_register_name (oper->reg));
347		    break;
348		  case RX_Operand_Zero_Indirect:
349		    PR (PS, "[%s]", get_register_name (oper->reg));
350		    break;
351		  case RX_Operand_Postinc:
352		    PR (PS, "[%s+]", get_register_name (oper->reg));
353		    break;
354		  case RX_Operand_Predec:
355		    PR (PS, "[-%s]", get_register_name (oper->reg));
356		    break;
357		  case RX_Operand_Condition:
358		    PR (PS, "%s", get_condition_name (oper->reg));
359		    break;
360		  case RX_Operand_Flag:
361		    PR (PS, "%s", get_flag_name (oper->reg));
362		    break;
363		  case RX_Operand_DoubleReg:
364		    PR (PS, "%s", get_double_register_name (oper->reg));
365		    break;
366		  case RX_Operand_DoubleRegH:
367		    PR (PS, "%s", get_double_register_high_name (oper->reg));
368		    break;
369		  case RX_Operand_DoubleRegL:
370		    PR (PS, "%s", get_double_register_low_name (oper->reg));
371		    break;
372		  case RX_Operand_DoubleCReg:
373		    PR (PS, "%s", get_double_control_register_name (oper->reg));
374		    break;
375		  case RX_Operand_DoubleCond:
376		    PR (PS, "%s", get_double_condition_name (oper->reg));
377		    break;
378		  default:
379		    PR (PS, "[???]");
380		    break;
381		  }
382	    }
383	}
384    }
385
386  return rv;
387}
388