1f7cc78ecSespie /* Disassemble D30V instructions. 2*5f210c2aSfgsch Copyright 1997, 1998, 2000 Free Software Foundation, Inc. 3f7cc78ecSespie 4f7cc78ecSespie This program is free software; you can redistribute it and/or modify 5f7cc78ecSespie it under the terms of the GNU General Public License as published by 6f7cc78ecSespie the Free Software Foundation; either version 2 of the License, or 7f7cc78ecSespie (at your option) any later version. 8f7cc78ecSespie 9f7cc78ecSespie This program is distributed in the hope that it will be useful, 10f7cc78ecSespie but WITHOUT ANY WARRANTY; without even the implied warranty of 11f7cc78ecSespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12f7cc78ecSespie GNU General Public License for more details. 13f7cc78ecSespie 14f7cc78ecSespie You should have received a copy of the GNU General Public License 15f7cc78ecSespie along with this program; if not, write to the Free Software 16f7cc78ecSespie Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 17f7cc78ecSespie 18f7cc78ecSespie #include <stdio.h> 19*5f210c2aSfgsch #include "sysdep.h" 20f7cc78ecSespie #include "opcode/d30v.h" 21f7cc78ecSespie #include "dis-asm.h" 22f7cc78ecSespie #include "opintl.h" 23f7cc78ecSespie 24f7cc78ecSespie #define PC_MASK 0xFFFFFFFF 25f7cc78ecSespie 26f7cc78ecSespie static int lookup_opcode PARAMS (( struct d30v_insn *insn, long num, int is_long )); 27f7cc78ecSespie static void print_insn PARAMS (( struct disassemble_info *info, bfd_vma memaddr, long long num, 28f7cc78ecSespie struct d30v_insn *insn, int is_long, int show_ext )); 29f7cc78ecSespie static int extract_value PARAMS (( long long num, struct d30v_operand *oper, int is_long )); 30f7cc78ecSespie 31f7cc78ecSespie int 32f7cc78ecSespie print_insn_d30v (memaddr, info) 33f7cc78ecSespie bfd_vma memaddr; 34f7cc78ecSespie struct disassemble_info *info; 35f7cc78ecSespie { 36f7cc78ecSespie int status, result; 37f7cc78ecSespie bfd_byte buffer[12]; 38f7cc78ecSespie unsigned long in1,in2; 39f7cc78ecSespie struct d30v_insn insn; 40f7cc78ecSespie long long num; 41f7cc78ecSespie 42f7cc78ecSespie insn.form = (struct d30v_format *)NULL; 43f7cc78ecSespie 44f7cc78ecSespie info->bytes_per_line = 8; 45f7cc78ecSespie info->bytes_per_chunk = 4; 46f7cc78ecSespie info->display_endian = BFD_ENDIAN_BIG; 47f7cc78ecSespie 48f7cc78ecSespie status = (*info->read_memory_func) (memaddr, buffer, 4, info); 49f7cc78ecSespie if (status != 0) 50f7cc78ecSespie { 51f7cc78ecSespie (*info->memory_error_func) (status, memaddr, info); 52f7cc78ecSespie return -1; 53f7cc78ecSespie } 54f7cc78ecSespie in1 = bfd_getb32 (buffer); 55f7cc78ecSespie 56f7cc78ecSespie status = (*info->read_memory_func) (memaddr+4, buffer, 4, info); 57f7cc78ecSespie if (status != 0) 58f7cc78ecSespie { 59f7cc78ecSespie info->bytes_per_line = 8; 60f7cc78ecSespie if (!(result = lookup_opcode(&insn, in1, 0))) 61f7cc78ecSespie (*info->fprintf_func) (info->stream, ".long\t0x%x",in1); 62f7cc78ecSespie else 63f7cc78ecSespie print_insn(info, memaddr, (long long) in1, &insn, 0, result); 64f7cc78ecSespie return 4; 65f7cc78ecSespie } 66f7cc78ecSespie in2 = bfd_getb32 (buffer); 67f7cc78ecSespie 68f7cc78ecSespie if (in1 & in2 & FM01) 69f7cc78ecSespie { 70f7cc78ecSespie /* LONG instruction */ 71f7cc78ecSespie if (!(result = lookup_opcode(&insn, in1, 1))) 72f7cc78ecSespie { 73f7cc78ecSespie (*info->fprintf_func) (info->stream, ".long\t0x%x,0x%x",in1,in2); 74f7cc78ecSespie return 8; 75f7cc78ecSespie } 76f7cc78ecSespie num = (long long)in1 << 32 | in2; 77f7cc78ecSespie print_insn(info, memaddr, num, &insn, 1, result); 78f7cc78ecSespie } 79f7cc78ecSespie else 80f7cc78ecSespie { 81f7cc78ecSespie num = in1; 82f7cc78ecSespie if (!(result = lookup_opcode(&insn, in1, 0))) 83f7cc78ecSespie (*info->fprintf_func) (info->stream, ".long\t0x%x",in1); 84f7cc78ecSespie else 85f7cc78ecSespie print_insn(info, memaddr, num, &insn, 0, result); 86f7cc78ecSespie 87f7cc78ecSespie switch ( ((in1>>31)<<1) | (in2>>31) ) 88f7cc78ecSespie { 89f7cc78ecSespie case 0: 90f7cc78ecSespie (*info->fprintf_func) (info->stream, "\t||\t"); 91f7cc78ecSespie break; 92f7cc78ecSespie case 1: 93f7cc78ecSespie (*info->fprintf_func) (info->stream, "\t->\t"); 94f7cc78ecSespie break; 95f7cc78ecSespie case 2: 96f7cc78ecSespie (*info->fprintf_func) (info->stream, "\t<-\t"); 97f7cc78ecSespie default: 98f7cc78ecSespie break; 99f7cc78ecSespie } 100f7cc78ecSespie 101f7cc78ecSespie insn.form = (struct d30v_format *)NULL; 102f7cc78ecSespie num = in2; 103f7cc78ecSespie if (!(result = lookup_opcode(&insn, in2, 0))) 104f7cc78ecSespie (*info->fprintf_func) (info->stream, ".long\t0x%x",in2); 105f7cc78ecSespie else 106f7cc78ecSespie print_insn(info, memaddr, num, &insn, 0, result); 107f7cc78ecSespie 108f7cc78ecSespie } 109f7cc78ecSespie return 8; 110f7cc78ecSespie } 111f7cc78ecSespie 112f7cc78ecSespie 113f7cc78ecSespie /* returns 0 if lookup fails */ 114f7cc78ecSespie /* 1 if found and only one form */ 115f7cc78ecSespie /* 2 if found and there are short and long forms */ 116f7cc78ecSespie static int 117f7cc78ecSespie lookup_opcode (insn, num, is_long) 118f7cc78ecSespie struct d30v_insn *insn; 119f7cc78ecSespie long num; 120f7cc78ecSespie int is_long; 121f7cc78ecSespie { 122f7cc78ecSespie int i=0, index; 123f7cc78ecSespie struct d30v_format *f; 124f7cc78ecSespie struct d30v_opcode *op = (struct d30v_opcode *)d30v_opcode_table; 125f7cc78ecSespie int op1 = (num >> 25) & 0x7; 126f7cc78ecSespie int op2 = (num >> 20) & 0x1f; 127f7cc78ecSespie int mod = (num >> 18) & 0x3; 128f7cc78ecSespie 129f7cc78ecSespie /* find the opcode */ 130f7cc78ecSespie do { 131f7cc78ecSespie if ((op->op1 == op1) && (op->op2 == op2)) 132f7cc78ecSespie break; 133f7cc78ecSespie op++; 134f7cc78ecSespie } while (op->name); 135f7cc78ecSespie 136f7cc78ecSespie if (!op || !op->name) 137f7cc78ecSespie return 0; 138f7cc78ecSespie 139f7cc78ecSespie while (op->op1 == op1 && op->op2 == op2) 140f7cc78ecSespie { 141f7cc78ecSespie /* scan through all the formats for the opcode */ 142f7cc78ecSespie index = op->format[i++]; 143f7cc78ecSespie do 144f7cc78ecSespie { 145f7cc78ecSespie f = (struct d30v_format *)&d30v_format_table[index]; 146f7cc78ecSespie while (f->form == index) 147f7cc78ecSespie { 148f7cc78ecSespie if ((!is_long || f->form >= LONG) && (f->modifier == mod)) 149f7cc78ecSespie { 150f7cc78ecSespie insn->form = f; 151f7cc78ecSespie break; 152f7cc78ecSespie } 153f7cc78ecSespie f++; 154f7cc78ecSespie } 155f7cc78ecSespie if (insn->form) 156f7cc78ecSespie break; 157f7cc78ecSespie } while ((index = op->format[i++]) != 0); 158f7cc78ecSespie if (insn->form) 159f7cc78ecSespie break; 160f7cc78ecSespie op++; 161f7cc78ecSespie i=0; 162f7cc78ecSespie } 163f7cc78ecSespie if (insn->form == NULL) 164f7cc78ecSespie return 0; 165f7cc78ecSespie 166f7cc78ecSespie insn->op = op; 167f7cc78ecSespie insn->ecc = (num >> 28) & 0x7; 168f7cc78ecSespie if (op->format[1]) 169f7cc78ecSespie return 2; 170f7cc78ecSespie else 171f7cc78ecSespie return 1; 172f7cc78ecSespie } 173f7cc78ecSespie 174f7cc78ecSespie 175f7cc78ecSespie static void 176f7cc78ecSespie print_insn ( info, memaddr, num, insn, is_long, show_ext ) 177f7cc78ecSespie struct disassemble_info *info; 178f7cc78ecSespie bfd_vma memaddr; 179f7cc78ecSespie long long num; 180f7cc78ecSespie struct d30v_insn *insn; 181f7cc78ecSespie int is_long; 182f7cc78ecSespie int show_ext; 183f7cc78ecSespie { 184f7cc78ecSespie int val, opnum, need_comma=0; 185f7cc78ecSespie struct d30v_operand *oper; 186f7cc78ecSespie int i, match, opind=0, need_paren=0, found_control=0; 187f7cc78ecSespie 188f7cc78ecSespie (*info->fprintf_func) (info->stream, "%s",insn->op->name); 189f7cc78ecSespie 190f7cc78ecSespie /* check for CMP or CMPU */ 191f7cc78ecSespie if (d30v_operand_table[insn->form->operands[0]].flags & OPERAND_NAME) 192f7cc78ecSespie { 193f7cc78ecSespie opind++; 194f7cc78ecSespie val = extract_value(num,(struct d30v_operand *)&d30v_operand_table[insn->form->operands[0]],is_long); 195f7cc78ecSespie (*info->fprintf_func) (info->stream, "%s",d30v_cc_names[val]); 196f7cc78ecSespie } 197f7cc78ecSespie 198f7cc78ecSespie /* add in ".s" or ".l" */ 199f7cc78ecSespie if (show_ext == 2) 200f7cc78ecSespie { 201f7cc78ecSespie if (is_long) 202f7cc78ecSespie (*info->fprintf_func) (info->stream, ".l"); 203f7cc78ecSespie else 204f7cc78ecSespie (*info->fprintf_func) (info->stream, ".s"); 205f7cc78ecSespie } 206f7cc78ecSespie 207f7cc78ecSespie if (insn->ecc) 208f7cc78ecSespie (*info->fprintf_func) (info->stream, "/%s",d30v_ecc_names[insn->ecc]); 209f7cc78ecSespie 210f7cc78ecSespie (*info->fprintf_func) (info->stream, "\t"); 211f7cc78ecSespie 212f7cc78ecSespie while ((opnum = insn->form->operands[opind++]) != 0) 213f7cc78ecSespie { 214f7cc78ecSespie int bits; 215f7cc78ecSespie oper = (struct d30v_operand *)&d30v_operand_table[opnum]; 216f7cc78ecSespie bits = oper->bits; 217f7cc78ecSespie if (oper->flags & OPERAND_SHIFT) 218f7cc78ecSespie bits += 3; 219f7cc78ecSespie 220f7cc78ecSespie if (need_comma && oper->flags != OPERAND_PLUS && oper->flags != OPERAND_MINUS) 221f7cc78ecSespie { 222f7cc78ecSespie need_comma=0; 223f7cc78ecSespie (*info->fprintf_func) (info->stream, ", "); 224f7cc78ecSespie } 225f7cc78ecSespie 226f7cc78ecSespie if (oper->flags == OPERAND_ATMINUS) 227f7cc78ecSespie { 228f7cc78ecSespie (*info->fprintf_func) (info->stream, "@-"); 229f7cc78ecSespie continue; 230f7cc78ecSespie } 231f7cc78ecSespie if (oper->flags == OPERAND_MINUS) 232f7cc78ecSespie { 233f7cc78ecSespie (*info->fprintf_func) (info->stream, "-"); 234f7cc78ecSespie continue; 235f7cc78ecSespie } 236f7cc78ecSespie if (oper->flags == OPERAND_PLUS) 237f7cc78ecSespie { 238f7cc78ecSespie (*info->fprintf_func) (info->stream, "+"); 239f7cc78ecSespie continue; 240f7cc78ecSespie } 241f7cc78ecSespie if (oper->flags == OPERAND_ATSIGN) 242f7cc78ecSespie { 243f7cc78ecSespie (*info->fprintf_func) (info->stream, "@"); 244f7cc78ecSespie continue; 245f7cc78ecSespie } 246f7cc78ecSespie if (oper->flags == OPERAND_ATPAR) 247f7cc78ecSespie { 248f7cc78ecSespie (*info->fprintf_func) (info->stream, "@("); 249f7cc78ecSespie need_paren = 1; 250f7cc78ecSespie continue; 251f7cc78ecSespie } 252f7cc78ecSespie 253f7cc78ecSespie if (oper->flags == OPERAND_SPECIAL) 254f7cc78ecSespie continue; 255f7cc78ecSespie 256f7cc78ecSespie val = extract_value(num, oper, is_long); 257f7cc78ecSespie 258f7cc78ecSespie if (oper->flags & OPERAND_REG) 259f7cc78ecSespie { 260f7cc78ecSespie match = 0; 261f7cc78ecSespie if (oper->flags & OPERAND_CONTROL) 262f7cc78ecSespie { 263f7cc78ecSespie struct d30v_operand *oper3 = 264f7cc78ecSespie (struct d30v_operand *)&d30v_operand_table[insn->form->operands[2]]; 265f7cc78ecSespie int id = extract_value (num, oper3, is_long ); 266f7cc78ecSespie found_control = 1; 267f7cc78ecSespie switch ( id ) 268f7cc78ecSespie { 269f7cc78ecSespie case 0: 270f7cc78ecSespie val |= OPERAND_CONTROL; 271f7cc78ecSespie break; 272f7cc78ecSespie case 1: 273f7cc78ecSespie case 2: 274f7cc78ecSespie val = OPERAND_CONTROL + MAX_CONTROL_REG + id; 275f7cc78ecSespie break; 276f7cc78ecSespie case 3: 277f7cc78ecSespie val |= OPERAND_FLAG; 278f7cc78ecSespie break; 279f7cc78ecSespie default: 280f7cc78ecSespie fprintf(stderr,"illegal id (%d)\n",id); 281f7cc78ecSespie } 282f7cc78ecSespie } 283f7cc78ecSespie else if (oper->flags & OPERAND_ACC) 284f7cc78ecSespie val |= OPERAND_ACC; 285f7cc78ecSespie else if (oper->flags & OPERAND_FLAG) 286f7cc78ecSespie val |= OPERAND_FLAG; 287f7cc78ecSespie for (i=0;i<reg_name_cnt();i++) 288f7cc78ecSespie { 289f7cc78ecSespie if (val == pre_defined_registers[i].value) 290f7cc78ecSespie { 291f7cc78ecSespie if (pre_defined_registers[i].pname) 292f7cc78ecSespie (*info->fprintf_func) 293f7cc78ecSespie (info->stream, "%s",pre_defined_registers[i].pname); 294f7cc78ecSespie else 295f7cc78ecSespie (*info->fprintf_func) 296f7cc78ecSespie (info->stream, "%s",pre_defined_registers[i].name); 297f7cc78ecSespie match=1; 298f7cc78ecSespie break; 299f7cc78ecSespie } 300f7cc78ecSespie } 301f7cc78ecSespie if (match==0) 302f7cc78ecSespie { 303f7cc78ecSespie /* this would only get executed if a register was not in the 304f7cc78ecSespie register table */ 305f7cc78ecSespie (*info->fprintf_func) 306f7cc78ecSespie (info->stream, _("<unknown register %d>"), val & 0x3F); 307f7cc78ecSespie } 308f7cc78ecSespie } 309f7cc78ecSespie /* repeati has a relocation, but its first argument is a plain 310f7cc78ecSespie immediate. OTOH instructions like djsri have a pc-relative 311f7cc78ecSespie delay target, but a absolute jump target. Therefore, a test 312f7cc78ecSespie of insn->op->reloc_flag is not specific enough; we must test 313f7cc78ecSespie if the actual operand we are handling now is pc-relative. */ 314f7cc78ecSespie else if (oper->flags & OPERAND_PCREL) 315f7cc78ecSespie { 316f7cc78ecSespie int neg = 0; 317f7cc78ecSespie 318f7cc78ecSespie /* IMM6S3 is unsigned. */ 319f7cc78ecSespie if (oper->flags & OPERAND_SIGNED || bits == 32) 320f7cc78ecSespie { 321f7cc78ecSespie long max; 322f7cc78ecSespie max = (1 << (bits - 1)); 323f7cc78ecSespie if (val & max) 324f7cc78ecSespie { 325f7cc78ecSespie if (bits == 32) 326f7cc78ecSespie val = -val; 327f7cc78ecSespie else 328f7cc78ecSespie val = -val & ((1 << bits)-1); 329f7cc78ecSespie neg = 1; 330f7cc78ecSespie } 331f7cc78ecSespie } 332f7cc78ecSespie if (neg) 333f7cc78ecSespie { 334f7cc78ecSespie (*info->fprintf_func) (info->stream, "-%x\t(",val); 335f7cc78ecSespie (*info->print_address_func) ((memaddr - val) & PC_MASK, info); 336f7cc78ecSespie (*info->fprintf_func) (info->stream, ")"); 337f7cc78ecSespie } 338f7cc78ecSespie else 339f7cc78ecSespie { 340f7cc78ecSespie (*info->fprintf_func) (info->stream, "%x\t(",val); 341f7cc78ecSespie (*info->print_address_func) ((memaddr + val) & PC_MASK, info); 342f7cc78ecSespie (*info->fprintf_func) (info->stream, ")"); 343f7cc78ecSespie } 344f7cc78ecSespie } 345f7cc78ecSespie else if (insn->op->reloc_flag == RELOC_ABS) 346f7cc78ecSespie { 347f7cc78ecSespie (*info->print_address_func) (val, info); 348f7cc78ecSespie } 349f7cc78ecSespie else 350f7cc78ecSespie { 351f7cc78ecSespie if (oper->flags & OPERAND_SIGNED) 352f7cc78ecSespie { 353f7cc78ecSespie int max = (1 << (bits - 1)); 354f7cc78ecSespie if (val & max) 355f7cc78ecSespie { 356f7cc78ecSespie val = -val; 357f7cc78ecSespie if (bits < 32) 358f7cc78ecSespie val &= ((1 << bits) - 1); 359f7cc78ecSespie (*info->fprintf_func) (info->stream, "-"); 360f7cc78ecSespie } 361f7cc78ecSespie } 362f7cc78ecSespie (*info->fprintf_func) (info->stream, "0x%x",val); 363f7cc78ecSespie } 364f7cc78ecSespie /* if there is another operand, then write a comma and space */ 365f7cc78ecSespie if (insn->form->operands[opind] && !(found_control && opind == 2)) 366f7cc78ecSespie need_comma = 1; 367f7cc78ecSespie } 368f7cc78ecSespie if (need_paren) 369f7cc78ecSespie (*info->fprintf_func) (info->stream, ")"); 370f7cc78ecSespie } 371f7cc78ecSespie 372f7cc78ecSespie 373f7cc78ecSespie 374f7cc78ecSespie static int 375f7cc78ecSespie extract_value (num, oper, is_long) 376f7cc78ecSespie long long num; 377f7cc78ecSespie struct d30v_operand *oper; 378f7cc78ecSespie int is_long; 379f7cc78ecSespie { 380f7cc78ecSespie int val; 381f7cc78ecSespie int shift = 12 - oper->position; 382f7cc78ecSespie int mask = (0xFFFFFFFF >> (32 - oper->bits)); 383f7cc78ecSespie 384f7cc78ecSespie if (is_long) 385f7cc78ecSespie { 386f7cc78ecSespie if (oper->bits == 32) 387f7cc78ecSespie { 388f7cc78ecSespie /* piece together 32-bit constant */ 389f7cc78ecSespie val = ((num & 0x3FFFF) 390f7cc78ecSespie | ((num & 0xFF00000) >> 2) 391f7cc78ecSespie | ((num & 0x3F00000000LL) >> 6)); 392f7cc78ecSespie } 393f7cc78ecSespie else 394f7cc78ecSespie val = (num >> (32 + shift)) & mask; 395f7cc78ecSespie } 396f7cc78ecSespie else 397f7cc78ecSespie val = (num >> shift) & mask; 398f7cc78ecSespie 399f7cc78ecSespie if (oper->flags & OPERAND_SHIFT) 400f7cc78ecSespie val <<= 3; 401f7cc78ecSespie 402f7cc78ecSespie return val; 403f7cc78ecSespie } 404