diff options
Diffstat (limited to 'opcodes/sh-dis.c')
-rw-r--r-- | opcodes/sh-dis.c | 130 |
1 files changed, 123 insertions, 7 deletions
diff --git a/opcodes/sh-dis.c b/opcodes/sh-dis.c index 3ca5130..34e84d2 100644 --- a/opcodes/sh-dis.c +++ b/opcodes/sh-dis.c @@ -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: ; |