1 /* Disassembler code for Renesas RX.
2    Copyright (C) 2008-2021 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 
34 typedef struct
35 {
36   bfd_vma pc;
37   disassemble_info * dis;
38 } RX_Data;
39 
40 struct private
41 {
42   OPCODES_SIGJMP_BUF bailout;
43 };
44 
45 static int
rx_get_byte(void * vdata)46 rx_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 
69 static char const * size_names[RX_MAX_SIZE] =
70 {
71   "", ".b", ".ub", ".b", ".w", ".uw", ".w", ".a", ".l", "", "<error>"
72 };
73 
74 static char const * opsize_names[RX_MAX_SIZE] =
75 {
76   "", ".b", ".b", ".b", ".w", ".w", ".w", ".a", ".l", ".d", "<error>"
77 };
78 
79 static 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 
91 static 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 
98 static const char * flag_names[] =
99 {
100   "c", "z", "s", "o", "", "", "", "",
101   "", "", "", "", "", "", "", "",
102   "i", "u", "", "", "", "", "", "",
103   "", "", "", "", "", "", "", ""
104 };
105 
106 static 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 
112 static 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 
118 static 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 
124 static const char * double_control_register_names[] =
125 {
126   "dpsw", "dcmr", "decnt", "depc"
127 };
128 
129 static const char * double_condition_names[] =
130 {
131   "", "un", "eq", "", "lt", "", "le"
132 };
133 
134 static inline const char *
get_register_name(unsigned int reg)135 get_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 
142 static inline const char *
get_condition_name(unsigned int cond)143 get_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 
150 static inline const char *
get_flag_name(unsigned int flag)151 get_flag_name (unsigned int flag)
152 {
153   if (flag < ARRAY_SIZE (flag_names))
154     return flag_names[flag];
155   return _("<invalid flag>");
156 }
157 
158 static inline const char *
get_double_register_name(unsigned int reg)159 get_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 
166 static inline const char *
get_double_register_high_name(unsigned int reg)167 get_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 
174 static inline const char *
get_double_register_low_name(unsigned int reg)175 get_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 
182 static inline const char *
get_double_control_register_name(unsigned int reg)183 get_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 
190 static inline const char *
get_double_condition_name(unsigned int cond)191 get_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 
198 static inline const char *
get_opsize_name(unsigned int opsize)199 get_opsize_name (unsigned int opsize)
200 {
201   if (opsize < ARRAY_SIZE (opsize_names))
202     return opsize_names[opsize];
203   return _("<invalid opsize>");
204 }
205 
206 static inline const char *
get_size_name(unsigned int size)207 get_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 
215 int
print_insn_rx(bfd_vma addr,disassemble_info * dis)216 print_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 = (PTR) &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