133965Sjdp/* Disassemble SH instructions.
2218822Sdim   Copyright 1993, 1994, 1995, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005
385815Sobrien   Free Software Foundation, Inc.
433965Sjdp
5130561Sobrien   This program is free software; you can redistribute it and/or modify
6130561Sobrien   it under the terms of the GNU General Public License as published by
7130561Sobrien   the Free Software Foundation; either version 2 of the License, or
8130561Sobrien   (at your option) any later version.
933965Sjdp
10130561Sobrien   This program is distributed in the hope that it will be useful,
11130561Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
12130561Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13130561Sobrien   GNU General Public License for more details.
1433965Sjdp
15130561Sobrien   You should have received a copy of the GNU General Public License
16130561Sobrien   along with this program; if not, write to the Free Software
17218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
18218822Sdim   MA 02110-1301, USA.  */
1933965Sjdp
2085815Sobrien#include <stdio.h>
2160484Sobrien#include "sysdep.h"
2233965Sjdp#define STATIC_TABLE
2333965Sjdp#define DEFINE_TABLE
2433965Sjdp
2533965Sjdp#include "sh-opc.h"
2633965Sjdp#include "dis-asm.h"
2733965Sjdp
28130561Sobrien#ifdef ARCH_all
29130561Sobrien#define INCLUDE_SHMEDIA
30130561Sobrien#endif
31130561Sobrien
3260484Sobrienstatic void
33218822Sdimprint_movxy (const sh_opcode_info *op,
34218822Sdim	     int rn,
35218822Sdim	     int rm,
36218822Sdim	     fprintf_ftype fprintf_fn,
37218822Sdim	     void *stream)
3860484Sobrien{
3960484Sobrien  int n;
4060484Sobrien
4185815Sobrien  fprintf_fn (stream, "%s\t", op->name);
4260484Sobrien  for (n = 0; n < 2; n++)
4360484Sobrien    {
4460484Sobrien      switch (op->arg[n])
4560484Sobrien	{
4660484Sobrien	case A_IND_N:
47130561Sobrien	case AX_IND_N:
48130561Sobrien	case AXY_IND_N:
49130561Sobrien	case AY_IND_N:
50130561Sobrien	case AYX_IND_N:
5185815Sobrien	  fprintf_fn (stream, "@r%d", rn);
5260484Sobrien	  break;
5360484Sobrien	case A_INC_N:
54130561Sobrien	case AX_INC_N:
55130561Sobrien	case AXY_INC_N:
56130561Sobrien	case AY_INC_N:
57130561Sobrien	case AYX_INC_N:
5885815Sobrien	  fprintf_fn (stream, "@r%d+", rn);
5960484Sobrien	  break;
60130561Sobrien	case AX_PMOD_N:
61130561Sobrien	case AXY_PMOD_N:
6285815Sobrien	  fprintf_fn (stream, "@r%d+r8", rn);
6360484Sobrien	  break;
64130561Sobrien	case AY_PMOD_N:
65130561Sobrien	case AYX_PMOD_N:
6685815Sobrien	  fprintf_fn (stream, "@r%d+r9", rn);
6760484Sobrien	  break;
68130561Sobrien	case DSP_REG_A_M:
6960484Sobrien	  fprintf_fn (stream, "a%c", '0' + rm);
7060484Sobrien	  break;
7160484Sobrien	case DSP_REG_X:
7260484Sobrien	  fprintf_fn (stream, "x%c", '0' + rm);
7360484Sobrien	  break;
7460484Sobrien	case DSP_REG_Y:
7560484Sobrien	  fprintf_fn (stream, "y%c", '0' + rm);
7660484Sobrien	  break;
77130561Sobrien	case DSP_REG_AX:
78130561Sobrien	  fprintf_fn (stream, "%c%c",
79130561Sobrien		      (rm & 1) ? 'x' : 'a',
80130561Sobrien		      (rm & 2) ? '1' : '0');
81130561Sobrien	  break;
82130561Sobrien	case DSP_REG_XY:
83130561Sobrien	  fprintf_fn (stream, "%c%c",
84130561Sobrien		      (rm & 1) ? 'y' : 'x',
85130561Sobrien		      (rm & 2) ? '1' : '0');
86130561Sobrien	  break;
87130561Sobrien	case DSP_REG_AY:
88130561Sobrien	  fprintf_fn (stream, "%c%c",
89130561Sobrien		      (rm & 2) ? 'y' : 'a',
90130561Sobrien		      (rm & 1) ? '1' : '0');
91130561Sobrien	  break;
92130561Sobrien	case DSP_REG_YX:
93130561Sobrien	  fprintf_fn (stream, "%c%c",
94130561Sobrien		      (rm & 2) ? 'x' : 'y',
95130561Sobrien		      (rm & 1) ? '1' : '0');
96130561Sobrien	  break;
9760484Sobrien	default:
9860484Sobrien	  abort ();
9960484Sobrien	}
10060484Sobrien      if (n == 0)
10185815Sobrien	fprintf_fn (stream, ",");
10260484Sobrien    }
10360484Sobrien}
10460484Sobrien
10560484Sobrien/* Print a double data transfer insn.  INSN is just the lower three
10660484Sobrien   nibbles of the insn, i.e. field a and the bit that indicates if
10760484Sobrien   a parallel processing insn follows.
10860484Sobrien   Return nonzero if a field b of a parallel processing insns follows.  */
10985815Sobrien
11060484Sobrienstatic void
111218822Sdimprint_insn_ddt (int insn, struct disassemble_info *info)
11260484Sobrien{
11360484Sobrien  fprintf_ftype fprintf_fn = info->fprintf_func;
11460484Sobrien  void *stream = info->stream;
11560484Sobrien
11660484Sobrien  /* If this is just a nop, make sure to emit something.  */
11760484Sobrien  if (insn == 0x000)
11860484Sobrien    fprintf_fn (stream, "nopx\tnopy");
11960484Sobrien
12060484Sobrien  /* If a parallel processing insn was printed before,
12160484Sobrien     and we got a non-nop, emit a tab.  */
12260484Sobrien  if ((insn & 0x800) && (insn & 0x3ff))
12360484Sobrien    fprintf_fn (stream, "\t");
12460484Sobrien
12560484Sobrien  /* Check if either the x or y part is invalid.  */
12660484Sobrien  if (((insn & 0xc) == 0 && (insn & 0x2a0))
12760484Sobrien      || ((insn & 3) == 0 && (insn & 0x150)))
128130561Sobrien    if (info->mach != bfd_mach_sh_dsp
129130561Sobrien        && info->mach != bfd_mach_sh3_dsp)
130130561Sobrien      {
131130561Sobrien	static const sh_opcode_info *first_movx, *first_movy;
132130561Sobrien	const sh_opcode_info *op;
133130561Sobrien	int is_movy;
134130561Sobrien
135130561Sobrien	if (! first_movx)
136130561Sobrien	  {
137130561Sobrien	    for (first_movx = sh_table; first_movx->nibbles[1] != MOVX_NOPY;)
138130561Sobrien	      first_movx++;
139130561Sobrien	    for (first_movy = first_movx; first_movy->nibbles[1] != MOVY_NOPX;)
140130561Sobrien	      first_movy++;
141130561Sobrien	  }
142130561Sobrien
143130561Sobrien	is_movy = ((insn & 3) != 0);
144130561Sobrien
145130561Sobrien	if (is_movy)
146130561Sobrien	  op = first_movy;
147130561Sobrien	else
148130561Sobrien	  op = first_movx;
149130561Sobrien
150130561Sobrien	while (op->nibbles[2] != (unsigned) ((insn >> 4) & 3)
151130561Sobrien	       || op->nibbles[3] != (unsigned) (insn & 0xf))
152130561Sobrien	  op++;
153130561Sobrien
154130561Sobrien	print_movxy (op,
155130561Sobrien		     (4 * ((insn & (is_movy ? 0x200 : 0x100)) == 0)
156130561Sobrien		      + 2 * is_movy
157130561Sobrien		      + 1 * ((insn & (is_movy ? 0x100 : 0x200)) != 0)),
158130561Sobrien		     (insn >> 6) & 3,
159130561Sobrien		     fprintf_fn, stream);
160130561Sobrien      }
161130561Sobrien    else
162130561Sobrien      fprintf_fn (stream, ".word 0x%x", insn);
16360484Sobrien  else
16460484Sobrien    {
165130561Sobrien      static const sh_opcode_info *first_movx, *first_movy;
166130561Sobrien      const sh_opcode_info *opx, *opy;
16785815Sobrien      unsigned int insn_x, insn_y;
16860484Sobrien
16960484Sobrien      if (! first_movx)
17060484Sobrien	{
17185815Sobrien	  for (first_movx = sh_table; first_movx->nibbles[1] != MOVX;)
17260484Sobrien	    first_movx++;
17385815Sobrien	  for (first_movy = first_movx; first_movy->nibbles[1] != MOVY;)
17460484Sobrien	    first_movy++;
17560484Sobrien	}
17660484Sobrien      insn_x = (insn >> 2) & 0xb;
17760484Sobrien      if (insn_x)
17860484Sobrien	{
17985815Sobrien	  for (opx = first_movx; opx->nibbles[2] != insn_x;)
18085815Sobrien	    opx++;
18160484Sobrien	  print_movxy (opx, ((insn >> 9) & 1) + 4, (insn >> 7) & 1,
18260484Sobrien		       fprintf_fn, stream);
18360484Sobrien	}
18460484Sobrien      insn_y = (insn & 3) | ((insn >> 1) & 8);
18560484Sobrien      if (insn_y)
18660484Sobrien	{
18760484Sobrien	  if (insn_x)
18860484Sobrien	    fprintf_fn (stream, "\t");
18985815Sobrien	  for (opy = first_movy; opy->nibbles[2] != insn_y;)
19085815Sobrien	    opy++;
19160484Sobrien	  print_movxy (opy, ((insn >> 8) & 1) + 6, (insn >> 6) & 1,
19260484Sobrien		       fprintf_fn, stream);
19360484Sobrien	}
19460484Sobrien    }
19560484Sobrien}
19660484Sobrien
19760484Sobrienstatic void
198218822Sdimprint_dsp_reg (int rm, fprintf_ftype fprintf_fn, void *stream)
19960484Sobrien{
20060484Sobrien  switch (rm)
20160484Sobrien    {
20260484Sobrien    case A_A1_NUM:
20360484Sobrien      fprintf_fn (stream, "a1");
20460484Sobrien      break;
20560484Sobrien    case A_A0_NUM:
20660484Sobrien      fprintf_fn (stream, "a0");
20760484Sobrien      break;
20860484Sobrien    case A_X0_NUM:
20960484Sobrien      fprintf_fn (stream, "x0");
21060484Sobrien      break;
21160484Sobrien    case A_X1_NUM:
21260484Sobrien      fprintf_fn (stream, "x1");
21360484Sobrien      break;
21460484Sobrien    case A_Y0_NUM:
21560484Sobrien      fprintf_fn (stream, "y0");
21660484Sobrien      break;
21760484Sobrien    case A_Y1_NUM:
21860484Sobrien      fprintf_fn (stream, "y1");
21960484Sobrien      break;
22060484Sobrien    case A_M0_NUM:
22160484Sobrien      fprintf_fn (stream, "m0");
22260484Sobrien      break;
22360484Sobrien    case A_A1G_NUM:
22460484Sobrien      fprintf_fn (stream, "a1g");
22560484Sobrien      break;
22660484Sobrien    case A_M1_NUM:
22760484Sobrien      fprintf_fn (stream, "m1");
22860484Sobrien      break;
22960484Sobrien    case A_A0G_NUM:
23060484Sobrien      fprintf_fn (stream, "a0g");
23160484Sobrien      break;
23260484Sobrien    default:
23360484Sobrien      fprintf_fn (stream, "0x%x", rm);
23460484Sobrien      break;
23560484Sobrien    }
23660484Sobrien}
23760484Sobrien
23860484Sobrienstatic void
239218822Sdimprint_insn_ppi (int field_b, struct disassemble_info *info)
24060484Sobrien{
24185815Sobrien  static char *sx_tab[] = { "x0", "x1", "a0", "a1" };
24285815Sobrien  static char *sy_tab[] = { "y0", "y1", "m0", "m1" };
24360484Sobrien  fprintf_ftype fprintf_fn = info->fprintf_func;
24460484Sobrien  void *stream = info->stream;
24585815Sobrien  unsigned int nib1, nib2, nib3;
246130561Sobrien  unsigned int altnib1, nib4;
24785815Sobrien  char *dc = NULL;
248130561Sobrien  const sh_opcode_info *op;
24960484Sobrien
25060484Sobrien  if ((field_b & 0xe800) == 0)
25160484Sobrien    {
25260484Sobrien      fprintf_fn (stream, "psh%c\t#%d,",
25360484Sobrien		  field_b & 0x1000 ? 'a' : 'l',
25460484Sobrien		  (field_b >> 4) & 127);
25560484Sobrien      print_dsp_reg (field_b & 0xf, fprintf_fn, stream);
25660484Sobrien      return;
25760484Sobrien    }
25860484Sobrien  if ((field_b & 0xc000) == 0x4000 && (field_b & 0x3000) != 0x1000)
25960484Sobrien    {
26085815Sobrien      static char *du_tab[] = { "x0", "y0", "a0", "a1" };
26185815Sobrien      static char *se_tab[] = { "x0", "x1", "y0", "a1" };
26285815Sobrien      static char *sf_tab[] = { "y0", "y1", "x0", "a1" };
26385815Sobrien      static char *sg_tab[] = { "m0", "m1", "a0", "a1" };
26460484Sobrien
26560484Sobrien      if (field_b & 0x2000)
266218822Sdim	fprintf_fn (stream, "p%s %s,%s,%s\t",
267218822Sdim		    (field_b & 0x1000) ? "add" : "sub",
268218822Sdim		    sx_tab[(field_b >> 6) & 3],
269218822Sdim		    sy_tab[(field_b >> 4) & 3],
270218822Sdim		    du_tab[(field_b >> 0) & 3]);
271218822Sdim
272130561Sobrien      else if ((field_b & 0xf0) == 0x10
273130561Sobrien	       && info->mach != bfd_mach_sh_dsp
274130561Sobrien	       && info->mach != bfd_mach_sh3_dsp)
275218822Sdim	fprintf_fn (stream, "pclr %s \t", du_tab[(field_b >> 0) & 3]);
276218822Sdim
277130561Sobrien      else if ((field_b & 0xf3) != 0)
278218822Sdim	fprintf_fn (stream, ".word 0x%x\t", field_b);
279218822Sdim
28060484Sobrien      fprintf_fn (stream, "pmuls%c%s,%s,%s",
28160484Sobrien		  field_b & 0x2000 ? ' ' : '\t',
28260484Sobrien		  se_tab[(field_b >> 10) & 3],
28360484Sobrien		  sf_tab[(field_b >>  8) & 3],
28460484Sobrien		  sg_tab[(field_b >>  2) & 3]);
28560484Sobrien      return;
28660484Sobrien    }
28760484Sobrien
28860484Sobrien  nib1 = PPIC;
28960484Sobrien  nib2 = field_b >> 12 & 0xf;
29060484Sobrien  nib3 = field_b >> 8 & 0xf;
291130561Sobrien  nib4 = field_b >> 4 & 0xf;
29260484Sobrien  switch (nib3 & 0x3)
29360484Sobrien    {
29460484Sobrien    case 0:
29560484Sobrien      dc = "";
29660484Sobrien      nib1 = PPI3;
29760484Sobrien      break;
29860484Sobrien    case 1:
29960484Sobrien      dc = "";
30060484Sobrien      break;
30160484Sobrien    case 2:
30260484Sobrien      dc = "dct ";
30360484Sobrien      nib3 -= 1;
30460484Sobrien      break;
30560484Sobrien    case 3:
30660484Sobrien      dc = "dcf ";
30760484Sobrien      nib3 -= 2;
30860484Sobrien      break;
30960484Sobrien    }
310130561Sobrien  if (nib1 == PPI3)
311130561Sobrien    altnib1 = PPI3NC;
312130561Sobrien  else
313130561Sobrien    altnib1 = nib1;
31460484Sobrien  for (op = sh_table; op->name; op++)
31560484Sobrien    {
316130561Sobrien      if ((op->nibbles[1] == nib1 || op->nibbles[1] == altnib1)
31760484Sobrien	  && op->nibbles[2] == nib2
31860484Sobrien	  && op->nibbles[3] == nib3)
31960484Sobrien	{
32060484Sobrien	  int n;
32160484Sobrien
322130561Sobrien	  switch (op->nibbles[4])
323130561Sobrien	    {
324130561Sobrien	    case HEX_0:
325130561Sobrien	      break;
326130561Sobrien	    case HEX_XX00:
327130561Sobrien	      if ((nib4 & 3) != 0)
328130561Sobrien		continue;
329130561Sobrien	      break;
330130561Sobrien	    case HEX_1:
331130561Sobrien	      if ((nib4 & 3) != 1)
332130561Sobrien		continue;
333130561Sobrien	      break;
334130561Sobrien	    case HEX_00YY:
335130561Sobrien	      if ((nib4 & 0xc) != 0)
336130561Sobrien		continue;
337130561Sobrien	      break;
338130561Sobrien	    case HEX_4:
339130561Sobrien	      if ((nib4 & 0xc) != 4)
340130561Sobrien		continue;
341130561Sobrien	      break;
342130561Sobrien	    default:
343130561Sobrien	      abort ();
344130561Sobrien	    }
34560484Sobrien	  fprintf_fn (stream, "%s%s\t", dc, op->name);
34685815Sobrien	  for (n = 0; n < 3 && op->arg[n] != A_END; n++)
34760484Sobrien	    {
34860484Sobrien	      if (n && op->arg[1] != A_END)
34960484Sobrien		fprintf_fn (stream, ",");
35085815Sobrien	      switch (op->arg[n])
35160484Sobrien		{
35260484Sobrien		case DSP_REG_N:
35360484Sobrien		  print_dsp_reg (field_b & 0xf, fprintf_fn, stream);
35460484Sobrien		  break;
35560484Sobrien		case DSP_REG_X:
35660484Sobrien		  fprintf_fn (stream, sx_tab[(field_b >> 6) & 3]);
35760484Sobrien		  break;
35860484Sobrien		case DSP_REG_Y:
35960484Sobrien		  fprintf_fn (stream, sy_tab[(field_b >> 4) & 3]);
36060484Sobrien		  break;
36160484Sobrien		case A_MACH:
36260484Sobrien		  fprintf_fn (stream, "mach");
36360484Sobrien		  break;
36460484Sobrien		case A_MACL:
36585815Sobrien		  fprintf_fn (stream, "macl");
36660484Sobrien		  break;
36760484Sobrien		default:
36860484Sobrien		  abort ();
36960484Sobrien		}
37060484Sobrien	    }
37160484Sobrien	  return;
37260484Sobrien	}
37360484Sobrien    }
37460484Sobrien  /* Not found.  */
37560484Sobrien  fprintf_fn (stream, ".word 0x%x", field_b);
37660484Sobrien}
37760484Sobrien
378218822Sdim/* FIXME mvs: movx insns print as ".word 0x%03x", insn & 0xfff
379218822Sdim   (ie. the upper nibble is missing).  */
380218822Sdim
381104834Sobrienint
382218822Sdimprint_insn_sh (bfd_vma memaddr, struct disassemble_info *info)
38333965Sjdp{
38438889Sjdp  fprintf_ftype fprintf_fn = info->fprintf_func;
38533965Sjdp  void *stream = info->stream;
386130561Sobrien  unsigned char insn[4];
387218822Sdim  unsigned char nibs[8];
38833965Sjdp  int status;
38985815Sobrien  bfd_vma relmask = ~(bfd_vma) 0;
390130561Sobrien  const sh_opcode_info *op;
391218822Sdim  unsigned int target_arch;
392218822Sdim  int allow_op32;
39333965Sjdp
39460484Sobrien  switch (info->mach)
39560484Sobrien    {
39660484Sobrien    case bfd_mach_sh:
39760484Sobrien      target_arch = arch_sh1;
398104834Sobrien      /* SH coff object files lack information about the machine type, so
399104834Sobrien         we end up with bfd_mach_sh unless it was set explicitly (which
400104834Sobrien	 could have happended if this is a call from gdb or the simulator.)  */
401104834Sobrien      if (info->symbols
402104834Sobrien	  && bfd_asymbol_flavour(*info->symbols) == bfd_target_coff_flavour)
403104834Sobrien	target_arch = arch_sh4;
40460484Sobrien      break;
40591041Sobrien    case bfd_mach_sh5:
406104834Sobrien#ifdef INCLUDE_SHMEDIA
407104834Sobrien      status = print_insn_sh64 (memaddr, info);
408104834Sobrien      if (status != -2)
409104834Sobrien	return status;
410104834Sobrien#endif
41191041Sobrien      /* When we get here for sh64, it's because we want to disassemble
41291041Sobrien	 SHcompact, i.e. arch_sh4.  */
41391041Sobrien      target_arch = arch_sh4;
41491041Sobrien      break;
41560484Sobrien    default:
416218822Sdim      target_arch = sh_get_arch_from_bfd_mach (info->mach);
41760484Sobrien    }
41860484Sobrien
41938889Sjdp  status = info->read_memory_func (memaddr, insn, 2, info);
42038889Sjdp
42185815Sobrien  if (status != 0)
42233965Sjdp    {
42338889Sjdp      info->memory_error_func (status, memaddr, info);
42433965Sjdp      return -1;
42533965Sjdp    }
42633965Sjdp
427104834Sobrien  if (info->endian == BFD_ENDIAN_LITTLE)
42833965Sjdp    {
42933965Sjdp      nibs[0] = (insn[1] >> 4) & 0xf;
43033965Sjdp      nibs[1] = insn[1] & 0xf;
43133965Sjdp
43233965Sjdp      nibs[2] = (insn[0] >> 4) & 0xf;
43333965Sjdp      nibs[3] = insn[0] & 0xf;
43433965Sjdp    }
43585815Sobrien  else
43633965Sjdp    {
43733965Sjdp      nibs[0] = (insn[0] >> 4) & 0xf;
43833965Sjdp      nibs[1] = insn[0] & 0xf;
43933965Sjdp
44033965Sjdp      nibs[2] = (insn[1] >> 4) & 0xf;
44133965Sjdp      nibs[3] = insn[1] & 0xf;
44233965Sjdp    }
443218822Sdim  status = info->read_memory_func (memaddr + 2, insn + 2, 2, info);
444218822Sdim  if (status != 0)
445218822Sdim    allow_op32 = 0;
446218822Sdim  else
447218822Sdim    {
448218822Sdim      allow_op32 = 1;
44933965Sjdp
450218822Sdim      if (info->endian == BFD_ENDIAN_LITTLE)
451218822Sdim	{
452218822Sdim	  nibs[4] = (insn[3] >> 4) & 0xf;
453218822Sdim	  nibs[5] = insn[3] & 0xf;
454218822Sdim
455218822Sdim	  nibs[6] = (insn[2] >> 4) & 0xf;
456218822Sdim	  nibs[7] = insn[2] & 0xf;
457218822Sdim	}
458218822Sdim      else
459218822Sdim	{
460218822Sdim	  nibs[4] = (insn[2] >> 4) & 0xf;
461218822Sdim	  nibs[5] = insn[2] & 0xf;
462218822Sdim
463218822Sdim	  nibs[6] = (insn[3] >> 4) & 0xf;
464218822Sdim	  nibs[7] = insn[3] & 0xf;
465218822Sdim	}
466218822Sdim    }
467218822Sdim
468218822Sdim  if (nibs[0] == 0xf && (nibs[1] & 4) == 0
469218822Sdim      && SH_MERGE_ARCH_SET_VALID (target_arch, arch_sh_dsp_up))
47060484Sobrien    {
47160484Sobrien      if (nibs[1] & 8)
47260484Sobrien	{
47360484Sobrien	  int field_b;
47460484Sobrien
47560484Sobrien	  status = info->read_memory_func (memaddr + 2, insn, 2, info);
47660484Sobrien
47785815Sobrien	  if (status != 0)
47860484Sobrien	    {
47960484Sobrien	      info->memory_error_func (status, memaddr + 2, info);
48060484Sobrien	      return -1;
48160484Sobrien	    }
48260484Sobrien
483104834Sobrien	  if (info->endian == BFD_ENDIAN_LITTLE)
48460484Sobrien	    field_b = insn[1] << 8 | insn[0];
48560484Sobrien	  else
48660484Sobrien	    field_b = insn[0] << 8 | insn[1];
48760484Sobrien
48860484Sobrien	  print_insn_ppi (field_b, info);
48960484Sobrien	  print_insn_ddt ((nibs[1] << 8) | (nibs[2] << 4) | nibs[3], info);
49060484Sobrien	  return 4;
49160484Sobrien	}
49260484Sobrien      print_insn_ddt ((nibs[1] << 8) | (nibs[2] << 4) | nibs[3], info);
49360484Sobrien      return 2;
49460484Sobrien    }
49585815Sobrien  for (op = sh_table; op->name; op++)
49633965Sjdp    {
49733965Sjdp      int n;
49838889Sjdp      int imm = 0;
49938889Sjdp      int rn = 0;
50038889Sjdp      int rm = 0;
50138889Sjdp      int rb = 0;
50238889Sjdp      int disp_pc;
50338889Sjdp      bfd_vma disp_pc_addr = 0;
504218822Sdim      int disp = 0;
505218822Sdim      int has_disp = 0;
506218822Sdim      int max_n = SH_MERGE_ARCH_SET (op->arch, arch_op32) ? 8 : 4;
50733965Sjdp
508218822Sdim      if (!allow_op32
509218822Sdim	  && SH_MERGE_ARCH_SET (op->arch, arch_op32))
51060484Sobrien	goto fail;
511218822Sdim
512218822Sdim      if (!SH_MERGE_ARCH_SET_VALID (op->arch, target_arch))
513218822Sdim	goto fail;
514218822Sdim      for (n = 0; n < max_n; n++)
51538889Sjdp	{
51638889Sjdp	  int i = op->nibbles[n];
51733965Sjdp
51885815Sobrien	  if (i < 16)
51938889Sjdp	    {
52038889Sjdp	      if (nibs[n] == i)
52138889Sjdp		continue;
52238889Sjdp	      goto fail;
52338889Sjdp	    }
52438889Sjdp	  switch (i)
52538889Sjdp	    {
52638889Sjdp	    case BRANCH_8:
52785815Sobrien	      imm = (nibs[2] << 4) | (nibs[3]);
52838889Sjdp	      if (imm & 0x80)
52938889Sjdp		imm |= ~0xff;
53085815Sobrien	      imm = ((char) imm) * 2 + 4;
53138889Sjdp	      goto ok;
53238889Sjdp	    case BRANCH_12:
53338889Sjdp	      imm = ((nibs[1]) << 8) | (nibs[2] << 4) | (nibs[3]);
53438889Sjdp	      if (imm & 0x800)
53538889Sjdp		imm |= ~0xfff;
53638889Sjdp	      imm = imm * 2 + 4;
53738889Sjdp	      goto ok;
538218822Sdim	    case IMM0_3c:
539218822Sdim	      if (nibs[3] & 0x8)
540218822Sdim		goto fail;
541218822Sdim	      imm = nibs[3] & 0x7;
542218822Sdim	      break;
543218822Sdim	    case IMM0_3s:
544218822Sdim	      if (!(nibs[3] & 0x8))
545218822Sdim		goto fail;
546218822Sdim	      imm = nibs[3] & 0x7;
547218822Sdim	      break;
548218822Sdim	    case IMM0_3Uc:
549218822Sdim	      if (nibs[2] & 0x8)
550218822Sdim		goto fail;
551218822Sdim	      imm = nibs[2] & 0x7;
552218822Sdim	      break;
553218822Sdim	    case IMM0_3Us:
554218822Sdim	      if (!(nibs[2] & 0x8))
555218822Sdim		goto fail;
556218822Sdim	      imm = nibs[2] & 0x7;
557218822Sdim	      break;
558218822Sdim	    case DISP0_12:
559218822Sdim	    case DISP1_12:
560218822Sdim	      disp = (nibs[5] << 8) | (nibs[6] << 4) | nibs[7];
561218822Sdim	      has_disp = 1;
562218822Sdim	      goto ok;
563218822Sdim	    case DISP0_12BY2:
564218822Sdim	    case DISP1_12BY2:
565218822Sdim	      disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 1;
566218822Sdim	      relmask = ~(bfd_vma) 1;
567218822Sdim	      has_disp = 1;
568218822Sdim	      goto ok;
569218822Sdim	    case DISP0_12BY4:
570218822Sdim	    case DISP1_12BY4:
571218822Sdim	      disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 2;
572218822Sdim	      relmask = ~(bfd_vma) 3;
573218822Sdim	      has_disp = 1;
574218822Sdim	      goto ok;
575218822Sdim	    case DISP0_12BY8:
576218822Sdim	    case DISP1_12BY8:
577218822Sdim	      disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 3;
578218822Sdim	      relmask = ~(bfd_vma) 7;
579218822Sdim	      has_disp = 1;
580218822Sdim	      goto ok;
581218822Sdim	    case IMM0_20_4:
582218822Sdim	      break;
583218822Sdim	    case IMM0_20:
584218822Sdim	      imm = ((nibs[2] << 16) | (nibs[4] << 12) | (nibs[5] << 8)
585218822Sdim		     | (nibs[6] << 4) | nibs[7]);
586218822Sdim	      if (imm & 0x80000)
587218822Sdim		imm -= 0x100000;
588218822Sdim	      goto ok;
589218822Sdim	    case IMM0_20BY8:
590218822Sdim	      imm = ((nibs[2] << 16) | (nibs[4] << 12) | (nibs[5] << 8)
591218822Sdim		     | (nibs[6] << 4) | nibs[7]);
592218822Sdim	      imm <<= 8;
593218822Sdim	      if (imm & 0x8000000)
594218822Sdim		imm -= 0x10000000;
595218822Sdim	      goto ok;
59685815Sobrien	    case IMM0_4:
59785815Sobrien	    case IMM1_4:
59838889Sjdp	      imm = nibs[3];
59938889Sjdp	      goto ok;
60085815Sobrien	    case IMM0_4BY2:
60185815Sobrien	    case IMM1_4BY2:
60285815Sobrien	      imm = nibs[3] << 1;
60338889Sjdp	      goto ok;
60485815Sobrien	    case IMM0_4BY4:
60585815Sobrien	    case IMM1_4BY4:
60685815Sobrien	      imm = nibs[3] << 2;
60738889Sjdp	      goto ok;
60885815Sobrien	    case IMM0_8:
60985815Sobrien	    case IMM1_8:
61038889Sjdp	      imm = (nibs[2] << 4) | nibs[3];
611218822Sdim	      disp = imm;
612218822Sdim	      has_disp = 1;
613218822Sdim	      if (imm & 0x80)
614218822Sdim		imm -= 0x100;
61538889Sjdp	      goto ok;
61638889Sjdp	    case PCRELIMM_8BY2:
61785815Sobrien	      imm = ((nibs[2] << 4) | nibs[3]) << 1;
61885815Sobrien	      relmask = ~(bfd_vma) 1;
61938889Sjdp	      goto ok;
62038889Sjdp	    case PCRELIMM_8BY4:
62185815Sobrien	      imm = ((nibs[2] << 4) | nibs[3]) << 2;
62285815Sobrien	      relmask = ~(bfd_vma) 3;
62338889Sjdp	      goto ok;
62485815Sobrien	    case IMM0_8BY2:
62585815Sobrien	    case IMM1_8BY2:
62685815Sobrien	      imm = ((nibs[2] << 4) | nibs[3]) << 1;
62738889Sjdp	      goto ok;
62885815Sobrien	    case IMM0_8BY4:
62985815Sobrien	    case IMM1_8BY4:
63085815Sobrien	      imm = ((nibs[2] << 4) | nibs[3]) << 2;
63138889Sjdp	      goto ok;
632130561Sobrien	    case REG_N_D:
633130561Sobrien	      if ((nibs[n] & 1) != 0)
634130561Sobrien		goto fail;
635218822Sdim	      /* Fall through.  */
63638889Sjdp	    case REG_N:
63738889Sjdp	      rn = nibs[n];
63838889Sjdp	      break;
63938889Sjdp	    case REG_M:
64038889Sjdp	      rm = nibs[n];
64138889Sjdp	      break;
642130561Sobrien	    case REG_N_B01:
643130561Sobrien	      if ((nibs[n] & 0x3) != 1 /* binary 01 */)
644130561Sobrien		goto fail;
645130561Sobrien	      rn = (nibs[n] & 0xc) >> 2;
646130561Sobrien	      break;
64738889Sjdp	    case REG_NM:
64838889Sjdp	      rn = (nibs[n] & 0xc) >> 2;
64938889Sjdp	      rm = (nibs[n] & 0x3);
65038889Sjdp	      break;
65138889Sjdp	    case REG_B:
65238889Sjdp	      rb = nibs[n] & 0x07;
65385815Sobrien	      break;
65460484Sobrien	    case SDT_REG_N:
65560484Sobrien	      /* sh-dsp: single data transfer.  */
65660484Sobrien	      rn = nibs[n];
65760484Sobrien	      if ((rn & 0xc) != 4)
65860484Sobrien		goto fail;
65960484Sobrien	      rn = rn & 0x3;
66085815Sobrien	      rn |= (!(rn & 2)) << 2;
66160484Sobrien	      break;
66260484Sobrien	    case PPI:
66385815Sobrien	    case REPEAT:
66460484Sobrien	      goto fail;
66538889Sjdp	    default:
66685815Sobrien	      abort ();
66738889Sjdp	    }
66838889Sjdp	}
66933965Sjdp
67033965Sjdp    ok:
671218822Sdim      /* sh2a has D_REG but not X_REG.  We don't know the pattern
672218822Sdim	 doesn't match unless we check the output args to see if they
673218822Sdim	 make sense.  */
674218822Sdim      if (target_arch == arch_sh2a
675218822Sdim	  && ((op->arg[0] == DX_REG_M && (rm & 1) != 0)
676218822Sdim	      || (op->arg[1] == DX_REG_N && (rn & 1) != 0)))
677218822Sdim	goto fail;
678218822Sdim
67985815Sobrien      fprintf_fn (stream, "%s\t", op->name);
68038889Sjdp      disp_pc = 0;
68185815Sobrien      for (n = 0; n < 3 && op->arg[n] != A_END; n++)
68233965Sjdp	{
68333965Sjdp	  if (n && op->arg[1] != A_END)
68438889Sjdp	    fprintf_fn (stream, ",");
68585815Sobrien	  switch (op->arg[n])
68633965Sjdp	    {
68733965Sjdp	    case A_IMM:
688218822Sdim	      fprintf_fn (stream, "#%d", imm);
68933965Sjdp	      break;
69033965Sjdp	    case A_R0:
69138889Sjdp	      fprintf_fn (stream, "r0");
69233965Sjdp	      break;
69333965Sjdp	    case A_REG_N:
69438889Sjdp	      fprintf_fn (stream, "r%d", rn);
69533965Sjdp	      break;
69633965Sjdp	    case A_INC_N:
697130561Sobrien	    case AS_INC_N:
69885815Sobrien	      fprintf_fn (stream, "@r%d+", rn);
69933965Sjdp	      break;
70033965Sjdp	    case A_DEC_N:
701130561Sobrien	    case AS_DEC_N:
70285815Sobrien	      fprintf_fn (stream, "@-r%d", rn);
70333965Sjdp	      break;
70433965Sjdp	    case A_IND_N:
705130561Sobrien	    case AS_IND_N:
70685815Sobrien	      fprintf_fn (stream, "@r%d", rn);
70733965Sjdp	      break;
70833965Sjdp	    case A_DISP_REG_N:
709218822Sdim	      fprintf_fn (stream, "@(%d,r%d)", has_disp?disp:imm, rn);
71033965Sjdp	      break;
711130561Sobrien	    case AS_PMOD_N:
71285815Sobrien	      fprintf_fn (stream, "@r%d+r8", rn);
71360484Sobrien	      break;
71433965Sjdp	    case A_REG_M:
71538889Sjdp	      fprintf_fn (stream, "r%d", rm);
71633965Sjdp	      break;
71733965Sjdp	    case A_INC_M:
71885815Sobrien	      fprintf_fn (stream, "@r%d+", rm);
71933965Sjdp	      break;
72033965Sjdp	    case A_DEC_M:
72185815Sobrien	      fprintf_fn (stream, "@-r%d", rm);
72233965Sjdp	      break;
72333965Sjdp	    case A_IND_M:
72485815Sobrien	      fprintf_fn (stream, "@r%d", rm);
72533965Sjdp	      break;
72633965Sjdp	    case A_DISP_REG_M:
727218822Sdim	      fprintf_fn (stream, "@(%d,r%d)", has_disp?disp:imm, rm);
72833965Sjdp	      break;
72938889Sjdp	    case A_REG_B:
73038889Sjdp	      fprintf_fn (stream, "r%d_bank", rb);
73133965Sjdp	      break;
73233965Sjdp	    case A_DISP_PC:
73338889Sjdp	      disp_pc = 1;
73438889Sjdp	      disp_pc_addr = imm + 4 + (memaddr & relmask);
73538889Sjdp	      (*info->print_address_func) (disp_pc_addr, info);
73633965Sjdp	      break;
73733965Sjdp	    case A_IND_R0_REG_N:
73838889Sjdp	      fprintf_fn (stream, "@(r0,r%d)", rn);
73985815Sobrien	      break;
74033965Sjdp	    case A_IND_R0_REG_M:
74138889Sjdp	      fprintf_fn (stream, "@(r0,r%d)", rm);
74285815Sobrien	      break;
74333965Sjdp	    case A_DISP_GBR:
744218822Sdim	      fprintf_fn (stream, "@(%d,gbr)", has_disp?disp:imm);
74533965Sjdp	      break;
746218822Sdim	    case A_TBR:
747218822Sdim	      fprintf_fn (stream, "tbr");
748218822Sdim	      break;
749218822Sdim	    case A_DISP2_TBR:
750218822Sdim	      fprintf_fn (stream, "@@(%d,tbr)", has_disp?disp:imm);
751218822Sdim	      break;
752218822Sdim	    case A_INC_R15:
753218822Sdim	      fprintf_fn (stream, "@r15+");
754218822Sdim	      break;
755218822Sdim	    case A_DEC_R15:
756218822Sdim	      fprintf_fn (stream, "@-r15");
757218822Sdim	      break;
75833965Sjdp	    case A_R0_GBR:
75938889Sjdp	      fprintf_fn (stream, "@(r0,gbr)");
76033965Sjdp	      break;
76133965Sjdp	    case A_BDISP12:
76233965Sjdp	    case A_BDISP8:
76333965Sjdp	      (*info->print_address_func) (imm + memaddr, info);
76433965Sjdp	      break;
76533965Sjdp	    case A_SR:
76638889Sjdp	      fprintf_fn (stream, "sr");
76733965Sjdp	      break;
76833965Sjdp	    case A_GBR:
76938889Sjdp	      fprintf_fn (stream, "gbr");
77033965Sjdp	      break;
77133965Sjdp	    case A_VBR:
77238889Sjdp	      fprintf_fn (stream, "vbr");
77333965Sjdp	      break;
77460484Sobrien	    case A_DSR:
77560484Sobrien	      fprintf_fn (stream, "dsr");
77660484Sobrien	      break;
77760484Sobrien	    case A_MOD:
77860484Sobrien	      fprintf_fn (stream, "mod");
77960484Sobrien	      break;
78060484Sobrien	    case A_RE:
78160484Sobrien	      fprintf_fn (stream, "re");
78260484Sobrien	      break;
78360484Sobrien	    case A_RS:
78460484Sobrien	      fprintf_fn (stream, "rs");
78560484Sobrien	      break;
78660484Sobrien	    case A_A0:
78760484Sobrien	      fprintf_fn (stream, "a0");
78860484Sobrien	      break;
78960484Sobrien	    case A_X0:
79060484Sobrien	      fprintf_fn (stream, "x0");
79160484Sobrien	      break;
79260484Sobrien	    case A_X1:
79360484Sobrien	      fprintf_fn (stream, "x1");
79460484Sobrien	      break;
79560484Sobrien	    case A_Y0:
79660484Sobrien	      fprintf_fn (stream, "y0");
79760484Sobrien	      break;
79860484Sobrien	    case A_Y1:
79960484Sobrien	      fprintf_fn (stream, "y1");
80060484Sobrien	      break;
80160484Sobrien	    case DSP_REG_M:
80260484Sobrien	      print_dsp_reg (rm, fprintf_fn, stream);
80360484Sobrien	      break;
80433965Sjdp	    case A_SSR:
80538889Sjdp	      fprintf_fn (stream, "ssr");
80633965Sjdp	      break;
80733965Sjdp	    case A_SPC:
80838889Sjdp	      fprintf_fn (stream, "spc");
80933965Sjdp	      break;
81033965Sjdp	    case A_MACH:
81138889Sjdp	      fprintf_fn (stream, "mach");
81233965Sjdp	      break;
81333965Sjdp	    case A_MACL:
81485815Sobrien	      fprintf_fn (stream, "macl");
81533965Sjdp	      break;
81633965Sjdp	    case A_PR:
81738889Sjdp	      fprintf_fn (stream, "pr");
81833965Sjdp	      break;
81938889Sjdp	    case A_SGR:
82038889Sjdp	      fprintf_fn (stream, "sgr");
82138889Sjdp	      break;
82238889Sjdp	    case A_DBR:
82338889Sjdp	      fprintf_fn (stream, "dbr");
82438889Sjdp	      break;
82533965Sjdp	    case F_REG_N:
82638889Sjdp	      fprintf_fn (stream, "fr%d", rn);
82733965Sjdp	      break;
82833965Sjdp	    case F_REG_M:
82938889Sjdp	      fprintf_fn (stream, "fr%d", rm);
83033965Sjdp	      break;
83138889Sjdp	    case DX_REG_N:
83238889Sjdp	      if (rn & 1)
83338889Sjdp		{
83438889Sjdp		  fprintf_fn (stream, "xd%d", rn & ~1);
83538889Sjdp		  break;
83638889Sjdp		}
83738889Sjdp	    case D_REG_N:
83838889Sjdp	      fprintf_fn (stream, "dr%d", rn);
83938889Sjdp	      break;
84038889Sjdp	    case DX_REG_M:
84138889Sjdp	      if (rm & 1)
84238889Sjdp		{
84338889Sjdp		  fprintf_fn (stream, "xd%d", rm & ~1);
84438889Sjdp		  break;
84538889Sjdp		}
84638889Sjdp	    case D_REG_M:
84738889Sjdp	      fprintf_fn (stream, "dr%d", rm);
84838889Sjdp	      break;
84933965Sjdp	    case FPSCR_M:
85033965Sjdp	    case FPSCR_N:
85138889Sjdp	      fprintf_fn (stream, "fpscr");
85233965Sjdp	      break;
85333965Sjdp	    case FPUL_M:
85433965Sjdp	    case FPUL_N:
85538889Sjdp	      fprintf_fn (stream, "fpul");
85633965Sjdp	      break;
85733965Sjdp	    case F_FR0:
85838889Sjdp	      fprintf_fn (stream, "fr0");
85933965Sjdp	      break;
86038889Sjdp	    case V_REG_N:
86185815Sobrien	      fprintf_fn (stream, "fv%d", rn * 4);
86238889Sjdp	      break;
86338889Sjdp	    case V_REG_M:
86485815Sobrien	      fprintf_fn (stream, "fv%d", rm * 4);
86538889Sjdp	      break;
86638889Sjdp	    case XMTRX_M4:
86738889Sjdp	      fprintf_fn (stream, "xmtrx");
86838889Sjdp	      break;
86933965Sjdp	    default:
87085815Sobrien	      abort ();
87133965Sjdp	    }
87233965Sjdp	}
87338889Sjdp
87438889Sjdp#if 0
87538889Sjdp      /* This code prints instructions in delay slots on the same line
87638889Sjdp         as the instruction which needs the delay slots.  This can be
87738889Sjdp         confusing, since other disassembler don't work this way, and
87838889Sjdp         it means that the instructions are not all in a line.  So I
87938889Sjdp         disabled it.  Ian.  */
88033965Sjdp      if (!(info->flags & 1)
88133965Sjdp	  && (op->name[0] == 'j'
88233965Sjdp	      || (op->name[0] == 'b'
88385815Sobrien		  && (op->name[1] == 'r'
88433965Sjdp		      || op->name[1] == 's'))
88533965Sjdp	      || (op->name[0] == 'r' && op->name[1] == 't')
88633965Sjdp	      || (op->name[0] == 'b' && op->name[2] == '.')))
88733965Sjdp	{
88833965Sjdp	  info->flags |= 1;
88938889Sjdp	  fprintf_fn (stream, "\t(slot ");
890104834Sobrien	  print_insn_sh (memaddr + 2, info);
89133965Sjdp	  info->flags &= ~1;
89238889Sjdp	  fprintf_fn (stream, ")");
89333965Sjdp	  return 4;
89433965Sjdp	}
89538889Sjdp#endif
89638889Sjdp
89738889Sjdp      if (disp_pc && strcmp (op->name, "mova") != 0)
89838889Sjdp	{
89938889Sjdp	  int size;
90038889Sjdp	  bfd_byte bytes[4];
90138889Sjdp
90285815Sobrien	  if (relmask == ~(bfd_vma) 1)
90338889Sjdp	    size = 2;
90438889Sjdp	  else
90538889Sjdp	    size = 4;
90638889Sjdp	  status = info->read_memory_func (disp_pc_addr, bytes, size, info);
90738889Sjdp	  if (status == 0)
90838889Sjdp	    {
90938889Sjdp	      unsigned int val;
91038889Sjdp
91138889Sjdp	      if (size == 2)
91238889Sjdp		{
913104834Sobrien		  if (info->endian == BFD_ENDIAN_LITTLE)
91438889Sjdp		    val = bfd_getl16 (bytes);
91538889Sjdp		  else
91638889Sjdp		    val = bfd_getb16 (bytes);
91738889Sjdp		}
91838889Sjdp	      else
91938889Sjdp		{
920104834Sobrien		  if (info->endian == BFD_ENDIAN_LITTLE)
92138889Sjdp		    val = bfd_getl32 (bytes);
92238889Sjdp		  else
92338889Sjdp		    val = bfd_getb32 (bytes);
92438889Sjdp		}
925218822Sdim	      if ((*info->symbol_at_address_func) (val, info))
926218822Sdim		{
927218822Sdim		  fprintf_fn (stream, "\t! ");
928218822Sdim		  (*info->print_address_func) (val, info);
929218822Sdim		}
930218822Sdim	      else
931218822Sdim		fprintf_fn (stream, "\t! %x", val);
93238889Sjdp	    }
93338889Sjdp	}
93438889Sjdp
935218822Sdim      return SH_MERGE_ARCH_SET (op->arch, arch_op32) ? 4 : 2;
93633965Sjdp    fail:
93733965Sjdp      ;
93833965Sjdp
93933965Sjdp    }
94038889Sjdp  fprintf_fn (stream, ".word 0x%x%x%x%x", nibs[0], nibs[1], nibs[2], nibs[3]);
94133965Sjdp  return 2;
94233965Sjdp}
943