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