1 1.1 christos /* Disassemble Xilinx microblaze instructions. 2 1.1 christos 3 1.1.1.9 christos Copyright (C) 2009-2024 Free Software Foundation, Inc. 4 1.1 christos 5 1.1 christos This file is part of the GNU opcodes library. 6 1.1 christos 7 1.1 christos This library is free software; you can redistribute it and/or modify 8 1.1 christos it under the terms of the GNU General Public License as published by 9 1.1 christos the Free Software Foundation; either version 3, or (at your option) 10 1.1 christos any later version. 11 1.1 christos 12 1.1 christos It is distributed in the hope that it will be useful, but WITHOUT 13 1.1 christos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 1.1 christos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15 1.1 christos License for more details. 16 1.1 christos 17 1.1 christos You should have received a copy of the GNU General Public License 18 1.1 christos along with this file; see the file COPYING. If not, write to the 19 1.1 christos Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, 20 1.1 christos MA 02110-1301, USA. */ 21 1.1 christos 22 1.1 christos 23 1.1 christos #include "sysdep.h" 24 1.1 christos #define STATIC_TABLE 25 1.1 christos #define DEFINE_TABLE 26 1.1 christos 27 1.1.1.6 christos #include "disassemble.h" 28 1.1 christos #include <strings.h> 29 1.1 christos #include "microblaze-opc.h" 30 1.1 christos #include "microblaze-dis.h" 31 1.1 christos 32 1.1.1.7 christos #define get_field_rd(buf, instr) get_field (buf, instr, RD_MASK, RD_LOW) 33 1.1.1.7 christos #define get_field_r1(buf, instr) get_field (buf, instr, RA_MASK, RA_LOW) 34 1.1.1.7 christos #define get_field_r2(buf, instr) get_field (buf, instr, RB_MASK, RB_LOW) 35 1.1 christos #define get_int_field_imm(instr) ((instr & IMM_MASK) >> IMM_LOW) 36 1.1 christos #define get_int_field_r1(instr) ((instr & RA_MASK) >> RA_LOW) 37 1.1 christos 38 1.1.1.9 christos #define NUM_STRBUFS 4 39 1.1.1.7 christos #define STRBUF_SIZE 25 40 1.1 christos 41 1.1.1.7 christos struct string_buf 42 1.1.1.7 christos { 43 1.1.1.7 christos unsigned int which; 44 1.1.1.7 christos char str[NUM_STRBUFS][STRBUF_SIZE]; 45 1.1.1.7 christos }; 46 1.1.1.7 christos 47 1.1.1.7 christos static inline char * 48 1.1.1.7 christos strbuf (struct string_buf *buf) 49 1.1.1.7 christos { 50 1.1.1.7 christos #ifdef ENABLE_CHECKING 51 1.1.1.7 christos if (buf->which >= NUM_STRBUFS) 52 1.1.1.7 christos abort (); 53 1.1.1.7 christos #endif 54 1.1.1.7 christos return buf->str[buf->which++]; 55 1.1.1.7 christos } 56 1.1 christos 57 1.1 christos static char * 58 1.1.1.7 christos get_field (struct string_buf *buf, long instr, long mask, unsigned short low) 59 1.1 christos { 60 1.1.1.7 christos char *p = strbuf (buf); 61 1.1 christos 62 1.1.1.7 christos sprintf (p, "%s%d", register_prefix, (int)((instr & mask) >> low)); 63 1.1.1.7 christos return p; 64 1.1 christos } 65 1.1 christos 66 1.1 christos static char * 67 1.1.1.7 christos get_field_imm (struct string_buf *buf, long instr) 68 1.1 christos { 69 1.1.1.7 christos char *p = strbuf (buf); 70 1.1 christos 71 1.1.1.7 christos sprintf (p, "%d", (short)((instr & IMM_MASK) >> IMM_LOW)); 72 1.1.1.7 christos return p; 73 1.1 christos } 74 1.1 christos 75 1.1 christos static char * 76 1.1.1.7 christos get_field_imm5 (struct string_buf *buf, long instr) 77 1.1 christos { 78 1.1.1.7 christos char *p = strbuf (buf); 79 1.1 christos 80 1.1.1.7 christos sprintf (p, "%d", (short)((instr & IMM5_MASK) >> IMM_LOW)); 81 1.1.1.7 christos return p; 82 1.1 christos } 83 1.1 christos 84 1.1 christos static char * 85 1.1.1.7 christos get_field_imm5_mbar (struct string_buf *buf, long instr) 86 1.1.1.2 christos { 87 1.1.1.7 christos char *p = strbuf (buf); 88 1.1.1.2 christos 89 1.1.1.7 christos sprintf (p, "%d", (short)((instr & IMM5_MBAR_MASK) >> IMM_MBAR)); 90 1.1.1.7 christos return p; 91 1.1.1.2 christos } 92 1.1.1.2 christos 93 1.1.1.2 christos static char * 94 1.1.1.9 christos get_field_immw (struct string_buf *buf, long instr) 95 1.1.1.9 christos { 96 1.1.1.9 christos char *p = strbuf (buf); 97 1.1.1.9 christos 98 1.1.1.9 christos if (instr & 0x00004000) 99 1.1.1.9 christos sprintf (p, "%d", (short)(((instr & IMM5_WIDTH_MASK) 100 1.1.1.9 christos >> IMM_WIDTH_LOW))); /* bsefi */ 101 1.1.1.9 christos else 102 1.1.1.9 christos sprintf (p, "%d", (short)(((instr & IMM5_WIDTH_MASK) >> 103 1.1.1.9 christos IMM_WIDTH_LOW) - ((instr & IMM5_MASK) >> 104 1.1.1.9 christos IMM_LOW) + 1)); /* bsifi */ 105 1.1.1.9 christos return p; 106 1.1.1.9 christos } 107 1.1.1.9 christos 108 1.1.1.9 christos static char * 109 1.1.1.7 christos get_field_rfsl (struct string_buf *buf, long instr) 110 1.1 christos { 111 1.1.1.7 christos char *p = strbuf (buf); 112 1.1 christos 113 1.1.1.7 christos sprintf (p, "%s%d", fsl_register_prefix, 114 1.1 christos (short)((instr & RFSL_MASK) >> IMM_LOW)); 115 1.1.1.7 christos return p; 116 1.1 christos } 117 1.1 christos 118 1.1 christos static char * 119 1.1.1.7 christos get_field_imm15 (struct string_buf *buf, long instr) 120 1.1 christos { 121 1.1.1.7 christos char *p = strbuf (buf); 122 1.1 christos 123 1.1.1.7 christos sprintf (p, "%d", (short)((instr & IMM15_MASK) >> IMM_LOW)); 124 1.1.1.7 christos return p; 125 1.1 christos } 126 1.1 christos 127 1.1 christos static char * 128 1.1.1.7 christos get_field_special (struct string_buf *buf, long instr, 129 1.1.1.8 christos const struct op_code_struct *op) 130 1.1 christos { 131 1.1.1.7 christos char *p = strbuf (buf); 132 1.1.1.7 christos char *spr; 133 1.1 christos 134 1.1 christos switch ((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask)) 135 1.1 christos { 136 1.1 christos case REG_MSR_MASK : 137 1.1.1.7 christos spr = "msr"; 138 1.1 christos break; 139 1.1 christos case REG_PC_MASK : 140 1.1.1.7 christos spr = "pc"; 141 1.1 christos break; 142 1.1 christos case REG_EAR_MASK : 143 1.1.1.7 christos spr = "ear"; 144 1.1 christos break; 145 1.1 christos case REG_ESR_MASK : 146 1.1.1.7 christos spr = "esr"; 147 1.1 christos break; 148 1.1 christos case REG_FSR_MASK : 149 1.1.1.7 christos spr = "fsr"; 150 1.1 christos break; 151 1.1 christos case REG_BTR_MASK : 152 1.1.1.7 christos spr = "btr"; 153 1.1 christos break; 154 1.1 christos case REG_EDR_MASK : 155 1.1.1.7 christos spr = "edr"; 156 1.1 christos break; 157 1.1 christos case REG_PID_MASK : 158 1.1.1.7 christos spr = "pid"; 159 1.1 christos break; 160 1.1 christos case REG_ZPR_MASK : 161 1.1.1.7 christos spr = "zpr"; 162 1.1 christos break; 163 1.1 christos case REG_TLBX_MASK : 164 1.1.1.7 christos spr = "tlbx"; 165 1.1 christos break; 166 1.1 christos case REG_TLBLO_MASK : 167 1.1.1.7 christos spr = "tlblo"; 168 1.1 christos break; 169 1.1 christos case REG_TLBHI_MASK : 170 1.1.1.7 christos spr = "tlbhi"; 171 1.1 christos break; 172 1.1 christos case REG_TLBSX_MASK : 173 1.1.1.7 christos spr = "tlbsx"; 174 1.1 christos break; 175 1.1.1.2 christos case REG_SHR_MASK : 176 1.1.1.7 christos spr = "shr"; 177 1.1.1.2 christos break; 178 1.1.1.2 christos case REG_SLR_MASK : 179 1.1.1.7 christos spr = "slr"; 180 1.1.1.2 christos break; 181 1.1 christos default : 182 1.1 christos if (((((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) & 0xE000) 183 1.1.1.7 christos == REG_PVR_MASK) 184 1.1.1.7 christos { 185 1.1.1.7 christos sprintf (p, "%spvr%d", register_prefix, 186 1.1 christos (unsigned short)(((instr & IMM_MASK) >> IMM_LOW) 187 1.1.1.7 christos ^ op->immval_mask) ^ REG_PVR_MASK); 188 1.1.1.7 christos return p; 189 1.1.1.7 christos } 190 1.1 christos else 191 1.1.1.7 christos spr = "pc"; 192 1.1 christos break; 193 1.1 christos } 194 1.1 christos 195 1.1.1.7 christos sprintf (p, "%s%s", register_prefix, spr); 196 1.1.1.7 christos return p; 197 1.1 christos } 198 1.1 christos 199 1.1 christos static unsigned long 200 1.1 christos read_insn_microblaze (bfd_vma memaddr, 201 1.1 christos struct disassemble_info *info, 202 1.1.1.8 christos const struct op_code_struct **opr) 203 1.1 christos { 204 1.1 christos unsigned char ibytes[4]; 205 1.1 christos int status; 206 1.1.1.8 christos const struct op_code_struct *op; 207 1.1 christos unsigned long inst; 208 1.1 christos 209 1.1 christos status = info->read_memory_func (memaddr, ibytes, 4, info); 210 1.1 christos 211 1.1 christos if (status != 0) 212 1.1 christos { 213 1.1 christos info->memory_error_func (status, memaddr, info); 214 1.1 christos return 0; 215 1.1 christos } 216 1.1 christos 217 1.1 christos if (info->endian == BFD_ENDIAN_BIG) 218 1.1.1.7 christos inst = (((unsigned) ibytes[0] << 24) | (ibytes[1] << 16) 219 1.1.1.7 christos | (ibytes[2] << 8) | ibytes[3]); 220 1.1 christos else if (info->endian == BFD_ENDIAN_LITTLE) 221 1.1.1.7 christos inst = (((unsigned) ibytes[3] << 24) | (ibytes[2] << 16) 222 1.1.1.7 christos | (ibytes[1] << 8) | ibytes[0]); 223 1.1 christos else 224 1.1 christos abort (); 225 1.1 christos 226 1.1 christos /* Just a linear search of the table. */ 227 1.1.1.8 christos for (op = microblaze_opcodes; op->name != 0; op ++) 228 1.1 christos if (op->bit_sequence == (inst & op->opcode_mask)) 229 1.1 christos break; 230 1.1 christos 231 1.1 christos *opr = op; 232 1.1 christos return inst; 233 1.1 christos } 234 1.1 christos 235 1.1 christos 236 1.1 christos int 237 1.1 christos print_insn_microblaze (bfd_vma memaddr, struct disassemble_info * info) 238 1.1 christos { 239 1.1.1.8 christos fprintf_ftype print_func = info->fprintf_func; 240 1.1.1.8 christos void *stream = info->stream; 241 1.1.1.8 christos unsigned long inst, prev_inst; 242 1.1.1.8 christos const struct op_code_struct *op, *pop; 243 1.1.1.8 christos int immval = 0; 244 1.1.1.8 christos bool immfound = false; 245 1.1.1.8 christos static bfd_vma prev_insn_addr = -1; /* Init the prev insn addr. */ 246 1.1.1.8 christos static int prev_insn_vma = -1; /* Init the prev insn vma. */ 247 1.1.1.8 christos int curr_insn_vma = info->buffer_vma; 248 1.1.1.8 christos struct string_buf buf; 249 1.1 christos 250 1.1.1.7 christos buf.which = 0; 251 1.1 christos info->bytes_per_chunk = 4; 252 1.1 christos 253 1.1 christos inst = read_insn_microblaze (memaddr, info, &op); 254 1.1 christos if (inst == 0) 255 1.1 christos return -1; 256 1.1 christos 257 1.1 christos if (prev_insn_vma == curr_insn_vma) 258 1.1 christos { 259 1.1 christos if (memaddr-(info->bytes_per_chunk) == prev_insn_addr) 260 1.1.1.7 christos { 261 1.1.1.7 christos prev_inst = read_insn_microblaze (prev_insn_addr, info, &pop); 262 1.1 christos if (prev_inst == 0) 263 1.1 christos return -1; 264 1.1 christos if (pop->instr == imm) 265 1.1 christos { 266 1.1 christos immval = (get_int_field_imm (prev_inst) << 16) & 0xffff0000; 267 1.1.1.8 christos immfound = true; 268 1.1 christos } 269 1.1 christos else 270 1.1 christos { 271 1.1 christos immval = 0; 272 1.1.1.8 christos immfound = false; 273 1.1 christos } 274 1.1 christos } 275 1.1 christos } 276 1.1 christos 277 1.1 christos /* Make curr insn as prev insn. */ 278 1.1 christos prev_insn_addr = memaddr; 279 1.1 christos prev_insn_vma = curr_insn_vma; 280 1.1 christos 281 1.1 christos if (op->name == NULL) 282 1.1.1.9 christos print_func (stream, ".long 0x%04x", (unsigned int) inst); 283 1.1 christos else 284 1.1 christos { 285 1.1 christos print_func (stream, "%s", op->name); 286 1.1 christos 287 1.1 christos switch (op->inst_type) 288 1.1 christos { 289 1.1.1.7 christos case INST_TYPE_RD_R1_R2: 290 1.1.1.7 christos print_func (stream, "\t%s, %s, %s", get_field_rd (&buf, inst), 291 1.1.1.7 christos get_field_r1 (&buf, inst), get_field_r2 (&buf, inst)); 292 1.1.1.7 christos break; 293 1.1.1.7 christos case INST_TYPE_RD_R1_IMM: 294 1.1.1.7 christos print_func (stream, "\t%s, %s, %s", get_field_rd (&buf, inst), 295 1.1.1.7 christos get_field_r1 (&buf, inst), get_field_imm (&buf, inst)); 296 1.1 christos if (info->print_address_func && get_int_field_r1 (inst) == 0 297 1.1 christos && info->symbol_at_address_func) 298 1.1 christos { 299 1.1 christos if (immfound) 300 1.1.1.7 christos immval |= (get_int_field_imm (inst) & 0x0000ffff); 301 1.1 christos else 302 1.1 christos { 303 1.1.1.7 christos immval = get_int_field_imm (inst); 304 1.1.1.7 christos if (immval & 0x8000) 305 1.1 christos immval |= 0xFFFF0000; 306 1.1.1.7 christos } 307 1.1 christos if (immval > 0 && info->symbol_at_address_func (immval, info)) 308 1.1 christos { 309 1.1.1.7 christos print_func (stream, "\t// "); 310 1.1.1.7 christos info->print_address_func (immval, info); 311 1.1.1.7 christos } 312 1.1 christos } 313 1.1 christos break; 314 1.1 christos case INST_TYPE_RD_R1_IMM5: 315 1.1.1.7 christos print_func (stream, "\t%s, %s, %s", get_field_rd (&buf, inst), 316 1.1.1.7 christos get_field_r1 (&buf, inst), get_field_imm5 (&buf, inst)); 317 1.1 christos break; 318 1.1 christos case INST_TYPE_RD_RFSL: 319 1.1.1.7 christos print_func (stream, "\t%s, %s", get_field_rd (&buf, inst), 320 1.1.1.7 christos get_field_rfsl (&buf, inst)); 321 1.1 christos break; 322 1.1 christos case INST_TYPE_R1_RFSL: 323 1.1.1.7 christos print_func (stream, "\t%s, %s", get_field_r1 (&buf, inst), 324 1.1.1.7 christos get_field_rfsl (&buf, inst)); 325 1.1 christos break; 326 1.1 christos case INST_TYPE_RD_SPECIAL: 327 1.1.1.7 christos print_func (stream, "\t%s, %s", get_field_rd (&buf, inst), 328 1.1.1.7 christos get_field_special (&buf, inst, op)); 329 1.1 christos break; 330 1.1 christos case INST_TYPE_SPECIAL_R1: 331 1.1.1.7 christos print_func (stream, "\t%s, %s", get_field_special (&buf, inst, op), 332 1.1.1.7 christos get_field_r1 (&buf, inst)); 333 1.1 christos break; 334 1.1 christos case INST_TYPE_RD_R1: 335 1.1.1.7 christos print_func (stream, "\t%s, %s", get_field_rd (&buf, inst), 336 1.1.1.7 christos get_field_r1 (&buf, inst)); 337 1.1 christos break; 338 1.1 christos case INST_TYPE_R1_R2: 339 1.1.1.7 christos print_func (stream, "\t%s, %s", get_field_r1 (&buf, inst), 340 1.1.1.7 christos get_field_r2 (&buf, inst)); 341 1.1 christos break; 342 1.1 christos case INST_TYPE_R1_IMM: 343 1.1.1.7 christos print_func (stream, "\t%s, %s", get_field_r1 (&buf, inst), 344 1.1.1.7 christos get_field_imm (&buf, inst)); 345 1.1 christos /* The non-pc relative instructions are returns, which shouldn't 346 1.1 christos have a label printed. */ 347 1.1 christos if (info->print_address_func && op->inst_offset_type == INST_PC_OFFSET 348 1.1 christos && info->symbol_at_address_func) 349 1.1 christos { 350 1.1 christos if (immfound) 351 1.1.1.7 christos immval |= (get_int_field_imm (inst) & 0x0000ffff); 352 1.1 christos else 353 1.1 christos { 354 1.1.1.7 christos immval = get_int_field_imm (inst); 355 1.1.1.7 christos if (immval & 0x8000) 356 1.1 christos immval |= 0xFFFF0000; 357 1.1.1.7 christos } 358 1.1 christos immval += memaddr; 359 1.1 christos if (immval > 0 && info->symbol_at_address_func (immval, info)) 360 1.1 christos { 361 1.1.1.7 christos print_func (stream, "\t// "); 362 1.1.1.7 christos info->print_address_func (immval, info); 363 1.1.1.7 christos } 364 1.1 christos else 365 1.1 christos { 366 1.1.1.7 christos print_func (stream, "\t\t// "); 367 1.1.1.7 christos print_func (stream, "%x", immval); 368 1.1.1.7 christos } 369 1.1 christos } 370 1.1 christos break; 371 1.1.1.7 christos case INST_TYPE_RD_IMM: 372 1.1.1.7 christos print_func (stream, "\t%s, %s", get_field_rd (&buf, inst), 373 1.1.1.7 christos get_field_imm (&buf, inst)); 374 1.1 christos if (info->print_address_func && info->symbol_at_address_func) 375 1.1 christos { 376 1.1.1.7 christos if (immfound) 377 1.1.1.7 christos immval |= (get_int_field_imm (inst) & 0x0000ffff); 378 1.1.1.7 christos else 379 1.1.1.7 christos { 380 1.1.1.7 christos immval = get_int_field_imm (inst); 381 1.1.1.7 christos if (immval & 0x8000) 382 1.1.1.7 christos immval |= 0xFFFF0000; 383 1.1.1.7 christos } 384 1.1.1.7 christos if (op->inst_offset_type == INST_PC_OFFSET) 385 1.1.1.7 christos immval += (int) memaddr; 386 1.1.1.7 christos if (info->symbol_at_address_func (immval, info)) 387 1.1.1.7 christos { 388 1.1.1.7 christos print_func (stream, "\t// "); 389 1.1.1.7 christos info->print_address_func (immval, info); 390 1.1.1.7 christos } 391 1.1 christos } 392 1.1 christos break; 393 1.1.1.7 christos case INST_TYPE_IMM: 394 1.1.1.7 christos print_func (stream, "\t%s", get_field_imm (&buf, inst)); 395 1.1 christos if (info->print_address_func && info->symbol_at_address_func 396 1.1 christos && op->instr != imm) 397 1.1 christos { 398 1.1 christos if (immfound) 399 1.1.1.7 christos immval |= (get_int_field_imm (inst) & 0x0000ffff); 400 1.1 christos else 401 1.1 christos { 402 1.1.1.7 christos immval = get_int_field_imm (inst); 403 1.1.1.7 christos if (immval & 0x8000) 404 1.1 christos immval |= 0xFFFF0000; 405 1.1.1.7 christos } 406 1.1 christos if (op->inst_offset_type == INST_PC_OFFSET) 407 1.1.1.7 christos immval += (int) memaddr; 408 1.1 christos if (immval > 0 && info->symbol_at_address_func (immval, info)) 409 1.1 christos { 410 1.1.1.7 christos print_func (stream, "\t// "); 411 1.1.1.7 christos info->print_address_func (immval, info); 412 1.1.1.7 christos } 413 1.1 christos else if (op->inst_offset_type == INST_PC_OFFSET) 414 1.1 christos { 415 1.1.1.7 christos print_func (stream, "\t\t// "); 416 1.1.1.7 christos print_func (stream, "%x", immval); 417 1.1.1.7 christos } 418 1.1 christos } 419 1.1 christos break; 420 1.1.1.7 christos case INST_TYPE_RD_R2: 421 1.1.1.7 christos print_func (stream, "\t%s, %s", get_field_rd (&buf, inst), 422 1.1.1.7 christos get_field_r2 (&buf, inst)); 423 1.1 christos break; 424 1.1 christos case INST_TYPE_R2: 425 1.1.1.7 christos print_func (stream, "\t%s", get_field_r2 (&buf, inst)); 426 1.1 christos break; 427 1.1 christos case INST_TYPE_R1: 428 1.1.1.7 christos print_func (stream, "\t%s", get_field_r1 (&buf, inst)); 429 1.1 christos break; 430 1.1.1.2 christos case INST_TYPE_R1_R2_SPECIAL: 431 1.1.1.7 christos print_func (stream, "\t%s, %s", get_field_r1 (&buf, inst), 432 1.1.1.7 christos get_field_r2 (&buf, inst)); 433 1.1 christos break; 434 1.1 christos case INST_TYPE_RD_IMM15: 435 1.1.1.7 christos print_func (stream, "\t%s, %s", get_field_rd (&buf, inst), 436 1.1.1.7 christos get_field_imm15 (&buf, inst)); 437 1.1 christos break; 438 1.1.1.7 christos /* For mbar insn. */ 439 1.1.1.7 christos case INST_TYPE_IMM5: 440 1.1.1.7 christos print_func (stream, "\t%s", get_field_imm5_mbar (&buf, inst)); 441 1.1.1.7 christos break; 442 1.1.1.7 christos /* For mbar 16 or sleep insn. */ 443 1.1.1.7 christos case INST_TYPE_NONE: 444 1.1.1.7 christos break; 445 1.1.1.9 christos /* For bit field insns. */ 446 1.1.1.9 christos case INST_TYPE_RD_R1_IMMW_IMMS: 447 1.1.1.9 christos print_func (stream, "\t%s, %s, %s, %s", 448 1.1.1.9 christos get_field_rd (&buf, inst), 449 1.1.1.9 christos get_field_r1 (&buf, inst), 450 1.1.1.9 christos get_field_immw (&buf, inst), 451 1.1.1.9 christos get_field_imm5 (&buf, inst)); 452 1.1.1.9 christos break; 453 1.1.1.7 christos /* For tuqula instruction */ 454 1.1 christos case INST_TYPE_RD: 455 1.1.1.7 christos print_func (stream, "\t%s", get_field_rd (&buf, inst)); 456 1.1 christos break; 457 1.1 christos case INST_TYPE_RFSL: 458 1.1.1.7 christos print_func (stream, "\t%s", get_field_rfsl (&buf, inst)); 459 1.1 christos break; 460 1.1 christos default: 461 1.1 christos /* If the disassembler lags the instruction set. */ 462 1.1.1.7 christos print_func (stream, "\tundecoded operands, inst is 0x%04x", 463 1.1.1.7 christos (unsigned int) inst); 464 1.1 christos break; 465 1.1 christos } 466 1.1 christos } 467 1.1 christos 468 1.1 christos /* Say how many bytes we consumed. */ 469 1.1 christos return 4; 470 1.1 christos } 471 1.1 christos 472 1.1 christos enum microblaze_instr 473 1.1 christos get_insn_microblaze (long inst, 474 1.1.1.8 christos bool *isunsignedimm, 475 1.1 christos enum microblaze_instr_type *insn_type, 476 1.1 christos short *delay_slots) 477 1.1 christos { 478 1.1.1.8 christos const struct op_code_struct *op; 479 1.1.1.8 christos *isunsignedimm = false; 480 1.1 christos 481 1.1 christos /* Just a linear search of the table. */ 482 1.1.1.8 christos for (op = microblaze_opcodes; op->name != 0; op ++) 483 1.1 christos if (op->bit_sequence == (inst & op->opcode_mask)) 484 1.1 christos break; 485 1.1 christos 486 1.1 christos if (op->name == 0) 487 1.1 christos return invalid_inst; 488 1.1 christos else 489 1.1 christos { 490 1.1 christos *isunsignedimm = (op->inst_type == INST_TYPE_RD_R1_UNSIGNED_IMM); 491 1.1 christos *insn_type = op->instr_type; 492 1.1 christos *delay_slots = op->delay_slots; 493 1.1 christos return op->instr; 494 1.1 christos } 495 1.1 christos } 496 1.1 christos 497 1.1 christos enum microblaze_instr 498 1.1 christos microblaze_decode_insn (long insn, int *rd, int *ra, int *rb, int *immed) 499 1.1 christos { 500 1.1 christos enum microblaze_instr op; 501 1.1.1.8 christos bool t1; 502 1.1 christos enum microblaze_instr_type t2; 503 1.1 christos short t3; 504 1.1 christos 505 1.1 christos op = get_insn_microblaze (insn, &t1, &t2, &t3); 506 1.1 christos *rd = (insn & RD_MASK) >> RD_LOW; 507 1.1 christos *ra = (insn & RA_MASK) >> RA_LOW; 508 1.1 christos *rb = (insn & RB_MASK) >> RB_LOW; 509 1.1 christos t3 = (insn & IMM_MASK) >> IMM_LOW; 510 1.1 christos *immed = (int) t3; 511 1.1 christos return (op); 512 1.1 christos } 513 1.1 christos 514 1.1 christos unsigned long 515 1.1.1.8 christos microblaze_get_target_address (long inst, bool immfound, int immval, 516 1.1 christos long pcval, long r1val, long r2val, 517 1.1.1.8 christos bool *targetvalid, 518 1.1.1.8 christos bool *unconditionalbranch) 519 1.1 christos { 520 1.1.1.8 christos const struct op_code_struct *op; 521 1.1 christos long targetaddr = 0; 522 1.1 christos 523 1.1.1.8 christos *unconditionalbranch = false; 524 1.1 christos /* Just a linear search of the table. */ 525 1.1.1.8 christos for (op = microblaze_opcodes; op->name != 0; op ++) 526 1.1 christos if (op->bit_sequence == (inst & op->opcode_mask)) 527 1.1 christos break; 528 1.1 christos 529 1.1 christos if (op->name == 0) 530 1.1 christos { 531 1.1.1.8 christos *targetvalid = false; 532 1.1 christos } 533 1.1 christos else if (op->instr_type == branch_inst) 534 1.1 christos { 535 1.1 christos switch (op->inst_type) 536 1.1 christos { 537 1.1 christos case INST_TYPE_R2: 538 1.1.1.8 christos *unconditionalbranch = true; 539 1.1 christos /* Fall through. */ 540 1.1 christos case INST_TYPE_RD_R2: 541 1.1 christos case INST_TYPE_R1_R2: 542 1.1 christos targetaddr = r2val; 543 1.1.1.8 christos *targetvalid = true; 544 1.1 christos if (op->inst_offset_type == INST_PC_OFFSET) 545 1.1 christos targetaddr += pcval; 546 1.1 christos break; 547 1.1 christos case INST_TYPE_IMM: 548 1.1.1.8 christos *unconditionalbranch = true; 549 1.1 christos /* Fall through. */ 550 1.1 christos case INST_TYPE_RD_IMM: 551 1.1 christos case INST_TYPE_R1_IMM: 552 1.1 christos if (immfound) 553 1.1 christos { 554 1.1 christos targetaddr = (immval << 16) & 0xffff0000; 555 1.1 christos targetaddr |= (get_int_field_imm (inst) & 0x0000ffff); 556 1.1 christos } 557 1.1 christos else 558 1.1 christos { 559 1.1 christos targetaddr = get_int_field_imm (inst); 560 1.1 christos if (targetaddr & 0x8000) 561 1.1 christos targetaddr |= 0xFFFF0000; 562 1.1 christos } 563 1.1 christos if (op->inst_offset_type == INST_PC_OFFSET) 564 1.1 christos targetaddr += pcval; 565 1.1.1.8 christos *targetvalid = true; 566 1.1 christos break; 567 1.1 christos default: 568 1.1.1.8 christos *targetvalid = false; 569 1.1 christos break; 570 1.1 christos } 571 1.1 christos } 572 1.1 christos else if (op->instr_type == return_inst) 573 1.1 christos { 574 1.1 christos if (immfound) 575 1.1 christos { 576 1.1 christos targetaddr = (immval << 16) & 0xffff0000; 577 1.1 christos targetaddr |= (get_int_field_imm (inst) & 0x0000ffff); 578 1.1 christos } 579 1.1 christos else 580 1.1 christos { 581 1.1 christos targetaddr = get_int_field_imm (inst); 582 1.1 christos if (targetaddr & 0x8000) 583 1.1 christos targetaddr |= 0xFFFF0000; 584 1.1 christos } 585 1.1 christos targetaddr += r1val; 586 1.1.1.8 christos *targetvalid = true; 587 1.1 christos } 588 1.1 christos else 589 1.1.1.8 christos *targetvalid = false; 590 1.1 christos return targetaddr; 591 1.1 christos } 592