| Index: opcodes/msp430-dis.c
|
| diff --git a/opcodes/msp430-dis.c b/opcodes/msp430-dis.c
|
| index 71690a3c62b8c60b492fd5f0a9a0dcdbfb683e3e..c31463881ec96d5351a8c5d00c811597fddb8d15 100644
|
| --- a/opcodes/msp430-dis.c
|
| +++ b/opcodes/msp430-dis.c
|
| @@ -1,7 +1,6 @@
|
| /* Disassemble MSP430 instructions.
|
| - Copyright (C) 2002, 2004, 2005, 2007, 2009, 2010, 2012
|
| - Free Software Foundation, Inc.
|
| -
|
| + Copyright (C) 2002-2013 Free Software Foundation, Inc.
|
| +
|
| Contributed by Dmitry Diky <diwil@mail.ru>
|
|
|
| This file is part of the GNU opcodes library.
|
| @@ -83,26 +82,80 @@ msp430_nooperands (struct msp430_opcode_s *opcode,
|
| }
|
|
|
| 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;
|
| - short dst = 0;
|
| + 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;
|
|
|
| - switch (opcode->fmt)
|
| + 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)
|
| @@ -146,6 +199,13 @@ msp430_singleoperand (disassemble_info *info,
|
| 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 if (regd == 2)
|
| {
|
| @@ -154,12 +214,25 @@ msp430_singleoperand (disassemble_info *info,
|
| 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
|
| {
|
| dst = msp430dis_opcode (addr + 2, info);
|
| cmd_len += 2;
|
| *cycles = 4;
|
| + if (extended_dst)
|
| + {
|
| + dst |= extended_dst << 16;
|
| + if (dst & 0x80000)
|
| + dst |= -1 << 20;
|
| + }
|
| + else if (dst & 0x8000)
|
| + dst |= -1 << 16;
|
| sprintf (op, "%d(r%d)", dst, regd);
|
| }
|
| }
|
| @@ -183,51 +256,31 @@ msp430_singleoperand (disassemble_info *info,
|
| }
|
| else if (as == 2)
|
| {
|
| - *cycles = 1;
|
| - if (regd == 2)
|
| - {
|
| - sprintf (op, "#4");
|
| - sprintf (comm, "r2 As==10");
|
| - }
|
| - else if (regd == 3)
|
| - {
|
| - sprintf (op, "#2");
|
| - sprintf (comm, "r3 As==10");
|
| - }
|
| - else
|
| - {
|
| - *cycles = 3;
|
| - /* Indexed register mode @Rn. */
|
| - sprintf (op, "@r%d", regd);
|
| - }
|
| + * cycles = print_as2_reg_name (regd, op, comm, 1, 1, 3);
|
| }
|
| else if (as == 3)
|
| {
|
| - *cycles = 1;
|
| - if (regd == 2)
|
| - {
|
| - sprintf (op, "#8");
|
| - sprintf (comm, "r2 As==11");
|
| - }
|
| - else if (regd == 3)
|
| - {
|
| - sprintf (op, "#-1");
|
| - sprintf (comm, "r3 As==11");
|
| - }
|
| - else if (regd == 0)
|
| + if (regd == 0)
|
| {
|
| *cycles = 3;
|
| /* absolute. @pc+ */
|
| dst = msp430dis_opcode (addr + 2, info);
|
| cmd_len += 2;
|
| sprintf (op, "#%d", dst);
|
| - sprintf (comm, "#0x%04x", PS (dst));
|
| + if (dst > 9 || dst < 0)
|
| + sprintf (comm, "#0x%04x", PS (dst));
|
| + if (extended_dst)
|
| + {
|
| + dst |= extended_dst << 16;
|
| + if (dst & 0x80000)
|
| + dst |= -1 << 20;
|
| + sprintf (op, "#%d", dst);
|
| + if (dst > 9 || dst < 0)
|
| + sprintf (comm, "#0x%05x", dst);
|
| + }
|
| }
|
| else
|
| - {
|
| - *cycles = 3;
|
| - sprintf (op, "@r%d+", regd);
|
| - }
|
| + * cycles = print_as3_reg_name (regd, op, comm, 1, 1, 3);
|
| }
|
| else if (as == 1)
|
| {
|
| @@ -240,6 +293,13 @@ msp430_singleoperand (disassemble_info *info,
|
| 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 if (regd == 2)
|
| {
|
| @@ -247,6 +307,11 @@ msp430_singleoperand (disassemble_info *info,
|
| dst = msp430dis_opcode (addr + 2, info);
|
| cmd_len += 2;
|
| sprintf (op, "&0x%04x", PS (dst));
|
| + if (extended_dst)
|
| + {
|
| + dst |= extended_dst << 16;
|
| + sprintf (op, "&0x%05x", dst & 0xfffff);
|
| + }
|
| }
|
| else if (regd == 3)
|
| {
|
| @@ -256,10 +321,20 @@ msp430_singleoperand (disassemble_info *info,
|
| }
|
| else
|
| {
|
| - /* Indexd. */
|
| + /* Indexed. */
|
| dst = msp430dis_opcode (addr + 2, info);
|
| cmd_len += 2;
|
| + if (extended_dst)
|
| + {
|
| + dst |= extended_dst << 16;
|
| + if (dst & 0x80000)
|
| + dst |= -1 << 20;
|
| + }
|
| + else if (dst & 0x8000)
|
| + dst |= -1 << 16;
|
| sprintf (op, "%d(r%d)", dst, regd);
|
| + if (dst > 9 || dst < 0)
|
| + sprintf (comm, "%05x", dst);
|
| }
|
| }
|
| break;
|
| @@ -273,7 +348,7 @@ msp430_singleoperand (disassemble_info *info,
|
|
|
| where *= 2;
|
| sprintf (op, "$%+-8d", where + 2);
|
| - sprintf (comm, "abs 0x%x", PS ((short) (addr) + 2 + where));
|
| + sprintf (comm, "abs 0x%lx", (long) (addr + 2 + where));
|
| *cycles = 2;
|
| return 2;
|
| break;
|
| @@ -293,19 +368,28 @@ msp430_doubleoperand (disassemble_info *info,
|
| 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;
|
| - short dst = 0;
|
| + 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)
|
| + 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. */
|
| @@ -343,7 +427,15 @@ msp430_doubleoperand (disassemble_info *info,
|
| sprintf (op1, "0x%04x", PS (dst));
|
| sprintf (comm1, "PC rel. 0x%04x",
|
| PS ((short) addr + 2 + dst));
|
| -
|
| + if (extended_dst)
|
| + {
|
| + dst |= extended_dst << 16;
|
| + if (dst & 0x80000)
|
| + dst |= -1 << 20;
|
| + sprintf (op1, "0x%05x", dst & 0xfffff);
|
| + sprintf (comm1, "PC rel. 0x%05lx",
|
| + (long)((addr + 2 + dst) & 0xfffff));
|
| + }
|
| }
|
| else if (regd == 2)
|
| {
|
| @@ -356,19 +448,35 @@ msp430_doubleoperand (disassemble_info *info,
|
| cmd_len += 4;
|
| *cycles = 6;
|
| sprintf (op1, "&0x%04x", PS (dst));
|
| + if (extended_dst)
|
| + {
|
| + dst |= extended_dst << 16;
|
| + sprintf (op1, "&0x%05x", dst & 0xfffff);
|
| + }
|
| }
|
| else
|
| {
|
| /* Indexed. */
|
| dst = msp430dis_opcode (addr + 2, info);
|
| + if (extended_dst)
|
| + {
|
| + dst |= extended_dst << 16;
|
| + if (dst & 0x80000)
|
| + dst |= -1 << 20;
|
| + }
|
| + else if (dst & 0x8000)
|
| + dst |= -1 << 16;
|
| cmd_len += 4;
|
| *cycles = 6;
|
| sprintf (op1, "%d(r%d)", dst, regd);
|
| + if (dst > 9 || dst < -9)
|
| + sprintf (comm1, "#0x%05x", dst);
|
| }
|
| }
|
|
|
| *op2 = 0;
|
| *comm2 = 0;
|
| +
|
| return cmd_len;
|
| }
|
|
|
| @@ -386,7 +494,7 @@ msp430_doubleoperand (disassemble_info *info,
|
| *cycles = 1;
|
| if (regs == 3)
|
| {
|
| - /* Constsnts. */
|
| + /* Constants. */
|
| sprintf (op1, "#0");
|
| sprintf (comm1, "r3 As==00");
|
| }
|
| @@ -398,56 +506,31 @@ msp430_doubleoperand (disassemble_info *info,
|
| }
|
| else if (as == 2)
|
| {
|
| - *cycles = 1;
|
| -
|
| - if (regs == 2)
|
| - {
|
| - sprintf (op1, "#4");
|
| - sprintf (comm1, "r2 As==10");
|
| - }
|
| - else if (regs == 3)
|
| - {
|
| - sprintf (op1, "#2");
|
| - sprintf (comm1, "r3 As==10");
|
| - }
|
| - else
|
| - {
|
| - *cycles = 2;
|
| -
|
| - /* Indexed register mode @Rn. */
|
| - sprintf (op1, "@r%d", regs);
|
| - }
|
| - if (!regs)
|
| - *cycles = 3;
|
| + * cycles = print_as2_reg_name (regs, op1, comm1, 1, 1, regs == 0 ? 3 : 2);
|
| }
|
| else if (as == 3)
|
| {
|
| - if (regs == 2)
|
| - {
|
| - sprintf (op1, "#8");
|
| - sprintf (comm1, "r2 As==11");
|
| - *cycles = 1;
|
| - }
|
| - else if (regs == 3)
|
| - {
|
| - sprintf (op1, "#-1");
|
| - sprintf (comm1, "r3 As==11");
|
| - *cycles = 1;
|
| - }
|
| - else if (regs == 0)
|
| + if (regs == 0)
|
| {
|
| *cycles = 3;
|
| /* Absolute. @pc+. */
|
| dst = msp430dis_opcode (addr + 2, info);
|
| cmd_len += 2;
|
| sprintf (op1, "#%d", dst);
|
| - sprintf (comm1, "#0x%04x", PS (dst));
|
| + if (dst > 9 || dst < 0)
|
| + sprintf (comm1, "#0x%04x", PS (dst));
|
| + if (extended_src)
|
| + {
|
| + dst |= extended_src << 16;
|
| + if (dst & 0x80000)
|
| + dst |= -1 << 20;
|
| + sprintf (op1, "#%d", dst);
|
| + if (dst > 9 || dst < 0)
|
| + sprintf (comm1, "0x%05x", dst & 0xfffff);
|
| + }
|
| }
|
| else
|
| - {
|
| - *cycles = 2;
|
| - sprintf (op1, "@r%d+", regs);
|
| - }
|
| + * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
|
| }
|
| else if (as == 1)
|
| {
|
| @@ -460,6 +543,15 @@ msp430_doubleoperand (disassemble_info *info,
|
| sprintf (op1, "0x%04x", PS (dst));
|
| sprintf (comm1, "PC rel. 0x%04x",
|
| PS ((short) addr + 2 + dst));
|
| + if (extended_src)
|
| + {
|
| + dst |= extended_src << 16;
|
| + if (dst & 0x80000)
|
| + dst |= -1 << 20;
|
| + sprintf (op1, "0x%05x", dst & 0xfffff);
|
| + sprintf (comm1, "PC rel. 0x%05lx",
|
| + (long) ((addr + 2 + dst) & 0xfffff));
|
| + }
|
| }
|
| else if (regs == 2)
|
| {
|
| @@ -469,6 +561,12 @@ msp430_doubleoperand (disassemble_info *info,
|
| cmd_len += 2;
|
| sprintf (op1, "&0x%04x", PS (dst));
|
| sprintf (comm1, "0x%04x", PS (dst));
|
| + if (extended_src)
|
| + {
|
| + dst |= extended_src << 16;
|
| + sprintf (op1, "&0x%05x", dst & 0xfffff);
|
| + * comm1 = 0;
|
| + }
|
| }
|
| else if (regs == 3)
|
| {
|
| @@ -482,7 +580,17 @@ msp430_doubleoperand (disassemble_info *info,
|
| /* Indexed. */
|
| dst = msp430dis_opcode (addr + 2, info);
|
| cmd_len += 2;
|
| + if (extended_src)
|
| + {
|
| + dst |= extended_src << 16;
|
| + if (dst & 0x80000)
|
| + dst |= -1 << 20;
|
| + }
|
| + else if (dst & 0x8000)
|
| + dst |= -1 << 16;
|
| sprintf (op1, "%d(r%d)", dst, regs);
|
| + if (dst > 9 || dst < -9)
|
| + sprintf (comm1, "0x%05x", dst);
|
| }
|
| }
|
|
|
| @@ -517,6 +625,15 @@ msp430_doubleoperand (disassemble_info *info,
|
| sprintf (op2, "0x%04x", PS (dst));
|
| sprintf (comm2, "PC rel. 0x%04x",
|
| PS ((short) addr + cmd_len + dst));
|
| + if (extended_dst)
|
| + {
|
| + dst |= extended_dst << 16;
|
| + if (dst & 0x80000)
|
| + dst |= -1 << 20;
|
| + sprintf (op2, "0x%05x", dst & 0xfffff);
|
| + sprintf (comm2, "PC rel. 0x%05lx",
|
| + (long)((addr + cmd_len + dst) & 0xfffff));
|
| + }
|
| cmd_len += 2;
|
| }
|
| else if (regd == 2)
|
| @@ -525,11 +642,28 @@ msp430_doubleoperand (disassemble_info *info,
|
| dst = msp430dis_opcode (addr + cmd_len, info);
|
| cmd_len += 2;
|
| sprintf (op2, "&0x%04x", PS (dst));
|
| + if (extended_dst)
|
| + {
|
| + dst |= extended_dst << 16;
|
| + sprintf (op2, "&0x%05x", dst & 0xfffff);
|
| + }
|
| }
|
| else
|
| {
|
| dst = msp430dis_opcode (addr + cmd_len, info);
|
| cmd_len += 2;
|
| + if (dst & 0x8000)
|
| + dst |= -1 << 16;
|
| + if (dst > 9 || dst < 0)
|
| + sprintf (comm2, "0x%04x", PS (dst));
|
| + if (extended_dst)
|
| + {
|
| + dst |= extended_dst << 16;
|
| + if (dst & 0x80000)
|
| + dst |= -1 << 20;
|
| + if (dst > 9 || dst < 0)
|
| + sprintf (comm2, "0x%05x", dst & 0xfffff);
|
| + }
|
| sprintf (op2, "%d(r%d)", dst, regd);
|
| }
|
| }
|
| @@ -577,40 +711,11 @@ msp430_branchinstr (disassemble_info *info,
|
| }
|
| else if (as == 2)
|
| {
|
| - if (regs == 2)
|
| - {
|
| - *cycles = 2;
|
| - sprintf (op1, "#4");
|
| - sprintf (comm1, "r2 As==10");
|
| - }
|
| - else if (regs == 3)
|
| - {
|
| - *cycles = 1;
|
| - sprintf (op1, "#2");
|
| - sprintf (comm1, "r3 As==10");
|
| - }
|
| - else
|
| - {
|
| - /* Indexed register mode @Rn. */
|
| - *cycles = 2;
|
| - sprintf (op1, "@r%d", regs);
|
| - }
|
| + * cycles = print_as2_reg_name (regs, op1, comm1, 2, 1, 2);
|
| }
|
| else if (as == 3)
|
| {
|
| - if (regs == 2)
|
| - {
|
| - *cycles = 1;
|
| - sprintf (op1, "#8");
|
| - sprintf (comm1, "r2 As==11");
|
| - }
|
| - else if (regs == 3)
|
| - {
|
| - *cycles = 1;
|
| - sprintf (op1, "#-1");
|
| - sprintf (comm1, "r3 As==11");
|
| - }
|
| - else if (regs == 0)
|
| + if (regs == 0)
|
| {
|
| /* Absolute. @pc+ */
|
| *cycles = 3;
|
| @@ -619,10 +724,7 @@ msp430_branchinstr (disassemble_info *info,
|
| sprintf (op1, "#0x%04x", PS (dst));
|
| }
|
| else
|
| - {
|
| - *cycles = 2;
|
| - sprintf (op1, "@r%d+", regs);
|
| - }
|
| + * cycles = print_as3_reg_name (regs, op1, comm1, 1, 1, 2);
|
| }
|
| else if (as == 1)
|
| {
|
| @@ -653,9 +755,11 @@ msp430_branchinstr (disassemble_info *info,
|
| }
|
| else
|
| {
|
| - /* Indexd. */
|
| + /* Indexed. */
|
| dst = msp430dis_opcode (addr + 2, info);
|
| cmd_len += 2;
|
| + if (dst & 0x8000)
|
| + dst |= -1 << 16;
|
| sprintf (op1, "%d(r%d)", dst, regs);
|
| }
|
| }
|
| @@ -663,6 +767,82 @@ msp430_branchinstr (disassemble_info *info,
|
| 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;
|
| + short dst = 0;
|
| +
|
| + switch (am)
|
| + {
|
| + case 4: /* CALLA Rdst */
|
| + *cycles = 1;
|
| + sprintf (op1, "r%d", reg);
|
| + break;
|
| +
|
| + case 5: /* CALLA x(Rdst) */
|
| + *cycles = 3;
|
| + dst = msp430dis_opcode (addr + 2, info);
|
| + 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);
|
| + 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 */
|
| + udst = msp430dis_opcode (addr + 2, info);
|
| + cmd_len += 2;
|
| + *cycles = 4;
|
| + sprintf (op1, "&%d", (ureg << 16) + udst);
|
| + sprintf (comm1, "0x%05x", (ureg << 16) + udst);
|
| + break;
|
| +
|
| + case 9: /* CALLA pcrel-sym */
|
| + dst = msp430dis_opcode (addr + 2, info);
|
| + cmd_len += 2;
|
| + *cycles = 4;
|
| + sprintf (op1, "%d(PC)", (reg << 16) + dst);
|
| + sprintf (comm1, "PC rel. 0x%05lx",
|
| + (long) (addr + 2 + dst + (reg << 16)));
|
| + break;
|
| +
|
| + case 11: /* CALLA #imm20 */
|
| + udst = msp430dis_opcode (addr + 2, info);
|
| + cmd_len += 2;
|
| + *cycles = 4;
|
| + sprintf (op1, "#%d", (ureg << 16) + udst);
|
| + sprintf (comm1, "0x%05x", (ureg << 16) + udst);
|
| + break;
|
| +
|
| + default:
|
| + strcpy (comm1, _("unrecognised CALLA addressing mode"));
|
| + return -1;
|
| + }
|
| +
|
| + return cmd_len;
|
| +}
|
| +
|
| int
|
| print_insn_msp430 (bfd_vma addr, disassemble_info *info)
|
| {
|
| @@ -674,10 +854,14 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
|
| unsigned short insn;
|
| int cycles = 0;
|
| char *bc = "";
|
| - char dinfo[32]; /* Debug purposes. */
|
| + unsigned short extension_word = 0;
|
|
|
| insn = msp430dis_opcode (addr, info);
|
| - sprintf (dinfo, "0x%04x", insn);
|
| + if (insn == (unsigned short) -1)
|
| + {
|
| + prin (stream, ".word 0xffff; ????");
|
| + return 2;
|
| + }
|
|
|
| if (((int) addr & 0xffff) > 0xffdf)
|
| {
|
| @@ -688,6 +872,20 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
|
| *comm1 = 0;
|
| *comm2 = 0;
|
|
|
| + /* Check for an extension word. */
|
| + if ((insn & 0xf800) == 0x1800)
|
| + {
|
| + extension_word = insn;
|
| + addr += 2;
|
| + insn = msp430dis_opcode (addr, info);
|
| + if (insn == (unsigned short) -1)
|
| + {
|
| + prin (stream, ".word 0x%04x, 0xffff; ????",
|
| + extension_word);
|
| + return 4;
|
| + }
|
| + }
|
| +
|
| for (opcode = msp430_opcodes; opcode->name; opcode++)
|
| {
|
| if ((insn & opcode->bin_mask) == opcode->bin_opcode
|
| @@ -699,10 +897,11 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
|
| *comm2 = 0;
|
|
|
| /* r0 as destination. Ad should be zero. */
|
| - if (opcode->insn_opnumb == 3 && (insn & 0x000f) == 0
|
| - && (0x0080 & insn) == 0)
|
| + if (opcode->insn_opnumb == 3
|
| + && (insn & 0x000f) == 0
|
| + && (insn & 0x0080) == 0)
|
| {
|
| - cmd_len =
|
| + cmd_len +=
|
| msp430_branchinstr (info, opcode, addr, insn, op1, comm1,
|
| &cycles);
|
| if (cmd_len)
|
| @@ -711,22 +910,244 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
|
|
|
| switch (opcode->insn_opnumb)
|
| {
|
| + int n;
|
| + int reg;
|
| +
|
| + case 4:
|
| + cmd_len += msp430x_calla_instr (info, addr, insn,
|
| + op1, comm1, & cycles);
|
| + 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;
|
| + n |= msp430dis_opcode (addr + 2, info);
|
| + sprintf (op1, "#%d", n);
|
| + if (n > 9 || n < 0)
|
| + sprintf (comm1, "0x%05x", n);
|
| + 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;
|
| + n |= msp430dis_opcode (addr + 2, info);
|
| + 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);
|
| + break;
|
| +
|
| + case 3: /* MOVA x(Rsrc), Rdst */
|
| + cmd_len = 4;
|
| + if (strcmp (opcode->name, "bra") != 0)
|
| + sprintf (op2, "r%d", reg);
|
| + reg = n;
|
| + n = msp430dis_opcode (addr + 2, info);
|
| + if (n & 0x8000)
|
| + n |= -1 << 16;
|
| + 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);
|
| + }
|
| + break;
|
| +
|
| + case 6: /* MOVA Rsrc, &abs20 */
|
| + cmd_len = 4;
|
| + reg <<= 16;
|
| + reg |= msp430dis_opcode (addr + 2, info);
|
| + sprintf (op1, "r%d", n);
|
| + sprintf (op2, "&%d", reg);
|
| + if (reg > 9 || reg < 0)
|
| + sprintf (comm2, "0x%05x", reg);
|
| + break;
|
| +
|
| + case 7: /* MOVA Rsrc, x(Rdst) */
|
| + cmd_len = 4;
|
| + sprintf (op1, "r%d", n);
|
| + n = msp430dis_opcode (addr + 2, info);
|
| + if (n & 0x8000)
|
| + n |= -1 << 16;
|
| + 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);
|
| + }
|
| + break;
|
| +
|
| + case 8: /* MOVA #imm20, Rdst */
|
| + cmd_len = 4;
|
| + n <<= 16;
|
| + n |= msp430dis_opcode (addr + 2, info);
|
| + if (n & 0x80000)
|
| + n |= -1 << 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);
|
| + 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)
|
| + {
|
| case 0:
|
| - cmd_len = msp430_nooperands (opcode, addr, insn, comm1, &cycles);
|
| + cmd_len += msp430_nooperands (opcode, addr, insn, comm1, &cycles);
|
| break;
|
| case 2:
|
| - cmd_len =
|
| + cmd_len +=
|
| msp430_doubleoperand (info, opcode, addr, insn, op1, op2,
|
| - comm1, comm2, &cycles);
|
| + comm1, comm2,
|
| + extension_word,
|
| + &cycles);
|
| if (insn & BYTE_OPERATION)
|
| - bc = ".b";
|
| + {
|
| + 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, _("Reserved use of A/L and B/W bits detected"));
|
| + }
|
| + }
|
| +
|
| break;
|
| case 1:
|
| - cmd_len =
|
| + cmd_len +=
|
| msp430_singleoperand (info, opcode, addr, insn, op1, comm1,
|
| + extension_word,
|
| &cycles);
|
| - if (insn & BYTE_OPERATION && opcode->fmt != 3)
|
| - bc = ".b";
|
| + if (extension_word
|
| + && (strcmp (opcode->name, "swpb") == 0
|
| + || strcmp (opcode->name, "sxt") == 0))
|
| + {
|
| + if (insn & BYTE_OPERATION)
|
| + {
|
| + bc = ".?";
|
| + sprintf (comm2, _("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, _("Reserved use of A/L and B/W bits detected"));
|
| + }
|
| + }
|
| break;
|
| default:
|
| break;
|
| @@ -737,16 +1158,33 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
|
| break;
|
| }
|
|
|
| - dinfo[5] = 0;
|
| -
|
| 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;
|
| }
|
|
|
| - (*prin) (stream, "%s%s", opcode->name, bc);
|
| + /* 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);
|
| + }
|
| +
|
| + 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);
|
| @@ -783,5 +1221,9 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info)
|
| (*prin) (stream, ",");
|
| if (*comm2)
|
| (*prin) (stream, " %s", comm2);
|
| +
|
| + if (extension_word)
|
| + cmd_len += 2;
|
| +
|
| return cmd_len;
|
| }
|
|
|