diff options
Diffstat (limited to 'gas')
-rw-r--r-- | gas/ChangeLog | 6 | ||||
-rw-r--r-- | gas/config/tc-msp430.c | 154 | ||||
-rw-r--r-- | gas/testsuite/ChangeLog | 10 | ||||
-rw-r--r-- | gas/testsuite/gas/msp430/bad.d | 3 | ||||
-rw-r--r-- | gas/testsuite/gas/msp430/bad.l | 7 | ||||
-rw-r--r-- | gas/testsuite/gas/msp430/bad.s | 13 | ||||
-rw-r--r-- | gas/testsuite/gas/msp430/msp430.exp | 1 | ||||
-rw-r--r-- | gas/testsuite/gas/msp430/msp430x.d | 11 | ||||
-rw-r--r-- | gas/testsuite/gas/msp430/msp430x.s | 16 |
9 files changed, 175 insertions, 46 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index 55bdf9e..d019f3a 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,9 @@ +2013-10-08 Nick Clifton <nickc@redhat.com> + + * config/tc-msp430.c (msp430_operands): Accept "<foo>.a" as an alias + for "<foo>a". Issue error messages for unrecognised or corrrupt + size extensions. + 2013-10-04 Kyrylo Tkachov <kyrylo.tkachov@arm.com> * config/tc-arm.c (do_t_mvn_tst): Use narrow form for tst when diff --git a/gas/config/tc-msp430.c b/gas/config/tc-msp430.c index 4f34a37..67aac43 100644 --- a/gas/config/tc-msp430.c +++ b/gas/config/tc-msp430.c @@ -485,6 +485,10 @@ static struct mcu_type_s mcu_types[] = {"msp430p337", MSP_ISA_430}, {"msp430tch5e", MSP_ISA_430}, + /* NB/ This section of the list should be kept in sync with the ones in: + gcc/config/msp430/t-msp430 + gcc/config/msp430/msp430.c */ + {"msp430cg4616", MSP_ISA_430X}, {"msp430cg4617", MSP_ISA_430X}, {"msp430cg4618", MSP_ISA_430X}, @@ -712,7 +716,7 @@ static struct mcu_type_s mcu_types[] = {"msp430", MSP_ISA_430}, {"msp430X", MSP_ISA_430X}, {"msp430Xv2", MSP_ISA_430Xv2}, - + {NULL, 0} }; @@ -1196,7 +1200,7 @@ md_parse_option (int c, char * arg) as_fatal (_("unrecognised argument to -mcpu option '%s'"), arg); return 1; - + case OPTION_RELAX: msp430_enable_relax = 1; return 1; @@ -2137,27 +2141,85 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) or .b @r2+, 5(R1). */ - /* Check if byte or word operation. */ - if (*line == '.' && TOLOWER (*(line + 1)) == 'b') + byte_op = 0; + addr_op = FALSE; + if (*line == '.') { - bin |= BYTE_OPERATION; - byte_op = 1; + bfd_boolean check = FALSE; + ++ line; + + switch (TOLOWER (* line)) + { + case 'b': + /* Byte operation. */ + bin |= BYTE_OPERATION; + byte_op = 1; + check = TRUE; + break; + + case 'a': + /* "Address" ops work on 20-bit values. */ + addr_op = TRUE; + bin |= BYTE_OPERATION; + check = TRUE; + break; + + case 'w': + /* Word operation - this is the default. */ + check = TRUE; + break; + + case 0: + case ' ': + case '\n': + case '\r': + as_warn (_("no size modifier after period, .w assumed")); + break; + + default: + as_bad (_("unrecognised instruction size modifier .%c"), + * line); + return 0; + } + + if (check) + { + ++ line; + + } } - else - byte_op = 0; - /* "Address" ops work on 20-bit values. */ - if (*line == '.' && TOLOWER (*(line + 1)) == 'a') + if (*line && ! ISSPACE (*line)) { - addr_op = TRUE; - bin |= BYTE_OPERATION; + as_bad (_("junk found after instruction: %s.%s"), + opcode->name, line); + return 0; } - else - addr_op = FALSE; - /* skip .[aAbwBW]. */ - while (! ISSPACE (*line) && *line) - line++; + /* Catch the case where the programmer has used a ".a" size modifier on an + instruction that does not support it. Look for an alternative extended + instruction that has the same name without the period. Eg: "add.a" + becomes "adda". Although this not an officially supported way of + specifing instruction aliases other MSP430 assemblers allow it. So we + support it for compatibility purposes. */ + if (addr_op && opcode->fmt >= 0) + { + char * old_name = opcode->name; + char real_name[32]; + + sprintf (real_name, "%sa", old_name); + opcode = hash_find (msp430_hash, real_name); + if (opcode == NULL) + { + as_bad (_("instruction %s.a does not exist"), old_name); + return 0; + } +#if 0 /* Enable for debugging. */ + as_warn ("treating %s.a as %s", old_name, real_name); +#endif + addr_op = FALSE; + bin = opcode->bin_opcode; + } if (opcode->fmt != -1 && opcode->insn_opnumb @@ -2252,7 +2314,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) insn_length = (extended_op ? 2 : 0) + 2 + (op1.ol * 2); frag = frag_more (insn_length); where = frag - frag_now->fr_literal; - + if (extended_op) { if (!addr_op) @@ -2263,7 +2325,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) as_bad (_("repeat instruction used with non-register mode instruction")); extended &= ~ 0xf; } - + if (op1.mode == OP_EXP) { if (op1.exp.X_op == O_constant) @@ -2276,7 +2338,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) fix_new_exp (frag_now, where, 6, &(op1.exp), FALSE, BFD_RELOC_MSP430X_PCR20_EXT_SRC); } - + /* Emit the extension word. */ bfd_putl16 (extended, frag); frag += 2; @@ -2344,7 +2406,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) if (target_is_430xv2 () && op1.mode == OP_REG - && op1.reg == 0 + && op1.reg == 0 && (is_opcode ("rlax") || is_opcode ("rlcx") || is_opcode ("rla") @@ -2353,7 +2415,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) as_bad (_("%s: attempt to rotate the PC register"), opcode->name); return 0; } - + if (extended_op) { if (!addr_op) @@ -2364,7 +2426,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) as_bad (_("repeat instruction used with non-register mode instruction")); extended &= ~ 0xf; } - + if (op1.mode == OP_EXP) { if (op1.exp.X_op == O_constant) @@ -2483,7 +2545,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) else { where += 2; - + bfd_putl16 ((bfd_vma) ZEROS, frag + 2); if (op1.reg || (op1.reg == 0 && op1.am == 3)) @@ -2554,7 +2616,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) bin |= 0x60 | op1.reg; else if (op1.am == 3) bin |= 0x70 | op1.reg; - + bfd_putl16 ((bfd_vma) bin, frag); if (op1.mode == OP_EXP) @@ -2756,7 +2818,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) where = frag - frag_now->fr_literal; bfd_putl16 ((bfd_vma) bin, frag); dwarf2_emit_insn (op_length); - } + } break; } @@ -2835,7 +2897,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) dwarf2_emit_insn (op_length); break; } - + case 9: /* MOVA, BRA, RETA. */ imm_op = 0; bin = opcode->bin_opcode; @@ -2871,7 +2933,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) res += msp430_dstoperand (&op2, l2, opcode->bin_opcode, extended_op, TRUE); } - + if (res) break; /* Error occurred. All warnings were done before. */ } @@ -2967,7 +3029,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) frag = frag_more (insn_length); where = frag - frag_now->fr_literal; - + if (extended_op) { if (!addr_op) @@ -2992,7 +3054,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) fix_new_exp (frag_now, where, 6, &(op1.exp), FALSE, BFD_RELOC_MSP430X_PCR20_EXT_SRC); } - + if (op2.mode == OP_EXP) { if (op2.exp.X_op == O_constant) @@ -3002,7 +3064,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) fix_new_exp (frag_now, where, 8, &(op2.exp), FALSE, op2.reg ? BFD_RELOC_MSP430X_ABS20_EXT_ODST : BFD_RELOC_MSP430X_PCR20_EXT_ODST); - + else fix_new_exp (frag_now, where, 6, &(op2.exp), FALSE, op2.reg ? BFD_RELOC_MSP430X_ABS20_EXT_DST @@ -3104,7 +3166,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) if (target_is_430xv2 () && op1.mode == OP_REG - && op1.reg == 0 + && op1.reg == 0 && (is_opcode ("rrax") || is_opcode ("rrcx") || is_opcode ("rra") @@ -3113,11 +3175,11 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) as_bad (_("%s: attempt to rotate the PC register"), opcode->name); return 0; } - + insn_length = (extended_op ? 2 : 0) + 2 + (op1.ol * 2); frag = frag_more (insn_length); where = frag - frag_now->fr_literal; - + if (extended_op) { if (is_opcode ("swpbx") || is_opcode ("sxtx")) @@ -3148,7 +3210,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) { if (op1.exp.X_op == O_constant) extended |= ((op1.exp.X_add_number >> 16) & 0xf) << 7; - + else if (op1.reg || (op1.reg == 0 && op1.am == 3)) /* Not PC relative. */ fix_new_exp (frag_now, where, 6, &(op1.exp), FALSE, BFD_RELOC_MSP430X_ABS20_EXT_SRC); @@ -3156,7 +3218,7 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) fix_new_exp (frag_now, where, 6, &(op1.exp), FALSE, BFD_RELOC_MSP430X_PCR20_EXT_SRC); } - + /* Emit the extension word. */ bfd_putl16 (extended, frag); frag += 2; @@ -3519,12 +3581,12 @@ md_apply_fix (fixS * fixp, valueT * valuep, segT seg) fixp->fx_no_overflow = 1; - /* If polymorphs are enabled and relax disabled. + /* If polymorphs are enabled and relax disabled. do not kill any relocs and pass them to linker. */ - if (msp430_enable_polys + if (msp430_enable_polys && !msp430_enable_relax) { - if (!fixp->fx_addsy || (fixp->fx_addsy + if (!fixp->fx_addsy || (fixp->fx_addsy && S_GET_SEGMENT (fixp->fx_addsy) == absolute_section)) fixp->fx_done = 1; /* It is ok to kill 'abs' reloc. */ else @@ -3593,13 +3655,13 @@ md_apply_fix (fixS * fixp, valueT * valuep, segT seg) case BFD_RELOC_MSP430X_ABS20_EXT_SRC: case BFD_RELOC_MSP430X_PCR20_EXT_SRC: bfd_putl16 ((bfd_vma) (value & 0xffff), where + 4); - value >>= 16; + value >>= 16; bfd_putl16 ((bfd_vma) (((value & 0xf) << 7) | insn), where); break; case BFD_RELOC_MSP430X_ABS20_ADR_SRC: bfd_putl16 ((bfd_vma) (value & 0xffff), where + 2); - value >>= 16; + value >>= 16; bfd_putl16 ((bfd_vma) (((value & 0xf) << 8) | insn), where); break; @@ -3633,7 +3695,7 @@ md_apply_fix (fixS * fixp, valueT * valuep, segT seg) value >>= 16; bfd_putl16 ((bfd_vma) ((value & 0xf) | insn), where); break; - + default: as_fatal (_("line %d: unknown relocation type: 0x%x"), fixp->fx_line, fixp->fx_r_type); @@ -3656,7 +3718,7 @@ S_IS_GAS_LOCAL (symbolS * s) return FALSE; name = S_GET_NAME (s); len = strlen (name) - 1; - + return name[len] == 1 || name[len] == 2; } @@ -3745,7 +3807,7 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp) *reloc2->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_subsy); } - reloc->addend = fixp->fx_offset; + reloc->addend = fixp->fx_offset; if (asec == absolute_section) { reloc->addend += S_GET_VALUE (fixp->fx_addsy); @@ -4045,7 +4107,7 @@ msp430_relax_frag (segT seg ATTRIBUTE_UNUSED, fragS * fragP, by setting 'aim' to quite high value. */ aim = 0x7fff; } - + this_state = fragP->fr_subtype; start_type = this_type = table + this_state; @@ -4095,7 +4157,7 @@ msp430_fix_adjustable (struct fix *fixp ATTRIBUTE_UNUSED) if (fixp->fx_addsy && ((S_GET_SEGMENT (fixp->fx_addsy)->flags & SEC_CODE) == 0)) return TRUE; - + return FALSE; } diff --git a/gas/testsuite/ChangeLog b/gas/testsuite/ChangeLog index e98e3d5..63f2c17 100644 --- a/gas/testsuite/ChangeLog +++ b/gas/testsuite/ChangeLog @@ -1,3 +1,13 @@ +2013-10-08 Nick Clifton <nickc@redhat.com> + + * gas/msp430/bad.s: New test: Checks erroneous size extensions. + * gas/msp430/bad.d: New test command file. + * gas/msp430/bad.l: New file: Expected error messages. + * gas/msp430/msp430.exp: Run the new test. + * gas/msp430/msp430x.s: Add "<foo>.a" aliases of "<foo>a" + instructions. + * gas/msp430/msp430x.d: Update expected disassembly. + 2013-10-07 Chao-ying Fu <Chao-ying.Fu@imgtec.com> * gas/mips/micromips@virt64.d: Fix dmfgc0 and dmtgc0. diff --git a/gas/testsuite/gas/msp430/bad.d b/gas/testsuite/gas/msp430/bad.d new file mode 100644 index 0000000..9302cee --- /dev/null +++ b/gas/testsuite/gas/msp430/bad.d @@ -0,0 +1,3 @@ +#name: Diagnostics Quality +#source: bad.s +#error-output: bad.l diff --git a/gas/testsuite/gas/msp430/bad.l b/gas/testsuite/gas/msp430/bad.l new file mode 100644 index 0000000..218dcd0 --- /dev/null +++ b/gas/testsuite/gas/msp430/bad.l @@ -0,0 +1,7 @@ +[^:]*: Assembler messages: +[^:]*:6: Error: unrecognised instruction size modifier .z +[^:]*:7: Error: junk found after instruction: mov.bc r1,r2 +[^:]*:8: Error: junk found after instruction: mov.cd r1,r2 +[^:]*:9: Error: junk found after instruction: mov.cd r1,r2 +[^:]*:10: Warning: no size modifier after period, .w assumed +[^:]*:11: Error: instruction bis.a does not exist diff --git a/gas/testsuite/gas/msp430/bad.s b/gas/testsuite/gas/msp430/bad.s new file mode 100644 index 0000000..2af83b7 --- /dev/null +++ b/gas/testsuite/gas/msp430/bad.s @@ -0,0 +1,13 @@ + .text + .cpu 430x + +;;; Test for the assembler detecting spurious size modifiers. + + mov.z r1, r2 + mov.abc r1, r2 + mov.bcd r1, r2 + mov.wcd r1, r2 + mov. r1, r2 + bis.a #8, r2 + +;;; FIXME: Add more tests of assembler error detection here. diff --git a/gas/testsuite/gas/msp430/msp430.exp b/gas/testsuite/gas/msp430/msp430.exp index 656ace8..0b5a3ae 100644 --- a/gas/testsuite/gas/msp430/msp430.exp +++ b/gas/testsuite/gas/msp430/msp430.exp @@ -21,4 +21,5 @@ if [expr [istarget "msp430-*-*"]] then { run_dump_test "opcode" run_dump_test "msp430x" + run_dump_test "bad" } diff --git a/gas/testsuite/gas/msp430/msp430x.d b/gas/testsuite/gas/msp430/msp430x.d index 13fdb0b..e080854 100644 --- a/gas/testsuite/gas/msp430/msp430x.d +++ b/gas/testsuite/gas/msp430/msp430x.d @@ -214,3 +214,14 @@ Disassembly of section .text: 0+03c8 <[^>]*> 40 18 82 11 sxtx.w r2 ; 0+03cc <[^>]*> 04 18 45 11 rpt #5 \{ rrax.a r5 ; 0+03d0 <[^>]*> 85 18 45 11 rpt r5 \{ rrax.a r5 ; +0+03d4 <[^>]*> e2 01 adda r1, r2 ; +0+03d6 <[^>]*> c0 01 mova r1, r0 ; +0+03d8 <[^>]*> 41 13 calla r1 ; +0+03da <[^>]*> 40 18 01 43 clrx.w r1 ; +0+03de <[^>]*> d2 01 cmpa r1, r2 ; +0+03e0 <[^>]*> 40 18 21 83 decdx.w r1 ; +0+03e4 <[^>]*> 40 18 21 53 incdx.w r1 ; +0+03e8 <[^>]*> c2 01 mova r1, r2 ; +0+03ea <[^>]*> 10 01 reta ; +0+03ec <[^>]*> f2 01 suba r1, r2 ; +0+03ee <[^>]*> 40 18 80 93 00 00 cmpx.w #0, 0x0000 ;r3 As==00, PC rel. 0x03f2 diff --git a/gas/testsuite/gas/msp430/msp430x.s b/gas/testsuite/gas/msp430/msp430x.s index db27597..d968fae 100644 --- a/gas/testsuite/gas/msp430/msp430x.s +++ b/gas/testsuite/gas/msp430/msp430x.s @@ -259,3 +259,19 @@ foo: rrax.a r5 rpt r5 rrax.a r5 + + ;; The following are all aliases for similarly named instructions + ;; without the period. Eg: add.a -> adda + add.a r1, r2 + br.a r1 + call.a r1 + clr.a r1 + cmp.a r1, r2 + decd.a r1 + incd.a r1 + mov.a r1, r2 + ret.a + sub.a r1, r2 + tst.a fooz + + |