sh-dis.c revision 38889
133965Sjdp/* Disassemble SH instructions.
238889Sjdp   Copyright (C) 1993, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
333965Sjdp
433965SjdpThis program is free software; you can redistribute it and/or modify
533965Sjdpit under the terms of the GNU General Public License as published by
633965Sjdpthe Free Software Foundation; either version 2 of the License, or
733965Sjdp(at your option) any later version.
833965Sjdp
933965SjdpThis program is distributed in the hope that it will be useful,
1033965Sjdpbut WITHOUT ANY WARRANTY; without even the implied warranty of
1133965SjdpMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1233965SjdpGNU General Public License for more details.
1333965Sjdp
1433965SjdpYou should have received a copy of the GNU General Public License
1533965Sjdpalong with this program; if not, write to the Free Software
1633965SjdpFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
1733965Sjdp
1833965Sjdp#include <stdio.h>
1933965Sjdp#define STATIC_TABLE
2033965Sjdp#define DEFINE_TABLE
2133965Sjdp
2233965Sjdp#include "sh-opc.h"
2333965Sjdp#include "dis-asm.h"
2433965Sjdp
2533965Sjdp#define LITTLE_BIT 2
2633965Sjdp
2733965Sjdpstatic int
2838889Sjdpprint_insn_shx (memaddr, info)
2933965Sjdp     bfd_vma memaddr;
3033965Sjdp     struct disassemble_info *info;
3133965Sjdp{
3238889Sjdp  fprintf_ftype fprintf_fn = info->fprintf_func;
3333965Sjdp  void *stream = info->stream;
3438889Sjdp  unsigned char insn[2];
3538889Sjdp  unsigned char nibs[4];
3633965Sjdp  int status;
3738889Sjdp  bfd_vma relmask = ~ (bfd_vma) 0;
3833965Sjdp  sh_opcode_info *op;
3933965Sjdp
4038889Sjdp  status = info->read_memory_func (memaddr, insn, 2, info);
4138889Sjdp
4233965Sjdp  if (status != 0)
4333965Sjdp    {
4438889Sjdp      info->memory_error_func (status, memaddr, info);
4533965Sjdp      return -1;
4633965Sjdp    }
4733965Sjdp
4833965Sjdp  if (info->flags & LITTLE_BIT)
4933965Sjdp    {
5033965Sjdp      nibs[0] = (insn[1] >> 4) & 0xf;
5133965Sjdp      nibs[1] = insn[1] & 0xf;
5233965Sjdp
5333965Sjdp      nibs[2] = (insn[0] >> 4) & 0xf;
5433965Sjdp      nibs[3] = insn[0] & 0xf;
5533965Sjdp    }
5633965Sjdp  else
5733965Sjdp    {
5833965Sjdp      nibs[0] = (insn[0] >> 4) & 0xf;
5933965Sjdp      nibs[1] = insn[0] & 0xf;
6033965Sjdp
6133965Sjdp      nibs[2] = (insn[1] >> 4) & 0xf;
6233965Sjdp      nibs[3] = insn[1] & 0xf;
6333965Sjdp    }
6433965Sjdp
6533965Sjdp  for (op = sh_table; op->name; op++)
6633965Sjdp    {
6733965Sjdp      int n;
6838889Sjdp      int imm = 0;
6938889Sjdp      int rn = 0;
7038889Sjdp      int rm = 0;
7138889Sjdp      int rb = 0;
7238889Sjdp      int disp_pc;
7338889Sjdp      bfd_vma disp_pc_addr = 0;
7433965Sjdp
7538889Sjdp      for (n = 0; n < 4; n++)
7638889Sjdp	{
7738889Sjdp	  int i = op->nibbles[n];
7833965Sjdp
7938889Sjdp	  if (i < 16)
8038889Sjdp	    {
8138889Sjdp	      if (nibs[n] == i)
8238889Sjdp		continue;
8338889Sjdp	      goto fail;
8438889Sjdp	    }
8538889Sjdp	  switch (i)
8638889Sjdp	    {
8738889Sjdp	    case BRANCH_8:
8838889Sjdp	      imm = (nibs[2] << 4) | (nibs[3]);
8938889Sjdp	      if (imm & 0x80)
9038889Sjdp		imm |= ~0xff;
9138889Sjdp	      imm = ((char)imm) * 2 + 4 ;
9238889Sjdp	      goto ok;
9338889Sjdp	    case BRANCH_12:
9438889Sjdp	      imm = ((nibs[1]) << 8) | (nibs[2] << 4) | (nibs[3]);
9538889Sjdp	      if (imm & 0x800)
9638889Sjdp		imm |= ~0xfff;
9738889Sjdp	      imm = imm * 2 + 4;
9838889Sjdp	      goto ok;
9938889Sjdp	    case IMM_4:
10038889Sjdp	      imm = nibs[3];
10138889Sjdp	      goto ok;
10238889Sjdp	    case IMM_4BY2:
10338889Sjdp	      imm = nibs[3] <<1;
10438889Sjdp	      goto ok;
10538889Sjdp	    case IMM_4BY4:
10638889Sjdp	      imm = nibs[3] <<2;
10738889Sjdp	      goto ok;
10838889Sjdp	    case IMM_8:
10938889Sjdp	      imm = (nibs[2] << 4) | nibs[3];
11038889Sjdp	      goto ok;
11138889Sjdp	    case PCRELIMM_8BY2:
11238889Sjdp	      imm = ((nibs[2] << 4) | nibs[3]) <<1;
11338889Sjdp	      relmask = ~ (bfd_vma) 1;
11438889Sjdp	      goto ok;
11538889Sjdp	    case PCRELIMM_8BY4:
11638889Sjdp	      imm = ((nibs[2] << 4) | nibs[3]) <<2;
11738889Sjdp	      relmask = ~ (bfd_vma) 3;
11838889Sjdp	      goto ok;
11938889Sjdp	    case IMM_8BY2:
12038889Sjdp	      imm = ((nibs[2] << 4) | nibs[3]) <<1;
12138889Sjdp	      goto ok;
12238889Sjdp	    case IMM_8BY4:
12338889Sjdp	      imm = ((nibs[2] << 4) | nibs[3]) <<2;
12438889Sjdp	      goto ok;
12538889Sjdp	    case DISP_8:
12638889Sjdp	      imm = (nibs[2] << 4) | (nibs[3]);
12738889Sjdp	      goto ok;
12838889Sjdp	    case DISP_4:
12938889Sjdp	      imm = nibs[3];
13038889Sjdp	      goto ok;
13138889Sjdp	    case REG_N:
13238889Sjdp	      rn = nibs[n];
13338889Sjdp	      break;
13438889Sjdp	    case REG_M:
13538889Sjdp	      rm = nibs[n];
13638889Sjdp	      break;
13738889Sjdp	    case REG_NM:
13838889Sjdp	      rn = (nibs[n] & 0xc) >> 2;
13938889Sjdp	      rm = (nibs[n] & 0x3);
14038889Sjdp	      break;
14138889Sjdp	    case REG_B:
14238889Sjdp	      rb = nibs[n] & 0x07;
14338889Sjdp	      break;
14438889Sjdp	    default:
14538889Sjdp	      abort();
14638889Sjdp	    }
14738889Sjdp	}
14833965Sjdp
14933965Sjdp    ok:
15038889Sjdp      fprintf_fn (stream,"%s\t", op->name);
15138889Sjdp      disp_pc = 0;
15233965Sjdp      for (n = 0; n < 3 && op->arg[n] != A_END; n++)
15333965Sjdp	{
15433965Sjdp	  if (n && op->arg[1] != A_END)
15538889Sjdp	    fprintf_fn (stream, ",");
15633965Sjdp	  switch (op->arg[n])
15733965Sjdp	    {
15833965Sjdp	    case A_IMM:
15938889Sjdp	      fprintf_fn (stream, "#%d", (char)(imm));
16033965Sjdp	      break;
16133965Sjdp	    case A_R0:
16238889Sjdp	      fprintf_fn (stream, "r0");
16333965Sjdp	      break;
16433965Sjdp	    case A_REG_N:
16538889Sjdp	      fprintf_fn (stream, "r%d", rn);
16633965Sjdp	      break;
16733965Sjdp	    case A_INC_N:
16838889Sjdp	      fprintf_fn (stream, "@r%d+", rn);
16933965Sjdp	      break;
17033965Sjdp	    case A_DEC_N:
17138889Sjdp	      fprintf_fn (stream, "@-r%d", rn);
17233965Sjdp	      break;
17333965Sjdp	    case A_IND_N:
17438889Sjdp	      fprintf_fn (stream, "@r%d", rn);
17533965Sjdp	      break;
17633965Sjdp	    case A_DISP_REG_N:
17738889Sjdp	      fprintf_fn (stream, "@(%d,r%d)", imm, rn);
17833965Sjdp	      break;
17933965Sjdp	    case A_REG_M:
18038889Sjdp	      fprintf_fn (stream, "r%d", rm);
18133965Sjdp	      break;
18233965Sjdp	    case A_INC_M:
18338889Sjdp	      fprintf_fn (stream, "@r%d+", rm);
18433965Sjdp	      break;
18533965Sjdp	    case A_DEC_M:
18638889Sjdp	      fprintf_fn (stream, "@-r%d", rm);
18733965Sjdp	      break;
18833965Sjdp	    case A_IND_M:
18938889Sjdp	      fprintf_fn (stream, "@r%d", rm);
19033965Sjdp	      break;
19133965Sjdp	    case A_DISP_REG_M:
19238889Sjdp	      fprintf_fn (stream, "@(%d,r%d)", imm, rm);
19333965Sjdp	      break;
19438889Sjdp	    case A_REG_B:
19538889Sjdp	      fprintf_fn (stream, "r%d_bank", rb);
19633965Sjdp	      break;
19733965Sjdp	    case A_DISP_PC:
19838889Sjdp	      disp_pc = 1;
19938889Sjdp	      disp_pc_addr = imm + 4 + (memaddr & relmask);
20038889Sjdp	      (*info->print_address_func) (disp_pc_addr, info);
20133965Sjdp	      break;
20233965Sjdp	    case A_IND_R0_REG_N:
20338889Sjdp	      fprintf_fn (stream, "@(r0,r%d)", rn);
20433965Sjdp	      break;
20533965Sjdp	    case A_IND_R0_REG_M:
20638889Sjdp	      fprintf_fn (stream, "@(r0,r%d)", rm);
20733965Sjdp	      break;
20833965Sjdp	    case A_DISP_GBR:
20938889Sjdp	      fprintf_fn (stream, "@(%d,gbr)",imm);
21033965Sjdp	      break;
21133965Sjdp	    case A_R0_GBR:
21238889Sjdp	      fprintf_fn (stream, "@(r0,gbr)");
21333965Sjdp	      break;
21433965Sjdp	    case A_BDISP12:
21533965Sjdp	    case A_BDISP8:
21633965Sjdp	      (*info->print_address_func) (imm + memaddr, info);
21733965Sjdp	      break;
21833965Sjdp	    case A_SR:
21938889Sjdp	      fprintf_fn (stream, "sr");
22033965Sjdp	      break;
22133965Sjdp	    case A_GBR:
22238889Sjdp	      fprintf_fn (stream, "gbr");
22333965Sjdp	      break;
22433965Sjdp	    case A_VBR:
22538889Sjdp	      fprintf_fn (stream, "vbr");
22633965Sjdp	      break;
22733965Sjdp	    case A_SSR:
22838889Sjdp	      fprintf_fn (stream, "ssr");
22933965Sjdp	      break;
23033965Sjdp	    case A_SPC:
23138889Sjdp	      fprintf_fn (stream, "spc");
23233965Sjdp	      break;
23333965Sjdp	    case A_MACH:
23438889Sjdp	      fprintf_fn (stream, "mach");
23533965Sjdp	      break;
23633965Sjdp	    case A_MACL:
23738889Sjdp	      fprintf_fn (stream ,"macl");
23833965Sjdp	      break;
23933965Sjdp	    case A_PR:
24038889Sjdp	      fprintf_fn (stream, "pr");
24133965Sjdp	      break;
24238889Sjdp	    case A_SGR:
24338889Sjdp	      fprintf_fn (stream, "sgr");
24438889Sjdp	      break;
24538889Sjdp	    case A_DBR:
24638889Sjdp	      fprintf_fn (stream, "dbr");
24738889Sjdp	      break;
24838889Sjdp	    case FD_REG_N:
24938889Sjdp	      if (0)
25038889Sjdp		goto d_reg_n;
25133965Sjdp	    case F_REG_N:
25238889Sjdp	      fprintf_fn (stream, "fr%d", rn);
25333965Sjdp	      break;
25433965Sjdp	    case F_REG_M:
25538889Sjdp	      fprintf_fn (stream, "fr%d", rm);
25633965Sjdp	      break;
25738889Sjdp	    case DX_REG_N:
25838889Sjdp	      if (rn & 1)
25938889Sjdp		{
26038889Sjdp		  fprintf_fn (stream, "xd%d", rn & ~1);
26138889Sjdp		  break;
26238889Sjdp		}
26338889Sjdp	    d_reg_n:
26438889Sjdp	    case D_REG_N:
26538889Sjdp	      fprintf_fn (stream, "dr%d", rn);
26638889Sjdp	      break;
26738889Sjdp	    case DX_REG_M:
26838889Sjdp	      if (rm & 1)
26938889Sjdp		{
27038889Sjdp		  fprintf_fn (stream, "xd%d", rm & ~1);
27138889Sjdp		  break;
27238889Sjdp		}
27338889Sjdp	    case D_REG_M:
27438889Sjdp	      fprintf_fn (stream, "dr%d", rm);
27538889Sjdp	      break;
27633965Sjdp	    case FPSCR_M:
27733965Sjdp	    case FPSCR_N:
27838889Sjdp	      fprintf_fn (stream, "fpscr");
27933965Sjdp	      break;
28033965Sjdp	    case FPUL_M:
28133965Sjdp	    case FPUL_N:
28238889Sjdp	      fprintf_fn (stream, "fpul");
28333965Sjdp	      break;
28433965Sjdp	    case F_FR0:
28538889Sjdp	      fprintf_fn (stream, "fr0");
28633965Sjdp	      break;
28738889Sjdp	    case V_REG_N:
28838889Sjdp	      fprintf_fn (stream, "fv%d", rn*4);
28938889Sjdp	      break;
29038889Sjdp	    case V_REG_M:
29138889Sjdp	      fprintf_fn (stream, "fv%d", rm*4);
29238889Sjdp	      break;
29338889Sjdp	    case XMTRX_M4:
29438889Sjdp	      fprintf_fn (stream, "xmtrx");
29538889Sjdp	      break;
29633965Sjdp	    default:
29733965Sjdp	      abort();
29833965Sjdp	    }
29933965Sjdp	}
30038889Sjdp
30138889Sjdp#if 0
30238889Sjdp      /* This code prints instructions in delay slots on the same line
30338889Sjdp         as the instruction which needs the delay slots.  This can be
30438889Sjdp         confusing, since other disassembler don't work this way, and
30538889Sjdp         it means that the instructions are not all in a line.  So I
30638889Sjdp         disabled it.  Ian.  */
30733965Sjdp      if (!(info->flags & 1)
30833965Sjdp	  && (op->name[0] == 'j'
30933965Sjdp	      || (op->name[0] == 'b'
31033965Sjdp		  && (op->name[1] == 'r'
31133965Sjdp		      || op->name[1] == 's'))
31233965Sjdp	      || (op->name[0] == 'r' && op->name[1] == 't')
31333965Sjdp	      || (op->name[0] == 'b' && op->name[2] == '.')))
31433965Sjdp	{
31533965Sjdp	  info->flags |= 1;
31638889Sjdp	  fprintf_fn (stream, "\t(slot ");
31738889Sjdp	  print_insn_shx (memaddr + 2, info);
31833965Sjdp	  info->flags &= ~1;
31938889Sjdp	  fprintf_fn (stream, ")");
32033965Sjdp	  return 4;
32133965Sjdp	}
32238889Sjdp#endif
32338889Sjdp
32438889Sjdp      if (disp_pc && strcmp (op->name, "mova") != 0)
32538889Sjdp	{
32638889Sjdp	  int size;
32738889Sjdp	  bfd_byte bytes[4];
32838889Sjdp
32938889Sjdp	  if (relmask == ~ (bfd_vma) 1)
33038889Sjdp	    size = 2;
33138889Sjdp	  else
33238889Sjdp	    size = 4;
33338889Sjdp	  status = info->read_memory_func (disp_pc_addr, bytes, size, info);
33438889Sjdp	  if (status == 0)
33538889Sjdp	    {
33638889Sjdp	      unsigned int val;
33738889Sjdp
33838889Sjdp	      if (size == 2)
33938889Sjdp		{
34038889Sjdp		  if ((info->flags & LITTLE_BIT) != 0)
34138889Sjdp		    val = bfd_getl16 (bytes);
34238889Sjdp		  else
34338889Sjdp		    val = bfd_getb16 (bytes);
34438889Sjdp		}
34538889Sjdp	      else
34638889Sjdp		{
34738889Sjdp		  if ((info->flags & LITTLE_BIT) != 0)
34838889Sjdp		    val = bfd_getl32 (bytes);
34938889Sjdp		  else
35038889Sjdp		    val = bfd_getb32 (bytes);
35138889Sjdp		}
35238889Sjdp	      fprintf_fn (stream, "\t! 0x%x", val);
35338889Sjdp	    }
35438889Sjdp	}
35538889Sjdp
35633965Sjdp      return 2;
35733965Sjdp    fail:
35833965Sjdp      ;
35933965Sjdp
36033965Sjdp    }
36138889Sjdp  fprintf_fn (stream, ".word 0x%x%x%x%x", nibs[0], nibs[1], nibs[2], nibs[3]);
36233965Sjdp  return 2;
36333965Sjdp}
36433965Sjdp
36533965Sjdpint
36638889Sjdpprint_insn_shl (memaddr, info)
36733965Sjdp     bfd_vma memaddr;
36833965Sjdp     struct disassemble_info *info;
36933965Sjdp{
37033965Sjdp  int r;
37138889Sjdp
37233965Sjdp  info->flags = LITTLE_BIT;
37338889Sjdp  r = print_insn_shx (memaddr, info);
37433965Sjdp  return r;
37533965Sjdp}
37633965Sjdp
37733965Sjdpint
37838889Sjdpprint_insn_sh (memaddr, info)
37933965Sjdp     bfd_vma memaddr;
38033965Sjdp     struct disassemble_info *info;
38133965Sjdp{
38233965Sjdp  int r;
38338889Sjdp
38433965Sjdp  info->flags = 0;
38538889Sjdp  r = print_insn_shx (memaddr, info);
38633965Sjdp  return r;
38733965Sjdp}
388