cpu/
[deliverable/binutils-gdb.git] / opcodes / sh-dis.c
index 3ca5130968bc17c1ca9f688043e52aa4b8b529dc..34e84d2940a82082bc7c683a37eb6fcb1a4ddc4b 100644 (file)
@@ -390,6 +390,8 @@ print_insn_ppi (field_b, info)
   fprintf_fn (stream, ".word 0x%x", field_b);
 }
 
+/* FIXME mvs: movx insns print as ".word 0x%03x", insn & 0xfff
+   (ie. the upper nibble is missing).  */
 int
 print_insn_sh (memaddr, info)
      bfd_vma memaddr;
@@ -398,11 +400,12 @@ print_insn_sh (memaddr, info)
   fprintf_ftype fprintf_fn = info->fprintf_func;
   void *stream = info->stream;
   unsigned char insn[4];
-  unsigned char nibs[4];
+  unsigned char nibs[8];
   int status;
   bfd_vma relmask = ~(bfd_vma) 0;
   const sh_opcode_info *op;
   unsigned int target_arch;
+  int allow_op32;
 
   switch (info->mach)
     {
@@ -453,6 +456,30 @@ print_insn_sh (memaddr, info)
       nibs[2] = (insn[1] >> 4) & 0xf;
       nibs[3] = insn[1] & 0xf;
     }
+  status = info->read_memory_func (memaddr + 2, insn + 2, 2, info);
+  if (status != 0)
+    allow_op32 = 0;
+  else
+    {
+      allow_op32 = 1;
+
+      if (info->endian == BFD_ENDIAN_LITTLE)
+       {
+         nibs[4] = (insn[3] >> 4) & 0xf;
+         nibs[5] = insn[3] & 0xf;
+
+         nibs[6] = (insn[2] >> 4) & 0xf;
+         nibs[7] = insn[2] & 0xf;
+       }
+      else
+       {
+         nibs[4] = (insn[2] >> 4) & 0xf;
+         nibs[5] = insn[2] & 0xf;
+
+         nibs[6] = (insn[3] >> 4) & 0xf;
+         nibs[7] = insn[3] & 0xf;
+       }
+    }
 
   if (nibs[0] == 0xf && (nibs[1] & 4) == 0
       && SH_MERGE_ARCH_SET_VALID (target_arch, arch_sh_dsp_up))
@@ -490,10 +517,17 @@ print_insn_sh (memaddr, info)
       int rb = 0;
       int disp_pc;
       bfd_vma disp_pc_addr = 0;
+      int disp = 0;
+      int has_disp = 0;
+      int max_n = SH_MERGE_ARCH_SET (op->arch, arch_op32) ? 8 : 4;
+
+      if (!allow_op32
+         && SH_MERGE_ARCH_SET (op->arch, arch_op32))
+       goto fail;
 
       if (!SH_MERGE_ARCH_SET_VALID (op->arch, target_arch))
        goto fail;
-      for (n = 0; n < 4; n++)
+      for (n = 0; n < max_n; n++)
        {
          int i = op->nibbles[n];
 
@@ -517,6 +551,64 @@ print_insn_sh (memaddr, info)
                imm |= ~0xfff;
              imm = imm * 2 + 4;
              goto ok;
+           case IMM0_3c:
+             if (nibs[3] & 0x8)
+               goto fail;
+             imm = nibs[3] & 0x7;
+             break;
+           case IMM0_3s:
+             if (!(nibs[3] & 0x8))
+               goto fail;
+             imm = nibs[3] & 0x7;
+             break;
+           case IMM0_3Uc:
+             if (nibs[2] & 0x8)
+               goto fail;
+             imm = nibs[2] & 0x7;
+             break;
+           case IMM0_3Us:
+             if (!(nibs[2] & 0x8))
+               goto fail;
+             imm = nibs[2] & 0x7;
+             break;
+           case DISP0_12:
+           case DISP1_12:
+             disp = (nibs[5] << 8) | (nibs[6] << 4) | nibs[7];
+             has_disp = 1;
+             goto ok;
+           case DISP0_12BY2:
+           case DISP1_12BY2:
+             disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 1;
+             relmask = ~(bfd_vma) 1;
+             has_disp = 1;
+             goto ok;
+           case DISP0_12BY4:
+           case DISP1_12BY4:
+             disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 2;
+             relmask = ~(bfd_vma) 3;
+             has_disp = 1;
+             goto ok;
+           case DISP0_12BY8:
+           case DISP1_12BY8:
+             disp = ((nibs[5] << 8) | (nibs[6] << 4) | nibs[7]) << 3;
+             relmask = ~(bfd_vma) 7;
+             has_disp = 1;
+             goto ok;
+           case IMM0_20_4:
+             break;
+           case IMM0_20:
+             imm = ((nibs[2] << 16) | (nibs[4] << 12) | (nibs[5] << 8)
+                    | (nibs[6] << 4) | nibs[7]);
+             if (imm & 0x80000)
+               imm -= 0x100000;
+             goto ok;
+           case IMM0_20BY8:
+             imm = ((nibs[2] << 16) | (nibs[4] << 12) | (nibs[5] << 8)
+                    | (nibs[6] << 4) | nibs[7]);
+             imm <<= 8;
+             if (imm & 0x8000000)
+               imm -= 0x10000000;
+             goto ok;
            case IMM0_4:
            case IMM1_4:
              imm = nibs[3];
@@ -532,6 +624,10 @@ print_insn_sh (memaddr, info)
            case IMM0_8:
            case IMM1_8:
              imm = (nibs[2] << 4) | nibs[3];
+             disp = imm;
+             has_disp = 1;
+             if (imm & 0x80)
+               imm -= 0x100;
              goto ok;
            case PCRELIMM_8BY2:
              imm = ((nibs[2] << 4) | nibs[3]) << 1;
@@ -588,6 +684,14 @@ print_insn_sh (memaddr, info)
        }
 
     ok:
+      /* sh2a has D_REG but not X_REG.  We don't know the pattern
+        doesn't match unless we check the output args to see if they
+        make sense.  */
+      if (target_arch == arch_sh2a
+         && ((op->arg[0] == DX_REG_M && (rm & 1) != 0)
+             || (op->arg[1] == DX_REG_N && (rn & 1) != 0)))
+       goto fail;
+
       fprintf_fn (stream, "%s\t", op->name);
       disp_pc = 0;
       for (n = 0; n < 3 && op->arg[n] != A_END; n++)
@@ -597,7 +701,7 @@ print_insn_sh (memaddr, info)
          switch (op->arg[n])
            {
            case A_IMM:
-             fprintf_fn (stream, "#%d", (char) (imm));
+             fprintf_fn (stream, "#%d", imm);
              break;
            case A_R0:
              fprintf_fn (stream, "r0");
@@ -618,7 +722,7 @@ print_insn_sh (memaddr, info)
              fprintf_fn (stream, "@r%d", rn);
              break;
            case A_DISP_REG_N:
-             fprintf_fn (stream, "@(%d,r%d)", imm, rn);
+             fprintf_fn (stream, "@(%d,r%d)", has_disp?disp:imm, rn);
              break;
            case AS_PMOD_N:
              fprintf_fn (stream, "@r%d+r8", rn);
@@ -636,7 +740,7 @@ print_insn_sh (memaddr, info)
              fprintf_fn (stream, "@r%d", rm);
              break;
            case A_DISP_REG_M:
-             fprintf_fn (stream, "@(%d,r%d)", imm, rm);
+             fprintf_fn (stream, "@(%d,r%d)", has_disp?disp:imm, rm);
              break;
            case A_REG_B:
              fprintf_fn (stream, "r%d_bank", rb);
@@ -653,7 +757,19 @@ print_insn_sh (memaddr, info)
              fprintf_fn (stream, "@(r0,r%d)", rm);
              break;
            case A_DISP_GBR:
-             fprintf_fn (stream, "@(%d,gbr)", imm);
+             fprintf_fn (stream, "@(%d,gbr)", has_disp?disp:imm);
+             break;
+           case A_TBR:
+             fprintf_fn (stream, "tbr");
+             break;
+           case A_DISP2_TBR:
+             fprintf_fn (stream, "@@(%d,tbr)", has_disp?disp:imm);
+             break;
+           case A_INC_R15:
+             fprintf_fn (stream, "@r15+");
+             break;
+           case A_DEC_R15:
+             fprintf_fn (stream, "@-r15");
              break;
            case A_R0_GBR:
              fprintf_fn (stream, "@(r0,gbr)");
@@ -832,7 +948,7 @@ print_insn_sh (memaddr, info)
            }
        }
 
-      return 2;
+      return SH_MERGE_ARCH_SET (op->arch, arch_op32) ? 4 : 2;
     fail:
       ;
 
This page took 0.025279 seconds and 4 git commands to generate.