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