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