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