/* tc-msp430.c -- Assembler code for the Texas Instruments MSP430
- Copyright (C) 2002-2013 Free Software Foundation, Inc.
+ Copyright (C) 2002-2014 Free Software Foundation, Inc.
Contributed by Dmitry Diky <diwil@mail.ru>
This file is part of GAS, the GNU Assembler.
#define MAX_OP_LEN 256
-struct mcu_type_s
+typedef enum msp_isa
{
- char * name;
- int isa;
- int mach;
-};
+ MSP_ISA_430,
+ MSP_ISA_430X,
+ MSP_ISA_430Xv2
+} msp_isa;
+
+static enum msp_isa selected_isa = MSP_ISA_430Xv2;
+
+static inline bfd_boolean
+target_is_430x (void)
+{
+ return selected_isa >= MSP_ISA_430X;
+}
+
+static inline bfd_boolean
+target_is_430xv2 (void)
+{
+ return selected_isa == MSP_ISA_430Xv2;
+}
-#define MSP430_ISA_11 11
-#define MSP430_ISA_110 110
-#define MSP430_ISA_12 12
-#define MSP430_ISA_13 13
-#define MSP430_ISA_14 14
-#define MSP430_ISA_15 15
-#define MSP430_ISA_16 16
-#define MSP430_ISA_20 20
-#define MSP430_ISA_21 21
-#define MSP430_ISA_22 22
-#define MSP430_ISA_23 23
-#define MSP430_ISA_24 24
-#define MSP430_ISA_26 26
-#define MSP430_ISA_31 31
-#define MSP430_ISA_32 32
-#define MSP430_ISA_33 33
-#define MSP430_ISA_41 41
-#define MSP430_ISA_42 42
-#define MSP430_ISA_43 43
-#define MSP430_ISA_44 44
-#define MSP430X_ISA 45
-#define MSP430_ISA_46 46
-#define MSP430_ISA_47 47
-#define MSP430_ISA_54 54
-
-/* Generate a 16-bit relocation.
- For the 430X we generate a relocation without linkwer range checking
- if the value is being used in an extended (ie 20-bit) instruction.
+/* Generate an absolute 16-bit relocation.
+ For the 430X we generate a relocation without linker range checking
+ if the value is being used in an extended (ie 20-bit) instruction,
+ otherwise if have a shifted expression we use a HI reloc.
For the 430 we generate a relocation without assembler range checking
- if we are handling an immediate value or a byte-width instruction. */
+ if we are handling an immediate value or a byte-width instruction. */
+
#undef CHECK_RELOC_MSP430
-#define CHECK_RELOC_MSP430 \
- (msp430_mcu->isa == MSP430X_ISA \
- ? (extended_op ? BFD_RELOC_16 : BFD_RELOC_MSP430X_ABS16) \
- : ((imm_op || byte_op) \
+#define CHECK_RELOC_MSP430(OP) \
+ (target_is_430x () \
+ ? (extended_op \
+ ? BFD_RELOC_16 \
+ : ((OP).vshift == 1) \
+ ? BFD_RELOC_MSP430_ABS_HI16 \
+ : BFD_RELOC_MSP430X_ABS16) \
+ : ((imm_op || byte_op) \
? BFD_RELOC_MSP430_16_BYTE : BFD_RELOC_MSP430_16))
/* Generate a 16-bit pc-relative relocation.
if we are handling an immediate value or a byte-width instruction. */
#undef CHECK_RELOC_MSP430_PCREL
#define CHECK_RELOC_MSP430_PCREL \
- (msp430_mcu->isa == MSP430X_ISA \
+ (target_is_430x () \
? BFD_RELOC_MSP430X_PCR16 \
: (imm_op || byte_op) \
? BFD_RELOC_MSP430_16_PCREL_BYTE : BFD_RELOC_MSP430_16_PCREL)
-static struct mcu_type_s mcu_types[] =
-{
- {"msp1", MSP430_ISA_11, bfd_mach_msp11},
- {"msp2", MSP430_ISA_14, bfd_mach_msp14},
- {"msp3", MSP430_ISA_20, bfd_mach_msp20},
- {"msp4", MSP430_ISA_24, bfd_mach_msp24},
- {"msp5", MSP430_ISA_31, bfd_mach_msp31},
- {"msp6", MSP430_ISA_42, bfd_mach_msp42},
-
- {"msp430x110", MSP430_ISA_11, bfd_mach_msp11},
- {"msp430x112", MSP430_ISA_11, bfd_mach_msp11},
- {"msp430x1101", MSP430_ISA_110, bfd_mach_msp110},
- {"msp430x1111", MSP430_ISA_110, bfd_mach_msp110},
- {"msp430x1121", MSP430_ISA_110, bfd_mach_msp110},
- {"msp430x1122", MSP430_ISA_11, bfd_mach_msp110},
- {"msp430x1132", MSP430_ISA_11, bfd_mach_msp110},
-
- {"msp430x122", MSP430_ISA_12, bfd_mach_msp12},
- {"msp430x123", MSP430_ISA_12, bfd_mach_msp12},
- {"msp430x1222", MSP430_ISA_12, bfd_mach_msp12},
- {"msp430x1232", MSP430_ISA_12, bfd_mach_msp12},
-
- {"msp430x133", MSP430_ISA_13, bfd_mach_msp13},
- {"msp430x135", MSP430_ISA_13, bfd_mach_msp13},
- {"msp430x1331", MSP430_ISA_13, bfd_mach_msp13},
- {"msp430x1351", MSP430_ISA_13, bfd_mach_msp13},
- {"msp430x147", MSP430_ISA_14, bfd_mach_msp14},
- {"msp430x148", MSP430_ISA_14, bfd_mach_msp14},
- {"msp430x149", MSP430_ISA_14, bfd_mach_msp14},
- {"msp430x1471", MSP430_ISA_14, bfd_mach_msp14},
- {"msp430x1481", MSP430_ISA_14, bfd_mach_msp14},
- {"msp430x1491", MSP430_ISA_14, bfd_mach_msp14},
-
- {"msp430x155", MSP430_ISA_15, bfd_mach_msp15},
- {"msp430x156", MSP430_ISA_15, bfd_mach_msp15},
- {"msp430x157", MSP430_ISA_15, bfd_mach_msp15},
- {"msp430x167", MSP430_ISA_16, bfd_mach_msp16},
- {"msp430x168", MSP430_ISA_16, bfd_mach_msp16},
- {"msp430x169", MSP430_ISA_16, bfd_mach_msp16},
- {"msp430x1610", MSP430_ISA_16, bfd_mach_msp16},
- {"msp430x1611", MSP430_ISA_16, bfd_mach_msp16},
- {"msp430x1612", MSP430_ISA_16, bfd_mach_msp16},
-
- {"msp430x2001", MSP430_ISA_20, bfd_mach_msp20},
- {"msp430x2011", MSP430_ISA_20, bfd_mach_msp20},
- {"msp430x2002", MSP430_ISA_20, bfd_mach_msp20},
- {"msp430x2012", MSP430_ISA_20, bfd_mach_msp20},
- {"msp430x2003", MSP430_ISA_20, bfd_mach_msp20},
- {"msp430x2013", MSP430_ISA_20, bfd_mach_msp20 },
-
- {"msp430x2101", MSP430_ISA_21, bfd_mach_msp21},
- {"msp430x2111", MSP430_ISA_21, bfd_mach_msp21},
- {"msp430x2112", MSP430_ISA_21, bfd_mach_msp21},
- {"msp430x2121", MSP430_ISA_21, bfd_mach_msp21},
- {"msp430x2131", MSP430_ISA_21, bfd_mach_msp21},
- {"msp430x2132", MSP430_ISA_21, bfd_mach_msp21},
-
- {"msp430x2232", MSP430_ISA_22, bfd_mach_msp22},
- {"msp430x2234", MSP430_ISA_22, bfd_mach_msp22},
- {"msp430x2252", MSP430_ISA_22, bfd_mach_msp22},
- {"msp430x2254", MSP430_ISA_22, bfd_mach_msp22},
- {"msp430x2272", MSP430_ISA_22, bfd_mach_msp22},
- {"msp430x2274", MSP430_ISA_22, bfd_mach_msp22},
-
- {"msp430x233", MSP430_ISA_23, bfd_mach_msp23},
- {"msp430x235", MSP430_ISA_23, bfd_mach_msp23},
- {"msp430x2330", MSP430_ISA_23, bfd_mach_msp23},
- {"msp430x2350", MSP430_ISA_23, bfd_mach_msp23},
- {"msp430x2370", MSP430_ISA_23, bfd_mach_msp23},
-
- {"msp430x247", MSP430_ISA_24, bfd_mach_msp24},
- {"msp430x2471", MSP430_ISA_24, bfd_mach_msp24},
- {"msp430x248", MSP430_ISA_24, bfd_mach_msp24},
- {"msp430x2481", MSP430_ISA_24, bfd_mach_msp24},
- {"msp430x249", MSP430_ISA_24, bfd_mach_msp24},
- {"msp430x2491", MSP430_ISA_24, bfd_mach_msp24},
- {"msp430x2410", MSP430_ISA_24, bfd_mach_msp24},
- {"msp430x2416", MSP430_ISA_24, bfd_mach_msp24},
- {"msp430x2417", MSP430_ISA_24, bfd_mach_msp24},
- {"msp430x2418", MSP430_ISA_24, bfd_mach_msp24},
- {"msp430x2419", MSP430_ISA_24, bfd_mach_msp24},
-
- {"msp430x2616", MSP430_ISA_26, bfd_mach_msp26},
- {"msp430x2617", MSP430_ISA_26, bfd_mach_msp26},
- {"msp430x2618", MSP430_ISA_26, bfd_mach_msp26},
- {"msp430x2619", MSP430_ISA_26, bfd_mach_msp26},
-
- {"msp430x311", MSP430_ISA_31, bfd_mach_msp31},
- {"msp430x312", MSP430_ISA_31, bfd_mach_msp31},
- {"msp430x313", MSP430_ISA_31, bfd_mach_msp31},
- {"msp430x314", MSP430_ISA_31, bfd_mach_msp31},
- {"msp430x315", MSP430_ISA_31, bfd_mach_msp31},
- {"msp430x323", MSP430_ISA_32, bfd_mach_msp32},
- {"msp430x325", MSP430_ISA_32, bfd_mach_msp32},
- {"msp430x336", MSP430_ISA_33, bfd_mach_msp33},
- {"msp430x337", MSP430_ISA_33, bfd_mach_msp33},
-
- {"msp430x412", MSP430_ISA_41, bfd_mach_msp41},
- {"msp430x413", MSP430_ISA_41, bfd_mach_msp41},
- {"msp430x415", MSP430_ISA_41, bfd_mach_msp41},
- {"msp430x417", MSP430_ISA_41, bfd_mach_msp41},
-
- {"msp430x423", MSP430_ISA_42, bfd_mach_msp42},
- {"msp430x425", MSP430_ISA_42, bfd_mach_msp42},
- {"msp430x427", MSP430_ISA_42, bfd_mach_msp42},
- {"msp430x4250", MSP430_ISA_42, bfd_mach_msp42},
- {"msp430x4260", MSP430_ISA_42, bfd_mach_msp42},
- {"msp430x4270", MSP430_ISA_42, bfd_mach_msp42},
- {"msp430xG4250",MSP430_ISA_42, bfd_mach_msp42},
- {"msp430xG4260",MSP430_ISA_42, bfd_mach_msp42},
- {"msp430xG4270",MSP430_ISA_42, bfd_mach_msp42},
-
- {"msp430xE423", MSP430_ISA_42, bfd_mach_msp42},
- {"msp430xE4232",MSP430_ISA_42, bfd_mach_msp42},
- {"msp430xE4242",MSP430_ISA_42, bfd_mach_msp42},
- {"msp430xE4252",MSP430_ISA_42, bfd_mach_msp42},
- {"msp430xE425", MSP430_ISA_42, bfd_mach_msp42},
- {"msp430xE427", MSP430_ISA_42, bfd_mach_msp42},
- {"msp430xE4272",MSP430_ISA_42, bfd_mach_msp42},
-
- {"msp430xW423", MSP430_ISA_42, bfd_mach_msp42},
- {"msp430xW425", MSP430_ISA_42, bfd_mach_msp42},
- {"msp430xW427", MSP430_ISA_42, bfd_mach_msp42},
-
- {"msp430xG437", MSP430_ISA_43, bfd_mach_msp43},
- {"msp430xG438", MSP430_ISA_43, bfd_mach_msp43},
- {"msp430xG439", MSP430_ISA_43, bfd_mach_msp43},
-
- {"msp430x435", MSP430_ISA_43, bfd_mach_msp43},
- {"msp430x4351", MSP430_ISA_43, bfd_mach_msp43},
- {"msp430x436", MSP430_ISA_43, bfd_mach_msp43},
- {"msp430x4361", MSP430_ISA_43, bfd_mach_msp43},
- {"msp430x437", MSP430_ISA_43, bfd_mach_msp43},
- {"msp430x4371", MSP430_ISA_43, bfd_mach_msp43},
-
- {"msp430x447", MSP430_ISA_44, bfd_mach_msp44},
- {"msp430x448", MSP430_ISA_44, bfd_mach_msp44},
- {"msp430x449", MSP430_ISA_44, bfd_mach_msp44},
-
- {"msp430xG4616",MSP430_ISA_46, bfd_mach_msp46},
- {"msp430xG4617",MSP430_ISA_46, bfd_mach_msp46},
- {"msp430xG4618",MSP430_ISA_46, bfd_mach_msp46},
- {"msp430xG4619",MSP430_ISA_46, bfd_mach_msp46},
-
- {"msp430x4783", MSP430_ISA_47, bfd_mach_msp47},
- {"msp430x4784", MSP430_ISA_47, bfd_mach_msp47},
- {"msp430x4793", MSP430_ISA_47, bfd_mach_msp47},
- {"msp430x4794", MSP430_ISA_47, bfd_mach_msp47},
- {"msp430x47166",MSP430_ISA_47, bfd_mach_msp47},
- {"msp430x47176",MSP430_ISA_47, bfd_mach_msp47},
- {"msp430x47186",MSP430_ISA_47, bfd_mach_msp47},
- {"msp430x47196",MSP430_ISA_47, bfd_mach_msp47},
- {"msp430x47167",MSP430_ISA_47, bfd_mach_msp47},
- {"msp430x47177",MSP430_ISA_47, bfd_mach_msp47},
- {"msp430x47187",MSP430_ISA_47, bfd_mach_msp47},
- {"msp430x47197",MSP430_ISA_47, bfd_mach_msp47},
-
- {"msp430x5418", MSP430_ISA_54, bfd_mach_msp54},
- {"msp430x5419", MSP430_ISA_54, bfd_mach_msp54},
- {"msp430x5435", MSP430_ISA_54, bfd_mach_msp54},
- {"msp430x5436", MSP430_ISA_54, bfd_mach_msp54},
- {"msp430x5437", MSP430_ISA_54, bfd_mach_msp54},
- {"msp430x5438", MSP430_ISA_54, bfd_mach_msp54},
-
- {"msp430X", MSP430X_ISA, bfd_mach_msp430x},
-
- {NULL, 0, 0}
-};
-
-
-static struct mcu_type_s default_mcu =
- { "msp430x11", MSP430_ISA_11, bfd_mach_msp11 };
-
-static struct mcu_type_s * msp430_mcu = & default_mcu;
-
/* Profiling capability:
It is a performance hit to use gcc's profiling approach for this tiny target.
Even more -- jtag hardware facility does not perform any profiling functions.
#define OPTION_LARGE 'l'
static bfd_boolean large_model = FALSE;
#define OPTION_NO_INTR_NOPS 'N'
-static bfd_boolean gen_interrupt_nops = TRUE;
+#define OPTION_INTR_NOPS 'n'
+static bfd_boolean gen_interrupt_nops = FALSE;
+#define OPTION_WARN_INTR_NOPS 'y'
+#define OPTION_NO_WARN_INTR_NOPS 'Y'
+static bfd_boolean warn_interrupt_nops = TRUE;
+#define OPTION_MCPU 'c'
+#define OPTION_MOVE_DATA 'd'
+static bfd_boolean move_data = FALSE;
static void
-msp430_set_arch (int dummy ATTRIBUTE_UNUSED)
+msp430_set_arch (int option)
{
char *str = (char *) alloca (32); /* 32 for good measure. */
input_line_pointer = extract_word (input_line_pointer, str, 32);
- md_parse_option (OPTION_MMCU, str);
- bfd_set_arch_mach (stdoutput, TARGET_ARCH, msp430_mcu->mach);
+ md_parse_option (option, str);
+ bfd_set_arch_mach (stdoutput, TARGET_ARCH,
+ target_is_430x () ? bfd_mach_msp430x : bfd_mach_msp11);
}
-static void
-show_mcu_list (FILE * stream)
+/* This is the full list of MCU names that are known to only
+ support the 430 ISA. */
+static const char * msp430_mcu_names [] =
{
- int i;
-
- fprintf (stream, _("Known MCU names:\n"));
-
- for (i = 0; mcu_types[i].name; i++)
- {
- fprintf (stream, "%13.13s", mcu_types[i].name);
- if ((i % 6) == 5)
- fprintf (stream, "\n");
- }
-
- fprintf (stream, "\n");
-}
+"msp430afe221", "msp430afe222", "msp430afe223", "msp430afe231",
+"msp430afe232", "msp430afe233", "msp430afe251", "msp430afe252",
+"msp430afe253", "msp430c091", "msp430c092", "msp430c111",
+"msp430c1111", "msp430c112", "msp430c1121", "msp430c1331",
+"msp430c1351", "msp430c311s", "msp430c312", "msp430c313",
+"msp430c314", "msp430c315", "msp430c323", "msp430c325",
+"msp430c336", "msp430c337", "msp430c412", "msp430c413",
+"msp430e112", "msp430e313", "msp430e315", "msp430e325",
+"msp430e337", "msp430f110", "msp430f1101", "msp430f1101a",
+"msp430f1111", "msp430f1111a", "msp430f112", "msp430f1121",
+"msp430f1121a", "msp430f1122", "msp430f1132", "msp430f122",
+"msp430f1222", "msp430f123", "msp430f1232", "msp430f133",
+"msp430f135", "msp430f147", "msp430f1471", "msp430f148",
+"msp430f1481", "msp430f149", "msp430f1491", "msp430f155",
+"msp430f156", "msp430f157", "msp430f1610", "msp430f1611",
+"msp430f1612", "msp430f167", "msp430f168", "msp430f169",
+"msp430f2001", "msp430f2002", "msp430f2003", "msp430f2011",
+"msp430f2012", "msp430f2013", "msp430f2101", "msp430f2111",
+"msp430f2112", "msp430f2121", "msp430f2122", "msp430f2131",
+"msp430f2132", "msp430f2232", "msp430f2234", "msp430f2252",
+"msp430f2254", "msp430f2272", "msp430f2274", "msp430f233",
+"msp430f2330", "msp430f235", "msp430f2350", "msp430f2370",
+"msp430f2410", "msp430f247", "msp430f2471", "msp430f248",
+"msp430f2481", "msp430f249", "msp430f2491", "msp430f412",
+"msp430f413", "msp430f4132", "msp430f415", "msp430f4152",
+"msp430f417", "msp430f423", "msp430f423a", "msp430f425",
+"msp430f4250", "msp430f425a", "msp430f4260", "msp430f427",
+"msp430f4270", "msp430f427a", "msp430f435", "msp430f4351",
+"msp430f436", "msp430f4361", "msp430f437", "msp430f4371",
+"msp430f438", "msp430f439", "msp430f447", "msp430f448",
+"msp430f4481", "msp430f449", "msp430f4491", "msp430f477",
+"msp430f478", "msp430f4783", "msp430f4784", "msp430f479",
+"msp430f4793", "msp430f4794", "msp430fe423", "msp430fe4232",
+"msp430fe423a", "msp430fe4242", "msp430fe425", "msp430fe4252",
+"msp430fe425a", "msp430fe427", "msp430fe4272", "msp430fe427a",
+"msp430fg4250", "msp430fg4260", "msp430fg4270", "msp430fg437",
+"msp430fg438", "msp430fg439", "msp430fg477", "msp430fg478",
+"msp430fg479", "msp430fw423", "msp430fw425", "msp430fw427",
+"msp430fw428", "msp430fw429", "msp430g2001", "msp430g2101",
+"msp430g2102", "msp430g2111", "msp430g2112", "msp430g2113",
+"msp430g2121", "msp430g2131", "msp430g2132", "msp430g2152",
+"msp430g2153", "msp430g2201", "msp430g2202", "msp430g2203",
+"msp430g2210", "msp430g2211", "msp430g2212", "msp430g2213",
+"msp430g2221", "msp430g2230", "msp430g2231", "msp430g2232",
+"msp430g2233", "msp430g2252", "msp430g2253", "msp430g2302",
+"msp430g2303", "msp430g2312", "msp430g2313", "msp430g2332",
+"msp430g2333", "msp430g2352", "msp430g2353", "msp430g2402",
+"msp430g2403", "msp430g2412", "msp430g2413", "msp430g2432",
+"msp430g2433", "msp430g2444", "msp430g2452", "msp430g2453",
+"msp430g2513", "msp430g2533", "msp430g2544", "msp430g2553",
+"msp430g2744", "msp430g2755", "msp430g2855", "msp430g2955",
+"msp430i2020", "msp430i2021", "msp430i2030", "msp430i2031",
+"msp430i2040", "msp430i2041", "msp430l092", "msp430p112",
+"msp430p313", "msp430p315", "msp430p315s", "msp430p325",
+"msp430p337", "msp430tch5e"
+};
int
md_parse_option (int c, char * arg)
{
- int i;
-
switch (c)
{
case OPTION_MMCU:
- for (i = 0; mcu_types[i].name; ++i)
- if (strcmp (mcu_types[i].name, arg) == 0)
- break;
-
- if (!mcu_types[i].name)
+ if (arg == NULL)
+ as_fatal (_("MCU option requires a name\n"));
+
+ if (strcasecmp ("msp430", arg) == 0)
+ selected_isa = MSP_ISA_430;
+ else if (strcasecmp ("msp430xv2", arg) == 0)
+ selected_isa = MSP_ISA_430Xv2;
+ else if (strcasecmp ("msp430x", arg) == 0)
+ selected_isa = MSP_ISA_430X;
+ else
{
- show_mcu_list (stderr);
- as_fatal (_("unknown MCU: %s\n"), arg);
+ int i;
+
+ for (i = sizeof msp430_mcu_names / sizeof msp430_mcu_names[0]; i--;)
+ if (strcasecmp (msp430_mcu_names[i], arg) == 0)
+ {
+ selected_isa = MSP_ISA_430;
+ break;
+ }
}
+ /* It is not an error if we do not match the MCU name. */
+ return 1;
- if (msp430_mcu == &default_mcu || msp430_mcu->mach == mcu_types[i].mach)
- msp430_mcu = &mcu_types[i];
- else if (msp430_mcu->mach == bfd_mach_msp430x)
- /* Allow switching to a lesser architecture. */
- msp430_mcu = mcu_types + i;
+ case OPTION_MCPU:
+ if (strcmp (arg, "430") == 0
+ || strcasecmp (arg, "msp430") == 0)
+ selected_isa = MSP_ISA_430;
+ else if (strcasecmp (arg, "430x") == 0
+ || strcasecmp (arg, "msp430x") == 0)
+ selected_isa = MSP_ISA_430X;
+ else if (strcasecmp (arg, "430xv2") == 0
+ || strcasecmp (arg, "msp430xv2") == 0)
+ selected_isa = MSP_ISA_430Xv2;
else
- as_fatal (_("redefinition of mcu type %s' to %s'"),
- msp430_mcu->name, mcu_types[i].name);
+ as_fatal (_("unrecognised argument to -mcpu option '%s'"), arg);
return 1;
case OPTION_RELAX:
case OPTION_NO_INTR_NOPS:
gen_interrupt_nops = FALSE;
return 1;
+ case OPTION_INTR_NOPS:
+ gen_interrupt_nops = TRUE;
+ return 1;
+
+ case OPTION_WARN_INTR_NOPS:
+ warn_interrupt_nops = TRUE;
+ return 1;
+ case OPTION_NO_WARN_INTR_NOPS:
+ warn_interrupt_nops = FALSE;
+ return 1;
+
+ case OPTION_MOVE_DATA:
+ move_data = TRUE;
+ return 1;
}
return 0;
}
+/* The intention here is to have the mere presence of these sections
+ cause the object to have a reference to a well-known symbol. This
+ reference pulls in the bits of the runtime (crt0) that initialize
+ these sections. Thus, for example, the startup code to call
+ memset() to initialize .bss will only be linked in when there is a
+ non-empty .bss section. Otherwise, the call would exist but have a
+ zero length parameter, which is a waste of memory and cycles.
+
+ The code which initializes these sections should have a global
+ label for these symbols, and should be marked with KEEP() in the
+ linker script.
+ */
+static void
+msp430_section (int arg)
+{
+ char * saved_ilp = input_line_pointer;
+ char * name = obj_elf_section_name ();
+
+ if (strncmp (name, ".bss", 4) == 0
+ || strncmp (name, ".gnu.linkonce.b.", 16) == 0)
+ (void) symbol_find_or_make ("__crt0_init_bss");
+
+ if (strncmp (name, ".data", 5) == 0
+ || strncmp (name, ".gnu.linkonce.d.", 16) == 0)
+ (void) symbol_find_or_make ("__crt0_movedata");
+
+ input_line_pointer = saved_ilp;
+ obj_elf_section (arg);
+}
+
+void
+msp430_frob_section (asection *sec)
+{
+ const char *name = sec->name;
+
+ if (sec->size == 0)
+ return;
+
+ if (strncmp (name, ".bss", 4) == 0
+ || strncmp (name, ".gnu.linkonce.b.", 16) == 0)
+ (void) symbol_find_or_make ("__crt0_init_bss");
+
+ if (strncmp (name, ".data", 5) == 0
+ || strncmp (name, ".gnu.linkonce.d.", 16) == 0)
+ (void) symbol_find_or_make ("__crt0_movedata");
+}
+
+static void
+msp430_lcomm (int ignore ATTRIBUTE_UNUSED)
+{
+ symbolS *symbolP = s_comm_internal (0, s_lcomm_internal);
+
+ if (symbolP)
+ symbol_get_bfdsym (symbolP)->flags |= BSF_OBJECT;
+ (void) symbol_find_or_make ("__crt0_init_bss");
+}
+
+static void
+msp430_comm (int needs_align)
+{
+ s_comm_internal (needs_align, elf_common_parse);
+ (void) symbol_find_or_make ("__crt0_init_bss");
+}
+
+static void
+msp430_refsym (int arg ATTRIBUTE_UNUSED)
+{
+ char sym_name[1024];
+ input_line_pointer = extract_word (input_line_pointer, sym_name, 1024);
+
+ (void) symbol_find_or_make (sym_name);
+}
const pseudo_typeS md_pseudo_table[] =
{
- {"arch", msp430_set_arch, 0},
+ {"arch", msp430_set_arch, OPTION_MMCU},
+ {"cpu", msp430_set_arch, OPTION_MCPU},
{"profiler", msp430_profiler, 0},
+ {"section", msp430_section, 0},
+ {"section.s", msp430_section, 0},
+ {"sect", msp430_section, 0},
+ {"sect.s", msp430_section, 0},
+ {"pushsection", msp430_section, 1},
+ {"refsym", msp430_refsym, 0},
+ {"comm", msp430_comm, 0},
+ {"lcomm", msp430_lcomm, 0},
{NULL, NULL, 0}
};
-const char *md_shortopts = "m:";
+const char *md_shortopts = "mm:,mP,mQ,ml,mN,mn,my,mY";
struct option md_longopts[] =
{
{"mmcu", required_argument, NULL, OPTION_MMCU},
+ {"mcpu", required_argument, NULL, OPTION_MCPU},
{"mP", no_argument, NULL, OPTION_POLYMORPHS},
{"mQ", no_argument, NULL, OPTION_RELAX},
{"ml", no_argument, NULL, OPTION_LARGE},
{"mN", no_argument, NULL, OPTION_NO_INTR_NOPS},
+ {"mn", no_argument, NULL, OPTION_INTR_NOPS},
+ {"mY", no_argument, NULL, OPTION_NO_WARN_INTR_NOPS},
+ {"my", no_argument, NULL, OPTION_WARN_INTR_NOPS},
+ {"md", no_argument, NULL, OPTION_MOVE_DATA},
{NULL, no_argument, NULL, 0}
};
{
fprintf (stream,
_("MSP430 options:\n"
- " -mmcu=<msp430-name> select microcontroller type\n"));
+ " -mmcu=<msp430-name> - select microcontroller type\n"
+ " -mcpu={430|430x|430xv2} - select microcontroller architecture\n"));
fprintf (stream,
_(" -mQ - enable relaxation at assembly time. DANGEROUS!\n"
" -mP - enable polymorph instructions\n"));
fprintf (stream,
_(" -ml - enable large code model\n"));
fprintf (stream,
- _(" -mN - disable generation of NOP after changing interrupts\n"));
-
- show_mcu_list (stream);
+ _(" -mN - do not insert NOPs after changing interrupts (default)\n"));
+ fprintf (stream,
+ _(" -mn - insert a NOP after changing interrupts\n"));
+ fprintf (stream,
+ _(" -mY - do not warn about missing NOPs after changing interrupts\n"));
+ fprintf (stream,
+ _(" -my - warn about missing NOPs after changing interrupts (default)\n"));
+ fprintf (stream,
+ _(" -md - Force copying of data from ROM to RAM at startup\n"));
}
symbolS *
for (opcode = msp430_opcodes; opcode->name; opcode++)
hash_insert (msp430_hash, opcode->name, (char *) opcode);
- bfd_set_arch_mach (stdoutput, TARGET_ARCH, msp430_mcu->mach);
+ bfd_set_arch_mach (stdoutput, TARGET_ARCH,
+ target_is_430x () ? bfd_mach_msp430x : bfd_mach_msp11);
}
/* Returns the register number equivalent to the string T.
msp430_srcoperand (struct msp430_operand_s * op,
char * l,
int bin,
- int * imm_op,
+ bfd_boolean * imm_op,
bfd_boolean allow_20bit_values,
bfd_boolean constants_allowed)
{
hhi(x) - x = (x >> 48) & 0xffff
The value _MUST_ be constant expression: #hlo(1231231231). */
- *imm_op = 1;
+ *imm_op = TRUE;
if (strncasecmp (h, "#llo(", 5) == 0)
{
op->reg = 0; /* Reg PC. */
op->am = 3;
- op->ol = 1; /* Immediate will follow an instruction. */
+ op->ol = 1; /* Immediate will follow an instruction. */
__tl = h + 1 + rval;
op->mode = OP_EXP;
+ op->vshift = vshift;
parse_exp (__tl, &(op->exp));
if (op->exp.X_op == O_constant)
{
x = (x >> 16) & 0xffff;
op->exp.X_add_number = x;
+ op->vshift = 0;
}
else if (vshift > 1)
{
else
op->exp.X_add_number = 0; /* Nothing left. */
x = op->exp.X_add_number;
+ op->vshift = 0;
}
if (allow_20bit_values)
{
- if (op->exp.X_add_number > 0xfffff || op->exp.X_add_number < - (0x7ffff))
+ if (op->exp.X_add_number > 0xfffff || op->exp.X_add_number < -524288)
{
as_bad (_("value 0x%x out of extended range."), x);
return 1;
}
else if (op->exp.X_op == O_symbol)
{
+ if (vshift > 1)
+ as_bad (_("error: unsupported #foo() directive used on symbol"));
op->mode = OP_EXP;
}
else if (op->exp.X_op == O_big)
{
short x;
+
if (vshift != -1)
{
op->exp.X_op = O_constant;
op->exp.X_add_number = 0xffff & generic_bignum[vshift];
x = op->exp.X_add_number;
+ op->vshift = 0;
}
else
{
__tl = h + 1;
parse_exp (__tl, &(op->exp));
op->mode = OP_EXP;
+ op->vshift = 0;
if (op->exp.X_op == O_constant)
{
int x = op->exp.X_add_number;
op->am = m ? 3 : 2;
op->ol = 0;
+ /* PC cannot be used in indirect addressing. */
+ if (target_is_430xv2 () && op->reg == 0)
+ {
+ as_bad (_("cannot use indirect addressing with the PC"));
+ return 1;
+ }
+
return 0;
}
char *m = strrchr (l, ')');
char *t;
- *imm_op = 1;
+ *imm_op = TRUE;
if (!h)
break;
__tl = l;
*h = 0;
op->mode = OP_EXP;
+ op->vshift = 0;
parse_exp (__tl, &(op->exp));
if (op->exp.X_op == O_constant)
{
/* An expression starting with a minus sign is a constant, not an address. */
op->am = (*l == '-' ? 3 : 1);
op->ol = 1;
+ op->vshift = 0;
__tl = l;
parse_exp (__tl, &(op->exp));
return 0;
op->mode = OP_EXP;
op->am = 1;
op->ol = 1;
+ op->vshift = 0;
parse_exp (__tl, &(op->exp));
if (op->exp.X_op != O_constant || op->exp.X_add_number != 0)
return 0;
}
-
/* Attempt to encode a MOVA instruction with the given operands.
Returns the length of the encoded instruction if successful
or 0 upon failure. If the encoding fails, an error message
return 0;
}
+static bfd_boolean check_for_nop = FALSE;
+
+#define is_opcode(NAME) (strcmp (opcode->name, NAME) == 0)
+
/* Parse instruction operands.
Return binary opcode. */
struct msp430_operand_s op1, op2;
int res = 0;
static short ZEROS = 0;
- int byte_op, imm_op;
+ bfd_boolean byte_op, imm_op;
int op_length = 0;
int fmt;
int extended = 0x1800;
const char * error_message;
static signed int repeat_count = 0;
bfd_boolean fix_emitted;
+ bfd_boolean nop_check_needed = FALSE;
/* Opcode is the one from opcodes table
line contains something like
or
.b @r2+, 5(R1). */
- /* Check if byte or word operation. */
- if (*line == '.' && TOLOWER (*(line + 1)) == 'b')
+ byte_op = FALSE;
+ 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 = TRUE;
+ 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
memset (&op1, 0, sizeof (op1));
memset (&op2, 0, sizeof (op2));
- imm_op = 0;
+ imm_op = FALSE;
if ((fmt = opcode->fmt) < 0)
{
- if (msp430_mcu->isa != MSP430X_ISA)
+ if (! target_is_430x ())
{
as_bad (_("instruction %s requires MSP430X mcu"),
opcode->name);
return 0;
}
-
+
fmt = (-fmt) - 1;
extended_op = TRUE;
}
repeat_count = 0;
}
+ if (check_for_nop && is_opcode ("nop"))
+ check_for_nop = FALSE;
+
switch (fmt)
{
case 0: /* Emulated. */
switch (opcode->insn_opnumb)
{
case 0:
+ if (is_opcode ("eint") || is_opcode ("dint"))
+ {
+ if (check_for_nop)
+ {
+ if (warn_interrupt_nops)
+ {
+ if (gen_interrupt_nops)
+ as_warn (_("NOP inserted between two instructions that change interrupt state"));
+ else
+ as_warn (_("a NOP might be needed here because of successive changes in interrupt state"));
+ }
+
+ if (gen_interrupt_nops)
+ {
+ /* Emit a NOP between interrupt enable/disable.
+ See 1.3.4.1 of the MSP430x5xx User Guide. */
+ insn_length += 2;
+ frag = frag_more (2);
+ bfd_putl16 ((bfd_vma) 0x4303 /* NOP */, frag);
+ }
+ }
+
+ nop_check_needed = TRUE;
+ }
+
/* Set/clear bits instructions. */
if (extended_op)
{
/* Emit the extension word. */
insn_length += 2;
- frag = frag_more (insn_length);
+ frag = frag_more (2);
bfd_putl16 (extended, frag);
}
+
insn_length += 2;
- frag = frag_more (insn_length);
+ frag = frag_more (2);
bfd_putl16 ((bfd_vma) bin, frag);
-
- if (gen_interrupt_nops
- && msp430_mcu->isa == MSP430_ISA_54
- && (strcmp (opcode->name, "eint") == 0
- || strcmp (opcode->name, "dint") == 0))
- {
- /* Emit a NOP following interrupt enable/disable.
- See 1.3.4.1 of the MSP430x5xx User Guide. */
- insn_length += 2;
- frag = frag_more (2);
- bfd_putl16 ((bfd_vma) 0x4303 /* NOP */, frag);
- }
-
dwarf2_emit_insn (insn_length);
break;
if (res)
break;
+ bin |= (op1.reg | (op1.am << 7));
+
+ if (is_opcode ("clr") && bin == 0x4302 /* CLR R2*/)
+ {
+ if (check_for_nop)
+ {
+ if (warn_interrupt_nops)
+ {
+ if (gen_interrupt_nops)
+ as_warn (_("NOP inserted between two instructions that change interrupt state"));
+ else
+ as_warn (_("a NOP might be needed here because of successive changes in interrupt state"));
+ }
+
+ if (gen_interrupt_nops)
+ {
+ /* Emit a NOP between interrupt enable/disable.
+ See 1.3.4.1 of the MSP430x5xx User Guide. */
+ insn_length += 2;
+ frag = frag_more (2);
+ bfd_putl16 ((bfd_vma) 0x4303 /* NOP */, frag);
+ }
+ }
+
+ nop_check_needed = TRUE;
+ }
+
/* Compute the entire instruction length, in bytes. */
- insn_length = (extended_op ? 2 : 0) + 2 + (op1.ol * 2);
- frag = frag_more (insn_length);
+ op_length = (extended_op ? 2 : 0) + 2 + (op1.ol * 2);
+ insn_length += op_length;
+ frag = frag_more (op_length);
where = frag - frag_now->fr_literal;
if (extended_op)
where += 2;
}
- bin |= (op1.reg | (op1.am << 7));
bfd_putl16 ((bfd_vma) bin, frag);
frag += 2;
where += 2;
{
if (op1.reg)
fix_new_exp (frag_now, where, 2,
- &(op1.exp), FALSE, CHECK_RELOC_MSP430);
+ &(op1.exp), FALSE, CHECK_RELOC_MSP430 (op1));
else
fix_new_exp (frag_now, where, 2,
&(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
}
}
- if (gen_interrupt_nops
- && msp430_mcu->isa == MSP430_ISA_54
- && strcmp (opcode->name, "clr") == 0
- && bin == 0x4302 /* CLR R2*/)
- {
- /* Emit a NOP following interrupt enable/disable.
- See 1.3.4.1 of the MSP430x5xx User Guide. */
- insn_length += 2;
- frag = frag_more (2);
- bfd_putl16 ((bfd_vma) 0x4303 /* NOP */, frag);
- }
-
dwarf2_emit_insn (insn_length);
break;
frag = frag_more (insn_length);
where = frag - frag_now->fr_literal;
+ if (target_is_430xv2 ()
+ && op1.mode == OP_REG
+ && op1.reg == 0
+ && (is_opcode ("rlax")
+ || is_opcode ("rlcx")
+ || is_opcode ("rla")
+ || is_opcode ("rlc")))
+ {
+ as_bad (_("%s: attempt to rotate the PC register"), opcode->name);
+ break;
+ }
+
if (extended_op)
{
if (!addr_op)
{
if (op1.reg || (op1.reg == 0 && op1.am == 3)) /* Not PC relative. */
fix_new_exp (frag_now, where, 2,
- &(op1.exp), FALSE, CHECK_RELOC_MSP430);
+ &(op1.exp), FALSE, CHECK_RELOC_MSP430 (op1));
else
fix_new_exp (frag_now, where, 2,
&(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
{
if (op2.reg) /* Not PC relative. */
fix_new_exp (frag_now, where, 2,
- &(op2.exp), FALSE, CHECK_RELOC_MSP430);
+ &(op2.exp), FALSE, CHECK_RELOC_MSP430 (op2));
else
fix_new_exp (frag_now, where, 2,
&(op2.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
if (extended_op)
{
as_bad ("Internal error: state 0/3 not coded for extended instructions");
- return 0;
+ break;
}
line = extract_operand (line, l1, sizeof (l1));
if (res)
break;
- byte_op = 0;
- imm_op = 0;
+ byte_op = FALSE;
+ imm_op = FALSE;
bin |= ((op1.reg << 8) | (op1.am << 4));
op_length = 2 + 2 * op1.ol;
frag = frag_more (op_length);
if (op1.reg || (op1.reg == 0 && op1.am == 3))
fix_new_exp (frag_now, where, 2,
- &(op1.exp), FALSE, CHECK_RELOC_MSP430);
+ &(op1.exp), FALSE, CHECK_RELOC_MSP430 (op1));
else
fix_new_exp (frag_now, where, 2,
&(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
fix_emitted = FALSE;
line = extract_operand (line, l1, sizeof (l1));
- imm_op = 0;
+ imm_op = FALSE;
res = msp430_srcoperand (&op1, l1, opcode->bin_opcode, &imm_op,
extended_op, FALSE);
if (res)
break;
- byte_op = 0;
+ byte_op = FALSE;
op_length = 2 + 2 * op1.ol;
frag = frag_more (op_length);
if (op1.ol != 1)
{
as_bad ("Internal error: unexpected CALLA instruction length: %d\n", op1.ol);
- return 0;
+ break;
}
bfd_putl16 ((bfd_vma) ZEROS, frag + 2);
if (*l1 != '#')
{
- as_bad (_("expected #n as first argument of POPM"));
- return 0;
+ as_bad (_("expected #n as first argument of %s"), opcode->name);
+ break;
}
parse_exp (l1 + 1, &(op1.exp));
if (op1.exp.X_op != O_constant)
{
as_bad (_("expected constant expression for first argument of %s"),
opcode->name);
- return 0;
+ break;
}
if ((reg = check_reg (l2)) == -1)
{
as_bad (_("expected register as second argument of %s"),
opcode->name);
- return 0;
+ break;
}
op_length = 2;
bin |= 0x100;
n = op1.exp.X_add_number;
bin |= (n - 1) << 4;
- if (strcmp (opcode->name, "pushm") == 0)
+ if (is_opcode ("pushm"))
bin |= reg;
else
{
if (reg - n + 1 < 0)
{
as_bad (_("Too many registers popped"));
- return 0;
+ break;
}
+
+ /* CPU21 errata: cannot use POPM to restore the SR register. */
+ if (target_is_430xv2 ()
+ && (reg - n + 1 < 3)
+ && reg >= 2
+ && is_opcode ("popm"))
+ {
+ as_bad (_("Cannot use POPM to restore the SR register"));
+ break;
+ }
+
bin |= (reg - n + 1);
}
if (extended & 0xff)
{
as_bad (_("repeat count cannot be used with %s"), opcode->name);
- return 0;
+ break;
}
line = extract_operand (line, l1, sizeof (l1));
if (*l1 != '#')
{
as_bad (_("expected #n as first argument of %s"), opcode->name);
- return 0;
+ break;
}
parse_exp (l1 + 1, &(op1.exp));
if (op1.exp.X_op != O_constant)
{
as_bad (_("expected constant expression for first argument of %s"),
opcode->name);
- return 0;
+ break;
}
n = op1.exp.X_add_number;
if (n > 4 || n < 1)
{
as_bad (_("expected first argument of %s to be in the range 1-4"),
opcode->name);
- return 0;
+ break;
}
if ((reg = check_reg (l2)) == -1)
{
as_bad (_("expected register as second argument of %s"),
opcode->name);
- return 0;
+ break;
+ }
+
+ if (target_is_430xv2 () && reg == 0)
+ {
+ as_bad (_("%s: attempt to rotate the PC register"), opcode->name);
+ break;
}
op_length = 2;
if (extended & 0xff)
{
as_bad (_("repeat count cannot be used with %s"), opcode->name);
- return 0;
+ break;
}
line = extract_operand (line, l1, sizeof (l1));
{
as_bad (_("expected register as argument of %s"),
opcode->name);
- return 0;
+ break;
+ }
+
+ if (target_is_430xv2 () && reg == 0)
+ {
+ as_bad (_("%s: attempt to rotate the PC register"), opcode->name);
+ break;
}
if (byte_op)
if (extended & 0xff)
{
as_bad (_("repeat count cannot be used with %s"), opcode->name);
- return 0;
+ break;
}
line = extract_operand (line, l1, sizeof (l1));
{
as_bad (_("expected value of first argument of %s to fit into 20-bits"),
opcode->name);
- return 0;
+ break;
}
bin |= ((n >> 16) & 0xf) << 8;
{
as_bad (_("expected register name or constant as first argument of %s"),
opcode->name);
- return 0;
+ break;
}
bin |= (n << 8) | (1 << 6);
{
as_bad (_("expected register as second argument of %s"),
opcode->name);
- return 0;
+ break;
}
frag = frag_more (op_length);
}
case 9: /* MOVA, BRA, RETA. */
- imm_op = 0;
+ imm_op = FALSE;
bin = opcode->bin_opcode;
- if (strcmp (opcode->name, "reta") == 0)
+ if (is_opcode ("reta"))
{
/* The RETA instruction does not take any arguments.
The implicit first argument is @SP+.
res = msp430_srcoperand (&op1, l1, opcode->bin_opcode,
&imm_op, extended_op, FALSE);
- if (strcmp (opcode->name, "bra") == 0)
+ if (is_opcode ("bra"))
{
/* This is the BRA synthetic instruction.
The second argument is always PC. */
& error_message)) == 0)
{
as_bad (error_message, opcode->name);
- return 0;
+ break;
}
dwarf2_emit_insn (op_length);
break;
if (op1.exp.X_op != O_constant)
{
as_bad (_("expected constant value as argument to RPT"));
- return 0;
+ break;
}
if (op1.exp.X_add_number < 1
|| op1.exp.X_add_number > (1 << 4))
{
as_bad (_("expected constant in the range 2..16"));
- return 0;
+ break;
}
/* We silently accept and ignore a repeat count of 1. */
else
{
as_bad (_("expected constant or register name as argument to RPT insn"));
- return 0;
+ break;
}
}
break;
break; /* Error occurred. All warnings were done before. */
if (extended_op
- && strcmp (opcode->name, "movx") == 0
+ && is_opcode ("movx")
&& addr_op
&& msp430_enable_relax)
{
}
}
+ bin |= (op2.reg | (op1.reg << 8) | (op1.am << 4) | (op2.am << 7));
+
+ if ( (is_opcode ("bic") && bin == 0xc232)
+ || (is_opcode ("bis") && bin == 0xd232)
+ || (is_opcode ("mov") && op2.mode == OP_REG && op2.reg == 2))
+ {
+ if (check_for_nop)
+ {
+ if (warn_interrupt_nops)
+ {
+ if (gen_interrupt_nops)
+ as_warn (_("NOP inserted between two instructions that change interrupt state"));
+ else
+ as_warn (_("a NOP might be needed here because of successive changes in interrupt state"));
+ }
+
+ if (gen_interrupt_nops)
+ {
+ /* Emit a NOP between interrupt enable/disable.
+ See 1.3.4.1 of the MSP430x5xx User Guide. */
+ insn_length += 2;
+ frag = frag_more (2);
+ bfd_putl16 ((bfd_vma) 0x4303 /* NOP */, frag);
+ }
+ }
+
+ nop_check_needed = TRUE;
+ }
+
/* Compute the entire length of the instruction in bytes. */
- insn_length =
- (extended_op ? 2 : 0) /* The extension word. */
+ op_length = (extended_op ? 2 : 0) /* The extension word. */
+ 2 /* The opcode */
+ (2 * op1.ol) /* The first operand. */
+ (2 * op2.ol); /* The second operand. */
- frag = frag_more (insn_length);
+ insn_length += op_length;
+ frag = frag_more (op_length);
where = frag - frag_now->fr_literal;
if (extended_op)
frag += 2;
}
- bin |= (op2.reg | (op1.reg << 8) | (op1.am << 4) | (op2.am << 7));
bfd_putl16 ((bfd_vma) bin, frag);
where += 2;
frag += 2;
{
if (op1.reg || (op1.reg == 0 && op1.am == 3)) /* Not PC relative. */
fix_new_exp (frag_now, where, 2,
- &(op1.exp), FALSE, CHECK_RELOC_MSP430);
+ &(op1.exp), FALSE, CHECK_RELOC_MSP430 (op1));
else
fix_new_exp (frag_now, where, 2,
&(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
{
if (op2.reg) /* Not PC relative. */
fix_new_exp (frag_now, where, 2,
- &(op2.exp), FALSE, CHECK_RELOC_MSP430);
+ &(op2.exp), FALSE, CHECK_RELOC_MSP430 (op2));
else
fix_new_exp (frag_now, where, 2,
&(op2.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
}
}
- if (gen_interrupt_nops
- && msp430_mcu->isa == MSP430_ISA_54
- && ( (strcmp (opcode->name, "bic") == 0 && bin == 0xc232)
- || (strcmp (opcode->name, "bis") == 0 && bin == 0xd232)
- || (strcmp (opcode->name, "mov") == 0 && op2.mode == OP_REG && op2.reg == 2)))
- {
- /* Emit a NOP following interrupt enable/disable.
- See 1.3.4.1 of the MSP430x5xx User Guide. */
- insn_length += 2;
- frag = frag_more (2);
- bfd_putl16 ((bfd_vma) 0x4303 /* NOP */, frag);
- }
-
dwarf2_emit_insn (insn_length);
break;
if (res)
break; /* Error in operand. */
+ if (target_is_430xv2 ()
+ && op1.mode == OP_REG
+ && op1.reg == 0
+ && (is_opcode ("rrax")
+ || is_opcode ("rrcx")
+ || is_opcode ("rra")
+ || is_opcode ("rrc")))
+ {
+ as_bad (_("%s: attempt to rotate the PC register"), opcode->name);
+ break;
+ }
+
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 (strcmp (opcode->name, "swpbx") == 0
- || strcmp (opcode->name, "sxtx") == 0)
+ if (is_opcode ("swpbx") || is_opcode ("sxtx"))
{
/* These two instructions use a special
encoding of the A/L and B/W bits. */
{
as_bad (_("%s instruction does not accept a .b suffix"),
opcode->name);
- return 0;
+ break;
}
else if (! addr_op)
extended |= BYTE_OPERATION;
{
if (op1.reg || (op1.reg == 0 && op1.am == 3)) /* Not PC relative. */
fix_new_exp (frag_now, where, 2,
- &(op1.exp), FALSE, CHECK_RELOC_MSP430);
+ &(op1.exp), FALSE, CHECK_RELOC_MSP430 (op1));
else
fix_new_exp (frag_now, where, 2,
&(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL);
as_bad (_("polymorphs are not enabled. Use -mP option to enable."));
break;
}
-
+
line = extract_operand (line, l1, sizeof (l1));
if (l1[0])
{
/* Relaxation required. */
struct rcodes_s rc = msp430_rcodes[opcode->insn_opnumb];
- if (msp430_mcu->isa == MSP430X_ISA)
+ if (target_is_430x ())
rc = msp430x_rcodes[opcode->insn_opnumb];
/* The parameter to dwarf2_emit_insn is actually the offset to
/* Relaxation required. */
struct hcodes_s hc = msp430_hcodes[opcode->insn_opnumb];
- if (msp430_mcu->isa == MSP430X_ISA)
+ if (target_is_430x ())
hc = msp430x_hcodes[opcode->insn_opnumb];
insn_length += 8;
}
input_line_pointer = line;
+ check_for_nop = nop_check_needed;
return 0;
}
{
if (fixp->fx_r_type == BFD_RELOC_MSP430_10_PCREL)
return 1;
-
if (fixp->fx_pcrel)
return 1;
-
if (msp430_enable_polys
&& !msp430_enable_relax)
return 1;
bfd_putl16 ((bfd_vma) value, where);
break;
+ case BFD_RELOC_MSP430_ABS_HI16:
+ value >>= 16;
+ value &= 0xffff; /* Get rid of extended sign. */
+ bfd_putl16 ((bfd_vma) value, where);
+ break;
+
case BFD_RELOC_32:
bfd_putl16 ((bfd_vma) value, where);
break;
case ENCODE_RELAX (STATE_UNCOND_BRANCH, STATE_WORD):
case ENCODE_RELAX (STATE_UNCOND_BRANCH, STATE_UNDEF):
/* Convert uncond branch jmp lab -> br lab. */
- cc = & msp430_rcodes[7];
- if (msp430_mcu->isa == MSP430X_ISA)
+ if (target_is_430x ())
cc = msp430x_rcodes + 7;
+ else
+ cc = msp430_rcodes + 7;
where = fragP->fr_literal + fragP->fr_fix;
bfd_putl16 (cc->lop0, where);
rela = BFD_RELOC_MSP430_RL_PCREL;
insn &= 0xffff;
/* Find actual instruction. */
- if (msp430_mcu->isa == MSP430X_ISA)
+ if (target_is_430x ())
{
for (i = 0; i < 7 && !cc; i++)
if (msp430x_rcodes[i].sop == insn)
case ENCODE_RELAX (STATE_NOOV_BRANCH, STATE_WORD):
case ENCODE_RELAX (STATE_NOOV_BRANCH, STATE_UNDEF):
- cc = & msp430_rcodes[6];
-
- if (msp430_mcu->isa == MSP430X_ISA)
+ if (target_is_430x ())
cc = msp430x_rcodes + 6;
-
+ else
+ cc = msp430_rcodes + 6;
where = fragP->fr_literal + fragP->fr_fix;
bfd_putl16 (cc->lop0, where);
bfd_putl16 (cc->lop1, where + 2);
int insn = bfd_getl16 (fragP->fr_opcode + 2);
insn &= 0xffff;
- if (msp430_mcu->isa == MSP430X_ISA)
+ if (target_is_430x ())
{
for (i = 0; i < 4 && !hc; i++)
if (msp430x_hcodes[i].op1 == insn)
if (msp430_hcodes[i].op1 == insn)
hc = &msp430_hcodes[i];
}
-
if (!hc || !hc->name)
as_fatal (_("internal inconsistency problem in %s: ext. insn %04lx"),
__FUNCTION__, (long) insn);
int insn = bfd_getl16 (fragP->fr_opcode + 2);
insn &= 0xffff;
- if (msp430_mcu->isa == MSP430X_ISA)
+ if (target_is_430x ())
{
for (i = 0; i < 4 && !hc; i++)
if (msp430x_hcodes[i].op1 == insn)
void
msp430_md_end (void)
{
+ if (check_for_nop == TRUE && warn_interrupt_nops)
+ as_warn ("assembly finished with the last instruction changing interrupt state - a NOP might be needed");
+
bfd_elf_add_proc_attr_int (stdoutput, OFBA_MSPABI_Tag_ISA,
- msp430_mcu->isa == MSP430X_ISA ? 2 : 1);
+ target_is_430x () ? 2 : 1);
bfd_elf_add_proc_attr_int (stdoutput, OFBA_MSPABI_Tag_Code_Model,
large_model ? 2 : 1);