1/* Disassemble h8500 instructions.
2   Copyright (C) 1993-2017 Free Software Foundation, Inc.
3
4   This file is part of the GNU opcodes library.
5
6   This library is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3, or (at your option)
9   any later version.
10
11   It is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
14   License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
19   MA 02110-1301, USA.  */
20
21#include "sysdep.h"
22#include <stdio.h>
23
24#define DISASSEMBLER_TABLE
25#define DEFINE_TABLE
26
27#include "h8500-opc.h"
28#include "dis-asm.h"
29#include "opintl.h"
30
31/* Maximum length of an instruction.  */
32#define MAXLEN 8
33
34#include <setjmp.h>
35
36struct private
37{
38  /* Points to first byte not fetched.  */
39  bfd_byte *max_fetched;
40  bfd_byte the_buffer[MAXLEN];
41  bfd_vma insn_start;
42  OPCODES_SIGJMP_BUF bailout;
43};
44
45/* Make sure that bytes from INFO->PRIVATE_DATA->BUFFER (inclusive)
46   to ADDR (exclusive) are valid.  Returns 1 for success, longjmps
47   on error.  */
48#define FETCH_DATA(info, addr) \
49  ((addr) <= ((struct private *)(info->private_data))->max_fetched \
50   ? 1 : fetch_data ((info), (addr)))
51
52static int
53fetch_data (struct disassemble_info *info, bfd_byte *addr)
54{
55  int status;
56  struct private *priv = (struct private *) info->private_data;
57  bfd_vma start = priv->insn_start + (priv->max_fetched - priv->the_buffer);
58
59  status = (*info->read_memory_func) (start,
60				      priv->max_fetched,
61				      addr - priv->max_fetched,
62				      info);
63  if (status != 0)
64    {
65      (*info->memory_error_func) (status, start, info);
66      OPCODES_SIGLONGJMP (priv->bailout, 1);
67    }
68  else
69    priv->max_fetched = addr;
70  return 1;
71}
72
73static char *crname[] = { "sr", "ccr", "*", "br", "ep", "dp", "*", "tp" };
74
75int
76print_insn_h8500 (bfd_vma addr, disassemble_info *info)
77{
78  const h8500_opcode_info *opcode;
79  void *stream = info->stream;
80  fprintf_ftype func = info->fprintf_func;
81  struct private priv;
82  bfd_byte *buffer = priv.the_buffer;
83
84  info->private_data = (PTR) & priv;
85  priv.max_fetched = priv.the_buffer;
86  priv.insn_start = addr;
87  if (OPCODES_SIGSETJMP (priv.bailout) != 0)
88    /* Error return.  */
89    return -1;
90
91  /* Run down the table to find the one which matches.  */
92  for (opcode = h8500_table; opcode->name; opcode++)
93    {
94      int byte;
95      int rn = 0;
96      int rd = 0;
97      int rs = 0;
98      int disp = 0;
99      int abs_val = 0;
100      int imm = 0;
101      int pcrel = 0;
102      int qim = 0;
103      int i;
104      int cr = 0;
105
106      for (byte = 0; byte < opcode->length; byte++)
107	{
108	  FETCH_DATA (info, buffer + byte + 1);
109	  if ((buffer[byte] & opcode->bytes[byte].mask)
110	      != (opcode->bytes[byte].contents))
111	    goto next;
112
113	  else
114	    {
115	      /* Extract any info parts.  */
116	      switch (opcode->bytes[byte].insert)
117		{
118		case 0:
119		case FP:
120		  break;
121		default:
122		  /* xgettext:c-format */
123		  func (stream, _("can't cope with insert %d\n"),
124			opcode->bytes[byte].insert);
125		  break;
126		case RN:
127		  rn = buffer[byte] & 0x7;
128		  break;
129		case RS:
130		  rs = buffer[byte] & 0x7;
131		  break;
132		case CRB:
133		  cr = buffer[byte] & 0x7;
134		  if (cr == 0)
135		    goto next;
136		  break;
137		case CRW:
138		  cr = buffer[byte] & 0x7;
139		  if (cr != 0)
140		    goto next;
141		  break;
142		case DISP16:
143		  FETCH_DATA (info, buffer + byte + 2);
144		  disp = (buffer[byte] << 8) | (buffer[byte + 1]);
145		  break;
146		case FPIND_D8:
147		case DISP8:
148		  disp = ((char) (buffer[byte]));
149		  break;
150		case RD:
151		case RDIND:
152		  rd = buffer[byte] & 0x7;
153		  break;
154		case ABS24:
155		  FETCH_DATA (info, buffer + byte + 3);
156		  abs_val =
157		    (buffer[byte] << 16)
158		    | (buffer[byte + 1] << 8)
159		    | (buffer[byte + 2]);
160		  break;
161		case ABS16:
162		  FETCH_DATA (info, buffer + byte + 2);
163		  abs_val = (buffer[byte] << 8) | (buffer[byte + 1]);
164		  break;
165		case ABS8:
166		  abs_val = (buffer[byte]);
167		  break;
168		case IMM16:
169		  FETCH_DATA (info, buffer + byte + 2);
170		  imm = (buffer[byte] << 8) | (buffer[byte + 1]);
171		  break;
172		case IMM4:
173		  imm = (buffer[byte]) & 0xf;
174		  break;
175		case IMM8:
176		case RLIST:
177		  imm = (buffer[byte]);
178		  break;
179		case PCREL16:
180		  FETCH_DATA (info, buffer + byte + 2);
181		  pcrel = (buffer[byte] << 8) | (buffer[byte + 1]);
182		  break;
183		case PCREL8:
184		  pcrel = (buffer[byte]);
185		  break;
186		case QIM:
187		  switch (buffer[byte] & 0x7)
188		    {
189		    case 0:
190		      qim = 1;
191		      break;
192		    case 1:
193		      qim = 2;
194		      break;
195		    case 4:
196		      qim = -1;
197		      break;
198		    case 5:
199		      qim = -2;
200		      break;
201		    }
202		  break;
203
204		}
205	    }
206	}
207      /* We get here when all the masks have passed so we can output
208	 the operands.  */
209      FETCH_DATA (info, buffer + opcode->length);
210      (func) (stream, "%s\t", opcode->name);
211      for (i = 0; i < opcode->nargs; i++)
212	{
213	  if (i)
214	    (func) (stream, ",");
215	  switch (opcode->arg_type[i])
216	    {
217	    case FP:
218	      func (stream, "fp");
219	      break;
220	    case RNIND_D16:
221	      func (stream, "@(0x%x:16,r%d)", disp, rn);
222	      break;
223	    case RNIND_D8:
224	      func (stream, "@(0x%x:8 (%d),r%d)", disp & 0xff, disp, rn);
225	      break;
226	    case RDIND_D16:
227	      func (stream, "@(0x%x:16,r%d)", disp, rd);
228	      break;
229	    case RDIND_D8:
230	      func (stream, "@(0x%x:8 (%d), r%d)", disp & 0xff, disp, rd);
231	      break;
232	    case FPIND_D8:
233	      func (stream, "@(0x%x:8 (%d), fp)", disp & 0xff, disp);
234	      break;
235	    case CRB:
236	    case CRW:
237	      func (stream, "%s", crname[cr]);
238	      break;
239	    case RN:
240	      func (stream, "r%d", rn);
241	      break;
242	    case RD:
243	      func (stream, "r%d", rd);
244	      break;
245	    case RS:
246	      func (stream, "r%d", rs);
247	      break;
248	    case RNDEC:
249	      func (stream, "@-r%d", rn);
250	      break;
251	    case RNINC:
252	      func (stream, "@r%d+", rn);
253	      break;
254	    case RNIND:
255	      func (stream, "@r%d", rn);
256	      break;
257	    case RDIND:
258	      func (stream, "@r%d", rd);
259	      break;
260	    case SPINC:
261	      func (stream, "@sp+");
262	      break;
263	    case SPDEC:
264	      func (stream, "@-sp");
265	      break;
266	    case ABS24:
267	      func (stream, "@0x%0x:24", abs_val);
268	      break;
269	    case ABS16:
270	      func (stream, "@0x%0x:16", abs_val & 0xffff);
271	      break;
272	    case ABS8:
273	      func (stream, "@0x%0x:8", abs_val & 0xff);
274	      break;
275	    case IMM16:
276	      func (stream, "#0x%0x:16", imm & 0xffff);
277	      break;
278	    case RLIST:
279	      {
280		int j;
281		int nc = 0;
282
283		func (stream, "(");
284		for (j = 0; j < 8; j++)
285		  {
286		    if (imm & (1 << j))
287		      {
288			func (stream, "r%d", j);
289			if (nc)
290			  func (stream, ",");
291			nc = 1;
292		      }
293		  }
294		func (stream, ")");
295	      }
296	      break;
297	    case IMM8:
298	      func (stream, "#0x%0x:8", imm & 0xff);
299	      break;
300	    case PCREL16:
301	      func (stream, "0x%0x:16",
302		    (int)(pcrel + addr + opcode->length) & 0xffff);
303	      break;
304	    case PCREL8:
305	      func (stream, "#0x%0x:8",
306		    (int)((char) pcrel + addr + opcode->length) & 0xffff);
307	      break;
308	    case QIM:
309	      func (stream, "#%d:q", qim);
310	      break;
311	    case IMM4:
312	      func (stream, "#%d:4", imm);
313	      break;
314	    }
315	}
316      return opcode->length;
317    next:
318      ;
319    }
320
321  /* Couldn't understand anything.  */
322  /* xgettext:c-format */
323  func (stream, _("%02x\t\t*unknown*"), buffer[0]);
324  return 1;
325}
326