|
| 1 | +/* Disassemble moxie instructions. |
| 2 | + Copyright (c) 2009 Free Software Foundation, Inc. |
| 3 | +
|
| 4 | + This program is free software; you can redistribute it and/or modify |
| 5 | + it under the terms of the GNU General Public License as published by |
| 6 | + the Free Software Foundation; either version 2 of the License, or |
| 7 | + (at your option) any later version. |
| 8 | +
|
| 9 | + This program is distributed in the hope that it will be useful, |
| 10 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | + GNU General Public License for more details. |
| 13 | +
|
| 14 | + You should have received a copy of the GNU General Public License |
| 15 | + along with this program; if not, see <http://www.gnu.org/licenses/>. */ |
| 16 | + |
| 17 | +#include <stdio.h> |
| 18 | +#define STATIC_TABLE |
| 19 | +#define DEFINE_TABLE |
| 20 | + |
| 21 | +#include "disas/bfd.h" |
| 22 | + |
| 23 | +static void *stream; |
| 24 | + |
| 25 | +/* Form 1 instructions come in different flavors: |
| 26 | +
|
| 27 | + Some have no arguments (MOXIE_F1_NARG) |
| 28 | + Some only use the A operand (MOXIE_F1_A) |
| 29 | + Some use A and B registers (MOXIE_F1_AB) |
| 30 | + Some use A and consume a 4 byte immediate value (MOXIE_F1_A4) |
| 31 | + Some use just a 4 byte immediate value (MOXIE_F1_4) |
| 32 | + Some use just a 4 byte memory address (MOXIE_F1_M) |
| 33 | + Some use B and an indirect A (MOXIE_F1_AiB) |
| 34 | + Some use A and an indirect B (MOXIE_F1_ABi) |
| 35 | + Some consume a 4 byte immediate value and use X (MOXIE_F1_4A) |
| 36 | + Some use B and an indirect A plus 4 bytes (MOXIE_F1_AiB4) |
| 37 | + Some use A and an indirect B plus 4 bytes (MOXIE_F1_ABi4) |
| 38 | +
|
| 39 | + Form 2 instructions also come in different flavors: |
| 40 | +
|
| 41 | + Some have no arguments (MOXIE_F2_NARG) |
| 42 | + Some use the A register and an 8-bit value (MOXIE_F2_A8V) |
| 43 | +
|
| 44 | + Form 3 instructions also come in different flavors: |
| 45 | +
|
| 46 | + Some have no arguments (MOXIE_F3_NARG) |
| 47 | + Some have a 10-bit PC relative operand (MOXIE_F3_PCREL). */ |
| 48 | + |
| 49 | +#define MOXIE_F1_NARG 0x100 |
| 50 | +#define MOXIE_F1_A 0x101 |
| 51 | +#define MOXIE_F1_AB 0x102 |
| 52 | +/* #define MOXIE_F1_ABC 0x103 */ |
| 53 | +#define MOXIE_F1_A4 0x104 |
| 54 | +#define MOXIE_F1_4 0x105 |
| 55 | +#define MOXIE_F1_AiB 0x106 |
| 56 | +#define MOXIE_F1_ABi 0x107 |
| 57 | +#define MOXIE_F1_4A 0x108 |
| 58 | +#define MOXIE_F1_AiB4 0x109 |
| 59 | +#define MOXIE_F1_ABi4 0x10a |
| 60 | +#define MOXIE_F1_M 0x10b |
| 61 | + |
| 62 | +#define MOXIE_F2_NARG 0x200 |
| 63 | +#define MOXIE_F2_A8V 0x201 |
| 64 | + |
| 65 | +#define MOXIE_F3_NARG 0x300 |
| 66 | +#define MOXIE_F3_PCREL 0x301 |
| 67 | + |
| 68 | +typedef struct moxie_opc_info_t { |
| 69 | + short opcode; |
| 70 | + unsigned itype; |
| 71 | + const char * name; |
| 72 | +} moxie_opc_info_t; |
| 73 | + |
| 74 | +extern const moxie_opc_info_t moxie_form1_opc_info[64]; |
| 75 | +extern const moxie_opc_info_t moxie_form2_opc_info[4]; |
| 76 | +extern const moxie_opc_info_t moxie_form3_opc_info[16]; |
| 77 | + |
| 78 | +/* The moxie processor's 16-bit instructions come in two forms: |
| 79 | +
|
| 80 | + FORM 1 instructions start with a 0 bit... |
| 81 | +
|
| 82 | + 0oooooooaaaabbbb |
| 83 | + 0 F |
| 84 | +
|
| 85 | + ooooooo - form 1 opcode number |
| 86 | + aaaa - operand A |
| 87 | + bbbb - operand B |
| 88 | +
|
| 89 | + FORM 2 instructions start with bits "10"... |
| 90 | +
|
| 91 | + 10ooaaaavvvvvvvv |
| 92 | + 0 F |
| 93 | +
|
| 94 | + oo - form 2 opcode number |
| 95 | + aaaa - operand A |
| 96 | + vvvvvvvv - 8-bit immediate value |
| 97 | +
|
| 98 | + FORM 3 instructions start with a bits "11"... |
| 99 | +
|
| 100 | + 11oooovvvvvvvvvv |
| 101 | + 0 F |
| 102 | +
|
| 103 | + oooo - form 3 opcode number |
| 104 | + vvvvvvvvvv - 10-bit immediate value. */ |
| 105 | + |
| 106 | +const moxie_opc_info_t moxie_form1_opc_info[64] = |
| 107 | + { |
| 108 | + { 0x00, MOXIE_F1_NARG, "nop" }, |
| 109 | + { 0x01, MOXIE_F1_A4, "ldi.l" }, |
| 110 | + { 0x02, MOXIE_F1_AB, "mov" }, |
| 111 | + { 0x03, MOXIE_F1_M, "jsra" }, |
| 112 | + { 0x04, MOXIE_F1_NARG, "ret" }, |
| 113 | + { 0x05, MOXIE_F1_AB, "add.l" }, |
| 114 | + { 0x06, MOXIE_F1_AB, "push" }, |
| 115 | + { 0x07, MOXIE_F1_AB, "pop" }, |
| 116 | + { 0x08, MOXIE_F1_A4, "lda.l" }, |
| 117 | + { 0x09, MOXIE_F1_4A, "sta.l" }, |
| 118 | + { 0x0a, MOXIE_F1_ABi, "ld.l" }, |
| 119 | + { 0x0b, MOXIE_F1_AiB, "st.l" }, |
| 120 | + { 0x0c, MOXIE_F1_ABi4, "ldo.l" }, |
| 121 | + { 0x0d, MOXIE_F1_AiB4, "sto.l" }, |
| 122 | + { 0x0e, MOXIE_F1_AB, "cmp" }, |
| 123 | + { 0x0f, MOXIE_F1_NARG, "bad" }, |
| 124 | + { 0x10, MOXIE_F1_NARG, "bad" }, |
| 125 | + { 0x11, MOXIE_F1_NARG, "bad" }, |
| 126 | + { 0x12, MOXIE_F1_NARG, "bad" }, |
| 127 | + { 0x13, MOXIE_F1_NARG, "bad" }, |
| 128 | + { 0x14, MOXIE_F1_NARG, "bad" }, |
| 129 | + { 0x15, MOXIE_F1_NARG, "bad" }, |
| 130 | + { 0x16, MOXIE_F1_NARG, "bad" }, |
| 131 | + { 0x17, MOXIE_F1_NARG, "bad" }, |
| 132 | + { 0x18, MOXIE_F1_NARG, "bad" }, |
| 133 | + { 0x19, MOXIE_F1_A, "jsr" }, |
| 134 | + { 0x1a, MOXIE_F1_M, "jmpa" }, |
| 135 | + { 0x1b, MOXIE_F1_A4, "ldi.b" }, |
| 136 | + { 0x1c, MOXIE_F1_ABi, "ld.b" }, |
| 137 | + { 0x1d, MOXIE_F1_A4, "lda.b" }, |
| 138 | + { 0x1e, MOXIE_F1_AiB, "st.b" }, |
| 139 | + { 0x1f, MOXIE_F1_4A, "sta.b" }, |
| 140 | + { 0x20, MOXIE_F1_A4, "ldi.s" }, |
| 141 | + { 0x21, MOXIE_F1_ABi, "ld.s" }, |
| 142 | + { 0x22, MOXIE_F1_A4, "lda.s" }, |
| 143 | + { 0x23, MOXIE_F1_AiB, "st.s" }, |
| 144 | + { 0x24, MOXIE_F1_4A, "sta.s" }, |
| 145 | + { 0x25, MOXIE_F1_A, "jmp" }, |
| 146 | + { 0x26, MOXIE_F1_AB, "and" }, |
| 147 | + { 0x27, MOXIE_F1_AB, "lshr" }, |
| 148 | + { 0x28, MOXIE_F1_AB, "ashl" }, |
| 149 | + { 0x29, MOXIE_F1_AB, "sub.l" }, |
| 150 | + { 0x2a, MOXIE_F1_AB, "neg" }, |
| 151 | + { 0x2b, MOXIE_F1_AB, "or" }, |
| 152 | + { 0x2c, MOXIE_F1_AB, "not" }, |
| 153 | + { 0x2d, MOXIE_F1_AB, "ashr" }, |
| 154 | + { 0x2e, MOXIE_F1_AB, "xor" }, |
| 155 | + { 0x2f, MOXIE_F1_AB, "mul.l" }, |
| 156 | + { 0x30, MOXIE_F1_4, "swi" }, |
| 157 | + { 0x31, MOXIE_F1_AB, "div.l" }, |
| 158 | + { 0x32, MOXIE_F1_AB, "udiv.l" }, |
| 159 | + { 0x33, MOXIE_F1_AB, "mod.l" }, |
| 160 | + { 0x34, MOXIE_F1_AB, "umod.l" }, |
| 161 | + { 0x35, MOXIE_F1_NARG, "brk" }, |
| 162 | + { 0x36, MOXIE_F1_ABi4, "ldo.b" }, |
| 163 | + { 0x37, MOXIE_F1_AiB4, "sto.b" }, |
| 164 | + { 0x38, MOXIE_F1_ABi4, "ldo.s" }, |
| 165 | + { 0x39, MOXIE_F1_AiB4, "sto.s" }, |
| 166 | + { 0x3a, MOXIE_F1_NARG, "bad" }, |
| 167 | + { 0x3b, MOXIE_F1_NARG, "bad" }, |
| 168 | + { 0x3c, MOXIE_F1_NARG, "bad" }, |
| 169 | + { 0x3d, MOXIE_F1_NARG, "bad" }, |
| 170 | + { 0x3e, MOXIE_F1_NARG, "bad" }, |
| 171 | + { 0x3f, MOXIE_F1_NARG, "bad" } |
| 172 | + }; |
| 173 | + |
| 174 | +const moxie_opc_info_t moxie_form2_opc_info[4] = |
| 175 | + { |
| 176 | + { 0x00, MOXIE_F2_A8V, "inc" }, |
| 177 | + { 0x01, MOXIE_F2_A8V, "dec" }, |
| 178 | + { 0x02, MOXIE_F2_A8V, "gsr" }, |
| 179 | + { 0x03, MOXIE_F2_A8V, "ssr" } |
| 180 | + }; |
| 181 | + |
| 182 | +const moxie_opc_info_t moxie_form3_opc_info[16] = |
| 183 | + { |
| 184 | + { 0x00, MOXIE_F3_PCREL,"beq" }, |
| 185 | + { 0x01, MOXIE_F3_PCREL,"bne" }, |
| 186 | + { 0x02, MOXIE_F3_PCREL,"blt" }, |
| 187 | + { 0x03, MOXIE_F3_PCREL,"bgt" }, |
| 188 | + { 0x04, MOXIE_F3_PCREL,"bltu" }, |
| 189 | + { 0x05, MOXIE_F3_PCREL,"bgtu" }, |
| 190 | + { 0x06, MOXIE_F3_PCREL,"bge" }, |
| 191 | + { 0x07, MOXIE_F3_PCREL,"ble" }, |
| 192 | + { 0x08, MOXIE_F3_PCREL,"bgeu" }, |
| 193 | + { 0x09, MOXIE_F3_PCREL,"bleu" }, |
| 194 | + { 0x0a, MOXIE_F3_NARG, "bad" }, |
| 195 | + { 0x0b, MOXIE_F3_NARG, "bad" }, |
| 196 | + { 0x0c, MOXIE_F3_NARG, "bad" }, |
| 197 | + { 0x0d, MOXIE_F3_NARG, "bad" }, |
| 198 | + { 0x0e, MOXIE_F3_NARG, "bad" }, |
| 199 | + { 0x0f, MOXIE_F3_NARG, "bad" } |
| 200 | + }; |
| 201 | + |
| 202 | +/* Macros to extract operands from the instruction word. */ |
| 203 | +#define OP_A(i) ((i >> 4) & 0xf) |
| 204 | +#define OP_B(i) (i & 0xf) |
| 205 | +#define INST2OFFSET(o) ((((signed short)((o & ((1<<10)-1))<<6))>>6)<<1) |
| 206 | + |
| 207 | +static const char * reg_names[16] = |
| 208 | + { "$fp", "$sp", "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", |
| 209 | + "$r6", "$r7", "$r8", "$r9", "$r10", "$r11", "$r12", "$r13" }; |
| 210 | + |
| 211 | +int |
| 212 | +print_insn_moxie(bfd_vma addr, struct disassemble_info * info) |
| 213 | +{ |
| 214 | + int length = 2; |
| 215 | + int status; |
| 216 | + stream = info->stream; |
| 217 | + const moxie_opc_info_t * opcode; |
| 218 | + bfd_byte buffer[4]; |
| 219 | + unsigned short iword; |
| 220 | + fprintf_function fpr = info->fprintf_func; |
| 221 | + |
| 222 | + if ((status = info->read_memory_func(addr, buffer, 2, info))) |
| 223 | + goto fail; |
| 224 | + iword = (bfd_getb16(buffer) >> 16); |
| 225 | + |
| 226 | + /* Form 1 instructions have the high bit set to 0. */ |
| 227 | + if ((iword & (1<<15)) == 0) { |
| 228 | + /* Extract the Form 1 opcode. */ |
| 229 | + opcode = &moxie_form1_opc_info[iword >> 8]; |
| 230 | + switch (opcode->itype) { |
| 231 | + case MOXIE_F1_NARG: |
| 232 | + fpr(stream, "%s", opcode->name); |
| 233 | + break; |
| 234 | + case MOXIE_F1_A: |
| 235 | + fpr(stream, "%s\t%s", opcode->name, |
| 236 | + reg_names[OP_A(iword)]); |
| 237 | + break; |
| 238 | + case MOXIE_F1_AB: |
| 239 | + fpr(stream, "%s\t%s, %s", opcode->name, |
| 240 | + reg_names[OP_A(iword)], |
| 241 | + reg_names[OP_B(iword)]); |
| 242 | + break; |
| 243 | + case MOXIE_F1_A4: |
| 244 | + { |
| 245 | + unsigned imm; |
| 246 | + if ((status = info->read_memory_func(addr + 2, buffer, 4, info))) |
| 247 | + goto fail; |
| 248 | + imm = bfd_getb32(buffer); |
| 249 | + fpr(stream, "%s\t%s, 0x%x", opcode->name, |
| 250 | + reg_names[OP_A(iword)], imm); |
| 251 | + length = 6; |
| 252 | + } |
| 253 | + break; |
| 254 | + case MOXIE_F1_4: |
| 255 | + { |
| 256 | + unsigned imm; |
| 257 | + if ((status = info->read_memory_func(addr + 2, buffer, 4, info))) |
| 258 | + goto fail; |
| 259 | + imm = bfd_getb32(buffer); |
| 260 | + fpr(stream, "%s\t0x%x", opcode->name, imm); |
| 261 | + length = 6; |
| 262 | + } |
| 263 | + break; |
| 264 | + case MOXIE_F1_M: |
| 265 | + { |
| 266 | + unsigned imm; |
| 267 | + if ((status = info->read_memory_func(addr + 2, buffer, 4, info))) |
| 268 | + goto fail; |
| 269 | + imm = bfd_getb32(buffer); |
| 270 | + fpr(stream, "%s\t", opcode->name); |
| 271 | + info->print_address_func((bfd_vma) imm, info); |
| 272 | + length = 6; |
| 273 | + } |
| 274 | + break; |
| 275 | + case MOXIE_F1_AiB: |
| 276 | + fpr (stream, "%s\t(%s), %s", opcode->name, |
| 277 | + reg_names[OP_A(iword)], reg_names[OP_B(iword)]); |
| 278 | + break; |
| 279 | + case MOXIE_F1_ABi: |
| 280 | + fpr(stream, "%s\t%s, (%s)", opcode->name, |
| 281 | + reg_names[OP_A(iword)], reg_names[OP_B(iword)]); |
| 282 | + break; |
| 283 | + case MOXIE_F1_4A: |
| 284 | + { |
| 285 | + unsigned imm; |
| 286 | + if ((status = info->read_memory_func(addr + 2, buffer, 4, info))) |
| 287 | + goto fail; |
| 288 | + imm = bfd_getb32(buffer); |
| 289 | + fpr(stream, "%s\t0x%x, %s", |
| 290 | + opcode->name, imm, reg_names[OP_A(iword)]); |
| 291 | + length = 6; |
| 292 | + } |
| 293 | + break; |
| 294 | + case MOXIE_F1_AiB4: |
| 295 | + { |
| 296 | + unsigned imm; |
| 297 | + if ((status = info->read_memory_func(addr+2, buffer, 4, info))) |
| 298 | + goto fail; |
| 299 | + imm = bfd_getb32(buffer); |
| 300 | + fpr(stream, "%s\t0x%x(%s), %s", opcode->name, |
| 301 | + imm, |
| 302 | + reg_names[OP_A(iword)], |
| 303 | + reg_names[OP_B(iword)]); |
| 304 | + length = 6; |
| 305 | + } |
| 306 | + break; |
| 307 | + case MOXIE_F1_ABi4: |
| 308 | + { |
| 309 | + unsigned imm; |
| 310 | + if ((status = info->read_memory_func(addr+2, buffer, 4, info))) |
| 311 | + goto fail; |
| 312 | + imm = bfd_getb32(buffer); |
| 313 | + fpr(stream, "%s\t%s, 0x%x(%s)", |
| 314 | + opcode->name, |
| 315 | + reg_names[OP_A(iword)], |
| 316 | + imm, |
| 317 | + reg_names[OP_B(iword)]); |
| 318 | + length = 6; |
| 319 | + } |
| 320 | + break; |
| 321 | + default: |
| 322 | + abort(); |
| 323 | + } |
| 324 | + } |
| 325 | + else if ((iword & (1<<14)) == 0) { |
| 326 | + /* Extract the Form 2 opcode. */ |
| 327 | + opcode = &moxie_form2_opc_info[(iword >> 12) & 3]; |
| 328 | + switch (opcode->itype) { |
| 329 | + case MOXIE_F2_A8V: |
| 330 | + fpr(stream, "%s\t%s, 0x%x", |
| 331 | + opcode->name, |
| 332 | + reg_names[(iword >> 8) & 0xf], |
| 333 | + iword & ((1 << 8) - 1)); |
| 334 | + break; |
| 335 | + case MOXIE_F2_NARG: |
| 336 | + fpr(stream, "%s", opcode->name); |
| 337 | + break; |
| 338 | + default: |
| 339 | + abort(); |
| 340 | + } |
| 341 | + } else { |
| 342 | + /* Extract the Form 3 opcode. */ |
| 343 | + opcode = &moxie_form3_opc_info[(iword >> 10) & 15]; |
| 344 | + switch (opcode->itype) { |
| 345 | + case MOXIE_F3_PCREL: |
| 346 | + fpr(stream, "%s\t", opcode->name); |
| 347 | + info->print_address_func((bfd_vma) (addr + INST2OFFSET(iword) + 2), |
| 348 | + info); |
| 349 | + break; |
| 350 | + default: |
| 351 | + abort(); |
| 352 | + } |
| 353 | + } |
| 354 | + |
| 355 | + return length; |
| 356 | + |
| 357 | + fail: |
| 358 | + info->memory_error_func(status, addr, info); |
| 359 | + return -1; |
| 360 | +} |
0 commit comments