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