1 /* Disassemble moxie instructions. 2 Copyright (C) 2009-2014 Free Software Foundation, Inc. 3 4 This file is part of the GNU opcodes library. 5 6 This library is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3, or (at your option) 9 any later version. 10 11 It is distributed in the hope that it will be useful, but WITHOUT 12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 13 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 14 License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 19 MA 02110-1301, USA. */ 20 21 #include "sysdep.h" 22 #include <stdio.h> 23 24 #define STATIC_TABLE 25 #define DEFINE_TABLE 26 27 #include "opcode/moxie.h" 28 #include "dis-asm.h" 29 30 static fprintf_ftype fpr; 31 static void *stream; 32 33 /* Macros to extract operands from the instruction word. */ 34 #define OP_A(i) ((i >> 4) & 0xf) 35 #define OP_B(i) (i & 0xf) 36 #define INST2OFFSET(o) ((((signed short)((o & ((1<<10)-1))<<6))>>6)<<1) 37 38 static const char * reg_names[16] = 39 { "$fp", "$sp", "$r0", "$r1", "$r2", "$r3", "$r4", "$r5", 40 "$r6", "$r7", "$r8", "$r9", "$r10", "$r11", "$r12", "$r13" }; 41 42 int 43 print_insn_moxie (bfd_vma addr, struct disassemble_info * info) 44 { 45 int length = 2; 46 int status; 47 stream = info->stream; 48 const moxie_opc_info_t * opcode; 49 bfd_byte buffer[4]; 50 unsigned short iword; 51 fpr = info->fprintf_func; 52 53 if ((status = info->read_memory_func (addr, buffer, 2, info))) 54 goto fail; 55 56 if (info->endian == BFD_ENDIAN_BIG) 57 iword = bfd_getb16 (buffer); 58 else 59 iword = bfd_getl16 (buffer); 60 61 /* Form 1 instructions have the high bit set to 0. */ 62 if ((iword & (1<<15)) == 0) 63 { 64 /* Extract the Form 1 opcode. */ 65 opcode = &moxie_form1_opc_info[iword >> 8]; 66 switch (opcode->itype) 67 { 68 case MOXIE_F1_NARG: 69 fpr (stream, "%s", opcode->name); 70 break; 71 case MOXIE_F1_A: 72 fpr (stream, "%s\t%s", opcode->name, 73 reg_names[OP_A(iword)]); 74 break; 75 case MOXIE_F1_AB: 76 fpr (stream, "%s\t%s, %s", opcode->name, 77 reg_names[OP_A(iword)], 78 reg_names[OP_B(iword)]); 79 break; 80 case MOXIE_F1_A4: 81 { 82 unsigned imm; 83 if ((status = info->read_memory_func (addr + 2, buffer, 4, info))) 84 goto fail; 85 if (info->endian == BFD_ENDIAN_BIG) 86 imm = bfd_getb32 (buffer); 87 else 88 imm = bfd_getl32 (buffer); 89 fpr (stream, "%s\t%s, 0x%x", opcode->name, 90 reg_names[OP_A(iword)], imm); 91 length = 6; 92 } 93 break; 94 case MOXIE_F1_4: 95 { 96 unsigned imm; 97 if ((status = info->read_memory_func (addr + 2, buffer, 4, info))) 98 goto fail; 99 if (info->endian == BFD_ENDIAN_BIG) 100 imm = bfd_getb32 (buffer); 101 else 102 imm = bfd_getl32 (buffer); 103 fpr (stream, "%s\t0x%x", opcode->name, imm); 104 length = 6; 105 } 106 break; 107 case MOXIE_F1_M: 108 { 109 unsigned imm; 110 if ((status = info->read_memory_func (addr + 2, buffer, 4, info))) 111 goto fail; 112 if (info->endian == BFD_ENDIAN_BIG) 113 imm = bfd_getb32 (buffer); 114 else 115 imm = bfd_getl32 (buffer); 116 fpr (stream, "%s\t", opcode->name); 117 info->print_address_func ((bfd_vma) imm, info); 118 length = 6; 119 } 120 break; 121 case MOXIE_F1_AiB: 122 fpr (stream, "%s\t(%s), %s", opcode->name, 123 reg_names[OP_A(iword)], reg_names[OP_B(iword)]); 124 break; 125 case MOXIE_F1_ABi: 126 fpr (stream, "%s\t%s, (%s)", opcode->name, 127 reg_names[OP_A(iword)], reg_names[OP_B(iword)]); 128 break; 129 case MOXIE_F1_4A: 130 { 131 unsigned imm; 132 if ((status = info->read_memory_func (addr + 2, buffer, 4, info))) 133 goto fail; 134 if (info->endian == BFD_ENDIAN_BIG) 135 imm = bfd_getb32 (buffer); 136 else 137 imm = bfd_getl32 (buffer); 138 fpr (stream, "%s\t0x%x, %s", 139 opcode->name, imm, reg_names[OP_A(iword)]); 140 length = 6; 141 } 142 break; 143 case MOXIE_F1_AiB4: 144 { 145 unsigned imm; 146 if ((status = info->read_memory_func (addr+2, buffer, 4, info))) 147 goto fail; 148 if (info->endian == BFD_ENDIAN_BIG) 149 imm = bfd_getb32 (buffer); 150 else 151 imm = bfd_getl32 (buffer); 152 fpr (stream, "%s\t0x%x(%s), %s", opcode->name, 153 imm, 154 reg_names[OP_A(iword)], 155 reg_names[OP_B(iword)]); 156 length = 6; 157 } 158 break; 159 case MOXIE_F1_ABi4: 160 { 161 unsigned imm; 162 if ((status = info->read_memory_func (addr+2, buffer, 4, info))) 163 goto fail; 164 if (info->endian == BFD_ENDIAN_BIG) 165 imm = bfd_getb32 (buffer); 166 else 167 imm = bfd_getl32 (buffer); 168 fpr (stream, "%s\t%s, 0x%x(%s)", 169 opcode->name, 170 reg_names[OP_A(iword)], 171 imm, 172 reg_names[OP_B(iword)]); 173 length = 6; 174 } 175 break; 176 case MOXIE_BAD: 177 fpr (stream, "bad"); 178 break; 179 default: 180 abort(); 181 } 182 } 183 else if ((iword & (1<<14)) == 0) 184 { 185 /* Extract the Form 2 opcode. */ 186 opcode = &moxie_form2_opc_info[(iword >> 12) & 3]; 187 switch (opcode->itype) 188 { 189 case MOXIE_F2_A8V: 190 fpr (stream, "%s\t%s, 0x%x", 191 opcode->name, 192 reg_names[(iword >> 8) & 0xf], 193 iword & ((1 << 8) - 1)); 194 break; 195 case MOXIE_F2_NARG: 196 fpr (stream, "%s", opcode->name); 197 break; 198 case MOXIE_BAD: 199 fpr (stream, "bad"); 200 break; 201 default: 202 abort(); 203 } 204 } 205 else 206 { 207 /* Extract the Form 3 opcode. */ 208 opcode = &moxie_form3_opc_info[(iword >> 10) & 15]; 209 switch (opcode->itype) 210 { 211 case MOXIE_F3_PCREL: 212 fpr (stream, "%s\t", opcode->name); 213 info->print_address_func ((bfd_vma) (addr + INST2OFFSET(iword) + 2), 214 info); 215 break; 216 case MOXIE_BAD: 217 fpr (stream, "bad"); 218 break; 219 default: 220 abort(); 221 } 222 } 223 224 return length; 225 226 fail: 227 info->memory_error_func (status, addr, info); 228 return -1; 229 } 230