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