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