1 1.1 christos /* Disassemble MSP430 instructions. 2 1.11 christos Copyright (C) 2002-2024 Free Software Foundation, Inc. 3 1.1 christos 4 1.1 christos Contributed by Dmitry Diky <diwil (at) mail.ru> 5 1.6 christos 6 1.1 christos This file is part of the GNU opcodes library. 7 1.1 christos 8 1.1 christos This library is free software; you can redistribute it and/or modify 9 1.1 christos it under the terms of the GNU General Public License as published by 10 1.1 christos the Free Software Foundation; either version 3, or (at your option) 11 1.1 christos any later version. 12 1.1 christos 13 1.1 christos It is distributed in the hope that it will be useful, but WITHOUT 14 1.1 christos ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 1.1 christos or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 16 1.1 christos License for more details. 17 1.1 christos 18 1.1 christos You should have received a copy of the GNU General Public License 19 1.1 christos along with this program; if not, write to the Free Software 20 1.1 christos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, 21 1.1 christos MA 02110-1301, USA. */ 22 1.1 christos 23 1.1 christos #include "sysdep.h" 24 1.1 christos #include <stdio.h> 25 1.1 christos #include <ctype.h> 26 1.1 christos #include <sys/types.h> 27 1.6 christos #include <errno.h> 28 1.1 christos 29 1.8 christos #include "disassemble.h" 30 1.1 christos #include "opintl.h" 31 1.1 christos #include "libiberty.h" 32 1.1 christos 33 1.1 christos #define DASM_SECTION 34 1.1 christos #include "opcode/msp430.h" 35 1.1 christos #undef DASM_SECTION 36 1.1 christos 37 1.1 christos 38 1.1 christos #define PS(x) (0xffff & (x)) 39 1.1 christos 40 1.10 christos static bool 41 1.6 christos msp430dis_read_two_bytes (bfd_vma addr, 42 1.6 christos disassemble_info * info, 43 1.6 christos bfd_byte * buffer, 44 1.6 christos char * comm) 45 1.1 christos { 46 1.1 christos int status; 47 1.1 christos 48 1.1 christos status = info->read_memory_func (addr, buffer, 2, info); 49 1.6 christos if (status == 0) 50 1.10 christos return true; 51 1.6 christos 52 1.6 christos /* PR 20150: A status of EIO means that there were no more bytes left 53 1.6 christos to read in the current section. This can happen when disassembling 54 1.6 christos interrupt vectors for example. Avoid cluttering the output with 55 1.6 christos unhelpful error messages in this case. */ 56 1.6 christos if (status == EIO) 57 1.6 christos { 58 1.6 christos if (comm) 59 1.6 christos sprintf (comm, _("Warning: disassembly unreliable - not enough bytes available")); 60 1.6 christos } 61 1.6 christos else 62 1.1 christos { 63 1.1 christos info->memory_error_func (status, addr, info); 64 1.6 christos if (comm) 65 1.6 christos sprintf (comm, _("Error: read from memory failed")); 66 1.6 christos } 67 1.6 christos 68 1.10 christos return false; 69 1.6 christos } 70 1.6 christos 71 1.10 christos static bool 72 1.6 christos msp430dis_opcode_unsigned (bfd_vma addr, 73 1.6 christos disassemble_info * info, 74 1.6 christos unsigned short * return_val, 75 1.6 christos char * comm) 76 1.6 christos { 77 1.6 christos bfd_byte buffer[2]; 78 1.6 christos 79 1.6 christos if (msp430dis_read_two_bytes (addr, info, buffer, comm)) 80 1.6 christos { 81 1.6 christos * return_val = bfd_getl16 (buffer); 82 1.10 christos return true; 83 1.6 christos } 84 1.6 christos else 85 1.6 christos { 86 1.6 christos * return_val = 0; 87 1.10 christos return false; 88 1.6 christos } 89 1.6 christos } 90 1.6 christos 91 1.10 christos static bool 92 1.6 christos msp430dis_opcode_signed (bfd_vma addr, 93 1.6 christos disassemble_info * info, 94 1.6 christos signed int * return_val, 95 1.6 christos char * comm) 96 1.6 christos { 97 1.6 christos bfd_byte buffer[2]; 98 1.6 christos 99 1.6 christos if (msp430dis_read_two_bytes (addr, info, buffer, comm)) 100 1.6 christos { 101 1.6 christos int status; 102 1.6 christos 103 1.6 christos status = bfd_getl_signed_16 (buffer); 104 1.6 christos if (status & 0x8000) 105 1.6 christos status |= -1U << 16; 106 1.6 christos * return_val = status; 107 1.10 christos return true; 108 1.6 christos } 109 1.6 christos else 110 1.6 christos { 111 1.6 christos * return_val = 0; 112 1.10 christos return false; 113 1.1 christos } 114 1.1 christos } 115 1.1 christos 116 1.1 christos static int 117 1.1 christos msp430_nooperands (struct msp430_opcode_s *opcode, 118 1.1 christos bfd_vma addr ATTRIBUTE_UNUSED, 119 1.1 christos unsigned short insn ATTRIBUTE_UNUSED, 120 1.1 christos char *comm, 121 1.1 christos int *cycles) 122 1.1 christos { 123 1.1 christos /* Pop with constant. */ 124 1.1 christos if (insn == 0x43b2) 125 1.1 christos return 0; 126 1.1 christos if (insn == opcode->bin_opcode) 127 1.1 christos return 2; 128 1.1 christos 129 1.1 christos if (opcode->fmt == 0) 130 1.1 christos { 131 1.5 christos if ((insn & 0x0f00) != 0x0300 || (insn & 0x0f00) != 0x0200) 132 1.1 christos return 0; 133 1.1 christos 134 1.1 christos strcpy (comm, "emulated..."); 135 1.1 christos *cycles = 1; 136 1.1 christos } 137 1.1 christos else 138 1.1 christos { 139 1.1 christos strcpy (comm, "return from interupt"); 140 1.1 christos *cycles = 5; 141 1.1 christos } 142 1.1 christos 143 1.1 christos return 2; 144 1.1 christos } 145 1.1 christos 146 1.1 christos static int 147 1.1 christos print_as2_reg_name (int regno, char * op1, char * comm1, 148 1.1 christos int c2, int c3, int cd) 149 1.1 christos { 150 1.1 christos switch (regno) 151 1.1 christos { 152 1.1 christos case 2: 153 1.1 christos sprintf (op1, "#4"); 154 1.1 christos sprintf (comm1, "r2 As==10"); 155 1.1 christos return c2; 156 1.1 christos 157 1.1 christos case 3: 158 1.1 christos sprintf (op1, "#2"); 159 1.1 christos sprintf (comm1, "r3 As==10"); 160 1.1 christos return c3; 161 1.1 christos 162 1.1 christos default: 163 1.1 christos /* Indexed register mode @Rn. */ 164 1.1 christos sprintf (op1, "@r%d", regno); 165 1.1 christos return cd; 166 1.1 christos } 167 1.1 christos } 168 1.1 christos 169 1.1 christos static int 170 1.1 christos print_as3_reg_name (int regno, char * op1, char * comm1, 171 1.1 christos int c2, int c3, int cd) 172 1.1 christos { 173 1.1 christos switch (regno) 174 1.1 christos { 175 1.1 christos case 2: 176 1.1 christos sprintf (op1, "#8"); 177 1.1 christos sprintf (comm1, "r2 As==11"); 178 1.1 christos return c2; 179 1.1 christos 180 1.1 christos case 3: 181 1.1 christos sprintf (op1, "#-1"); 182 1.1 christos sprintf (comm1, "r3 As==11"); 183 1.1 christos return c3; 184 1.1 christos 185 1.1 christos default: 186 1.1 christos /* Post incremented @Rn+. */ 187 1.1 christos sprintf (op1, "@r%d+", regno); 188 1.1 christos return cd; 189 1.1 christos } 190 1.1 christos } 191 1.1 christos 192 1.1 christos static int 193 1.1 christos msp430_singleoperand (disassemble_info *info, 194 1.1 christos struct msp430_opcode_s *opcode, 195 1.1 christos bfd_vma addr, 196 1.1 christos unsigned short insn, 197 1.1 christos char *op, 198 1.1 christos char *comm, 199 1.1 christos unsigned short extension_word, 200 1.1 christos int *cycles) 201 1.1 christos { 202 1.1 christos int regs = 0, regd = 0; 203 1.1 christos int ad = 0, as = 0; 204 1.1 christos int where = 0; 205 1.1 christos int cmd_len = 2; 206 1.1 christos int dst = 0; 207 1.1 christos int fmt; 208 1.1 christos int extended_dst = extension_word & 0xf; 209 1.1 christos 210 1.1 christos regd = insn & 0x0f; 211 1.1 christos regs = (insn & 0x0f00) >> 8; 212 1.1 christos as = (insn & 0x0030) >> 4; 213 1.1 christos ad = (insn & 0x0080) >> 7; 214 1.1 christos 215 1.1 christos if (opcode->fmt < 0) 216 1.1 christos fmt = (- opcode->fmt) - 1; 217 1.1 christos else 218 1.1 christos fmt = opcode->fmt; 219 1.1 christos 220 1.1 christos switch (fmt) 221 1.1 christos { 222 1.1 christos case 0: /* Emulated work with dst register. */ 223 1.1 christos if (regs != 2 && regs != 3 && regs != 1) 224 1.1 christos return 0; 225 1.1 christos 226 1.1 christos /* Check if not clr insn. */ 227 1.1 christos if (opcode->bin_opcode == 0x4300 && (ad || as)) 228 1.1 christos return 0; 229 1.1 christos 230 1.1 christos /* Check if really inc, incd insns. */ 231 1.1 christos if ((opcode->bin_opcode & 0xff00) == 0x5300 && as == 3) 232 1.1 christos return 0; 233 1.1 christos 234 1.1 christos if (ad == 0) 235 1.1 christos { 236 1.1 christos *cycles = 1; 237 1.1 christos 238 1.1 christos /* Register. */ 239 1.1 christos if (regd == 0) 240 1.1 christos { 241 1.1 christos *cycles += 1; 242 1.1 christos sprintf (op, "r0"); 243 1.1 christos } 244 1.1 christos else if (regd == 1) 245 1.1 christos sprintf (op, "r1"); 246 1.1 christos 247 1.1 christos else if (regd == 2) 248 1.1 christos sprintf (op, "r2"); 249 1.1 christos 250 1.1 christos else 251 1.1 christos sprintf (op, "r%d", regd); 252 1.1 christos } 253 1.1 christos else /* ad == 1 msp430dis_opcode. */ 254 1.1 christos { 255 1.1 christos if (regd == 0) 256 1.1 christos { 257 1.1 christos /* PC relative. */ 258 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 259 1.1 christos { 260 1.6 christos cmd_len += 2; 261 1.6 christos *cycles = 4; 262 1.6 christos sprintf (op, "0x%04x", dst); 263 1.6 christos sprintf (comm, "PC rel. abs addr 0x%04x", 264 1.6 christos PS ((short) (addr + 2) + dst)); 265 1.6 christos if (extended_dst) 266 1.6 christos { 267 1.6 christos dst |= extended_dst << 16; 268 1.6 christos sprintf (op, "0x%05x", dst); 269 1.6 christos sprintf (comm, "PC rel. abs addr 0x%05lx", 270 1.6 christos (long)((addr + 2 + dst) & 0xfffff)); 271 1.6 christos } 272 1.1 christos } 273 1.7 christos else 274 1.7 christos return -1; 275 1.1 christos } 276 1.1 christos else if (regd == 2) 277 1.1 christos { 278 1.1 christos /* Absolute. */ 279 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 280 1.1 christos { 281 1.6 christos cmd_len += 2; 282 1.6 christos *cycles = 4; 283 1.6 christos sprintf (op, "&0x%04x", PS (dst)); 284 1.6 christos if (extended_dst) 285 1.6 christos { 286 1.6 christos dst |= extended_dst << 16; 287 1.6 christos sprintf (op, "&0x%05x", dst & 0xfffff); 288 1.6 christos } 289 1.1 christos } 290 1.7 christos else 291 1.7 christos return -1; 292 1.1 christos } 293 1.1 christos else 294 1.1 christos { 295 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 296 1.1 christos { 297 1.6 christos cmd_len += 2; 298 1.6 christos *cycles = 4; 299 1.6 christos if (extended_dst) 300 1.6 christos { 301 1.6 christos dst |= extended_dst << 16; 302 1.6 christos if (dst & 0x80000) 303 1.6 christos dst |= -1U << 20; 304 1.6 christos } 305 1.6 christos sprintf (op, "%d(r%d)", dst, regd); 306 1.1 christos } 307 1.7 christos else 308 1.7 christos return -1; 309 1.1 christos } 310 1.1 christos } 311 1.1 christos break; 312 1.1 christos 313 1.1 christos case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */ 314 1.1 christos if (as == 0) 315 1.1 christos { 316 1.1 christos if (regd == 3) 317 1.1 christos { 318 1.1 christos /* Constsnts. */ 319 1.1 christos sprintf (op, "#0"); 320 1.1 christos sprintf (comm, "r3 As==00"); 321 1.1 christos } 322 1.1 christos else 323 1.1 christos { 324 1.1 christos /* Register. */ 325 1.1 christos sprintf (op, "r%d", regd); 326 1.1 christos } 327 1.1 christos *cycles = 1; 328 1.1 christos } 329 1.1 christos else if (as == 2) 330 1.1 christos { 331 1.1 christos * cycles = print_as2_reg_name (regd, op, comm, 1, 1, 3); 332 1.1 christos } 333 1.1 christos else if (as == 3) 334 1.1 christos { 335 1.1 christos if (regd == 0) 336 1.1 christos { 337 1.1 christos *cycles = 3; 338 1.1 christos /* absolute. @pc+ */ 339 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 340 1.1 christos { 341 1.6 christos cmd_len += 2; 342 1.1 christos sprintf (op, "#%d", dst); 343 1.1 christos if (dst > 9 || dst < 0) 344 1.6 christos sprintf (comm, "#0x%04x", PS (dst)); 345 1.6 christos if (extended_dst) 346 1.6 christos { 347 1.6 christos dst |= extended_dst << 16; 348 1.6 christos if (dst & 0x80000) 349 1.6 christos dst |= -1U << 20; 350 1.6 christos sprintf (op, "#%d", dst); 351 1.6 christos if (dst > 9 || dst < 0) 352 1.6 christos sprintf (comm, "#0x%05x", dst); 353 1.6 christos } 354 1.1 christos } 355 1.7 christos else 356 1.7 christos return -1; 357 1.1 christos } 358 1.1 christos else 359 1.1 christos * cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3); 360 1.1 christos } 361 1.1 christos else if (as == 1) 362 1.1 christos { 363 1.1 christos *cycles = 4; 364 1.1 christos if (regd == 0) 365 1.1 christos { 366 1.1 christos /* PC relative. */ 367 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 368 1.1 christos { 369 1.6 christos cmd_len += 2; 370 1.6 christos sprintf (op, "0x%04x", PS (dst)); 371 1.6 christos sprintf (comm, "PC rel. 0x%04x", 372 1.6 christos PS ((short) addr + 2 + dst)); 373 1.6 christos if (extended_dst) 374 1.6 christos { 375 1.6 christos dst |= extended_dst << 16; 376 1.6 christos sprintf (op, "0x%05x", dst & 0xffff); 377 1.6 christos sprintf (comm, "PC rel. 0x%05lx", 378 1.6 christos (long)((addr + 2 + dst) & 0xfffff)); 379 1.6 christos } 380 1.1 christos } 381 1.7 christos else 382 1.7 christos return -1; 383 1.1 christos } 384 1.1 christos else if (regd == 2) 385 1.1 christos { 386 1.1 christos /* Absolute. */ 387 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 388 1.1 christos { 389 1.6 christos cmd_len += 2; 390 1.6 christos sprintf (op, "&0x%04x", PS (dst)); 391 1.6 christos if (extended_dst) 392 1.6 christos { 393 1.6 christos dst |= extended_dst << 16; 394 1.6 christos sprintf (op, "&0x%05x", dst & 0xfffff); 395 1.6 christos } 396 1.1 christos } 397 1.7 christos else 398 1.7 christos return -1; 399 1.1 christos } 400 1.1 christos else if (regd == 3) 401 1.1 christos { 402 1.1 christos *cycles = 1; 403 1.1 christos sprintf (op, "#1"); 404 1.1 christos sprintf (comm, "r3 As==01"); 405 1.1 christos } 406 1.1 christos else 407 1.1 christos { 408 1.1 christos /* Indexed. */ 409 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm)) 410 1.1 christos { 411 1.6 christos cmd_len += 2; 412 1.6 christos if (extended_dst) 413 1.6 christos { 414 1.6 christos dst |= extended_dst << 16; 415 1.6 christos if (dst & 0x80000) 416 1.6 christos dst |= -1U << 20; 417 1.6 christos } 418 1.6 christos sprintf (op, "%d(r%d)", dst, regd); 419 1.6 christos if (dst > 9 || dst < 0) 420 1.6 christos sprintf (comm, "%05x", dst); 421 1.1 christos } 422 1.7 christos else 423 1.7 christos return -1; 424 1.1 christos } 425 1.1 christos } 426 1.1 christos break; 427 1.1 christos 428 1.1 christos case 3: /* Jumps. */ 429 1.1 christos where = insn & 0x03ff; 430 1.1 christos if (where & 0x200) 431 1.1 christos where |= ~0x03ff; 432 1.1 christos if (where > 512 || where < -511) 433 1.1 christos return 0; 434 1.1 christos 435 1.1 christos where *= 2; 436 1.1 christos sprintf (op, "$%+-8d", where + 2); 437 1.1 christos sprintf (comm, "abs 0x%lx", (long) (addr + 2 + where)); 438 1.1 christos *cycles = 2; 439 1.1 christos return 2; 440 1.1 christos break; 441 1.6 christos 442 1.1 christos default: 443 1.1 christos cmd_len = 0; 444 1.1 christos } 445 1.1 christos 446 1.1 christos return cmd_len; 447 1.1 christos } 448 1.1 christos 449 1.1 christos static int 450 1.1 christos msp430_doubleoperand (disassemble_info *info, 451 1.1 christos struct msp430_opcode_s *opcode, 452 1.1 christos bfd_vma addr, 453 1.1 christos unsigned short insn, 454 1.1 christos char *op1, 455 1.1 christos char *op2, 456 1.1 christos char *comm1, 457 1.1 christos char *comm2, 458 1.1 christos unsigned short extension_word, 459 1.1 christos int *cycles) 460 1.1 christos { 461 1.1 christos int regs = 0, regd = 0; 462 1.1 christos int ad = 0, as = 0; 463 1.1 christos int cmd_len = 2; 464 1.1 christos int dst = 0; 465 1.1 christos int fmt; 466 1.1 christos int extended_dst = extension_word & 0xf; 467 1.1 christos int extended_src = (extension_word >> 7) & 0xf; 468 1.1 christos 469 1.1 christos regd = insn & 0x0f; 470 1.1 christos regs = (insn & 0x0f00) >> 8; 471 1.1 christos as = (insn & 0x0030) >> 4; 472 1.1 christos ad = (insn & 0x0080) >> 7; 473 1.1 christos 474 1.1 christos if (opcode->fmt < 0) 475 1.1 christos fmt = (- opcode->fmt) - 1; 476 1.1 christos else 477 1.1 christos fmt = opcode->fmt; 478 1.1 christos 479 1.1 christos if (fmt == 0) 480 1.1 christos { 481 1.1 christos /* Special case: rla and rlc are the only 2 emulated instructions that 482 1.1 christos fall into two operand instructions. */ 483 1.1 christos /* With dst, there are only: 484 1.1 christos Rm Register, 485 1.1 christos x(Rm) Indexed, 486 1.1 christos 0xXXXX Relative, 487 1.6 christos &0xXXXX Absolute 488 1.1 christos emulated_ins dst 489 1.1 christos basic_ins dst, dst. */ 490 1.1 christos 491 1.1 christos if (regd != regs || as != ad) 492 1.1 christos return 0; /* May be 'data' section. */ 493 1.1 christos 494 1.1 christos if (ad == 0) 495 1.1 christos { 496 1.1 christos /* Register mode. */ 497 1.1 christos if (regd == 3) 498 1.1 christos { 499 1.6 christos strcpy (comm1, _("Warning: illegal as emulation instr")); 500 1.1 christos return -1; 501 1.1 christos } 502 1.1 christos 503 1.1 christos sprintf (op1, "r%d", regd); 504 1.1 christos *cycles = 1; 505 1.1 christos } 506 1.1 christos else /* ad == 1 */ 507 1.1 christos { 508 1.1 christos if (regd == 0) 509 1.1 christos { 510 1.1 christos /* PC relative, Symbolic. */ 511 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 512 1.1 christos { 513 1.6 christos cmd_len += 4; 514 1.6 christos *cycles = 6; 515 1.6 christos sprintf (op1, "0x%04x", PS (dst)); 516 1.6 christos sprintf (comm1, "PC rel. 0x%04x", 517 1.6 christos PS ((short) addr + 2 + dst)); 518 1.6 christos if (extension_word) 519 1.6 christos { 520 1.6 christos dst |= extended_dst << 16; 521 1.6 christos if (dst & 0x80000) 522 1.6 christos dst |= -1U << 20; 523 1.6 christos sprintf (op1, "0x%05x", dst & 0xfffff); 524 1.6 christos sprintf (comm1, "PC rel. 0x%05lx", 525 1.6 christos (long)((addr + 2 + dst) & 0xfffff)); 526 1.6 christos } 527 1.1 christos } 528 1.7 christos else 529 1.7 christos return -1; 530 1.1 christos } 531 1.1 christos else if (regd == 2) 532 1.1 christos { 533 1.1 christos /* Absolute. */ 534 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 535 1.1 christos { 536 1.6 christos int src; 537 1.6 christos 538 1.6 christos /* If the 'src' field is not the same as the dst 539 1.6 christos then this is not an rla instruction. */ 540 1.6 christos if (msp430dis_opcode_signed (addr + 4, info, &src, comm2)) 541 1.6 christos { 542 1.6 christos if (src != dst) 543 1.6 christos return 0; 544 1.6 christos } 545 1.7 christos else 546 1.7 christos return -1; 547 1.6 christos cmd_len += 4; 548 1.6 christos *cycles = 6; 549 1.6 christos sprintf (op1, "&0x%04x", PS (dst)); 550 1.6 christos if (extension_word) 551 1.6 christos { 552 1.6 christos dst |= extended_dst << 16; 553 1.6 christos sprintf (op1, "&0x%05x", dst & 0xfffff); 554 1.6 christos } 555 1.1 christos } 556 1.7 christos else 557 1.7 christos return -1; 558 1.1 christos } 559 1.1 christos else 560 1.1 christos { 561 1.1 christos /* Indexed. */ 562 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 563 1.1 christos { 564 1.6 christos if (extension_word) 565 1.6 christos { 566 1.6 christos dst |= extended_dst << 16; 567 1.6 christos if (dst & 0x80000) 568 1.6 christos dst |= -1U << 20; 569 1.6 christos } 570 1.6 christos cmd_len += 4; 571 1.6 christos *cycles = 6; 572 1.6 christos sprintf (op1, "%d(r%d)", dst, regd); 573 1.6 christos if (dst > 9 || dst < -9) 574 1.6 christos sprintf (comm1, "#0x%05x", dst); 575 1.1 christos } 576 1.7 christos else 577 1.7 christos return -1; 578 1.1 christos } 579 1.1 christos } 580 1.1 christos 581 1.1 christos *op2 = 0; 582 1.1 christos *comm2 = 0; 583 1.1 christos 584 1.1 christos return cmd_len; 585 1.1 christos } 586 1.1 christos 587 1.1 christos /* Two operands exactly. */ 588 1.1 christos if (ad == 0 && regd == 3) 589 1.1 christos { 590 1.1 christos /* R2/R3 are illegal as dest: may be data section. */ 591 1.6 christos strcpy (comm1, _("Warning: illegal as 2-op instr")); 592 1.1 christos return -1; 593 1.1 christos } 594 1.1 christos 595 1.1 christos /* Source. */ 596 1.1 christos if (as == 0) 597 1.1 christos { 598 1.1 christos *cycles = 1; 599 1.1 christos if (regs == 3) 600 1.1 christos { 601 1.1 christos /* Constants. */ 602 1.1 christos sprintf (op1, "#0"); 603 1.1 christos sprintf (comm1, "r3 As==00"); 604 1.1 christos } 605 1.1 christos else 606 1.1 christos { 607 1.1 christos /* Register. */ 608 1.1 christos sprintf (op1, "r%d", regs); 609 1.1 christos } 610 1.1 christos } 611 1.1 christos else if (as == 2) 612 1.1 christos { 613 1.1 christos * cycles = print_as2_reg_name (regs, op1, comm1, 1, 1, regs == 0 ? 3 : 2); 614 1.1 christos } 615 1.1 christos else if (as == 3) 616 1.1 christos { 617 1.1 christos if (regs == 0) 618 1.1 christos { 619 1.1 christos *cycles = 3; 620 1.1 christos /* Absolute. @pc+. */ 621 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 622 1.6 christos { 623 1.6 christos cmd_len += 2; 624 1.1 christos sprintf (op1, "#%d", dst); 625 1.1 christos if (dst > 9 || dst < 0) 626 1.6 christos sprintf (comm1, "#0x%04x", PS (dst)); 627 1.6 christos if (extension_word) 628 1.6 christos { 629 1.6 christos dst &= 0xffff; 630 1.6 christos dst |= extended_src << 16; 631 1.6 christos if (dst & 0x80000) 632 1.6 christos dst |= -1U << 20; 633 1.6 christos sprintf (op1, "#%d", dst); 634 1.6 christos if (dst > 9 || dst < 0) 635 1.6 christos sprintf (comm1, "0x%05x", dst & 0xfffff); 636 1.6 christos } 637 1.1 christos } 638 1.7 christos else 639 1.7 christos return -1; 640 1.1 christos } 641 1.1 christos else 642 1.1 christos * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2); 643 1.1 christos } 644 1.1 christos else if (as == 1) 645 1.1 christos { 646 1.1 christos if (regs == 0) 647 1.1 christos { 648 1.1 christos *cycles = 4; 649 1.1 christos /* PC relative. */ 650 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 651 1.6 christos { 652 1.6 christos cmd_len += 2; 653 1.6 christos sprintf (op1, "0x%04x", PS (dst)); 654 1.6 christos sprintf (comm1, "PC rel. 0x%04x", 655 1.6 christos PS ((short) addr + 2 + dst)); 656 1.6 christos if (extension_word) 657 1.6 christos { 658 1.6 christos dst &= 0xffff; 659 1.6 christos dst |= extended_src << 16; 660 1.6 christos if (dst & 0x80000) 661 1.6 christos dst |= -1U << 20; 662 1.6 christos sprintf (op1, "0x%05x", dst & 0xfffff); 663 1.6 christos sprintf (comm1, "PC rel. 0x%05lx", 664 1.6 christos (long) ((addr + 2 + dst) & 0xfffff)); 665 1.6 christos } 666 1.1 christos } 667 1.7 christos else 668 1.7 christos return -1; 669 1.1 christos } 670 1.1 christos else if (regs == 2) 671 1.1 christos { 672 1.1 christos *cycles = 2; 673 1.1 christos /* Absolute. */ 674 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 675 1.6 christos { 676 1.6 christos cmd_len += 2; 677 1.6 christos sprintf (op1, "&0x%04x", PS (dst)); 678 1.6 christos sprintf (comm1, "0x%04x", PS (dst)); 679 1.6 christos if (extension_word) 680 1.6 christos { 681 1.6 christos dst &= 0xffff; 682 1.6 christos dst |= extended_src << 16; 683 1.6 christos sprintf (op1, "&0x%05x", dst & 0xfffff); 684 1.6 christos * comm1 = 0; 685 1.6 christos } 686 1.1 christos } 687 1.7 christos else 688 1.7 christos return -1; 689 1.1 christos } 690 1.1 christos else if (regs == 3) 691 1.1 christos { 692 1.1 christos *cycles = 1; 693 1.1 christos sprintf (op1, "#1"); 694 1.1 christos sprintf (comm1, "r3 As==01"); 695 1.1 christos } 696 1.1 christos else 697 1.1 christos { 698 1.1 christos *cycles = 3; 699 1.1 christos /* Indexed. */ 700 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 701 1.1 christos { 702 1.6 christos cmd_len += 2; 703 1.6 christos if (extension_word) 704 1.6 christos { 705 1.6 christos dst &= 0xffff; 706 1.6 christos dst |= extended_src << 16; 707 1.6 christos if (dst & 0x80000) 708 1.6 christos dst |= -1U << 20; 709 1.6 christos } 710 1.6 christos sprintf (op1, "%d(r%d)", dst, regs); 711 1.6 christos if (dst > 9 || dst < -9) 712 1.6 christos sprintf (comm1, "0x%05x", dst); 713 1.6 christos } 714 1.7 christos else 715 1.7 christos return -1; 716 1.1 christos } 717 1.1 christos } 718 1.1 christos 719 1.1 christos /* Destination. Special care needed on addr + XXXX. */ 720 1.1 christos 721 1.1 christos if (ad == 0) 722 1.1 christos { 723 1.1 christos /* Register. */ 724 1.1 christos if (regd == 0) 725 1.1 christos { 726 1.1 christos *cycles += 1; 727 1.1 christos sprintf (op2, "r0"); 728 1.1 christos } 729 1.1 christos else if (regd == 1) 730 1.1 christos sprintf (op2, "r1"); 731 1.1 christos 732 1.1 christos else if (regd == 2) 733 1.1 christos sprintf (op2, "r2"); 734 1.1 christos 735 1.1 christos else 736 1.1 christos sprintf (op2, "r%d", regd); 737 1.1 christos } 738 1.1 christos else /* ad == 1. */ 739 1.1 christos { 740 1.1 christos * cycles += 3; 741 1.1 christos 742 1.1 christos if (regd == 0) 743 1.1 christos { 744 1.1 christos /* PC relative. */ 745 1.1 christos *cycles += 1; 746 1.6 christos if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2)) 747 1.6 christos { 748 1.6 christos sprintf (op2, "0x%04x", PS (dst)); 749 1.6 christos sprintf (comm2, "PC rel. 0x%04x", 750 1.6 christos PS ((short) addr + cmd_len + dst)); 751 1.6 christos if (extension_word) 752 1.6 christos { 753 1.6 christos dst |= extended_dst << 16; 754 1.6 christos if (dst & 0x80000) 755 1.6 christos dst |= -1U << 20; 756 1.6 christos sprintf (op2, "0x%05x", dst & 0xfffff); 757 1.6 christos sprintf (comm2, "PC rel. 0x%05lx", 758 1.6 christos (long)((addr + cmd_len + dst) & 0xfffff)); 759 1.6 christos } 760 1.1 christos } 761 1.7 christos else 762 1.7 christos return -1; 763 1.1 christos cmd_len += 2; 764 1.1 christos } 765 1.1 christos else if (regd == 2) 766 1.1 christos { 767 1.1 christos /* Absolute. */ 768 1.6 christos if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2)) 769 1.1 christos { 770 1.6 christos cmd_len += 2; 771 1.6 christos sprintf (op2, "&0x%04x", PS (dst)); 772 1.6 christos if (extension_word) 773 1.6 christos { 774 1.6 christos dst |= extended_dst << 16; 775 1.6 christos sprintf (op2, "&0x%05x", dst & 0xfffff); 776 1.6 christos } 777 1.1 christos } 778 1.7 christos else 779 1.7 christos return -1; 780 1.1 christos } 781 1.1 christos else 782 1.1 christos { 783 1.6 christos if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2)) 784 1.6 christos { 785 1.6 christos cmd_len += 2; 786 1.1 christos if (dst > 9 || dst < 0) 787 1.6 christos sprintf (comm2, "0x%04x", PS (dst)); 788 1.6 christos if (extension_word) 789 1.6 christos { 790 1.6 christos dst |= extended_dst << 16; 791 1.6 christos if (dst & 0x80000) 792 1.6 christos dst |= -1U << 20; 793 1.6 christos if (dst > 9 || dst < 0) 794 1.6 christos sprintf (comm2, "0x%05x", dst & 0xfffff); 795 1.6 christos } 796 1.6 christos sprintf (op2, "%d(r%d)", dst, regd); 797 1.1 christos } 798 1.7 christos else 799 1.7 christos return -1; 800 1.1 christos } 801 1.1 christos } 802 1.1 christos 803 1.1 christos return cmd_len; 804 1.1 christos } 805 1.1 christos 806 1.1 christos static int 807 1.1 christos msp430_branchinstr (disassemble_info *info, 808 1.1 christos struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED, 809 1.1 christos bfd_vma addr ATTRIBUTE_UNUSED, 810 1.1 christos unsigned short insn, 811 1.1 christos char *op1, 812 1.1 christos char *comm1, 813 1.1 christos int *cycles) 814 1.1 christos { 815 1.1 christos int regs = 0, regd = 0; 816 1.1 christos int as = 0; 817 1.1 christos int cmd_len = 2; 818 1.6 christos int dst = 0; 819 1.6 christos unsigned short udst = 0; 820 1.1 christos 821 1.1 christos regd = insn & 0x0f; 822 1.1 christos regs = (insn & 0x0f00) >> 8; 823 1.1 christos as = (insn & 0x0030) >> 4; 824 1.1 christos 825 1.1 christos if (regd != 0) /* Destination register is not a PC. */ 826 1.1 christos return 0; 827 1.1 christos 828 1.1 christos /* dst is a source register. */ 829 1.1 christos if (as == 0) 830 1.1 christos { 831 1.1 christos /* Constants. */ 832 1.1 christos if (regs == 3) 833 1.1 christos { 834 1.1 christos *cycles = 1; 835 1.1 christos sprintf (op1, "#0"); 836 1.1 christos sprintf (comm1, "r3 As==00"); 837 1.1 christos } 838 1.1 christos else 839 1.1 christos { 840 1.1 christos /* Register. */ 841 1.1 christos *cycles = 1; 842 1.1 christos sprintf (op1, "r%d", regs); 843 1.1 christos } 844 1.1 christos } 845 1.1 christos else if (as == 2) 846 1.1 christos { 847 1.1 christos * cycles = print_as2_reg_name (regs, op1, comm1, 2, 1, 2); 848 1.1 christos } 849 1.1 christos else if (as == 3) 850 1.1 christos { 851 1.1 christos if (regs == 0) 852 1.1 christos { 853 1.1 christos /* Absolute. @pc+ */ 854 1.1 christos *cycles = 3; 855 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1)) 856 1.6 christos { 857 1.6 christos cmd_len += 2; 858 1.6 christos sprintf (op1, "#0x%04x", PS (udst)); 859 1.6 christos } 860 1.7 christos else 861 1.7 christos return -1; 862 1.1 christos } 863 1.1 christos else 864 1.1 christos * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2); 865 1.1 christos } 866 1.1 christos else if (as == 1) 867 1.1 christos { 868 1.1 christos * cycles = 3; 869 1.1 christos 870 1.1 christos if (regs == 0) 871 1.1 christos { 872 1.1 christos /* PC relative. */ 873 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 874 1.6 christos { 875 1.6 christos cmd_len += 2; 876 1.6 christos (*cycles)++; 877 1.6 christos sprintf (op1, "0x%04x", PS (dst)); 878 1.6 christos sprintf (comm1, "PC rel. 0x%04x", 879 1.6 christos PS ((short) addr + 2 + dst)); 880 1.6 christos } 881 1.7 christos else 882 1.7 christos return -1; 883 1.1 christos } 884 1.1 christos else if (regs == 2) 885 1.1 christos { 886 1.1 christos /* Absolute. */ 887 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1)) 888 1.6 christos { 889 1.6 christos cmd_len += 2; 890 1.6 christos sprintf (op1, "&0x%04x", PS (udst)); 891 1.6 christos } 892 1.7 christos else 893 1.7 christos return -1; 894 1.1 christos } 895 1.1 christos else if (regs == 3) 896 1.1 christos { 897 1.1 christos (*cycles)--; 898 1.1 christos sprintf (op1, "#1"); 899 1.1 christos sprintf (comm1, "r3 As==01"); 900 1.1 christos } 901 1.1 christos else 902 1.1 christos { 903 1.1 christos /* Indexed. */ 904 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 905 1.6 christos { 906 1.6 christos cmd_len += 2; 907 1.6 christos sprintf (op1, "%d(r%d)", dst, regs); 908 1.6 christos } 909 1.7 christos else 910 1.7 christos return -1; 911 1.1 christos } 912 1.1 christos } 913 1.1 christos 914 1.1 christos return cmd_len; 915 1.1 christos } 916 1.1 christos 917 1.1 christos static int 918 1.1 christos msp430x_calla_instr (disassemble_info * info, 919 1.1 christos bfd_vma addr, 920 1.1 christos unsigned short insn, 921 1.1 christos char * op1, 922 1.1 christos char * comm1, 923 1.1 christos int * cycles) 924 1.1 christos { 925 1.1 christos unsigned int ureg = insn & 0xf; 926 1.1 christos int reg = insn & 0xf; 927 1.1 christos int am = (insn & 0xf0) >> 4; 928 1.1 christos int cmd_len = 2; 929 1.1 christos unsigned short udst = 0; 930 1.6 christos int dst = 0; 931 1.1 christos 932 1.1 christos switch (am) 933 1.1 christos { 934 1.1 christos case 4: /* CALLA Rdst */ 935 1.1 christos *cycles = 1; 936 1.1 christos sprintf (op1, "r%d", reg); 937 1.1 christos break; 938 1.1 christos 939 1.1 christos case 5: /* CALLA x(Rdst) */ 940 1.1 christos *cycles = 3; 941 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 942 1.6 christos { 943 1.6 christos cmd_len += 2; 944 1.6 christos sprintf (op1, "%d(r%d)", dst, reg); 945 1.6 christos if (reg == 0) 946 1.6 christos sprintf (comm1, "PC rel. 0x%05lx", (long) (addr + 2 + dst)); 947 1.6 christos else 948 1.6 christos sprintf (comm1, "0x%05x", dst); 949 1.6 christos } 950 1.7 christos else 951 1.7 christos return -1; 952 1.1 christos break; 953 1.1 christos 954 1.1 christos case 6: /* CALLA @Rdst */ 955 1.1 christos *cycles = 2; 956 1.1 christos sprintf (op1, "@r%d", reg); 957 1.1 christos break; 958 1.1 christos 959 1.1 christos case 7: /* CALLA @Rdst+ */ 960 1.1 christos *cycles = 2; 961 1.1 christos sprintf (op1, "@r%d+", reg); 962 1.1 christos break; 963 1.1 christos 964 1.1 christos case 8: /* CALLA &abs20 */ 965 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1)) 966 1.6 christos { 967 1.6 christos cmd_len += 2; 968 1.6 christos *cycles = 4; 969 1.6 christos sprintf (op1, "&%d", (ureg << 16) + udst); 970 1.6 christos sprintf (comm1, "0x%05x", (ureg << 16) + udst); 971 1.6 christos } 972 1.7 christos else 973 1.7 christos return -1; 974 1.1 christos break; 975 1.1 christos 976 1.1 christos case 9: /* CALLA pcrel-sym */ 977 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1)) 978 1.6 christos { 979 1.6 christos cmd_len += 2; 980 1.6 christos *cycles = 4; 981 1.6 christos sprintf (op1, "%d(PC)", (reg << 16) + dst); 982 1.6 christos sprintf (comm1, "PC rel. 0x%05lx", 983 1.6 christos (long) (addr + 2 + dst + (reg << 16))); 984 1.6 christos } 985 1.7 christos else 986 1.7 christos return -1; 987 1.1 christos break; 988 1.1 christos 989 1.1 christos case 11: /* CALLA #imm20 */ 990 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1)) 991 1.6 christos { 992 1.6 christos cmd_len += 2; 993 1.6 christos *cycles = 4; 994 1.6 christos sprintf (op1, "#%d", (ureg << 16) + udst); 995 1.6 christos sprintf (comm1, "0x%05x", (ureg << 16) + udst); 996 1.6 christos } 997 1.7 christos else 998 1.7 christos return -1; 999 1.1 christos break; 1000 1.1 christos 1001 1.1 christos default: 1002 1.6 christos strcpy (comm1, _("Warning: unrecognised CALLA addressing mode")); 1003 1.1 christos return -1; 1004 1.1 christos } 1005 1.1 christos 1006 1.1 christos return cmd_len; 1007 1.1 christos } 1008 1.1 christos 1009 1.1 christos int 1010 1.1 christos print_insn_msp430 (bfd_vma addr, disassemble_info *info) 1011 1.1 christos { 1012 1.1 christos void *stream = info->stream; 1013 1.1 christos fprintf_ftype prin = info->fprintf_func; 1014 1.1 christos struct msp430_opcode_s *opcode; 1015 1.1 christos char op1[32], op2[32], comm1[64], comm2[64]; 1016 1.1 christos int cmd_len = 0; 1017 1.1 christos unsigned short insn; 1018 1.1 christos int cycles = 0; 1019 1.1 christos char *bc = ""; 1020 1.1 christos unsigned short extension_word = 0; 1021 1.6 christos unsigned short bits; 1022 1.1 christos 1023 1.6 christos if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL)) 1024 1.7 christos return -1; 1025 1.1 christos 1026 1.1 christos if (((int) addr & 0xffff) > 0xffdf) 1027 1.1 christos { 1028 1.1 christos (*prin) (stream, "interrupt service routine at 0x%04x", 0xffff & insn); 1029 1.1 christos return 2; 1030 1.1 christos } 1031 1.1 christos 1032 1.1 christos *comm1 = 0; 1033 1.1 christos *comm2 = 0; 1034 1.1 christos 1035 1.1 christos /* Check for an extension word. */ 1036 1.1 christos if ((insn & 0xf800) == 0x1800) 1037 1.1 christos { 1038 1.1 christos extension_word = insn; 1039 1.1 christos addr += 2; 1040 1.6 christos if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL)) 1041 1.7 christos return -1; 1042 1.1 christos } 1043 1.1 christos 1044 1.1 christos for (opcode = msp430_opcodes; opcode->name; opcode++) 1045 1.1 christos { 1046 1.1 christos if ((insn & opcode->bin_mask) == opcode->bin_opcode 1047 1.1 christos && opcode->bin_opcode != 0x9300) 1048 1.1 christos { 1049 1.1 christos *op1 = 0; 1050 1.1 christos *op2 = 0; 1051 1.1 christos *comm1 = 0; 1052 1.1 christos *comm2 = 0; 1053 1.1 christos 1054 1.1 christos /* r0 as destination. Ad should be zero. */ 1055 1.1 christos if (opcode->insn_opnumb == 3 1056 1.1 christos && (insn & 0x000f) == 0 1057 1.1 christos && (insn & 0x0080) == 0) 1058 1.1 christos { 1059 1.7 christos int ret = 1060 1.1 christos msp430_branchinstr (info, opcode, addr, insn, op1, comm1, 1061 1.1 christos &cycles); 1062 1.7 christos 1063 1.7 christos if (ret == -1) 1064 1.7 christos return -1; 1065 1.7 christos cmd_len += ret; 1066 1.1 christos if (cmd_len) 1067 1.1 christos break; 1068 1.1 christos } 1069 1.1 christos 1070 1.1 christos switch (opcode->insn_opnumb) 1071 1.1 christos { 1072 1.1 christos int n; 1073 1.1 christos int reg; 1074 1.7 christos int ret; 1075 1.1 christos 1076 1.1 christos case 4: 1077 1.7 christos ret = msp430x_calla_instr (info, addr, insn, 1078 1.7 christos op1, comm1, & cycles); 1079 1.7 christos if (ret == -1) 1080 1.7 christos return -1; 1081 1.7 christos cmd_len += ret; 1082 1.1 christos break; 1083 1.1 christos 1084 1.1 christos case 5: /* PUSHM/POPM */ 1085 1.1 christos n = (insn & 0xf0) >> 4; 1086 1.1 christos reg = (insn & 0xf); 1087 1.1 christos 1088 1.1 christos sprintf (op1, "#%d", n + 1); 1089 1.1 christos if (opcode->bin_opcode == 0x1400) 1090 1.1 christos /* PUSHM */ 1091 1.1 christos sprintf (op2, "r%d", reg); 1092 1.1 christos else 1093 1.1 christos /* POPM */ 1094 1.1 christos sprintf (op2, "r%d", reg + n); 1095 1.1 christos if (insn & 0x100) 1096 1.1 christos sprintf (comm1, "16-bit words"); 1097 1.1 christos else 1098 1.1 christos { 1099 1.1 christos sprintf (comm1, "20-bit words"); 1100 1.1 christos bc =".a"; 1101 1.1 christos } 1102 1.6 christos 1103 1.1 christos cycles = 2; /*FIXME*/ 1104 1.1 christos cmd_len = 2; 1105 1.1 christos break; 1106 1.1 christos 1107 1.1 christos case 6: /* RRAM, RRCM, RRUM, RLAM. */ 1108 1.1 christos n = ((insn >> 10) & 0x3) + 1; 1109 1.1 christos reg = (insn & 0xf); 1110 1.1 christos if ((insn & 0x10) == 0) 1111 1.1 christos bc =".a"; 1112 1.1 christos sprintf (op1, "#%d", n); 1113 1.1 christos sprintf (op2, "r%d", reg); 1114 1.1 christos cycles = 2; /*FIXME*/ 1115 1.1 christos cmd_len = 2; 1116 1.1 christos break; 1117 1.1 christos 1118 1.1 christos case 8: /* ADDA, CMPA, SUBA. */ 1119 1.1 christos reg = (insn & 0xf); 1120 1.1 christos n = (insn >> 8) & 0xf; 1121 1.1 christos if (insn & 0x40) 1122 1.1 christos { 1123 1.1 christos sprintf (op1, "r%d", n); 1124 1.1 christos cmd_len = 2; 1125 1.1 christos } 1126 1.1 christos else 1127 1.1 christos { 1128 1.1 christos n <<= 16; 1129 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1)) 1130 1.6 christos { 1131 1.6 christos n |= bits; 1132 1.6 christos sprintf (op1, "#%d", n); 1133 1.6 christos if (n > 9 || n < 0) 1134 1.6 christos sprintf (comm1, "0x%05x", n); 1135 1.6 christos } 1136 1.7 christos else 1137 1.7 christos return -1; 1138 1.1 christos cmd_len = 4; 1139 1.1 christos } 1140 1.1 christos sprintf (op2, "r%d", reg); 1141 1.1 christos cycles = 2; /*FIXME*/ 1142 1.1 christos break; 1143 1.1 christos 1144 1.1 christos case 9: /* MOVA */ 1145 1.1 christos reg = (insn & 0xf); 1146 1.1 christos n = (insn >> 8) & 0xf; 1147 1.1 christos switch ((insn >> 4) & 0xf) 1148 1.1 christos { 1149 1.1 christos case 0: /* MOVA @Rsrc, Rdst */ 1150 1.1 christos cmd_len = 2; 1151 1.1 christos sprintf (op1, "@r%d", n); 1152 1.1 christos if (strcmp (opcode->name, "bra") != 0) 1153 1.1 christos sprintf (op2, "r%d", reg); 1154 1.1 christos break; 1155 1.6 christos 1156 1.1 christos case 1: /* MOVA @Rsrc+, Rdst */ 1157 1.1 christos cmd_len = 2; 1158 1.1 christos if (strcmp (opcode->name, "reta") != 0) 1159 1.1 christos { 1160 1.1 christos sprintf (op1, "@r%d+", n); 1161 1.1 christos if (strcmp (opcode->name, "bra") != 0) 1162 1.1 christos sprintf (op2, "r%d", reg); 1163 1.1 christos } 1164 1.1 christos break; 1165 1.6 christos 1166 1.1 christos case 2: /* MOVA &abs20, Rdst */ 1167 1.1 christos cmd_len = 4; 1168 1.1 christos n <<= 16; 1169 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1)) 1170 1.6 christos { 1171 1.6 christos n |= bits; 1172 1.6 christos sprintf (op1, "&%d", n); 1173 1.6 christos if (n > 9 || n < 0) 1174 1.6 christos sprintf (comm1, "0x%05x", n); 1175 1.6 christos if (strcmp (opcode->name, "bra") != 0) 1176 1.6 christos sprintf (op2, "r%d", reg); 1177 1.6 christos } 1178 1.7 christos else 1179 1.7 christos return -1; 1180 1.1 christos break; 1181 1.6 christos 1182 1.1 christos case 3: /* MOVA x(Rsrc), Rdst */ 1183 1.1 christos cmd_len = 4; 1184 1.1 christos if (strcmp (opcode->name, "bra") != 0) 1185 1.1 christos sprintf (op2, "r%d", reg); 1186 1.1 christos reg = n; 1187 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &n, comm1)) 1188 1.6 christos { 1189 1.6 christos sprintf (op1, "%d(r%d)", n, reg); 1190 1.6 christos if (n > 9 || n < 0) 1191 1.6 christos { 1192 1.6 christos if (reg == 0) 1193 1.6 christos sprintf (comm1, "PC rel. 0x%05lx", 1194 1.6 christos (long) (addr + 2 + n)); 1195 1.6 christos else 1196 1.6 christos sprintf (comm1, "0x%05x", n); 1197 1.6 christos } 1198 1.1 christos } 1199 1.7 christos else 1200 1.7 christos return -1; 1201 1.1 christos break; 1202 1.1 christos 1203 1.1 christos case 6: /* MOVA Rsrc, &abs20 */ 1204 1.1 christos cmd_len = 4; 1205 1.1 christos reg <<= 16; 1206 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm2)) 1207 1.6 christos { 1208 1.6 christos reg |= bits; 1209 1.6 christos sprintf (op1, "r%d", n); 1210 1.6 christos sprintf (op2, "&%d", reg); 1211 1.6 christos if (reg > 9 || reg < 0) 1212 1.6 christos sprintf (comm2, "0x%05x", reg); 1213 1.6 christos } 1214 1.7 christos else 1215 1.7 christos return -1; 1216 1.1 christos break; 1217 1.1 christos 1218 1.1 christos case 7: /* MOVA Rsrc, x(Rdst) */ 1219 1.1 christos cmd_len = 4; 1220 1.1 christos sprintf (op1, "r%d", n); 1221 1.6 christos if (msp430dis_opcode_signed (addr + 2, info, &n, comm2)) 1222 1.6 christos { 1223 1.6 christos sprintf (op2, "%d(r%d)", n, reg); 1224 1.6 christos if (n > 9 || n < 0) 1225 1.6 christos { 1226 1.6 christos if (reg == 0) 1227 1.6 christos sprintf (comm2, "PC rel. 0x%05lx", 1228 1.6 christos (long) (addr + 2 + n)); 1229 1.6 christos else 1230 1.6 christos sprintf (comm2, "0x%05x", n); 1231 1.6 christos } 1232 1.1 christos } 1233 1.7 christos else 1234 1.7 christos return -1; 1235 1.1 christos break; 1236 1.6 christos 1237 1.1 christos case 8: /* MOVA #imm20, Rdst */ 1238 1.1 christos cmd_len = 4; 1239 1.1 christos n <<= 16; 1240 1.6 christos if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1)) 1241 1.6 christos { 1242 1.6 christos n |= bits; 1243 1.6 christos if (n & 0x80000) 1244 1.6 christos n |= -1U << 20; 1245 1.6 christos sprintf (op1, "#%d", n); 1246 1.6 christos if (n > 9 || n < 0) 1247 1.6 christos sprintf (comm1, "0x%05x", n); 1248 1.6 christos if (strcmp (opcode->name, "bra") != 0) 1249 1.6 christos sprintf (op2, "r%d", reg); 1250 1.6 christos } 1251 1.7 christos else 1252 1.7 christos return -1; 1253 1.1 christos break; 1254 1.6 christos 1255 1.1 christos case 12: /* MOVA Rsrc, Rdst */ 1256 1.1 christos cmd_len = 2; 1257 1.1 christos sprintf (op1, "r%d", n); 1258 1.1 christos if (strcmp (opcode->name, "bra") != 0) 1259 1.1 christos sprintf (op2, "r%d", reg); 1260 1.1 christos break; 1261 1.1 christos 1262 1.1 christos default: 1263 1.1 christos break; 1264 1.1 christos } 1265 1.1 christos cycles = 2; /* FIXME */ 1266 1.1 christos break; 1267 1.1 christos } 1268 1.1 christos 1269 1.1 christos if (cmd_len) 1270 1.1 christos break; 1271 1.1 christos 1272 1.1 christos switch (opcode->insn_opnumb) 1273 1.1 christos { 1274 1.7 christos int ret; 1275 1.7 christos 1276 1.1 christos case 0: 1277 1.1 christos cmd_len += msp430_nooperands (opcode, addr, insn, comm1, &cycles); 1278 1.1 christos break; 1279 1.1 christos case 2: 1280 1.7 christos ret = 1281 1.1 christos msp430_doubleoperand (info, opcode, addr, insn, op1, op2, 1282 1.1 christos comm1, comm2, 1283 1.1 christos extension_word, 1284 1.1 christos &cycles); 1285 1.7 christos 1286 1.7 christos if (ret == -1) 1287 1.7 christos return -1; 1288 1.7 christos cmd_len += ret; 1289 1.1 christos if (insn & BYTE_OPERATION) 1290 1.1 christos { 1291 1.1 christos if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0)) 1292 1.1 christos bc = ".a"; 1293 1.1 christos else 1294 1.1 christos bc = ".b"; 1295 1.1 christos } 1296 1.1 christos else if (extension_word) 1297 1.1 christos { 1298 1.6 christos if (extension_word & BYTE_OPERATION) 1299 1.1 christos bc = ".w"; 1300 1.1 christos else 1301 1.1 christos { 1302 1.1 christos bc = ".?"; 1303 1.6 christos sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected")); 1304 1.1 christos } 1305 1.1 christos } 1306 1.6 christos 1307 1.1 christos break; 1308 1.1 christos case 1: 1309 1.7 christos ret = 1310 1.1 christos msp430_singleoperand (info, opcode, addr, insn, op1, comm1, 1311 1.1 christos extension_word, 1312 1.1 christos &cycles); 1313 1.7 christos 1314 1.7 christos if (ret == -1) 1315 1.7 christos return -1; 1316 1.7 christos cmd_len += ret; 1317 1.1 christos if (extension_word 1318 1.1 christos && (strcmp (opcode->name, "swpb") == 0 1319 1.1 christos || strcmp (opcode->name, "sxt") == 0)) 1320 1.1 christos { 1321 1.1 christos if (insn & BYTE_OPERATION) 1322 1.1 christos { 1323 1.1 christos bc = ".?"; 1324 1.6 christos sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected")); 1325 1.1 christos } 1326 1.1 christos else if (extension_word & BYTE_OPERATION) 1327 1.1 christos bc = ".w"; 1328 1.1 christos else 1329 1.1 christos bc = ".a"; 1330 1.1 christos } 1331 1.1 christos else if (insn & BYTE_OPERATION && opcode->fmt != 3) 1332 1.1 christos { 1333 1.1 christos if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0)) 1334 1.1 christos bc = ".a"; 1335 1.1 christos else 1336 1.1 christos bc = ".b"; 1337 1.1 christos } 1338 1.1 christos else if (extension_word) 1339 1.1 christos { 1340 1.1 christos if (extension_word & (1 << 6)) 1341 1.1 christos bc = ".w"; 1342 1.1 christos else 1343 1.1 christos { 1344 1.1 christos bc = ".?"; 1345 1.6 christos sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected")); 1346 1.1 christos } 1347 1.1 christos } 1348 1.1 christos break; 1349 1.1 christos default: 1350 1.1 christos break; 1351 1.1 christos } 1352 1.1 christos } 1353 1.1 christos 1354 1.1 christos if (cmd_len) 1355 1.1 christos break; 1356 1.1 christos } 1357 1.1 christos 1358 1.1 christos if (cmd_len < 1) 1359 1.1 christos { 1360 1.1 christos /* Unknown opcode, or invalid combination of operands. */ 1361 1.1 christos if (extension_word) 1362 1.1 christos { 1363 1.1 christos prin (stream, ".word 0x%04x, 0x%04x; ????", extension_word, PS (insn)); 1364 1.1 christos if (*comm1) 1365 1.1 christos prin (stream, "\t %s", comm1); 1366 1.1 christos return 4; 1367 1.1 christos } 1368 1.1 christos (*prin) (stream, ".word 0x%04x; ????", PS (insn)); 1369 1.1 christos return 2; 1370 1.1 christos } 1371 1.1 christos 1372 1.1 christos /* Display the repeat count (if set) for extended register mode. */ 1373 1.1 christos if (cmd_len == 2 && ((extension_word & 0xf) != 0)) 1374 1.1 christos { 1375 1.1 christos if (extension_word & (1 << 7)) 1376 1.1 christos prin (stream, "rpt r%d { ", extension_word & 0xf); 1377 1.1 christos else 1378 1.1 christos prin (stream, "rpt #%d { ", (extension_word & 0xf) + 1); 1379 1.1 christos } 1380 1.1 christos 1381 1.6 christos /* Special case: RRC with an extension word and the ZC bit set is actually RRU. */ 1382 1.6 christos if (extension_word 1383 1.6 christos && (extension_word & IGNORE_CARRY_BIT) 1384 1.6 christos && strcmp (opcode->name, "rrc") == 0) 1385 1.6 christos (*prin) (stream, "rrux%s", bc); 1386 1.6 christos else if (extension_word && opcode->name[strlen (opcode->name) - 1] != 'x') 1387 1.1 christos (*prin) (stream, "%sx%s", opcode->name, bc); 1388 1.1 christos else 1389 1.1 christos (*prin) (stream, "%s%s", opcode->name, bc); 1390 1.1 christos 1391 1.1 christos if (*op1) 1392 1.1 christos (*prin) (stream, "\t%s", op1); 1393 1.1 christos if (*op2) 1394 1.1 christos (*prin) (stream, ","); 1395 1.1 christos 1396 1.1 christos if (strlen (op1) < 7) 1397 1.1 christos (*prin) (stream, "\t"); 1398 1.1 christos if (!strlen (op1)) 1399 1.1 christos (*prin) (stream, "\t"); 1400 1.1 christos 1401 1.1 christos if (*op2) 1402 1.1 christos (*prin) (stream, "%s", op2); 1403 1.1 christos if (strlen (op2) < 8) 1404 1.1 christos (*prin) (stream, "\t"); 1405 1.1 christos 1406 1.1 christos if (*comm1 || *comm2) 1407 1.1 christos (*prin) (stream, ";"); 1408 1.1 christos else if (cycles) 1409 1.1 christos { 1410 1.1 christos if (*op2) 1411 1.1 christos (*prin) (stream, ";"); 1412 1.1 christos else 1413 1.1 christos { 1414 1.1 christos if (strlen (op1) < 7) 1415 1.1 christos (*prin) (stream, ";"); 1416 1.1 christos else 1417 1.1 christos (*prin) (stream, "\t;"); 1418 1.1 christos } 1419 1.1 christos } 1420 1.1 christos if (*comm1) 1421 1.1 christos (*prin) (stream, "%s", comm1); 1422 1.1 christos if (*comm1 && *comm2) 1423 1.1 christos (*prin) (stream, ","); 1424 1.1 christos if (*comm2) 1425 1.1 christos (*prin) (stream, " %s", comm2); 1426 1.1 christos 1427 1.1 christos if (extension_word) 1428 1.1 christos cmd_len += 2; 1429 1.1 christos 1430 1.1 christos return cmd_len; 1431 1.1 christos } 1432