1/* Disassemble MN10200 instructions. 2 Copyright 1996, 1997, 1998, 2000, 2005, 2007 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 <stdio.h> 22 23#include "sysdep.h" 24#include "opcode/mn10200.h" 25#include "dis-asm.h" 26#include "opintl.h" 27 28static void 29disassemble (bfd_vma memaddr, 30 struct disassemble_info *info, 31 unsigned long insn, 32 unsigned long extension, 33 unsigned int size) 34{ 35 struct mn10200_opcode *op = (struct mn10200_opcode *)mn10200_opcodes; 36 const struct mn10200_operand *operand; 37 int match = 0; 38 39 /* Find the opcode. */ 40 while (op->name) 41 { 42 int mysize, extra_shift; 43 44 if (op->format == FMT_1) 45 mysize = 1; 46 else if (op->format == FMT_2 47 || op->format == FMT_4) 48 mysize = 2; 49 else if (op->format == FMT_3 50 || op->format == FMT_5) 51 mysize = 3; 52 else if (op->format == FMT_6) 53 mysize = 4; 54 else if (op->format == FMT_7) 55 mysize = 5; 56 else 57 abort (); 58 59 if (op->format == FMT_2 || op->format == FMT_5) 60 extra_shift = 8; 61 else if (op->format == FMT_3 62 || op->format == FMT_6 63 || op->format == FMT_7) 64 extra_shift = 16; 65 else 66 extra_shift = 0; 67 68 if ((op->mask & insn) == op->opcode 69 && size == (unsigned int) mysize) 70 { 71 const unsigned char *opindex_ptr; 72 unsigned int nocomma; 73 int paren = 0; 74 75 match = 1; 76 (*info->fprintf_func) (info->stream, "%s\t", op->name); 77 78 /* Now print the operands. */ 79 for (opindex_ptr = op->operands, nocomma = 1; 80 *opindex_ptr != 0; 81 opindex_ptr++) 82 { 83 unsigned long value; 84 85 operand = &mn10200_operands[*opindex_ptr]; 86 87 if ((operand->flags & MN10200_OPERAND_EXTENDED) != 0) 88 { 89 value = (insn & 0xffff) << 8; 90 value |= extension; 91 } 92 else 93 { 94 value = ((insn >> (operand->shift)) 95 & ((1L << operand->bits) - 1L)); 96 } 97 98 if ((operand->flags & MN10200_OPERAND_SIGNED) != 0) 99 value = ((long)(value << (32 - operand->bits)) 100 >> (32 - operand->bits)); 101 102 if (!nocomma 103 && (!paren 104 || ((operand->flags & MN10200_OPERAND_PAREN) == 0))) 105 (*info->fprintf_func) (info->stream, ","); 106 107 nocomma = 0; 108 109 if ((operand->flags & MN10200_OPERAND_DREG) != 0) 110 { 111 value = ((insn >> (operand->shift + extra_shift)) 112 & ((1 << operand->bits) - 1)); 113 (*info->fprintf_func) (info->stream, "d%ld", value); 114 } 115 116 else if ((operand->flags & MN10200_OPERAND_AREG) != 0) 117 { 118 value = ((insn >> (operand->shift + extra_shift)) 119 & ((1 << operand->bits) - 1)); 120 (*info->fprintf_func) (info->stream, "a%ld", value); 121 } 122 123 else if ((operand->flags & MN10200_OPERAND_PSW) != 0) 124 (*info->fprintf_func) (info->stream, "psw"); 125 126 else if ((operand->flags & MN10200_OPERAND_MDR) != 0) 127 (*info->fprintf_func) (info->stream, "mdr"); 128 129 else if ((operand->flags & MN10200_OPERAND_PAREN) != 0) 130 { 131 if (paren) 132 (*info->fprintf_func) (info->stream, ")"); 133 else 134 { 135 (*info->fprintf_func) (info->stream, "("); 136 nocomma = 1; 137 } 138 paren = !paren; 139 } 140 141 else if ((operand->flags & MN10200_OPERAND_PCREL) != 0) 142 (*info->print_address_func) 143 ((value + memaddr + mysize) & 0xffffff, info); 144 145 else if ((operand->flags & MN10200_OPERAND_MEMADDR) != 0) 146 (*info->print_address_func) (value, info); 147 148 else 149 (*info->fprintf_func) (info->stream, "%ld", value); 150 } 151 /* All done. */ 152 break; 153 } 154 op++; 155 } 156 157 if (!match) 158 (*info->fprintf_func) (info->stream, _("unknown\t0x%04lx"), insn); 159} 160 161int 162print_insn_mn10200 (bfd_vma memaddr, struct disassemble_info *info) 163{ 164 int status; 165 bfd_byte buffer[4]; 166 unsigned long insn; 167 unsigned long extension = 0; 168 unsigned int consume; 169 170 /* First figure out how big the opcode is. */ 171 status = (*info->read_memory_func) (memaddr, buffer, 1, info); 172 if (status != 0) 173 { 174 (*info->memory_error_func) (status, memaddr, info); 175 return -1; 176 } 177 178 insn = *(unsigned char *) buffer; 179 180 /* These are one byte insns. */ 181 if ((insn & 0xf0) == 0x00 182 || (insn & 0xf0) == 0x10 183 || (insn & 0xf0) == 0x20 184 || (insn & 0xf0) == 0x30 185 || ((insn & 0xf0) == 0x80 186 && (insn & 0x0c) >> 2 != (insn & 0x03)) 187 || (insn & 0xf0) == 0x90 188 || (insn & 0xf0) == 0xa0 189 || (insn & 0xf0) == 0xb0 190 || (insn & 0xff) == 0xeb 191 || (insn & 0xff) == 0xf6 192 || (insn & 0xff) == 0xfe 193 || (insn & 0xff) == 0xff) 194 { 195 extension = 0; 196 consume = 1; 197 } 198 199 /* These are two byte insns. */ 200 else if ((insn & 0xf0) == 0x40 201 || (insn & 0xf0) == 0x50 202 || (insn & 0xf0) == 0x60 203 || (insn & 0xf0) == 0x70 204 || (insn & 0xf0) == 0x80 205 || (insn & 0xfc) == 0xd0 206 || (insn & 0xfc) == 0xd4 207 || (insn & 0xfc) == 0xd8 208 || (insn & 0xfc) == 0xe0 209 || (insn & 0xfc) == 0xe4 210 || (insn & 0xff) == 0xe8 211 || (insn & 0xff) == 0xe9 212 || (insn & 0xff) == 0xea 213 || (insn & 0xff) == 0xf0 214 || (insn & 0xff) == 0xf1 215 || (insn & 0xff) == 0xf2 216 || (insn & 0xff) == 0xf3) 217 { 218 status = (*info->read_memory_func) (memaddr, buffer, 2, info); 219 if (status != 0) 220 { 221 (*info->memory_error_func) (status, memaddr, info); 222 return -1; 223 } 224 insn = bfd_getb16 (buffer); 225 consume = 2; 226 } 227 228 /* These are three byte insns with a 16bit operand in little 229 endian form. */ 230 else if ((insn & 0xf0) == 0xc0 231 || (insn & 0xfc) == 0xdc 232 || (insn & 0xfc) == 0xec 233 || (insn & 0xff) == 0xf8 234 || (insn & 0xff) == 0xf9 235 || (insn & 0xff) == 0xfa 236 || (insn & 0xff) == 0xfb 237 || (insn & 0xff) == 0xfc 238 || (insn & 0xff) == 0xfd) 239 { 240 status = (*info->read_memory_func) (memaddr + 1, buffer, 2, info); 241 if (status != 0) 242 { 243 (*info->memory_error_func) (status, memaddr, info); 244 return -1; 245 } 246 insn <<= 16; 247 insn |= bfd_getl16 (buffer); 248 extension = 0; 249 consume = 3; 250 } 251 /* These are three byte insns too, but we don't have to mess with 252 endianness stuff. */ 253 else if ((insn & 0xff) == 0xf5) 254 { 255 status = (*info->read_memory_func) (memaddr + 1, buffer, 2, info); 256 if (status != 0) 257 { 258 (*info->memory_error_func) (status, memaddr, info); 259 return -1; 260 } 261 insn <<= 16; 262 insn |= bfd_getb16 (buffer); 263 extension = 0; 264 consume = 3; 265 } 266 267 /* These are four byte insns. */ 268 else if ((insn & 0xff) == 0xf7) 269 { 270 status = (*info->read_memory_func) (memaddr, buffer, 2, info); 271 if (status != 0) 272 { 273 (*info->memory_error_func) (status, memaddr, info); 274 return -1; 275 } 276 insn = bfd_getb16 (buffer); 277 insn <<= 16; 278 status = (*info->read_memory_func) (memaddr + 2, buffer, 2, info); 279 if (status != 0) 280 { 281 (*info->memory_error_func) (status, memaddr, info); 282 return -1; 283 } 284 insn |= bfd_getl16 (buffer); 285 extension = 0; 286 consume = 4; 287 } 288 289 /* These are five byte insns. */ 290 else if ((insn & 0xff) == 0xf4) 291 { 292 status = (*info->read_memory_func) (memaddr, buffer, 2, info); 293 if (status != 0) 294 { 295 (*info->memory_error_func) (status, memaddr, info); 296 return -1; 297 } 298 insn = bfd_getb16 (buffer); 299 insn <<= 16; 300 301 status = (*info->read_memory_func) (memaddr + 4, buffer, 1, info); 302 if (status != 0) 303 { 304 (*info->memory_error_func) (status, memaddr, info); 305 return -1; 306 } 307 insn |= (*(unsigned char *)buffer << 8) & 0xff00; 308 309 status = (*info->read_memory_func) (memaddr + 3, buffer, 1, info); 310 if (status != 0) 311 { 312 (*info->memory_error_func) (status, memaddr, info); 313 return -1; 314 } 315 insn |= (*(unsigned char *)buffer) & 0xff; 316 317 status = (*info->read_memory_func) (memaddr + 2, buffer, 1, info); 318 if (status != 0) 319 { 320 (*info->memory_error_func) (status, memaddr, info); 321 return -1; 322 } 323 extension = (*(unsigned char *)buffer) & 0xff; 324 consume = 5; 325 } 326 else 327 { 328 (*info->fprintf_func) (info->stream, _("unknown\t0x%02lx"), insn); 329 return 1; 330 } 331 332 disassemble (memaddr, info, insn, extension, consume); 333 334 return consume; 335} 336