xref: /netbsd-src/external/gpl3/binutils/dist/opcodes/v850-dis.c (revision 413d532bcc3f62d122e56d92e13ac64825a40baf)
1 /* Disassemble V850 instructions.
2    Copyright 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2005, 2007, 2010,
3    2012  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 "sysdep.h"
24 #include <stdio.h>
25 #include "opcode/v850.h"
26 #include "dis-asm.h"
27 #include "opintl.h"
28 
29 static const char *const v850_reg_names[] =
30 {
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 };
36 
37 static const char *const v850_sreg_names[] =
38 {
39   "eipc/vip/mpm", "eipsw/mpc", "fepc/tid", "fepsw/ppa", "ecr/vmecr", "psw/vmtid",
40   "sr6/fpsr/vmadr/dcc", "sr7/fpepc/dc0",
41   "sr8/fpst/vpecr/dcv1", "sr9/fpcc/vptid", "sr10/fpcfg/vpadr/spal", "sr11/spau",
42   "sr12/vdecr/ipa0l", "eiic/vdtid/ipa0u", "feic/ipa1l", "dbic/ipa1u",
43   "ctpc/ipa2l", "ctpsw/ipa2u", "dbpc/ipa3l", "dbpsw/ipa3u", "ctbp/dpa0l",
44   "dir/dpa0u", "bpc/dpa0u", "asid/dpa1l",
45   "bpav/dpa1u", "bpam/dpa2l", "bpdv/dpa2u", "bpdm/dpa3l", "eiwr/dpa3u",
46   "fewr", "dbwr", "bsel"
47 };
48 
49 static const char *const v850_cc_names[] =
50 {
51   "v", "c/l", "z", "nh", "s/n", "t", "lt", "le",
52   "nv", "nc/nl", "nz", "h", "ns/p", "sa", "ge", "gt"
53 };
54 
55 static const char *const v850_float_cc_names[] =
56 {
57   "f/t", "un/or", "eq/neq", "ueq/ogl", "olt/uge", "ult/oge", "ole/ugt", "ule/ogt",
58   "sf/st", "ngle/gle", "seq/sne", "ngl/gl", "lt/nlt", "nge/ge", "le/nle", "ngt/gt"
59 };
60 
61 
62 static void
63 print_value (int flags, bfd_vma memaddr, struct disassemble_info *info, long value)
64 {
65   if (flags & V850_PCREL)
66     {
67       bfd_vma addr = value + memaddr;
68       info->print_address_func (addr, info);
69     }
70   else if (flags & V850_OPERAND_DISP)
71     {
72       if (flags & V850_OPERAND_SIGNED)
73         {
74           info->fprintf_func (info->stream, "%ld", value);
75         }
76       else
77         {
78           info->fprintf_func (info->stream, "%lu", value);
79         }
80     }
81   else if (flags & V850E_IMMEDIATE32)
82     {
83       info->fprintf_func (info->stream, "0x%lx", value);
84     }
85   else
86     {
87       if (flags & V850_OPERAND_SIGNED)
88 	{
89 	  info->fprintf_func (info->stream, "%ld", value);
90 	}
91       else
92 	{
93 	  info->fprintf_func (info->stream, "%lu", value);
94 	}
95     }
96 }
97 
98 static long
99 get_operand_value (const struct v850_operand *operand,
100 		   unsigned long insn,
101 		   int bytes_read,
102 		   bfd_vma memaddr,
103 		   struct disassemble_info * info,
104 		   bfd_boolean noerror,
105 		   int *invalid)
106 {
107   long value;
108   bfd_byte buffer[4];
109 
110   if ((operand->flags & V850E_IMMEDIATE16)
111       || (operand->flags & V850E_IMMEDIATE16HI))
112     {
113       int status = info->read_memory_func (memaddr + bytes_read, buffer, 2, info);
114 
115       if (status == 0)
116 	{
117 	  value = bfd_getl16 (buffer);
118 
119 	  if (operand->flags & V850E_IMMEDIATE16HI)
120 	    value <<= 16;
121 
122 	  return value;
123 	}
124 
125       if (!noerror)
126 	info->memory_error_func (status, memaddr + bytes_read, info);
127 
128       return 0;
129     }
130 
131   if (operand->flags & V850E_IMMEDIATE23)
132     {
133       int status = info->read_memory_func (memaddr + 2, buffer, 4, info);
134 
135       if (status == 0)
136 	{
137 	  value = bfd_getl32 (buffer);
138 
139 	  value = (operand->extract) (value, invalid);
140 
141 	  return value;
142 	}
143 
144       if (!noerror)
145 	info->memory_error_func (status, memaddr + bytes_read, info);
146 
147       return 0;
148     }
149 
150   if (operand->flags & V850E_IMMEDIATE32)
151     {
152       int status = info->read_memory_func (memaddr + bytes_read, buffer, 4, info);
153 
154       if (status == 0)
155 	{
156 	  bytes_read += 4;
157 	  value = bfd_getl32 (buffer);
158 
159 	  return value;
160 	}
161 
162       if (!noerror)
163 	info->memory_error_func (status, memaddr + bytes_read, info);
164 
165       return 0;
166     }
167 
168   if (operand->extract)
169     value = (operand->extract) (insn, invalid);
170   else
171     {
172       if (operand->bits == -1)
173 	value = (insn & operand->shift);
174       else
175 	value = (insn >> operand->shift) & ((1 << operand->bits) - 1);
176 
177       if (operand->flags & V850_OPERAND_SIGNED)
178 	value = ((long)(value << (sizeof (long)*8 - operand->bits))
179 		 >> (sizeof (long)*8 - operand->bits));
180     }
181 
182   return value;
183 }
184 
185 
186 static int
187 disassemble (bfd_vma memaddr, struct disassemble_info *info, int bytes_read, unsigned long insn)
188 {
189   struct v850_opcode *op = (struct v850_opcode *)v850_opcodes;
190   const struct v850_operand *operand;
191   int match = 0;
192   int target_processor;
193 
194   switch (info->mach)
195     {
196     case 0:
197     default:
198       target_processor = PROCESSOR_V850;
199       break;
200 
201     case bfd_mach_v850e:
202       target_processor = PROCESSOR_V850E;
203       break;
204 
205     case bfd_mach_v850e1:
206       target_processor = PROCESSOR_V850E;
207       break;
208 
209     case bfd_mach_v850e2:
210       target_processor = PROCESSOR_V850E2;
211       break;
212 
213     case bfd_mach_v850e2v3:
214       target_processor = PROCESSOR_V850E2V3;
215       break;
216     }
217 
218   /* If this is a two byte insn, then mask off the high bits.  */
219   if (bytes_read == 2)
220     insn &= 0xffff;
221 
222   /* Find the opcode.  */
223   while (op->name)
224     {
225       if ((op->mask & insn) == op->opcode
226 	  && (op->processors & target_processor)
227 	  && !(op->processors & PROCESSOR_OPTION_ALIAS))
228 	{
229 	  /* Code check start.  */
230 	  const unsigned char *opindex_ptr;
231 	  unsigned int opnum;
232 	  unsigned int memop;
233 
234 	  for (opindex_ptr = op->operands, opnum = 1;
235 	       *opindex_ptr != 0;
236 	       opindex_ptr++, opnum++)
237 	    {
238 	      int invalid = 0;
239 	      long value;
240 
241 	      operand = &v850_operands[*opindex_ptr];
242 
243 	      value = get_operand_value (operand, insn, bytes_read, memaddr, info, 1, &invalid);
244 
245 	      if (invalid)
246 		goto next_opcode;
247 
248               if ((operand->flags & V850_NOT_R0) && value == 0 && (op->memop) <=2)
249 		goto next_opcode;
250 
251 	      if ((operand->flags & V850_NOT_SA) && value == 0xd)
252 		goto next_opcode;
253 
254 	      if ((operand->flags & V850_NOT_IMM0) && value == 0)
255 		goto next_opcode;
256 	    }
257 
258 	  /* Code check end.  */
259 
260 	  match = 1;
261 	  (*info->fprintf_func) (info->stream, "%s\t", op->name);
262 #if 0
263 	  fprintf (stderr, "match: insn: %lx, mask: %lx, opcode: %lx, name: %s\n",
264 		   insn, op->mask, op->opcode, op->name );
265 #endif
266 
267 	  memop = op->memop;
268 	  /* Now print the operands.
269 
270 	     MEMOP is the operand number at which a memory
271 	     address specification starts, or zero if this
272 	     instruction has no memory addresses.
273 
274 	     A memory address is always two arguments.
275 
276 	     This information allows us to determine when to
277 	     insert commas into the output stream as well as
278 	     when to insert disp[reg] expressions onto the
279 	     output stream.  */
280 
281 	  for (opindex_ptr = op->operands, opnum = 1;
282 	       *opindex_ptr != 0;
283 	       opindex_ptr++, opnum++)
284 	    {
285 	      bfd_boolean square = FALSE;
286 	      long value;
287 	      int flag;
288 	      char *prefix;
289 
290 	      operand = &v850_operands[*opindex_ptr];
291 
292 	      value = get_operand_value (operand, insn, bytes_read, memaddr, info, 0, 0);
293 
294 	      /* The first operand is always output without any
295 		 special handling.
296 
297 		 For the following arguments:
298 
299 		   If memop && opnum == memop + 1, then we need '[' since
300 		   we're about to output the register used in a memory
301 		   reference.
302 
303 		   If memop && opnum == memop + 2, then we need ']' since
304 		   we just finished the register in a memory reference.  We
305 		   also need a ',' before this operand.
306 
307 		   Else we just need a comma.
308 
309 		   We may need to output a trailing ']' if the last operand
310 		   in an instruction is the register for a memory address.
311 
312 		   The exception (and there's always an exception) is the
313 		   "jmp" insn which needs square brackets around it's only
314 		   register argument.  */
315 	      prefix = "";
316 	      if (operand->flags & V850_OPERAND_BANG)
317 		{
318 		  prefix = "!";
319 		}
320 	      else if (operand->flags & V850_OPERAND_PERCENT)
321 		{
322 		  prefix = "%";
323 		}
324 
325 	      if (opnum == 1 && opnum == memop)
326 		{
327 		  info->fprintf_func (info->stream, "%s[", prefix);
328 		  square = TRUE;
329 		}
330 	      else if (opnum > 1
331 		       && (v850_operands[*(opindex_ptr - 1)].flags & V850_OPERAND_DISP) != 0
332 		       && opnum == memop)
333 		{
334 		  info->fprintf_func (info->stream, "%s[", prefix);
335 		  square = TRUE;
336 		}
337 	      else if (opnum > 1)
338 		info->fprintf_func (info->stream, ", %s", prefix);
339 
340  	      /* Extract the flags, ignoring ones which do not effect disassembly output.  */
341 	      flag = operand->flags & (V850_OPERAND_REG
342 				       | V850_REG_EVEN
343 				       | V850_OPERAND_EP
344 				       | V850_OPERAND_SRG
345 				       | V850E_OPERAND_REG_LIST
346 				       | V850_OPERAND_CC
347 				       | V850_OPERAND_FLOAT_CC);
348 
349 	      switch (flag)
350 		{
351 		case V850_OPERAND_REG:  info->fprintf_func (info->stream, "%s", v850_reg_names[value]); break;
352 		case (V850_OPERAND_REG|V850_REG_EVEN):  info->fprintf_func (info->stream, "%s", v850_reg_names[value*2]); break;
353 		case V850_OPERAND_EP:   info->fprintf_func (info->stream, "ep"); break;
354 		case V850_OPERAND_SRG:  info->fprintf_func (info->stream, "%s", v850_sreg_names[value]); break;
355 
356 		case V850E_OPERAND_REG_LIST:
357 		  {
358 		    static int list12_regs[32]   = { 30, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
359 						     0,  0, 0, 0, 0, 31, 29, 28, 23, 22, 21, 20, 27, 26, 25, 24 };
360 		    int *regs;
361 		    int i;
362 		    unsigned long int mask = 0;
363 		    int pc = 0;
364 
365 
366 		    switch (operand->shift)
367 		      {
368 		      case 0xffe00001: regs = list12_regs; break;
369 		      default:
370 			/* xgettext:c-format */
371 			fprintf (stderr, _("unknown operand shift: %x\n"), operand->shift );
372 			abort ();
373 		      }
374 
375 		    for (i = 0; i < 32; i++)
376 		      {
377 			if (value & (1 << i))
378 			  {
379 			    switch (regs[ i ])
380 			      {
381 			      default: mask |= (1 << regs[ i ]); break;
382 				/* xgettext:c-format */
383 			      case 0:  fprintf (stderr, _("unknown reg: %d\n"), i ); abort ();
384 			      case -1: pc = 1; break;
385 			      }
386 			  }
387 		      }
388 
389 		    info->fprintf_func (info->stream, "{");
390 
391 		    if (mask || pc)
392 		      {
393 			if (mask)
394 			  {
395 			    unsigned int bit;
396 			    int shown_one = 0;
397 
398 			    for (bit = 0; bit < 32; bit++)
399 			      if (mask & (1 << bit))
400 				{
401 				  unsigned long int first = bit;
402 				  unsigned long int last;
403 
404 				  if (shown_one)
405 				    info->fprintf_func (info->stream, ", ");
406 				  else
407 				    shown_one = 1;
408 
409 				  info->fprintf_func (info->stream, "%s", v850_reg_names[first]);
410 
411 				  for (bit++; bit < 32; bit++)
412 				    if ((mask & (1 << bit)) == 0)
413 				      break;
414 
415 				  last = bit;
416 
417 				  if (last > first + 1)
418 				    {
419 				      info->fprintf_func (info->stream, " - %s", v850_reg_names[ last - 1 ]);
420 				    }
421 				}
422 			  }
423 
424 			if (pc)
425 			  info->fprintf_func (info->stream, "%sPC", mask ? ", " : "");
426 		      }
427 
428 		    info->fprintf_func (info->stream, "}");
429 		  }
430 		  break;
431 
432 		case V850_OPERAND_CC:   info->fprintf_func (info->stream, "%s", v850_cc_names[value]); break;
433 		case V850_OPERAND_FLOAT_CC:   info->fprintf_func (info->stream, "%s", v850_float_cc_names[value]); break;
434 
435 		default:
436 		  print_value (operand->flags, memaddr, info, value);
437 		  break;
438 		}
439 
440 	      if (square)
441 		(*info->fprintf_func) (info->stream, "]");
442 	    }
443 
444 	  /* All done. */
445 	  break;
446 	}
447     next_opcode:
448       op++;
449     }
450 
451   return match;
452 }
453 
454 int
455 print_insn_v850 (bfd_vma memaddr, struct disassemble_info * info)
456 {
457   int status, status2, match;
458   bfd_byte buffer[8];
459   int length = 0, code_length = 0;
460   unsigned long insn = 0, insn2 = 0;
461   int target_processor;
462 
463   switch (info->mach)
464     {
465     case 0:
466     default:
467       target_processor = PROCESSOR_V850;
468       break;
469 
470     case bfd_mach_v850e:
471       target_processor = PROCESSOR_V850E;
472       break;
473 
474     case bfd_mach_v850e1:
475       target_processor = PROCESSOR_V850E;
476       break;
477 
478     case bfd_mach_v850e2:
479       target_processor = PROCESSOR_V850E2;
480       break;
481 
482     case bfd_mach_v850e2v3:
483       target_processor = PROCESSOR_V850E2V3;
484       break;
485     }
486 
487   status = info->read_memory_func (memaddr, buffer, 2, info);
488 
489   if (status)
490     {
491       info->memory_error_func (status, memaddr, info);
492       return -1;
493     }
494 
495   insn = bfd_getl16 (buffer);
496 
497   status2 = info->read_memory_func (memaddr+2, buffer, 2 , info);
498 
499   if (!status2)
500     {
501       insn2 = bfd_getl16 (buffer);
502       /* fprintf (stderr, "insn2 0x%08lx\n", insn2); */
503     }
504 
505   /* Special case.  */
506   if (length == 0
507       && (target_processor == PROCESSOR_V850E2
508 	  || target_processor == PROCESSOR_V850E2V3))
509     {
510       if ((insn & 0xffff) == 0x02e0		/* jr 32bit */
511 	  && !status2 && (insn2 & 0x1) == 0)
512 	{
513 	  length = 2;
514 	  code_length = 6;
515 	}
516       else if ((insn & 0xffe0) == 0x02e0	/* jarl 32bit */
517 	       && !status2 && (insn2 & 0x1) == 0)
518 	{
519 	  length = 2;
520 	  code_length = 6;
521 	}
522       else if ((insn & 0xffe0) == 0x06e0	/* jmp 32bit */
523 	       && !status2 && (insn2 & 0x1) == 0)
524 	{
525 	  length = 2;
526 	  code_length = 6;
527 	}
528     }
529 
530   if (length == 0
531       && target_processor == PROCESSOR_V850E2V3)
532     {
533       if (((insn & 0xffe0) == 0x0780		/* ld.b 23bit */
534 	   && !status2 && (insn2 & 0x000f) == 0x0005)
535 	  || ((insn & 0xffe0) == 0x07a0		/* ld.bu 23bit */
536 	      && !status2 && (insn2 & 0x000f) == 0x0005)
537 	  || ((insn & 0xffe0) == 0x0780		/* ld.h 23bit */
538 	      && !status2 && (insn2 & 0x000f) == 0x0007)
539 	  || ((insn & 0xffe0) == 0x07a0		/* ld.hu 23bit */
540 	      && !status2 && (insn2 & 0x000f) == 0x0007)
541 	  || ((insn & 0xffe0) == 0x0780		/* ld.w 23bit */
542 	      && !status2 && (insn2 & 0x000f) == 0x0009))
543 	{
544 	  length = 4;
545 	  code_length = 6;
546 	}
547       else if (((insn & 0xffe0) == 0x0780	/* st.b 23bit */
548 	       && !status2 && (insn2 & 0x000f) == 0x000d)
549 	      || ((insn & 0xffe0) == 0x07a0	/* st.h 23bit */
550 		  && !status2 && (insn2 & 0x000f) == 0x000d)
551 	      || ((insn & 0xffe0) == 0x0780	/* st.w 23bit */
552 		  && !status2 && (insn2 & 0x000f) == 0x000f))
553 	{
554 	  length = 4;
555 	  code_length = 6;
556 	}
557     }
558 
559   if (length == 0
560       && target_processor != PROCESSOR_V850)
561     {
562       if ((insn & 0xffe0) == 0x0620)		/* 32 bit MOV */
563 	{
564 	  length = 2;
565 	  code_length = 6;
566 	}
567       else if ((insn & 0xffc0) == 0x0780	/* prepare {list}, imm5, imm16<<16 */
568 	       && !status2 && (insn2 & 0x001f) == 0x0013)
569 	{
570 	  length = 4;
571 	  code_length = 6;
572 	}
573       else if ((insn & 0xffc0) == 0x0780	/* prepare {list}, imm5, imm16 */
574 	       && !status2 && (insn2 & 0x001f) == 0x000b)
575 	{
576 	  length = 4;
577 	  code_length = 6;
578 	}
579       else if ((insn & 0xffc0) == 0x0780	/* prepare {list}, imm5, imm32 */
580 	       && !status2 && (insn2 & 0x001f) == 0x001b)
581 	{
582 	  length = 4;
583 	  code_length = 8;
584 	}
585     }
586 
587   if (length == 4
588       || (length == 0
589 	  && (insn & 0x0600) == 0x0600))
590     {
591       /* This is a 4 byte insn.  */
592       status = info->read_memory_func (memaddr, buffer, 4, info);
593       if (!status)
594 	{
595 	  insn = bfd_getl32 (buffer);
596 
597 	  if (!length)
598 	    length = code_length = 4;
599 	}
600     }
601 
602   if (code_length > length)
603     {
604       status = info->read_memory_func (memaddr + length, buffer, code_length - length, info);
605       if (status)
606 	length = 0;
607     }
608 
609   if (length == 0 && !status)
610     length = code_length = 2;
611 
612   if (length == 2)
613     insn &= 0xffff;
614 
615   match = disassemble (memaddr, info, length, insn);
616 
617   if (!match)
618     {
619       int l = 0;
620 
621       status = info->read_memory_func (memaddr, buffer, code_length, info);
622 
623       while (l < code_length)
624 	{
625 	  if (code_length - l == 2)
626 	    {
627 	      insn = bfd_getl16 (buffer + l) & 0xffff;
628 	      info->fprintf_func (info->stream, ".short\t0x%04lx", insn);
629 	      l += 2;
630 	    }
631 	  else
632 	    {
633 	      insn = bfd_getl32 (buffer + l);
634 	      info->fprintf_func (info->stream, ".long\t0x%08lx", insn);
635 	      l += 4;
636 	    }
637 	}
638     }
639 
640   return code_length;
641 }
642