sh-dis.c revision 104834
133965Sjdp/* Disassemble SH instructions.
289857Sobrien   Copyright 1993, 1994, 1995, 1997, 1998, 2000, 2001
385815Sobrien   Free Software Foundation, Inc.
433965Sjdp
533965SjdpThis program is free software; you can redistribute it and/or modify
633965Sjdpit under the terms of the GNU General Public License as published by
733965Sjdpthe Free Software Foundation; either version 2 of the License, or
833965Sjdp(at your option) any later version.
933965Sjdp
1033965SjdpThis program is distributed in the hope that it will be useful,
1133965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of
1233965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1333965SjdpGNU General Public License for more details.
1433965Sjdp
1533965SjdpYou should have received a copy of the GNU General Public License
1633965Sjdpalong with this program; if not, write to the Free Software
1733965SjdpFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
1833965Sjdp
1985815Sobrien#include <stdio.h>
2060484Sobrien#include "sysdep.h"
2133965Sjdp#define STATIC_TABLE
2233965Sjdp#define DEFINE_TABLE
2333965Sjdp
2433965Sjdp#include "sh-opc.h"
2533965Sjdp#include "dis-asm.h"
2633965Sjdp
2789857Sobrienstatic void print_movxy
2889857Sobrien  PARAMS ((sh_opcode_info *, int, int, fprintf_ftype, void *));
2989857Sobrienstatic void print_insn_ddt PARAMS ((int, struct disassemble_info *));
3089857Sobrienstatic void print_dsp_reg PARAMS ((int, fprintf_ftype, void *));
3189857Sobrienstatic void print_insn_ppi PARAMS ((int, struct disassemble_info *));
3289857Sobrien
3360484Sobrienstatic void
3460484Sobrienprint_movxy (op, rn, rm, fprintf_fn, stream)
3560484Sobrien     sh_opcode_info *op;
3660484Sobrien     int rn, rm;
3760484Sobrien     fprintf_ftype fprintf_fn;
3860484Sobrien     void *stream;
3960484Sobrien{
4060484Sobrien  int n;
4160484Sobrien
4285815Sobrien  fprintf_fn (stream, "%s\t", op->name);
4360484Sobrien  for (n = 0; n < 2; n++)
4460484Sobrien    {
4560484Sobrien      switch (op->arg[n])
4660484Sobrien	{
4760484Sobrien	case A_IND_N:
4885815Sobrien	  fprintf_fn (stream, "@r%d", rn);
4960484Sobrien	  break;
5060484Sobrien	case A_INC_N:
5185815Sobrien	  fprintf_fn (stream, "@r%d+", rn);
5260484Sobrien	  break;
5360484Sobrien	case A_PMOD_N:
5485815Sobrien	  fprintf_fn (stream, "@r%d+r8", rn);
5560484Sobrien	  break;
5660484Sobrien	case A_PMODY_N:
5785815Sobrien	  fprintf_fn (stream, "@r%d+r9", rn);
5860484Sobrien	  break;
5960484Sobrien	case DSP_REG_M:
6060484Sobrien	  fprintf_fn (stream, "a%c", '0' + rm);
6160484Sobrien	  break;
6260484Sobrien	case DSP_REG_X:
6360484Sobrien	  fprintf_fn (stream, "x%c", '0' + rm);
6460484Sobrien	  break;
6560484Sobrien	case DSP_REG_Y:
6660484Sobrien	  fprintf_fn (stream, "y%c", '0' + rm);
6760484Sobrien	  break;
6860484Sobrien	default:
6960484Sobrien	  abort ();
7060484Sobrien	}
7160484Sobrien      if (n == 0)
7285815Sobrien	fprintf_fn (stream, ",");
7360484Sobrien    }
7460484Sobrien}
7560484Sobrien
7660484Sobrien/* Print a double data transfer insn.  INSN is just the lower three
7760484Sobrien   nibbles of the insn, i.e. field a and the bit that indicates if
7860484Sobrien   a parallel processing insn follows.
7960484Sobrien   Return nonzero if a field b of a parallel processing insns follows.  */
8085815Sobrien
8160484Sobrienstatic void
8260484Sobrienprint_insn_ddt (insn, info)
8360484Sobrien     int insn;
8460484Sobrien     struct disassemble_info *info;
8560484Sobrien{
8660484Sobrien  fprintf_ftype fprintf_fn = info->fprintf_func;
8760484Sobrien  void *stream = info->stream;
8860484Sobrien
8960484Sobrien  /* If this is just a nop, make sure to emit something.  */
9060484Sobrien  if (insn == 0x000)
9160484Sobrien    fprintf_fn (stream, "nopx\tnopy");
9260484Sobrien
9360484Sobrien  /* If a parallel processing insn was printed before,
9460484Sobrien     and we got a non-nop, emit a tab.  */
9560484Sobrien  if ((insn & 0x800) && (insn & 0x3ff))
9660484Sobrien    fprintf_fn (stream, "\t");
9760484Sobrien
9860484Sobrien  /* Check if either the x or y part is invalid.  */
9960484Sobrien  if (((insn & 0xc) == 0 && (insn & 0x2a0))
10060484Sobrien      || ((insn & 3) == 0 && (insn & 0x150)))
10160484Sobrien    fprintf_fn (stream, ".word 0x%x", insn);
10260484Sobrien  else
10360484Sobrien    {
10460484Sobrien      static sh_opcode_info *first_movx, *first_movy;
10560484Sobrien      sh_opcode_info *opx, *opy;
10685815Sobrien      unsigned int insn_x, insn_y;
10760484Sobrien
10860484Sobrien      if (! first_movx)
10960484Sobrien	{
11085815Sobrien	  for (first_movx = sh_table; first_movx->nibbles[1] != MOVX;)
11160484Sobrien	    first_movx++;
11285815Sobrien	  for (first_movy = first_movx; first_movy->nibbles[1] != MOVY;)
11360484Sobrien	    first_movy++;
11460484Sobrien	}
11560484Sobrien      insn_x = (insn >> 2) & 0xb;
11660484Sobrien      if (insn_x)
11760484Sobrien	{
11885815Sobrien	  for (opx = first_movx; opx->nibbles[2] != insn_x;)
11985815Sobrien	    opx++;
12060484Sobrien	  print_movxy (opx, ((insn >> 9) & 1) + 4, (insn >> 7) & 1,
12160484Sobrien		       fprintf_fn, stream);
12260484Sobrien	}
12360484Sobrien      insn_y = (insn & 3) | ((insn >> 1) & 8);
12460484Sobrien      if (insn_y)
12560484Sobrien	{
12660484Sobrien	  if (insn_x)
12760484Sobrien	    fprintf_fn (stream, "\t");
12885815Sobrien	  for (opy = first_movy; opy->nibbles[2] != insn_y;)
12985815Sobrien	    opy++;
13060484Sobrien	  print_movxy (opy, ((insn >> 8) & 1) + 6, (insn >> 6) & 1,
13160484Sobrien		       fprintf_fn, stream);
13260484Sobrien	}
13360484Sobrien    }
13460484Sobrien}
13560484Sobrien
13660484Sobrienstatic void
13760484Sobrienprint_dsp_reg (rm, fprintf_fn, stream)
13860484Sobrien     int rm;
13960484Sobrien     fprintf_ftype fprintf_fn;
14060484Sobrien     void *stream;
14160484Sobrien{
14260484Sobrien  switch (rm)
14360484Sobrien    {
14460484Sobrien    case A_A1_NUM:
14560484Sobrien      fprintf_fn (stream, "a1");
14660484Sobrien      break;
14760484Sobrien    case A_A0_NUM:
14860484Sobrien      fprintf_fn (stream, "a0");
14960484Sobrien      break;
15060484Sobrien    case A_X0_NUM:
15160484Sobrien      fprintf_fn (stream, "x0");
15260484Sobrien      break;
15360484Sobrien    case A_X1_NUM:
15460484Sobrien      fprintf_fn (stream, "x1");
15560484Sobrien      break;
15660484Sobrien    case A_Y0_NUM:
15760484Sobrien      fprintf_fn (stream, "y0");
15860484Sobrien      break;
15960484Sobrien    case A_Y1_NUM:
16060484Sobrien      fprintf_fn (stream, "y1");
16160484Sobrien      break;
16260484Sobrien    case A_M0_NUM:
16360484Sobrien      fprintf_fn (stream, "m0");
16460484Sobrien      break;
16560484Sobrien    case A_A1G_NUM:
16660484Sobrien      fprintf_fn (stream, "a1g");
16760484Sobrien      break;
16860484Sobrien    case A_M1_NUM:
16960484Sobrien      fprintf_fn (stream, "m1");
17060484Sobrien      break;
17160484Sobrien    case A_A0G_NUM:
17260484Sobrien      fprintf_fn (stream, "a0g");
17360484Sobrien      break;
17460484Sobrien    default:
17560484Sobrien      fprintf_fn (stream, "0x%x", rm);
17660484Sobrien      break;
17760484Sobrien    }
17860484Sobrien}
17960484Sobrien
18060484Sobrienstatic void
18160484Sobrienprint_insn_ppi (field_b, info)
18260484Sobrien     int field_b;
18360484Sobrien     struct disassemble_info *info;
18460484Sobrien{
18585815Sobrien  static char *sx_tab[] = { "x0", "x1", "a0", "a1" };
18685815Sobrien  static char *sy_tab[] = { "y0", "y1", "m0", "m1" };
18760484Sobrien  fprintf_ftype fprintf_fn = info->fprintf_func;
18860484Sobrien  void *stream = info->stream;
18985815Sobrien  unsigned int nib1, nib2, nib3;
19085815Sobrien  char *dc = NULL;
19160484Sobrien  sh_opcode_info *op;
19260484Sobrien
19360484Sobrien  if ((field_b & 0xe800) == 0)
19460484Sobrien    {
19560484Sobrien      fprintf_fn (stream, "psh%c\t#%d,",
19660484Sobrien		  field_b & 0x1000 ? 'a' : 'l',
19760484Sobrien		  (field_b >> 4) & 127);
19860484Sobrien      print_dsp_reg (field_b & 0xf, fprintf_fn, stream);
19960484Sobrien      return;
20060484Sobrien    }
20160484Sobrien  if ((field_b & 0xc000) == 0x4000 && (field_b & 0x3000) != 0x1000)
20260484Sobrien    {
20385815Sobrien      static char *du_tab[] = { "x0", "y0", "a0", "a1" };
20485815Sobrien      static char *se_tab[] = { "x0", "x1", "y0", "a1" };
20585815Sobrien      static char *sf_tab[] = { "y0", "y1", "x0", "a1" };
20685815Sobrien      static char *sg_tab[] = { "m0", "m1", "a0", "a1" };
20760484Sobrien
20860484Sobrien      if (field_b & 0x2000)
20960484Sobrien	{
21060484Sobrien	  fprintf_fn (stream, "p%s %s,%s,%s\t",
21160484Sobrien		      (field_b & 0x1000) ? "add" : "sub",
21260484Sobrien		      sx_tab[(field_b >> 6) & 3],
21360484Sobrien		      sy_tab[(field_b >> 4) & 3],
21460484Sobrien		      du_tab[(field_b >> 0) & 3]);
21560484Sobrien	}
21660484Sobrien      fprintf_fn (stream, "pmuls%c%s,%s,%s",
21760484Sobrien		  field_b & 0x2000 ? ' ' : '\t',
21860484Sobrien		  se_tab[(field_b >> 10) & 3],
21960484Sobrien		  sf_tab[(field_b >>  8) & 3],
22060484Sobrien		  sg_tab[(field_b >>  2) & 3]);
22160484Sobrien      return;
22260484Sobrien    }
22360484Sobrien
22460484Sobrien  nib1 = PPIC;
22560484Sobrien  nib2 = field_b >> 12 & 0xf;
22660484Sobrien  nib3 = field_b >> 8 & 0xf;
22760484Sobrien  switch (nib3 & 0x3)
22860484Sobrien    {
22960484Sobrien    case 0:
23060484Sobrien      dc = "";
23160484Sobrien      nib1 = PPI3;
23260484Sobrien      break;
23360484Sobrien    case 1:
23460484Sobrien      dc = "";
23560484Sobrien      break;
23660484Sobrien    case 2:
23760484Sobrien      dc = "dct ";
23860484Sobrien      nib3 -= 1;
23960484Sobrien      break;
24060484Sobrien    case 3:
24160484Sobrien      dc = "dcf ";
24260484Sobrien      nib3 -= 2;
24360484Sobrien      break;
24460484Sobrien    }
24560484Sobrien  for (op = sh_table; op->name; op++)
24660484Sobrien    {
24760484Sobrien      if (op->nibbles[1] == nib1
24860484Sobrien	  && op->nibbles[2] == nib2
24960484Sobrien	  && op->nibbles[3] == nib3)
25060484Sobrien	{
25160484Sobrien	  int n;
25260484Sobrien
25360484Sobrien	  fprintf_fn (stream, "%s%s\t", dc, op->name);
25485815Sobrien	  for (n = 0; n < 3 && op->arg[n] != A_END; n++)
25560484Sobrien	    {
25660484Sobrien	      if (n && op->arg[1] != A_END)
25760484Sobrien		fprintf_fn (stream, ",");
25885815Sobrien	      switch (op->arg[n])
25960484Sobrien		{
26060484Sobrien		case DSP_REG_N:
26160484Sobrien		  print_dsp_reg (field_b & 0xf, fprintf_fn, stream);
26260484Sobrien		  break;
26360484Sobrien		case DSP_REG_X:
26460484Sobrien		  fprintf_fn (stream, sx_tab[(field_b >> 6) & 3]);
26560484Sobrien		  break;
26660484Sobrien		case DSP_REG_Y:
26760484Sobrien		  fprintf_fn (stream, sy_tab[(field_b >> 4) & 3]);
26860484Sobrien		  break;
26960484Sobrien		case A_MACH:
27060484Sobrien		  fprintf_fn (stream, "mach");
27160484Sobrien		  break;
27260484Sobrien		case A_MACL:
27385815Sobrien		  fprintf_fn (stream, "macl");
27460484Sobrien		  break;
27560484Sobrien		default:
27660484Sobrien		  abort ();
27760484Sobrien		}
27860484Sobrien	    }
27960484Sobrien	  return;
28060484Sobrien	}
28160484Sobrien    }
28260484Sobrien  /* Not found.  */
28360484Sobrien  fprintf_fn (stream, ".word 0x%x", field_b);
28460484Sobrien}
28560484Sobrien
286104834Sobrienint
287104834Sobrienprint_insn_sh (memaddr, info)
28833965Sjdp     bfd_vma memaddr;
28933965Sjdp     struct disassemble_info *info;
29033965Sjdp{
29138889Sjdp  fprintf_ftype fprintf_fn = info->fprintf_func;
29233965Sjdp  void *stream = info->stream;
29338889Sjdp  unsigned char insn[2];
29438889Sjdp  unsigned char nibs[4];
29533965Sjdp  int status;
29685815Sobrien  bfd_vma relmask = ~(bfd_vma) 0;
29733965Sjdp  sh_opcode_info *op;
29860484Sobrien  int target_arch;
29933965Sjdp
30060484Sobrien  switch (info->mach)
30160484Sobrien    {
30260484Sobrien    case bfd_mach_sh:
30360484Sobrien      target_arch = arch_sh1;
304104834Sobrien      /* SH coff object files lack information about the machine type, so
305104834Sobrien         we end up with bfd_mach_sh unless it was set explicitly (which
306104834Sobrien	 could have happended if this is a call from gdb or the simulator.)  */
307104834Sobrien      if (info->symbols
308104834Sobrien	  && bfd_asymbol_flavour(*info->symbols) == bfd_target_coff_flavour)
309104834Sobrien	target_arch = arch_sh4;
31060484Sobrien      break;
31160484Sobrien    case bfd_mach_sh2:
31260484Sobrien      target_arch = arch_sh2;
31360484Sobrien      break;
31460484Sobrien    case bfd_mach_sh_dsp:
31560484Sobrien      target_arch = arch_sh_dsp;
31660484Sobrien      break;
31760484Sobrien    case bfd_mach_sh3:
31860484Sobrien      target_arch = arch_sh3;
31960484Sobrien      break;
32060484Sobrien    case bfd_mach_sh3_dsp:
32160484Sobrien      target_arch = arch_sh3_dsp;
32260484Sobrien      break;
32360484Sobrien    case bfd_mach_sh3e:
32460484Sobrien      target_arch = arch_sh3e;
32560484Sobrien      break;
32660484Sobrien    case bfd_mach_sh4:
32760484Sobrien      target_arch = arch_sh4;
32860484Sobrien      break;
32991041Sobrien    case bfd_mach_sh5:
330104834Sobrien#ifdef INCLUDE_SHMEDIA
331104834Sobrien      status = print_insn_sh64 (memaddr, info);
332104834Sobrien      if (status != -2)
333104834Sobrien	return status;
334104834Sobrien#endif
33591041Sobrien      /* When we get here for sh64, it's because we want to disassemble
33691041Sobrien	 SHcompact, i.e. arch_sh4.  */
33791041Sobrien      target_arch = arch_sh4;
33891041Sobrien      break;
33960484Sobrien    default:
34060484Sobrien      abort ();
34160484Sobrien    }
34260484Sobrien
34338889Sjdp  status = info->read_memory_func (memaddr, insn, 2, info);
34438889Sjdp
34585815Sobrien  if (status != 0)
34633965Sjdp    {
34738889Sjdp      info->memory_error_func (status, memaddr, info);
34833965Sjdp      return -1;
34933965Sjdp    }
35033965Sjdp
351104834Sobrien  if (info->endian == BFD_ENDIAN_LITTLE)
35233965Sjdp    {
35333965Sjdp      nibs[0] = (insn[1] >> 4) & 0xf;
35433965Sjdp      nibs[1] = insn[1] & 0xf;
35533965Sjdp
35633965Sjdp      nibs[2] = (insn[0] >> 4) & 0xf;
35733965Sjdp      nibs[3] = insn[0] & 0xf;
35833965Sjdp    }
35985815Sobrien  else
36033965Sjdp    {
36133965Sjdp      nibs[0] = (insn[0] >> 4) & 0xf;
36233965Sjdp      nibs[1] = insn[0] & 0xf;
36333965Sjdp
36433965Sjdp      nibs[2] = (insn[1] >> 4) & 0xf;
36533965Sjdp      nibs[3] = insn[1] & 0xf;
36633965Sjdp    }
36733965Sjdp
36860484Sobrien  if (nibs[0] == 0xf && (nibs[1] & 4) == 0 && target_arch & arch_sh_dsp_up)
36960484Sobrien    {
37060484Sobrien      if (nibs[1] & 8)
37160484Sobrien	{
37260484Sobrien	  int field_b;
37360484Sobrien
37460484Sobrien	  status = info->read_memory_func (memaddr + 2, insn, 2, info);
37560484Sobrien
37685815Sobrien	  if (status != 0)
37760484Sobrien	    {
37860484Sobrien	      info->memory_error_func (status, memaddr + 2, info);
37960484Sobrien	      return -1;
38060484Sobrien	    }
38160484Sobrien
382104834Sobrien	  if (info->endian == BFD_ENDIAN_LITTLE)
38360484Sobrien	    field_b = insn[1] << 8 | insn[0];
38460484Sobrien	  else
38560484Sobrien	    field_b = insn[0] << 8 | insn[1];
38660484Sobrien
38760484Sobrien	  print_insn_ppi (field_b, info);
38860484Sobrien	  print_insn_ddt ((nibs[1] << 8) | (nibs[2] << 4) | nibs[3], info);
38960484Sobrien	  return 4;
39060484Sobrien	}
39160484Sobrien      print_insn_ddt ((nibs[1] << 8) | (nibs[2] << 4) | nibs[3], info);
39260484Sobrien      return 2;
39360484Sobrien    }
39485815Sobrien  for (op = sh_table; op->name; op++)
39533965Sjdp    {
39633965Sjdp      int n;
39738889Sjdp      int imm = 0;
39838889Sjdp      int rn = 0;
39938889Sjdp      int rm = 0;
40038889Sjdp      int rb = 0;
40138889Sjdp      int disp_pc;
40238889Sjdp      bfd_vma disp_pc_addr = 0;
40333965Sjdp
40460484Sobrien      if ((op->arch & target_arch) == 0)
40560484Sobrien	goto fail;
40638889Sjdp      for (n = 0; n < 4; n++)
40738889Sjdp	{
40838889Sjdp	  int i = op->nibbles[n];
40933965Sjdp
41085815Sobrien	  if (i < 16)
41138889Sjdp	    {
41238889Sjdp	      if (nibs[n] == i)
41338889Sjdp		continue;
41438889Sjdp	      goto fail;
41538889Sjdp	    }
41638889Sjdp	  switch (i)
41738889Sjdp	    {
41838889Sjdp	    case BRANCH_8:
41985815Sobrien	      imm = (nibs[2] << 4) | (nibs[3]);
42038889Sjdp	      if (imm & 0x80)
42138889Sjdp		imm |= ~0xff;
42285815Sobrien	      imm = ((char) imm) * 2 + 4;
42338889Sjdp	      goto ok;
42438889Sjdp	    case BRANCH_12:
42538889Sjdp	      imm = ((nibs[1]) << 8) | (nibs[2] << 4) | (nibs[3]);
42638889Sjdp	      if (imm & 0x800)
42738889Sjdp		imm |= ~0xfff;
42838889Sjdp	      imm = imm * 2 + 4;
42938889Sjdp	      goto ok;
43085815Sobrien	    case IMM0_4:
43185815Sobrien	    case IMM1_4:
43238889Sjdp	      imm = nibs[3];
43338889Sjdp	      goto ok;
43485815Sobrien	    case IMM0_4BY2:
43585815Sobrien	    case IMM1_4BY2:
43685815Sobrien	      imm = nibs[3] << 1;
43738889Sjdp	      goto ok;
43885815Sobrien	    case IMM0_4BY4:
43985815Sobrien	    case IMM1_4BY4:
44085815Sobrien	      imm = nibs[3] << 2;
44138889Sjdp	      goto ok;
44285815Sobrien	    case IMM0_8:
44385815Sobrien	    case IMM1_8:
44438889Sjdp	      imm = (nibs[2] << 4) | nibs[3];
44538889Sjdp	      goto ok;
44638889Sjdp	    case PCRELIMM_8BY2:
44785815Sobrien	      imm = ((nibs[2] << 4) | nibs[3]) << 1;
44885815Sobrien	      relmask = ~(bfd_vma) 1;
44938889Sjdp	      goto ok;
45038889Sjdp	    case PCRELIMM_8BY4:
45185815Sobrien	      imm = ((nibs[2] << 4) | nibs[3]) << 2;
45285815Sobrien	      relmask = ~(bfd_vma) 3;
45338889Sjdp	      goto ok;
45485815Sobrien	    case IMM0_8BY2:
45585815Sobrien	    case IMM1_8BY2:
45685815Sobrien	      imm = ((nibs[2] << 4) | nibs[3]) << 1;
45738889Sjdp	      goto ok;
45885815Sobrien	    case IMM0_8BY4:
45985815Sobrien	    case IMM1_8BY4:
46085815Sobrien	      imm = ((nibs[2] << 4) | nibs[3]) << 2;
46138889Sjdp	      goto ok;
46238889Sjdp	    case REG_N:
46338889Sjdp	      rn = nibs[n];
46438889Sjdp	      break;
46538889Sjdp	    case REG_M:
46638889Sjdp	      rm = nibs[n];
46738889Sjdp	      break;
46838889Sjdp	    case REG_NM:
46938889Sjdp	      rn = (nibs[n] & 0xc) >> 2;
47038889Sjdp	      rm = (nibs[n] & 0x3);
47138889Sjdp	      break;
47238889Sjdp	    case REG_B:
47338889Sjdp	      rb = nibs[n] & 0x07;
47485815Sobrien	      break;
47560484Sobrien	    case SDT_REG_N:
47660484Sobrien	      /* sh-dsp: single data transfer.  */
47760484Sobrien	      rn = nibs[n];
47860484Sobrien	      if ((rn & 0xc) != 4)
47960484Sobrien		goto fail;
48060484Sobrien	      rn = rn & 0x3;
48185815Sobrien	      rn |= (!(rn & 2)) << 2;
48260484Sobrien	      break;
48360484Sobrien	    case PPI:
48485815Sobrien	    case REPEAT:
48560484Sobrien	      goto fail;
48638889Sjdp	    default:
48785815Sobrien	      abort ();
48838889Sjdp	    }
48938889Sjdp	}
49033965Sjdp
49133965Sjdp    ok:
49285815Sobrien      fprintf_fn (stream, "%s\t", op->name);
49338889Sjdp      disp_pc = 0;
49485815Sobrien      for (n = 0; n < 3 && op->arg[n] != A_END; n++)
49533965Sjdp	{
49633965Sjdp	  if (n && op->arg[1] != A_END)
49738889Sjdp	    fprintf_fn (stream, ",");
49885815Sobrien	  switch (op->arg[n])
49933965Sjdp	    {
50033965Sjdp	    case A_IMM:
50185815Sobrien	      fprintf_fn (stream, "#%d", (char) (imm));
50233965Sjdp	      break;
50333965Sjdp	    case A_R0:
50438889Sjdp	      fprintf_fn (stream, "r0");
50533965Sjdp	      break;
50633965Sjdp	    case A_REG_N:
50738889Sjdp	      fprintf_fn (stream, "r%d", rn);
50833965Sjdp	      break;
50933965Sjdp	    case A_INC_N:
51085815Sobrien	      fprintf_fn (stream, "@r%d+", rn);
51133965Sjdp	      break;
51233965Sjdp	    case A_DEC_N:
51385815Sobrien	      fprintf_fn (stream, "@-r%d", rn);
51433965Sjdp	      break;
51533965Sjdp	    case A_IND_N:
51685815Sobrien	      fprintf_fn (stream, "@r%d", rn);
51733965Sjdp	      break;
51833965Sjdp	    case A_DISP_REG_N:
51985815Sobrien	      fprintf_fn (stream, "@(%d,r%d)", imm, rn);
52033965Sjdp	      break;
52160484Sobrien	    case A_PMOD_N:
52285815Sobrien	      fprintf_fn (stream, "@r%d+r8", rn);
52360484Sobrien	      break;
52433965Sjdp	    case A_REG_M:
52538889Sjdp	      fprintf_fn (stream, "r%d", rm);
52633965Sjdp	      break;
52733965Sjdp	    case A_INC_M:
52885815Sobrien	      fprintf_fn (stream, "@r%d+", rm);
52933965Sjdp	      break;
53033965Sjdp	    case A_DEC_M:
53185815Sobrien	      fprintf_fn (stream, "@-r%d", rm);
53233965Sjdp	      break;
53333965Sjdp	    case A_IND_M:
53485815Sobrien	      fprintf_fn (stream, "@r%d", rm);
53533965Sjdp	      break;
53633965Sjdp	    case A_DISP_REG_M:
53785815Sobrien	      fprintf_fn (stream, "@(%d,r%d)", imm, rm);
53833965Sjdp	      break;
53938889Sjdp	    case A_REG_B:
54038889Sjdp	      fprintf_fn (stream, "r%d_bank", rb);
54133965Sjdp	      break;
54233965Sjdp	    case A_DISP_PC:
54338889Sjdp	      disp_pc = 1;
54438889Sjdp	      disp_pc_addr = imm + 4 + (memaddr & relmask);
54538889Sjdp	      (*info->print_address_func) (disp_pc_addr, info);
54633965Sjdp	      break;
54733965Sjdp	    case A_IND_R0_REG_N:
54838889Sjdp	      fprintf_fn (stream, "@(r0,r%d)", rn);
54985815Sobrien	      break;
55033965Sjdp	    case A_IND_R0_REG_M:
55138889Sjdp	      fprintf_fn (stream, "@(r0,r%d)", rm);
55285815Sobrien	      break;
55333965Sjdp	    case A_DISP_GBR:
55485815Sobrien	      fprintf_fn (stream, "@(%d,gbr)", imm);
55533965Sjdp	      break;
55633965Sjdp	    case A_R0_GBR:
55738889Sjdp	      fprintf_fn (stream, "@(r0,gbr)");
55833965Sjdp	      break;
55933965Sjdp	    case A_BDISP12:
56033965Sjdp	    case A_BDISP8:
56133965Sjdp	      (*info->print_address_func) (imm + memaddr, info);
56233965Sjdp	      break;
56333965Sjdp	    case A_SR:
56438889Sjdp	      fprintf_fn (stream, "sr");
56533965Sjdp	      break;
56633965Sjdp	    case A_GBR:
56738889Sjdp	      fprintf_fn (stream, "gbr");
56833965Sjdp	      break;
56933965Sjdp	    case A_VBR:
57038889Sjdp	      fprintf_fn (stream, "vbr");
57133965Sjdp	      break;
57260484Sobrien	    case A_DSR:
57360484Sobrien	      fprintf_fn (stream, "dsr");
57460484Sobrien	      break;
57560484Sobrien	    case A_MOD:
57660484Sobrien	      fprintf_fn (stream, "mod");
57760484Sobrien	      break;
57860484Sobrien	    case A_RE:
57960484Sobrien	      fprintf_fn (stream, "re");
58060484Sobrien	      break;
58160484Sobrien	    case A_RS:
58260484Sobrien	      fprintf_fn (stream, "rs");
58360484Sobrien	      break;
58460484Sobrien	    case A_A0:
58560484Sobrien	      fprintf_fn (stream, "a0");
58660484Sobrien	      break;
58760484Sobrien	    case A_X0:
58860484Sobrien	      fprintf_fn (stream, "x0");
58960484Sobrien	      break;
59060484Sobrien	    case A_X1:
59160484Sobrien	      fprintf_fn (stream, "x1");
59260484Sobrien	      break;
59360484Sobrien	    case A_Y0:
59460484Sobrien	      fprintf_fn (stream, "y0");
59560484Sobrien	      break;
59660484Sobrien	    case A_Y1:
59760484Sobrien	      fprintf_fn (stream, "y1");
59860484Sobrien	      break;
59960484Sobrien	    case DSP_REG_M:
60060484Sobrien	      print_dsp_reg (rm, fprintf_fn, stream);
60160484Sobrien	      break;
60233965Sjdp	    case A_SSR:
60338889Sjdp	      fprintf_fn (stream, "ssr");
60433965Sjdp	      break;
60533965Sjdp	    case A_SPC:
60638889Sjdp	      fprintf_fn (stream, "spc");
60733965Sjdp	      break;
60833965Sjdp	    case A_MACH:
60938889Sjdp	      fprintf_fn (stream, "mach");
61033965Sjdp	      break;
61133965Sjdp	    case A_MACL:
61285815Sobrien	      fprintf_fn (stream, "macl");
61333965Sjdp	      break;
61433965Sjdp	    case A_PR:
61538889Sjdp	      fprintf_fn (stream, "pr");
61633965Sjdp	      break;
61738889Sjdp	    case A_SGR:
61838889Sjdp	      fprintf_fn (stream, "sgr");
61938889Sjdp	      break;
62038889Sjdp	    case A_DBR:
62138889Sjdp	      fprintf_fn (stream, "dbr");
62238889Sjdp	      break;
62333965Sjdp	    case F_REG_N:
62438889Sjdp	      fprintf_fn (stream, "fr%d", rn);
62533965Sjdp	      break;
62633965Sjdp	    case F_REG_M:
62738889Sjdp	      fprintf_fn (stream, "fr%d", rm);
62833965Sjdp	      break;
62938889Sjdp	    case DX_REG_N:
63038889Sjdp	      if (rn & 1)
63138889Sjdp		{
63238889Sjdp		  fprintf_fn (stream, "xd%d", rn & ~1);
63338889Sjdp		  break;
63438889Sjdp		}
63538889Sjdp	    case D_REG_N:
63638889Sjdp	      fprintf_fn (stream, "dr%d", rn);
63738889Sjdp	      break;
63838889Sjdp	    case DX_REG_M:
63938889Sjdp	      if (rm & 1)
64038889Sjdp		{
64138889Sjdp		  fprintf_fn (stream, "xd%d", rm & ~1);
64238889Sjdp		  break;
64338889Sjdp		}
64438889Sjdp	    case D_REG_M:
64538889Sjdp	      fprintf_fn (stream, "dr%d", rm);
64638889Sjdp	      break;
64733965Sjdp	    case FPSCR_M:
64833965Sjdp	    case FPSCR_N:
64938889Sjdp	      fprintf_fn (stream, "fpscr");
65033965Sjdp	      break;
65133965Sjdp	    case FPUL_M:
65233965Sjdp	    case FPUL_N:
65338889Sjdp	      fprintf_fn (stream, "fpul");
65433965Sjdp	      break;
65533965Sjdp	    case F_FR0:
65638889Sjdp	      fprintf_fn (stream, "fr0");
65733965Sjdp	      break;
65838889Sjdp	    case V_REG_N:
65985815Sobrien	      fprintf_fn (stream, "fv%d", rn * 4);
66038889Sjdp	      break;
66138889Sjdp	    case V_REG_M:
66285815Sobrien	      fprintf_fn (stream, "fv%d", rm * 4);
66338889Sjdp	      break;
66438889Sjdp	    case XMTRX_M4:
66538889Sjdp	      fprintf_fn (stream, "xmtrx");
66638889Sjdp	      break;
66733965Sjdp	    default:
66885815Sobrien	      abort ();
66933965Sjdp	    }
67033965Sjdp	}
67138889Sjdp
67238889Sjdp#if 0
67338889Sjdp      /* This code prints instructions in delay slots on the same line
67438889Sjdp         as the instruction which needs the delay slots.  This can be
67538889Sjdp         confusing, since other disassembler don't work this way, and
67638889Sjdp         it means that the instructions are not all in a line.  So I
67738889Sjdp         disabled it.  Ian.  */
67833965Sjdp      if (!(info->flags & 1)
67933965Sjdp	  && (op->name[0] == 'j'
68033965Sjdp	      || (op->name[0] == 'b'
68185815Sobrien		  && (op->name[1] == 'r'
68233965Sjdp		      || op->name[1] == 's'))
68333965Sjdp	      || (op->name[0] == 'r' && op->name[1] == 't')
68433965Sjdp	      || (op->name[0] == 'b' && op->name[2] == '.')))
68533965Sjdp	{
68633965Sjdp	  info->flags |= 1;
68738889Sjdp	  fprintf_fn (stream, "\t(slot ");
688104834Sobrien	  print_insn_sh (memaddr + 2, info);
68933965Sjdp	  info->flags &= ~1;
69038889Sjdp	  fprintf_fn (stream, ")");
69133965Sjdp	  return 4;
69233965Sjdp	}
69338889Sjdp#endif
69438889Sjdp
69538889Sjdp      if (disp_pc && strcmp (op->name, "mova") != 0)
69638889Sjdp	{
69738889Sjdp	  int size;
69838889Sjdp	  bfd_byte bytes[4];
69938889Sjdp
70085815Sobrien	  if (relmask == ~(bfd_vma) 1)
70138889Sjdp	    size = 2;
70238889Sjdp	  else
70338889Sjdp	    size = 4;
70438889Sjdp	  status = info->read_memory_func (disp_pc_addr, bytes, size, info);
70538889Sjdp	  if (status == 0)
70638889Sjdp	    {
70738889Sjdp	      unsigned int val;
70838889Sjdp
70938889Sjdp	      if (size == 2)
71038889Sjdp		{
711104834Sobrien		  if (info->endian == BFD_ENDIAN_LITTLE)
71238889Sjdp		    val = bfd_getl16 (bytes);
71338889Sjdp		  else
71438889Sjdp		    val = bfd_getb16 (bytes);
71538889Sjdp		}
71638889Sjdp	      else
71738889Sjdp		{
718104834Sobrien		  if (info->endian == BFD_ENDIAN_LITTLE)
71938889Sjdp		    val = bfd_getl32 (bytes);
72038889Sjdp		  else
72138889Sjdp		    val = bfd_getb32 (bytes);
72238889Sjdp		}
72338889Sjdp	      fprintf_fn (stream, "\t! 0x%x", val);
72438889Sjdp	    }
72538889Sjdp	}
72638889Sjdp
72733965Sjdp      return 2;
72833965Sjdp    fail:
72933965Sjdp      ;
73033965Sjdp
73133965Sjdp    }
73238889Sjdp  fprintf_fn (stream, ".word 0x%x%x%x%x", nibs[0], nibs[1], nibs[2], nibs[3]);
73333965Sjdp  return 2;
73433965Sjdp}
735