diff options
Diffstat (limited to 'opcodes/i860-dis.c')
-rw-r--r-- | opcodes/i860-dis.c | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/opcodes/i860-dis.c b/opcodes/i860-dis.c new file mode 100644 index 0000000..d969200 --- /dev/null +++ b/opcodes/i860-dis.c @@ -0,0 +1,288 @@ +/* Disassembler for the i860. + Copyright 2000 Free Software Foundation, Inc. + + Contributed by Jason Eckhardt <jle@cygnus.com>. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#include "dis-asm.h" +#include "opcode/i860.h" + +/* Later we should probably choose the prefix based on which OS flavor. */ +#define I860_REG_PREFIX "%" + +/* Integer register names (encoded as 0..31 in the instruction). */ +static const char *const grnames[] = + {"r0", "r1", "sp", "fp", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"}; + +/* FP register names (encoded as 0..31 in the instruction). */ +static const char *const frnames[] = + {"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"}; + +/* Control/status register names (encoded as 0..5 in the instruction). */ +static const char *const crnames[] = + {"fir", "psr", "dirbase", "db", "fsr", "epsr", "", ""}; + + +/* Prototypes. */ +static int sign_ext PARAMS((unsigned int, int)); +static void print_br_address PARAMS((disassemble_info *, bfd_vma, int)); + + +/* True if opcode is xor, xorh, and, andh, or, orh, andnot, andnoth. */ +#define BITWISE_OP(op) ((op) == 0x30 || (op) == 0x31 \ + || (op) == 0x34 || (op) == 0x35 \ + || (op) == 0x38 || (op) == 0x39 \ + || (op) == 0x3c || (op) == 0x3d \ + || (op) == 0x33 || (op) == 0x37 \ + || (op) == 0x3b || (op) == 0x3f) + + +/* Sign extend N-bit number. */ +static int +sign_ext (x, n) + unsigned int x; + int n; +{ + int t; + t = x >> (n - 1); + t = ((-t) << n) | x; + return t; +} + + +/* Print a PC-relative branch offset. VAL is the sign extended value + from the branch instruction. */ +static void +print_br_address (info, memaddr, val) + disassemble_info *info; + bfd_vma memaddr; + int val; +{ + + int adj = memaddr + 4 + (val << 2); + + (*info->fprintf_func) (info->stream, "0x%08x", adj); + + /* Attempt to obtain a symbol for the target address. */ + + if (info->print_address_func && adj != 0) + { + (*info->fprintf_func) (info->stream, "\t// "); + (*info->print_address_func) (adj, info); + } +} + + +/* Print one instruction. */ +int +print_insn_i860 (memaddr, info) + bfd_vma memaddr; + disassemble_info *info; +{ + bfd_byte buff[4]; + unsigned int insn, i; + int status; + const struct i860_opcode *opcode = 0; + + status = (*info->read_memory_func) (memaddr, buff, sizeof (buff), info); + if (status != 0) + { + (*info->memory_error_func) (status, memaddr, info); + return -1; + } + + /* Note that i860 instructions are always accessed as little endian + data, regardless of the endian mode of the i860. */ + insn = bfd_getl32 (buff); + + status = 0; + i = 0; + while (i860_opcodes[i].name != NULL) + { + opcode = &i860_opcodes[i]; + if ((insn & opcode->match) == opcode->match + && (insn & opcode->lose) == 0) + { + status = 1; + break; + } + ++i; + } + + if (status == 0) + { + /* Instruction not in opcode table. */ + (*info->fprintf_func) (info->stream, ".long %#08x", insn); + } + else + { + const char *s; + int val; + + /* If this a flop and its dual bit is set, prefix with 'd.'. */ + if ((insn & 0xfc000000) == 0x48000000 && (insn & 0x200)) + (*info->fprintf_func) (info->stream, "d.%s\t", opcode->name); + else + (*info->fprintf_func) (info->stream, "%s\t", opcode->name); + + for (s = opcode->args; *s; s++) + { + switch (*s) + { + /* Integer register (src1). */ + case '1': + (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, + grnames[(insn >> 11) & 0x1f]); + break; + + /* Integer register (src2). */ + case '2': + (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, + grnames[(insn >> 21) & 0x1f]); + break; + + /* Integer destination register. */ + case 'd': + (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, + grnames[(insn >> 16) & 0x1f]); + break; + + /* Floating-point register (src1). */ + case 'e': + (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, + frnames[(insn >> 11) & 0x1f]); + break; + + /* Floating-point register (src2). */ + case 'f': + (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, + frnames[(insn >> 21) & 0x1f]); + break; + + /* Floating-point destination register. */ + case 'g': + (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, + frnames[(insn >> 16) & 0x1f]); + break; + + /* Control register. */ + case 'c': + (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, + crnames[(insn >> 21) & 0x7]); + break; + + /* 16-bit immediate (sign extend, except for bitwise ops). */ + case 'i': + if (BITWISE_OP ((insn & 0xfc000000) >> 26)) + (*info->fprintf_func) (info->stream, "0x%04x", + (unsigned int) (insn & 0xffff)); + else + (*info->fprintf_func) (info->stream, "%d", + sign_ext ((insn & 0xffff), 16)); + break; + + /* 16-bit immediate, aligned (2^0, ld.b). */ + case 'I': + (*info->fprintf_func) (info->stream, "%d", + sign_ext ((insn & 0xffff), 16)); + break; + + /* 16-bit immediate, aligned (2^1, ld.s). */ + case 'J': + (*info->fprintf_func) (info->stream, "%d", + sign_ext ((insn & 0xfffe), 16)); + break; + + /* 16-bit immediate, aligned (2^2, ld.l, {p}fld.l, fst.l). */ + case 'K': + (*info->fprintf_func) (info->stream, "%d", + sign_ext ((insn & 0xfffc), 16)); + break; + + /* 16-bit immediate, aligned (2^3, {p}fld.d, fst.d). */ + case 'L': + (*info->fprintf_func) (info->stream, "%d", + sign_ext ((insn & 0xfff8), 16)); + break; + + /* 16-bit immediate, aligned (2^4, {p}fld.q, fst.q). */ + case 'M': + (*info->fprintf_func) (info->stream, "%d", + sign_ext ((insn & 0xfff0), 16)); + break; + + /* 5-bit immediate (zero extend). */ + case '5': + (*info->fprintf_func) (info->stream, "%d", + ((insn >> 11) & 0x1f)); + break; + + /* Split 16 bit immediate (20..16:10..0). */ + case 's': + val = ((insn >> 5) & 0xf800) | (insn & 0x07ff); + (*info->fprintf_func) (info->stream, "%d", + sign_ext (val, 16)); + break; + + /* Split 16 bit immediate, aligned. (2^0, st.b). */ + case 'S': + val = ((insn >> 5) & 0xf800) | (insn & 0x07ff); + (*info->fprintf_func) (info->stream, "%d", + sign_ext (val, 16)); + break; + + /* Split 16 bit immediate, aligned. (2^1, st.s). */ + case 'T': + val = ((insn >> 5) & 0xf800) | (insn & 0x07fe); + (*info->fprintf_func) (info->stream, "%d", + sign_ext (val, 16)); + break; + + /* Split 16 bit immediate, aligned. (2^2, st.l). */ + case 'U': + val = ((insn >> 5) & 0xf800) | (insn & 0x07fc); + (*info->fprintf_func) (info->stream, "%d", + sign_ext (val, 16)); + break; + + /* 26-bit PC relative immediate (lbroff). */ + case 'l': + val = sign_ext ((insn & 0x03ffffff), 26); + print_br_address (info, memaddr, val); + break; + + /* 16-bit PC relative immediate (sbroff). */ + case 'r': + val = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16); + print_br_address (info, memaddr, val); + break; + + default: + (*info->fprintf_func) (info->stream, "%c", *s); + break; + } + } + } + + return sizeof (insn); +} + |