1 /* Disassembler code for Renesas RX.
2    Copyright (C) 2008-2024 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 = &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