1 /* Disassembler for the i860. 2 Copyright (C) 2000-2014 Free Software Foundation, Inc. 3 4 Contributed by Jason Eckhardt <jle (at) cygnus.com>. 5 6 This file is part of the GNU opcodes library. 7 8 This library is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 3, or (at your option) 11 any later version. 12 13 It is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 16 License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 21 MA 02110-1301, USA. */ 22 23 #include "sysdep.h" 24 #include "dis-asm.h" 25 #include "opcode/i860.h" 26 27 /* Later we should probably choose the prefix based on which OS flavor. */ 28 #define I860_REG_PREFIX "%" 29 30 /* Integer register names (encoded as 0..31 in the instruction). */ 31 static const char *const grnames[] = 32 {"r0", "r1", "sp", "fp", "r4", "r5", "r6", "r7", 33 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 34 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 35 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"}; 36 37 /* FP register names (encoded as 0..31 in the instruction). */ 38 static const char *const frnames[] = 39 {"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", 40 "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", 41 "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", 42 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"}; 43 44 /* Control/status register names (encoded as 0..11 in the instruction). 45 Registers bear, ccr, p0, p1, p2 and p3 are XP only. */ 46 static const char *const crnames[] = 47 {"fir", "psr", "dirbase", "db", "fsr", "epsr", "bear", "ccr", 48 "p0", "p1", "p2", "p3", "--", "--", "--", "--" }; 49 50 51 52 /* True if opcode is xor, xorh, and, andh, or, orh, andnot, andnoth. */ 53 #define BITWISE_OP(op) ((op) == 0x30 || (op) == 0x31 \ 54 || (op) == 0x34 || (op) == 0x35 \ 55 || (op) == 0x38 || (op) == 0x39 \ 56 || (op) == 0x3c || (op) == 0x3d \ 57 || (op) == 0x33 || (op) == 0x37 \ 58 || (op) == 0x3b || (op) == 0x3f) 59 60 61 /* Sign extend N-bit number. */ 62 static int 63 sign_ext (unsigned int x, int n) 64 { 65 int t; 66 t = x >> (n - 1); 67 t = ((-t) << n) | x; 68 return t; 69 } 70 71 72 /* Print a PC-relative branch offset. VAL is the sign extended value 73 from the branch instruction. */ 74 static void 75 print_br_address (disassemble_info *info, bfd_vma memaddr, long val) 76 { 77 78 long adj = (long)memaddr + 4 + (val << 2); 79 80 (*info->fprintf_func) (info->stream, "0x%08lx", adj); 81 82 /* Attempt to obtain a symbol for the target address. */ 83 84 if (info->print_address_func && adj != 0) 85 { 86 (*info->fprintf_func) (info->stream, "\t// "); 87 (*info->print_address_func) (adj, info); 88 } 89 } 90 91 92 /* Print one instruction. */ 93 int 94 print_insn_i860 (bfd_vma memaddr, disassemble_info *info) 95 { 96 bfd_byte buff[4]; 97 unsigned int insn, i; 98 int status; 99 const struct i860_opcode *opcode = 0; 100 101 status = (*info->read_memory_func) (memaddr, buff, sizeof (buff), info); 102 if (status != 0) 103 { 104 (*info->memory_error_func) (status, memaddr, info); 105 return -1; 106 } 107 108 /* Note that i860 instructions are always accessed as little endian 109 data, regardless of the endian mode of the i860. */ 110 insn = bfd_getl32 (buff); 111 112 status = 0; 113 i = 0; 114 while (i860_opcodes[i].name != NULL) 115 { 116 opcode = &i860_opcodes[i]; 117 if ((insn & opcode->match) == opcode->match 118 && (insn & opcode->lose) == 0) 119 { 120 status = 1; 121 break; 122 } 123 ++i; 124 } 125 126 if (status == 0) 127 { 128 /* Instruction not in opcode table. */ 129 (*info->fprintf_func) (info->stream, ".long %#08x", insn); 130 } 131 else 132 { 133 const char *s; 134 int val; 135 136 /* If this a flop (or a shrd) and its dual bit is set, 137 prefix with 'd.'. */ 138 if (((insn & 0xfc000000) == 0x48000000 139 || (insn & 0xfc000000) == 0xb0000000) 140 && (insn & 0x200)) 141 (*info->fprintf_func) (info->stream, "d.%s\t", opcode->name); 142 else 143 (*info->fprintf_func) (info->stream, "%s\t", opcode->name); 144 145 for (s = opcode->args; *s; s++) 146 { 147 switch (*s) 148 { 149 /* Integer register (src1). */ 150 case '1': 151 (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, 152 grnames[(insn >> 11) & 0x1f]); 153 break; 154 155 /* Integer register (src2). */ 156 case '2': 157 (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, 158 grnames[(insn >> 21) & 0x1f]); 159 break; 160 161 /* Integer destination register. */ 162 case 'd': 163 (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, 164 grnames[(insn >> 16) & 0x1f]); 165 break; 166 167 /* Floating-point register (src1). */ 168 case 'e': 169 (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, 170 frnames[(insn >> 11) & 0x1f]); 171 break; 172 173 /* Floating-point register (src2). */ 174 case 'f': 175 (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, 176 frnames[(insn >> 21) & 0x1f]); 177 break; 178 179 /* Floating-point destination register. */ 180 case 'g': 181 (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, 182 frnames[(insn >> 16) & 0x1f]); 183 break; 184 185 /* Control register. */ 186 case 'c': 187 (*info->fprintf_func) (info->stream, "%s%s", I860_REG_PREFIX, 188 crnames[(insn >> 21) & 0xf]); 189 break; 190 191 /* 16-bit immediate (sign extend, except for bitwise ops). */ 192 case 'i': 193 if (BITWISE_OP ((insn & 0xfc000000) >> 26)) 194 (*info->fprintf_func) (info->stream, "0x%04x", 195 (unsigned int) (insn & 0xffff)); 196 else 197 (*info->fprintf_func) (info->stream, "%d", 198 sign_ext ((insn & 0xffff), 16)); 199 break; 200 201 /* 16-bit immediate, aligned (2^0, ld.b). */ 202 case 'I': 203 (*info->fprintf_func) (info->stream, "%d", 204 sign_ext ((insn & 0xffff), 16)); 205 break; 206 207 /* 16-bit immediate, aligned (2^1, ld.s). */ 208 case 'J': 209 (*info->fprintf_func) (info->stream, "%d", 210 sign_ext ((insn & 0xfffe), 16)); 211 break; 212 213 /* 16-bit immediate, aligned (2^2, ld.l, {p}fld.l, fst.l). */ 214 case 'K': 215 (*info->fprintf_func) (info->stream, "%d", 216 sign_ext ((insn & 0xfffc), 16)); 217 break; 218 219 /* 16-bit immediate, aligned (2^3, {p}fld.d, fst.d). */ 220 case 'L': 221 (*info->fprintf_func) (info->stream, "%d", 222 sign_ext ((insn & 0xfff8), 16)); 223 break; 224 225 /* 16-bit immediate, aligned (2^4, {p}fld.q, fst.q). */ 226 case 'M': 227 (*info->fprintf_func) (info->stream, "%d", 228 sign_ext ((insn & 0xfff0), 16)); 229 break; 230 231 /* 5-bit immediate (zero extend). */ 232 case '5': 233 (*info->fprintf_func) (info->stream, "%d", 234 ((insn >> 11) & 0x1f)); 235 break; 236 237 /* Split 16 bit immediate (20..16:10..0). */ 238 case 's': 239 val = ((insn >> 5) & 0xf800) | (insn & 0x07ff); 240 (*info->fprintf_func) (info->stream, "%d", 241 sign_ext (val, 16)); 242 break; 243 244 /* Split 16 bit immediate, aligned. (2^0, st.b). */ 245 case 'S': 246 val = ((insn >> 5) & 0xf800) | (insn & 0x07ff); 247 (*info->fprintf_func) (info->stream, "%d", 248 sign_ext (val, 16)); 249 break; 250 251 /* Split 16 bit immediate, aligned. (2^1, st.s). */ 252 case 'T': 253 val = ((insn >> 5) & 0xf800) | (insn & 0x07fe); 254 (*info->fprintf_func) (info->stream, "%d", 255 sign_ext (val, 16)); 256 break; 257 258 /* Split 16 bit immediate, aligned. (2^2, st.l). */ 259 case 'U': 260 val = ((insn >> 5) & 0xf800) | (insn & 0x07fc); 261 (*info->fprintf_func) (info->stream, "%d", 262 sign_ext (val, 16)); 263 break; 264 265 /* 26-bit PC relative immediate (lbroff). */ 266 case 'l': 267 val = sign_ext ((insn & 0x03ffffff), 26); 268 print_br_address (info, memaddr, val); 269 break; 270 271 /* 16-bit PC relative immediate (sbroff). */ 272 case 'r': 273 val = sign_ext ((((insn >> 5) & 0xf800) | (insn & 0x07ff)), 16); 274 print_br_address (info, memaddr, val); 275 break; 276 277 default: 278 (*info->fprintf_func) (info->stream, "%c", *s); 279 break; 280 } 281 } 282 } 283 284 return sizeof (insn); 285 } 286 287