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