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