1/* Disassemble V850 instructions.
2   Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2005, 2007
3   Free Software Foundation, Inc.
4
5   This file is part of the GNU opcodes library.
6
7   This library is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 3, or (at your option)
10   any later version.
11
12   It is distributed in the hope that it will be useful, but WITHOUT
13   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
15   License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20   MA 02110-1301, USA.  */
21
22
23#include <stdio.h>
24
25#include "sysdep.h"
26#include "opcode/v850.h"
27#include "dis-asm.h"
28#include "opintl.h"
29
30static const char *const v850_reg_names[] =
31{ "r0", "r1", "r2", "sp", "gp", "r5", "r6", "r7",
32  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
33  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
34  "r24", "r25", "r26", "r27", "r28", "r29", "ep", "lp" };
35
36static const char *const v850_sreg_names[] =
37{ "eipc", "eipsw", "fepc", "fepsw", "ecr", "psw", "sr6", "sr7",
38  "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15",
39  "ctpc", "ctpsw", "dbpc", "dbpsw", "ctbp", "sr21", "sr22", "sr23",
40  "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31",
41  "sr16", "sr17", "sr18", "sr19", "sr20", "sr21", "sr22", "sr23",
42  "sr24", "sr25", "sr26", "sr27", "sr28", "sr29", "sr30", "sr31" };
43
44static const char *const v850_cc_names[] =
45{ "v", "c/l", "z", "nh", "s/n", "t", "lt", "le",
46  "nv", "nc/nl", "nz", "h", "ns/p", "sa", "ge", "gt" };
47
48static int
49disassemble (bfd_vma memaddr,
50	     struct disassemble_info * info,
51	     unsigned long insn)
52{
53  struct v850_opcode * op = (struct v850_opcode *) v850_opcodes;
54  const struct v850_operand * operand;
55  int match = 0;
56  int short_op = ((insn & 0x0600) != 0x0600);
57  int bytes_read;
58  int target_processor;
59
60  /* Special case: 32 bit MOV.  */
61  if ((insn & 0xffe0) == 0x0620)
62    short_op = 1;
63
64  bytes_read = short_op ? 2 : 4;
65
66  /* If this is a two byte insn, then mask off the high bits.  */
67  if (short_op)
68    insn &= 0xffff;
69
70  switch (info->mach)
71    {
72    case 0:
73    default:
74      target_processor = PROCESSOR_V850;
75      break;
76
77    case bfd_mach_v850e:
78      target_processor = PROCESSOR_V850E;
79      break;
80
81    case bfd_mach_v850e1:
82      target_processor = PROCESSOR_V850E1;
83      break;
84    }
85
86  /* Find the opcode.  */
87  while (op->name)
88    {
89      if ((op->mask & insn) == op->opcode
90	  && (op->processors & target_processor))
91	{
92	  const unsigned char *opindex_ptr;
93	  unsigned int opnum;
94	  unsigned int memop;
95
96	  match = 1;
97	  (*info->fprintf_func) (info->stream, "%s\t", op->name);
98
99	  memop = op->memop;
100	  /* Now print the operands.
101
102	     MEMOP is the operand number at which a memory
103	     address specification starts, or zero if this
104	     instruction has no memory addresses.
105
106	     A memory address is always two arguments.
107
108	     This information allows us to determine when to
109	     insert commas into the output stream as well as
110	     when to insert disp[reg] expressions onto the
111	     output stream.  */
112
113	  for (opindex_ptr = op->operands, opnum = 1;
114	       *opindex_ptr != 0;
115	       opindex_ptr++, opnum++)
116	    {
117	      long value;
118	      int flag;
119	      int status;
120	      bfd_byte buffer[4];
121
122	      operand = &v850_operands[*opindex_ptr];
123
124	      if (operand->extract)
125		value = (operand->extract) (insn, 0);
126	      else
127		{
128		  if (operand->bits == -1)
129		    value = (insn & operand->shift);
130		  else
131		    value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
132
133		  if (operand->flags & V850_OPERAND_SIGNED)
134		    value = ((long)(value << (32 - operand->bits))
135			     >> (32 - operand->bits));
136		}
137
138	      /* The first operand is always output without any
139		 special handling.
140
141		 For the following arguments:
142
143		   If memop && opnum == memop + 1, then we need '[' since
144		   we're about to output the register used in a memory
145		   reference.
146
147		   If memop && opnum == memop + 2, then we need ']' since
148		   we just finished the register in a memory reference.  We
149		   also need a ',' before this operand.
150
151		   Else we just need a comma.
152
153		   We may need to output a trailing ']' if the last operand
154		   in an instruction is the register for a memory address.
155
156		   The exception (and there's always an exception) is the
157		   "jmp" insn which needs square brackets around it's only
158		   register argument.  */
159
160	           if (memop && opnum == memop + 1)
161		     info->fprintf_func (info->stream, "[");
162		   else if (memop && opnum == memop + 2)
163		     info->fprintf_func (info->stream, "],");
164		   else if (memop == 1 && opnum == 1
165			    && (operand->flags & V850_OPERAND_REG))
166		     info->fprintf_func (info->stream, "[");
167		   else if (opnum > 1)
168		     info->fprintf_func (info->stream, ", ");
169
170	      /* Extract the flags, ignorng ones which
171		 do not effect disassembly output. */
172	      flag = operand->flags;
173	      flag &= ~ V850_OPERAND_SIGNED;
174	      flag &= ~ V850_OPERAND_RELAX;
175	      flag &= - flag;
176
177	      switch (flag)
178		{
179		case V850_OPERAND_REG:
180		  info->fprintf_func (info->stream, "%s", v850_reg_names[value]);
181		  break;
182		case V850_OPERAND_SRG:
183		  info->fprintf_func (info->stream, "%s", v850_sreg_names[value]);
184		  break;
185		case V850_OPERAND_CC:
186		  info->fprintf_func (info->stream, "%s", v850_cc_names[value]);
187		  break;
188		case V850_OPERAND_EP:
189		  info->fprintf_func (info->stream, "ep");
190		  break;
191		default:
192		  info->fprintf_func (info->stream, "%ld", value);
193		  break;
194		case V850_OPERAND_DISP:
195		  {
196		    bfd_vma addr = value + memaddr;
197
198		    /* On the v850 the top 8 bits of an address are used by an
199		       overlay manager.  Thus it may happen that when we are
200		       looking for a symbol to match against an address with
201		       some of its top bits set, the search fails to turn up an
202		       exact match.  In this case we try to find an exact match
203		       against a symbol in the lower address space, and if we
204		       find one, we use that address.   We only do this for
205		       JARL instructions however, as we do not want to
206		       misinterpret branch instructions.  */
207		    if (operand->bits == 22)
208		      {
209			if ( ! info->symbol_at_address_func (addr, info)
210			    && ((addr & 0xFF000000) != 0)
211			    && info->symbol_at_address_func (addr & 0x00FFFFFF, info))
212			  addr &= 0x00FFFFFF;
213		      }
214		    info->print_address_func (addr, info);
215		    break;
216		  }
217
218		case V850E_PUSH_POP:
219		  {
220		    static int list12_regs[32]   = { 30,  0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 };
221		    static int list18_h_regs[32] = { 19, 18, 17, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 30, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 };
222		    static int list18_l_regs[32] = {  3,  2,  1, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 14, 15, 13, 12,  7,  6,  5,  4, 11, 10,  9,  8 };
223		    int *regs;
224		    int i;
225		    unsigned long int mask = 0;
226		    int pc = 0;
227		    int sr = 0;
228
229		    switch (operand->shift)
230		      {
231		      case 0xffe00001: regs = list12_regs; break;
232		      case 0xfff8000f: regs = list18_h_regs; break;
233		      case 0xfff8001f:
234			regs = list18_l_regs;
235			value &= ~0x10;  /* Do not include magic bit.  */
236			  break;
237		      default:
238			/* xgettext:c-format */
239			fprintf (stderr, _("unknown operand shift: %x\n"),
240				 operand->shift);
241			abort ();
242		      }
243
244		    for (i = 0; i < 32; i++)
245		      {
246			if (value & (1 << i))
247			  {
248			    switch (regs[ i ])
249			      {
250			      default: mask |= (1 << regs[ i ]); break;
251				/* xgettext:c-format */
252			      case 0:
253				fprintf (stderr, _("unknown pop reg: %d\n"), i );
254				abort ();
255			      case -1: pc = 1; break;
256			      case -2: sr = 1; break;
257			      }
258			  }
259		      }
260
261		    info->fprintf_func (info->stream, "{");
262
263		    if (mask || pc || sr)
264		      {
265			if (mask)
266			  {
267			    unsigned int bit;
268			    int shown_one = 0;
269
270			    for (bit = 0; bit < 32; bit++)
271			      if (mask & (1 << bit))
272				{
273				  unsigned long int first = bit;
274				  unsigned long int last;
275
276				  if (shown_one)
277				    info->fprintf_func (info->stream, ", ");
278				  else
279				    shown_one = 1;
280
281				  info->fprintf_func (info->stream,
282						      v850_reg_names[first]);
283
284				  for (bit++; bit < 32; bit++)
285				    if ((mask & (1 << bit)) == 0)
286				      break;
287
288				  last = bit;
289
290				  if (last > first + 1)
291				    info->fprintf_func (info->stream, " - %s",
292							v850_reg_names[last - 1]);
293				}
294			  }
295
296			if (pc)
297			  info->fprintf_func (info->stream, "%sPC", mask ? ", " : "");
298			if (sr)
299			  info->fprintf_func (info->stream, "%sSR", (mask || pc) ? ", " : "");
300		      }
301
302		    info->fprintf_func (info->stream, "}");
303		  }
304		break;
305
306		case V850E_IMMEDIATE16:
307		  status = info->read_memory_func (memaddr + bytes_read,
308						   buffer, 2, info);
309		  if (status == 0)
310		    {
311		      bytes_read += 2;
312		      value = bfd_getl16 (buffer);
313
314		      /* If this is a DISPOSE instruction with ff
315			 set to 0x10, then shift value up by 16.  */
316		      if ((insn & 0x001fffc0) == 0x00130780)
317			value <<= 16;
318
319		      info->fprintf_func (info->stream, "0x%lx", value);
320		    }
321		  else
322		    info->memory_error_func (status, memaddr + bytes_read,
323					     info);
324		  break;
325
326		case V850E_IMMEDIATE32:
327		  status = info->read_memory_func (memaddr + bytes_read,
328						   buffer, 4, info);
329		  if (status == 0)
330		    {
331		      bytes_read += 4;
332		      value = bfd_getl32 (buffer);
333		      info->fprintf_func (info->stream, "0x%lx", value);
334		    }
335		  else
336		    info->memory_error_func (status, memaddr + bytes_read,
337					     info);
338		  break;
339		}
340
341	      /* Handle jmp correctly.  */
342	      if (memop == 1 && opnum == 1
343		  && ((operand->flags & V850_OPERAND_REG) != 0))
344		(*info->fprintf_func) (info->stream, "]");
345	    }
346
347	  /* Close any square bracket we left open.  */
348	  if (memop && opnum == memop + 2)
349	    (*info->fprintf_func) (info->stream, "]");
350
351	  /* All done. */
352	  break;
353	}
354      op++;
355    }
356
357  if (!match)
358    {
359      if (short_op)
360	info->fprintf_func (info->stream, ".short\t0x%04lx", insn);
361      else
362	info->fprintf_func (info->stream, ".long\t0x%08lx", insn);
363    }
364
365  return bytes_read;
366}
367
368int
369print_insn_v850 (bfd_vma memaddr, struct disassemble_info * info)
370{
371  int status;
372  bfd_byte buffer[4];
373  unsigned long insn = 0;
374
375  /* First figure out how big the opcode is.  */
376  status = info->read_memory_func (memaddr, buffer, 2, info);
377  if (status == 0)
378    {
379      insn = bfd_getl16 (buffer);
380
381      if (   (insn & 0x0600) == 0x0600
382	  && (insn & 0xffe0) != 0x0620)
383	{
384	  /* If this is a 4 byte insn, read 4 bytes of stuff.  */
385	  status = info->read_memory_func (memaddr, buffer, 4, info);
386
387	  if (status == 0)
388	    insn = bfd_getl32 (buffer);
389	}
390    }
391
392  if (status != 0)
393    {
394      info->memory_error_func (status, memaddr, info);
395      return -1;
396    }
397
398  /* Make sure we tell our caller how many bytes we consumed.  */
399  return disassemble (memaddr, info, insn);
400}
401