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; |
} |