123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431 |
- /* Disassemble MSP430 instructions.
- Copyright (C) 2002-2022 Free Software Foundation, Inc.
- Contributed by Dmitry Diky <diwil@mail.ru>
- This file is part of the GNU opcodes library.
- This library is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3, or (at your option)
- any later version.
- It is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
- License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
- MA 02110-1301, USA. */
- #include "sysdep.h"
- #include <stdio.h>
- #include <ctype.h>
- #include <sys/types.h>
- #include <errno.h>
- #include "disassemble.h"
- #include "opintl.h"
- #include "libiberty.h"
- #define DASM_SECTION
- #include "opcode/msp430.h"
- #undef DASM_SECTION
- #define PS(x) (0xffff & (x))
- static bool
- msp430dis_read_two_bytes (bfd_vma addr,
- disassemble_info * info,
- bfd_byte * buffer,
- char * comm)
- {
- int status;
- status = info->read_memory_func (addr, buffer, 2, info);
- if (status == 0)
- return true;
- /* PR 20150: A status of EIO means that there were no more bytes left
- to read in the current section. This can happen when disassembling
- interrupt vectors for example. Avoid cluttering the output with
- unhelpful error messages in this case. */
- if (status == EIO)
- {
- if (comm)
- sprintf (comm, _("Warning: disassembly unreliable - not enough bytes available"));
- }
- else
- {
- info->memory_error_func (status, addr, info);
- if (comm)
- sprintf (comm, _("Error: read from memory failed"));
- }
- return false;
- }
- static bool
- msp430dis_opcode_unsigned (bfd_vma addr,
- disassemble_info * info,
- unsigned short * return_val,
- char * comm)
- {
- bfd_byte buffer[2];
- if (msp430dis_read_two_bytes (addr, info, buffer, comm))
- {
- * return_val = bfd_getl16 (buffer);
- return true;
- }
- else
- {
- * return_val = 0;
- return false;
- }
- }
- static bool
- msp430dis_opcode_signed (bfd_vma addr,
- disassemble_info * info,
- signed int * return_val,
- char * comm)
- {
- bfd_byte buffer[2];
- if (msp430dis_read_two_bytes (addr, info, buffer, comm))
- {
- int status;
- status = bfd_getl_signed_16 (buffer);
- if (status & 0x8000)
- status |= -1U << 16;
- * return_val = status;
- return true;
- }
- else
- {
- * return_val = 0;
- return false;
- }
- }
- static int
- msp430_nooperands (struct msp430_opcode_s *opcode,
- bfd_vma addr ATTRIBUTE_UNUSED,
- unsigned short insn ATTRIBUTE_UNUSED,
- char *comm,
- int *cycles)
- {
- /* Pop with constant. */
- if (insn == 0x43b2)
- return 0;
- if (insn == opcode->bin_opcode)
- return 2;
- if (opcode->fmt == 0)
- {
- if ((insn & 0x0f00) != 0x0300 || (insn & 0x0f00) != 0x0200)
- return 0;
- strcpy (comm, "emulated...");
- *cycles = 1;
- }
- else
- {
- strcpy (comm, "return from interupt");
- *cycles = 5;
- }
- return 2;
- }
- static int
- print_as2_reg_name (int regno, char * op1, char * comm1,
- int c2, int c3, int cd)
- {
- switch (regno)
- {
- case 2:
- sprintf (op1, "#4");
- sprintf (comm1, "r2 As==10");
- return c2;
- case 3:
- sprintf (op1, "#2");
- sprintf (comm1, "r3 As==10");
- return c3;
- default:
- /* Indexed register mode @Rn. */
- sprintf (op1, "@r%d", regno);
- return cd;
- }
- }
- static int
- print_as3_reg_name (int regno, char * op1, char * comm1,
- int c2, int c3, int cd)
- {
- switch (regno)
- {
- case 2:
- sprintf (op1, "#8");
- sprintf (comm1, "r2 As==11");
- return c2;
- case 3:
- sprintf (op1, "#-1");
- sprintf (comm1, "r3 As==11");
- return c3;
- default:
- /* Post incremented @Rn+. */
- sprintf (op1, "@r%d+", regno);
- return cd;
- }
- }
- static int
- msp430_singleoperand (disassemble_info *info,
- struct msp430_opcode_s *opcode,
- bfd_vma addr,
- unsigned short insn,
- char *op,
- char *comm,
- unsigned short extension_word,
- int *cycles)
- {
- int regs = 0, regd = 0;
- int ad = 0, as = 0;
- int where = 0;
- int cmd_len = 2;
- int dst = 0;
- int fmt;
- int extended_dst = extension_word & 0xf;
- regd = insn & 0x0f;
- regs = (insn & 0x0f00) >> 8;
- as = (insn & 0x0030) >> 4;
- ad = (insn & 0x0080) >> 7;
- if (opcode->fmt < 0)
- fmt = (- opcode->fmt) - 1;
- else
- fmt = opcode->fmt;
- switch (fmt)
- {
- case 0: /* Emulated work with dst register. */
- if (regs != 2 && regs != 3 && regs != 1)
- return 0;
- /* Check if not clr insn. */
- if (opcode->bin_opcode == 0x4300 && (ad || as))
- return 0;
- /* Check if really inc, incd insns. */
- if ((opcode->bin_opcode & 0xff00) == 0x5300 && as == 3)
- return 0;
- if (ad == 0)
- {
- *cycles = 1;
- /* Register. */
- if (regd == 0)
- {
- *cycles += 1;
- sprintf (op, "r0");
- }
- else if (regd == 1)
- sprintf (op, "r1");
- else if (regd == 2)
- sprintf (op, "r2");
- else
- sprintf (op, "r%d", regd);
- }
- else /* ad == 1 msp430dis_opcode. */
- {
- if (regd == 0)
- {
- /* PC relative. */
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
- {
- cmd_len += 2;
- *cycles = 4;
- sprintf (op, "0x%04x", dst);
- sprintf (comm, "PC rel. abs addr 0x%04x",
- PS ((short) (addr + 2) + dst));
- if (extended_dst)
- {
- dst |= extended_dst << 16;
- sprintf (op, "0x%05x", dst);
- sprintf (comm, "PC rel. abs addr 0x%05lx",
- (long)((addr + 2 + dst) & 0xfffff));
- }
- }
- else
- return -1;
- }
- else if (regd == 2)
- {
- /* Absolute. */
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
- {
- cmd_len += 2;
- *cycles = 4;
- sprintf (op, "&0x%04x", PS (dst));
- if (extended_dst)
- {
- dst |= extended_dst << 16;
- sprintf (op, "&0x%05x", dst & 0xfffff);
- }
- }
- else
- return -1;
- }
- else
- {
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
- {
- cmd_len += 2;
- *cycles = 4;
- if (extended_dst)
- {
- dst |= extended_dst << 16;
- if (dst & 0x80000)
- dst |= -1U << 20;
- }
- sprintf (op, "%d(r%d)", dst, regd);
- }
- else
- return -1;
- }
- }
- break;
- case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */
- if (as == 0)
- {
- if (regd == 3)
- {
- /* Constsnts. */
- sprintf (op, "#0");
- sprintf (comm, "r3 As==00");
- }
- else
- {
- /* Register. */
- sprintf (op, "r%d", regd);
- }
- *cycles = 1;
- }
- else if (as == 2)
- {
- * cycles = print_as2_reg_name (regd, op, comm, 1, 1, 3);
- }
- else if (as == 3)
- {
- if (regd == 0)
- {
- *cycles = 3;
- /* absolute. @pc+ */
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
- {
- cmd_len += 2;
- sprintf (op, "#%d", dst);
- if (dst > 9 || dst < 0)
- sprintf (comm, "#0x%04x", PS (dst));
- if (extended_dst)
- {
- dst |= extended_dst << 16;
- if (dst & 0x80000)
- dst |= -1U << 20;
- sprintf (op, "#%d", dst);
- if (dst > 9 || dst < 0)
- sprintf (comm, "#0x%05x", dst);
- }
- }
- else
- return -1;
- }
- else
- * cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3);
- }
- else if (as == 1)
- {
- *cycles = 4;
- if (regd == 0)
- {
- /* PC relative. */
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
- {
- cmd_len += 2;
- sprintf (op, "0x%04x", PS (dst));
- sprintf (comm, "PC rel. 0x%04x",
- PS ((short) addr + 2 + dst));
- if (extended_dst)
- {
- dst |= extended_dst << 16;
- sprintf (op, "0x%05x", dst & 0xffff);
- sprintf (comm, "PC rel. 0x%05lx",
- (long)((addr + 2 + dst) & 0xfffff));
- }
- }
- else
- return -1;
- }
- else if (regd == 2)
- {
- /* Absolute. */
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
- {
- cmd_len += 2;
- sprintf (op, "&0x%04x", PS (dst));
- if (extended_dst)
- {
- dst |= extended_dst << 16;
- sprintf (op, "&0x%05x", dst & 0xfffff);
- }
- }
- else
- return -1;
- }
- else if (regd == 3)
- {
- *cycles = 1;
- sprintf (op, "#1");
- sprintf (comm, "r3 As==01");
- }
- else
- {
- /* Indexed. */
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm))
- {
- cmd_len += 2;
- if (extended_dst)
- {
- dst |= extended_dst << 16;
- if (dst & 0x80000)
- dst |= -1U << 20;
- }
- sprintf (op, "%d(r%d)", dst, regd);
- if (dst > 9 || dst < 0)
- sprintf (comm, "%05x", dst);
- }
- else
- return -1;
- }
- }
- break;
- case 3: /* Jumps. */
- where = insn & 0x03ff;
- if (where & 0x200)
- where |= ~0x03ff;
- if (where > 512 || where < -511)
- return 0;
- where *= 2;
- sprintf (op, "$%+-8d", where + 2);
- sprintf (comm, "abs 0x%lx", (long) (addr + 2 + where));
- *cycles = 2;
- return 2;
- break;
- default:
- cmd_len = 0;
- }
- return cmd_len;
- }
- static int
- msp430_doubleoperand (disassemble_info *info,
- struct msp430_opcode_s *opcode,
- bfd_vma addr,
- unsigned short insn,
- char *op1,
- char *op2,
- char *comm1,
- char *comm2,
- unsigned short extension_word,
- int *cycles)
- {
- int regs = 0, regd = 0;
- int ad = 0, as = 0;
- int cmd_len = 2;
- int dst = 0;
- int fmt;
- int extended_dst = extension_word & 0xf;
- int extended_src = (extension_word >> 7) & 0xf;
- regd = insn & 0x0f;
- regs = (insn & 0x0f00) >> 8;
- as = (insn & 0x0030) >> 4;
- ad = (insn & 0x0080) >> 7;
- if (opcode->fmt < 0)
- fmt = (- opcode->fmt) - 1;
- else
- fmt = opcode->fmt;
- if (fmt == 0)
- {
- /* Special case: rla and rlc are the only 2 emulated instructions that
- fall into two operand instructions. */
- /* With dst, there are only:
- Rm Register,
- x(Rm) Indexed,
- 0xXXXX Relative,
- &0xXXXX Absolute
- emulated_ins dst
- basic_ins dst, dst. */
- if (regd != regs || as != ad)
- return 0; /* May be 'data' section. */
- if (ad == 0)
- {
- /* Register mode. */
- if (regd == 3)
- {
- strcpy (comm1, _("Warning: illegal as emulation instr"));
- return -1;
- }
- sprintf (op1, "r%d", regd);
- *cycles = 1;
- }
- else /* ad == 1 */
- {
- if (regd == 0)
- {
- /* PC relative, Symbolic. */
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
- {
- cmd_len += 4;
- *cycles = 6;
- sprintf (op1, "0x%04x", PS (dst));
- sprintf (comm1, "PC rel. 0x%04x",
- PS ((short) addr + 2 + dst));
- if (extension_word)
- {
- dst |= extended_dst << 16;
- if (dst & 0x80000)
- dst |= -1U << 20;
- sprintf (op1, "0x%05x", dst & 0xfffff);
- sprintf (comm1, "PC rel. 0x%05lx",
- (long)((addr + 2 + dst) & 0xfffff));
- }
- }
- else
- return -1;
- }
- else if (regd == 2)
- {
- /* Absolute. */
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
- {
- int src;
- /* If the 'src' field is not the same as the dst
- then this is not an rla instruction. */
- if (msp430dis_opcode_signed (addr + 4, info, &src, comm2))
- {
- if (src != dst)
- return 0;
- }
- else
- return -1;
- cmd_len += 4;
- *cycles = 6;
- sprintf (op1, "&0x%04x", PS (dst));
- if (extension_word)
- {
- dst |= extended_dst << 16;
- sprintf (op1, "&0x%05x", dst & 0xfffff);
- }
- }
- else
- return -1;
- }
- else
- {
- /* Indexed. */
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
- {
- if (extension_word)
- {
- dst |= extended_dst << 16;
- if (dst & 0x80000)
- dst |= -1U << 20;
- }
- cmd_len += 4;
- *cycles = 6;
- sprintf (op1, "%d(r%d)", dst, regd);
- if (dst > 9 || dst < -9)
- sprintf (comm1, "#0x%05x", dst);
- }
- else
- return -1;
- }
- }
- *op2 = 0;
- *comm2 = 0;
- return cmd_len;
- }
- /* Two operands exactly. */
- if (ad == 0 && regd == 3)
- {
- /* R2/R3 are illegal as dest: may be data section. */
- strcpy (comm1, _("Warning: illegal as 2-op instr"));
- return -1;
- }
- /* Source. */
- if (as == 0)
- {
- *cycles = 1;
- if (regs == 3)
- {
- /* Constants. */
- sprintf (op1, "#0");
- sprintf (comm1, "r3 As==00");
- }
- else
- {
- /* Register. */
- sprintf (op1, "r%d", regs);
- }
- }
- else if (as == 2)
- {
- * cycles = print_as2_reg_name (regs, op1, comm1, 1, 1, regs == 0 ? 3 : 2);
- }
- else if (as == 3)
- {
- if (regs == 0)
- {
- *cycles = 3;
- /* Absolute. @pc+. */
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
- {
- cmd_len += 2;
- sprintf (op1, "#%d", dst);
- if (dst > 9 || dst < 0)
- sprintf (comm1, "#0x%04x", PS (dst));
- if (extension_word)
- {
- dst &= 0xffff;
- dst |= extended_src << 16;
- if (dst & 0x80000)
- dst |= -1U << 20;
- sprintf (op1, "#%d", dst);
- if (dst > 9 || dst < 0)
- sprintf (comm1, "0x%05x", dst & 0xfffff);
- }
- }
- else
- return -1;
- }
- else
- * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
- }
- else if (as == 1)
- {
- if (regs == 0)
- {
- *cycles = 4;
- /* PC relative. */
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
- {
- cmd_len += 2;
- sprintf (op1, "0x%04x", PS (dst));
- sprintf (comm1, "PC rel. 0x%04x",
- PS ((short) addr + 2 + dst));
- if (extension_word)
- {
- dst &= 0xffff;
- dst |= extended_src << 16;
- if (dst & 0x80000)
- dst |= -1U << 20;
- sprintf (op1, "0x%05x", dst & 0xfffff);
- sprintf (comm1, "PC rel. 0x%05lx",
- (long) ((addr + 2 + dst) & 0xfffff));
- }
- }
- else
- return -1;
- }
- else if (regs == 2)
- {
- *cycles = 2;
- /* Absolute. */
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
- {
- cmd_len += 2;
- sprintf (op1, "&0x%04x", PS (dst));
- sprintf (comm1, "0x%04x", PS (dst));
- if (extension_word)
- {
- dst &= 0xffff;
- dst |= extended_src << 16;
- sprintf (op1, "&0x%05x", dst & 0xfffff);
- * comm1 = 0;
- }
- }
- else
- return -1;
- }
- else if (regs == 3)
- {
- *cycles = 1;
- sprintf (op1, "#1");
- sprintf (comm1, "r3 As==01");
- }
- else
- {
- *cycles = 3;
- /* Indexed. */
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
- {
- cmd_len += 2;
- if (extension_word)
- {
- dst &= 0xffff;
- dst |= extended_src << 16;
- if (dst & 0x80000)
- dst |= -1U << 20;
- }
- sprintf (op1, "%d(r%d)", dst, regs);
- if (dst > 9 || dst < -9)
- sprintf (comm1, "0x%05x", dst);
- }
- else
- return -1;
- }
- }
- /* Destination. Special care needed on addr + XXXX. */
- if (ad == 0)
- {
- /* Register. */
- if (regd == 0)
- {
- *cycles += 1;
- sprintf (op2, "r0");
- }
- else if (regd == 1)
- sprintf (op2, "r1");
- else if (regd == 2)
- sprintf (op2, "r2");
- else
- sprintf (op2, "r%d", regd);
- }
- else /* ad == 1. */
- {
- * cycles += 3;
- if (regd == 0)
- {
- /* PC relative. */
- *cycles += 1;
- if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
- {
- sprintf (op2, "0x%04x", PS (dst));
- sprintf (comm2, "PC rel. 0x%04x",
- PS ((short) addr + cmd_len + dst));
- if (extension_word)
- {
- dst |= extended_dst << 16;
- if (dst & 0x80000)
- dst |= -1U << 20;
- sprintf (op2, "0x%05x", dst & 0xfffff);
- sprintf (comm2, "PC rel. 0x%05lx",
- (long)((addr + cmd_len + dst) & 0xfffff));
- }
- }
- else
- return -1;
- cmd_len += 2;
- }
- else if (regd == 2)
- {
- /* Absolute. */
- if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
- {
- cmd_len += 2;
- sprintf (op2, "&0x%04x", PS (dst));
- if (extension_word)
- {
- dst |= extended_dst << 16;
- sprintf (op2, "&0x%05x", dst & 0xfffff);
- }
- }
- else
- return -1;
- }
- else
- {
- if (msp430dis_opcode_signed (addr + cmd_len, info, &dst, comm2))
- {
- cmd_len += 2;
- if (dst > 9 || dst < 0)
- sprintf (comm2, "0x%04x", PS (dst));
- if (extension_word)
- {
- dst |= extended_dst << 16;
- if (dst & 0x80000)
- dst |= -1U << 20;
- if (dst > 9 || dst < 0)
- sprintf (comm2, "0x%05x", dst & 0xfffff);
- }
- sprintf (op2, "%d(r%d)", dst, regd);
- }
- else
- return -1;
- }
- }
- return cmd_len;
- }
- static int
- msp430_branchinstr (disassemble_info *info,
- struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED,
- bfd_vma addr ATTRIBUTE_UNUSED,
- unsigned short insn,
- char *op1,
- char *comm1,
- int *cycles)
- {
- int regs = 0, regd = 0;
- int as = 0;
- int cmd_len = 2;
- int dst = 0;
- unsigned short udst = 0;
- regd = insn & 0x0f;
- regs = (insn & 0x0f00) >> 8;
- as = (insn & 0x0030) >> 4;
- if (regd != 0) /* Destination register is not a PC. */
- return 0;
- /* dst is a source register. */
- if (as == 0)
- {
- /* Constants. */
- if (regs == 3)
- {
- *cycles = 1;
- sprintf (op1, "#0");
- sprintf (comm1, "r3 As==00");
- }
- else
- {
- /* Register. */
- *cycles = 1;
- sprintf (op1, "r%d", regs);
- }
- }
- else if (as == 2)
- {
- * cycles = print_as2_reg_name (regs, op1, comm1, 2, 1, 2);
- }
- else if (as == 3)
- {
- if (regs == 0)
- {
- /* Absolute. @pc+ */
- *cycles = 3;
- if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
- {
- cmd_len += 2;
- sprintf (op1, "#0x%04x", PS (udst));
- }
- else
- return -1;
- }
- else
- * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
- }
- else if (as == 1)
- {
- * cycles = 3;
- if (regs == 0)
- {
- /* PC relative. */
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
- {
- cmd_len += 2;
- (*cycles)++;
- sprintf (op1, "0x%04x", PS (dst));
- sprintf (comm1, "PC rel. 0x%04x",
- PS ((short) addr + 2 + dst));
- }
- else
- return -1;
- }
- else if (regs == 2)
- {
- /* Absolute. */
- if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
- {
- cmd_len += 2;
- sprintf (op1, "&0x%04x", PS (udst));
- }
- else
- return -1;
- }
- else if (regs == 3)
- {
- (*cycles)--;
- sprintf (op1, "#1");
- sprintf (comm1, "r3 As==01");
- }
- else
- {
- /* Indexed. */
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
- {
- cmd_len += 2;
- sprintf (op1, "%d(r%d)", dst, regs);
- }
- else
- return -1;
- }
- }
- return cmd_len;
- }
- static int
- msp430x_calla_instr (disassemble_info * info,
- bfd_vma addr,
- unsigned short insn,
- char * op1,
- char * comm1,
- int * cycles)
- {
- unsigned int ureg = insn & 0xf;
- int reg = insn & 0xf;
- int am = (insn & 0xf0) >> 4;
- int cmd_len = 2;
- unsigned short udst = 0;
- int dst = 0;
- switch (am)
- {
- case 4: /* CALLA Rdst */
- *cycles = 1;
- sprintf (op1, "r%d", reg);
- break;
- case 5: /* CALLA x(Rdst) */
- *cycles = 3;
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
- {
- cmd_len += 2;
- sprintf (op1, "%d(r%d)", dst, reg);
- if (reg == 0)
- sprintf (comm1, "PC rel. 0x%05lx", (long) (addr + 2 + dst));
- else
- sprintf (comm1, "0x%05x", dst);
- }
- else
- return -1;
- break;
- case 6: /* CALLA @Rdst */
- *cycles = 2;
- sprintf (op1, "@r%d", reg);
- break;
- case 7: /* CALLA @Rdst+ */
- *cycles = 2;
- sprintf (op1, "@r%d+", reg);
- break;
- case 8: /* CALLA &abs20 */
- if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
- {
- cmd_len += 2;
- *cycles = 4;
- sprintf (op1, "&%d", (ureg << 16) + udst);
- sprintf (comm1, "0x%05x", (ureg << 16) + udst);
- }
- else
- return -1;
- break;
- case 9: /* CALLA pcrel-sym */
- if (msp430dis_opcode_signed (addr + 2, info, &dst, comm1))
- {
- cmd_len += 2;
- *cycles = 4;
- sprintf (op1, "%d(PC)", (reg << 16) + dst);
- sprintf (comm1, "PC rel. 0x%05lx",
- (long) (addr + 2 + dst + (reg << 16)));
- }
- else
- return -1;
- break;
- case 11: /* CALLA #imm20 */
- if (msp430dis_opcode_unsigned (addr + 2, info, &udst, comm1))
- {
- cmd_len += 2;
- *cycles = 4;
- sprintf (op1, "#%d", (ureg << 16) + udst);
- sprintf (comm1, "0x%05x", (ureg << 16) + udst);
- }
- else
- return -1;
- break;
- default:
- strcpy (comm1, _("Warning: unrecognised CALLA addressing mode"));
- return -1;
- }
- return cmd_len;
- }
- int
- print_insn_msp430 (bfd_vma addr, disassemble_info *info)
- {
- void *stream = info->stream;
- fprintf_ftype prin = info->fprintf_func;
- struct msp430_opcode_s *opcode;
- char op1[32], op2[32], comm1[64], comm2[64];
- int cmd_len = 0;
- unsigned short insn;
- int cycles = 0;
- char *bc = "";
- unsigned short extension_word = 0;
- unsigned short bits;
- if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
- return -1;
- if (((int) addr & 0xffff) > 0xffdf)
- {
- (*prin) (stream, "interrupt service routine at 0x%04x", 0xffff & insn);
- return 2;
- }
- *comm1 = 0;
- *comm2 = 0;
- /* Check for an extension word. */
- if ((insn & 0xf800) == 0x1800)
- {
- extension_word = insn;
- addr += 2;
- if (! msp430dis_opcode_unsigned (addr, info, &insn, NULL))
- return -1;
- }
- for (opcode = msp430_opcodes; opcode->name; opcode++)
- {
- if ((insn & opcode->bin_mask) == opcode->bin_opcode
- && opcode->bin_opcode != 0x9300)
- {
- *op1 = 0;
- *op2 = 0;
- *comm1 = 0;
- *comm2 = 0;
- /* r0 as destination. Ad should be zero. */
- if (opcode->insn_opnumb == 3
- && (insn & 0x000f) == 0
- && (insn & 0x0080) == 0)
- {
- int ret =
- msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
- &cycles);
- if (ret == -1)
- return -1;
- cmd_len += ret;
- if (cmd_len)
- break;
- }
- switch (opcode->insn_opnumb)
- {
- int n;
- int reg;
- int ret;
- case 4:
- ret = msp430x_calla_instr (info, addr, insn,
- op1, comm1, & cycles);
- if (ret == -1)
- return -1;
- cmd_len += ret;
- break;
- case 5: /* PUSHM/POPM */
- n = (insn & 0xf0) >> 4;
- reg = (insn & 0xf);
- sprintf (op1, "#%d", n + 1);
- if (opcode->bin_opcode == 0x1400)
- /* PUSHM */
- sprintf (op2, "r%d", reg);
- else
- /* POPM */
- sprintf (op2, "r%d", reg + n);
- if (insn & 0x100)
- sprintf (comm1, "16-bit words");
- else
- {
- sprintf (comm1, "20-bit words");
- bc =".a";
- }
- cycles = 2; /*FIXME*/
- cmd_len = 2;
- break;
- case 6: /* RRAM, RRCM, RRUM, RLAM. */
- n = ((insn >> 10) & 0x3) + 1;
- reg = (insn & 0xf);
- if ((insn & 0x10) == 0)
- bc =".a";
- sprintf (op1, "#%d", n);
- sprintf (op2, "r%d", reg);
- cycles = 2; /*FIXME*/
- cmd_len = 2;
- break;
- case 8: /* ADDA, CMPA, SUBA. */
- reg = (insn & 0xf);
- n = (insn >> 8) & 0xf;
- if (insn & 0x40)
- {
- sprintf (op1, "r%d", n);
- cmd_len = 2;
- }
- else
- {
- n <<= 16;
- if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
- {
- n |= bits;
- sprintf (op1, "#%d", n);
- if (n > 9 || n < 0)
- sprintf (comm1, "0x%05x", n);
- }
- else
- return -1;
- cmd_len = 4;
- }
- sprintf (op2, "r%d", reg);
- cycles = 2; /*FIXME*/
- break;
- case 9: /* MOVA */
- reg = (insn & 0xf);
- n = (insn >> 8) & 0xf;
- switch ((insn >> 4) & 0xf)
- {
- case 0: /* MOVA @Rsrc, Rdst */
- cmd_len = 2;
- sprintf (op1, "@r%d", n);
- if (strcmp (opcode->name, "bra") != 0)
- sprintf (op2, "r%d", reg);
- break;
- case 1: /* MOVA @Rsrc+, Rdst */
- cmd_len = 2;
- if (strcmp (opcode->name, "reta") != 0)
- {
- sprintf (op1, "@r%d+", n);
- if (strcmp (opcode->name, "bra") != 0)
- sprintf (op2, "r%d", reg);
- }
- break;
- case 2: /* MOVA &abs20, Rdst */
- cmd_len = 4;
- n <<= 16;
- if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
- {
- n |= bits;
- sprintf (op1, "&%d", n);
- if (n > 9 || n < 0)
- sprintf (comm1, "0x%05x", n);
- if (strcmp (opcode->name, "bra") != 0)
- sprintf (op2, "r%d", reg);
- }
- else
- return -1;
- break;
- case 3: /* MOVA x(Rsrc), Rdst */
- cmd_len = 4;
- if (strcmp (opcode->name, "bra") != 0)
- sprintf (op2, "r%d", reg);
- reg = n;
- if (msp430dis_opcode_signed (addr + 2, info, &n, comm1))
- {
- sprintf (op1, "%d(r%d)", n, reg);
- if (n > 9 || n < 0)
- {
- if (reg == 0)
- sprintf (comm1, "PC rel. 0x%05lx",
- (long) (addr + 2 + n));
- else
- sprintf (comm1, "0x%05x", n);
- }
- }
- else
- return -1;
- break;
- case 6: /* MOVA Rsrc, &abs20 */
- cmd_len = 4;
- reg <<= 16;
- if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm2))
- {
- reg |= bits;
- sprintf (op1, "r%d", n);
- sprintf (op2, "&%d", reg);
- if (reg > 9 || reg < 0)
- sprintf (comm2, "0x%05x", reg);
- }
- else
- return -1;
- break;
- case 7: /* MOVA Rsrc, x(Rdst) */
- cmd_len = 4;
- sprintf (op1, "r%d", n);
- if (msp430dis_opcode_signed (addr + 2, info, &n, comm2))
- {
- sprintf (op2, "%d(r%d)", n, reg);
- if (n > 9 || n < 0)
- {
- if (reg == 0)
- sprintf (comm2, "PC rel. 0x%05lx",
- (long) (addr + 2 + n));
- else
- sprintf (comm2, "0x%05x", n);
- }
- }
- else
- return -1;
- break;
- case 8: /* MOVA #imm20, Rdst */
- cmd_len = 4;
- n <<= 16;
- if (msp430dis_opcode_unsigned (addr + 2, info, &bits, comm1))
- {
- n |= bits;
- if (n & 0x80000)
- n |= -1U << 20;
- sprintf (op1, "#%d", n);
- if (n > 9 || n < 0)
- sprintf (comm1, "0x%05x", n);
- if (strcmp (opcode->name, "bra") != 0)
- sprintf (op2, "r%d", reg);
- }
- else
- return -1;
- break;
- case 12: /* MOVA Rsrc, Rdst */
- cmd_len = 2;
- sprintf (op1, "r%d", n);
- if (strcmp (opcode->name, "bra") != 0)
- sprintf (op2, "r%d", reg);
- break;
- default:
- break;
- }
- cycles = 2; /* FIXME */
- break;
- }
- if (cmd_len)
- break;
- switch (opcode->insn_opnumb)
- {
- int ret;
- case 0:
- cmd_len += msp430_nooperands (opcode, addr, insn, comm1, &cycles);
- break;
- case 2:
- ret =
- msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
- comm1, comm2,
- extension_word,
- &cycles);
- if (ret == -1)
- return -1;
- cmd_len += ret;
- if (insn & BYTE_OPERATION)
- {
- if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0))
- bc = ".a";
- else
- bc = ".b";
- }
- else if (extension_word)
- {
- if (extension_word & BYTE_OPERATION)
- bc = ".w";
- else
- {
- bc = ".?";
- sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
- }
- }
- break;
- case 1:
- ret =
- msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
- extension_word,
- &cycles);
- if (ret == -1)
- return -1;
- cmd_len += ret;
- if (extension_word
- && (strcmp (opcode->name, "swpb") == 0
- || strcmp (opcode->name, "sxt") == 0))
- {
- if (insn & BYTE_OPERATION)
- {
- bc = ".?";
- sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
- }
- else if (extension_word & BYTE_OPERATION)
- bc = ".w";
- else
- bc = ".a";
- }
- else if (insn & BYTE_OPERATION && opcode->fmt != 3)
- {
- if (extension_word != 0 && ((extension_word & BYTE_OPERATION) == 0))
- bc = ".a";
- else
- bc = ".b";
- }
- else if (extension_word)
- {
- if (extension_word & (1 << 6))
- bc = ".w";
- else
- {
- bc = ".?";
- sprintf (comm2, _("Warning: reserved use of A/L and B/W bits detected"));
- }
- }
- break;
- default:
- break;
- }
- }
- if (cmd_len)
- break;
- }
- if (cmd_len < 1)
- {
- /* Unknown opcode, or invalid combination of operands. */
- if (extension_word)
- {
- prin (stream, ".word 0x%04x, 0x%04x; ????", extension_word, PS (insn));
- if (*comm1)
- prin (stream, "\t %s", comm1);
- return 4;
- }
- (*prin) (stream, ".word 0x%04x; ????", PS (insn));
- return 2;
- }
- /* Display the repeat count (if set) for extended register mode. */
- if (cmd_len == 2 && ((extension_word & 0xf) != 0))
- {
- if (extension_word & (1 << 7))
- prin (stream, "rpt r%d { ", extension_word & 0xf);
- else
- prin (stream, "rpt #%d { ", (extension_word & 0xf) + 1);
- }
- /* Special case: RRC with an extension word and the ZC bit set is actually RRU. */
- if (extension_word
- && (extension_word & IGNORE_CARRY_BIT)
- && strcmp (opcode->name, "rrc") == 0)
- (*prin) (stream, "rrux%s", bc);
- else if (extension_word && opcode->name[strlen (opcode->name) - 1] != 'x')
- (*prin) (stream, "%sx%s", opcode->name, bc);
- else
- (*prin) (stream, "%s%s", opcode->name, bc);
- if (*op1)
- (*prin) (stream, "\t%s", op1);
- if (*op2)
- (*prin) (stream, ",");
- if (strlen (op1) < 7)
- (*prin) (stream, "\t");
- if (!strlen (op1))
- (*prin) (stream, "\t");
- if (*op2)
- (*prin) (stream, "%s", op2);
- if (strlen (op2) < 8)
- (*prin) (stream, "\t");
- if (*comm1 || *comm2)
- (*prin) (stream, ";");
- else if (cycles)
- {
- if (*op2)
- (*prin) (stream, ";");
- else
- {
- if (strlen (op1) < 7)
- (*prin) (stream, ";");
- else
- (*prin) (stream, "\t;");
- }
- }
- if (*comm1)
- (*prin) (stream, "%s", comm1);
- if (*comm1 && *comm2)
- (*prin) (stream, ",");
- if (*comm2)
- (*prin) (stream, " %s", comm2);
- if (extension_word)
- cmd_len += 2;
- return cmd_len;
- }
|