1/* Disassembler code for Renesas RX.
2   Copyright (C) 2008-2017 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
30#include <setjmp.h>
31
32typedef struct
33{
34  bfd_vma pc;
35  disassemble_info * dis;
36} RX_Data;
37
38struct private
39{
40  OPCODES_SIGJMP_BUF bailout;
41};
42
43static int
44rx_get_byte (void * vdata)
45{
46  bfd_byte buf[1];
47  RX_Data *rx_data = (RX_Data *) vdata;
48  int status;
49
50  status = rx_data->dis->read_memory_func (rx_data->pc,
51					   buf,
52					   1,
53					   rx_data->dis);
54  if (status != 0)
55    {
56      struct private *priv = (struct private *) rx_data->dis->private_data;
57
58      rx_data->dis->memory_error_func (status, rx_data->pc,
59				       rx_data->dis);
60       OPCODES_SIGLONGJMP (priv->bailout, 1);
61    }
62
63  rx_data->pc ++;
64  return buf[0];
65}
66
67static char const * size_names[RX_MAX_SIZE] =
68{
69  "", ".b", ".ub", ".b", ".w", ".uw", ".w", ".a", ".l", "<error>"
70};
71
72static char const * opsize_names[RX_MAX_SIZE] =
73{
74  "", ".b", ".b", ".b", ".w", ".w", ".w", ".a", ".l", "<error>"
75};
76
77static char const * register_names[] =
78{
79  /* general registers */
80  "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
81  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
82  /* control register */
83  "psw", "pc", "usp", "fpsw", NULL, NULL, NULL, NULL,
84  "bpsw", "bpc", "isp", "fintv", "intb", "extb", NULL, NULL,
85  "a0", "a1", NULL, NULL, NULL, NULL, NULL, NULL,
86  NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
87};
88
89static char const * condition_names[] =
90{
91  /* condition codes */
92  "eq", "ne", "c", "nc", "gtu", "leu", "pz", "n",
93  "ge", "lt", "gt", "le", "o", "no", "<invalid>", "<invalid>"
94};
95
96static const char * flag_names[] =
97{
98  "c", "z", "s", "o", "", "", "", "",
99  "", "", "", "", "", "", "", "",
100  "i", "u", "", "", "", "", "", ""
101  "", "", "", "", "", "", "", "",
102};
103
104int
105print_insn_rx (bfd_vma addr, disassemble_info * dis)
106{
107  int rv;
108  RX_Data rx_data;
109  RX_Opcode_Decoded opcode;
110  const char * s;
111  struct private priv;
112
113  dis->private_data = (PTR) &priv;
114  rx_data.pc = addr;
115  rx_data.dis = dis;
116
117  if (OPCODES_SIGSETJMP (priv.bailout) != 0)
118    {
119      /* Error return.  */
120      return -1;
121    }
122
123  rv = rx_decode_opcode (addr, &opcode, rx_get_byte, &rx_data);
124
125  dis->bytes_per_line = 10;
126
127#define PR (dis->fprintf_func)
128#define PS (dis->stream)
129#define PC(c) PR (PS, "%c", c)
130
131  /* Detect illegal instructions.  */
132  if (opcode.op[0].size == RX_Bad_Size
133      || register_names [opcode.op[0].reg] == NULL
134      || register_names [opcode.op[1].reg] == NULL
135      || register_names [opcode.op[2].reg] == NULL)
136    {
137      bfd_byte buf[10];
138      int i;
139
140      PR (PS, ".byte ");
141      rx_data.dis->read_memory_func (rx_data.pc - rv, buf, rv, rx_data.dis);
142
143      for (i = 0 ; i < rv; i++)
144	PR (PS, "0x%02x ", buf[i]);
145      return rv;
146    }
147
148  for (s = opcode.syntax; *s; s++)
149    {
150      if (*s != '%')
151	{
152	  PC (*s);
153	}
154      else
155	{
156	  RX_Opcode_Operand * oper;
157	  int do_size = 0;
158	  int do_hex = 0;
159	  int do_addr = 0;
160
161	  s ++;
162
163	  if (*s == 'S')
164	    {
165	      do_size = 1;
166	      s++;
167	    }
168	  if (*s == 'x')
169	    {
170	      do_hex = 1;
171	      s++;
172	    }
173	  if (*s == 'a')
174	    {
175	      do_addr = 1;
176	      s++;
177	    }
178
179	  switch (*s)
180	    {
181	    case '%':
182	      PC ('%');
183	      break;
184
185	    case 's':
186	      PR (PS, "%s", opsize_names[opcode.size]);
187	      break;
188
189	    case '0':
190	    case '1':
191	    case '2':
192	      oper = opcode.op + *s - '0';
193	      if (do_size)
194		{
195		  if (oper->type == RX_Operand_Indirect || oper->type == RX_Operand_Zero_Indirect)
196		    PR (PS, "%s", size_names[oper->size]);
197		}
198	      else
199		switch (oper->type)
200		  {
201		  case RX_Operand_Immediate:
202		    if (do_addr)
203		      dis->print_address_func (oper->addend, dis);
204		    else if (do_hex
205			     || oper->addend > 999
206			     || oper->addend < -999)
207		      PR (PS, "%#x", oper->addend);
208		    else
209		      PR (PS, "%d", oper->addend);
210		    break;
211		  case RX_Operand_Register:
212		  case RX_Operand_TwoReg:
213		    PR (PS, "%s", register_names[oper->reg]);
214		    break;
215		  case RX_Operand_Indirect:
216		    PR (PS, "%d[%s]", oper->addend, register_names[oper->reg]);
217		    break;
218		  case RX_Operand_Zero_Indirect:
219		    PR (PS, "[%s]", register_names[oper->reg]);
220		    break;
221		  case RX_Operand_Postinc:
222		    PR (PS, "[%s+]", register_names[oper->reg]);
223		    break;
224		  case RX_Operand_Predec:
225		    PR (PS, "[-%s]", register_names[oper->reg]);
226		    break;
227		  case RX_Operand_Condition:
228		    PR (PS, "%s", condition_names[oper->reg]);
229		    break;
230		  case RX_Operand_Flag:
231		    PR (PS, "%s", flag_names[oper->reg]);
232		    break;
233		  default:
234		    PR (PS, "[???]");
235		    break;
236		  }
237	    }
238	}
239    }
240
241  return rv;
242}
243