Copyright 2000-2012 Free Software Foundation, Inc. The material in this patch is a derivative work of the binutils package, and is subject to licensing and copyright of its parent package. This patch adds/enhances support for the Texas Instruments MSP430 family of microcontrollers to GNU binutils. The material incorporated is maintained in a git repository hosted at: git://mspgcc.git.sourceforge.net/gitroot/mspgcc/binutils This patch incorporates changes between: upstream/release/binutils-2.22 (3e07ad0fcb22e8fed15f5c86c8998ba5cec7ca0c) and binutils-2_22/binutils-2.22 (c35cfdccacef04f2618afe8ae5368c8cf8bd5ae0) To build, obtain the upstream release distribution from: ftp://ftp.gnu.org/pub/gnu/binutils/binutils-2.22.tar.bz2 Unpack the distribution, apply the patch, and build. (Note: The example commands are in Bourne-shell syntax.) tar xjf binutils-2.22.tar.bz2 ( cd binutils-2.22 ; patch -p1 < ../msp430-binutils-2.22-20120911.patch ) mkdir -p BUILD/binutils cd BUILD/binutils ../../binutils-2.22/configure \ --target=msp430 \ --prefix=/usr/local/msp430 \ 2>&1 | tee co make 2>&1 | tee mo make install 2>&1 | tee moi For support please use the mspgcc-users mailing list. You can subscribe at https://lists.sourceforge.net/lists/listinfo/mspgcc-users. Once subscribed, you can post by email to mspgcc-users@lists.sourceforge.net. To report bugs, please file a tracker ticket on SourceForge at https://sourceforge.net/tracker/?group_id=42303&atid=432701 Log of relevant changes: 3d91e75 [2012-09-11 09:15:14 -0500] Update DEV-PHASE for release d5323c6 [2012-09-10 10:45:37 -0500] SF 3554291 refine FRAM ISR fix 9bae3ae [2012-07-16 14:32:05 -0500] Update DEV-PHASE for release 1a0ef3d [2012-07-07 17:52:29 -0500] SF 3541237 truncated address in disassembled jmp 0876ac8 [2012-07-02 06:28:15 -0500] Back-port upstream patch. 7077174 [2012-06-27 17:15:03 -0500] Update DEV-PHASE for release bef747c [2012-06-22 15:11:35 -0500] SF 3537200 detect incompatible object files a71c9f9 [2012-06-18 15:35:49 -0500] Update DEV-PHASE for release 1dce643 [2012-06-18 15:10:50 -0500] Assign .any.* sections to output sections based on available space 43e9c84 [2012-06-07 09:34:59 -0500] Clean up alignment and input sections 49a8b47 [2012-06-07 08:56:46 -0500] SF 3532786: invalid placement of .near.text 6a28808 [2012-06-06 07:15:12 -0500] Update DEV-PHASE for release 8805129 [2012-05-30 17:50:59 -0500] SF 3530932 unable to link with 20-bit symbols in debug sections 4e7ccd8 [2012-05-22 11:55:09 -0500] Temporarily place .any* in default sections afddce7 [2012-05-14 20:04:59 -0500] Update DEV-PHASE for release 17d6d5d [2012-04-27 11:08:16 -0500] Complete set of far sections de75aa8 [2012-04-27 11:03:19 -0500] Eliminate PROVIDE from symbols user should not be overriding bf12d20 [2012-04-07 11:47:08 -0500] Update DEV-PHASE for release 971f51a [2012-03-29 04:00:07 -0500] SF 3512502 address mode fails to accept CG-compatible immediates f750278 [2012-02-23 12:26:43 -0600] Use standard DOLLAR_DOT approach instead of custom version 049e0c1 [2012-02-21 10:15:55 -0600] Cleanup detection of pc-relative fixup/relocations dc140d3 [2012-02-21 07:36:30 -0600] SF 3489407 restore legacy symbolic operands e2d0f29 [2012-02-19 15:03:46 -0600] Baby-step cleanup 9f51953 [2012-02-19 12:22:50 -0600] Eliminate constraints preventing symbol-.(r0) or symbol(r2) aa4a4dd [2012-02-19 11:08:27 -0600] Make dependence on r0 explicit when emitting indexed operands 513e8bf [2012-02-18 10:29:14 -0600] Refactor code that emits fixups b961cbb [2012-02-18 09:16:32 -0600] Default to non-PC-relative symbolic relocations f9ab2a9 [2012-02-17 19:25:11 -0600] Default to non-PC-relative conditional jump relocations 256d094 [2012-02-17 18:34:28 -0600] Add non-PCREL 10-bit conditional jump relocation bfbaf281 [2012-02-17 18:14:44 -0600] cleanup fixup application f46f9ca [2012-02-17 13:43:27 -0600] SF 3488636 mis-assembly using program location counter 390f3dc [2012-02-17 10:11:57 -0600] SF 3487856 gas mis-disassemble symbolics 6bf61d4 [2012-02-17 04:39:16 -0600] msp430-dis: clean up magic numbers bf39491 [2012-02-17 03:27:30 -0600] emit more useful error when addresses unaligned f4f99a7 [2012-02-17 02:34:01 -0600] Run code through indent again 38d084d [2012-02-16 19:51:42 -0600] Validate relocation ranges 8646241 [2012-02-16 15:56:45 -0600] Enhance range validation in assembler 79f641a [2012-02-15 20:32:48 -0600] Document all relocations 93bb457 [2012-02-15 20:30:48 -0600] Clean up fixup formatting/fallthru 4acdccc [2012-02-15 19:55:29 -0600] Correct and validate HOWTO order c68de7e [2012-02-15 18:46:58 -0600] Refactor reloc selection and storage ab7eaa2 [2012-02-15 16:04:46 -0600] Remove unnecessary imm_op output parameter e4ffed4 [2012-02-15 15:53:10 -0600] Relax operand alignment check for push/pushx bd49bb0 [2012-02-15 13:42:50 -0600] Disallow unaligned access off stack pointer f2b82b5 [2012-02-15 13:37:23 -0600] Uniform detection of encoded immediates that might break alignment 12dabed [2012-02-15 08:00:32 -0600] Avoid gratuitous distinction between source/dest addressing modes afad040 [2012-02-15 07:08:46 -0600] Eliminate redundant mode field 95f675a [2012-02-15 02:44:16 -0600] Move all dwarf2 line emission to end of function. b65ed61 [2012-02-14 20:43:24 -0600] Fix error due to inconsistent use of __is 8618f91 [2012-02-14 20:38:03 -0600] Revert effect of 3487332 and 3487629 3e03d32 [2012-02-14 19:56:18 -0600] Rename local variable for clarity 02bb16b [2012-02-14 16:59:25 -0600] Remove redundant set of op->mode feee899 [2012-02-14 13:27:56 -0600] Catch unhandled unsupported operands efed795 [2012-02-14 13:03:06 -0600] SF 3487629 430x address mode gets symbolic wrong 41bd111 [2012-02-14 11:17:28 -0600] Remove bypassed PCREL relocation generation for source operands 45b27a1 [2012-02-14 10:52:26 -0600] Confirm that no operands need to be PCREL adjusted 6b486fe [2012-02-14 10:51:50 -0600] Expand all reloc selection macros b89b2d6 [2012-02-14 08:49:18 -0600] Improve description of relocation for conditional jumps fc65d73 [2012-02-14 08:48:19 -0600] Record exemplar instructions for each pattern a212a4d [2012-02-13 17:33:17 -0600] SF 3487332 gas misassemble symbolic constant fc8f393 [2012-02-13 16:33:31 -0600] SF 3487360 gas mis-disassemble symbolics 4f2543f [2012-02-13 14:41:14 -0600] Refactor test for non-PC-relative relocations b06968c [2012-02-13 14:03:53 -0600] Note how to get the opcodes that must be tested bc38317 [2012-02-13 13:16:06 -0600] SF 3487361 clra opcode incorrect 4f02e8e [2012-02-13 13:11:57 -0600] SF 3487364 430x address opcodes ignore CG dbcdd3c [2012-02-13 11:59:38 -0600] magic number and fix comment 707a2da [2012-02-12 19:31:49 -0600] Reject arithmetic on registers at compile time 98c0b67 [2012-02-12 18:46:05 -0600] Substitute -1 for constants that are all ones for the operation width 92050eb [2012-02-12 18:24:52 -0600] clean up opcode width extraction 9460593 [2012-02-12 17:35:02 -0600] Reorder for clarity 67e7e62 [2012-02-12 15:40:36 -0600] Avoid premature marking of immediate operand 187471f [2012-02-12 15:24:43 -0600] Avoid double-converting operand in emulated shift operations 715b4d8 [2012-02-12 13:26:54 -0600] Clean up register recognition and other processing 955d646 [2012-02-12 11:56:13 -0600] documentation cleanup 6436980 [2012-02-12 10:58:20 -0600] clean up immediate operand validation cc9ac44 [2012-02-12 10:15:20 -0600] clean up local variables in srcoperand 4f46cee [2012-02-12 10:02:45 -0600] Clean up dstoperand conversion ea9189b [2012-02-12 09:36:31 -0600] cleanup: constants, remove gratuitous declaration aaca308 [2012-02-10 15:17:39 -0600] Replace check_reg with extract_regno 4b8baca [2012-02-10 14:43:41 -0600] Eliminate magic number where OP_EXP was intended 3006a6d [2012-02-10 14:39:35 -0600] Clean up .rpt pseudo-op 0ee8f62 [2012-02-10 13:33:25 -0600] Style cleanup: eliminate C++-style comments 04fe4a8 [2012-02-10 12:59:46 -0600] Style cleanup 9693b43 [2012-02-10 12:30:04 -0600] Correct #lo/#hi processing to retain recognition of -1 constant 053d2fb [2012-02-10 11:16:34 -0600] Run everything through GNU indent for style cleanup b2a8754 [2012-02-10 11:10:10 -0600] Eliminate mask constants in favor of macros 9e4255b [2012-02-10 10:29:54 -0600] more removal of magic numbers 0536308 [2012-02-10 09:49:28 -0600] Remove disabled code to display interrupt vectors 05c05a8 [2012-02-10 09:25:49 -0600] SF 3486454 .rpt disassembles incorrectly a76daca [2012-02-10 09:18:35 -0600] SF 3486453 rrux not supported 217097b [2012-02-09 23:20:23 -0600] SF 3486451 430x 20-bit immediates mistranslated e26569e [2012-02-09 23:02:44 -0600] eliminate magic register numbers 2fc2487 [2012-02-09 22:47:55 -0600] gas: eliminate magic numbers in immediate range checks a84da4a [2012-02-09 22:39:19 -0600] convert src/dst operand extractors to bfd_boolean functions 4a4cad7 [2012-02-09 18:54:45 -0600] Remove relaxation and polymorph support for MSP430 1c633cf [2012-02-09 11:34:56 -0600] tc-msp430.h: cleanup 8be6e86 [2012-02-09 12:08:52 -0600] Add relevant errata provided by TI 69945cc [2012-01-19 18:28:35 -0600] Correct version infrastructure to also modify release version string 05e807a [2012-01-11 12:00:05 -0600] SF 3472485 need visible version info in tool output 5b9c67c [2011-08-30 09:37:12 -0500] SF 3400750 infomemnobits missing 722d4bd [2011-08-23 18:33:24 -0500] SF 3383736 separate info sections c3f2339 [2011-08-03 04:15:21 -0500] Make relocation section definitions consistent with elf.sc f73a426 [2011-08-03 04:10:55 -0500] Clean up data sections de15d45 [2011-08-02 10:06:59 -0500] SF 3143071 error in addend of relocation entry in output b23dce1 [2011-08-02 16:59:15 -0500] SF 3384754 relocatable links discard CRT section information cee33c6 [2011-08-02 16:34:31 -0500] SF 3384766 string constants misplaced in text section 74b7db4 [2011-07-27 11:06:56 -0500] SF 3379341: non-empty ARCH environment variable results unusable ld bf4dc9a [2011-02-10 23:44:12 +0000] Revert 2010-11-02 H.J. Lu. 4863b80 [2011-06-12 11:09:24 -0500] SF 3315471 remove _init_section__ function f3f8502 [2011-05-07 11:43:29 -0500] SF 3293911 gas 2.21 segfault when building gcc 4.4.5 83014a1 [2011-04-21 10:02:40 -0500] Avoid complaints in relocatable links 7403104 [2011-04-18 16:42:26 -0500] SF 3289064 uniarch binutils missing far section support 06250ac [2011-04-13 19:06:23 -0500] SF 3286248 broken #hlo calculation for small constants fe611a8 [2011-04-10 21:39:34 -0500] SF 3237855: clean up -mmcu documentation 405e961 [2011-04-02 09:11:34 -0500] SF 3266079: binutils link does not preserve cpu architecture 9c37f03 [2011-04-02 09:09:52 -0500] Clone genelf.em prior to msp430-specific mods 4c47737 [2011-03-22 09:55:52 -0500] Store architecture, not CPU, in elf flags field b1ccb84 [2011-03-14 12:55:23 -0500] Clean up section management. aac2048 [2011-03-12 11:19:17 -0600] SF 3207853: bad constant extraction on 64-bit systems 3ae4c6c [2011-03-12 09:55:14 -0600] SF 3207853: validate llo/lhi/hlo/hhi 7970684 [2011-03-12 09:28:50 -0600] Update to match current output (whitespace variations only) 989579c [2011-03-02 18:24:57 -0600] SF 3197755: long long type not working b0fcba5 [2011-02-20 14:44:58 -0600] Eliminate warning that breaks gcc test infrastructure 5a5c7b9 [2011-02-10 17:01:58 -0600] SF 3177314: undefined reference with too many template parameters 7e953d0 [2011-02-07 10:49:43 -0600] Parse cpu/mpy directives in assembly code 3fd56bb [2011-02-07 09:03:21 -0600] Remove hard-coded MCU-specific information from msp430 port. d326a72 [2011-02-05 21:37:53 -0600] Correct vector start for ISA_24 chips 8bedb57 [2011-02-05 13:36:03 -0600] Regenerate 5938e0d [2011-02-05 13:35:39 -0600] Add MCUs supported by msp430all.sh fae9f6f [2011-02-05 13:31:09 -0600] Regenerate 47fd0f0 [2011-02-05 13:29:08 -0600] Update to match MCUs in msp430all.sh 16e97e6 [2011-01-26 11:53:58 -0600] SF 3154622: Correct support for MSP430F2132 b11dcea [2011-01-26 11:12:49 -0600] SF 3146404: Support for msp430f550x chips 3e6a58c [2011-01-21 16:01:15 +0200] Add support for msp430f471x3 638070a [2011-01-03 15:30:29 -0600] Regenerate e845ac1 [2010-11-14 10:07:12 -0600] SF 3109143: Support value-line MSP430G22x1 devices 3909fd6 [2010-11-06 14:31:43 -0500] SF 3096352: Illegal disassembly instruction (addx.a R14,R15) e291e09 [2010-08-29 13:11:44 -0500] SF 3055519: add support for 55xx chips a0f3a60 [2010-05-27 12:22:04 -0500] Replace undefined cc430x5123 with missing cc430x5133 aeec5cc [2010-05-27 11:32:07 -0500] Fix info/bsl locations on newer chips 70aa46c [2011-01-02 10:53:49 -0600] Apply binutils-2.20.patch from revision aac9a66b of mspgcc4 repository. diff --git binutils-2.22.orig/bfd/Makefile.am binutils-2.22/bfd/Makefile.am index ea4fd28..b08f975 100644 --- binutils-2.22.orig/bfd/Makefile.am +++ binutils-2.22/bfd/Makefile.am @@ -969,10 +969,13 @@ bfdver.h: $(srcdir)/version.h $(srcdir)/Makefile.in bfd_soversion="$(VERSION)" ;\ bfd_version_package="\"$(PKGVERSION)\"" ;\ report_bugs_to="\"$(REPORT_BUGS_TO)\"" ;\ + bfd_mspgcc_version=`sed -n -e 's/.*MSPGCC_VERSION //p' < $(srcdir)/version.h` ;\ if test "x$(RELEASE)" = x ; then \ bfd_version_date=`sed -n -e 's/.*DATE //p' < $(srcdir)/version.h` ;\ - bfd_version_string="\"$(VERSION).$${bfd_version_date}\"" ;\ + bfd_version_string="\"$(VERSION).$${bfd_version_date} (mspgcc $${bfd_mspgcc_version})\"" ;\ bfd_soversion="$(VERSION).$${bfd_version_date}" ;\ + else\ + bfd_version_string="\"$(VERSION) (mspgcc $${bfd_mspgcc_version})\"" ;\ fi ;\ sed -e "s,@bfd_version@,$$bfd_version," \ -e "s,@bfd_version_string@,$$bfd_version_string," \ diff --git binutils-2.22.orig/bfd/Makefile.in binutils-2.22/bfd/Makefile.in index 741809c..6c862e6 100644 --- binutils-2.22.orig/bfd/Makefile.in +++ binutils-2.22/bfd/Makefile.in @@ -2009,10 +2009,13 @@ bfdver.h: $(srcdir)/version.h $(srcdir)/Makefile.in bfd_soversion="$(VERSION)" ;\ bfd_version_package="\"$(PKGVERSION)\"" ;\ report_bugs_to="\"$(REPORT_BUGS_TO)\"" ;\ + bfd_mspgcc_version=`sed -n -e 's/.*MSPGCC_VERSION //p' < $(srcdir)/version.h` ;\ if test "x$(RELEASE)" = x ; then \ bfd_version_date=`sed -n -e 's/.*DATE //p' < $(srcdir)/version.h` ;\ - bfd_version_string="\"$(VERSION).$${bfd_version_date}\"" ;\ + bfd_version_string="\"$(VERSION).$${bfd_version_date} (mspgcc $${bfd_mspgcc_version})\"" ;\ bfd_soversion="$(VERSION).$${bfd_version_date}" ;\ + else\ + bfd_version_string="\"$(VERSION) (mspgcc $${bfd_mspgcc_version})\"" ;\ fi ;\ sed -e "s,@bfd_version@,$$bfd_version," \ -e "s,@bfd_version_string@,$$bfd_version_string," \ diff --git binutils-2.22.orig/bfd/archures.c binutils-2.22/bfd/archures.c index 44850e7..91f557f 100644 --- binutils-2.22.orig/bfd/archures.c +++ binutils-2.22/bfd/archures.c @@ -413,21 +413,8 @@ DESCRIPTION . bfd_arch_xstormy16, .#define bfd_mach_xstormy16 1 . bfd_arch_msp430, {* Texas Instruments MSP430 architecture. *} -.#define bfd_mach_msp11 11 -.#define bfd_mach_msp110 110 -.#define bfd_mach_msp12 12 -.#define bfd_mach_msp13 13 -.#define bfd_mach_msp14 14 -.#define bfd_mach_msp15 15 -.#define bfd_mach_msp16 16 -.#define bfd_mach_msp21 21 -.#define bfd_mach_msp31 31 -.#define bfd_mach_msp32 32 -.#define bfd_mach_msp33 33 -.#define bfd_mach_msp41 41 -.#define bfd_mach_msp42 42 -.#define bfd_mach_msp43 43 -.#define bfd_mach_msp44 44 +.#define bfd_mach_msp430 430 +.#define bfd_mach_msp430x 431 . bfd_arch_xc16x, {* Infineon's XC16X Series. *} .#define bfd_mach_xc16x 1 .#define bfd_mach_xc16xl 2 diff --git binutils-2.22.orig/bfd/bfd-in2.h binutils-2.22/bfd/bfd-in2.h index 22fcdf6..afd45a7 100644 --- binutils-2.22.orig/bfd/bfd-in2.h +++ binutils-2.22/bfd/bfd-in2.h @@ -2120,21 +2120,8 @@ enum bfd_architecture bfd_arch_xstormy16, #define bfd_mach_xstormy16 1 bfd_arch_msp430, /* Texas Instruments MSP430 architecture. */ -#define bfd_mach_msp11 11 -#define bfd_mach_msp110 110 -#define bfd_mach_msp12 12 -#define bfd_mach_msp13 13 -#define bfd_mach_msp14 14 -#define bfd_mach_msp15 15 -#define bfd_mach_msp16 16 -#define bfd_mach_msp21 21 -#define bfd_mach_msp31 31 -#define bfd_mach_msp32 32 -#define bfd_mach_msp33 33 -#define bfd_mach_msp41 41 -#define bfd_mach_msp42 42 -#define bfd_mach_msp43 43 -#define bfd_mach_msp44 44 +#define bfd_mach_msp430 430 +#define bfd_mach_msp430x 431 bfd_arch_xc16x, /* Infineon's XC16X Series. */ #define bfd_mach_xc16x 1 #define bfd_mach_xc16xl 2 @@ -4649,6 +4636,26 @@ This is the 5 bits of a value. */ BFD_RELOC_MSP430_16_BYTE, BFD_RELOC_MSP430_2X_PCREL, BFD_RELOC_MSP430_RL_PCREL, + BFD_RELOC_MSP430X_SRC_BYTE, + BFD_RELOC_MSP430X_SRC, + BFD_RELOC_MSP430X_DST_BYTE, + BFD_RELOC_MSP430X_DST, + BFD_RELOC_MSP430X_DST_2ND_BYTE, + BFD_RELOC_MSP430X_DST_2ND, + BFD_RELOC_MSP430X_PCREL_SRC_BYTE, + BFD_RELOC_MSP430X_PCREL_SRC, + BFD_RELOC_MSP430X_PCREL_DST_BYTE, + BFD_RELOC_MSP430X_PCREL_DST, + BFD_RELOC_MSP430X_PCREL_DST_2ND, + BFD_RELOC_MSP430X_PCREL_DST_2ND_BYTE, + BFD_RELOC_MSP430X_S_BYTE, + BFD_RELOC_MSP430X_S, + BFD_RELOC_MSP430X_D_BYTE, + BFD_RELOC_MSP430X_D, + BFD_RELOC_MSP430X_PCREL_D, + BFD_RELOC_MSP430X_INDXD, + BFD_RELOC_MSP430X_PCREL_INDXD, + BFD_RELOC_MSP430_10, /* IQ2000 Relocations. */ BFD_RELOC_IQ2000_OFFSET_16, diff --git binutils-2.22.orig/bfd/cpu-msp430.c binutils-2.22/bfd/cpu-msp430.c index 63c301a..2e85442 100644 --- binutils-2.22.orig/bfd/cpu-msp430.c +++ binutils-2.22/bfd/cpu-msp430.c @@ -23,86 +23,13 @@ #include "bfd.h" #include "libbfd.h" -static const bfd_arch_info_type *compatible - PARAMS ((const bfd_arch_info_type *, const bfd_arch_info_type *)); - -#define N(addr_bits, machine, print, default, next) \ -{ \ - 16, /* 16 bits in a word. */ \ - addr_bits, /* Bits in an address. */ \ - 8, /* 8 bits in a byte. */ \ - bfd_arch_msp430, \ - machine, /* Machine number. */ \ - "msp430", /* Architecture name. */ \ - print, /* Printable name. */ \ - 1, /* Section align power. */ \ - default, /* The default machine. */ \ - compatible, \ - bfd_default_scan, \ - next \ -} - -static const bfd_arch_info_type arch_info_struct[] = -{ - /* msp430x11x. */ - N (16, bfd_mach_msp11, "msp:11", FALSE, & arch_info_struct[1]), - - /* msp430x11x1. */ - N (16, bfd_mach_msp110, "msp:110", FALSE, & arch_info_struct[2]), - - /* msp430x12x. */ - N (16, bfd_mach_msp12, "msp:12", FALSE, & arch_info_struct[3]), - - /* msp430x13x. */ - N (16, bfd_mach_msp13, "msp:13", FALSE, & arch_info_struct[4]), - - /* msp430x14x. */ - N (16, bfd_mach_msp14, "msp:14", FALSE, & arch_info_struct[5]), - - /* msp430x15x. */ - N (16, bfd_mach_msp15, "msp:15", FALSE, & arch_info_struct[6]), - - /* msp430x16x. */ - N (16, bfd_mach_msp16, "msp:16", FALSE, & arch_info_struct[7]), - - /* msp430x21x. */ - N (16, bfd_mach_msp21, "msp:21", FALSE, & arch_info_struct[8]), - - /* msp430x31x. */ - N (16, bfd_mach_msp31, "msp:31", FALSE, & arch_info_struct[9]), - - /* msp430x32x. */ - N (16, bfd_mach_msp32, "msp:32", FALSE, & arch_info_struct[10]), - - /* msp430x33x. */ - N (16, bfd_mach_msp33, "msp:33", FALSE, & arch_info_struct[11]), - - /* msp430x41x. */ - N (16, bfd_mach_msp41, "msp:41", FALSE, & arch_info_struct[12]), - - /* msp430x42x. */ - N (16, bfd_mach_msp42, "msp:42", FALSE, & arch_info_struct[13]), - - /* msp430x43x. */ - N (16, bfd_mach_msp43, "msp:43", FALSE, & arch_info_struct[14]), - - /* msp430x44x. */ - N (16, bfd_mach_msp43, "msp:44", FALSE, NULL) -}; - -const bfd_arch_info_type bfd_msp430_arch = - N (16, bfd_mach_msp14, "msp:14", TRUE, & arch_info_struct[0]); - /* This routine is provided two arch_infos and works out which MSP machine which would be compatible with both and returns a pointer - to its info structure. */ - + to its info structure. */ static const bfd_arch_info_type * -compatible (a,b) - const bfd_arch_info_type * a; - const bfd_arch_info_type * b; +compatible (const bfd_arch_info_type * a, const bfd_arch_info_type * b) { - /* If a & b are for different architectures we can do nothing. */ + /* If a & b are for different architectures we can do nothing */ if (a->arch != b->arch) return NULL; @@ -111,3 +38,35 @@ compatible (a,b) return a; } + +/* Architecture for MSP430X and MSP430XV2 */ +static const bfd_arch_info_type bfd_msp430x_arch = { + 16, /* 16 bits in a word */ + 32, /* 20 padded to 32 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_msp430, + bfd_mach_msp430x, /* Machine number */ + "msp430", /* Architecture name. */ + "msp430:430X", /* Printable name */ + 1, /* Section align power */ + FALSE, /* The default machine */ + compatible, + bfd_default_scan, + 0 +}; + +/* Architecture for MSP430 */ +const bfd_arch_info_type bfd_msp430_arch = { + 16, /* 16 bits in a word */ + 16, /* 16 bits in an address */ + 8, /* 8 bits in a byte */ + bfd_arch_msp430, + bfd_mach_msp430, /* Machine number */ + "msp430", /* Architecture name */ + "msp430:430", /* Printable name */ + 1, /* Section align power */ + TRUE, /* The default machine */ + compatible, + bfd_default_scan, + &bfd_msp430x_arch +}; diff --git binutils-2.22.orig/bfd/elf32-msp430.c binutils-2.22/bfd/elf32-msp430.c index 9a5fb2a..23f286c 100644 --- binutils-2.22.orig/bfd/elf32-msp430.c +++ binutils-2.22/bfd/elf32-msp430.c @@ -1,5 +1,5 @@ /* MSP430-specific support for 32-bit ELF - Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2010 + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2010, 2012 Free Software Foundation, Inc. Contributed by Dmitry Diky @@ -26,19 +26,41 @@ #include "libbfd.h" #include "elf-bfd.h" #include "elf/msp430.h" +#include /* Use RELA instead of REL. */ #undef USE_REL -static reloc_howto_type elf_msp430_howto_table[] = -{ +#define MSP430_MASK_10(_x) ((_x) & 0x000003FF) +#define MSP430_MASK_16(_x) ((_x) & 0x0000FFFF) +#define MSP430_MASK_20(_x) ((_x) & 0x000FFFFF) + +/* Test that the value is representable in 16 bits, either signed or + * unsigned */ +#define MSP430_16_IN_RANGE(_v) ((_v) >= -((bfd_signed_vma)1 << 15) && (_v) < ((bfd_signed_vma)1 << 16)) + +/* Test that the value is representable in 15 bits, signed only */ +#define MSP430_S16_IN_RANGE(_v) ((_v) >= -((bfd_signed_vma)1 << 15) && (_v) < ((bfd_signed_vma)1 << 15)) + +/* Test that the value is representable in 20 bits, either signed or + * unsigned */ +#define MSP430_20_IN_RANGE(_v) ((_v) >= -((bfd_signed_vma)1 << 19) && (_v) < ((bfd_signed_vma)1 << 20)) + +/* Test that the value is representable in 10 bits, signed only */ +#define MSP430_S10_IN_RANGE(_v) ((_v) >= -((bfd_signed_vma)1 << 9) && (_v) < ((bfd_signed_vma)1 << 9)) + +/* Test whether the value is odd */ +#define MSP430_ODD(_v) ((_v) & 1) + +static reloc_howto_type elf_msp430_howto_table[] = { + /* BFD_RELOC_NONE */ HOWTO (R_MSP430_NONE, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 32, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ + complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MSP430_NONE", /* name */ FALSE, /* partial_inplace */ @@ -46,13 +68,15 @@ static reloc_howto_type elf_msp430_howto_table[] = 0, /* dst_mask */ FALSE), /* pcrel_offset */ + /* BFD_RELOC_32: Not used by msp430 back end, but invoked perhaps to + * write elf header fields. */ HOWTO (R_MSP430_32, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 32, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ + complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MSP430_32", /* name */ FALSE, /* partial_inplace */ @@ -60,29 +84,33 @@ static reloc_howto_type elf_msp430_howto_table[] = 0xffffffff, /* dst_mask */ FALSE), /* pcrel_offset */ - /* A 13 bit PC relative relocation. */ + /* BFD_RELOC_MSP430_10_PCREL: Same as BFD_RELOC_MSP430_10, but the + * offset of the storage location is subtracted prior to + * non-relocatable storage. */ HOWTO (R_MSP430_10_PCREL, /* type */ 1, /* rightshift */ 1, /* size (0 = byte, 1 = short, 2 = long) */ 10, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ + complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_13_PCREL", /* name */ + "R_MSP430_10_PCREL", /* name */ FALSE, /* partial_inplace */ - 0xfff, /* src_mask */ - 0xfff, /* dst_mask */ + 0x3ff, /* src_mask */ + 0x3ff, /* dst_mask */ TRUE), /* pcrel_offset */ - /* A 16 bit absolute relocation. */ + /* BFD_RELOC_MSP430_16: Same as BFD_RELOC_MSP430_16_BYTE, but + * enforces aligned access by rejecting final values that are not + * even. */ HOWTO (R_MSP430_16, /* type */ 0, /* rightshift */ 1, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ + complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MSP430_16", /* name */ FALSE, /* partial_inplace */ @@ -90,14 +118,16 @@ static reloc_howto_type elf_msp430_howto_table[] = 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ - /* A 16 bit absolute relocation for command address. */ + /* BFD_RELOC_MSP430_16_PCREL: Same as BFD_RELOC_MSP430_16, but the + * offset of the storage location is subtracted prior to + * non-relocatable storage. */ HOWTO (R_MSP430_16_PCREL, /* type */ 1, /* rightshift */ 1, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ + complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MSP430_16_PCREL", /* name */ FALSE, /* partial_inplace */ @@ -105,14 +135,16 @@ static reloc_howto_type elf_msp430_howto_table[] = 0xffff, /* dst_mask */ TRUE), /* pcrel_offset */ - /* A 16 bit absolute relocation, byte operations. */ + /* BFD_RELOC_MSP430_16_BYTE: A 16-bit value representing an + * immediate or offset, generally stored in a instruction word after + * an opcode. */ HOWTO (R_MSP430_16_BYTE, /* type */ 0, /* rightshift */ 1, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ FALSE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ + complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MSP430_16_BYTE", /* name */ FALSE, /* partial_inplace */ @@ -120,29 +152,31 @@ static reloc_howto_type elf_msp430_howto_table[] = 0xffff, /* dst_mask */ FALSE), /* pcrel_offset */ - /* A 16 bit absolute relocation for command address. */ - HOWTO (R_MSP430_16_PCREL_BYTE,/* type */ + /* BFD_RELOC_MSP430_16_PCREL_BYTE: Same as BFD_RELOC_MSP430_16_BYTE, + * but the offset of the storage location is subtracted prior to + * non-relocatable storage. */ + HOWTO (R_MSP430_16_PCREL_BYTE, /* type */ 1, /* rightshift */ 1, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ + complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ - "R_MSP430_16_PCREL_BYTE",/* name */ + "R_MSP430_16_PCREL_BYTE", /* name */ FALSE, /* partial_inplace */ 0xffff, /* src_mask */ 0xffff, /* dst_mask */ TRUE), /* pcrel_offset */ - /* A 13 bit PC relative relocation for complicated polymorphs. */ + /* OBSOLETE: A 13 bit PC relative relocation for complicated polymorphs. */ HOWTO (R_MSP430_2X_PCREL, /* type */ 1, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 10, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_bitfield,/* complain_on_overflow */ + complain_overflow_bitfield, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MSP430_2X_PCREL", /* name */ FALSE, /* partial_inplace */ @@ -150,20 +184,364 @@ static reloc_howto_type elf_msp430_howto_table[] = 0xfff, /* dst_mask */ TRUE), /* pcrel_offset */ - /* A 16 bit relaxable relocation for command address. */ + /* OBSOLETE: A 16 bit relaxable relocation for command address. */ HOWTO (R_MSP430_RL_PCREL, /* type */ 1, /* rightshift */ 1, /* size (0 = byte, 1 = short, 2 = long) */ 16, /* bitsize */ TRUE, /* pc_relative */ 0, /* bitpos */ - complain_overflow_dont,/* complain_on_overflow */ + complain_overflow_dont, /* complain_on_overflow */ bfd_elf_generic_reloc, /* special_function */ "R_MSP430_RL_PCREL", /* name */ FALSE, /* partial_inplace */ 0, /* src_mask */ 0xffff, /* dst_mask */ - TRUE) /* pcrel_offset */ + TRUE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_SRC_BYTE: A 20 bit absolute value: high 4 bits + * written into bits 10..7 of the extension word, low 16 bits + * written into the word after the opcode (+4). */ + HOWTO (R_MSP430X_SRC_BYTE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_SRC_BYTE", /* name */ + FALSE, /* partial_inplace */ + 0xfffff, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_SRC: Same as BFD_RELOC_MSP430X_SRC_BYTE, but + * enforces aligned access by rejecting final values that are not + * even. */ + HOWTO (R_MSP430X_SRC, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_SRC", /* name */ + FALSE, /* partial_inplace */ + 0xfffff, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_DST_BYTE: A 20 bit absolute value: high 4 bits + * written into bits 3..0 of the extension word, low 16 bits written + * into the word after the opcode (+4). */ + HOWTO (R_MSP430X_DST_BYTE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_DST_BYTE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xfffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_DST: Same as BFD_RELOC_MSP430X_DST_BYTE, but + * enforces aligned access by rejecting final values that are not + * even. */ + HOWTO (R_MSP430X_DST, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_DST", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xfffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_DST_2ND_BYTE: Same as + * BFD_RELOC_MSP430X_DST_BYTE, but the low 16 bits written two words + * after the opcode (+6). */ + HOWTO (R_MSP430X_DST_2ND_BYTE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_DST_2ND_BYTE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xfffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_DST_2ND: Same as + * BFD_RELOC_MSP430X_DST_2ND_BYTE, but enforces aligned access by + * rejecting final values that are not even. */ + HOWTO (R_MSP430X_DST_2ND, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_DST_2ND", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xfffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_PCREL_SRC_BYTE: Same as + * BFD_RELOC_MSP430X_SRC_BYTE, but the offset of the storage + * location is subtracted prior to non-relocatable storage. */ + HOWTO (R_MSP430X_PCREL_SRC_BYTE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_PCREL_SRC_BYTE", /* name */ + FALSE, /* partial_inplace */ + 0xfffff, /* src_mask */ + 0, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_PCREL_SRC: Same as BFD_RELOC_MSP430X_SRC, but + * the offset of the storage location is subtracted prior to + * non-relocatable storage. */ + HOWTO (R_MSP430X_PCREL_SRC, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_PCREL_SRC", /* name */ + FALSE, /* partial_inplace */ + 0xfffff, /* src_mask */ + 0, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_PCREL_DST_BYTE: Same as + * BFD_RELOC_MSP430X_DST_BYTE, but the offset of the storage + * location is subtracted prior to non-relocatable storage. */ + HOWTO (R_MSP430X_PCREL_DST_BYTE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_PCREL_DST_BYTE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xfffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_PCREL_DST: Same as BFD_RELOC_MSP430X_DST, but + * the offset of the storage location is subtracted prior to + * non-relocatable storage. */ + HOWTO (R_MSP430X_PCREL_DST, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_PCREL_DST", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xfffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_PCREL_DST_2ND: Same as + * BFD_RELOC_MSP430X_DST_2ND, but the offset of the storage location + * is subtracted prior to non-relocatable storage. */ + HOWTO (R_MSP430X_PCREL_DST_2ND, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_PCREL_DST_2ND", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xfffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_PCREL_DST_2ND_BYTE: Same as + * BFD_RELOC_MSP430X_DST_2ND_BYTE, but the offset of the storage + * location is subtracted prior to non-relocatable storage. */ + HOWTO (R_MSP430X_PCREL_DST_2ND_BYTE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_PCREL_DST_2ND_BYTE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xfffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_S_BYTE: A 20 bit absolute value for address + * instructions: high 4 bits written into bits 11..8 of the opcode + * word, low 16 bits written into the word after the opcode + * (+2). */ + HOWTO (R_MSP430X_S_BYTE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_S_BYTE", /* name */ + FALSE, /* partial_inplace */ + 0xfffff, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_S: Same as BFD_RELOC_MSP430X_S_BYTE, but + * enforces aligned access by rejecting final values that are not + * even. */ + HOWTO (R_MSP430X_S, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_S", /* name */ + FALSE, /* partial_inplace */ + 0xfffff, /* src_mask */ + 0, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_D_BYTE: A 20 bit absolute value for address + * instructions: high 4 bits written into bits 3..0 of the opcode + * word, low 16 bits written into the word after the opcode (+2). */ + HOWTO (R_MSP430X_D_BYTE, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_D_BYTE", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xfffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_D: Same as BFD_RELOC_MSP430X_D_BYTE, but + * enforces aligned access by rejecting final values that are not + * even. */ + HOWTO (R_MSP430X_D, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_D", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xfffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_PCREL_D: Same as BFD_RELOC_MSP430X_D, but the + * offset of the storage location is subtracted prior to + * non-relocatable storage. */ + HOWTO (R_MSP430X_PCREL_D, /* type */ + 0, /* rightshift */ + 2, /* size (0 = byte, 1 = short, 2 = long) */ + 20, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_PCREL_D", /* name */ + FALSE, /* partial_inplace */ + 0, /* src_mask */ + 0xfffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_INDXD: A 16 bit value that will be sign + * extended and added to a register to produce a 20-bit address for + * MOVA/CALLA insns: written into the word after the opcode (+2). */ + HOWTO (R_MSP430X_INDXD, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_INDXD", /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + FALSE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430X_PCREL_INDXD: Same as BFD_RELOC_MSP430X_INDXD, + * but the offset of the storage location is subtracted prior to + * non-relocatable storage. */ + HOWTO (R_MSP430X_PCREL_INDXD, /* type */ + 0, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 16, /* bitsize */ + TRUE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_dont, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430X_PCREL_INDXD", /* name */ + FALSE, /* partial_inplace */ + 0xffff, /* src_mask */ + 0xffff, /* dst_mask */ + TRUE), /* pcrel_offset */ + + /* BFD_RELOC_MSP430_10: A 10-bit value representing a PC-relative + * offset, used in conditional jump instructions. The relocation + * value is in bytes, although the representation in the instruction + * is in words. (NB: The fact-of PC-relative is encoded in the + * operation: the value itself is not adjusted except to convert + * from bytes to words.) */ + HOWTO (R_MSP430_10, /* type */ + 1, /* rightshift */ + 1, /* size (0 = byte, 1 = short, 2 = long) */ + 10, /* bitsize */ + FALSE, /* pc_relative */ + 0, /* bitpos */ + complain_overflow_bitfield, /* complain_on_overflow */ + bfd_elf_generic_reloc, /* special_function */ + "R_MSP430_10", /* name */ + FALSE, /* partial_inplace */ + 0x3ff, /* src_mask */ + 0x3ff, /* dst_mask */ + TRUE), /* pcrel_offset */ }; /* Map BFD reloc types to MSP430 ELF reloc types. */ @@ -174,19 +552,42 @@ struct msp430_reloc_map unsigned int elf_reloc_val; }; -static const struct msp430_reloc_map msp430_reloc_map[] = - { - {BFD_RELOC_NONE, R_MSP430_NONE}, - {BFD_RELOC_32, R_MSP430_32}, - {BFD_RELOC_MSP430_10_PCREL, R_MSP430_10_PCREL}, - {BFD_RELOC_16, R_MSP430_16_BYTE}, - {BFD_RELOC_MSP430_16_PCREL, R_MSP430_16_PCREL}, - {BFD_RELOC_MSP430_16, R_MSP430_16}, - {BFD_RELOC_MSP430_16_PCREL_BYTE, R_MSP430_16_PCREL_BYTE}, - {BFD_RELOC_MSP430_16_BYTE, R_MSP430_16_BYTE}, - {BFD_RELOC_MSP430_2X_PCREL, R_MSP430_2X_PCREL}, - {BFD_RELOC_MSP430_RL_PCREL, R_MSP430_RL_PCREL} - }; +static const struct msp430_reloc_map msp430_reloc_map[] = { + {BFD_RELOC_NONE, R_MSP430_NONE}, + {BFD_RELOC_32, R_MSP430_32}, + {BFD_RELOC_MSP430_10_PCREL, R_MSP430_10_PCREL}, + {BFD_RELOC_16, R_MSP430_16_BYTE}, + {BFD_RELOC_MSP430_16_PCREL, R_MSP430_16_PCREL}, + {BFD_RELOC_MSP430_16, R_MSP430_16}, + {BFD_RELOC_MSP430_16_PCREL_BYTE, R_MSP430_16_PCREL_BYTE}, + {BFD_RELOC_MSP430_16_BYTE, R_MSP430_16_BYTE}, + {BFD_RELOC_MSP430_2X_PCREL, R_MSP430_2X_PCREL}, + {BFD_RELOC_MSP430_RL_PCREL, R_MSP430_RL_PCREL}, + + {BFD_RELOC_MSP430X_SRC_BYTE, R_MSP430X_SRC_BYTE}, + {BFD_RELOC_MSP430X_SRC, R_MSP430X_SRC}, + {BFD_RELOC_MSP430X_DST_BYTE, R_MSP430X_DST_BYTE}, + {BFD_RELOC_MSP430X_DST, R_MSP430X_DST}, + {BFD_RELOC_MSP430X_DST_2ND_BYTE, R_MSP430X_DST_2ND_BYTE}, + {BFD_RELOC_MSP430X_DST_2ND, R_MSP430X_DST_2ND}, + + {BFD_RELOC_MSP430X_PCREL_SRC_BYTE, R_MSP430X_PCREL_SRC_BYTE}, + {BFD_RELOC_MSP430X_PCREL_SRC, R_MSP430X_PCREL_SRC}, + {BFD_RELOC_MSP430X_PCREL_DST_BYTE, R_MSP430X_PCREL_DST_BYTE}, + {BFD_RELOC_MSP430X_PCREL_DST, R_MSP430X_PCREL_DST}, + {BFD_RELOC_MSP430X_PCREL_DST_2ND_BYTE, R_MSP430X_PCREL_DST_2ND_BYTE}, + {BFD_RELOC_MSP430X_PCREL_DST_2ND, R_MSP430X_PCREL_DST_2ND}, + + {BFD_RELOC_MSP430X_S_BYTE, R_MSP430X_S_BYTE}, + {BFD_RELOC_MSP430X_S, R_MSP430X_S}, + {BFD_RELOC_MSP430X_D_BYTE, R_MSP430X_D_BYTE}, + {BFD_RELOC_MSP430X_D, R_MSP430X_D}, + {BFD_RELOC_MSP430X_PCREL_D, R_MSP430X_PCREL_D}, + {BFD_RELOC_MSP430X_INDXD, R_MSP430X_INDXD}, + {BFD_RELOC_MSP430X_PCREL_INDXD, R_MSP430X_PCREL_INDXD}, + + {BFD_RELOC_MSP430_10, R_MSP430_10}, +}; static reloc_howto_type * bfd_elf32_bfd_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, @@ -202,15 +603,12 @@ bfd_elf32_bfd_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED, } static reloc_howto_type * -bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, +bfd_elf32_bfd_reloc_name_lookup (bfd * abfd ATTRIBUTE_UNUSED, const char *r_name) { unsigned int i; - for (i = 0; - i < (sizeof (elf_msp430_howto_table) - / sizeof (elf_msp430_howto_table[0])); - i++) + for (i = 0; i < ARRAY_SIZE (elf_msp430_howto_table); i++) if (elf_msp430_howto_table[i].name != NULL && strcasecmp (elf_msp430_howto_table[i].name, r_name) == 0) return &elf_msp430_howto_table[i]; @@ -222,14 +620,19 @@ bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, static void msp430_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED, - arelent * cache_ptr, - Elf_Internal_Rela * dst) + arelent * cache_ptr, Elf_Internal_Rela * dst) { unsigned int r_type; r_type = ELF32_R_TYPE (dst->r_info); BFD_ASSERT (r_type < (unsigned int) R_MSP430_max); cache_ptr->howto = &elf_msp430_howto_table[r_type]; + if (r_type != cache_ptr->howto->type) + { + fprintf (stderr, "r_type %u != %u = %s\n", r_type, + cache_ptr->howto->type, cache_ptr->howto->name); + abort (); + } } /* Look through the relocs for a section during the first phase. @@ -237,7 +640,7 @@ msp430_info_to_howto_rela (bfd * abfd ATTRIBUTE_UNUSED, virtual table relocs for gc. */ static bfd_boolean -elf32_msp430_check_relocs (bfd * abfd, struct bfd_link_info * info, +elf32_msp430_check_relocs (bfd * abfd, struct bfd_link_info *info, asection * sec, const Elf_Internal_Rela * relocs) { Elf_Internal_Shdr *symtab_hdr; @@ -282,107 +685,171 @@ msp430_final_link_relocate (reloc_howto_type * howto, bfd * input_bfd, { bfd_reloc_status_type r = bfd_reloc_ok; bfd_vma x; - bfd_signed_vma srel; + bfd_signed_vma srel = 0; - switch (howto->type) + if (howto->type > R_MSP430_32 && howto->type < R_MSP430_max) { - case R_MSP430_10_PCREL: contents += rel->r_offset; srel = (bfd_signed_vma) relocation; srel += rel->r_addend; - srel -= rel->r_offset; - srel -= 2; /* Branch instructions add 2 to the PC... */ - srel -= (input_section->output_section->vma + - input_section->output_offset); - if (srel & 1) - return bfd_reloc_outofrange; + if (howto->pc_relative) + { + srel -= rel->r_offset; + srel -= (input_section->output_section->vma + + input_section->output_offset); + } + + switch (howto->type) + { + case R_MSP430_10_PCREL: + /* Account for r0 already being incremented by the time the + * value is applied. */ + srel -= 2; + break; + case R_MSP430X_PCREL_D: /* PC relative dst operand of calla */ + case R_MSP430X_PCREL_INDXD: /* 16-bit idx in mova/bra instruction PC relative (symbolic) mode operand */ + srel -= 2; /* operand located 2 bytes after opcode */ + break; + case R_MSP430X_PCREL_SRC: /* PC-relative 20-bit address operand */ + case R_MSP430X_PCREL_SRC_BYTE: + case R_MSP430X_PCREL_DST: + case R_MSP430X_PCREL_DST_BYTE: + srel -= 4; /* operand located 4 bytes after opcode */ + break; + case R_MSP430X_PCREL_DST_2ND: + case R_MSP430X_PCREL_DST_2ND_BYTE: + srel -= 6; /* operand located 6 bytes after opcode */ + break; + } + } + + switch (howto->type) + { + case R_MSP430_10: + case R_MSP430_10_PCREL: + if (MSP430_ODD (srel)) + r = bfd_reloc_dangerous; /* MSP430 addresses commands as words. */ srel >>= 1; - /* Check for an overflow. */ - if (srel < -512 || srel > 511) - return bfd_reloc_overflow; - x = bfd_get_16 (input_bfd, contents); - x = (x & 0xfc00) | (srel & 0x3ff); + x = (x & 0xfc00) | MSP430_MASK_10 (srel); bfd_put_16 (input_bfd, x, contents); + if (r == bfd_reloc_ok && !MSP430_S10_IN_RANGE (srel)) + r = bfd_reloc_overflow; break; case R_MSP430_2X_PCREL: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - srel -= rel->r_offset; - srel -= 2; /* Branch instructions add 2 to the PC... */ - srel -= (input_section->output_section->vma + - input_section->output_offset); - - if (srel & 1) - return bfd_reloc_outofrange; - - /* MSP430 addresses commands as words. */ - srel >>= 1; + case R_MSP430_RL_PCREL: + r = bfd_reloc_notsupported; + break; - /* Check for an overflow. */ - if (srel < -512 || srel > 511) - return bfd_reloc_overflow; + case R_MSP430_16: + case R_MSP430_16_PCREL: + if (MSP430_ODD (srel)) + r = bfd_reloc_dangerous; + /*FALLTHRU*/; + case R_MSP430_16_PCREL_BYTE: + case R_MSP430_16_BYTE: + bfd_put_16 (input_bfd, MSP430_MASK_16 (srel), contents); + if (r == bfd_reloc_ok && !MSP430_16_IN_RANGE (srel)) + r = bfd_reloc_overflow; + break; + case R_MSP430X_SRC: + case R_MSP430X_PCREL_SRC: + if (MSP430_ODD (srel)) + r = bfd_reloc_dangerous; + /*FALLTHRU*/; + case R_MSP430X_SRC_BYTE: + case R_MSP430X_PCREL_SRC_BYTE: + /* src(19:16) located at positions 10:7 of extension word */ + /* src(15:0) located just after opcode */ x = bfd_get_16 (input_bfd, contents); - x = (x & 0xfc00) | (srel & 0x3ff); + /* 4 most-significant bits */ + x = (x & 0xf87f) | ((srel >> 9) & 0x0780); bfd_put_16 (input_bfd, x, contents); - /* Handle second jump instruction. */ - x = bfd_get_16 (input_bfd, contents - 2); - srel += 1; - x = (x & 0xfc00) | (srel & 0x3ff); - bfd_put_16 (input_bfd, x, contents - 2); + /* 16 least-significant bits */ + bfd_put_16 (input_bfd, MSP430_MASK_16 (srel), contents + 4); + if (r == bfd_reloc_ok && !MSP430_20_IN_RANGE (srel)) + r = bfd_reloc_overflow; break; - case R_MSP430_16_PCREL: - case R_MSP430_RL_PCREL: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - srel -= rel->r_offset; - /* Only branch instructions add 2 to the PC... */ - srel -= (input_section->output_section->vma + - input_section->output_offset); - - if (srel & 1) - return bfd_reloc_outofrange; - - bfd_put_16 (input_bfd, srel & 0xffff, contents); + case R_MSP430X_DST: + case R_MSP430X_PCREL_DST: + if (MSP430_ODD (srel)) + r = bfd_reloc_dangerous; + /*FALLTHRU*/; + case R_MSP430X_DST_BYTE: + case R_MSP430X_PCREL_DST_BYTE: + /* dst(19:16) located at positions 3:0 of extension word */ + /* dst(15:0) located just after opcode */ + x = bfd_get_16 (input_bfd, contents); + x = (x & 0xfff0) | ((srel >> 16) & 0x000f); + bfd_put_16 (input_bfd, x, contents); + bfd_put_16 (input_bfd, MSP430_MASK_16 (srel), contents + 4); + if (r == bfd_reloc_ok && !MSP430_20_IN_RANGE (srel)) + r = bfd_reloc_overflow; break; - case R_MSP430_16_PCREL_BYTE: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - srel -= rel->r_offset; - /* Only branch instructions add 2 to the PC... */ - srel -= (input_section->output_section->vma + - input_section->output_offset); - - bfd_put_16 (input_bfd, srel & 0xffff, contents); + case R_MSP430X_DST_2ND: + case R_MSP430X_PCREL_DST_2ND: + if (MSP430_ODD (srel)) + r = bfd_reloc_dangerous; + /*FALLTHRU*/; + case R_MSP430X_DST_2ND_BYTE: + case R_MSP430X_PCREL_DST_2ND_BYTE: + /* dst(19:16) located at positions 3:0 of extension word */ + /* dst(15:0) located after src(15:0) */ + x = bfd_get_16 (input_bfd, contents); + x = (x & 0xfff0) | ((srel >> 16) & 0x000f); + bfd_put_16 (input_bfd, x, contents); + bfd_put_16 (input_bfd, MSP430_MASK_16 (srel), contents + 6); + if (r == bfd_reloc_ok && !MSP430_20_IN_RANGE (srel)) + r = bfd_reloc_overflow; break; - case R_MSP430_16_BYTE: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - bfd_put_16 (input_bfd, srel & 0xffff, contents); + case R_MSP430X_S: + if (MSP430_ODD (srel)) + r = bfd_reloc_dangerous; + /*FALLTHRU*/; + case R_MSP430X_S_BYTE: + x = bfd_get_16 (input_bfd, contents); + x = (x & 0xf0ff) | ((srel >> 8) & 0x0f00); + /* src(19:16) located at positions 11:8 of opcode */ + /* src(15:0) located just after opcode */ + bfd_put_16 (input_bfd, x, contents); + bfd_put_16 (input_bfd, MSP430_MASK_16 (srel), contents + 2); + if (r == bfd_reloc_ok && !MSP430_20_IN_RANGE (srel)) + r = bfd_reloc_overflow; break; - case R_MSP430_16: - contents += rel->r_offset; - srel = (bfd_signed_vma) relocation; - srel += rel->r_addend; - - if (srel & 1) - return bfd_reloc_notsupported; + case R_MSP430X_D: + case R_MSP430X_PCREL_D: + if (MSP430_ODD (srel)) + r = bfd_reloc_dangerous; + /*FALLTHRU*/; + case R_MSP430X_D_BYTE: + /* dst(19:16) located at positions 3:0 of opcode */ + /* dst(15:0) located just after opcode */ + x = bfd_get_16 (input_bfd, contents); + x = (x & 0xfff0) | ((srel >> 16) & 0x000f); + bfd_put_16 (input_bfd, x, contents); + bfd_put_16 (input_bfd, MSP430_MASK_16 (srel), contents + 2); + if (r == bfd_reloc_ok && !MSP430_20_IN_RANGE (srel)) + r = bfd_reloc_overflow; + break; - bfd_put_16 (input_bfd, srel & 0xffff, contents); + case R_MSP430X_PCREL_INDXD: + if (MSP430_ODD (srel)) /*odd address */ + r = bfd_reloc_dangerous; + /*FALLTHRU*/; + case R_MSP430X_INDXD: + bfd_put_16 (input_bfd, MSP430_MASK_16 (srel), contents + 2); + if (r == bfd_reloc_ok && !MSP430_S16_IN_RANGE (srel)) + r = bfd_reloc_overflow; break; default: @@ -398,7 +865,7 @@ msp430_final_link_relocate (reloc_howto_type * howto, bfd * input_bfd, static bfd_boolean elf32_msp430_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, - struct bfd_link_info * info, + struct bfd_link_info *info, bfd * input_bfd, asection * input_section, bfd_byte * contents, @@ -441,7 +908,7 @@ elf32_msp430_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); name = bfd_elf_string_from_elf_section - (input_bfd, symtab_hdr->sh_link, sym->st_name); + (input_bfd, symtab_hdr->sh_link, sym->st_name); name = (name == NULL) ? bfd_section_name (input_bfd, sec) : name; } else @@ -459,7 +926,12 @@ elf32_msp430_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, rel, relend, howto, contents); if (info->relocatable) - continue; + { + BFD_ASSERT (!howto->partial_inplace); + if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION) + rel->r_addend += sec->output_offset; + continue; + } r = msp430_final_link_relocate (howto, input_bfd, input_section, contents, rel, relocation); @@ -472,14 +944,13 @@ elf32_msp430_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, { case bfd_reloc_overflow: r = info->callbacks->reloc_overflow - (info, (h ? &h->root : NULL), name, howto->name, - (bfd_vma) 0, input_bfd, input_section, - rel->r_offset); + (info, (h ? &h->root : NULL), name, howto->name, + (bfd_vma) 0, input_bfd, input_section, rel->r_offset); break; case bfd_reloc_undefined: r = info->callbacks->undefined_symbol - (info, name, input_bfd, input_section, rel->r_offset, TRUE); + (info, name, input_bfd, input_section, rel->r_offset, TRUE); break; case bfd_reloc_outofrange: @@ -491,7 +962,8 @@ elf32_msp430_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, break; case bfd_reloc_dangerous: - msg = _("internal error: dangerous relocation"); + r = info->callbacks->reloc_dangerous + (info, _("unaligned address"), input_bfd, input_section, rel->r_offset); break; default: @@ -501,7 +973,7 @@ elf32_msp430_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, if (msg) r = info->callbacks->warning - (info, msg, name, input_bfd, input_section, rel->r_offset); + (info, msg, name, input_bfd, input_section, rel->r_offset); if (!r) return FALSE; @@ -517,646 +989,133 @@ elf32_msp430_relocate_section (bfd * output_bfd ATTRIBUTE_UNUSED, number. */ static void -bfd_elf_msp430_final_write_processing (bfd * abfd, - bfd_boolean linker ATTRIBUTE_UNUSED) +msp430_elf_backend_final_write_processing (bfd * abfd, + bfd_boolean linker + ATTRIBUTE_UNUSED) { - unsigned long val; + Elf_Internal_Ehdr *i_ehdrp; + unsigned long flags; + i_ehdrp = elf_elfheader (abfd); + i_ehdrp->e_machine = EM_MSP430; + flags = 0; switch (bfd_get_mach (abfd)) { default: - case bfd_mach_msp110: - val = E_MSP430_MACH_MSP430x11x1; - break; - - case bfd_mach_msp11: - val = E_MSP430_MACH_MSP430x11; - break; - - case bfd_mach_msp12: - val = E_MSP430_MACH_MSP430x12; - break; - - case bfd_mach_msp13: - val = E_MSP430_MACH_MSP430x13; - break; - - case bfd_mach_msp14: - val = E_MSP430_MACH_MSP430x14; - break; - - case bfd_mach_msp15: - val = E_MSP430_MACH_MSP430x15; + case bfd_mach_msp430: + flags = EF_MSP430_ARCH_430; break; - - case bfd_mach_msp16: - val = E_MSP430_MACH_MSP430x16; - break; - - case bfd_mach_msp31: - val = E_MSP430_MACH_MSP430x31; - break; - - case bfd_mach_msp32: - val = E_MSP430_MACH_MSP430x32; - break; - - case bfd_mach_msp33: - val = E_MSP430_MACH_MSP430x33; - break; - - case bfd_mach_msp41: - val = E_MSP430_MACH_MSP430x41; - break; - - case bfd_mach_msp42: - val = E_MSP430_MACH_MSP430x42; - break; - - case bfd_mach_msp43: - val = E_MSP430_MACH_MSP430x43; - break; - - case bfd_mach_msp44: - val = E_MSP430_MACH_MSP430x44; + case bfd_mach_msp430x: + flags = EF_MSP430_ARCH_430X; break; } - - elf_elfheader (abfd)->e_machine = EM_MSP430; - elf_elfheader (abfd)->e_flags &= ~EF_MSP430_MACH; - elf_elfheader (abfd)->e_flags |= val; + i_ehdrp->e_flags = EF_MSP430_UNIARCH | flags; } /* Set the right machine number. */ static bfd_boolean -elf32_msp430_object_p (bfd * abfd) +msp430_elf_backend_object_p (bfd * abfd ATTRIBUTE_UNUSED) { - int e_set = bfd_mach_msp14; + Elf_Internal_Ehdr *i_ehdrp; + int bfd_mach; - if (elf_elfheader (abfd)->e_machine == EM_MSP430 - || elf_elfheader (abfd)->e_machine == EM_MSP430_OLD) + i_ehdrp = elf_elfheader (abfd); + if (EM_MSP430 != i_ehdrp->e_machine) + return FALSE; + if (EF_MSP430_UNIARCH & i_ehdrp->e_flags) { - int e_mach = elf_elfheader (abfd)->e_flags & EF_MSP430_MACH; - - switch (e_mach) + switch (i_ehdrp->e_flags & EF_MSP430_ARCH) { default: - case E_MSP430_MACH_MSP430x11: - e_set = bfd_mach_msp11; + case EF_MSP430_ARCH_430: + bfd_mach = bfd_mach_msp430; break; - - case E_MSP430_MACH_MSP430x11x1: - e_set = bfd_mach_msp110; - break; - - case E_MSP430_MACH_MSP430x12: - e_set = bfd_mach_msp12; - break; - - case E_MSP430_MACH_MSP430x13: - e_set = bfd_mach_msp13; - break; - - case E_MSP430_MACH_MSP430x14: - e_set = bfd_mach_msp14; - break; - - case E_MSP430_MACH_MSP430x15: - e_set = bfd_mach_msp15; - break; - - case E_MSP430_MACH_MSP430x16: - e_set = bfd_mach_msp16; - break; - - case E_MSP430_MACH_MSP430x31: - e_set = bfd_mach_msp31; - break; - - case E_MSP430_MACH_MSP430x32: - e_set = bfd_mach_msp32; - break; - - case E_MSP430_MACH_MSP430x33: - e_set = bfd_mach_msp33; - break; - - case E_MSP430_MACH_MSP430x41: - e_set = bfd_mach_msp41; - break; - - case E_MSP430_MACH_MSP430x42: - e_set = bfd_mach_msp42; - break; - - case E_MSP430_MACH_MSP430x43: - e_set = bfd_mach_msp43; - break; - - case E_MSP430_MACH_MSP430x44: - e_set = bfd_mach_msp44; + case EF_MSP430_ARCH_430X: + bfd_mach = bfd_mach_msp430x; break; } } - - return bfd_default_set_arch_mach (abfd, bfd_arch_msp430, e_set); -} - -/* These functions handle relaxing for the msp430. - Relaxation required only in two cases: - - Bad hand coding like jumps from one section to another or - from file to file. - - Sibling calls. This will affect onlu 'jump label' polymorph. Without - relaxing this enlarges code by 2 bytes. Sibcalls implemented but - do not work in gcc's port by the reason I do not know. - Anyway, if a relaxation required, user should pass -relax option to the - linker. - - There are quite a few relaxing opportunities available on the msp430: - - ================================================================ - - 1. 3 words -> 1 word - - eq == jeq label jne +4; br lab - ne != jne label jeq +4; br lab - lt < jl label jge +4; br lab - ltu < jlo label lhs +4; br lab - ge >= jge label jl +4; br lab - geu >= jhs label jlo +4; br lab - - 2. 4 words -> 1 word - - ltn < jn jn +2; jmp +4; br lab - - 3. 4 words -> 2 words - - gt > jeq +2; jge label jeq +6; jl +4; br label - gtu > jeq +2; jhs label jeq +6; jlo +4; br label - - 4. 4 words -> 2 words and 2 labels - - leu <= jeq label; jlo label jeq +2; jhs +4; br label - le <= jeq label; jl label jeq +2; jge +4; br label - ================================================================= - - codemap for first cases is (labels masked ): - eq: 0x2002,0x4010,0x0000 -> 0x2400 - ne: 0x2402,0x4010,0x0000 -> 0x2000 - lt: 0x3402,0x4010,0x0000 -> 0x3800 - ltu: 0x2c02,0x4010,0x0000 -> 0x2800 - ge: 0x3802,0x4010,0x0000 -> 0x3400 - geu: 0x2802,0x4010,0x0000 -> 0x2c00 - - second case: - ltn: 0x3001,0x3c02,0x4010,0x0000 -> 0x3000 - - third case: - gt: 0x2403,0x3802,0x4010,0x0000 -> 0x2401,0x3400 - gtu: 0x2403,0x2802,0x4010,0x0000 -> 0x2401,0x2c00 - - fourth case: - leu: 0x2401,0x2c02,0x4010,0x0000 -> 0x2400,0x2800 - le: 0x2401,0x3402,0x4010,0x0000 -> 0x2400,0x3800 - - Unspecified case :) - jump: 0x4010,0x0000 -> 0x3c00. */ - -#define NUMB_RELAX_CODES 12 -static struct rcodes_s -{ - int f0, f1; /* From code. */ - int t0, t1; /* To code. */ - int labels; /* Position of labels: 1 - one label at first - word, 2 - one at second word, 3 - two - labels at both. */ - int cdx; /* Words to match. */ - int bs; /* Shrink bytes. */ - int off; /* Offset from old label for new code. */ - int ncl; /* New code length. */ -} rcode[] = -{/* lab,cdx,bs,off,ncl */ - { 0x0000, 0x0000, 0x3c00, 0x0000, 1, 0, 2, 2, 2}, /* jump */ - { 0x0000, 0x2002, 0x2400, 0x0000, 1, 1, 4, 4, 2}, /* eq */ - { 0x0000, 0x2402, 0x2000, 0x0000, 1, 1, 4, 4, 2}, /* ne */ - { 0x0000, 0x3402, 0x3800, 0x0000, 1, 1, 4, 4, 2}, /* lt */ - { 0x0000, 0x2c02, 0x2800, 0x0000, 1, 1, 4, 4, 2}, /* ltu */ - { 0x0000, 0x3802, 0x3400, 0x0000, 1, 1, 4, 4, 2}, /* ge */ - { 0x0000, 0x2802, 0x2c00, 0x0000, 1, 1, 4, 4, 2}, /* geu */ - { 0x3001, 0x3c02, 0x3000, 0x0000, 1, 2, 6, 6, 2}, /* ltn */ - { 0x2403, 0x3802, 0x2401, 0x3400, 2, 2, 4, 6, 4}, /* gt */ - { 0x2403, 0x2802, 0x2401, 0x2c00, 2, 2, 4, 6, 4}, /* gtu */ - { 0x2401, 0x2c02, 0x2400, 0x2800, 3, 2, 4, 6, 4}, /* leu , 2 labels */ - { 0x2401, 0x2c02, 0x2400, 0x2800, 3, 2, 4, 6, 4}, /* le , 2 labels */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0} -}; - -/* Return TRUE if a symbol exists at the given address. */ - -static bfd_boolean -msp430_elf_symbol_address_p (bfd * abfd, - asection * sec, - Elf_Internal_Sym * isym, - bfd_vma addr) -{ - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - Elf_Internal_Sym *isymend; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); - - /* Examine all the local symbols. */ - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) - if (isym->st_shndx == sec_shndx && isym->st_value == addr) - return TRUE; - - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) + else { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value == addr) - return TRUE; + bfd_mach = bfd_mach_msp430; } - - return FALSE; + return bfd_default_set_arch_mach (abfd, bfd_arch_msp430, bfd_mach); } -/* Adjust all local symbols defined as '.section + 0xXXXX' (.section has sec_shndx) - referenced from current and other sections */ -static bfd_boolean -msp430_elf_relax_adjust_locals(bfd * abfd, asection * sec, bfd_vma addr, - int count, unsigned int sec_shndx, bfd_vma toaddr) +static char * +decode_cpux_target (int bits, + char * buffer, + size_t buflen) { - Elf_Internal_Shdr *symtab_hdr; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *irelend; - Elf_Internal_Sym *isym; - - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; - symtab_hdr = & elf_tdata (abfd)->symtab_hdr; - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - - for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) - { - int sidx = ELF32_R_SYM(irel->r_info); - Elf_Internal_Sym *lsym = isym + sidx; - - /* Adjust symbols referenced by .sec+0xXX */ - if (irel->r_addend > addr && irel->r_addend < toaddr - && lsym->st_shndx == sec_shndx) - irel->r_addend -= count; - } - - return TRUE; + size_t nw = 0; + + buffer[nw] = 0; + if (bits & TAG_CPUX_TARGET_A20) + nw += snprintf(buffer + nw, buflen - nw, " -ma20"); + if (bits & TAG_CPUX_TARGET_C20) + nw += snprintf(buffer + nw, buflen - nw, " -mc20"); + if (bits & TAG_CPUX_TARGET_D20) + nw += snprintf(buffer + nw, buflen - nw, " -md20"); + if (bits & TAG_CPUX_TARGET_SR20) + nw += snprintf(buffer + nw, buflen - nw, " -msr20"); + if (bits & TAG_CPUX_TARGET_ISR20) + nw += snprintf(buffer + nw, buflen - nw, " -misr20"); + return buffer; } -/* Delete some bytes from a section while relaxing. */ - static bfd_boolean -msp430_elf_relax_delete_bytes (bfd * abfd, asection * sec, bfd_vma addr, - int count) +msp430_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) { - Elf_Internal_Shdr *symtab_hdr; - unsigned int sec_shndx; - bfd_byte *contents; - Elf_Internal_Rela *irel; - Elf_Internal_Rela *irelend; - bfd_vma toaddr; - Elf_Internal_Sym *isym; - Elf_Internal_Sym *isymend; - struct elf_link_hash_entry **sym_hashes; - struct elf_link_hash_entry **end_hashes; - unsigned int symcount; - asection *p; - - sec_shndx = _bfd_elf_section_from_bfd_section (abfd, sec); + obj_attribute *in_attrs, *out_attrs; + obj_attribute *in_target, *out_target; - contents = elf_section_data (sec)->this_hdr.contents; - - toaddr = sec->size; - - irel = elf_section_data (sec)->relocs; - irelend = irel + sec->reloc_count; - - /* Actually delete the bytes. */ - memmove (contents + addr, contents + addr + count, - (size_t) (toaddr - addr - count)); - sec->size -= count; - - /* Adjust all the relocs. */ - symtab_hdr = & elf_tdata (abfd)->symtab_hdr; - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - for (irel = elf_section_data (sec)->relocs; irel < irelend; irel++) + if (!elf_known_obj_attributes_proc (obfd)[0].i) { - /* Get the new reloc address. */ - if ((irel->r_offset > addr && irel->r_offset < toaddr)) - irel->r_offset -= count; - } - - for (p = abfd->sections; p != NULL; p = p->next) - msp430_elf_relax_adjust_locals(abfd,p,addr,count,sec_shndx,toaddr); - - /* Adjust the local symbols defined in this section. */ - symtab_hdr = & elf_tdata (abfd)->symtab_hdr; - isym = (Elf_Internal_Sym *) symtab_hdr->contents; - for (isymend = isym + symtab_hdr->sh_info; isym < isymend; isym++) - if (isym->st_shndx == sec_shndx - && isym->st_value > addr && isym->st_value < toaddr) - isym->st_value -= count; - - /* Now adjust the global symbols defined in this section. */ - symcount = (symtab_hdr->sh_size / sizeof (Elf32_External_Sym) - - symtab_hdr->sh_info); - sym_hashes = elf_sym_hashes (abfd); - end_hashes = sym_hashes + symcount; - for (; sym_hashes < end_hashes; sym_hashes++) - { - struct elf_link_hash_entry *sym_hash = *sym_hashes; - - if ((sym_hash->root.type == bfd_link_hash_defined - || sym_hash->root.type == bfd_link_hash_defweak) - && sym_hash->root.u.def.section == sec - && sym_hash->root.u.def.value > addr - && sym_hash->root.u.def.value < toaddr) - sym_hash->root.u.def.value -= count; - } - - return TRUE; -} - - -static bfd_boolean -msp430_elf_relax_section (bfd * abfd, asection * sec, - struct bfd_link_info * link_info, - bfd_boolean * again) -{ - Elf_Internal_Shdr * symtab_hdr; - Elf_Internal_Rela * internal_relocs; - Elf_Internal_Rela * irel; - Elf_Internal_Rela * irelend; - bfd_byte * contents = NULL; - Elf_Internal_Sym * isymbuf = NULL; - - /* Assume nothing changes. */ - *again = FALSE; - - /* We don't have to do anything for a relocatable link, if - this section does not have relocs, or if this is not a - code section. */ - if (link_info->relocatable - || (sec->flags & SEC_RELOC) == 0 - || sec->reloc_count == 0 || (sec->flags & SEC_CODE) == 0) - return TRUE; - - symtab_hdr = & elf_tdata (abfd)->symtab_hdr; - - /* Get a copy of the native relocations. */ - internal_relocs = - _bfd_elf_link_read_relocs (abfd, sec, NULL, NULL, link_info->keep_memory); - if (internal_relocs == NULL) - goto error_return; - - /* Walk through them looking for relaxing opportunities. */ - irelend = internal_relocs + sec->reloc_count; - for (irel = internal_relocs; irel < irelend; irel++) - { - bfd_vma symval; - - /* If this isn't something that can be relaxed, then ignore - this reloc. */ - if (ELF32_R_TYPE (irel->r_info) != (int) R_MSP430_RL_PCREL) - continue; - - /* Get the section contents if we haven't done so already. */ - if (contents == NULL) - { - /* Get cached copy if it exists. */ - if (elf_section_data (sec)->this_hdr.contents != NULL) - contents = elf_section_data (sec)->this_hdr.contents; - else if (! bfd_malloc_and_get_section (abfd, sec, &contents)) - goto error_return; - } + /* This is the first object. Copy the attributes. */ + _bfd_elf_copy_obj_attributes (ibfd, obfd); - /* Read this BFD's local symbols if we haven't done so already. */ - if (isymbuf == NULL && symtab_hdr->sh_info != 0) - { - isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; - if (isymbuf == NULL) - isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, - symtab_hdr->sh_info, 0, - NULL, NULL, NULL); - if (isymbuf == NULL) - goto error_return; - } + /* Use the Tag_null value to indicate the attributes have been + initialized. */ + elf_known_obj_attributes_proc (obfd)[0].i = 1; - /* Get the value of the symbol referred to by the reloc. */ - if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) - { - /* A local symbol. */ - Elf_Internal_Sym *isym; - asection *sym_sec; - - isym = isymbuf + ELF32_R_SYM (irel->r_info); - if (isym->st_shndx == SHN_UNDEF) - sym_sec = bfd_und_section_ptr; - else if (isym->st_shndx == SHN_ABS) - sym_sec = bfd_abs_section_ptr; - else if (isym->st_shndx == SHN_COMMON) - sym_sec = bfd_com_section_ptr; - else - sym_sec = bfd_section_from_elf_index (abfd, isym->st_shndx); - symval = (isym->st_value - + sym_sec->output_section->vma + sym_sec->output_offset); - } - else - { - unsigned long indx; - struct elf_link_hash_entry *h; - - /* An external symbol. */ - indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; - h = elf_sym_hashes (abfd)[indx]; - BFD_ASSERT (h != NULL); - - if (h->root.type != bfd_link_hash_defined - && h->root.type != bfd_link_hash_defweak) - /* This appears to be a reference to an undefined - symbol. Just ignore it--it will be caught by the - regular reloc processing. */ - continue; - - symval = (h->root.u.def.value - + h->root.u.def.section->output_section->vma - + h->root.u.def.section->output_offset); - } - - /* For simplicity of coding, we are going to modify the section - contents, the section relocs, and the BFD symbol table. We - must tell the rest of the code not to free up this - information. It would be possible to instead create a table - of changes which have to be made, as is done in coff-mips.c; - that would be more work, but would require less memory when - the linker is run. */ - - /* Try to turn a 16bit pc-relative branch into a 10bit pc-relative - branch. */ - /* Paranoia? paranoia... */ - if (ELF32_R_TYPE (irel->r_info) == (int) R_MSP430_RL_PCREL) - { - bfd_vma value = symval; - - /* Deal with pc-relative gunk. */ - value -= (sec->output_section->vma + sec->output_offset); - value -= irel->r_offset; - value += irel->r_addend; - - /* See if the value will fit in 10 bits, note the high value is - 1016 as the target will be two bytes closer if we are - able to relax. */ - if ((long) value < 1016 && (long) value > -1016) - { - int code0 = 0, code1 = 0, code2 = 0; - int i; - struct rcodes_s *rx; - - /* Get the opcode. */ - if (irel->r_offset >= 6) - code0 = bfd_get_16 (abfd, contents + irel->r_offset - 6); - - if (irel->r_offset >= 4) - code1 = bfd_get_16 (abfd, contents + irel->r_offset - 4); - - code2 = bfd_get_16 (abfd, contents + irel->r_offset - 2); - - if (code2 != 0x4010) - continue; - - /* Check r4 and r3. */ - for (i = NUMB_RELAX_CODES - 1; i >= 0; i--) - { - rx = &rcode[i]; - if (rx->cdx == 2 && rx->f0 == code0 && rx->f1 == code1) - break; - else if (rx->cdx == 1 && rx->f1 == code1) - break; - else if (rx->cdx == 0) /* This is an unconditional jump. */ - break; - } - - /* Check labels: - .Label0: ; we do not care about this label - jeq +6 - .Label1: ; make sure there is no label here - jl +4 - .Label2: ; make sure there is no label here - br .Label_dst - - So, if there is .Label1 or .Label2 we cannot relax this code. - This actually should not happen, cause for relaxable - instructions we use RL_PCREL reloc instead of 16_PCREL. - Will change this in the future. */ - - if (rx->cdx > 0 - && msp430_elf_symbol_address_p (abfd, sec, isymbuf, - irel->r_offset - 2)) - continue; - if (rx->cdx > 1 - && msp430_elf_symbol_address_p (abfd, sec, isymbuf, - irel->r_offset - 4)) - continue; - - /* Note that we've changed the relocs, section contents, etc. */ - elf_section_data (sec)->relocs = internal_relocs; - elf_section_data (sec)->this_hdr.contents = contents; - symtab_hdr->contents = (unsigned char *) isymbuf; - - /* Fix the relocation's type. */ - if (rx->labels == 3) /* Handle special cases. */ - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MSP430_2X_PCREL); - else - irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), - R_MSP430_10_PCREL); - - /* Fix the opcode right way. */ - bfd_put_16 (abfd, rx->t0, contents + irel->r_offset - rx->off); - if (rx->t1) - bfd_put_16 (abfd, rx->t1, - contents + irel->r_offset - rx->off + 2); - - /* Delete bytes. */ - if (!msp430_elf_relax_delete_bytes (abfd, sec, - irel->r_offset - rx->off + - rx->ncl, rx->bs)) - goto error_return; - - /* Handle unconditional jumps. */ - if (rx->cdx == 0) - irel->r_offset -= 2; - - /* That will change things, so, we should relax again. - Note that this is not required, and it may be slow. */ - *again = TRUE; - } - } + return TRUE; } - if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) - { - if (!link_info->keep_memory) - free (isymbuf); - else - { - /* Cache the symbols for elf_link_input_bfd. */ - symtab_hdr->contents = (unsigned char *) isymbuf; - } - } + in_attrs = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU]; + out_attrs = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) + in_target = &in_attrs[Tag_GNU_MSP430_CPUX_TARGET]; + out_target = &out_attrs[Tag_GNU_MSP430_CPUX_TARGET]; + if (! (in_target->i & TAG_CPUX_TARGET_IGNORE) + && ! (out_target->i & TAG_CPUX_TARGET_CONFLICT) + && in_target->i != out_target->i) { - if (!link_info->keep_memory) - free (contents); + out_target->type = 1; + if (out_target->i == 0) + ; + else if (in_target->i == 0) + _bfd_error_handler (_("Warning: %B does not have CPUX target data"), ibfd); + else if (in_target->i & TAG_CPUX_TARGET_CONFLICT) + _bfd_error_handler (_("Warning: %B records previous CPUX target flag conflict"), ibfd); else { - /* Cache the section contents for elf_link_input_bfd. */ - elf_section_data (sec)->this_hdr.contents = contents; + char in_decode[32]; + char out_decode[32]; + + /* Yes, the arguments to this are right: the BFD args + precede standard printf args */ + decode_cpux_target (in_target->i, in_decode, sizeof(in_decode)); + decode_cpux_target (out_target->i, out_decode, sizeof(out_decode)); + _bfd_error_handler (_("Warning: Conflicting CPUX target flags\n\t%B:%s\n\t%B:%s"), + ibfd, obfd, in_decode, out_decode); + out_target->i |= TAG_CPUX_TARGET_CONFLICT; } + out_target->i |= in_target->i; } - - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return TRUE; - -error_return: - if (isymbuf != NULL && symtab_hdr->contents != (unsigned char *) isymbuf) - free (isymbuf); - if (contents != NULL - && elf_section_data (sec)->this_hdr.contents != contents) - free (contents); - if (internal_relocs != NULL - && elf_section_data (sec)->relocs != internal_relocs) - free (internal_relocs); - - return FALSE; + return _bfd_elf_merge_object_attributes (ibfd, obfd); } - #define ELF_ARCH bfd_arch_msp430 #define ELF_MACHINE_CODE EM_MSP430 #define ELF_MACHINE_ALT1 EM_MSP430_OLD @@ -1167,13 +1126,12 @@ error_return: #define TARGET_LITTLE_NAME "elf32-msp430" #define elf_info_to_howto msp430_info_to_howto_rela -#define elf_info_to_howto_rel NULL #define elf_backend_relocate_section elf32_msp430_relocate_section #define elf_backend_check_relocs elf32_msp430_check_relocs #define elf_backend_can_gc_sections 1 -#define elf_backend_final_write_processing bfd_elf_msp430_final_write_processing -#define elf_backend_object_p elf32_msp430_object_p #define elf_backend_post_process_headers _bfd_elf_set_osabi -#define bfd_elf32_bfd_relax_section msp430_elf_relax_section +#define elf_backend_final_write_processing msp430_elf_backend_final_write_processing +#define elf_backend_object_p msp430_elf_backend_object_p +#define bfd_elf32_bfd_merge_private_bfd_data msp430_elf_merge_private_bfd_data #include "elf32-target.h" diff --git binutils-2.22.orig/bfd/libbfd.h binutils-2.22/bfd/libbfd.h index 200a6fa..149aa21 100644 --- binutils-2.22.orig/bfd/libbfd.h +++ binutils-2.22/bfd/libbfd.h @@ -2219,6 +2219,26 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@", "BFD_RELOC_MSP430_16_BYTE", "BFD_RELOC_MSP430_2X_PCREL", "BFD_RELOC_MSP430_RL_PCREL", + "BFD_RELOC_MSP430X_SRC_BYTE", + "BFD_RELOC_MSP430X_SRC", + "BFD_RELOC_MSP430X_DST_BYTE", + "BFD_RELOC_MSP430X_DST", + "BFD_RELOC_MSP430X_DST_2ND_BYTE", + "BFD_RELOC_MSP430X_DST_2ND", + "BFD_RELOC_MSP430X_PCREL_SRC_BYTE", + "BFD_RELOC_MSP430X_PCREL_SRC", + "BFD_RELOC_MSP430X_PCREL_DST_BYTE", + "BFD_RELOC_MSP430X_PCREL_DST", + "BFD_RELOC_MSP430X_PCREL_DST_2ND", + "BFD_RELOC_MSP430X_PCREL_DST_2ND_BYTE", + "BFD_RELOC_MSP430X_S_BYTE", + "BFD_RELOC_MSP430X_S", + "BFD_RELOC_MSP430X_D_BYTE", + "BFD_RELOC_MSP430X_D", + "BFD_RELOC_MSP430X_PCREL_D", + "BFD_RELOC_MSP430X_INDXD", + "BFD_RELOC_MSP430X_PCREL_INDXD", + "BFD_RELOC_MSP430_10", "BFD_RELOC_IQ2000_OFFSET_16", "BFD_RELOC_IQ2000_OFFSET_21", "BFD_RELOC_IQ2000_UHI16", diff --git binutils-2.22.orig/bfd/reloc.c binutils-2.22/bfd/reloc.c index 6ac7148..6b24d9e 100644 --- binutils-2.22.orig/bfd/reloc.c +++ binutils-2.22/bfd/reloc.c @@ -5314,6 +5314,46 @@ ENUMX BFD_RELOC_MSP430_2X_PCREL ENUMX BFD_RELOC_MSP430_RL_PCREL +ENUMX + BFD_RELOC_MSP430X_SRC_BYTE +ENUMX + BFD_RELOC_MSP430X_SRC +ENUMX + BFD_RELOC_MSP430X_DST_BYTE +ENUMX + BFD_RELOC_MSP430X_DST +ENUMX + BFD_RELOC_MSP430X_DST_2ND_BYTE +ENUMX + BFD_RELOC_MSP430X_DST_2ND +ENUMX + BFD_RELOC_MSP430X_PCREL_SRC_BYTE +ENUMX + BFD_RELOC_MSP430X_PCREL_SRC +ENUMX + BFD_RELOC_MSP430X_PCREL_DST_BYTE +ENUMX + BFD_RELOC_MSP430X_PCREL_DST +ENUMX + BFD_RELOC_MSP430X_PCREL_DST_2ND +ENUMX + BFD_RELOC_MSP430X_PCREL_DST_2ND_BYTE +ENUMX + BFD_RELOC_MSP430X_S_BYTE +ENUMX + BFD_RELOC_MSP430X_S +ENUMX + BFD_RELOC_MSP430X_D_BYTE +ENUMX + BFD_RELOC_MSP430X_D +ENUMX + BFD_RELOC_MSP430X_PCREL_D +ENUMX + BFD_RELOC_MSP430X_INDXD +ENUMX + BFD_RELOC_MSP430X_PCREL_INDXD +ENUMX + BFD_RELOC_MSP430_10 ENUMDOC msp430 specific relocation codes diff --git binutils-2.22.orig/bfd/version.h binutils-2.22/bfd/version.h index c6800ec..2767280 100644 --- binutils-2.22.orig/bfd/version.h +++ binutils-2.22/bfd/version.h @@ -1,4 +1,5 @@ #define BFD_VERSION_DATE 20111121 +#define BFD_MSPGCC_VERSION dev 20120911 #define BFD_VERSION @bfd_version@ #define BFD_VERSION_STRING @bfd_version_package@ @bfd_version_string@ #define REPORT_BUGS_TO @report_bugs_to@ diff --git binutils-2.22.orig/binutils/readelf.c binutils-2.22/binutils/readelf.c index 9e13190..492214e 100644 --- binutils-2.22.orig/binutils/readelf.c +++ binutils-2.22/binutils/readelf.c @@ -11237,6 +11237,56 @@ display_mips_gnu_attribute (unsigned char * p, int tag) } static unsigned char * +display_msp430_gnu_attribute (unsigned char * p, int tag) +{ + int type; + unsigned int len; + int val; + + if (tag == Tag_GNU_MSP430_CPUX_TARGET) + { + int elts = 0; + + val = read_uleb128 (p, &len); + p += len; + printf (" Tag_GNU_MSP430_CPUX_TARGET: "); + + if (val & TAG_CPUX_TARGET_A20) + printf("%sa20", elts++ ? "," : ""); + if (val & TAG_CPUX_TARGET_C20) + printf("%sc20", elts++ ? "," : ""); + if (val & TAG_CPUX_TARGET_D20) + printf("%sd20", elts++ ? "," : ""); + if (val & TAG_CPUX_TARGET_SR20) + printf("%ssr20", elts++ ? "," : ""); + if (val & TAG_CPUX_TARGET_ISR20) + printf("%sisr20", elts++ ? "," : ""); + putchar('\n'); + return p; + } + + if (tag & 1) + type = 1; /* String. */ + else + type = 2; /* uleb128. */ + printf (" Tag_unknown_%d: ", tag); + + if (type == 1) + { + printf ("\"%s\"\n", p); + p += strlen ((char *) p) + 1; + } + else + { + val = read_uleb128 (p, &len); + p += len; + printf ("%d (0x%x)\n", val, val); + } + + return p; +} + +static unsigned char * display_tic6x_attribute (unsigned char * p) { int tag; @@ -11620,6 +11670,13 @@ process_arm_specific (FILE * file) } static int +process_msp430_specific (FILE * file) +{ + return process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL, + display_msp430_gnu_attribute); +} + +static int process_power_specific (FILE * file) { return process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL, @@ -12984,6 +13041,9 @@ process_arch_specific (FILE * file) case EM_MIPS_RS3_LE: return process_mips_specific (file); break; + case EM_MSP430: + return process_msp430_specific (file); + break; case EM_PPC: return process_power_specific (file); break; diff --git binutils-2.22.orig/gas/config/tc-msp430.c binutils-2.22/gas/config/tc-msp430.c index 98d90c6..b24f3b5 100644 --- binutils-2.22.orig/gas/config/tc-msp430.c +++ binutils-2.22/gas/config/tc-msp430.c @@ -1,6 +1,6 @@ /* tc-msp430.c -- Assembler code for the Texas Instruments MSP430 - Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010 + Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2009, 2010, 2012 Free Software Foundation, Inc. Contributed by Dmitry Diky @@ -23,143 +23,14 @@ #include -#define PUSH_1X_WORKAROUND #include "as.h" #include "subsegs.h" #include "opcode/msp430.h" #include "safe-ctype.h" #include "dwarf2dbg.h" +#include "elf/msp430.h" -/* We will disable polymorphs by default because it is dangerous. - The potential problem here is the following: assume we got the - following code: - - jump .l1 - nop - jump subroutine ; external symbol - .l1: - nop - ret - - In case of assembly time relaxation we'll get: - 0: jmp .l1 <.text +0x08> (reloc deleted) - 2: nop - 4: br subroutine - .l1: - 8: nop - 10: ret - - If the 'subroutine' is within +-1024 bytes range then linker - will produce: - 0: jmp .text +0x08 - 2: nop - 4: jmp subroutine - .l1: - 6: nop - 8: ret ; 'jmp .text +0x08' will land here. WRONG!!! - - The workaround is the following: - 1. Declare global var enable_polymorphs which set to 1 via option -mp. - 2. Declare global var enable_relax which set to 1 via option -mQ. - - If polymorphs are enabled, and relax isn't, treat all jumps as long jumps, - do not delete any relocs and leave them for linker. - - If relax is enabled, relax at assembly time and kill relocs as necessary. */ - -int msp430_enable_relax; -int msp430_enable_polys; - -/* GCC uses the some condition codes which we'll - implement as new polymorph instructions. - - COND EXPL SHORT JUMP LONG JUMP - =============================================== - eq == jeq jne +4; br lab - ne != jne jeq +4; br lab - - ltn honours no-overflow flag - ltn < jn jn +2; jmp +4; br lab - - lt < jl jge +4; br lab - ltu < jlo lhs +4; br lab - le <= see below - leu <= see below - - gt > see below - gtu > see below - ge >= jge jl +4; br lab - geu >= jhs jlo +4; br lab - =============================================== - - Therefore, new opcodes are (BranchEQ -> beq; and so on...) - beq,bne,blt,bltn,bltu,bge,bgeu - 'u' means unsigned compares - - Also, we add 'jump' instruction: - jump UNCOND -> jmp br lab - - They will have fmt == 4, and insn_opnumb == number of instruction. */ - -struct rcodes_s -{ - char * name; - int index; /* Corresponding insn_opnumb. */ - int sop; /* Opcode if jump length is short. */ - long lpos; /* Label position. */ - long lop0; /* Opcode 1 _word_ (16 bits). */ - long lop1; /* Opcode second word. */ - long lop2; /* Opcode third word. */ -}; - -#define MSP430_RLC(n,i,sop,o1) \ - {#n, i, sop, 2, (o1 + 2), 0x4010, 0} - -static struct rcodes_s msp430_rcodes[] = -{ - MSP430_RLC (beq, 0, 0x2400, 0x2000), - MSP430_RLC (bne, 1, 0x2000, 0x2400), - MSP430_RLC (blt, 2, 0x3800, 0x3400), - MSP430_RLC (bltu, 3, 0x2800, 0x2c00), - MSP430_RLC (bge, 4, 0x3400, 0x3800), - MSP430_RLC (bgeu, 5, 0x2c00, 0x2800), - {"bltn", 6, 0x3000, 3, 0x3000 + 1, 0x3c00 + 2,0x4010}, - {"jump", 7, 0x3c00, 1, 0x4010, 0, 0}, - {0,0,0,0,0,0,0} -}; -#undef MSP430_RLC - - -/* More difficult than above and they have format 5. - - COND EXPL SHORT LONG - ================================================================= - gt > jeq +2; jge label jeq +6; jl +4; br label - gtu > jeq +2; jhs label jeq +6; jlo +4; br label - leu <= jeq label; jlo label jeq +2; jhs +4; br label - le <= jeq label; jl label jeq +2; jge +4; br label - ================================================================= */ - -struct hcodes_s -{ - char * name; - int index; /* Corresponding insn_opnumb. */ - int tlab; /* Number of labels in short mode. */ - int op0; /* Opcode for first word of short jump. */ - int op1; /* Opcode for second word of short jump. */ - int lop0; /* Opcodes for long jump mode. */ - int lop1; - int lop2; -}; - -static struct hcodes_s msp430_hcodes[] = -{ - {"bgt", 0, 1, 0x2401, 0x3400, 0x2403, 0x3802, 0x4010 }, - {"bgtu", 1, 1, 0x2401, 0x2c00, 0x2403, 0x2802, 0x4010 }, - {"bleu", 2, 2, 0x2400, 0x2800, 0x2401, 0x2c02, 0x4010 }, - {"ble", 3, 2, 0x2400, 0x3800, 0x2401, 0x3402, 0x4010 }, - {0,0,0,0,0,0,0,0} -}; +static int msp430x_repeats; const char comment_chars[] = ";"; const char line_comment_chars[] = "#"; @@ -167,177 +38,596 @@ const char line_separator_chars[] = "{"; const char EXP_CHARS[] = "eE"; const char FLT_CHARS[] = "dD"; -/* Handle long expressions. */ -extern LITTLENUM_TYPE generic_bignum[]; - static struct hash_control *msp430_hash; - -/* Relaxations. */ -#define STATE_UNCOND_BRANCH 1 /* jump */ -#define STATE_NOOV_BRANCH 3 /* bltn */ -#define STATE_SIMPLE_BRANCH 2 /* bne, beq, etc... */ -#define STATE_EMUL_BRANCH 4 - -#define CNRL 2 -#define CUBL 4 -#define CNOL 8 -#define CSBL 6 -#define CEBL 4 - -/* Length. */ -#define STATE_BITS10 1 /* wild guess. short jump */ -#define STATE_WORD 2 /* 2 bytes pc rel. addr. more */ -#define STATE_UNDEF 3 /* cannot handle this yet. convert to word mode */ - -#define ENCODE_RELAX(what,length) (((what) << 2) + (length)) -#define RELAX_STATE(s) ((s) & 3) -#define RELAX_LEN(s) ((s) >> 2) -#define RELAX_NEXT(a,b) ENCODE_RELAX (a, b + 1) - -relax_typeS md_relax_table[] = +static symbolS *msp430_register_table[REGNO_MAX + 1]; + +/* TRUE iff the operand includes an offset encoded into or after the + * instruction (formerly mode==OP_EXP). */ +#define OP_HAS_IMMEDIATE(_op) \ + (((_op).am == AMs_Immediate && (_op).reg == REGNO_PC) \ + ||((_op).am == AM_Indexed && (_op).reg != REGNO_CG2)) + +/* TRUE iff the operand is an index offset to a register that might + * have an odd value. This is used in verifying that the actual + * offset may be even, thus allowing its use for aligned addresses. */ +#define OP_INDEXED_PERMITS_ODD(_op) \ + ((_op).am == AM_Indexed \ + && (_op).reg != REGNO_PC \ + && (_op).reg != REGNO_CG1 \ + && (_op).reg != REGNO_SP) + +/* TRUE iff the operand is an immediate appearing in a destination + * operand in a context where the value of that immediate is permitted + * to be odd. This is a legacy check to ensure that offsets added to + * registers known to be even will produce a word-aligned address + * (legacy did not check SP, which this does). */ +#define OP_DST_IMMEDIATE_PERMITS_ODD(_op) \ + OP_INDEXED_PERMITS_ODD(_op) + +/* TRUE iff the operand is an immediate appearing in a source operand + * in a context where the value of that immediate is permitted to be + * odd. This is a legacy check to ensure that offsets added to + * registers known to be even will produce a word-aligned address + * (legacy did not check SP, which this does). */ +#define OP_SRC_IMMEDIATE_PERMITS_ODD(_op) \ + (((_op).am == AMs_Immediate && (_op).reg == REGNO_PC) \ + || OP_DST_IMMEDIATE_PERMITS_ODD(_op)) + +enum immediate_range_e { - /* Unused. */ - {1, 1, 0, 0}, - {1, 1, 0, 0}, - {1, 1, 0, 0}, - {1, 1, 0, 0}, - - /* Unconditional jump. */ - {1, 1, 8, 5}, - {1024, -1024, CNRL, RELAX_NEXT (STATE_UNCOND_BRANCH, STATE_BITS10)}, /* state 10 bits displ */ - {0, 0, CUBL, RELAX_NEXT (STATE_UNCOND_BRANCH, STATE_WORD)}, /* state word */ - {1, 1, CUBL, 0}, /* state undef */ - - /* Simple branches. */ - {0, 0, 8, 9}, - {1024, -1024, CNRL, RELAX_NEXT (STATE_SIMPLE_BRANCH, STATE_BITS10)}, /* state 10 bits displ */ - {0, 0, CSBL, RELAX_NEXT (STATE_SIMPLE_BRANCH, STATE_WORD)}, /* state word */ - {1, 1, CSBL, 0}, - - /* blt no overflow branch. */ - {1, 1, 8, 13}, - {1024, -1024, CNRL, RELAX_NEXT (STATE_NOOV_BRANCH, STATE_BITS10)}, /* state 10 bits displ */ - {0, 0, CNOL, RELAX_NEXT (STATE_NOOV_BRANCH, STATE_WORD)}, /* state word */ - {1, 1, CNOL, 0}, - - /* Emulated branches. */ - {1, 1, 8, 17}, - {1020, -1020, CEBL, RELAX_NEXT (STATE_EMUL_BRANCH, STATE_BITS10)}, /* state 10 bits displ */ - {0, 0, CNOL, RELAX_NEXT (STATE_EMUL_BRANCH, STATE_WORD)}, /* state word */ - {1, 1, CNOL, 0} + IMM_RANGE_INT16, /* signed 16-bit integer */ + IMM_RANGE_INT20, /* signed 20-bit integer */ + IMM_RANGE_REPETITION_COUNT, /* repetition count 1..16 */ + IMM_RANGE_ROTATE_COUNT, /* rotation count 1..4 */ }; +/* Test that the value is representable in 16 bits, either signed or + * unsigned */ +#define MSP430_16_IN_RANGE(_v) ((_v) >= -((offsetT)1 << 15) && (_v) < ((offsetT)1 << 16)) -#define MAX_OP_LEN 256 +/* Test that the value is representable in 15 bits, signed only */ +#define MSP430_S16_IN_RANGE(_v) ((_v) >= -((offsetT)1 << 15) && (_v) < ((offsetT)1 << 15)) -struct mcu_type_s +/* Test that the value is representable in 20 bits, either signed or + * unsigned */ +#define MSP430_20_IN_RANGE(_v) ((_v) >= -((offsetT)1 << 19) && (_v) < ((offsetT)1 << 20)) + +/* Test that the value is representable in 10 bits, signed only */ +#define MSP430_S10_IN_RANGE(_v) ((_v) >= -((offsetT)1 << 9) && (_v) < ((offsetT)1 << 9)) + +/* Test whether the value is odd */ +#define MSP430_ODD(_v) ((_v) & 1) + +static int +valid_immediate (offsetT value, enum immediate_range_e imm_range) { - char * name; - int isa; - int mach; -}; + bfd_boolean valid; + switch (imm_range) + { + case IMM_RANGE_INT16: + valid = MSP430_16_IN_RANGE (value); + if (!valid) + as_bad (_("value %ld out of range for 16-bit immediate"), + (long int) value); + break; + case IMM_RANGE_INT20: + valid = MSP430_20_IN_RANGE (value); + if (!valid) + as_bad (_("value %ld out of range for 20-bit immediate"), + (long int) value); + break; + case IMM_RANGE_REPETITION_COUNT: + valid = value >= 1 && value <= 16; + if (!valid) + as_bad (_("value %ld not a repetition count (1..16)"), + (long int) value); + break; + case IMM_RANGE_ROTATE_COUNT: + valid = value >= 1 && value <= 4; + if (!valid) + as_bad (_("value %ld not a rotate count (1..4)"), (long int) value); + break; + default: + gas_assert (0); + valid = FALSE; + } + return valid; +} -#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_21 21 -#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 CHECK_RELOC_MSP430 ((imm_op || byte_op)?BFD_RELOC_MSP430_16_BYTE:BFD_RELOC_MSP430_16) -#define CHECK_RELOC_MSP430_PCREL ((imm_op || byte_op)?BFD_RELOC_MSP430_16_PCREL_BYTE:BFD_RELOC_MSP430_16_PCREL) - -static struct mcu_type_s mcu_types[] = +/** List known silicon errata with a description of the problem (where + * this can be found). Errata descriptions are available in PDF files + * that can be found on the device-specific web page at TI. Errata + * numbers are consistent across the product line. + * + * Note that not all documented errata are currently recognized by the + * assembler. In fact, most are completely ignored. Future work... + * + * Legacy errata descriptions are from previous versions of + * binutils. */ +typedef enum msp430_errata_e { - {"msp1", MSP430_ISA_11, bfd_mach_msp11}, - {"msp2", MSP430_ISA_14, bfd_mach_msp14}, - {"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}, - - {"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}, - - {"msp430x2101", MSP430_ISA_21, bfd_mach_msp21}, - {"msp430x2111", MSP430_ISA_21, bfd_mach_msp21}, - {"msp430x2121", MSP430_ISA_21, bfd_mach_msp21}, - {"msp430x2131", MSP430_ISA_21, bfd_mach_msp21}, - - {"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}, - - {"msp430xE423", MSP430_ISA_42, bfd_mach_msp42}, - {"msp430xE425", MSP430_ISA_42, bfd_mach_msp42}, - {"msp430xE427", 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}, - {"msp430x436", MSP430_ISA_43, bfd_mach_msp43}, - {"msp430x437", 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}, - - {NULL, 0, 0} + /* CPU4: PUSH #4, PUSH #8 + * + * The single operand instruction PUSH cannot use the internal + * constants (CG) 4 and 8. The other internal constants (0, 1, 2, + * –1) can be used. The number of clock cycles is different: + * + * - PUSH #CG uses address mode 00, requiring 3 cycles, 1-word instruction + * - PUSH #4/#8 uses address mode 11, requiring 5 cycles, 2-word instruction + * + * Workaround: + * - Assembler generate code not referencing constant generator + */ + ERRATUM_CPU4 = 4, + + /* CALL and PUSH with @SP+, @SP, and X(SP) uses the SP to calculate the address, then decrements it */ + ERRATUM_CPU7 = 7, + + /* CPU8: Using odd values in the SP register + * + * The SP can be written with odd values. In the original CPU, an + * odd SP value could be combined with an odd offset (for example, + * mov. #value, 5(SP)). In the new CPU, the SP can be written with + * an odd value, but the first time the SP is used, the LSB is + * forced to 0. + * + * Workaround: + * - Do not use odd values with the SP. + */ + ERRATUM_CPU8 = 8, /* UNHANDLED */ + + /* CPU11: Invalid status register after program counter access + * + * When addressing the program counter (PC) in register mode when + * the PC is the destination, the Status Register (SR) may be + * erroneous. The instructions BIS, BIC, and MOV do not affect SR + * contents. Only CPU flags are affected. This bug does not apply to + * LPMx control bits. + * + * Workaround: None + */ + ERRATUM_CPU11 = 11, /* UNHANDLED */ + + /* CPU12: CMP or BIT with PC destination + * + * Any instruction immediately following a CMP(.B) or BIT(.B) + * instruction when the PC is the destination address using register + * mode is ignored or erroneously executed. When the following + * instruction is longer than one word, the second word is fetched + * by the CPU and decoded as the instruction, leading to + * unpredictable behavior. Affected source-addressing modes are + * indexed and indirect addressing modes. + * + * Example: + * cmp &200,PC + * add #4,R8 + * The add command is not executed. + * + * Workaround: + * - Insert a NOP instruction after the BIT or CMP instruction. The + * NOP is ignored, and program execution continues as expected. + */ + ERRATUM_CPU12 = 12, /* UNHANDLED */ + + /* CPU13: Arithmetic operations and the SR + * + * Performing arithmetic operations with the Status Register (SR) as + * the destination address does not update the SR as intended. The + * result in SR can be invalid, leading to erroneous low-power mode + * entry. Arithmetic operations are defined as all instructions that + * modify the SR flag bits (RRA, SUB, XOR, and ADD, for example). + * + * Workaround: None + */ + ERRATUM_CPU13 = 13, /* UNHANDLED */ + + /* CPU15: Modifying the Program Counter (PC) behaves differently + * than in previous devices + * + * When using instructions with immediate or indirect addressing + * mode to modify the PC, a different value compared to previous + * devices must be added to get to the same destination. + * + * NOTE: The MOV instruction is not affected + * + * Example: Previous device (MSP430F4619) + * label_1 ADD.W #Branch1-label_1-4h,PC + * MSP430F5438: + * label_1 ADD.W #Branch1-label_1-2h,PC + * + * Workaround: + * - Additional NOP after the PC-modifying instruction; or + * - Change the offset value in software + */ + ERRATUM_CPU15 = 15, /* UNHANDLED */ + + /* CPU16 Indexed addressing with instructions calla, mova, and bra + * + * With indexed addressing mode and instructions calla, mova, and bra, it is not possible + * to reach memory above 64k if the register content is < 64k. + * Example: Assume R5 = FFFEh. The instruction calla 0004h(R5) results in a 20-bit call + * of address 0002h instead of 10002h. + * + * Workaround: + * - Use different addressing mode to reach memory above 64k. + * - First use adda [index],[Rx] to calculate address in upper memory and then use + * calla [Rx]. + */ + ERRATUM_CPU16 = 16, /* UNHANDLED */ + + /* CPU18: LPM instruction can corrupt PC/SR registers + * + * The PC and SR registers have the potential to be corrupted when: + * - An instruction using register, absolute, indexed, indirect, + * indirect auto-increment, or symbolic mode is used to set the + * LPM bits (for example, BIS &xyh, SR). + * and + * - This instruction is followed by a CALL or CALLA instruction. + * + * Upon servicing an interrupt service routine, the program counter + * (PC) is pushed twice onto the stack instead of the correct + * operation where the PC, then the SR registers are pushed onto the + * stack. This corrupts the SR and possibly the PC on RETI from the + * ISR. + * + * Workaround: + * - Insert a NOP or __no_operation() intrinsic function between the + * instruction to enter low-power mode and the CALL or CALLA + * instruction. + */ + ERRATUM_CPU18 = 18, /* UNHANDLED */ + + /* CPU19: CPUOFF can change register values + * + * If a CPUOFF command is followed by an instruction with an + * indirect addressed operand (for example, mov @R8, R9, and RET), + * an unintentional register-read operation can occur during the + * wakeup of the CPU. If the unintentional read occurs to a + * read-sensitive register (for example, UCB0RXBUF or TAIV), which + * changes its value or the value of other registers (IFGs), the bug + * leads to lost interrupts or wrong register read values. + * + * Workaround: + * - Insert a NOP instruction after each CPUOFF instruction. + */ + ERRATUM_CPU19 = 19, /* UNHANDLED */ + + /* CPU20: An unexpected Vacant Memory Access Flag (VMAIFG) can be + * triggered due to the CPU autoincrement of the MAB + 2 + * outside the range of a valid memory block. + * + * The VMAIFG is triggered if a PC-modifying instruction (for + * example, ret, push, call, pop, jmp, br) is fetched from the last + * address of a section of memory (for example, flash or RAM) that + * is not contiguous to a higher valid section on the memory map. + * + * Workaround: + * - If code is affected, edit the linker command file to make the + * last four bytes of affected memory sections unavailable. + */ + ERRATUM_CPU20 = 20, /* UNHANDLED */ + + /* NO DESCRIPTION */ + ERRATUM_CPU21 = 21, /* UNHANDLED */ + + /* NO DESCRIPTION */ + ERRATUM_CPU22 = 22, /* UNHANDLED */ + + /* NO DESCRIPTION */ + ERRATUM_CPU23 = 23, /* UNHANDLED */ + + /* CPU24: Program counter corruption following entry into low power mode + * + * The program counter is corrupted when an interrupt event occurs + * in the time between (and including) one cycle before and one + * cycle after the CPUOFF bit is set in the status register. This + * failure occurs when the BIS instruction is followed by a CALL or + * CALLA instruction using the following addressing modes: + * + * - BIS &, SR + * CALLA indir, indir autoinc, reg + * + * - BIS INDEX, SR + * CALLA indir, indir autoinc, reg + * + * - BIS reg, SR + * CALLA reg, indir, indir autoinc + * + * Due to the instruction emulation, the EINT instruction, as well + * as the __enable_interrupts() and possibly the __bis_SR_register() + * intrinsic functions are affected. + * + * Workaround: + * - Insert a NOP instruction or __no_operation() intrinsic function + * call between the BIS and CALL or CALLA instructions. + */ + ERRATUM_CPU24 = 24, /* UNHANDLED */ + + /* CPU25: DMA transfer does not execute during low power mode + * + * If the following instruction sequence is used ([] denotes an + * addressing mode): + * + * BIS [register|index|absolute|symbolic],SR + * CALLA [register] + * + * ...to enter a low power mode, AND the DMARMWDIS bit is set then + * DMA transfers will be blocked for the duration of the low power + * mode. + * + * Workaround: + * 1. Insert a NOP instruction or __no_operation() intrinsic + * function call between the BIS and CALLA instructions ... OR + * ... + * 2. Temporarily clear the DMARMWDIS bit when entering low power + * mode + */ + ERRATUM_CPU25 = 25, /* UNHANDLED */ + + /* CPU26: CALL SP does not behave as expected + * + * When the intention is to execute code from the stack, a CALL SP + * instruction skips the first piece of data (instruction) on the + * stack. The second piece of data at SP + 2 is used as the first + * executable instruction. + * + * Workaround: + * - Write the op code for a NOP as the first instruction on the + * stack. Begin the intended subroutine at address SP + 2. + */ + ERRATUM_CPU26 = 26, /* UNHANDLED */ + + /* CPU27: Program Counter (PC) is corrupted during the context save + * of a nested interrupt + * + * When a low-power mode is entered within an interrupt service + * routine that has enabled nested interrupts (by setting the GIE + * bit), and the instruction that sets the low-power mode is + * directly followed by a RETI instruction, an incorrect value of PC + * + 2 is pushed to the stack during the context save. Hence, the + * RETI instruction is not executed on return from the nested + * interrupt, and the PC becomes corrupted. + * + * Workaround: + * - Insert a NOP or __no_operation() intrinsic function between the + * instruction that sets the lower power mode and the RETI + * instruction. + */ + ERRATUM_CPU27 = 27, /* UNHANDLED */ + + /* CPU28: PC is corrupted when using certain extended addressing + * mode combinations + * + * An extended memory instruction that modifies the program counter + * executes incorrectly when preceded by an extended memory + * write-back instruction under the following conditions: + * + * - First instruction: + * 2-operand instruction, extended mode using (register,index), + * (register,absolute), or (register,symbolic) addressing modes + * - Second instruction: + * 2-operand instruction, extended mode using the (indirect,PC), + * (indirect auto-increment,PC), or (indexed [with ind 0], PC) + * addressing modes + * + * Example: + * BISX.A R6,&AABCD + * ANDX.A @R4+,PC + * + * Workaround: + * - Insert a NOP or a __no_operation() intrinsic function between + * the two instructions. + * or + * - Do not use an extended memory instruction to modify the PC. + */ + ERRATUM_CPU28 = 28, /* UNHANDLED */ + + /* CPU29: Using a certain instruction sequence to enter low-power + * mode(s) affects the instruction width of the first + * instruction in an NMI ISR + * + * If there is a pending NMI request when the CPU enters a low-power + * mode (LPMx) using an instruction of Indexed source addressing + * mode, and that instruction is followed by a 20-bit wide + * instruction of Register source and Destination addressing modes, + * the first instruction of the ISR is executed as a 20-bit wide + * instruction. + * + * Example: + * main: + * ... + * MOV.W [indexed],SR ; Enter LPMx + * MOVX.A [register],[register] ; 20-bit wide instruction + * ... + * ISR_start: + * MOV.B [indexed],[register] ; ERROR - Executed as a 20-bit instruction! + * + * Note: [ ] indicates addressing mode + * + * Workaround: + * - Insert a NOP or a __no_operation() intrinsic function following + * the instruction that enters the LPMx using indexed addressing + * mode. + * or + * - Use a NOP or a __no_operation() intrinsic function as first + * instruction in the ISR. + * or + * - Do not use the indexed mode to enter LPMx. + */ + ERRATUM_CPU29 = 29, /* UNHANDLED */ + + /* CPU30: ADDA, SUBA, CMPA [immediate],PC behave as if immediate + * value were offset by -2 + * + * The extended address instructions ADDA, SUBA, and CMPA in + * immediate addressing mode are represented by 4 bytes of opcode + * (see the MSP430F5xx Family User's Guide (SLAU208) for more + * details). In cases where the program counter (PC) is used as the + * destination register, only 2 bytes of the current instruction's + * 4-byte opcode are accounted for in the PC value. The resulting + * operation executes as if the immediate value were offset by a + * value of -2. + * + * Example: + * Ideal: ADDA #Immediate-4, PC + * ...is equivalent to... + * Actual: ADDA #Immediate-2, PC + * NOTE: The MOV instruction is not affected. + * + * Workaround: + * - Modify immediate value in software to account for the offset of 2. + * or + * - Use extended 20-bit instructions (addx.a, subx.a, cmpx.a) instead. + */ + ERRATUM_CPU30 = 30, /* UNHANDLED */ + + /* CPU31: Instruction PUSHX.A @SP+ corrupts stack pointer + * + * When the instruction PUSHX.A is executed using the indirect + * auto-increment mode with the stack pointer (SP) as the source + * register [PUSHX.A @SP+] the SP is consequently corrupted. Instead + * of decrementing the value of the SP by four, the value of the SP + * is replaced with the data pointed to by the SP previous to the + * PUSHX.A instruction execution. + * + * Workaround: + * None. The compiler must not generate a PUSHX.A instruction that + * involves the SP. + */ + ERRATUM_CPU31 = 31, /* UNHANDLED */ + + /* CPU32: CALLA PC executes incorrectly + * + * When the instruction CALLA PC is executed, the program counter + * (PC) that is pushed onto the stack during the context save is + * incorrectly offset by a value of -2. + * + * Workaround: + * None. The compiler must not generate a CALLA PC instruction. + */ + ERRATUM_CPU32 = 32, /* UNHANDLED */ + + /* CPU33: Instruction sequence PUSH &addr; CALLA x(SP); generates + * incorrect access for CALLA + * + * When the Stack Pointer (SP) is used as the destination register + * in the CALLA index(Rdst) instruction and is preceded by a PUSH or + * PUSHX instruction in any of the following addressing modes: + * Absolute, Symbolic, Indexed, Indirect register or Indirect auto + * increment, the "index" of the CALLA instruction is not sign + * extended to 20-bits and is always treated as a positive + * value. This causes the Program Counter to be set to a wrong + * address location when the index of the CALLA instruction + * represents a negative offset. + * + * Note: + * 1. This erratum only applies when the instruction sequence is: + * PUSH or PUSHX followed by CALLA index(SP) + * 2. This erratum does not apply if the PUSH or PUSHX instruction + * is used in the Register or Immediate addressing mode + * 3. This erratum only applies when SP is used as the destination + * register in the CALLA index(Rdst) instruction + * + * Workaround: + * Place a "NOP" instruction in between the PUSH or PUSHX and the + * CALLA index(SP) instructions. + */ + ERRATUM_CPU33 = 33, /* UNHANDLED */ + + /* CPU34: CPU may be halted if a conditional jump is followed by a + * rotate PC instruction + * + * If a conditional jump instruction (JZ, JNZ, JC, JNC, JN, JGE, JL) + * is followed by an Address Rotate instruction on the PC (RRCM, + * RRAM, RLAM, RRUM) and the jump is not performed, the CPU is + * halted. + * + * Workaround: + * Insert a NOP between the conditional jump and the rotate PC + * instructions. + */ + ERRATUM_CPU34 = 34, /* UNHANDLED */ + + /* CPU35: Instruction BIT.B @Rx,PC uses the wrong PC value + * + * The BIT(.B/.W) instruction in indirect register addressing mode + * uses the wrong PC value. This instruction is represented by 2 + * bytes of opcode. If the Program Counter (PC) is used as the + * destination register, the 2 opcode bytes of the current BIT + * instruction are not accounted for. The resulting operation + * executes the instruction using the wrong PC value and this + * affects the results in the Status Register (SR). + * + * Workaround: None + */ + ERRATUM_CPU35 = 35, /* UNHANDLED */ + + /* CPU40: PC is corrupted when executing jump/conditional jump + * instruction that is followed by instruction with PC as + * destination register or a data section + * + * If the value at the memory location immediately following a + * jump/conditional jump instruction is 0X40h or 0X50h (where X = + * don't care), which could either be an instruction opcode (for + * instructions like RRCM, RRAM, RLAM, RRUM) with PC as destination + * register or a data section (const data in flash memory or data + * variable in RAM), then the PC value gets auto-incremented by 2 + * after the jump instruction is executed; thus branching to a wrong + * address location in code and leading to wrong program execution. + * + * For example, a conditional jump instruction followed by data + * section (0140h). + * + * @0x8012 Loop DEC.W R6 + * @0x8014 DEC.W R7 + * @0x8016 JNZ Loop + * @0x8018 Value1 DW 0140h + * + * Workaround: + * - In assembly, insert a NOP between the jump/conditional jump + * instruction and program code with instruction that contains PC + * as destination register or the data section. + */ + ERRATUM_CPU40 = 40, /* UNHANDLED */ +} msp430_errata_e; + +/* sed -e '1,/enum msp430_errata/d' -e '/^\}/,$d' tc-msp430.c \ + | grep '^ *ERRATUM_*' \ + | cut -d= -f1 \ + | sed 's@ *$@,@' */ +static const int recognized_errata[] = { + ERRATUM_CPU4, + ERRATUM_CPU7, + ERRATUM_CPU8, + ERRATUM_CPU11, + ERRATUM_CPU12, + ERRATUM_CPU13, + ERRATUM_CPU15, + ERRATUM_CPU16, + ERRATUM_CPU18, + ERRATUM_CPU19, + ERRATUM_CPU20, + ERRATUM_CPU21, + ERRATUM_CPU22, + ERRATUM_CPU23, + ERRATUM_CPU24, + ERRATUM_CPU25, + ERRATUM_CPU26, + ERRATUM_CPU27, + ERRATUM_CPU28, + ERRATUM_CPU29, + ERRATUM_CPU30, + ERRATUM_CPU31, + ERRATUM_CPU32, + ERRATUM_CPU33, + ERRATUM_CPU34, + ERRATUM_CPU35, + ERRATUM_CPU40, }; - -static struct mcu_type_s default_mcu = - { "msp430x11", MSP430_ISA_11, bfd_mach_msp11 }; - -static struct mcu_type_s * msp430_mcu = & default_mcu; +static int msp430_cpu = MSP430_CPU_MSP430; +static int msp430_mpy = MSP430_MPY_NONE; +static int *msp430_errata = 0; /* Profiling capability: It is a performance hit to use gcc's profiling approach for this tiny target. @@ -441,89 +731,80 @@ pow2value (int y) return n == 1; } -/* Parse ordinary expression. */ - +/* Invoke read routines to parse anordinary expression. + * + * s points to a standalone operand. op is where to store the + * resulting expression. The call returns a pointer to the suffix of + * s that remained unparsed. + * + * Note that the underlying GAS parsing code may assume that it can + * modify the contents of the buffer. */ static char * -parse_exp (char * s, expressionS * op) +parse_exp (char *s, expressionS * op) { + char *in_save = input_line_pointer; input_line_pointer = s; expression (op); + s = input_line_pointer; if (op->X_op == O_absent) as_bad (_("missing operand")); - return input_line_pointer; -} - - -/* Delete spaces from s: X ( r 1 2) => X(r12). */ - -static void -del_spaces (char * s) -{ - while (*s) - { - if (ISSPACE (*s)) - { - char *m = s + 1; - - while (ISSPACE (*m) && *m) - m++; - memmove (s, m, strlen (m) + 1); - } - else - s++; - } -} - -static inline char * -skip_space (char * s) -{ - while (ISSPACE (*s)) - ++s; + input_line_pointer = in_save; return s; } -/* Extract one word from FROM and copy it to TO. Delimiters are ",;\n" */ - +/* Extract one operand into a dynamically allocated mutable buffer. + * + * The operand begins at input_line_pointer, and is terminated by + * comma (','), semicolon (';'), or newline ('\n'). Leading and + * interior whitespace is removed. If the terminating character is + * comma (','), it is consumed (but not part of the operand). */ static char * -extract_operand (char * from, char * to, int limit) +get_operand (void) { - int size = 0; + char *sp = input_line_pointer; + char *end_ilp; + char *dest; + char *dp; + int operand_length = 0; - /* Drop leading whitespace. */ - from = skip_space (from); - - while (size < limit && *from) + while (*sp && ',' != *sp && ';' != *sp && '\n' != *sp) { - *(to + size) = *from; - if (*from == ',' || *from == ';' || *from == '\n') - break; - from++; - size++; + if (!ISSPACE (*sp)) + ++operand_length; + ++sp; } + end_ilp = sp; - *(to + size) = 0; - del_spaces (to); - - from++; - - return from; + dp = dest = xmalloc (operand_length + 1); + sp = input_line_pointer; + while (0 < operand_length) + { + if (!ISSPACE (*sp)) + { + *dp++ = *sp; + --operand_length; + } + ++sp; + } + *dp = 0; + input_line_pointer = end_ilp; + if (',' == *input_line_pointer) + ++input_line_pointer; + return dest; } static void msp430_profiler (int dummy ATTRIBUTE_UNUSED) { - char buffer[1024]; - char f[32]; - char * str = buffer; - char * flags = f; - int p_flags = 0; - char * halt; - int ops = 0; - int left; - char * s; - segT seg; - int subseg; - char * end = 0; + char *flag_token = 0; + char *flags; + int p_flags = 0; + int ops = 0; + int left; + char *s; + segT seg; + int subseg; + char *end = 0; expressionS exp; expressionS exp1; @@ -549,8 +830,7 @@ msp430_profiler (int dummy ATTRIBUTE_UNUSED) return; } - input_line_pointer = extract_operand (input_line_pointer, flags, 32); - + flags = flag_token = get_operand (); while (*flags) { switch (*flags) @@ -608,18 +888,20 @@ msp430_profiler (int dummy ATTRIBUTE_UNUSED) } flags++; } + xfree (flag_token); if (p_flags - && ( ! pow2value (p_flags & ( MSP430_PROFILER_FLAG_ENTRY - | MSP430_PROFILER_FLAG_EXIT)) - || ! pow2value (p_flags & ( MSP430_PROFILER_FLAG_PROLSTART - | MSP430_PROFILER_FLAG_PROLEND - | MSP430_PROFILER_FLAG_EPISTART - | MSP430_PROFILER_FLAG_EPIEND)) - || ! pow2value (p_flags & ( MSP430_PROFILER_FLAG_INITSECT - | MSP430_PROFILER_FLAG_FINISECT)))) + && (!pow2value (p_flags & (MSP430_PROFILER_FLAG_ENTRY + | MSP430_PROFILER_FLAG_EXIT)) + || !pow2value (p_flags & (MSP430_PROFILER_FLAG_PROLSTART + | MSP430_PROFILER_FLAG_PROLEND + | MSP430_PROFILER_FLAG_EPISTART + | MSP430_PROFILER_FLAG_EPIEND)) + || !pow2value (p_flags & (MSP430_PROFILER_FLAG_INITSECT + | MSP430_PROFILER_FLAG_FINISECT)))) { - as_bad (_("ambiguous flags combination - '.profiler' directive ignored.")); + as_bad (_ + ("ambiguous flags combination - '.profiler' directive ignored.")); input_line_pointer = end; return; } @@ -650,136 +932,304 @@ msp430_profiler (int dummy ATTRIBUTE_UNUSED) obj_elf_change_section (".profiler", SHT_PROGBITS, 0, 0, 0, 0, 0); /* Save flags. */ - emit_expr (& exp, 2); + emit_expr (&exp, 2); /* Save label value. */ - emit_expr (& exp1, 2); + emit_expr (&exp1, 2); while (ops--) { /* Now get profiling info. */ - halt = extract_operand (input_line_pointer, str, 1024); + char *halt = get_operand (); /* Process like ".word xxx" directive. */ - parse_exp (str, & exp); - emit_expr (& exp, 2); - input_line_pointer = halt; + parse_exp (halt, &exp); + emit_expr (&exp, 2); + xfree (halt); } /* Fill the rest with zeros. */ exp.X_op = O_constant; exp.X_add_number = 0; while (left--) - emit_expr (& exp, 2); + emit_expr (&exp, 2); /* Return to current section. */ subseg_set (seg, subseg); } -static char * -extract_word (char * from, char * to, int limit) +struct tag_value_pair_t { - char *op_end; - int size = 0; + const char *tag; + unsigned long value; +}; + +static const struct tag_value_pair_t cpu_tag_value_map[] = { + {"430", MSP430_CPU_MSP430}, + {"430x", MSP430_CPU_MSP430X}, + {"430xv2", MSP430_CPU_MSP430XV2}, + {0, 0} +}; - /* Drop leading whitespace. */ - from = skip_space (from); - *to = 0; +static const struct tag_value_pair_t mpy_tag_value_map[] = { + {"none", MSP430_MPY_NONE}, + {"16", MSP430_MPY_16}, + {"16se", MSP430_MPY_16SE}, + {"32", MSP430_MPY_32}, + {"32dw", MSP430_MPY_32DW}, + {0, 0} +}; - /* Find the op code end. */ - for (op_end = from; *op_end != 0 && is_part_of_name (*op_end);) +static const struct tag_value_pair_t * +find_pair_by_tag (const char *tag, const struct tag_value_pair_t *map) +{ + while (map->tag) { - to[size++] = *op_end++; - if (size + 1 >= limit) - break; + if (0 == strcmp (tag, map->tag)) + return map; + ++map; } + return 0; +} - to[size] = 0; - return op_end; +#if 0 +static const struct tag_value_pair_t * +find_pair_by_value (unsigned long value, const struct tag_value_pair_t *map) +{ + while (map->tag) + { + if (map->value == value) + return map; + ++map; + } + return 0; } +#endif -#define OPTION_MMCU 'm' -#define OPTION_RELAX 'Q' -#define OPTION_POLYMORPHS 'P' +enum +{ + OPTION_MMCU = 'm', + OPTION_CPU = OPTION_MD_BASE + 0, + OPTION_MPY, + OPTION_ERRATA, +}; -static void -msp430_set_arch (int dummy ATTRIBUTE_UNUSED) +static int +erratum_applies (int erratum) { - char *str = (char *) alloca (32); /* 32 for good measure. */ + if (!msp430_errata) + if (ERRATUM_CPU4 == erratum) + return msp430_cpu < MSP430_CPU_MSP430X; + return 0; +} - input_line_pointer = extract_word (input_line_pointer, str, 32); +static int +cpu_from_text (const char *text) +{ + const struct tag_value_pair_t *mp = + find_pair_by_tag (text, cpu_tag_value_map); + if (!mp) + as_fatal (_("unrecognized cpu type %s"), text); + return mp->value; +} - md_parse_option (OPTION_MMCU, str); - bfd_set_arch_mach (stdoutput, TARGET_ARCH, msp430_mcu->mach); +static int +mpy_from_text (const char *text) +{ + const struct tag_value_pair_t *mp = + find_pair_by_tag (text, mpy_tag_value_map); + if (!mp) + as_fatal (_("unrecognized hardware multiplier type %s"), text); + return mp->value; } static void -show_mcu_list (FILE * stream) +set_arch_mach (int cpu, int mpy ATTRIBUTE_UNUSED) { - int i; + unsigned long mach = bfd_mach_msp430; + if (MSP430_CPU_MSP430X <= cpu) + mach = bfd_mach_msp430x; + bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach); +} - fprintf (stream, _("Known MCU names:\n")); +/* Like get_symbol_end, but accepts sequences that start with + * digits and doesn't strip out name ends */ +static char +get_token_end (void) +{ + char c; - for (i = 0; mcu_types[i].name; i++) - fprintf (stream, _("\t %s\n"), mcu_types[i].name); + while (is_part_of_name (c = *input_line_pointer++)) + ; + *--input_line_pointer = 0; + return (c); +} - fprintf (stream, "\n"); +static void +msp430_set_mcu (int dummy ATTRIBUTE_UNUSED) +{ + SKIP_WHITESPACE (); + if (!is_end_of_line[(unsigned char) *input_line_pointer]) + { + char *tag_start = input_line_pointer; + int ch = get_token_end (); + md_parse_option (OPTION_MMCU, tag_start); + *input_line_pointer = ch; + demand_empty_rest_of_line (); + } + else + as_bad (_("missing value for arch")); } -int -md_parse_option (int c, char * arg) +static void +msp430_set (int option) { - int i; + char *tag = 0; - switch (c) + SKIP_WHITESPACE (); + if (!is_end_of_line[(unsigned char) *input_line_pointer]) { - case OPTION_MMCU: - for (i = 0; mcu_types[i].name; ++i) - if (strcmp (mcu_types[i].name, arg) == 0) - break; + char *tag_start = input_line_pointer; + char e = get_token_end (); + int tag_len = input_line_pointer + 1 - tag_start; + tag = (char *) xmalloc (tag_len); + memcpy (tag, tag_start, tag_len); + *input_line_pointer = e; + demand_empty_rest_of_line (); + } + + switch (option) + { + case OPTION_CPU: + if (!tag) + as_bad (_("missing value for cpu")); + msp430_cpu = cpu_from_text (tag); + break; + case OPTION_MPY: + if (!tag) + as_bad (_("missing value for mpy")); + msp430_mpy = mpy_from_text (tag); + break; + default: + abort (); + } + + set_arch_mach (msp430_cpu, msp430_mpy); + +} - if (!mcu_types[i].name) +static void +msp430_set_errata (int dummy ATTRIBUTE_UNUSED) +{ +} + +static void +msp430_set_cpux_target (int dummy ATTRIBUTE_UNUSED) +{ + int bits = TAG_CPUX_TARGET_VALID; + SKIP_WHITESPACE (); + while (!is_end_of_line[(unsigned char) *input_line_pointer]) + { + char *tag_start = input_line_pointer; + char e = get_token_end (); + + if (strcmp ("a20", tag_start) == 0) + bits |= TAG_CPUX_TARGET_A20; + else if (strcmp ("c20", tag_start) == 0) + bits |= TAG_CPUX_TARGET_C20; + else if (strcmp ("d20", tag_start) == 0) + bits |= TAG_CPUX_TARGET_D20; + else if (strcmp ("sr20", tag_start) == 0) + bits |= TAG_CPUX_TARGET_SR20; + else if (strcmp ("isr20", tag_start) == 0) + bits |= TAG_CPUX_TARGET_ISR20; + else if (strcmp ("ignore", tag_start) == 0) + bits |= TAG_CPUX_TARGET_IGNORE; + else if (strcmp ("none", tag_start) == 0) + ; + else if (strcmp ("bits", tag_start) == 0) { - show_mcu_list (stderr); - as_fatal (_("unknown MCU: %s\n"), arg); + char* value_str; + expressionS value_exp; + + *input_line_pointer = e; + SKIP_WHITESPACE (); + if ('=' != *input_line_pointer) + { + as_bad (_("cpux_target bits missing =")); + bits = 0; + break; + } + ++input_line_pointer; + SKIP_WHITESPACE (); + value_str = get_operand (); + value_str = parse_exp (value_str, &value_exp); + if (!value_str || value_exp.X_op != O_constant) + { + as_bad (_("cpux_target unable to extract bits value")); + bits = 0; + break; + } + bits |= (TAG_CPUX_TARGET_MASK & value_exp.X_add_number); + e = *input_line_pointer; } - - if (msp430_mcu == &default_mcu || msp430_mcu->mach == mcu_types[i].mach) - msp430_mcu = &mcu_types[i]; else - as_fatal (_("redefinition of mcu type %s' to %s'"), - msp430_mcu->name, mcu_types[i].name); + as_bad (_("unrecognized cpux_target option: %s"), tag_start); + *input_line_pointer = e; + if (',' == *input_line_pointer) + ++input_line_pointer; + SKIP_WHITESPACE (); + } + if (bits & TAG_CPUX_TARGET_VALID) + bfd_elf_add_obj_attr_int (stdoutput, OBJ_ATTR_GNU, Tag_GNU_MSP430_CPUX_TARGET, bits); +} + +int +md_parse_option (int c, char *arg) +{ + switch (c) + { + case OPTION_MMCU: + /* TODO: warn about unrecognized mcu option */ return 1; break; - - case OPTION_RELAX: - msp430_enable_relax = 1; + + case OPTION_CPU: + msp430_cpu = cpu_from_text (arg); return 1; break; - - case OPTION_POLYMORPHS: - msp430_enable_polys = 1; + + case OPTION_MPY: + msp430_mpy = mpy_from_text (arg); return 1; break; + + case OPTION_ERRATA: + break; } return 0; } +static void msp430_repeat_insn (int dummy ATTRIBUTE_UNUSED); -const pseudo_typeS md_pseudo_table[] = -{ - {"arch", msp430_set_arch, 0}, +const pseudo_typeS md_pseudo_table[] = { + {"arch", msp430_set_mcu, 0}, {"profiler", msp430_profiler, 0}, + {"rpt", msp430_repeat_insn, 0}, + {"cpu", msp430_set, OPTION_CPU}, + {"mpy", msp430_set, OPTION_MPY}, + {"errata", msp430_set_errata, 0}, + {"cpux_target", msp430_set_cpux_target, 0}, {NULL, NULL, 0} }; const char *md_shortopts = "m:"; -struct option md_longopts[] = -{ +struct option md_longopts[] = { {"mmcu", required_argument, NULL, OPTION_MMCU}, - {"mP", no_argument, NULL, OPTION_POLYMORPHS}, - {"mQ", no_argument, NULL, OPTION_RELAX}, + {"mcpu", required_argument, NULL, OPTION_CPU}, + {"mmpy", required_argument, NULL, OPTION_MPY}, + {"merrata", required_argument, NULL, OPTION_ERRATA}, {NULL, no_argument, NULL, 0} }; @@ -789,60 +1239,31 @@ void md_show_usage (FILE * stream) { fprintf (stream, - _("MSP430 options:\n" - " -mmcu=[msp430-name] select microcontroller type\n" - " msp430x110 msp430x112\n" - " msp430x1101 msp430x1111\n" - " msp430x1121 msp430x1122 msp430x1132\n" - " msp430x122 msp430x123\n" - " msp430x1222 msp430x1232\n" - " msp430x133 msp430x135\n" - " msp430x1331 msp430x1351\n" - " msp430x147 msp430x148 msp430x149\n" - " msp430x155 msp430x156 msp430x157\n" - " msp430x167 msp430x168 msp430x169\n" - " msp430x1610 msp430x1611 msp430x1612\n" - " msp430x311 msp430x312 msp430x313 msp430x314 msp430x315\n" - " msp430x323 msp430x325\n" - " msp430x336 msp430x337\n" - " msp430x412 msp430x413 msp430x415 msp430x417\n" - " msp430xE423 msp430xE425 msp430E427\n" - " msp430xW423 msp430xW425 msp430W427\n" - " msp430xG437 msp430xG438 msp430G439\n" - " msp430x435 msp430x436 msp430x437\n" - " msp430x447 msp430x448 msp430x449\n")); - fprintf (stream, - _(" -mQ - enable relaxation at assembly time. DANGEROUS!\n" - " -mP - enable polymorph instructions\n")); - - show_mcu_list (stream); + _("MSP430 as-specific options:\n" + " -mmcu=[msp430-name] select microcontroller type (ignored)\n" + " -mcpu={430,430x,430xv2} select cpu model\n" + " -mmpy={none,16,16se,32,32dw} select hardware multiplier type\n" + " -merrata=[cpuX,...] list relevant errata\n")); } symbolS * -md_undefined_symbol (char * name ATTRIBUTE_UNUSED) -{ - return 0; -} - -static char * -extract_cmd (char * from, char * to, int limit) +md_undefined_symbol (char *name) { - int size = 0; - - while (*from && ! ISSPACE (*from) && *from != '.' && limit > size) + if ('r' == TOLOWER (name[0]) && ISDIGIT (name[1])) { - *(to + size) = *from; - from++; - size++; - } - - *(to + size) = 0; + char *rp = name + 1; + unsigned int regno = *rp++ - '0'; - return from; + if (ISDIGIT (*rp)) + regno = (regno * 10) + *rp++ - '0'; + if (0 == *rp && regno <= REGNO_MAX) + return msp430_register_table[regno]; + } + return 0; } char * -md_atof (int type, char * litP, int * sizeP) +md_atof (int type, char *litP, int *sizeP) { return ieee_md_atof (type, litP, sizeP, FALSE); } @@ -850,564 +1271,626 @@ md_atof (int type, char * litP, int * sizeP) void md_begin (void) { - struct msp430_opcode_s * opcode; + int regno; + struct msp430_opcode_s const *opcode; msp430_hash = hash_new (); for (opcode = msp430_opcodes; opcode->name; opcode++) hash_insert (msp430_hash, opcode->name, (char *) opcode); + for (regno = REGNO_MIN; regno <= REGNO_MAX; ++regno) + { + char regname[4]; + snprintf (regname, sizeof (regname), "r%u", regno); + msp430_register_table[regno] = + symbol_create (regname, reg_section, regno, &zero_address_frag); + } - bfd_set_arch_mach (stdoutput, TARGET_ARCH, msp430_mcu->mach); + set_arch_mach (msp430_cpu, msp430_mpy); } -static int -check_reg (char * t) +static void +msp430_address_substitute_CG (struct msp430_opcode_s const *opcode, + struct msp430_operand_s *op) { - /* If this is a reg numb, str 't' must be a number from 0 - 15. */ - - if (strlen (t) > 2 && *(t + 2) != '+') - return 1; - - while (*t) + offsetT supported_cg2; + + /* Substitute CG2 if applicable. */ + if (!OP_HAS_IMMEDIATE (*op) + || (op->exp.X_op != O_constant && op->exp.X_op != O_big)) + return; + if (op->am != AMs_Immediate || op->reg != REGNO_PC) /* not #N */ + return; + + if (opcode_variant (opcode) == V_CG2_TWO) + supported_cg2 = 2; + else + supported_cg2 = 0; + if (op->exp.X_add_number == supported_cg2) { - if ((*t < '0' || *t > '9') && *t != '+') - break; - t++; + op->reg = REGNO_CG2; + op->am = AM_Register; + op->ol = 0; } - - if (*t) - return 1; - - return 0; } +static void +msp430_substitute_CG (struct msp430_operand_s *op, opwidth_t op_width, + int workaround) +{ + /* Substitute register mode with a constant generator if applicable. */ + if (!OP_HAS_IMMEDIATE (*op) + || (op->exp.X_op != O_constant && op->exp.X_op != O_big)) + return; + if (op->am != AMs_Immediate || op->reg != REGNO_PC) /* not #N */ + return; + offsetT x = op->exp.X_add_number; + + if ((BYTE_OP == op_width && MASK_8 (x) == MASK_8 (-1)) + || (WORD_OP == op_width && MASK_16 (x) == MASK_16 (-1)) + || (ADDR_OP == op_width && MASK_20 (x) == MASK_20 (-1))) + x = -1; + + if (x == 0) + { + op->reg = REGNO_CG2; + op->am = 0; /* AM_Register */ + op->ol = 0; + } + else if (x == 1) + { + op->reg = REGNO_CG2; + op->am = 1; /* AM_Indexed */ + op->ol = 0; + } + else if (x == 2) + { + op->reg = REGNO_CG2; + op->am = 2; /* AMs_IndirectRegister */ + op->ol = 0; + } + else if (x == -1) + { + op->reg = REGNO_CG2; + op->am = 3; /* AMs_IndirectAutoIncrement */ + op->ol = 0; + } + else if (x == 4 && !workaround) + { + op->reg = REGNO_CG1; + op->am = 2; /* AMs_IndirectRegister */ + op->ol = 0; + } + else if (x == 8 && !workaround) + { + op->reg = REGNO_CG1; + op->am = 3; /* AMs_IndirectAutoIncrement */ + op->ol = 0; + } +} -static int -msp430_srcoperand (struct msp430_operand_s * op, - char * l, int bin, int * imm_op) +static bfd_boolean +msp430_srcoperand (struct msp430_operand_s *op, + const char *operand_string, + enum immediate_range_e imm_range) { - char *__tl = l; + symbolS * symbol; + char *opstr = ""; + + if (operand_string) + { + opstr = alloca (strlen (operand_string) + 1); + strcpy (opstr, operand_string); + } /* Check if an immediate #VALUE. The hash sign should be only at the beginning! */ - if (*l == '#') + if (*opstr == '#') { - char *h = l; int vshift = -1; - int rval = 0; + int extractor_len = 0; /* Check if there is: - llo(x) - least significant 16 bits, x &= 0xffff - lhi(x) - x = (x >> 16) & 0xffff, - hlo(x) - x = (x >> 32) & 0xffff, - hhi(x) - x = (x >> 48) & 0xffff - The value _MUST_ be constant expression: #hlo(1231231231). */ + llo(x) - least significant 16 bits, x &= 0xffff + lhi(x) - x = (x >> 16) & 0xffff, + hlo(x) - x = (x >> 32) & 0xffff, + hhi(x) - x = (x >> 48) & 0xffff + The value _MUST_ be constant expression: #hlo(1231231231). */ - *imm_op = 1; - - if (strncasecmp (h, "#llo(", 5) == 0) + if (strncasecmp (opstr, "#llo(", 5) == 0) { vshift = 0; - rval = 3; + extractor_len = 3; } - else if (strncasecmp (h, "#lhi(", 5) == 0) + else if (strncasecmp (opstr, "#lhi(", 5) == 0) { vshift = 1; - rval = 3; + extractor_len = 3; } - else if (strncasecmp (h, "#hlo(", 5) == 0) + else if (strncasecmp (opstr, "#hlo(", 5) == 0) { vshift = 2; - rval = 3; + extractor_len = 3; } - else if (strncasecmp (h, "#hhi(", 5) == 0) + else if (strncasecmp (opstr, "#hhi(", 5) == 0) { vshift = 3; - rval = 3; + extractor_len = 3; } - else if (strncasecmp (h, "#lo(", 4) == 0) + else if (strncasecmp (opstr, "#lo(", 4) == 0) { vshift = 0; - rval = 2; + extractor_len = 2; } - else if (strncasecmp (h, "#hi(", 4) == 0) + else if (strncasecmp (opstr, "#hi(", 4) == 0) { vshift = 1; - rval = 2; + extractor_len = 2; } - op->reg = 0; /* Reg PC. */ - op->am = 3; + op->reg = REGNO_PC; + op->am = AMs_Immediate; op->ol = 1; /* Immediate will follow an instruction. */ - __tl = h + 1 + rval; - op->mode = OP_EXP; - parse_exp (__tl, &(op->exp)); + /* Extract the value after the hash and any extractor */ + opstr = parse_exp (opstr + 1 + extractor_len, &(op->exp)); + if (0 != *opstr) + { + as_bad (_("garbage after immediate: %s"), operand_string); + return FALSE; + } if (op->exp.X_op == O_constant) { - int x = op->exp.X_add_number; - - if (vshift == 0) + if (0 <= vshift) { - x = x & 0xffff; - op->exp.X_add_number = x; - } - else if (vshift == 1) - { - x = (x >> 16) & 0xffff; - op->exp.X_add_number = x; - } - else if (vshift > 1) - { - if (x < 0) - op->exp.X_add_number = -1; + int is_negative = 0 > op->exp.X_add_number; + unsigned int shift_bits = vshift * 16; + + if (shift_bits < (8 * sizeof (op->exp.X_add_number))) + { + offsetT shifted = op->exp.X_add_number >> shift_bits; + shifted = MASK_16 (shifted); + if (shifted == MASK_16 (-1)) + shifted = -1; + op->exp.X_add_number = shifted; + } else - op->exp.X_add_number = 0; /* Nothing left. */ - x = op->exp.X_add_number; + op->exp.X_add_number = is_negative ? -1 : 0; } - if (op->exp.X_add_number > 65535 || op->exp.X_add_number < -32768) + return valid_immediate (op->exp.X_add_number, imm_range); + } + if (op->exp.X_op == O_symbol || op->exp.X_op == O_subtract) + return TRUE; + if (op->exp.X_op == O_big) + { + if (0 <= vshift) { - as_bad (_("value %d out of range. Use #lo() or #hi()"), x); - return 1; + op->exp.X_op = O_constant; + op->exp.X_add_number = MASK_16 (generic_bignum[vshift]); + if (op->exp.X_add_number == MASK_16 (-1)) + op->exp.X_add_number = -1; + return valid_immediate (op->exp.X_add_number, imm_range); } + as_bad (_("operand too big (use #llo(), etc.): %s"), + operand_string); + return FALSE; + } + as_bad (_("invalid immediate operand: %s"), operand_string); + return FALSE; + } - /* Now check constants. */ - /* Substitute register mode with a constant generator if applicable. */ + /* Check if absolute &VALUE (assume that we can construct something like ((a&b)<<7 + 25). */ + if (*opstr == '&') + { + op->reg = REGNO_CG1; /* reg 2 in absolute addr mode. */ + op->am = AM_Absolute; /* mode As == 01 bin. */ + op->ol = 1; /* Immediate value followed by instruction. */ + opstr = parse_exp (opstr + 1, &(op->exp)); + if (0 != *opstr) + { + as_bad (_("garbage after absolute: %s"), operand_string); + return FALSE; + } + if (op->exp.X_op == O_constant) + return valid_immediate (op->exp.X_add_number, imm_range); + if (op->exp.X_op == O_symbol || op->exp.X_op == O_subtract) + return TRUE; - x = (short) x; /* Extend sign. */ + as_bad (_("invalid absolute operand: %s"), operand_string); + return FALSE; + } - if (x == 0) - { - op->reg = 3; - op->am = 0; - op->ol = 0; - op->mode = OP_REG; - } - else if (x == 1) - { - op->reg = 3; - op->am = 1; - op->ol = 0; - op->mode = OP_REG; - } - else if (x == 2) - { - op->reg = 3; - op->am = 2; - op->ol = 0; - op->mode = OP_REG; - } - else if (x == -1) - { - op->reg = 3; - op->am = 3; - op->ol = 0; - op->mode = OP_REG; - } - else if (x == 4) - { -#ifdef PUSH_1X_WORKAROUND - if (bin == 0x1200) - { - /* Remove warning as confusing. - as_warn (_("Hardware push bug workaround")); */ - } - else -#endif - { - op->reg = 2; - op->am = 2; - op->ol = 0; - op->mode = OP_REG; - } - } - else if (x == 8) - { -#ifdef PUSH_1X_WORKAROUND - if (bin == 0x1200) - { - /* Remove warning as confusing. - as_warn (_("Hardware push bug workaround")); */ - } - else -#endif - { - op->reg = 2; - op->am = 3; - op->ol = 0; - op->mode = OP_REG; - } - } + /* Check if indirect register mode @Rn / postincrement @Rn+. */ + if (*opstr == '@') + { + expressionS deref; + char *plusp = strchr (opstr, '+'); + + if (NULL != plusp) + *plusp = 0; + opstr = parse_exp (opstr + 1, &deref); + if (NULL != plusp) + *plusp = '+'; + if (deref.X_op != O_register) + { + as_bad (_("invalid indirect operand: %s"), operand_string); + return FALSE; } - else if (op->exp.X_op == O_symbol) + + op->ol = 0; + op->reg = deref.X_add_number; + op->am = AMs_IndirectRegister; + if ('+' == *opstr) { - op->mode = OP_EXP; + op->am = AMs_IndirectAutoIncrement; + ++opstr; } - else if (op->exp.X_op == O_big) + if (0 != *opstr) { - 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; - } - else - { - as_bad (_ - ("unknown expression in operand %s. use #llo() #lhi() #hlo() #hhi() "), - l); - return 1; - } - - if (x == 0) - { - op->reg = 3; - op->am = 0; - op->ol = 0; - op->mode = OP_REG; - } - else if (x == 1) - { - op->reg = 3; - op->am = 1; - op->ol = 0; - op->mode = OP_REG; - } - else if (x == 2) - { - op->reg = 3; - op->am = 2; - op->ol = 0; - op->mode = OP_REG; - } - else if (x == -1) - { - op->reg = 3; - op->am = 3; - op->ol = 0; - op->mode = OP_REG; - } - else if (x == 4) - { - op->reg = 2; - op->am = 2; - op->ol = 0; - op->mode = OP_REG; - } - else if (x == 8) - { - op->reg = 2; - op->am = 3; - op->ol = 0; - op->mode = OP_REG; - } + as_bad (_("garbage after indirection: %s"), operand_string); + return FALSE; } - /* Redundant (yet) check. */ - else if (op->exp.X_op == O_register) - as_bad - (_("Registers cannot be used within immediate expression [%s]"), l); - else - as_bad (_("unknown operand %s"), l); - - return 0; - } - - /* Check if absolute &VALUE (assume that we can construct something like ((a&b)<<7 + 25). */ - if (*l == '&') - { - char *h = l; - - op->reg = 2; /* reg 2 in absolute addr mode. */ - op->am = 1; /* mode As == 01 bin. */ - op->ol = 1; /* Immediate value followed by instruction. */ - __tl = h + 1; - parse_exp (__tl, &(op->exp)); - op->mode = OP_EXP; - if (op->exp.X_op == O_constant) - { - int x = op->exp.X_add_number; - - if (x > 65535 || x < -32768) - { - as_bad (_("value out of range: %d"), x); - return 1; - } - } - else if (op->exp.X_op == O_symbol) - ; - else - { - /* Redundant (yet) check. */ - if (op->exp.X_op == O_register) - as_bad - (_("Registers cannot be used within absolute expression [%s]"), l); - else - as_bad (_("unknown expression in operand %s"), l); - return 1; - } - return 0; - } - - /* Check if indirect register mode @Rn / postincrement @Rn+. */ - if (*l == '@') - { - char *t = l; - char *m = strchr (l, '+'); - - if (t != l) - { - as_bad (_("unknown addressing mode %s"), l); - return 1; - } - - t++; - if (*t != 'r' && *t != 'R') - { - as_bad (_("unknown addressing mode %s"), l); - return 1; - } - - t++; /* Points to the reg value. */ - - if (check_reg (t)) - { - as_bad (_("Bad register name r%s"), t); - return 1; - } - - op->mode = OP_REG; - op->am = m ? 3 : 2; - op->ol = 0; - if (m) - *m = 0; /* strip '+' */ - op->reg = atoi (t); - if (op->reg < 0 || op->reg > 15) - { - as_bad (_("MSP430 does not have %d registers"), op->reg); - return 1; - } - - return 0; + return TRUE; } /* Check if register indexed X(Rn). */ do { - char *h = strrchr (l, '('); - char *m = strrchr (l, ')'); - char *t; - - *imm_op = 1; + char *lparenp = strrchr (opstr, '('); + char *rparenp; + char *irendp; + expressionS index_register; + + /* Commit to register if the operand ends with a parenthesized + * register. */ + if (NULL == lparenp) + break; + rparenp = strchr (lparenp + 1, ')'); + if (NULL == rparenp) + break; - if (!h) + *rparenp = 0; + irendp = parse_exp (lparenp + 1, &index_register); + *rparenp = ')'; + if (index_register.X_op != O_register || irendp != rparenp) break; - if (!m) - { - as_bad (_("')' required")); - return 1; - } - t = h; - op->am = 1; + op->am = AM_Indexed; op->ol = 1; - /* Extract a register. */ - t++; /* Advance pointer. */ - - if (*t != 'r' && *t != 'R') - { - as_bad (_ - ("unknown operator %s. Did you mean X(Rn) or #[hl][hl][oi](CONST) ?"), - l); - return 1; - } - t++; + op->reg = index_register.X_add_number; - op->reg = *t - '0'; - if (op->reg > 9 || op->reg < 0) - { - as_bad (_("unknown operator (r%s substituted as a register name"), - t); - return 1; - } - t++; - if (*t != ')') + /* Extract what precedes (Rn) which should be an expression */ + *lparenp = 0; + opstr = parse_exp (opstr, &op->exp); + *lparenp = '('; + if (opstr != lparenp) { - op->reg = op->reg * 10; - op->reg += *t - '0'; - - if (op->reg > 15) - { - as_bad (_("unknown operator %s"), l); - return 1; - } - if (op->reg == 2) - { - as_bad (_("r2 should not be used in indexed addressing mode")); - return 1; - } - - if (*(t + 1) != ')') - { - as_bad (_("unknown operator %s"), l); - return 1; - } + as_bad (_("garbage after offset in indexed operand: %s"), + operand_string); + return FALSE; } - /* Extract constant. */ - __tl = l; - *h = 0; - op->mode = OP_EXP; - parse_exp (__tl, &(op->exp)); + /* Validate constant, convert to indirect if possible */ if (op->exp.X_op == O_constant) { - int x = op->exp.X_add_number; - - if (x > 65535 || x < -32768) - { - as_bad (_("value out of range: %d"), x); - return 1; - } + if (!valid_immediate (op->exp.X_add_number, imm_range)) + return FALSE; - if (x == 0) + if (op->exp.X_add_number == 0) { - op->mode = OP_REG; - op->am = 2; + op->am = AMs_IndirectRegister; op->ol = 0; - return 0; } + return TRUE; } - else if (op->exp.X_op == O_symbol) - ; - else - { - /* Redundant (yet) check. */ - if (op->exp.X_op == O_register) - as_bad - (_("Registers cannot be used as a prefix of indexed expression [%s]"), l); - else - as_bad (_("unknown expression in operand %s"), l); - return 1; - } + if (op->exp.X_op == O_symbol || op->exp.X_op == O_subtract) + return TRUE; - return 0; + as_bad (_("invalid indexed operand: %s"), operand_string); + return FALSE; } while (0); - /* Register mode 'mov r1,r2'. */ - do + /* Assume a symbolic, but correct if it's a register */ + opstr = parse_exp (opstr, &(op->exp)); + if (op->exp.X_op == O_register) { - char *t = l; + int regno = op->exp.X_add_number; - /* Operand should be a register. */ - if (*t == 'r' || *t == 'R') + if (0 != *opstr) { - int x = atoi (t + 1); - - if (check_reg (t + 1)) - break; - - if (x < 0 || x > 15) - break; /* Symbolic mode. */ - - op->mode = OP_REG; - op->am = 0; - op->ol = 0; - op->reg = x; - return 0; + as_bad (_("garbage after register operand: %s"), operand_string); + return FALSE; } + memset (op, 0, sizeof (*op)); + op->reg = regno; + op->am = AM_Register; + op->ol = 0; + return TRUE; } - while (0); + if (0 != *opstr) + { + as_bad (_("garbage after operand: %s"), operand_string); + return FALSE; + } + op->reg = REGNO_PC; + op->am = AM_Symbolic; + op->ol = 1; + /* Make the offset PC-relative */ + symbol = make_expr_symbol (&op->exp); + memset (&op->exp, 0, sizeof (op->exp)); + op->exp.X_op = O_subtract; + op->exp.X_add_symbol = symbol; + op->exp.X_op_symbol = expr_build_dot (); + + return TRUE; +} - /* Symbolic mode 'mov a, b' == 'mov x(pc), y(pc)'. */ - do +static bfd_boolean +convert_operand_to_dst (struct msp430_operand_s *dop, + const struct msp430_operand_s *sop, + const char *operand_string) +{ + if (sop != dop) + *dop = *sop; + + if (dop->am <= AM_Indexed) + return TRUE; + + /* Destination does not recognize indirect register: convert to + * indexed register with zero offset */ + if (dop->am == AMs_IndirectRegister) { - op->mode = OP_EXP; - op->reg = 0; /* PC relative... be careful. */ - op->am = 1; - op->ol = 1; - __tl = l; - parse_exp (__tl, &(op->exp)); - return 0; + dop->am = AM_Indexed; + dop->ol = 1; + memset (&dop->exp, 0, sizeof (dop->exp)); + dop->exp.X_op = O_constant; + dop->exp.X_add_number = 0; + return TRUE; } - while (0); - /* Unreachable. */ - as_bad (_("unknown addressing mode for operand %s"), l); - return 1; + /* Note that symbols and absolute addresses are indexed registers */ + as_bad (_("invalid destination (must be register or indexed register): %s"), + operand_string); + return FALSE; } -static int -msp430_dstoperand (struct msp430_operand_s * op, char * l, int bin) +static bfd_boolean +msp430_dstoperand (struct msp430_operand_s *op, + const char *operand_string, + enum immediate_range_e imm_range) { - int dummy; - int ret = msp430_srcoperand (op, l, bin, & dummy); + if (!msp430_srcoperand (op, operand_string, imm_range)) + return FALSE; + return convert_operand_to_dst (op, op, operand_string); +} - if (ret) - return ret; +static void +msp430_repeat_insn (int dummy ATTRIBUTE_UNUSED) +{ + char *operand = 0; + struct msp430_operand_s op; + char *line = input_line_pointer; - if (op->am == 2) + if (msp430_cpu < MSP430_CPU_MSP430X) { - char *__tl = "0"; + as_bad (_("Repeatable instructions require 430X-based mcu")); + return; + } - op->mode = OP_EXP; - op->am = 1; - op->ol = 1; - parse_exp (__tl, &(op->exp)); + if (msp430x_repeats) + as_warn (_("two consecutive .rpt pseudo-ops. Previous .rpt discarded")); + msp430x_repeats = 0; - if (op->exp.X_op != O_constant || op->exp.X_add_number != 0) - { - as_bad (_("Internal bug. Try to use 0(r%d) instead of @r%d"), - op->reg, op->reg); - return 1; - } - return 0; + if (!*line || *line == '\n') + { + as_bad (_("rpt pseudo-op requires 1 operand")); + return; } - if (op->am > 1) + memset (&op, 0, sizeof (op)); + operand = get_operand (); + + if (msp430_srcoperand (&op, operand, IMM_RANGE_REPETITION_COUNT)) { - as_bad (_ - ("this addressing mode is not applicable for destination operand")); - return 1; + if (op.am != AM_Register /* Rn */ + && op.am != AMs_Immediate) /* #N */ + as_bad (_("rpt pseudo-op requires immediate or register operand")); + else if (op.am == AM_Register) /* rpt Rn */ + msp430x_repeats = 0x80 | op.reg; + else + msp430x_repeats = op.exp.X_add_number - 1; } - return 0; + + xfree (operand); } +enum msp430_fixup_e { + FX_INVALID, + + /* R_MSP430_16, odd check SRC */ + FX_16S, + + /* R_MSP430_16, odd checks DST */ + FX_16D, + + /* R_MSP430X_SRC, odd check SRC */ + FX_X20S, + + /* R_MSP430X_DST, odd check DST */ + FX_X20D, + + /* R_MSP430X_DST, odd check SRC (for pushx) */ + FX_X20D_SRCI, + + /* R_MSP430X_DST_2ND, odd check DST */ + FX_X20D2, + + /* R_MSP430X_S */ + FX_A20S, + + /* R_MSP430X_S, disallows byte variant (for bra) */ + FX_A20S_W, + + /* R_MSP430X_D */ + FX_A20D, + + /* R_MSP430X_INDXD */ + FX_A16 +}; + +static void +record_fixup (int where, + int size, + opwidth_t op_width, + struct msp430_operand_s *op, + enum msp430_fixup_e fixup) +{ + int is_pcrel; + bfd_reloc_code_real_type reloc = BFD_RELOC_NONE; + + is_pcrel = (op->reg == REGNO_PC && op->am == AM_Indexed && op->exp.X_op == O_subtract); + switch (fixup) + { + case FX_16D: + reloc = is_pcrel ? BFD_RELOC_MSP430_16_PCREL : BFD_RELOC_MSP430_16; + if (op_width == BYTE_OP || OP_DST_IMMEDIATE_PERMITS_ODD (*op)) + reloc = is_pcrel ? BFD_RELOC_MSP430_16_PCREL_BYTE : BFD_RELOC_MSP430_16_BYTE; + break; + case FX_16S: + reloc = is_pcrel ? BFD_RELOC_MSP430_16_PCREL : BFD_RELOC_MSP430_16; + if (op_width == BYTE_OP || OP_SRC_IMMEDIATE_PERMITS_ODD (*op)) + reloc = is_pcrel ? BFD_RELOC_MSP430_16_PCREL_BYTE : BFD_RELOC_MSP430_16_BYTE; + break; + case FX_X20S: + reloc = is_pcrel ? BFD_RELOC_MSP430X_PCREL_SRC : BFD_RELOC_MSP430X_SRC; + if (op_width == BYTE_OP || OP_SRC_IMMEDIATE_PERMITS_ODD (*op)) + reloc = is_pcrel ? BFD_RELOC_MSP430X_PCREL_SRC_BYTE : BFD_RELOC_MSP430X_SRC_BYTE; + break; + case FX_X20D: + reloc = is_pcrel ? BFD_RELOC_MSP430X_PCREL_DST : BFD_RELOC_MSP430X_DST; + if (op_width == BYTE_OP || OP_DST_IMMEDIATE_PERMITS_ODD (*op)) + reloc = is_pcrel ? BFD_RELOC_MSP430X_PCREL_DST_BYTE : BFD_RELOC_MSP430X_DST_BYTE; + break; + case FX_X20D_SRCI: + reloc = is_pcrel ? BFD_RELOC_MSP430X_PCREL_DST : BFD_RELOC_MSP430X_DST; + if (op_width == BYTE_OP || OP_SRC_IMMEDIATE_PERMITS_ODD (*op)) + reloc = is_pcrel ? BFD_RELOC_MSP430X_PCREL_DST_BYTE : BFD_RELOC_MSP430X_DST_BYTE; + break; + case FX_X20D2: + reloc = is_pcrel ? BFD_RELOC_MSP430X_PCREL_DST_2ND : BFD_RELOC_MSP430X_DST_2ND; + if (op_width == BYTE_OP || OP_DST_IMMEDIATE_PERMITS_ODD (*op)) + reloc = is_pcrel ? BFD_RELOC_MSP430X_PCREL_DST_2ND_BYTE : BFD_RELOC_MSP430X_DST_2ND_BYTE; + break; + case FX_A20S_W: + case FX_A20S: + /* NB: No A20S that are PCREL */ + reloc = /* is_pcrel ? BFD_RELOC_MSP430X_PCREL_S : */ BFD_RELOC_MSP430X_S; + if (FX_A20S_W != fixup && (op_width == BYTE_OP || OP_SRC_IMMEDIATE_PERMITS_ODD (*op))) + reloc = /* is_pcrel ? BFD_RELOC_MSP430X_PCREL_S_BYTE : */ BFD_RELOC_MSP430X_S_BYTE; + break; + case FX_A20D: + reloc = is_pcrel ? BFD_RELOC_MSP430X_PCREL_D : BFD_RELOC_MSP430X_D; + break; + case FX_A16: + reloc = is_pcrel ? BFD_RELOC_MSP430X_PCREL_INDXD : BFD_RELOC_MSP430X_INDXD; + break; + default: + gas_assert (0); + } + fix_new_exp (frag_now, where, size, &op->exp, is_pcrel, reloc); +} /* Parse instruction operands. Return binary opcode. */ static unsigned int -msp430_operands (struct msp430_opcode_s * opcode, char * line) +msp430_operands (struct msp430_opcode_s const *opcode, char *line) { int bin = opcode->bin_opcode; /* Opcode mask. */ - int __is = 0; - char l1[MAX_OP_LEN], l2[MAX_OP_LEN]; - char *frag; - int where; + enum msp430_fixup_e fixup; + int insn_len_words = 0; + char *l1 = 0; + char *l2 = 0; + char *frag = 0; + int where = 0; struct msp430_operand_s op1, op2; - int res = 0; + bfd_boolean bad_operand = FALSE; static short ZEROS = 0; - int byte_op, imm_op; + opwidth_t op_width; /* Opcode is the one from opcodes table line contains something like [.w] @r2+, 5(R1) or - .b @r2+, 5(R1). */ + .b @r2+, 5(R1) + or + .a @r2+, 5(R1) */ - /* Check if byte or word operation. */ - if (*line == '.' && TOLOWER (*(line + 1)) == 'b') + /* Extract operation width */ + op_width = DEFAULT_OP; + if (*line == '.') { - bin |= BYTE_OPERATION; - byte_op = 1; + int opchar; + opchar = TOLOWER (line[1]); + if (opchar == 'b') + op_width = BYTE_OP; + else if (opchar == 'w') + op_width = WORD_OP; + else if (opchar == 'a') + op_width = ADDR_OP; + if (op_width == DEFAULT_OP || !ISSPACE (line[2])) + { + as_bad (_("unrecognized opcode width: %s%s"), opcode->name, line); + return 0; + } + line += 2; + } + + /* Verify specified width is supported by operation */ + if ((op_width == WORD_OP && !(opcode_modifier (opcode) & MOD_W)) + || (op_width == BYTE_OP && !(opcode_modifier (opcode) & MOD_B)) + || (op_width == ADDR_OP && !(opcode_modifier (opcode) & MOD_A))) + { + static char *const modifier[] = { "", ".w", ".b", ".a" }; + as_bad (_("%s%s is not a supported operation/width combination"), + opcode->name, modifier[op_width]); + return 0; + } + if (DEFAULT_OP == op_width) + op_width = WORD_OP; + + if (opcode_format (opcode) == FMT_X_DOUBLE_OPERAND + || opcode_format (opcode) == FMT_X_SINGLE_OPERAND + || opcode_format (opcode) == FMT_X_EMULATED) + { + switch (op_width) + { + case DEFAULT_OP: + case WORD_OP: + bin |= NON_ADDR_OPERATION; + break; + case BYTE_OP: + bin |= NON_ADDR_OPERATION; + bin |= BYTE_OPERATION_X; + break; + case ADDR_OP: + bin |= BYTE_OPERATION_X; + break; + } } else - byte_op = 0; + { + if (msp430x_repeats) + { + as_bad (_("%s instruction is not repeatable"), opcode->name); + msp430x_repeats = 0; + return 0; + } - /* skip .[bwBW]. */ - while (! ISSPACE (*line) && *line) - line++; + if (opcode_format (opcode) < FMT_X && op_width == BYTE_OP) /* 430 instructions */ + bin |= BYTE_OPERATION; + } if (opcode->insn_opnumb && (!*line || *line == '\n')) { @@ -1416,424 +1899,789 @@ msp430_operands (struct msp430_opcode_s * opcode, char * line) return 0; } - memset (l1, 0, sizeof (l1)); - memset (l2, 0, sizeof (l2)); + input_line_pointer = line; + memset (&op1, 0, sizeof (op1)); memset (&op2, 0, sizeof (op2)); - imm_op = 0; - - switch (opcode->fmt) + switch (opcode_format (opcode)) { - case 0: /* Emulated. */ - switch (opcode->insn_opnumb) + case FMT_EMULATED: /* Emulated. */ + switch (opcode_variant (opcode)) { - case 0: - /* Set/clear bits instructions. */ - __is = 2; - frag = frag_more (__is); + case V_NOOP: /* Exemplar: setz */ + /* Set/clear SR bits instructions, ret, nop */ + insn_len_words = 1; + frag = frag_more (2 * insn_len_words); bfd_putl16 ((bfd_vma) bin, frag); - dwarf2_emit_insn (__is); break; - case 1: + case V_NONE: /* Exemplar: inv */ /* Something which works with destination operand. */ - line = extract_operand (line, l1, sizeof (l1)); - res = msp430_dstoperand (&op1, l1, opcode->bin_opcode); - if (res) + l1 = get_operand (); + if (!msp430_dstoperand (&op1, l1, IMM_RANGE_INT16)) break; bin |= (op1.reg | (op1.am << 7)); - __is = 1 + op1.ol; - frag = frag_more (2 * __is); + insn_len_words = 1 + op1.ol; + frag = frag_more (2 * insn_len_words); where = frag - frag_now->fr_literal; bfd_putl16 ((bfd_vma) bin, frag); - dwarf2_emit_insn (2 * __is); - if (op1.mode == OP_EXP) + if (OP_HAS_IMMEDIATE (op1)) { where += 2; bfd_putl16 ((bfd_vma) ZEROS, frag + 2); - - if (op1.reg) - fix_new_exp (frag_now, where, 2, - &(op1.exp), FALSE, CHECK_RELOC_MSP430); - else - fix_new_exp (frag_now, where, 2, - &(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL); + record_fixup (where, 2, op_width, &op1, FX_16D); } break; - case 2: + case V_SHIFT: /* Exemplar: rlc */ { - /* Shift instruction. */ - line = extract_operand (line, l1, sizeof (l1)); - strncpy (l2, l1, sizeof (l2)); - l2[sizeof (l2) - 1] = '\0'; - res = msp430_srcoperand (&op1, l1, opcode->bin_opcode, &imm_op); - res += msp430_dstoperand (&op2, l2, opcode->bin_opcode); - - if (res) - break; /* An error occurred. All warnings were done before. */ + /* Shift instruction simulated by add op1, op2 */ + l1 = get_operand (); + if (!msp430_srcoperand (&op1, l1, IMM_RANGE_INT16)) + break; + if (!convert_operand_to_dst (&op2, &op1, l1)) + break; bin |= (op2.reg | (op1.reg << 8) | (op1.am << 4) | (op2.am << 7)); - __is = 1 + op1.ol + op2.ol; /* insn size in words. */ - frag = frag_more (2 * __is); + insn_len_words = 1 + op1.ol + op2.ol; /* insn size in words. */ + frag = frag_more (2 * insn_len_words); where = frag - frag_now->fr_literal; bfd_putl16 ((bfd_vma) bin, frag); - dwarf2_emit_insn (2 * __is); - - if (op1.mode == OP_EXP) + + if (OP_HAS_IMMEDIATE (op1)) { where += 2; /* Advance 'where' as we do not know _where_. */ bfd_putl16 ((bfd_vma) ZEROS, 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); - else - fix_new_exp (frag_now, where, 2, - &(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL); + record_fixup (where, 2, op_width, &op1, FX_16S); } - if (op2.mode == OP_EXP) + if (OP_HAS_IMMEDIATE (op2)) { - imm_op = 0; - bfd_putl16 ((bfd_vma) ZEROS, frag + 2 + ((__is == 3) ? 2 : 0)); - - if (op2.reg) /* Not PC relative. */ - fix_new_exp (frag_now, where + 2, 2, - &(op2.exp), FALSE, CHECK_RELOC_MSP430); - else - fix_new_exp (frag_now, where + 2, 2, - &(op2.exp), TRUE, CHECK_RELOC_MSP430_PCREL); + bfd_putl16 ((bfd_vma) ZEROS, + frag + 2 + ((insn_len_words == 3) ? 2 : 0)); + record_fixup (where + 2, 2, op_width, &op2, FX_16D); } break; } - case 3: + case V_BR: /* Exemplar: br */ /* Branch instruction => mov dst, r0. */ - line = extract_operand (line, l1, sizeof (l1)); - - res = msp430_srcoperand (&op1, l1, opcode->bin_opcode, &imm_op); - if (res) + l1 = get_operand (); + if (!msp430_srcoperand (&op1, l1, IMM_RANGE_INT16)) break; - - byte_op = 0; - imm_op = 0; + msp430_substitute_CG (&op1, WORD_OP, 0); bin |= ((op1.reg << 8) | (op1.am << 4)); - __is = 1 + op1.ol; - frag = frag_more (2 * __is); + insn_len_words = 1 + op1.ol; + frag = frag_more (2 * insn_len_words); where = frag - frag_now->fr_literal; bfd_putl16 ((bfd_vma) bin, frag); - dwarf2_emit_insn (2 * __is); - if (op1.mode == OP_EXP) + if (OP_HAS_IMMEDIATE (op1)) { where += 2; bfd_putl16 ((bfd_vma) ZEROS, frag + 2); - - if (op1.reg || (op1.reg == 0 && op1.am == 3)) - fix_new_exp (frag_now, where, 2, - &(op1.exp), FALSE, CHECK_RELOC_MSP430); - else - fix_new_exp (frag_now, where, 2, - &(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL); + /* NB: Use DST_IMMEDIATE since this is going into r0 */ + record_fixup (where, 2, op_width, &op1, FX_16D); } break; } break; - case 1: /* Format 1, double operand. */ - line = extract_operand (line, l1, sizeof (l1)); - line = extract_operand (line, l2, sizeof (l2)); - res = msp430_srcoperand (&op1, l1, opcode->bin_opcode, &imm_op); - res += msp430_dstoperand (&op2, l2, opcode->bin_opcode); + case FMT_DOUBLE_OPERAND: /* Exemplar: and */ + /* Format 1, double operand. */ + l1 = get_operand (); + l2 = get_operand (); + bad_operand = !msp430_srcoperand (&op1, l1, IMM_RANGE_INT16); + bad_operand |= !msp430_dstoperand (&op2, l2, IMM_RANGE_INT16); + if (bad_operand) + break; - if (res) - break; /* Error occurred. All warnings were done before. */ + msp430_substitute_CG (&op1, op_width, 0); bin |= (op2.reg | (op1.reg << 8) | (op1.am << 4) | (op2.am << 7)); - __is = 1 + op1.ol + op2.ol; /* insn size in words. */ - frag = frag_more (2 * __is); + insn_len_words = 1 + op1.ol + op2.ol; /* insn size in words. */ + frag = frag_more (2 * insn_len_words); where = frag - frag_now->fr_literal; bfd_putl16 ((bfd_vma) bin, frag); - dwarf2_emit_insn (2 * __is); - if (op1.mode == OP_EXP) + if (OP_HAS_IMMEDIATE (op1)) { where += 2; /* Advance where as we do not know _where_. */ bfd_putl16 ((bfd_vma) ZEROS, frag + 2); + record_fixup (where, 2, op_width, &op1, FX_16S); + } - 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); - else - fix_new_exp (frag_now, where, 2, - &(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL); + if (OP_HAS_IMMEDIATE (op2)) + { + bfd_putl16 ((bfd_vma) ZEROS, + frag + 2 + ((insn_len_words == 3) ? 2 : 0)); + record_fixup (where + 2, 2, op_width, &op2, FX_16D); } + break; - if (op2.mode == OP_EXP) + case FMT_SINGLE_OPERAND: /* Exemplar: sxt, call, reti */ + /* Single-operand mostly instr. */ + if (opcode_variant (opcode) == V_RETI) /* Exemplar: reti */ { - imm_op = 0; - bfd_putl16 ((bfd_vma) ZEROS, frag + 2 + ((__is == 3) ? 2 : 0)); + /* reti instruction. */ + insn_len_words = 1; + frag = frag_more (2 * insn_len_words); + bfd_putl16 ((bfd_vma) bin, frag); + break; + } - if (op2.reg) /* Not PC relative. */ - fix_new_exp (frag_now, where + 2, 2, - &(op2.exp), FALSE, CHECK_RELOC_MSP430); - else - fix_new_exp (frag_now, where + 2, 2, - &(op2.exp), TRUE, CHECK_RELOC_MSP430_PCREL); + l1 = get_operand (); + if (!msp430_srcoperand (&op1, l1, IMM_RANGE_INT16)) + break; /* Error in operand. */ + msp430_substitute_CG (&op1, op_width, erratum_applies (ERRATUM_CPU4) + && (opcode->bin_opcode == 0x1200)); + + bin |= op1.reg | (op1.am << 4); + insn_len_words = 1 + op1.ol; + frag = frag_more (2 * insn_len_words); + where = frag - frag_now->fr_literal; + bfd_putl16 ((bfd_vma) bin, frag); + + if (OP_HAS_IMMEDIATE (op1)) + { + bfd_putl16 ((bfd_vma) ZEROS, frag + 2); + record_fixup (where + 2, 2, op_width, &op1, + opcode_variant (opcode) == V_PUSH ? FX_16S : FX_16D); } break; - case 2: /* Single-operand mostly instr. */ - if (opcode->insn_opnumb == 0) + case FMT_JUMP: /* Exemplar: jmp */ + { + expressionS exp; + + /* Conditional jumps instructions. */ + l1 = get_operand (); + parse_exp(l1, &exp); + if (exp.X_op == O_absent) + break; + + insn_len_words = 1; + frag = frag_more (2 * insn_len_words); /* Instr size is 1 word. */ + + if (exp.X_op == O_constant) + { + int x = exp.X_add_number; + + if (MSP430_ODD (x)) + { + as_bad (_("jump offset must be even: %s"), l1); + break; + } + bin |= MASK_10 (exp.X_add_number / 2); + bfd_putl16 ((bfd_vma) bin, frag); + } + else if (exp.X_op == O_symbol || exp.X_op == O_subtract) + { + where = frag - frag_now->fr_literal; + bfd_putl16 ((bfd_vma) bin, frag); + fix_new_exp (frag_now, where, 2, &exp, TRUE, BFD_RELOC_MSP430_10_PCREL); + } + else + as_bad (_("unrecognized jump target: %s"), l1); + } + break; + + case FMT_X_DOUBLE_OPERAND: /* Exemplar: movx */ + /* Extended Format 1 ( double operand). */ + l1 = get_operand (); + l2 = get_operand (); + bad_operand = !msp430_srcoperand (&op1, l1, IMM_RANGE_INT20); + bad_operand |= !msp430_dstoperand (&op2, l2, IMM_RANGE_INT20); + if (bad_operand) + break; /* Error occurred. All warnings were done before. */ + + msp430_substitute_CG (&op1, op_width, 0); + + if (msp430x_repeats + && (OP_HAS_IMMEDIATE (op1) || OP_HAS_IMMEDIATE (op2))) { - /* reti instruction. */ - frag = frag_more (2); + as_bad (_("Repeated instruction must have register mode operands")); + msp430x_repeats = 0; + break; + } + bin |= msp430x_repeats; + msp430x_repeats = 0; + + bin |= (op2.reg | (op1.reg << 8) | (op1.am << 4) | (op2.am << 7)) << 16; + + insn_len_words = 2 + op1.ol + op2.ol; /* insn size in words, opcode is 2 words wide. */ + frag = frag_more (2 * insn_len_words); + where = frag - frag_now->fr_literal; + bfd_putl32 ((bfd_vma) bin, frag); + + if (OP_HAS_IMMEDIATE (op1)) + { + bfd_putl16 ((bfd_vma) ZEROS, frag + 4); + record_fixup (where, 2, op_width, &op1, FX_X20S); + } + + if (OP_HAS_IMMEDIATE (op2)) + { + bfd_putl16 ((bfd_vma) ZEROS, + frag + 4 + ((insn_len_words == 4) ? 2 : 0)); + record_fixup (where, 2, op_width, &op2, OP_HAS_IMMEDIATE (op1) ? FX_X20D2 : FX_X20D); + } + break; + + case FMT_X_SINGLE_OPERAND: /* Exemplar: swpbx, rrcx, pushx */ + /* Extended format 2 (single-operand). */ + l1 = get_operand (); + if (!msp430_srcoperand (&op1, l1, IMM_RANGE_INT20)) + break; /* Error in operand. */ + + msp430_substitute_CG (&op1, op_width, 0); + if (opcode_variant (opcode) != V_PUSHX && OP_HAS_IMMEDIATE (op1) && op1.am == AMs_Immediate) /* #N */ + { + as_bad (_("bad operand [%s]"), l1); + break; + } + + if (msp430x_repeats && OP_HAS_IMMEDIATE (op1)) + { + as_bad (_("Repeated instruction must have register mode operand")); + msp430x_repeats = 0; + break; + } + bin |= msp430x_repeats; + msp430x_repeats = 0; + + /* sxtx.a | swpbx.a opcode */ + if (opcode_variant (opcode) == V_SWPSXT && op_width == ADDR_OP) + bin ^= BYTE_OPERATION_X; + + bin |= (op1.reg | (op1.am << 4)) << 16; + insn_len_words = 2 + op1.ol; /* insn size in words, opcode is 2 words wide. */ + frag = frag_more (2 * insn_len_words); + where = frag - frag_now->fr_literal; + bfd_putl32 ((bfd_vma) bin, frag); + + if (OP_HAS_IMMEDIATE (op1)) + { + bfd_putl16 ((bfd_vma) ZEROS, frag + 4); + record_fixup (where, 2, op_width, &op1, + opcode_variant (opcode) == V_PUSHX ? FX_X20D_SRCI : FX_X20D); + } + break; + + case FMT_X_EXCEPTION: /* Exemplar: calla, popm, pushm, rrcm */ + /* calla, pushm, popm, rrcm, rrum, rram, rlam */ + bin = opcode->bin_opcode; /* remove WB/AL bits */ + l1 = get_operand (); + switch (opcode_variant (opcode)) + { + case V_CALLA: /* Exemplar: calla */ + if (!msp430_srcoperand (&op1, l1, IMM_RANGE_INT20)) + break; /* Error in operand. */ + + insn_len_words = 1 + op1.ol; + frag = frag_more (insn_len_words * 2); + + if (!OP_HAS_IMMEDIATE (op1) && op1.am != AM_Indexed) + { + bin |= op1.reg | 0x0040 | (op1.am << 4); + bfd_putl16 ((bfd_vma) bin, frag); + } + else + { + fixup = FX_A20D; + bfd_putl16 ((bfd_vma) ZEROS, frag + 2); + where = frag - frag_now->fr_literal; + if (op1.am == AM_Indexed) + { + if (op1.reg == REGNO_PC || op1.reg == REGNO_CG1) + { + bin |= 0x0080; + if (op1.reg == REGNO_PC) + bin |= 0x0010; + } + else + { + bin |= 0x0050 | op1.reg; + fixup = FX_A16; + } + } + else + { + gas_assert (op1.am == AMs_Immediate); + bin |= 0x00b0; + } + bfd_putl16 ((bfd_vma) bin, frag); + record_fixup (where, 2, op_width, &op1, fixup); + } + break; + case V_ROTM: /* Exemplar: rrcm */ + l2 = get_operand (); + bad_operand = !msp430_srcoperand (&op1, l1, IMM_RANGE_ROTATE_COUNT); + bad_operand |= !msp430_dstoperand (&op2, l2, IMM_RANGE_INT20); + if (bad_operand) + break; /* An error occurred. All warnings were done before. */ + + if (op_width != ADDR_OP) + bin |= (1 << 4); + + if (!OP_HAS_IMMEDIATE (op1) || op1.am != AMs_Immediate) /* not #imm */ + { + as_bad (_("bad operand [%s]"), l1); + break; + } + + bin |= ((op1.exp.X_add_number - 1) & 0x0003) << 10; + + if (OP_HAS_IMMEDIATE (op2)) + { + as_bad (_("bad operand [%s]"), l2); + break; + } + bin |= op2.reg; + + insn_len_words = 1; + frag = frag_more (2 * insn_len_words); + bfd_putl16 ((bfd_vma) bin, frag); + break; + case V_PUSHM: /* Exemplar: pushm */ + case V_POPM: /* Exemplar: popm */ + l2 = get_operand (); + bad_operand = + !msp430_srcoperand (&op1, l1, IMM_RANGE_REPETITION_COUNT); + bad_operand |= !msp430_dstoperand (&op2, l2, IMM_RANGE_INT20); + if (bad_operand) + break; /* An error occurred. All warnings were done before. */ + + if (!OP_HAS_IMMEDIATE (op1)) + { + as_bad (_("bad operand [%s]"), l1); + break; + } + + if (op_width != ADDR_OP) + bin |= (1 << 8); + bin |= ((op1.exp.X_add_number - 1) & 0x000F) << 4; + + if (OP_HAS_IMMEDIATE (op2)) + { + as_bad (_("bad operand [%s]"), l2); + break; + } + if (opcode_variant (opcode) == V_POPM) + bin |= (op2.reg - op1.exp.X_add_number + 1) & 0x000F; + else + bin |= op2.reg; + + insn_len_words = 1; + frag = frag_more (2 * insn_len_words); bfd_putl16 ((bfd_vma) bin, frag); - dwarf2_emit_insn (2); break; } - - line = extract_operand (line, l1, sizeof (l1)); - res = msp430_srcoperand (&op1, l1, opcode->bin_opcode, &imm_op); - if (res) - break; /* Error in operand. */ - - bin |= op1.reg | (op1.am << 4); - __is = 1 + op1.ol; - frag = frag_more (2 * __is); - where = frag - frag_now->fr_literal; - bfd_putl16 ((bfd_vma) bin, frag); - dwarf2_emit_insn (2 * __is); - - if (op1.mode == OP_EXP) + break; + case FMT_X_ADDRESS: /* Exemplar: adda, mova */ + /* mova, adda, suba, cmpa */ + l1 = get_operand (); + l2 = get_operand (); + bad_operand = !msp430_srcoperand (&op1, l1, IMM_RANGE_INT20); + bad_operand |= !msp430_dstoperand (&op2, l2, IMM_RANGE_INT20); + if (bad_operand) + break; /* Error in operand. */ + + msp430_address_substitute_CG (opcode, &op1); + + insn_len_words = 1 + op1.ol + op2.ol; + frag = frag_more (insn_len_words * 2); + where = frag - frag_now->fr_literal; + bin = opcode->bin_opcode; /* remove WB/AL bits */ + if (opcode_variant (opcode) == V_MOVA) /* Exemplar: mova */ + { + if (!OP_HAS_IMMEDIATE (op1) && op1.am == AM_Register) + { /* Rsrc */ + bin |= op1.reg << 8; + if (op2.am != AM_Indexed) + { + /* mova Rsrc, Rdst */ + bin |= 0x00c0 | op2.reg; + bfd_putl16 ((bfd_vma) bin, frag); + } + else + { + fixup = FX_A20D; + gas_assert (op2.am == AM_Indexed); + if (op2.reg == REGNO_CG1) /* AM_Absolute */ + bin |= 0x0060; + else + { + /* mova Rsrc, z16(Rdst) */ + bin |= 0x0070 | op2.reg; + bfd_putl16 ((bfd_vma) bin, frag); + bfd_putl16 ((bfd_vma) ZEROS, frag + 2); + fixup = FX_A16; + } + bfd_putl16 ((bfd_vma) bin, frag); + bfd_putl16 ((bfd_vma) ZEROS, frag + 2); + record_fixup (where, 2, op_width, &op2, fixup); + } + } + else if (!OP_HAS_IMMEDIATE (op2) && op2.am == AM_Register) + { /* Rdst */ + fixup = FX_INVALID; + if (!OP_HAS_IMMEDIATE (op1) && op1.am == AMs_IndirectRegister) + { + /* mova @Rsrc, Rdst */ + bin |= 0x0000 | op1.reg << 8 | op2.reg; + bfd_putl16 ((bfd_vma) bin, frag); + } + else if (!OP_HAS_IMMEDIATE (op1) + && op1.am == AMs_IndirectAutoIncrement) + { + /* mova @Rsrc+, Rdst */ + bin |= 0x0010 | op1.reg << 8 | op2.reg; + bfd_putl16 ((bfd_vma) bin, frag); + } + else if (OP_HAS_IMMEDIATE (op1) && op1.am == AM_Indexed) + { + if (op1.reg == REGNO_CG1) /* AM_Absolute */ + { + /* mova &abs20, Rdst */ + bin |= 0x0020 | op2.reg; + fixup = FX_A20S; + } + else /* AM_Symbolic or AM_Indexed */ + { + /* mova z16(Rsrc), Rdst */ + bin |= 0x0030 | op1.reg << 8 | op2.reg; + fixup = FX_A16; + } + bfd_putl16 ((bfd_vma) bin, frag); + bfd_putl16 ((bfd_vma) ZEROS, frag + 2); + } + else if (OP_HAS_IMMEDIATE (op1) && op1.am == AMs_Immediate) + { + /* mova #imm20, Rdst */ + bin |= 0x0080 | op2.reg; + bfd_putl16 ((bfd_vma) bin, frag); + bfd_putl16 ((bfd_vma) ZEROS, frag + 2); + fixup = FX_A20S; + } + else + as_bad (_ + ("source operand address mode %d not allowed with mova instruction"), + op1.am); + if (fixup != FX_INVALID) + record_fixup (where, 2, op_width, &op1, fixup); + } + else + as_bad (_("unsupported operands for mova: %s, %s"), l1, l2); + break; + } + else /* Exemplar: adda */ + /* adda, suba, cmpa */ { - bfd_putl16 ((bfd_vma) ZEROS, frag + 2); - - if (op1.reg || (op1.reg == 0 && op1.am == 3)) /* Not PC relative. */ - fix_new_exp (frag_now, where + 2, 2, - &(op1.exp), FALSE, CHECK_RELOC_MSP430); + if (!OP_HAS_IMMEDIATE (op2) && op2.am == AM_Register) + { + if (!OP_HAS_IMMEDIATE (op1) && op1.am == AM_Register) + { /* Rsrc, Rdst */ + bin |= 0x0040 | op1.reg << 8 | op2.reg; + bfd_putl16 ((bfd_vma) bin, frag); + } + else if (OP_HAS_IMMEDIATE (op1) && op1.am == AMs_Immediate) + { + /* #imm20, Rdst */ + bin |= 0x0080 | op2.reg; + bfd_putl16 ((bfd_vma) bin, frag); + bfd_putl16 ((bfd_vma) ZEROS, frag + 2); + record_fixup (where, 2, op_width, &op1, FX_A20S); + } + else + as_bad (_ + ("source operand address mode not allowed with %s instruction"), + opcode->name); + } else - fix_new_exp (frag_now, where + 2, 2, - &(op1.exp), TRUE, CHECK_RELOC_MSP430_PCREL); + as_bad (_ + ("destination operand address mode not allowed with %s instruction"), + opcode->name); + break; } break; - case 3: /* Conditional jumps instructions. */ - line = extract_operand (line, l1, sizeof (l1)); - /* l1 is a label. */ - if (l1[0]) + case FMT_X_EMULATED: /* Extended emulated. */ + switch (opcode_variant (opcode)) { - char *m = l1; - expressionS exp; - - if (*m == '$') - m++; - - parse_exp (m, &exp); - frag = frag_more (2); /* Instr size is 1 word. */ - - /* In order to handle something like: - - and #0x8000, r5 - tst r5 - jz 4 ; skip next 4 bytes - inv r5 - inc r5 - nop ; will jump here if r5 positive or zero - - jCOND -n ;assumes jump n bytes backward: - - mov r5,r6 - jmp -2 - - is equal to: - lab: - mov r5,r6 - jmp lab - - jCOND $n ; jump from PC in either direction. */ + case V_NONE: /* Exemplar: popx */ + /* single operand instruction emulated with Extended type 1 (double operand) instructions. */ + l1 = get_operand (); + if (!msp430_dstoperand (&op1, l1, IMM_RANGE_INT20)) + break; - if (exp.X_op == O_constant) + if (msp430x_repeats) { - int x = exp.X_add_number; - - if (x & 1) + if ((bin >> 20) && 0x3 == 1) { - as_warn (_("Even number required. Rounded to %d"), x + 1); - x++; + as_bad (_("%s instruction is not repeatable"), + opcode->name); + msp430x_repeats = 0; + break; } - - if ((*l1 == '$' && x > 0) || x < 0) - x -= 2; - - x >>= 1; - - if (x > 512 || x < -511) + if (OP_HAS_IMMEDIATE (op1)) { - as_bad (_("Wrong displacement %d"), x << 1); + as_bad (_ + ("Repeated instruction must have register mode operand")); + msp430x_repeats = 0; break; } - - bin |= x & 0x3ff; - bfd_putl16 ((bfd_vma) bin, frag); + bin |= msp430x_repeats; + msp430x_repeats = 0; } - else if (exp.X_op == O_symbol && *l1 != '$') - { - where = frag - frag_now->fr_literal; - fix_new_exp (frag_now, where, 2, - &exp, TRUE, BFD_RELOC_MSP430_10_PCREL); - bfd_putl16 ((bfd_vma) bin, frag); - } - else if (*l1 == '$') + bin |= (op1.reg | (op1.am << 7)) << 16; + insn_len_words = 2 + op1.ol; + frag = frag_more (2 * insn_len_words); + where = frag - frag_now->fr_literal; + bfd_putl32 ((bfd_vma) bin, frag); + + if (OP_HAS_IMMEDIATE (op1)) { - as_bad (_("instruction requires label sans '$'")); + bfd_putl16 ((bfd_vma) ZEROS, frag + 4); + record_fixup (where, 2, op_width, &op1, FX_X20D); } - else + break; + case V_MOVA: /* Exemplar clra: ops = #0, dst=Rdst */ + l1 = get_operand (); + if (!msp430_dstoperand (&op1, l1, IMM_RANGE_INT20)) + break; + /* Technically as an emulated instruction the destination + * could also be z16(Rdst) or &abs20, but the ISA + * description specifies only Rdst. Use the real mova #0 + * for the others. */ + if (OP_HAS_IMMEDIATE (op1)) { - as_bad (_ - ("instruction requires label or value in range -511:512")); + as_bad (_("%s operand must be register"), opcode->name); + break; } - dwarf2_emit_insn (2 * __is); - break; - } - else - { - as_bad (_("instruction requires label")); + insn_len_words = 1; + frag = frag_more (insn_len_words * 2); + where = frag - frag_now->fr_literal; + bin |= op1.reg; + bfd_putl16 ((bfd_vma) bin, frag); break; - } - break; + case V_X_SHIFT: /* Exemplar: rlax */ + { + /* Shift instruction. */ + l1 = get_operand (); + if (!msp430_srcoperand (&op1, l1, IMM_RANGE_INT20)) + break; + if (!convert_operand_to_dst (&op2, &op1, l1)) + break; - case 4: /* Extended jumps. */ - if (!msp430_enable_polys) - { - as_bad (_("polymorphs are not enabled. Use -mP option to enable.")); - break; - } - - line = extract_operand (line, l1, sizeof (l1)); - if (l1[0]) - { - char *m = l1; - expressionS exp; + if (msp430x_repeats && OP_HAS_IMMEDIATE (op2)) + { + as_bad (_ + ("Repeated instruction must have register mode operands")); + msp430x_repeats = 0; + break; + } + bin |= msp430x_repeats; + msp430x_repeats = 0; + + bin |= + (op2. + reg | (op1.reg << 8) | (op1.am << 4) | (op2.am << 7)) << 16; + + insn_len_words = 2 + op1.ol + op2.ol; /* insn size in words. */ + frag = frag_more (2 * insn_len_words); + where = frag - frag_now->fr_literal; + bfd_putl32 ((bfd_vma) bin, frag); - /* Ignore absolute addressing. make it PC relative anyway. */ - if (*m == '#' || *m == '$') - m++; + if (OP_HAS_IMMEDIATE (op1)) + { + bfd_putl16 ((bfd_vma) ZEROS, frag + 4); + record_fixup (where, 2, op_width, &op1, FX_X20S); + } - parse_exp (m, & exp); - if (exp.X_op == O_symbol) + if (OP_HAS_IMMEDIATE (op2)) + { + bfd_putl16 ((bfd_vma) ZEROS, + frag + 4 + ((insn_len_words == 4) ? 2 : 0)); + record_fixup (where, 2, op_width, &op2, OP_HAS_IMMEDIATE (op1) ? FX_X20D2 : FX_X20D); + } + } + break; + case V_RETA: /* Exemplar: reta */ + if (msp430x_repeats) { - /* Relaxation required. */ - struct rcodes_s rc = msp430_rcodes[opcode->insn_opnumb]; - - /* The parameter to dwarf2_emit_insn is actually the offset to the start - of the insn from the fix piece of instruction that was emitted. - Since next fragments may have variable size we tie debug info - to the beginning of the instruction. */ - frag = frag_more (8); - dwarf2_emit_insn (0); - bfd_putl16 ((bfd_vma) rc.sop, frag); - frag = frag_variant (rs_machine_dependent, 8, 2, - ENCODE_RELAX (rc.lpos, STATE_BITS10), /* Wild guess. */ - exp.X_add_symbol, - 0, /* Offset is zero if jump dist less than 1K. */ - (char *) frag); + as_bad (_("%s instruction is not repeatable"), opcode->name); + msp430x_repeats = 0; break; } - } - - as_bad (_("instruction requires label")); - break; + bin = opcode->bin_opcode; /* remove WB/AL bits */ + insn_len_words = 1; + frag = frag_more (2 * insn_len_words); + bfd_putl16 ((bfd_vma) bin, frag); + break; + case V_EMU_ADDR: /* Exemplar: incda */ + /* incda, decda, tsta */ + if (msp430x_repeats) + { + as_bad (_("%s instruction is not repeatable"), opcode->name); + msp430x_repeats = 0; + break; + } + bin = opcode->bin_opcode; /* remove WB/AL bits */ + l1 = get_operand (); + if (!msp430_dstoperand (&op1, l1, IMM_RANGE_INT20)) + break; - case 5: /* Emulated extended branches. */ - if (!msp430_enable_polys) - { - as_bad (_("polymorphs are not enabled. Use -mP option to enable.")); + insn_len_words = 1; + if (!OP_HAS_IMMEDIATE (op1) && op1.am == AM_Register) + { + frag = frag_more (2 * insn_len_words); + bin |= op1.reg; + bfd_putl16 ((bfd_vma) bin, frag); + } + else + as_bad (_ + ("destination operand address mode not allowed with %s instruction"), + opcode->name); break; - } - line = extract_operand (line, l1, sizeof (l1)); - if (l1[0]) - { - char * m = l1; - expressionS exp; + case V_BRA: /* Exemplar: bra */ + /* bra, emulated with Address type instruction */ + if (msp430x_repeats) + { + as_bad (_("%s instruction is not repeatable"), opcode->name); + msp430x_repeats = 0; + break; + } - /* Ignore absolute addressing. make it PC relative anyway. */ - if (*m == '#' || *m == '$') - m++; + bin = opcode->bin_opcode; /* remove WB/AL bits */ + l1 = get_operand (); + if (!msp430_srcoperand (&op1, l1, IMM_RANGE_INT20)) + break; /* Error in operand. */ + msp430_substitute_CG (&op1, ADDR_OP, 0); - parse_exp (m, & exp); - if (exp.X_op == O_symbol) + insn_len_words = 1 + op1.ol; + frag = frag_more (insn_len_words * 2); + where = frag - frag_now->fr_literal; + fixup = FX_INVALID; + if (!OP_HAS_IMMEDIATE (op1) && op1.am == AM_Register) { - /* Relaxation required. */ - struct hcodes_s hc = msp430_hcodes[opcode->insn_opnumb]; - - frag = frag_more (8); - dwarf2_emit_insn (0); - bfd_putl16 ((bfd_vma) hc.op0, frag); - bfd_putl16 ((bfd_vma) hc.op1, frag+2); - - frag = frag_variant (rs_machine_dependent, 8, 2, - ENCODE_RELAX (STATE_EMUL_BRANCH, STATE_BITS10), /* Wild guess. */ - exp.X_add_symbol, - 0, /* Offset is zero if jump dist less than 1K. */ - (char *) frag); - break; + /* mova Rsrc, PC */ + bin |= 0x00C0 | op1.reg << 8; + bfd_putl16 ((bfd_vma) bin, frag); + } + else if (!OP_HAS_IMMEDIATE (op1) && op1.am == AMs_IndirectRegister) + { + /* mova @Rsrc, PC */ + bin |= 0x0000 | op1.reg << 8; + bfd_putl16 ((bfd_vma) bin, frag); + } + else if (!OP_HAS_IMMEDIATE (op1) + && op1.am == AMs_IndirectAutoIncrement) + { + /* mova @Rsrc+, PC */ + bin |= 0x0010 | op1.reg << 8; + bfd_putl16 ((bfd_vma) bin, frag); + } + else if (OP_HAS_IMMEDIATE (op1) && op1.am == AM_Indexed) + { + if (op1.reg == REGNO_CG1) + { + /* mova &abs20, PC */ + bin |= 0x0020; + fixup = FX_A20S_W; + } + else + { + /* mova z16(Rsrc), PC */ + bin |= 0x0030 | op1.reg << 8; + fixup = FX_A16; + } + bfd_putl16 ((bfd_vma) bin, frag); + bfd_putl16 ((bfd_vma) ZEROS, frag + 2); + } + else if (OP_HAS_IMMEDIATE (op1) && op1.am == AMs_Immediate) + { + /* mova #imm20, Rdst */ + bin |= 0x0080; + bfd_putl16 ((bfd_vma) bin, frag); + bfd_putl16 ((bfd_vma) ZEROS, frag + 2); + fixup = FX_A20S_W; } + else + as_bad (_ + ("source operand address mode not allowed with bra instruction")); + if (fixup != FX_INVALID) + record_fixup (where, 2, op_width, &op1, fixup); } - - as_bad (_("instruction requires label")); break; default: as_bad (_("Illegal instruction or not implemented opcode.")); } - input_line_pointer = line; + if (0 < insn_len_words && 0 == had_errors ()) + dwarf2_emit_insn (2 * insn_len_words); + + if (l1) + xfree (l1); + if (l2) + xfree (l2); + return 0; } void -md_assemble (char * str) +md_assemble (char *str) { - struct msp430_opcode_s * opcode; - char cmd[32]; - unsigned int i = 0; - - str = skip_space (str); /* Skip leading spaces. */ - str = extract_cmd (str, cmd, sizeof (cmd)); - - while (cmd[i] && i < sizeof (cmd)) - { - char a = TOLOWER (cmd[i]); - cmd[i] = a; - i++; - } - - if (!cmd[0]) + struct msp430_opcode_s const *opcode; + char *cmda; + char *cmd; + int i = 0; + int cmd_length; + + while (ISSPACE (*str)) + ++str; + cmd = str; + while (*str && (!ISSPACE (*str)) && '.' != *str) + ++str; + cmd_length = str - cmd; + if (0 == cmd_length) { as_bad (_("can't find opcode ")); return; } - opcode = (struct msp430_opcode_s *) hash_find (msp430_hash, cmd); + cmda = alloca (1 + cmd_length); + do + cmda[i] = TOLOWER (cmd[i]); + while (++i < cmd_length); + cmda[i] = 0; + + opcode = (struct msp430_opcode_s const *) hash_find (msp430_hash, cmda); if (opcode == NULL) { - as_bad (_("unknown opcode `%s'"), cmd); + as_bad (_("unknown opcode `%s'"), cmda); + return; + } + + if (msp430_cpu < MSP430_CPU_MSP430X && opcode_format (opcode) >= FMT_X) + { + as_bad (_("Extended instruction (%s) requires 430X-based mcu"), + opcode->name); return; } { - char *__t = input_line_pointer; + char *t = input_line_pointer; msp430_operands (opcode, str); - input_line_pointer = __t; + input_line_pointer = t; } } @@ -1857,105 +2705,49 @@ md_section_align (asection * seg, valueT addr) long md_pcrel_from_section (fixS * fixp, segT sec) { + long rv; if (fixp->fx_addsy != (symbolS *) NULL && (!S_IS_DEFINED (fixp->fx_addsy) || (S_GET_SEGMENT (fixp->fx_addsy) != sec))) return 0; - - return fixp->fx_frag->fr_address + fixp->fx_where; -} - -/* Replaces standard TC_FORCE_RELOCATION_LOCAL. - Now it handles the situation when relocations - have to be passed to linker. */ -int -msp430_force_relocation_local(fixS *fixp) -{ - if (msp430_enable_polys - && !msp430_enable_relax) - return 1; + if (fixp->fx_r_type == BFD_RELOC_MSP430_10_PCREL) + /* The only real PC-relative operand */ + rv = fixp->fx_frag->fr_address + fixp->fx_where; else - return (!fixp->fx_pcrel - || generic_force_reloc(fixp)); + /* NB: 430X relocations/fixups do additional adjustments to + * account for the value not being written at "where", which + * instead points to the extension word. Those are independent of + * pcrel so do not belong here. */ + rv = fixp->fx_where - fixp->fx_dot_value; + return rv; } - /* GAS will call this for each fixup. It should store the correct value in the object file. */ void md_apply_fix (fixS * fixp, valueT * valuep, segT seg) { - unsigned char * where; + unsigned char *where; unsigned long insn; long value; + value = *valuep; if (fixp->fx_addsy == (symbolS *) NULL) - { - value = *valuep; - fixp->fx_done = 1; - } - else if (fixp->fx_pcrel) + fixp->fx_done = 1; + else if (fixp->fx_pcrel && fixp->fx_addsy != (symbolS *)NULL) { segT s = S_GET_SEGMENT (fixp->fx_addsy); - - if (fixp->fx_addsy && (s == seg || s == absolute_section)) - { - /* FIXME: We can appear here only in case if we perform a pc - relative jump to the label which is i) global, ii) locally - defined or this is a jump to an absolute symbol. - If this is an absolute symbol -- everything is OK. - If this is a global label, we've got a symbol value defined - twice: - 1. S_GET_VALUE (fixp->fx_addsy) will contain a symbol offset - from this section start - 2. *valuep will contain the real offset from jump insn to the - label - So, the result of S_GET_VALUE (fixp->fx_addsy) + (* valuep); - will be incorrect. Therefore remove s_get_value. */ - value = /* S_GET_VALUE (fixp->fx_addsy) + */ * valuep; - fixp->fx_done = 1; - } - else - value = *valuep; - } - else - { - value = fixp->fx_offset; - - if (fixp->fx_subsy != (symbolS *) NULL) - { - if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section) - { - value -= S_GET_VALUE (fixp->fx_subsy); - fixp->fx_done = 1; - } - else - { - /* We don't actually support subtracting a symbol. */ - as_bad_where (fixp->fx_file, fixp->fx_line, - _("expression too complex")); - } - } + fixp->fx_done = (s == seg || s == absolute_section); } + if (fixp->fx_subsy != (symbolS *) NULL) + as_bad_where (fixp->fx_file, fixp->fx_line, _("expression too complex")); fixp->fx_no_overflow = 1; - /* if polymorphs are enabled and relax disabled. - do not kill any relocs and pass them to linker. */ - if (msp430_enable_polys - && !msp430_enable_relax) - { - 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 - fixp->fx_done = 0; - } - if (fixp->fx_done) { /* Fetch the instruction, insert the fully resolved operand - value, and stuff the instruction back again. */ + value, and stuff the instruction back again. */ where = (unsigned char *) fixp->fx_frag->fr_literal + fixp->fx_where; @@ -1963,68 +2755,210 @@ md_apply_fix (fixS * fixp, valueT * valuep, segT seg) switch (fixp->fx_r_type) { + case BFD_RELOC_MSP430X_PCREL_D: + case BFD_RELOC_MSP430X_PCREL_INDXD: + /* operand located 2 bytes after where */ + value -= 2; + break; + case BFD_RELOC_MSP430X_PCREL_SRC: + case BFD_RELOC_MSP430X_PCREL_SRC_BYTE: + case BFD_RELOC_MSP430X_PCREL_DST: + case BFD_RELOC_MSP430X_PCREL_DST_BYTE: + /* operand located 4 bytes after where */ + value -= 4; + break; + case BFD_RELOC_MSP430X_PCREL_DST_2ND: + case BFD_RELOC_MSP430X_PCREL_DST_2ND_BYTE: + /* operand located 6 bytes after where */ + value -= 6; + break; + default: + break; + } + + switch (fixp->fx_r_type) + { + case BFD_RELOC_32: /* Required; used for elf header? */ + bfd_putl32 ((bfd_vma) MASK_32 (value), where); + break; + + case BFD_RELOC_MSP430_10: case BFD_RELOC_MSP430_10_PCREL: - if (value & 1) + if (MSP430_ODD (value)) as_bad_where (fixp->fx_file, fixp->fx_line, _("odd address operand: %ld"), value); + /* If we get here at all, it's because the operand + * expression involved a PC-relative calculation, but the + * final value could be determined without resolving an + * external symbol. That value does not account for the + * fact that the PC will have been incremented by two at the + * point where the offset is applied. Do that now. */ + value -= 2; + /* Jumps are in words. */ value >>= 1; - --value; /* Correct PC. */ - if (value < -512 || value > 511) + if (!MSP430_S10_IN_RANGE (value)) as_bad_where (fixp->fx_file, fixp->fx_line, _("operand out of range: %ld"), value); - value &= 0x3ff; /* get rid of extended sign */ + value = MASK_10 (value); /* get rid of extended sign */ bfd_putl16 ((bfd_vma) (value | insn), where); break; - case BFD_RELOC_MSP430_RL_PCREL: + case BFD_RELOC_MSP430_16: case BFD_RELOC_MSP430_16_PCREL: - if (value & 1) + if (MSP430_ODD (value)) as_bad_where (fixp->fx_file, fixp->fx_line, - _("odd address operand: %ld"), value); + _("odd operand: %ld"), value); + /*FALLTHRU*/; + case BFD_RELOC_16: /* Required; used for elf header? */ + case BFD_RELOC_MSP430_16_BYTE: + case BFD_RELOC_MSP430_16_PCREL_BYTE: + if (!MSP430_16_IN_RANGE (value)) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("operand out of range: %ld"), value); + bfd_putl16 ((bfd_vma) MASK_16 (value), where); + break; - /* Nothing to be corrected here. */ - if (value < -32768 || value > 65536) + case BFD_RELOC_MSP430X_SRC: + case BFD_RELOC_MSP430X_PCREL_SRC: + if (MSP430_ODD (value)) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("odd operand: %ld"), value); + /*FALLTHRU*/; + case BFD_RELOC_MSP430X_SRC_BYTE: + case BFD_RELOC_MSP430X_PCREL_SRC_BYTE: + if (!MSP430_20_IN_RANGE (value)) as_bad_where (fixp->fx_file, fixp->fx_line, _("operand out of range: %ld"), value); + value = MASK_20 (value); + bfd_putl16 ((bfd_vma) (bfd_getl16 (where) & 0xf87f) | + ((value >> 9) & 0x0780), where); + bfd_putl16 ((bfd_vma) MASK_16 (value), where + 4); + break; - value &= 0xffff; /* Get rid of extended sign. */ - bfd_putl16 ((bfd_vma) value, where); + case BFD_RELOC_MSP430X_DST: + case BFD_RELOC_MSP430X_PCREL_DST: + if (MSP430_ODD (value)) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("odd operand: %ld"), value); + /*FALLTHRU*/; + case BFD_RELOC_MSP430X_DST_BYTE: + case BFD_RELOC_MSP430X_PCREL_DST_BYTE: + if (!MSP430_20_IN_RANGE (value)) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("operand out of range: %ld"), value); + value = MASK_20 (value); + bfd_putl16 ((bfd_vma) (bfd_getl16 (where) & 0xfff0) | + ((value >> 16) & 0x000f), where); + bfd_putl16 ((bfd_vma) MASK_16 (value), where + 4); break; - case BFD_RELOC_MSP430_16_PCREL_BYTE: - /* Nothing to be corrected here. */ - if (value < -32768 || value > 65536) + case BFD_RELOC_MSP430X_DST_2ND: + case BFD_RELOC_MSP430X_PCREL_DST_2ND: + if (MSP430_ODD (value)) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("odd operand: %ld"), value); + /*FALLTHRU*/; + case BFD_RELOC_MSP430X_DST_2ND_BYTE: + case BFD_RELOC_MSP430X_PCREL_DST_2ND_BYTE: + if (!MSP430_20_IN_RANGE (value)) as_bad_where (fixp->fx_file, fixp->fx_line, _("operand out of range: %ld"), value); + value = MASK_20 (value); + bfd_putl16 ((bfd_vma) (bfd_getl16 (where) & 0xfff0) | + ((value >> 16) & 0x000f), where); + bfd_putl16 ((bfd_vma) MASK_16 (value), where + 6); + break; - value &= 0xffff; /* Get rid of extended sign. */ - bfd_putl16 ((bfd_vma) value, where); + case BFD_RELOC_MSP430X_S: + if (MSP430_ODD (value)) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("odd operand: %ld"), value); + /*FALLTHRU*/; + case BFD_RELOC_MSP430X_S_BYTE: + if (!MSP430_20_IN_RANGE (value)) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("operand out of range: %ld"), value); + value = MASK_20 (value); + bfd_putl16 ((bfd_vma) (bfd_getl16 (where) & 0xf0ff) | + ((value >> 8) & 0x0f00), where); + bfd_putl16 ((bfd_vma) MASK_16 (value), where + 2); break; - case BFD_RELOC_32: - bfd_putl16 ((bfd_vma) value, where); + case BFD_RELOC_MSP430X_D: + case BFD_RELOC_MSP430X_PCREL_D: + if (MSP430_ODD (value)) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("odd operand: %ld"), value); + /*FALLTHRU*/; + case BFD_RELOC_MSP430X_D_BYTE: + if (!MSP430_20_IN_RANGE (value)) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("operand out of range: %ld"), value); + value = MASK_20 (value); + bfd_putl16 ((bfd_vma) (bfd_getl16 (where) & 0xfff0) | + ((value >> 16) & 0x000f), where); + /* 16 least-significant bits */ + bfd_putl16 ((bfd_vma) MASK_16 (value), where + 2); break; - case BFD_RELOC_MSP430_16: - case BFD_RELOC_16: - case BFD_RELOC_MSP430_16_BYTE: - value &= 0xffff; - bfd_putl16 ((bfd_vma) value, where); + case BFD_RELOC_MSP430X_PCREL_INDXD: + if (MSP430_ODD (value)) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("odd operand: %ld"), value); + /*FALLTHRU*/; + case BFD_RELOC_MSP430X_INDXD: + if (!MSP430_S16_IN_RANGE (value)) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("operand out of range: %ld"), value); + bfd_putl16 ((bfd_vma) MASK_16 (value), where + 2); break; + case BFD_RELOC_MSP430_RL_PCREL: + case BFD_RELOC_MSP430_2X_PCREL: default: - as_fatal (_("line %d: unknown relocation type: 0x%x"), - fixp->fx_line, fixp->fx_r_type); + as_fatal (_("line %d: unknown relocation type: 0x%x (%s)"), + fixp->fx_line, fixp->fx_r_type, + bfd_get_reloc_code_name (fixp->fx_r_type)); break; } } else { + int reloc_is_pcrel = + fixp->fx_r_type == BFD_RELOC_MSP430X_PCREL_D || + fixp->fx_r_type == BFD_RELOC_MSP430X_PCREL_DST || + fixp->fx_r_type == BFD_RELOC_MSP430X_PCREL_DST_2ND || + fixp->fx_r_type == BFD_RELOC_MSP430X_PCREL_DST_2ND_BYTE || + fixp->fx_r_type == BFD_RELOC_MSP430X_PCREL_DST_BYTE || + fixp->fx_r_type == BFD_RELOC_MSP430X_PCREL_INDXD || + fixp->fx_r_type == BFD_RELOC_MSP430X_PCREL_SRC || + fixp->fx_r_type == BFD_RELOC_MSP430X_PCREL_SRC_BYTE || + fixp->fx_r_type == BFD_RELOC_MSP430_10_PCREL || + fixp->fx_r_type == BFD_RELOC_MSP430_16_PCREL || + fixp->fx_r_type == BFD_RELOC_MSP430_16_PCREL_BYTE || + fixp->fx_r_type == BFD_RELOC_MSP430_2X_PCREL || + fixp->fx_r_type == BFD_RELOC_MSP430_RL_PCREL; + + /* TODO: This is useless; the fx_addnumber field is unused. + Probably fx_offset was desired, as that becames the addend in + the relocation. Not changed at this time, because currently + the BFD code repeats the adjustments that were made above. */ fixp->fx_addnumber = value; + /* If the value we calculate is not the same as is going into + * the relocation, the expression semantics is not preserved. + * This can happen with symbol-. where symbol is in a different + * section. We could fix this by updating the offset in + * relocation, although object file backwards compatibility has + * to be validated. */ + if (value != (long)fixp->fx_offset && fixp->fx_pcrel && !reloc_is_pcrel) + as_bad_where (fixp->fx_file, fixp->fx_line, + _("expression %d too complex for %s (offset %ld will be %ld)"), + fixp->fx_pcrel, bfd_get_reloc_code_name (fixp->fx_r_type), + value, fixp->fx_offset); } } @@ -2040,7 +2974,7 @@ md_apply_fix (fixS * fixp, valueT * valuep, segT seg) arelent * tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp) { - arelent * reloc; + arelent *reloc; reloc = xmalloc (sizeof (arelent)); @@ -2066,230 +3000,19 @@ tc_gen_reloc (asection * seg ATTRIBUTE_UNUSED, fixS * fixp) return reloc; } -int -md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED, - asection * segment_type ATTRIBUTE_UNUSED) -{ - if (fragP->fr_symbol && S_GET_SEGMENT (fragP->fr_symbol) == segment_type) - { - /* This is a jump -> pcrel mode. Nothing to do much here. - Return value == 2. */ - fragP->fr_subtype = - ENCODE_RELAX (RELAX_LEN (fragP->fr_subtype), STATE_BITS10); - } - else if (fragP->fr_symbol) - { - /* Its got a segment, but its not ours. Even if fr_symbol is in - an absolute segment, we don't know a displacement until we link - object files. So it will always be long. This also applies to - labels in a subsegment of current. Liker may relax it to short - jump later. Return value == 8. */ - fragP->fr_subtype = - ENCODE_RELAX (RELAX_LEN (fragP->fr_subtype), STATE_WORD); - } - else - { - /* We know the abs value. may be it is a jump to fixed address. - Impossible in our case, cause all constants already handled. */ - fragP->fr_subtype = - ENCODE_RELAX (RELAX_LEN (fragP->fr_subtype), STATE_UNDEF); - } - - return md_relax_table[fragP->fr_subtype].rlx_length; -} - void md_convert_frag (bfd * abfd ATTRIBUTE_UNUSED, asection * sec ATTRIBUTE_UNUSED, - fragS * fragP) + fragS * fragP ATTRIBUTE_UNUSED) { - char * where = 0; - int rela = -1; - int i; - struct rcodes_s * cc = NULL; - struct hcodes_s * hc = NULL; - - switch (fragP->fr_subtype) - { - case ENCODE_RELAX (STATE_UNCOND_BRANCH, STATE_BITS10): - case ENCODE_RELAX (STATE_SIMPLE_BRANCH, STATE_BITS10): - case ENCODE_RELAX (STATE_NOOV_BRANCH, STATE_BITS10): - /* We do not have to convert anything here. - Just apply a fix. */ - rela = BFD_RELOC_MSP430_10_PCREL; - 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]; - where = fragP->fr_literal + fragP->fr_fix; - bfd_putl16 (cc->lop0, where); - rela = BFD_RELOC_MSP430_RL_PCREL; - fragP->fr_fix += 2; - break; - - case ENCODE_RELAX (STATE_SIMPLE_BRANCH, STATE_WORD): - case ENCODE_RELAX (STATE_SIMPLE_BRANCH, STATE_UNDEF): - { - /* Other simple branches. */ - int insn = bfd_getl16 (fragP->fr_opcode); - - insn &= 0xffff; - /* Find actual instruction. */ - for (i = 0; i < 7 && !cc; i++) - if (msp430_rcodes[i].sop == insn) - cc = & msp430_rcodes[i]; - if (!cc || !cc->name) - as_fatal (_("internal inconsistency problem in %s: insn %04lx"), - __FUNCTION__, (long) insn); - where = fragP->fr_literal + fragP->fr_fix; - bfd_putl16 (cc->lop0, where); - bfd_putl16 (cc->lop1, where + 2); - rela = BFD_RELOC_MSP430_RL_PCREL; - fragP->fr_fix += 4; - } - break; - - case ENCODE_RELAX (STATE_NOOV_BRANCH, STATE_WORD): - case ENCODE_RELAX (STATE_NOOV_BRANCH, STATE_UNDEF): - cc = & msp430_rcodes[6]; - where = fragP->fr_literal + fragP->fr_fix; - bfd_putl16 (cc->lop0, where); - bfd_putl16 (cc->lop1, where + 2); - bfd_putl16 (cc->lop2, where + 4); - rela = BFD_RELOC_MSP430_RL_PCREL; - fragP->fr_fix += 6; - break; - - case ENCODE_RELAX (STATE_EMUL_BRANCH, STATE_BITS10): - { - int insn = bfd_getl16 (fragP->fr_opcode + 2); - - insn &= 0xffff; - for (i = 0; i < 4 && !hc; i++) - 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); - rela = BFD_RELOC_MSP430_10_PCREL; - /* Apply a fix for a first label if necessary. - another fix will be applied to the next word of insn anyway. */ - if (hc->tlab == 2) - fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, - fragP->fr_offset, TRUE, rela); - fragP->fr_fix += 2; - } - - break; - - case ENCODE_RELAX (STATE_EMUL_BRANCH, STATE_WORD): - case ENCODE_RELAX (STATE_EMUL_BRANCH, STATE_UNDEF): - { - int insn = bfd_getl16 (fragP->fr_opcode + 2); - - insn &= 0xffff; - for (i = 0; i < 4 && !hc; i++) - 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); - rela = BFD_RELOC_MSP430_RL_PCREL; - where = fragP->fr_literal + fragP->fr_fix; - bfd_putl16 (hc->lop0, where); - bfd_putl16 (hc->lop1, where + 2); - bfd_putl16 (hc->lop2, where + 4); - fragP->fr_fix += 6; - } - break; - - default: - as_fatal (_("internal inconsistency problem in %s: %lx"), - __FUNCTION__, (long) fragP->fr_subtype); - break; - } - - /* Now apply fix. */ - fix_new (fragP, fragP->fr_fix, 2, fragP->fr_symbol, - fragP->fr_offset, TRUE, rela); - /* Just fixed 2 bytes. */ - fragP->fr_fix += 2; + gas_assert (0); } -/* Relax fragment. Mostly stolen from hc11 and mcore - which arches I think I know. */ -long -msp430_relax_frag (segT seg ATTRIBUTE_UNUSED, fragS * fragP, - long stretch ATTRIBUTE_UNUSED) +int +md_estimate_size_before_relax (fragS * fragp ATTRIBUTE_UNUSED, + asection * seg ATTRIBUTE_UNUSED) { - long growth; - offsetT aim = 0; - symbolS *symbolP; - const relax_typeS *this_type; - const relax_typeS *start_type; - relax_substateT next_state; - relax_substateT this_state; - const relax_typeS *table = md_relax_table; - - /* Nothing to be done if the frag has already max size. */ - if (RELAX_STATE (fragP->fr_subtype) == STATE_UNDEF - || RELAX_STATE (fragP->fr_subtype) == STATE_WORD) - return 0; - - if (RELAX_STATE (fragP->fr_subtype) == STATE_BITS10) - { - symbolP = fragP->fr_symbol; - if (symbol_resolved_p (symbolP)) - as_fatal (_("internal inconsistency problem in %s: resolved symbol"), - __FUNCTION__); - /* We know the offset. calculate a distance. */ - aim = S_GET_VALUE (symbolP) - fragP->fr_address - fragP->fr_fix; - } - - if (!msp430_enable_relax) - { - /* Relaxation is not enabled. So, make all jump as long ones - by setting 'aim' to quite high value. */ - aim = 0x7fff; - } - - this_state = fragP->fr_subtype; - start_type = this_type = table + this_state; - - if (aim < 0) - { - /* Look backwards. */ - for (next_state = this_type->rlx_more; next_state;) - if (aim >= this_type->rlx_backward || !this_type->rlx_backward) - next_state = 0; - else - { - /* Grow to next state. */ - this_state = next_state; - this_type = table + this_state; - next_state = this_type->rlx_more; - } - } - else - { - /* Look forwards. */ - for (next_state = this_type->rlx_more; next_state;) - if (aim <= this_type->rlx_forward || !this_type->rlx_forward) - next_state = 0; - else - { - /* Grow to next state. */ - this_state = next_state; - this_type = table + this_state; - next_state = this_type->rlx_more; - } - } - - growth = this_type->rlx_length - start_type->rlx_length; - if (growth != 0) - fragP->fr_subtype = this_state; - return growth; + gas_assert (0); + return 0; } diff --git binutils-2.22.orig/gas/config/tc-msp430.h binutils-2.22/gas/config/tc-msp430.h index 2f7aea2..1202603 100644 --- binutils-2.22.orig/gas/config/tc-msp430.h +++ binutils-2.22/gas/config/tc-msp430.h @@ -1,5 +1,5 @@ /* This file is tc-msp430.h - Copyright (C) 2002, 2004, 2005, 2007 Free Software Foundation, Inc. + Copyright (C) 2002, 2004, 2005, 2007, 2012 Free Software Foundation, Inc. Contributed by Dmitry Diky @@ -20,103 +20,41 @@ Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -#define TC_MSP430 -/* By convention, you should define this macro in the `.h' file. For - example, `tc-m68k.h' defines `TC_M68K'. You might have to use this - if it is necessary to add CPU specific code to the object format - file. */ +#ifndef TC_MSP430 +#define TC_MSP430 1 #define TARGET_FORMAT "elf32-msp430" -/* This macro is the BFD target name to use when creating the output - file. This will normally depend upon the `OBJ_FMT' macro. */ - #define TARGET_ARCH bfd_arch_msp430 -/* This macro is the BFD architecture to pass to `bfd_set_arch_mach'. */ - -#define TARGET_MACH 0 -/* This macro is the BFD machine number to pass to - `bfd_set_arch_mach'. If it is not defined, GAS will use 0. */ #define TARGET_BYTES_BIG_ENDIAN 0 -/* You should define this macro to be non-zero if the target is big - endian, and zero if the target is little endian. */ +#define md_number_to_chars number_to_chars_littleendian #define ONLY_STANDARD_ESCAPES -/* If you define this macro, GAS will warn about the use of - nonstandard escape sequences in a string. */ #define md_operand(x) -/* GAS will call this function for any expression that can not be - recognized. When the function is called, `input_line_pointer' - will point to the start of the expression. */ -#define md_number_to_chars number_to_chars_littleendian -/* This should just call either `number_to_chars_bigendian' or - `number_to_chars_littleendian', whichever is appropriate. On - targets like the MIPS which support options to change the - endianness, which function to call is a runtime decision. On - other targets, `md_number_to_chars' can be a simple macro. */ +#define DOLLAR_DOT +/* True at least until far pointers invalidate this: */ #define WORKING_DOT_WORD -/* -`md_short_jump_size' -`md_long_jump_size' -`md_create_short_jump' -`md_create_long_jump' - If `WORKING_DOT_WORD' is defined, GAS will not do broken word - processing (*note Broken words::.). Otherwise, you should set - `md_short_jump_size' to the size of a short jump (a jump that is - just long enough to jump around a long jmp) and - `md_long_jump_size' to the size of a long jump (a jump that can go - anywhere in the function), You should define - `md_create_short_jump' to create a short jump around a long jump, - and define `md_create_long_jump' to create a long jump. */ - -#define MD_APPLY_FIX3 - -#define TC_HANDLES_FX_DONE - -#undef RELOC_EXPANSION_POSSIBLE -/* If you define this macro, it means that `tc_gen_reloc' may return - multiple relocation entries for a single fixup. In this case, the - return value of `tc_gen_reloc' is a pointer to a null terminated - array. */ -#define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from_section(FIXP, SEC) -/* If you define this macro, it should return the offset between the - address of a PC relative fixup and the position from which the PC - relative adjustment should be made. On many processors, the base - of a PC relative instruction is the next instruction, so this - macro would return the length of an instruction. */ +/* Values passed to md_apply_fix don't include symbol values. */ +#define MD_APPLY_SYM_VALUE(FIX) 0 -extern long md_pcrel_from_section (struct fix *, segT); +/* Do not allow r3-2 to become r1 */ +#define md_register_arithmetic 0 #define LISTING_WORD_SIZE 2 -/* The number of bytes to put into a word in a listing. This affects - the way the bytes are clumped together in the listing. For - example, a value of 2 might print `1234 5678' where a value of 1 - would print `12 34 56 78'. The default value is 4. */ - -#define LEX_DOLLAR 0 -/* MSP430 port does not use `$' as a logical line separator */ +/* TBD: SF 3486339 */ #define TC_IMPLICIT_LCOMM_ALIGNMENT(SIZE, P2VAR) (P2VAR) = 0 -/* An `.lcomm' directive with no explicit alignment parameter will - use this macro to set P2VAR to the alignment that a request for - SIZE bytes will have. The alignment is expressed as a power of - two. If no alignment should take place, the macro definition - should do nothing. Some targets define a `.bss' directive that is - also affected by this macro. The default definition will set - P2VAR to the truncated power of two of sizes up to eight bytes. */ -#define md_relax_frag(SEG, FRAGP, STRETCH) \ - msp430_relax_frag (SEG, FRAGP, STRETCH) -extern long msp430_relax_frag (segT, fragS *, long); +#define MD_PCREL_FROM_SECTION(FIXP, SEC) md_pcrel_from_section(FIXP, SEC) +extern long md_pcrel_from_section (struct fix *, segT); -#define TC_FORCE_RELOCATION_LOCAL(FIX) \ - msp430_force_relocation_local(FIX) -extern int msp430_force_relocation_local(struct fix *); +#define MD_APPLY_SYM(FIXP) (0) +/* Allow symbol-. to force PCREL relocations */ +#define DIFF_EXPR_OK -extern int msp430_enable_relax; -extern int msp430_enable_polys; +#endif /* TC_MSP430 */ diff --git binutils-2.22.orig/gas/doc/c-msp430.texi binutils-2.22/gas/doc/c-msp430.texi index e5db407..5f59d08 100644 --- binutils-2.22.orig/gas/doc/c-msp430.texi +++ binutils-2.22/gas/doc/c-msp430.texi @@ -1,4 +1,4 @@ -@c Copyright 2002, 2004, 2005, 2011 Free Software Foundation, Inc. +@c Copyright 2002, 2004, 2005, 2011, 2012 Free Software Foundation, Inc. @c This is part of the GAS manual. @c For copying conditions, see the file as.texinfo. @ifset GENERIC @@ -30,12 +30,6 @@ @item -m select the mpu arch. Currently has no effect. -@item -mP -enables polymorph instructions handler. - -@item -mQ -enables relaxation at assembly time. DANGEROUS! - @end table @node MSP430 Syntax diff --git binutils-2.22.orig/gas/testsuite/gas/msp430/opcode.d binutils-2.22/gas/testsuite/gas/msp430/opcode.d index 22df51c..297d3e1 100644 --- binutils-2.22.orig/gas/testsuite/gas/msp430/opcode.d +++ binutils-2.22/gas/testsuite/gas/msp430/opcode.d @@ -5,41 +5,49 @@ Disassembly of section .text: 0+000 <[^>]*> 1b f3 and #1, r11 ;r3 As==01 -0+002 <[^>]*> 3a e3 inv r10 ; +0+002 <[^>]*> 3a e3 inv r10 0+004 <[^>]*> 3b e0 ff 00 xor #255, r11 ;#0x00ff 0+008 <[^>]*> 3c d2 bis #8, r12 ;r2 As==11 0+00a <[^>]*> 3d b0 10 00 bit #16, r13 ;#0x0010 0+00e <[^>]*> 3e c0 a0 00 bic #160, r14 ;#0x00a0 -0+012 <[^>]*> 0f 93 cmp #0, r15 ;r3 As==00 -0+014 <[^>]*> 1a 83 dec r10 ; -0+016 <[^>]*> 0b 73 sbc r11 ; -0+018 <[^>]*> 1c 53 inc r12 ; +0+012 <[^>]*> 0f 93 tst r15 +0+014 <[^>]*> 1a 83 dec r10 +0+016 <[^>]*> 0b 73 sbc r11 +0+018 <[^>]*> 1c 53 inc r12 0+01a <[^>]*> 2d 63 addc #2, r13 ;r3 As==10 -0+01c <[^>]*> 0e 12 push r14 ; -0+01e <[^>]*> 3f 41 pop r15 ; -0+020 <[^>]*> 8a 11 sxt r10 ; -0+022 <[^>]*> 0b 11 rra r11 ; -0+024 <[^>]*> 8c 10 swpb r12 ; -0+026 <[^>]*> 0d 10 rrc r13 ; +0+01c <[^>]*> 0e 12 push r14 +0+01e <[^>]*> 3f 41 pop r15 +0+020 <[^>]*> 8a 11 sxt r10 +0+022 <[^>]*> 0b 11 rra r11 +0+024 <[^>]*> 8c 10 swpb r12 +0+026 <[^>]*> 0d 10 rrc r13 0+028 <[^>]*> 30 41 ret 0+02a <[^>]*> 31 40 00 00 mov #0, r1 ;#0x0000 -0+02e <[^>]*> b0 12 00 00 call #0 ;#0x0000 -0+032 <[^>]*> 1e 42 00 00 mov &0x0000,r14 ;0x0000 -0+036 <[^>]*> 0f 4e mov r14, r15 ; -0+038 <[^>]*> 0f 5f rla r15 ; -0+03a <[^>]*> 0f 7f subc r15, r15 ; -0+03c <[^>]*> 3f e3 inv r15 ; -0+03e <[^>]*> b0 12 00 00 call #0 ;#0x0000 -0+042 <[^>]*> 82 4e 00 00 mov r14, &0x0000 ; -0+046 <[^>]*> 82 4f 00 00 mov r15, &0x0000 ; -0+04a <[^>]*> 1e 42 00 00 mov &0x0000,r14 ;0x0000 -0+04e <[^>]*> 0f 4e mov r14, r15 ; -0+050 <[^>]*> 0f 5f rla r15 ; -0+052 <[^>]*> 0f 7f subc r15, r15 ; -0+054 <[^>]*> 3f e3 inv r15 ; -0+056 <[^>]*> b0 12 00 00 call #0 ;#0x0000 -0+05a <[^>]*> 82 4e 00 00 mov r14, &0x0000 ; -0+05e <[^>]*> 82 4f 00 00 mov r15, &0x0000 ; +0+02e <[^>]*> b0 12 00 00 call #0x0000 +0+032 <[^>]*> 1e 42 00 00 mov &0x0000,r14 +0+036 <[^>]*> 0f 4e mov r14, r15 +0+038 <[^>]*> 0f 5f rla r15 +0+03a <[^>]*> 0f 7f subc r15, r15 +0+03c <[^>]*> 3f e3 inv r15 +0+03e <[^>]*> b0 12 00 00 call #0x0000 +0+042 <[^>]*> 82 4e 00 00 mov r14, &0x0000 +0+046 <[^>]*> 82 4f 00 00 mov r15, &0x0000 +0+04a <[^>]*> 1e 42 00 00 mov &0x0000,r14 +0+04e <[^>]*> 0f 4e mov r14, r15 +0+050 <[^>]*> 0f 5f rla r15 +0+052 <[^>]*> 0f 7f subc r15, r15 +0+054 <[^>]*> 3f e3 inv r15 +0+056 <[^>]*> b0 12 00 00 call #0x0000 +0+05a <[^>]*> 82 4e 00 00 mov r14, &0x0000 +0+05e <[^>]*> 82 4f 00 00 mov r15, &0x0000 0+062 <[^>]*> 3f 40 f0 00 mov #240, r15 ;#0x00f0 -0+066 <[^>]*> 30 40 00 00 br #0x0000 ; -0+06a <[^>]*> 92 52 00 02 72 01 add &0x0200,&0x0172 ;0x0200 +0+066 <[^>]*> 30 40 00 00 br #0x0000 +0+06a <[^>]*> 92 52 00 02 72 01 add &0x0200,&0x0172 +0+070 3a 40 f0 de mov #-8464, r10 ;#0xdef0 +0+074 3b 40 bc 9a mov #-25924,r11 ;#0x9abc +0+078 3c 40 78 56 mov #22136, r12 ;#0x5678 +0+07c 3d 40 34 12 mov #4660, r13 ;#0x1234 +0+080 3a 40 7b 00 mov #123, r10 ;#0x007b +0+084 0b 43 clr r11 +0+086 0c 43 clr r12 +0+088 0d 43 clr r13 diff --git binutils-2.22.orig/gas/testsuite/gas/msp430/opcode.s binutils-2.22/gas/testsuite/gas/msp430/opcode.s index b85a463..8fa444f 100644 --- binutils-2.22.orig/gas/testsuite/gas/msp430/opcode.s +++ binutils-2.22/gas/testsuite/gas/msp430/opcode.s @@ -55,3 +55,19 @@ main: ;; This next instruction triggered a bug which ;; was fixed by a patch to msp430-dis.c on Jan 2, 2004 add &0x200, &0x172 + +.global extract + .type extract,@function +extract: + mov #llo(0x123456789abcdef0), r10 + mov #lhi(0x123456789abcdef0), r11 + mov #hlo(0x123456789abcdef0), r12 + mov #hhi(0x123456789abcdef0), r13 + +.global extract0 + .type extract,@function +extract0: + mov #llo(123), r10 + mov #lhi(123), r11 + mov #hlo(123), r12 + mov #hhi(123), r13 diff --git binutils-2.22.orig/gas/write.c binutils-2.22/gas/write.c index a1e0205..c89837b 100644 --- binutils-2.22.orig/gas/write.c +++ binutils-2.22/gas/write.c @@ -1019,6 +1019,10 @@ fixup_segment (fixS *fixP, segT this_segment) S_GET_NAME (fixP->fx_subsy), segment_name (sub_symbol_segment)); } + else if (sub_symbol_segment != undefined_section + && ! bfd_is_com_section (sub_symbol_segment) + && MD_APPLY_SYM_VALUE (fixP)) + add_number -= S_GET_VALUE (fixP->fx_subsy); } if (fixP->fx_addsy) diff --git binutils-2.22.orig/include/elf/msp430.h binutils-2.22/include/elf/msp430.h index 44f5c51..50d3f67 100644 --- binutils-2.22.orig/include/elf/msp430.h +++ binutils-2.22/include/elf/msp430.h @@ -1,5 +1,5 @@ /* MSP430 ELF support for BFD. - Copyright (C) 2002, 2003, 2004, 2010 Free Software Foundation, Inc. + Copyright (C) 2002, 2003, 2004, 2010, 2012 Free Software Foundation, Inc. Contributed by Dmitry Diky This file is part of BFD, the Binary File Descriptor library. @@ -23,24 +23,6 @@ #include "elf/reloc-macros.h" -/* Processor specific flags for the ELF header e_flags field. */ -#define EF_MSP430_MACH 0xff - -#define E_MSP430_MACH_MSP430x11 11 -#define E_MSP430_MACH_MSP430x11x1 110 -#define E_MSP430_MACH_MSP430x12 12 -#define E_MSP430_MACH_MSP430x13 13 -#define E_MSP430_MACH_MSP430x14 14 -#define E_MSP430_MACH_MSP430x15 15 -#define E_MSP430_MACH_MSP430x16 16 -#define E_MSP430_MACH_MSP430x31 31 -#define E_MSP430_MACH_MSP430x32 32 -#define E_MSP430_MACH_MSP430x33 33 -#define E_MSP430_MACH_MSP430x41 41 -#define E_MSP430_MACH_MSP430x42 42 -#define E_MSP430_MACH_MSP430x43 43 -#define E_MSP430_MACH_MSP430x44 44 - /* Relocations. */ START_RELOC_NUMBERS (elf_msp430_reloc_type) RELOC_NUMBER (R_MSP430_NONE, 0) @@ -50,9 +32,82 @@ START_RELOC_NUMBERS (elf_msp430_reloc_type) RELOC_NUMBER (R_MSP430_16_PCREL, 4) RELOC_NUMBER (R_MSP430_16_BYTE, 5) RELOC_NUMBER (R_MSP430_16_PCREL_BYTE, 6) - RELOC_NUMBER (R_MSP430_2X_PCREL, 7) - RELOC_NUMBER (R_MSP430_RL_PCREL, 8) + RELOC_NUMBER (R_MSP430_2X_PCREL, 7) /* obsolete */ + RELOC_NUMBER (R_MSP430_RL_PCREL, 8) /* obsolete */ + RELOC_NUMBER (R_MSP430X_SRC_BYTE, 9) + RELOC_NUMBER (R_MSP430X_SRC, 10) + RELOC_NUMBER (R_MSP430X_DST_BYTE, 11) + RELOC_NUMBER (R_MSP430X_DST, 12) + RELOC_NUMBER (R_MSP430X_DST_2ND_BYTE, 13) + RELOC_NUMBER (R_MSP430X_DST_2ND, 14) + RELOC_NUMBER (R_MSP430X_PCREL_SRC_BYTE, 15) + RELOC_NUMBER (R_MSP430X_PCREL_SRC, 16) + RELOC_NUMBER (R_MSP430X_PCREL_DST_BYTE, 17) + RELOC_NUMBER (R_MSP430X_PCREL_DST, 18) + RELOC_NUMBER (R_MSP430X_PCREL_DST_2ND, 19) + RELOC_NUMBER (R_MSP430X_PCREL_DST_2ND_BYTE, 20) + RELOC_NUMBER (R_MSP430X_S_BYTE, 21) + RELOC_NUMBER (R_MSP430X_S, 22) + RELOC_NUMBER (R_MSP430X_D_BYTE, 23) + RELOC_NUMBER (R_MSP430X_D, 24) + RELOC_NUMBER (R_MSP430X_PCREL_D, 25) + RELOC_NUMBER (R_MSP430X_INDXD, 26) + RELOC_NUMBER (R_MSP430X_PCREL_INDXD, 27) + RELOC_NUMBER (R_MSP430_10, 28) END_RELOC_NUMBERS (R_MSP430_max) +/* Pre-uniarch versions of binutils stored machine types in the + * e_flags field, with values up to 471 decimal. Now we store the + * machine type in the e_mach field, and use e_flags to identify the + * characteristics of the code. + * + * Use the following flag to indicate that this object file uses the + * uniarch flag layout. */ +#define EF_MSP430_UNIARCH 0x10000000 + +#define EF_MSP430_ARCH_430 0x00000000 +#define EF_MSP430_ARCH_430X 0x00000001 +#define EF_MSP430_ARCH 0x000000FF + +/* EABI object attributes. */ + +enum +{ + /* 0-3 are generic. These are OBJ_ATTR_GNU tags, so the lower two + bits encode type. */ + Tag_GNU_MSP430_CPUX_TARGET = 4 +}; + +/* Bits reflecting content of __MSP430X__, which holds the flags that + drive compilation by GCC */ +#define TAG_CPUX_TARGET_ISR20 0x0100 +#define TAG_CPUX_TARGET_SR20 0x0200 +#define TAG_CPUX_TARGET_A20 0x0400 +#define TAG_CPUX_TARGET_C20 0x0800 +#define TAG_CPUX_TARGET_D20 0x1000 +#define TAG_CPUX_TARGET_MASK 0x1F00 +#define TAG_CPUX_TARGET_VALID 0x0001 +#define TAG_CPUX_TARGET_CONFLICT 0x0002 +#define TAG_CPUX_TARGET_IGNORE 0x0004 + +#if 0 +/* Bits encoding the hardware multiplier assumed. */ +#define TAG_MPY_TYPE_16 0x0010 +#define TAG_MPY_TYPE_32 0x0020 +#define TAG_MPY_HAS_SE 0x0001 +#define TAG_MPY_HAS_DW 0x0002 + +#define TAG_MSP430X_CPU_MSP430 0x0000 +#define TAG_MSP430X_CPU_MSP430X 0x0002 +#define TAG_MSP430X_CPU_MSP430XV2 0x0003 +#define TAG_MSP430X_CPU 0x0003 +#define TAG_MSP430X_MEMORY_MODEL_NONE 0x0000 +#define TAG_MSP430X_MEMORY_MODEL_SMALL 0x0010 +#define TAG_MSP430X_MEMORY_MODEL_MEDIUM 0x0020 +#define TAG_MSP430X_MEMORY_MODEL_LARGE 0x0030 +#define TAG_MSP430X_MEMORY_MODEL_HUGE 0x0040 +#define TAG_MSP430X_MEMORY_MODEL 0x0070 +#endif + #endif /* _ELF_MSP430_H */ diff --git binutils-2.22.orig/include/opcode/msp430.h binutils-2.22/include/opcode/msp430.h index d3bf130..b6b1707 100644 --- binutils-2.22.orig/include/opcode/msp430.h +++ binutils-2.22/include/opcode/msp430.h @@ -1,6 +1,6 @@ /* Opcode table for the TI MSP430 microcontrollers - Copyright 2002, 2004, 2010 Free Software Foundation, Inc. + Copyright 2002, 2004, 2010-2012 Free Software Foundation, Inc. Contributed by Dmitry Diky This program is free software; you can redistribute it and/or modify @@ -26,99 +26,289 @@ struct msp430_operand_s int ol; /* Operand length words. */ int am; /* Addr mode. */ int reg; /* Register. */ - int mode; /* Pperand mode. */ -#define OP_REG 0 -#define OP_EXP 1 #ifndef DASM_SECTION expressionS exp; #endif }; -#define BYTE_OPERATION (1 << 6) /* Byte operation flag for all instructions. */ +#define BYTE_OPERATION (1 << 6) /* Byte operation flag for 430 instructions. */ +#define BYTE_OPERATION_X (1 << 22) /* Byte operation flag for 430x instructions. */ +#define NON_ADDR_OPERATION (1 << 6) /* Address operation flag for 430x instructions. */ + +typedef enum +{ + DEFAULT_OP, /* instruction has no modifier (treat as .w) */ + WORD_OP, /* .w */ + BYTE_OP, /* .b */ + ADDR_OP /* .a */ +} +opwidth_t; + +/** Bit-markers for type of CPU present. */ +typedef enum msp430_cpu_e +{ + MSP430_CPU_MSP430 = 0x0000, + MSP430_CPU_MSP430X = 0x0002, + MSP430_CPU_MSP430XV2 = 0x0003, + MSP430_CPU = 0x0003, +} msp430_cpu_e; + +/** Bit-markers for type of hardware multiplier present. */ +typedef enum msp430_mpy_e +{ + MSP430_MPY_NONE = 0x0000, + MSP430_MPY_16 = 0x0010, + MSP430_MPY_16SE = 0x0011, + MSP430_MPY_32 = 0x0020, + MSP430_MPY_32DW = 0x0022, + MSP430_MPY = 0x0030 +} msp430_mpy_e; + +/* Constants for common registers */ +#define REGNO_MIN 0 +#define REGNO_MAX 15 +#define REGNO_PC 0 +#define REGNO_SP 1 +#define REGNO_SR 2 +#define REGNO_CG1 2 +#define REGNO_CG2 3 + +/* Source (2-bit) and destination (1-bit) addressing mode constants. */ +#define AM_Register 0 +#define AM_Indexed 1 +/* Symbolic is indexed off r0=PC */ +#define AM_Symbolic 1 +/* Absolute is indexed off r2=CG1 (0) */ +#define AM_Absolute 1 +/* Source-only addressing mode constants */ +#define AMs_IndirectRegister 2 +#define AMs_IndirectAutoIncrement 3 +/* Immediate is indirect auto increment of r0=PC */ +#define AMs_Immediate 3 + +/* Mask all but the low 8 bits */ +#define MASK_8(_x) ((_x) & 0x000000FF) +/* Mask all but the low 10 bits */ +#define MASK_10(_x) ((_x) & 0x000003FF) +/* Mask all but the low 16 bits */ +#define MASK_16(_x) ((_x) & 0x0000FFFF) +/* Mask all but the low 20 bits */ +#define MASK_20(_x) ((_x) & 0x000FFFFF) +/* Mask all but the low 32 bits */ +#define MASK_32(_x) ((_x) & 0xFFFFFFFF) + +typedef enum +{ + FMT_EMULATED = 0, + FMT_DOUBLE_OPERAND, + FMT_SINGLE_OPERAND, + FMT_JUMP, + FMT_X_DOUBLE_OPERAND, + FMT_X_SINGLE_OPERAND, + FMT_X_EXCEPTION, + FMT_X_EMULATED, + FMT_X_ADDRESS, + + FMT_X = FMT_X_DOUBLE_OPERAND, + FMT_MASK = 0x000f, + + /* allowed modifiers: .b, .w, .a */ + MOD_NONE = 0, + MOD_W = 1 << 4, + MOD_B = 1 << 5, + MOD_A = 1 << 6, + MOD_MASK = 0x0070, + + /* opcode variant */ + VAR_MASK = 0x0380, +} +format_t; + +#define OP_V(x) (x << 7) struct msp430_opcode_s { char *name; - int fmt; - int insn_opnumb; - int bin_opcode; - int bin_mask; + format_t fmt; + unsigned int insn_opnumb; + unsigned int bin_opcode; + unsigned int bin_mask; +}; + +#define opcode_format(opcode) (opcode->fmt & FMT_MASK) +#define opcode_modifier(opcode) (opcode->fmt & MOD_MASK) +#define opcode_variant(opcode) ((opcode->fmt & VAR_MASK) >> 7) + +/* opcode variants: */ +enum +{ + V_NONE = 0, /* ordinary instruction */ + + /* FMT_EMULATED: */ + V_NOOP, /* no operands: set/clear bit instructions, reti */ + V_SHIFT, /* shift instructions */ + V_BR, /* br instruction */ + + /* FMT_SINGLE_OPERAND: */ + V_RETI = 1, /* reti */ + V_CALL = 2, /* hex operand in disassembly */ + V_PUSH, /* operand is source, not dest */ + + /* FMT_X_SINGLE_OPERAND: */ + /* V_NONE - #N operand disallowed */ + V_SWPSXT = 1, /* #N operand disallowed, special A/L, B/W bits case with .a modifier */ + V_PUSHX, /* #N operand allowed */ + + /* FMT_X_EXCEPTIONS: */ + V_CALLA = 0, /* calla */ + V_ROTM, /* two operands, rotations */ + V_POPM, /* two operands, popm */ + V_PUSHM, /* two operands, pushm */ + + /* FMT_X_EMULATED: */ + /* V_NONE - substituted by 430x double operand instruction */ + V_X_SHIFT, /* shifts */ + V_RETA, /* reta, short instruction, no operands */ + V_EMU_ADDR, /* substituted by address instruction other than mova */ + V_BRA, /* bra, substituted by mova address instruction == format II exception instruction */ + /* clra emulated by msp430 instruction */ + + /* FMT_X_ADDRESS: */ + V_MOVA = 1, /* mova, more address modes allowed */ + V_CG2_TWO, /* r3 has value #2 (instead of #0) */ }; -#define MSP_INSN(name, size, numb, bin, mask) { #name, size, numb, bin, mask } +/* For validation purposes, we ensure the tests include at least one + opcode of every distinct pattern. Identify the opcodes with this + sequence: +grep MSP_INSN include/opcode/msp430.h \ + | cut -c20-86 \ + | sort \ + | uniq \ + | while read PATTERN ; do + fgrep "${PATTERN}" include/opcode/msp430.h \ + | head -1 +done + */ + +#define MSP_INSN(name, format, opnumb, bin, mask) { #name, format, opnumb, bin, mask } -static struct msp430_opcode_s msp430_opcodes[] = +static struct msp430_opcode_s const msp430_opcodes[] = { - MSP_INSN (and, 1, 2, 0xf000, 0xf000), - MSP_INSN (inv, 0, 1, 0xe330, 0xfff0), - MSP_INSN (xor, 1, 2, 0xe000, 0xf000), - MSP_INSN (setz, 0, 0, 0xd322, 0xffff), - MSP_INSN (setc, 0, 0, 0xd312, 0xffff), - MSP_INSN (eint, 0, 0, 0xd232, 0xffff), - MSP_INSN (setn, 0, 0, 0xd222, 0xffff), - MSP_INSN (bis, 1, 2, 0xd000, 0xf000), - MSP_INSN (clrz, 0, 0, 0xc322, 0xffff), - MSP_INSN (clrc, 0, 0, 0xc312, 0xffff), - MSP_INSN (dint, 0, 0, 0xc232, 0xffff), - MSP_INSN (clrn, 0, 0, 0xc222, 0xffff), - MSP_INSN (bic, 1, 2, 0xc000, 0xf000), - MSP_INSN (bit, 1, 2, 0xb000, 0xf000), - MSP_INSN (dadc, 0, 1, 0xa300, 0xff30), - MSP_INSN (dadd, 1, 2, 0xa000, 0xf000), - MSP_INSN (tst, 0, 1, 0x9300, 0xff30), - MSP_INSN (cmp, 1, 2, 0x9000, 0xf000), - MSP_INSN (decd, 0, 1, 0x8320, 0xff30), - MSP_INSN (dec, 0, 1, 0x8310, 0xff30), - MSP_INSN (sub, 1, 2, 0x8000, 0xf000), - MSP_INSN (sbc, 0, 1, 0x7300, 0xff30), - MSP_INSN (subc, 1, 2, 0x7000, 0xf000), - MSP_INSN (adc, 0, 1, 0x6300, 0xff30), - MSP_INSN (rlc, 0, 2, 0x6000, 0xf000), - MSP_INSN (addc, 1, 2, 0x6000, 0xf000), - MSP_INSN (incd, 0, 1, 0x5320, 0xff30), - MSP_INSN (inc, 0, 1, 0x5310, 0xff30), - MSP_INSN (rla, 0, 2, 0x5000, 0xf000), - MSP_INSN (add, 1, 2, 0x5000, 0xf000), - MSP_INSN (nop, 0, 0, 0x4303, 0xffff), - MSP_INSN (clr, 0, 1, 0x4300, 0xff30), - MSP_INSN (ret, 0, 0, 0x4130, 0xff30), - MSP_INSN (pop, 0, 1, 0x4130, 0xff30), - MSP_INSN (br, 0, 3, 0x4000, 0xf000), - MSP_INSN (mov, 1, 2, 0x4000, 0xf000), - MSP_INSN (jmp, 3, 1, 0x3c00, 0xfc00), - MSP_INSN (jl, 3, 1, 0x3800, 0xfc00), - MSP_INSN (jge, 3, 1, 0x3400, 0xfc00), - MSP_INSN (jn, 3, 1, 0x3000, 0xfc00), - MSP_INSN (jc, 3, 1, 0x2c00, 0xfc00), - MSP_INSN (jhs, 3, 1, 0x2c00, 0xfc00), - MSP_INSN (jnc, 3, 1, 0x2800, 0xfc00), - MSP_INSN (jlo, 3, 1, 0x2800, 0xfc00), - MSP_INSN (jz, 3, 1, 0x2400, 0xfc00), - MSP_INSN (jeq, 3, 1, 0x2400, 0xfc00), - MSP_INSN (jnz, 3, 1, 0x2000, 0xfc00), - MSP_INSN (jne, 3, 1, 0x2000, 0xfc00), - MSP_INSN (reti, 2, 0, 0x1300, 0xffc0), - MSP_INSN (call, 2, 1, 0x1280, 0xffc0), - MSP_INSN (push, 2, 1, 0x1200, 0xff80), - MSP_INSN (sxt, 2, 1, 0x1180, 0xffc0), - MSP_INSN (rra, 2, 1, 0x1100, 0xff80), - MSP_INSN (swpb, 2, 1, 0x1080, 0xffc0), - MSP_INSN (rrc, 2, 1, 0x1000, 0xff80), - /* Simple polymorphs. */ - MSP_INSN (beq, 4, 0, 0, 0xffff), - MSP_INSN (bne, 4, 1, 0, 0xffff), - MSP_INSN (blt, 4, 2, 0, 0xffff), - MSP_INSN (bltu, 4, 3, 0, 0xffff), - MSP_INSN (bge, 4, 4, 0, 0xffff), - MSP_INSN (bgeu, 4, 5, 0, 0xffff), - MSP_INSN (bltn, 4, 6, 0, 0xffff), - MSP_INSN (jump, 4, 7, 0, 0xffff), - /* Long polymorphs. */ - MSP_INSN (bgt, 5, 0, 0, 0xffff), - MSP_INSN (bgtu, 5, 1, 0, 0xffff), - MSP_INSN (bleu, 5, 2, 0, 0xffff), - MSP_INSN (ble, 5, 3, 0, 0xffff), + MSP_INSN (and, FMT_DOUBLE_OPERAND | MOD_W|MOD_B | OP_V(0), 2, 0xf000, 0xfffff000), + MSP_INSN (inv, FMT_EMULATED | MOD_W|MOD_B | OP_V(0), 1, 0xe330, 0xfffffff0), + MSP_INSN (xor, FMT_DOUBLE_OPERAND | MOD_W|MOD_B | OP_V(0), 2, 0xe000, 0xfffff000), + MSP_INSN (setz, FMT_EMULATED | MOD_NONE | OP_V(V_NOOP), 0, 0xd322, 0xffffffff), + MSP_INSN (setc, FMT_EMULATED | MOD_NONE | OP_V(V_NOOP), 0, 0xd312, 0xffffffff), + MSP_INSN (eint, FMT_EMULATED | MOD_NONE | OP_V(V_NOOP), 0, 0xd232, 0xffffffff), + MSP_INSN (setn, FMT_EMULATED | MOD_NONE | OP_V(V_NOOP), 0, 0xd222, 0xffffffff), + MSP_INSN (bis, FMT_DOUBLE_OPERAND | MOD_W|MOD_B | OP_V(0), 2, 0xd000, 0xfffff000), + MSP_INSN (clrz, FMT_EMULATED | MOD_NONE | OP_V(V_NOOP), 0, 0xc322, 0xffffffff), + MSP_INSN (clrc, FMT_EMULATED | MOD_NONE | OP_V(V_NOOP), 0, 0xc312, 0xffffffff), + MSP_INSN (dint, FMT_EMULATED | MOD_NONE | OP_V(V_NOOP), 0, 0xc232, 0xffffffff), + MSP_INSN (clrn, FMT_EMULATED | MOD_NONE | OP_V(V_NOOP), 0, 0xc222, 0xffffffff), + MSP_INSN (bic, FMT_DOUBLE_OPERAND | MOD_W|MOD_B | OP_V(0), 2, 0xc000, 0xfffff000), + MSP_INSN (bit, FMT_DOUBLE_OPERAND | MOD_W|MOD_B | OP_V(0), 2, 0xb000, 0xfffff000), + MSP_INSN (dadc, FMT_EMULATED | MOD_W|MOD_B | OP_V(0), 1, 0xa300, 0xffffff30), + MSP_INSN (dadd, FMT_DOUBLE_OPERAND | MOD_W|MOD_B | OP_V(0), 2, 0xa000, 0xfffff000), + MSP_INSN (tst, FMT_EMULATED | MOD_W|MOD_B | OP_V(0), 1, 0x9300, 0xffffff30), + MSP_INSN (cmp, FMT_DOUBLE_OPERAND | MOD_W|MOD_B | OP_V(0), 2, 0x9000, 0xfffff000), + MSP_INSN (decd, FMT_EMULATED | MOD_W|MOD_B | OP_V(0), 1, 0x8320, 0xffffff30), + MSP_INSN (dec, FMT_EMULATED | MOD_W|MOD_B | OP_V(0), 1, 0x8310, 0xffffff30), + MSP_INSN (sub, FMT_DOUBLE_OPERAND | MOD_W|MOD_B | OP_V(0), 2, 0x8000, 0xfffff000), + MSP_INSN (sbc, FMT_EMULATED | MOD_W|MOD_B | OP_V(0), 1, 0x7300, 0xffffff30), + MSP_INSN (subc, FMT_DOUBLE_OPERAND | MOD_W|MOD_B | OP_V(0), 2, 0x7000, 0xfffff000), + MSP_INSN (adc, FMT_EMULATED | MOD_W|MOD_B | OP_V(0), 1, 0x6300, 0xffffff30), + MSP_INSN (rlc, FMT_EMULATED | MOD_W|MOD_B | OP_V(V_SHIFT), 2, 0x6000, 0xfffff000), + MSP_INSN (addc, FMT_DOUBLE_OPERAND | MOD_W|MOD_B | OP_V(0), 2, 0x6000, 0xfffff000), + MSP_INSN (incd, FMT_EMULATED | MOD_W|MOD_B | OP_V(0), 1, 0x5320, 0xffffff30), + MSP_INSN (inc, FMT_EMULATED | MOD_W|MOD_B | OP_V(0), 1, 0x5310, 0xffffff30), + MSP_INSN (rla, FMT_EMULATED | MOD_W|MOD_B | OP_V(V_SHIFT), 2, 0x5000, 0xfffff000), + MSP_INSN (add, FMT_DOUBLE_OPERAND | MOD_W|MOD_B | OP_V(0), 2, 0x5000, 0xfffff000), + MSP_INSN (nop, FMT_EMULATED | MOD_NONE | OP_V(V_NOOP), 0, 0x4303, 0xffffffff), + MSP_INSN (clr, FMT_EMULATED | MOD_W|MOD_B | OP_V(0), 1, 0x4300, 0xffffff30), + MSP_INSN (ret, FMT_EMULATED | MOD_NONE | OP_V(V_NOOP), 0, 0x4130, 0xffffffff), + MSP_INSN (pop, FMT_EMULATED | MOD_W|MOD_B | OP_V(0), 1, 0x4130, 0xffffff30), + MSP_INSN (br, FMT_EMULATED | MOD_NONE | OP_V(V_BR), 1, 0x4000, 0xfffff08f), + MSP_INSN (mov, FMT_DOUBLE_OPERAND | MOD_W|MOD_B | OP_V(0), 2, 0x4000, 0xfffff000), + + MSP_INSN (jmp, FMT_JUMP | MOD_NONE | OP_V(0), 1, 0x3c00, 0xfffffc00), + MSP_INSN (jl, FMT_JUMP | MOD_NONE | OP_V(0), 1, 0x3800, 0xfffffc00), + MSP_INSN (jge, FMT_JUMP | MOD_NONE | OP_V(0), 1, 0x3400, 0xfffffc00), + MSP_INSN (jn, FMT_JUMP | MOD_NONE | OP_V(0), 1, 0x3000, 0xfffffc00), + MSP_INSN (jc, FMT_JUMP | MOD_NONE | OP_V(0), 1, 0x2c00, 0xfffffc00), + MSP_INSN (jhs, FMT_JUMP | MOD_NONE | OP_V(0), 1, 0x2c00, 0xfffffc00), + MSP_INSN (jnc, FMT_JUMP | MOD_NONE | OP_V(0), 1, 0x2800, 0xfffffc00), + MSP_INSN (jlo, FMT_JUMP | MOD_NONE | OP_V(0), 1, 0x2800, 0xfffffc00), + MSP_INSN (jz, FMT_JUMP | MOD_NONE | OP_V(0), 1, 0x2400, 0xfffffc00), + MSP_INSN (jeq, FMT_JUMP | MOD_NONE | OP_V(0), 1, 0x2400, 0xfffffc00), + MSP_INSN (jnz, FMT_JUMP | MOD_NONE | OP_V(0), 1, 0x2000, 0xfffffc00), + MSP_INSN (jne, FMT_JUMP | MOD_NONE | OP_V(0), 1, 0x2000, 0xfffffc00), + + MSP_INSN (reti, FMT_SINGLE_OPERAND | MOD_NONE | OP_V(V_RETI), 0, 0x1300, 0xffffffc0), + MSP_INSN (call, FMT_SINGLE_OPERAND | MOD_NONE | OP_V(V_CALL), 1, 0x1280, 0xffffffc0), + MSP_INSN (push, FMT_SINGLE_OPERAND | MOD_W|MOD_B | OP_V(V_PUSH), 1, 0x1200, 0xffffff80), + MSP_INSN (sxt, FMT_SINGLE_OPERAND | MOD_NONE | OP_V(0), 1, 0x1180, 0xffffffc0), + MSP_INSN (rra, FMT_SINGLE_OPERAND | MOD_W|MOD_B | OP_V(0), 1, 0x1100, 0xffffff80), + MSP_INSN (swpb, FMT_SINGLE_OPERAND | MOD_NONE | OP_V(0), 1, 0x1080, 0xffffffc0), + MSP_INSN (rrc, FMT_SINGLE_OPERAND | MOD_W|MOD_B | OP_V(0), 1, 0x1000, 0xffffff80), + + + /* emulated instructions placed just before instruction emulated by for disassembly search */ + MSP_INSN (popx, FMT_X_EMULATED | MOD_W|MOD_B|MOD_A | OP_V(0), 1, 0x41301800, 0xff30f800), /* MOVX @SP+, dst */ + MSP_INSN (clrx, FMT_X_EMULATED | MOD_W|MOD_B|MOD_A | OP_V(0), 1, 0x43001800, 0xff30f800), /* MOVX #0, dst */ + MSP_INSN (movx, FMT_X_DOUBLE_OPERAND | MOD_W|MOD_B|MOD_A | OP_V(0), 2, 0x40001800, 0xf000f800), + MSP_INSN (incx, FMT_X_EMULATED | MOD_W|MOD_B|MOD_A | OP_V(0), 1, 0x53101800, 0xff30f800), /* ADDX #1, dst */ + MSP_INSN (incdx, FMT_X_EMULATED | MOD_W|MOD_B|MOD_A | OP_V(0), 1, 0x53201800, 0xff30f800), /* ADDX #2, dst */ + MSP_INSN (rlax, FMT_X_EMULATED | MOD_W|MOD_B|MOD_A | OP_V(V_X_SHIFT), 1, 0x50001800, 0xf000f800), /* ADDX dst, dst */ + MSP_INSN (addx, FMT_X_DOUBLE_OPERAND | MOD_W|MOD_B|MOD_A | OP_V(0), 2, 0x50001800, 0xf000f800), + MSP_INSN (adcx, FMT_X_EMULATED | MOD_W|MOD_B|MOD_A | OP_V(0), 1, 0x63001800, 0xff30f800), /* ADDCX #0, dst */ + MSP_INSN (rlcx, FMT_X_EMULATED | MOD_W|MOD_B|MOD_A | OP_V(V_X_SHIFT), 1, 0x60001800, 0xf000f800), /* ADDCX dst, dst */ + MSP_INSN (addcx, FMT_X_DOUBLE_OPERAND | MOD_W|MOD_B|MOD_A | OP_V(0), 2, 0x60001800, 0xf000f800), + MSP_INSN (sbcx, FMT_X_EMULATED | MOD_W|MOD_B|MOD_A | OP_V(0), 1, 0x73001800, 0xff30f800), /* SUBCX #0, dst */ + MSP_INSN (subcx, FMT_X_DOUBLE_OPERAND | MOD_W|MOD_B|MOD_A | OP_V(0), 2, 0x70001800, 0xf000f800), + MSP_INSN (decx, FMT_X_EMULATED | MOD_W|MOD_B|MOD_A | OP_V(0), 1, 0x83101800, 0xff30f800), /* SUBX #1, dst */ + MSP_INSN (decdx, FMT_X_EMULATED | MOD_W|MOD_B|MOD_A | OP_V(0), 1, 0x83201800, 0xff30f800), /* SUBX #2, dst */ + MSP_INSN (subx, FMT_X_DOUBLE_OPERAND | MOD_W|MOD_B|MOD_A | OP_V(0), 2, 0x80001800, 0xf000f800), + MSP_INSN (tstx, FMT_X_EMULATED | MOD_W|MOD_B|MOD_A | OP_V(0), 1, 0x93001800, 0xff30f800), /* CMPX #0, dst */ + MSP_INSN (cmpx, FMT_X_DOUBLE_OPERAND | MOD_W|MOD_B|MOD_A | OP_V(0), 2, 0x90001800, 0xf000f800), + MSP_INSN (dadcx, FMT_X_EMULATED | MOD_W|MOD_B|MOD_A | OP_V(0), 1, 0xa3001800, 0xff30f800), /* DADDX #0, dst */ + MSP_INSN (daddx, FMT_X_DOUBLE_OPERAND | MOD_W|MOD_B|MOD_A | OP_V(0), 2, 0xa0001800, 0xf000f800), + MSP_INSN (bitx, FMT_X_DOUBLE_OPERAND | MOD_W|MOD_B|MOD_A | OP_V(0), 2, 0xb0001800, 0xf000f800), + MSP_INSN (bicx, FMT_X_DOUBLE_OPERAND | MOD_W|MOD_B|MOD_A | OP_V(0), 2, 0xc0001800, 0xf000f800), + MSP_INSN (bisx, FMT_X_DOUBLE_OPERAND | MOD_W|MOD_B|MOD_A | OP_V(0), 2, 0xd0001800, 0xf000f800), + MSP_INSN (invx, FMT_X_EMULATED | MOD_W|MOD_B|MOD_A | OP_V(0), 1, 0xe3301800, 0xff30f800), /* XORX #-1, dst */ + MSP_INSN (xorx, FMT_X_DOUBLE_OPERAND | MOD_W|MOD_B|MOD_A | OP_V(0), 2, 0xe0001800, 0xf000f800), + MSP_INSN (andx, FMT_X_DOUBLE_OPERAND | MOD_W|MOD_B|MOD_A | OP_V(0), 2, 0xf0001800, 0xf000f800), + + MSP_INSN (rrcx, FMT_X_SINGLE_OPERAND | MOD_W|MOD_B|MOD_A | OP_V(0), 1, 0x10001800, 0xff80f900), + MSP_INSN (rrux, FMT_X_SINGLE_OPERAND | MOD_W|MOD_B|MOD_A | OP_V(0), 1, 0x10001900, 0xff80f900), + MSP_INSN (swpbx, FMT_X_SINGLE_OPERAND | MOD_W|MOD_A | OP_V(V_SWPSXT), 1, 0x10801800, 0xffc0f800), + MSP_INSN (rrax, FMT_X_SINGLE_OPERAND | MOD_W|MOD_B|MOD_A | OP_V(0), 1, 0x11001800, 0xff80f800), + MSP_INSN (sxtx, FMT_X_SINGLE_OPERAND | MOD_W|MOD_A | OP_V(V_SWPSXT), 1, 0x11801800, 0xffc0f800), + MSP_INSN (pushx, FMT_X_SINGLE_OPERAND | MOD_W|MOD_B|MOD_A | OP_V(V_PUSHX), 1, 0x12001800, 0xff80f800), + + MSP_INSN (calla, FMT_X_EXCEPTION | MOD_NONE | OP_V(V_CALLA), 1, 0x1300, 0xffffff00), + MSP_INSN (pushm, FMT_X_EXCEPTION | MOD_W|MOD_A | OP_V(V_PUSHM), 2, 0x1400, 0xfffffe00), + MSP_INSN (popm, FMT_X_EXCEPTION | MOD_W|MOD_A | OP_V(V_POPM), 2, 0x1600, 0xfffffe00), + MSP_INSN (rrcm, FMT_X_EXCEPTION | MOD_W|MOD_A | OP_V(V_ROTM), 2, 0x0040, 0xfffff3e0), + MSP_INSN (rram, FMT_X_EXCEPTION | MOD_W|MOD_A | OP_V(V_ROTM), 2, 0x0140, 0xfffff3e0), + MSP_INSN (rlam, FMT_X_EXCEPTION | MOD_W|MOD_A | OP_V(V_ROTM), 2, 0x0240, 0xfffff3e0), + MSP_INSN (rrum, FMT_X_EXCEPTION | MOD_W|MOD_A | OP_V(V_ROTM), 2, 0x0340, 0xfffff3e0), + /* Address. */ + MSP_INSN (incda, FMT_X_EMULATED | MOD_NONE | OP_V(V_EMU_ADDR), 1, 0x03e0, 0xfffffff0), /* ADDA #2, Rdst = ADDA R3, Rdst */ + MSP_INSN (adda, FMT_X_ADDRESS | MOD_NONE | OP_V(V_CG2_TWO), 2, 0x00a0, 0xfffff0b0), + MSP_INSN (tsta, FMT_X_EMULATED | MOD_NONE | OP_V(V_EMU_ADDR), 1, 0x03d0, 0xfffffff0), /* CMPA #0, Rdst = CMPA R3, Rdst */ + MSP_INSN (cmpa, FMT_X_ADDRESS | MOD_NONE | OP_V(0), 2, 0x0090, 0xfffff0b0), + MSP_INSN (decda, FMT_X_EMULATED | MOD_NONE | OP_V(V_EMU_ADDR), 1, 0x03f0, 0xfffffff0), /* SUBA #2, Rdst = SUBA R3, Rdst */ + MSP_INSN (suba, FMT_X_ADDRESS | MOD_NONE | OP_V(V_CG2_TWO), 2, 0x00b0, 0xfffff0b0), + MSP_INSN (reta, FMT_X_EMULATED | MOD_NONE | OP_V(V_RETA), 0, 0x0110, 0xffffffff), /* MOVA @SP+, PC */ + MSP_INSN (bra, FMT_X_EMULATED | MOD_NONE | OP_V(V_BRA), 1, 0x0000, 0xfffff0cf), /* MOVA dst, PC */ + MSP_INSN (bra, FMT_X_EMULATED | MOD_NONE | OP_V(V_BRA), 1, 0x0080, 0xfffff0bf), /* MOVA #imm20, PC; MOVA Rsrc, Rdst */ + MSP_INSN (clra, FMT_X_EMULATED | MOD_NONE | OP_V(V_MOVA), 1, 0x03c0, 0xfffffff0), /* MOVA #0, Rdst */ + MSP_INSN (mova, FMT_X_ADDRESS | MOD_NONE | OP_V(V_MOVA), 1, 0x0000, 0xfffff000), + /* End of instruction set. */ { NULL, 0, 0, 0, 0 } }; diff --git binutils-2.22.orig/ld/Makefile.am binutils-2.22/ld/Makefile.am index 5ae86ba..2530b48 100644 --- binutils-2.22.orig/ld/Makefile.am +++ binutils-2.22/ld/Makefile.am @@ -335,65 +335,7 @@ ALL_EMULATION_SOURCES = \ emipspe.c \ emn10200.c \ emn10300.c \ - emsp430x110.c \ - emsp430x1101.c \ - emsp430x1111.c \ - emsp430x112.c \ - emsp430x1121.c \ - emsp430x1122.c \ - emsp430x1132.c \ - emsp430x122.c \ - emsp430x1222.c \ - emsp430x123.c \ - emsp430x1232.c \ - emsp430x133.c \ - emsp430x1331.c \ - emsp430x135.c \ - emsp430x1351.c \ - emsp430x147.c \ - emsp430x148.c \ - emsp430x149.c \ - emsp430x155.c \ - emsp430x156.c \ - emsp430x157.c \ - emsp430x1610.c \ - emsp430x1611.c \ - emsp430x1612.c \ - emsp430x167.c \ - emsp430x168.c \ - emsp430x169.c \ - emsp430x2101.c \ - emsp430x2111.c \ - emsp430x2121.c \ - emsp430x2131.c \ - emsp430x311.c \ - emsp430x312.c \ - emsp430x313.c \ - emsp430x314.c \ - emsp430x315.c \ - emsp430x323.c \ - emsp430x325.c \ - emsp430x336.c \ - emsp430x337.c \ - emsp430x412.c \ - emsp430x413.c \ - emsp430x415.c \ - emsp430x417.c \ - emsp430x435.c \ - emsp430x436.c \ - emsp430x437.c \ - emsp430x447.c \ - emsp430x448.c \ - emsp430x449.c \ - emsp430xE423.c \ - emsp430xE425.c \ - emsp430xE427.c \ - emsp430xG437.c \ - emsp430xG438.c \ - emsp430xG439.c \ - emsp430xW423.c \ - emsp430xW425.c \ - emsp430xW427.c \ + emsp430.c \ enews.c \ ens32knbsd.c \ eor32.c \ @@ -1436,242 +1378,10 @@ emn10300.c: $(srcdir)/emulparams/mn10300.sh \ $(srcdir)/emulparams/mn10200.sh \ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} ${GENSCRIPTS} mn10300 "$(tdir_mn10300)" -emsp430x110.c: $(srcdir)/emulparams/msp430all.sh \ +emsp430.c: $(srcdir)/emulparams/msp430uni.sh \ $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x110 "$(tdir_msp430x110)" msp430all -emsp430x1101.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1101 "$(tdir_msp430x1101)" msp430all -emsp430x1111.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1111 "$(tdir_msp430x1111)" msp430all -emsp430x112.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x112 "$(tdir_msp430x112)" msp430all -emsp430x1121.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1121 "$(tdir_msp430x1121)" msp430all -emsp430x1122.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1122 "$(tdir_msp430x1122)" msp430all -emsp430x1132.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1132 "$(tdir_msp430x1132)" msp430all -emsp430x122.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x122 "$(tdir_msp430x122)" msp430all -emsp430x1222.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1222 "$(tdir_msp430x1222)" msp430all -emsp430x123.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x123 "$(tdir_msp430x123)" msp430all -emsp430x1232.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1232 "$(tdir_msp430x1232)" msp430all -emsp430x133.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x133 "$(tdir_msp430x133)" msp430all -emsp430x1331.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1331 "$(tdir_msp430x1331)" msp430all -emsp430x135.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x135 "$(tdir_msp430x135)" msp430all -emsp430x1351.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1351 "$(tdir_msp430x1351)" msp430all -emsp430x147.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x147 "$(tdir_msp430x147)" msp430all -emsp430x148.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x148 "$(tdir_msp430x148)" msp430all -emsp430x149.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x149 "$(tdir_msp430x149)" msp430all -emsp430x155.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x155 "$(tdir_msp430x155)" msp430all -emsp430x156.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x156 "$(tdir_msp430x156)" msp430all -emsp430x157.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x157 "$(tdir_msp430x157)" msp430all -emsp430x1610.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1610 "$(tdir_msp430x1610)" msp430all -emsp430x1611.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1611 "$(tdir_msp430x1611)" msp430all -emsp430x1612.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1612 "$(tdir_msp430x1612)" msp430all -emsp430x167.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x167 "$(tdir_msp430x167)" msp430all -emsp430x168.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x168 "$(tdir_msp430x168)" msp430all -emsp430x169.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x169 "$(tdir_msp430x169)" msp430all -emsp430x2101.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x2101 "$(tdir_msp430x2101)" msp430all -emsp430x2111.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x2111 "$(tdir_msp430x2111)" msp430all -emsp430x2121.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x2121 "$(tdir_msp430x2121)" msp430all -emsp430x2131.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x2131 "$(tdir_msp430x2131)" msp430all -emsp430x311.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x311 "$(tdir_msp430x311)" msp430all -emsp430x312.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x312 "$(tdir_msp430x312)" msp430all -emsp430x313.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x313 "$(tdir_msp430x313)" msp430all -emsp430x314.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x314 "$(tdir_msp430x314)" msp430all -emsp430x315.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x315 "$(tdir_msp430x315)" msp430all -emsp430x323.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x323 "$(tdir_msp430x323)" msp430all -emsp430x325.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x325 "$(tdir_msp430x325)" msp430all -emsp430x336.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x336 "$(tdir_msp430x336)" msp430all -emsp430x337.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x337 "$(tdir_msp430x337)" msp430all -emsp430x412.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x412 "$(tdir_msp430x412)" msp430all -emsp430x413.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x413 "$(tdir_msp430x413)" msp430all -emsp430x415.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x415 "$(tdir_msp430x415)" msp430all -emsp430x417.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x417 "$(tdir_msp430x417)" msp430all -emsp430x435.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x435 "$(tdir_msp430x435)" msp430all -emsp430x436.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x436 "$(tdir_msp430x436)" msp430all -emsp430x437.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x437 "$(tdir_msp430x437)" msp430all -emsp430x447.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x447 "$(tdir_msp430x447)" msp430all -emsp430x448.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x448 "$(tdir_msp430x448)" msp430all -emsp430x449.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x449 "$(tdir_msp430x449)" msp430all -emsp430xE423.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xE423 "$(tdir_msp430xE423)" msp430all -emsp430xE425.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xE425 "$(tdir_msp430xE425)" msp430all -emsp430xE427.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xE427 "$(tdir_msp430xE427)" msp430all -emsp430xG437.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xG437 "$(tdir_msp430xG437)" msp430all -emsp430xG438.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xG438 "$(tdir_msp430xG438)" msp430all -emsp430xG439.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xG439 "$(tdir_msp430xG439)" msp430all -emsp430xW423.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xW423 "$(tdir_msp430xW423)" msp430all -emsp430xW425.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xW425 "$(tdir_msp430xW425)" msp430all -emsp430xW427.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xW427 "$(tdir_msp430xW427)" msp430all + ${GENSCRIPTS} msp430 "$(tdir_msp430)" msp430uni enews.c: $(srcdir)/emulparams/news.sh \ $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS} ${GENSCRIPTS} news "$(tdir_news)" diff --git binutils-2.22.orig/ld/Makefile.in binutils-2.22/ld/Makefile.in index f062b92..ac63d29 100644 --- binutils-2.22.orig/ld/Makefile.in +++ binutils-2.22/ld/Makefile.in @@ -641,65 +641,7 @@ ALL_EMULATION_SOURCES = \ emipspe.c \ emn10200.c \ emn10300.c \ - emsp430x110.c \ - emsp430x1101.c \ - emsp430x1111.c \ - emsp430x112.c \ - emsp430x1121.c \ - emsp430x1122.c \ - emsp430x1132.c \ - emsp430x122.c \ - emsp430x1222.c \ - emsp430x123.c \ - emsp430x1232.c \ - emsp430x133.c \ - emsp430x1331.c \ - emsp430x135.c \ - emsp430x1351.c \ - emsp430x147.c \ - emsp430x148.c \ - emsp430x149.c \ - emsp430x155.c \ - emsp430x156.c \ - emsp430x157.c \ - emsp430x1610.c \ - emsp430x1611.c \ - emsp430x1612.c \ - emsp430x167.c \ - emsp430x168.c \ - emsp430x169.c \ - emsp430x2101.c \ - emsp430x2111.c \ - emsp430x2121.c \ - emsp430x2131.c \ - emsp430x311.c \ - emsp430x312.c \ - emsp430x313.c \ - emsp430x314.c \ - emsp430x315.c \ - emsp430x323.c \ - emsp430x325.c \ - emsp430x336.c \ - emsp430x337.c \ - emsp430x412.c \ - emsp430x413.c \ - emsp430x415.c \ - emsp430x417.c \ - emsp430x435.c \ - emsp430x436.c \ - emsp430x437.c \ - emsp430x447.c \ - emsp430x448.c \ - emsp430x449.c \ - emsp430xE423.c \ - emsp430xE425.c \ - emsp430xE427.c \ - emsp430xG437.c \ - emsp430xG438.c \ - emsp430xG439.c \ - emsp430xW423.c \ - emsp430xW425.c \ - emsp430xW427.c \ + emsp430.c \ enews.c \ ens32knbsd.c \ eor32.c \ @@ -1270,65 +1212,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emmo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emn10200.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emn10300.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x110.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1101.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1111.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x112.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1121.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1122.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1132.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x122.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1222.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x123.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1232.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x133.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1331.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x135.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1351.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x147.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x148.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x149.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x155.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x156.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x157.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1610.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1611.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x1612.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x167.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x168.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x169.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x2101.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x2111.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x2121.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x2131.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x311.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x312.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x313.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x314.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x315.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x323.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x325.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x336.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x337.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x412.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x413.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x415.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x417.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x435.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x436.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x437.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x447.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x448.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430x449.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430xE423.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430xE425.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430xE427.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430xG437.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430xG438.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430xG439.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430xW423.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430xW425.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430xW427.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/emsp430.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/enews.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ens32knbsd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/eor32.Po@am__quote@ @@ -2889,242 +2773,10 @@ emn10300.c: $(srcdir)/emulparams/mn10300.sh \ $(srcdir)/emulparams/mn10200.sh \ $(ELF_DEPS) $(srcdir)/scripttempl/elf.sc ${GEN_DEPENDS} ${GENSCRIPTS} mn10300 "$(tdir_mn10300)" -emsp430x110.c: $(srcdir)/emulparams/msp430all.sh \ +emsp430.c: $(srcdir)/emulparams/msp430uni.sh \ $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x110 "$(tdir_msp430x110)" msp430all -emsp430x1101.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1101 "$(tdir_msp430x1101)" msp430all -emsp430x1111.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1111 "$(tdir_msp430x1111)" msp430all -emsp430x112.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x112 "$(tdir_msp430x112)" msp430all -emsp430x1121.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1121 "$(tdir_msp430x1121)" msp430all -emsp430x1122.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1122 "$(tdir_msp430x1122)" msp430all -emsp430x1132.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1132 "$(tdir_msp430x1132)" msp430all -emsp430x122.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x122 "$(tdir_msp430x122)" msp430all -emsp430x1222.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1222 "$(tdir_msp430x1222)" msp430all -emsp430x123.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x123 "$(tdir_msp430x123)" msp430all -emsp430x1232.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1232 "$(tdir_msp430x1232)" msp430all -emsp430x133.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x133 "$(tdir_msp430x133)" msp430all -emsp430x1331.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1331 "$(tdir_msp430x1331)" msp430all -emsp430x135.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x135 "$(tdir_msp430x135)" msp430all -emsp430x1351.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1351 "$(tdir_msp430x1351)" msp430all -emsp430x147.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x147 "$(tdir_msp430x147)" msp430all -emsp430x148.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x148 "$(tdir_msp430x148)" msp430all -emsp430x149.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x149 "$(tdir_msp430x149)" msp430all -emsp430x155.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x155 "$(tdir_msp430x155)" msp430all -emsp430x156.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x156 "$(tdir_msp430x156)" msp430all -emsp430x157.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x157 "$(tdir_msp430x157)" msp430all -emsp430x1610.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1610 "$(tdir_msp430x1610)" msp430all -emsp430x1611.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1611 "$(tdir_msp430x1611)" msp430all -emsp430x1612.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x1612 "$(tdir_msp430x1612)" msp430all -emsp430x167.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x167 "$(tdir_msp430x167)" msp430all -emsp430x168.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x168 "$(tdir_msp430x168)" msp430all -emsp430x169.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x169 "$(tdir_msp430x169)" msp430all -emsp430x2101.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x2101 "$(tdir_msp430x2101)" msp430all -emsp430x2111.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x2111 "$(tdir_msp430x2111)" msp430all -emsp430x2121.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x2121 "$(tdir_msp430x2121)" msp430all -emsp430x2131.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x2131 "$(tdir_msp430x2131)" msp430all -emsp430x311.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x311 "$(tdir_msp430x311)" msp430all -emsp430x312.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x312 "$(tdir_msp430x312)" msp430all -emsp430x313.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x313 "$(tdir_msp430x313)" msp430all -emsp430x314.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x314 "$(tdir_msp430x314)" msp430all -emsp430x315.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x315 "$(tdir_msp430x315)" msp430all -emsp430x323.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x323 "$(tdir_msp430x323)" msp430all -emsp430x325.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x325 "$(tdir_msp430x325)" msp430all -emsp430x336.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x336 "$(tdir_msp430x336)" msp430all -emsp430x337.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430_3.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x337 "$(tdir_msp430x337)" msp430all -emsp430x412.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x412 "$(tdir_msp430x412)" msp430all -emsp430x413.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x413 "$(tdir_msp430x413)" msp430all -emsp430x415.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x415 "$(tdir_msp430x415)" msp430all -emsp430x417.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x417 "$(tdir_msp430x417)" msp430all -emsp430x435.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x435 "$(tdir_msp430x435)" msp430all -emsp430x436.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x436 "$(tdir_msp430x436)" msp430all -emsp430x437.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x437 "$(tdir_msp430x437)" msp430all -emsp430x447.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x447 "$(tdir_msp430x447)" msp430all -emsp430x448.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x448 "$(tdir_msp430x448)" msp430all -emsp430x449.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430x449 "$(tdir_msp430x449)" msp430all -emsp430xE423.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xE423 "$(tdir_msp430xE423)" msp430all -emsp430xE425.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xE425 "$(tdir_msp430xE425)" msp430all -emsp430xE427.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xE427 "$(tdir_msp430xE427)" msp430all -emsp430xG437.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xG437 "$(tdir_msp430xG437)" msp430all -emsp430xG438.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xG438 "$(tdir_msp430xG438)" msp430all -emsp430xG439.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xG439 "$(tdir_msp430xG439)" msp430all -emsp430xW423.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xW423 "$(tdir_msp430xW423)" msp430all -emsp430xW425.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xW425 "$(tdir_msp430xW425)" msp430all -emsp430xW427.c: $(srcdir)/emulparams/msp430all.sh \ - $(ELF_GEN_DEPS) $(srcdir)/scripttempl/elf32msp430.sc \ - ${GEN_DEPENDS} - ${GENSCRIPTS} msp430xW427 "$(tdir_msp430xW427)" msp430all + ${GENSCRIPTS} msp430 "$(tdir_msp430)" msp430uni enews.c: $(srcdir)/emulparams/news.sh \ $(srcdir)/emultempl/generic.em $(srcdir)/scripttempl/aout.sc ${GEN_DEPENDS} ${GENSCRIPTS} news "$(tdir_news)" diff --git binutils-2.22.orig/ld/configure.tgt binutils-2.22/ld/configure.tgt index 197f27a..ff529b4 100644 --- binutils-2.22.orig/ld/configure.tgt +++ binutils-2.22/ld/configure.tgt @@ -436,8 +436,7 @@ mn10300-*-*) targ_emul=mn10300 ;; mt-*elf) targ_emul=elf32mt ;; -msp430-*-*) targ_emul=msp430x110 - targ_extra_emuls="msp430x112 msp430x1101 msp430x1111 msp430x1121 msp430x1122 msp430x1132 msp430x122 msp430x123 msp430x1222 msp430x1232 msp430x133 msp430x135 msp430x1331 msp430x1351 msp430x147 msp430x148 msp430x149 msp430x155 msp430x156 msp430x157 msp430x167 msp430x168 msp430x169 msp430x1610 msp430x1611 msp430x1612 msp430x2101 msp430x2111 msp430x2121 msp430x2131 msp430x311 msp430x312 msp430x313 msp430x314 msp430x315 msp430x323 msp430x325 msp430x336 msp430x337 msp430x412 msp430x413 msp430x415 msp430x417 msp430xE423 msp430xE425 msp430xE427 msp430xW423 msp430xW425 msp430xW427 msp430xG437 msp430xG438 msp430xG439 msp430x435 msp430x436 msp430x437 msp430x447 msp430x448 msp430x449" +msp430-*-*) targ_emul=msp430 ;; ns32k-pc532-mach* | ns32k-pc532-ux*) targ_emul=pc532macha ;; ns32k-*-netbsd* | ns32k-pc532-lites*) targ_emul=ns32knbsd diff --git binutils-2.22.orig/ld/emulparams/msp430all.sh binutils-2.22/ld/emulparams/msp430all.sh deleted file mode 100644 index 57d21c2..0000000 --- binutils-2.22.orig/ld/emulparams/msp430all.sh +++ /dev/null @@ -1,553 +0,0 @@ -#!/bin/sh - -# This called by genscripts_extra.sh - -MSP430_NAME=${EMULATION_NAME} - -SCRIPT_NAME=elf32msp430 -TEMPLATE_NAME=generic -EXTRA_EM_FILE=genelf -OUTPUT_FORMAT="elf32-msp430" -MACHINE= -MAXPAGESIZE=1 -EMBEDDED=yes - -if [ "${MSP430_NAME}" = "msp430x110" ] ; then -ARCH=msp:11 -ROM_START=0xfc00 -ROM_SIZE=0x3e0 -RAM_START=0x0200 -RAM_SIZE=128 -STACK=0x280 -fi - -if [ "${MSP430_NAME}" = "msp430x1101" ] ; then -ARCH=msp:110 -ROM_START=0xfc00 -ROM_SIZE=0x3e0 -RAM_START=0x0200 -RAM_SIZE=128 -STACK=0x280 -fi - -if [ "${MSP430_NAME}" = "msp430x1111" ] ; then -ARCH=msp:110 -ROM_START=0xf800 -ROM_SIZE=0x07e0 -RAM_START=0x0200 -RAM_SIZE=128 -STACK=0x280 -fi - -if [ "${MSP430_NAME}" = "msp430x112" ] ; then -ARCH=msp:11 -ROM_START=0xf000 -ROM_SIZE=0xfe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x1121" ] ; then -ARCH=msp:110 -ROM_START=0xf000 -ROM_SIZE=0x0fe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x1122" ] ; then -ARCH=msp:110 -ROM_START=0xf000 -ROM_SIZE=0x0fe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x1132" ] ; then -ARCH=msp:110 -ROM_START=0xe000 -ROM_SIZE=0x1fe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x122" ] ; then -ARCH=msp:12 -ROM_START=0xf000 -ROM_SIZE=0xfe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x1222" ] ; then -ARCH=msp:12 -ROM_START=0xf000 -ROM_SIZE=0xfe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x123" ] ; then -ARCH=msp:12 -ROM_START=0xe000 -ROM_SIZE=0x1fe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x1232" ] ; then -ARCH=msp:12 -ROM_START=0xe000 -ROM_SIZE=0x1fe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x133" ] ; then -ARCH=msp:13 -ROM_START=0xe000 -ROM_SIZE=0x1fe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x1331" ] ; then -ARCH=msp:13 -ROM_START=0xe000 -ROM_SIZE=0x1fe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x135" ] ; then -ARCH=msp:13 -ROM_START=0xc000 -ROM_SIZE=0x3fe0 -RAM_START=0x0200 -RAM_SIZE=512 -STACK=0x400 -fi - -if [ "${MSP430_NAME}" = "msp430x1351" ] ; then -ARCH=msp:13 -ROM_START=0xc000 -ROM_SIZE=0x3fe0 -RAM_START=0x0200 -RAM_SIZE=512 -STACK=0x400 -fi - -if [ "${MSP430_NAME}" = "msp430x147" ] ; then -ARCH=msp:14 -ROM_START=0x8000 -ROM_SIZE=0x7fe0 -RAM_START=0x0200 -RAM_SIZE=1K -STACK=0x600 -fi - -if [ "${MSP430_NAME}" = "msp430x148" ] ; then -ARCH=msp:14 -ROM_START=0x4000 -ROM_SIZE=0xbfe0 -RAM_START=0x0200 -RAM_SIZE=0x0800 -STACK=0xa00 -fi - -if [ "${MSP430_NAME}" = "msp430x149" ] ; then -ARCH=msp:14 -ROM_START=0x1100 -ROM_SIZE=0xeee0 -RAM_START=0x0200 -RAM_SIZE=0x0800 -STACK=0xa00 -fi - -if [ "${MSP430_NAME}" = "msp430x155" ] ; then -ARCH=msp:15 -ROM_START=0xc000 -ROM_SIZE=0x3fe0 -RAM_START=0x0200 -RAM_SIZE=512 -STACK=0x400 -fi - -if [ "${MSP430_NAME}" = "msp430x156" ] ; then -ARCH=msp:15 -ROM_START=0xa000 -ROM_SIZE=0x5fe0 -RAM_START=0x0200 -RAM_SIZE=512 -STACK=0x400 -fi - -if [ "${MSP430_NAME}" = "msp430x157" ] ; then -ARCH=msp:15 -ROM_START=0x8000 -ROM_SIZE=0x7fe0 -RAM_START=0x0200 -RAM_SIZE=1K -STACK=0x600 -fi - -if [ "${MSP430_NAME}" = "msp430x167" ] ; then -ARCH=msp:16 -ROM_START=0x8000 -ROM_SIZE=0x7fe0 -RAM_START=0x0200 -RAM_SIZE=1K -STACK=0x600 -fi - -if [ "${MSP430_NAME}" = "msp430x168" ] ; then -ARCH=msp:16 -ROM_START=0x4000 -ROM_SIZE=0xbfe0 -RAM_START=0x0200 -RAM_SIZE=0x0800 -STACK=0xa00 -fi - -if [ "${MSP430_NAME}" = "msp430x169" ] ; then -ARCH=msp:16 -ROM_START=0x1100 -ROM_SIZE=0xeee0 -RAM_START=0x0200 -RAM_SIZE=0x0800 -STACK=0xa00 -fi - -if [ "${MSP430_NAME}" = "msp430x1610" ] ; then -ARCH=msp:16 -ROM_START=0x8000 -ROM_SIZE=0x7fe0 -RAM_START=0x1100 -RAM_SIZE=0x1400 -STACK=0x2500 -fi - -if [ "${MSP430_NAME}" = "msp430x1611" ] ; then -ARCH=msp:16 -ROM_START=0x4000 -ROM_SIZE=0xbfe0 -RAM_START=0x1100 -RAM_SIZE=0x2800 -STACK=0x3900 -fi - -if [ "${MSP430_NAME}" = "msp430x1612" ] ; then -ARCH=msp:16 -ROM_START=0x2500 -ROM_SIZE=0xdae0 -RAM_START=0x1100 -RAM_SIZE=0x1400 -STACK=0x2500 -fi - -if [ "${MSP430_NAME}" = "msp430x2101" ] ; then -ARCH=msp:21 -ROM_START=0xFC00 -ROM_SIZE=0x03e0 -RAM_START=0x0200 -RAM_SIZE=128 -STACK=0x280 -fi - -if [ "${MSP430_NAME}" = "msp430x2111" ] ; then -ARCH=msp:21 -ROM_START=0xF800 -ROM_SIZE=0x07e0 -RAM_START=0x0200 -RAM_SIZE=128 -STACK=0x280 -fi - -if [ "${MSP430_NAME}" = "msp430x2121" ] ; then -ARCH=msp:21 -ROM_START=0xf000 -ROM_SIZE=0x0fe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x2131" ] ; then -ARCH=msp:21 -ROM_START=0xe000 -ROM_SIZE=0x1fe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x311" ] ; then -ARCH=msp:31 -SCRIPT_NAME=elf32msp430_3 -ROM_START=0xf800 -ROM_SIZE=0x07e0 -RAM_START=0x0200 -RAM_SIZE=128 -STACK=0x280 -fi - -if [ "${MSP430_NAME}" = "msp430x312" ] ; then -ARCH=msp:31 -SCRIPT_NAME=elf32msp430_3 -ROM_START=0xf000 -ROM_SIZE=0x0fe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x313" ] ; then -ARCH=msp:31 -SCRIPT_NAME=elf32msp430_3 -ROM_START=0xe000 -ROM_SIZE=0x1fe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x314" ] ; then -ARCH=msp:31 -SCRIPT_NAME=elf32msp430_3 -ROM_START=0xd000 -ROM_SIZE=0x2fe0 -RAM_START=0x0200 -RAM_SIZE=512 -STACK=0x400 -fi - -if [ "${MSP430_NAME}" = "msp430x315" ] ; then -ARCH=msp:31 -SCRIPT_NAME=elf32msp430_3 -ROM_START=0xc000 -ROM_SIZE=0x3fe0 -RAM_START=0x0200 -RAM_SIZE=512 -STACK=0x400 -fi - -if [ "${MSP430_NAME}" = "msp430x323" ] ; then -ARCH=msp:32 -SCRIPT_NAME=elf32msp430_3 -ROM_START=0xe000 -ROM_SIZE=0x1fe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x325" ] ; then -ARCH=msp:32 -SCRIPT_NAME=elf32msp430_3 -ROM_START=0xc000 -ROM_SIZE=0x3fe0 -RAM_START=0x0200 -RAM_SIZE=512 -STACK=0x400 -fi - -if [ "${MSP430_NAME}" = "msp430x336" ] ; then -ARCH=msp:33 -SCRIPT_NAME=elf32msp430_3 -ROM_START=0xa000 -ROM_SIZE=0x5fe0 -RAM_START=0x0200 -RAM_SIZE=1024 -STACK=0x600 -fi - -if [ "${MSP430_NAME}" = "msp430x337" ] ; then -ARCH=msp:33 -SCRIPT_NAME=elf32msp430_3 -ROM_START=0x8000 -ROM_SIZE=0x7fe0 -RAM_START=0x0200 -RAM_SIZE=1024 -STACK=0x600 -fi - -if [ "${MSP430_NAME}" = "msp430x412" ] ; then -ARCH=msp:41 -ROM_START=0xf000 -ROM_SIZE=0x0fe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x413" ] ; then -ARCH=msp:41 -ROM_START=0xe000 -ROM_SIZE=0x1fe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430x415" ] ; then -ARCH=msp:41 -ROM_START=0xc000 -ROM_SIZE=0x3fe0 -RAM_START=0x0200 -RAM_SIZE=512 -STACK=0x400 -fi - -if [ "${MSP430_NAME}" = "msp430x417" ] ; then -ARCH=msp:41 -ROM_START=0x8000 -ROM_SIZE=0x7fe0 -RAM_START=0x0200 -RAM_SIZE=1024 -STACK=0x600 -fi - -if [ "${MSP430_NAME}" = "msp430x435" ] ; then -ARCH=msp:43 -ROM_START=0xc000 -ROM_SIZE=0x3fe0 -RAM_START=0x0200 -RAM_SIZE=512 -STACK=0x400 -fi - -if [ "${MSP430_NAME}" = "msp430x436" ] ; then -ARCH=msp:43 -ROM_START=0xa000 -ROM_SIZE=0x5fe0 -RAM_START=0x0200 -RAM_SIZE=1024 -STACK=0x600 -fi - -if [ "${MSP430_NAME}" = "msp430x437" ] ; then -ARCH=msp:43 -ROM_START=0x8000 -ROM_SIZE=0x7fe0 -RAM_START=0x0200 -RAM_SIZE=1024 -STACK=0x600 -fi - -if [ "${MSP430_NAME}" = "msp430x447" ] ; then -ARCH=msp:44 -ROM_START=0x8000 -ROM_SIZE=0x7fe0 -RAM_START=0x0200 -RAM_SIZE=1024 -STACK=0x600 -fi - -if [ "${MSP430_NAME}" = "msp430x448" ] ; then -ARCH=msp:44 -ROM_START=0x4000 -ROM_SIZE=0xbfe0 -RAM_START=0x0200 -RAM_SIZE=0x0800 -STACK=0xa00 -fi - -if [ "${MSP430_NAME}" = "msp430x449" ] ; then -ARCH=msp:44 -ROM_START=0x1100 -ROM_SIZE=0xeee0 -RAM_START=0x0200 -RAM_SIZE=0x0800 -STACK=0xa00 -fi - -if [ "${MSP430_NAME}" = "msp430xE423" ] ; then -ARCH=msp:42 -ROM_START=0xe000 -ROM_SIZE=0x1fe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430xE425" ] ; then -ARCH=msp:42 -ROM_START=0xc000 -ROM_SIZE=0x3fe0 -RAM_START=0x0200 -RAM_SIZE=512 -STACK=0x400 -fi - -if [ "${MSP430_NAME}" = "msp430xE427" ] ; then -ARCH=msp:42 -ROM_START=0x8000 -ROM_SIZE=0x7fe0 -RAM_START=0x0200 -RAM_SIZE=1024 -STACK=0x600 -fi - -if [ "${MSP430_NAME}" = "msp430xG437" ] ; then -ARCH=msp:43 -ROM_START=0x8000 -ROM_SIZE=0x7fe0 -RAM_START=0x0200 -RAM_SIZE=1024 -STACK=0x600 -fi - -if [ "${MSP430_NAME}" = "msp430xG438" ] ; then -ARCH=msp:43 -ROM_START=0x4000 -ROM_SIZE=0xbef0 -RAM_START=0x0200 -RAM_SIZE=0x0800 -STACK=0xa00 -fi - -if [ "${MSP430_NAME}" = "msp430xG439" ] ; then -ARCH=msp:43 -ROM_START=0x1100 -ROM_SIZE=0xeee0 -RAM_START=0x0200 -RAM_SIZE=0x0800 -STACK=0xa00 -fi - -if [ "${MSP430_NAME}" = "msp430xW423" ] ; then -ARCH=msp:42 -ROM_START=0xe000 -ROM_SIZE=0x1fe0 -RAM_START=0x0200 -RAM_SIZE=256 -STACK=0x300 -fi - -if [ "${MSP430_NAME}" = "msp430xW425" ] ; then -ARCH=msp:42 -ROM_START=0xc000 -ROM_SIZE=0x3fe0 -RAM_START=0x0200 -RAM_SIZE=512 -STACK=0x400 -fi - -if [ "${MSP430_NAME}" = "msp430xW427" ] ; then -ARCH=msp:42 -ROM_START=0x8000 -ROM_SIZE=0x7fe0 -RAM_START=0x0200 -RAM_SIZE=0x400 -STACK=0x600 -fi diff --git binutils-2.22.orig/ld/emulparams/msp430uni.sh binutils-2.22/ld/emulparams/msp430uni.sh new file mode 100644 index 0000000..949fe85 --- /dev/null +++ binutils-2.22/ld/emulparams/msp430uni.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +# This called by genscripts_extra.sh + +MSP430_NAME=${EMULATION_NAME} +ARCH=msp430 +SCRIPT_NAME=elf32msp430 +TEMPLATE_NAME=generic +EXTRA_EM_FILE=msp430 +OUTPUT_FORMAT="elf32-msp430" +MACHINE= +MAXPAGESIZE=1 +EMBEDDED=yes + diff --git binutils-2.22.orig/ld/emultempl/msp430.em binutils-2.22/ld/emultempl/msp430.em new file mode 100644 index 0000000..04af89d --- /dev/null +++ binutils-2.22/ld/emultempl/msp430.em @@ -0,0 +1,218 @@ +# This shell script emits a C file. -*- C -*- +# Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# +# This file is part of the GNU Binutils. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, +# MA 02110-1301, USA. +# + +# Adapt genelf.em for MSP430 +# This file is sourced from generic.em +# +fragment <link_next) + if ((syms = bfd_get_outsymbols (ibfd)) != NULL + && bfd_get_flavour (ibfd) == bfd_target_elf_flavour) + for (sec = ibfd->sections; sec != NULL; sec = sec->next) + if ((sec->flags & (SEC_GROUP | SEC_LINKER_CREATED)) == SEC_GROUP) + { + struct bfd_elf_section_data *sec_data = elf_section_data (sec); + elf_group_id (sec) = syms[sec_data->this_hdr.sh_info - 1]; + } +} + +/* Locate the named output sections associated with each orphan save + * structure. */ +static void +gld${EMULATION_NAME}_init_orphan_save (struct orphan_save *hold, + size_t nhold) +{ + struct orphan_save *ho; + for (ho = hold; ho < hold + nhold; ++ho) + { + ho->os = lang_output_section_find (ho->name); + ASSERT(NULL != ho->os); + if (ho->os != NULL && ho->os->flags == 0) + ho->os->flags = ho->flags; + } +} + +/* Check whether section S fits in output section OS. If so, accrue + * its size to the corresponding region and return TRUE; otherwise + * return FALSE. */ +static bfd_boolean +gld${EMULATION_NAME}_section_fits (asection *s, + lang_output_section_statement_type *os) +{ + bfd_vma newdot = os->region->current; + int section_alignment = os->section_alignment; + + if (section_alignment > 0) + newdot = align_power (newdot, section_alignment); + /* TO_ADDR not accessible, assume octets-per-byte == 1; */ + newdot += s->size; + if (newdot - os->region->origin <= os->region->length) + { + os->region->current = newdot; + return TRUE; + } + return FALSE; +} + +static lang_output_section_statement_type * +gld${EMULATION_NAME}_place_orphan (asection *s, + const char *secname, + int constraint) +{ + static struct orphan_save near_orphan_save[] = + { + { ".text", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE, + 0, 0, 0, 0 }, + { ".rodata", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, + 0, 0, 0, 0 }, + { ".data", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA, + 0, 0, 0, 0 }, + { ".bss", + SEC_ALLOC, + 0, 0, 0, 0 }, + }; + static struct orphan_save *end_near_orphan_save = near_orphan_save + sizeof(near_orphan_save)/sizeof(*near_orphan_save); + static struct orphan_save far_orphan_save[] = + { + { ".far.text", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_CODE, + 0, 0, 0, 0 }, + { ".far.rodata", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_DATA, + 0, 0, 0, 0 }, + { ".far.data", + SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD | SEC_DATA, + 0, 0, 0, 0 }, + { ".far.bss", + SEC_ALLOC, + 0, 0, 0, 0 }, + }; + const char *trimmed_secname; + static int orphan_init_done = 0; + struct orphan_save *osp; + + if (! orphan_init_done) + { + orphan_init_done = 1; + lang_reset_memory_regions (); + lang_size_sections (NULL, TRUE); + gld${EMULATION_NAME}_init_orphan_save (near_orphan_save, sizeof(near_orphan_save)/sizeof(*near_orphan_save)); + gld${EMULATION_NAME}_init_orphan_save (far_orphan_save, sizeof(far_orphan_save)/sizeof(*far_orphan_save)); + } + + ASSERT(0 == constraint); + if (strncmp(".any.", secname, 5)) + return NULL; + trimmed_secname = secname + 4; + osp = near_orphan_save; + while (osp < end_near_orphan_save) + { + size_t len = strlen(osp->name); + if (0 == strcmp(trimmed_secname, osp->name) + || (0 == strncmp(trimmed_secname, osp->name, len) && '.' == trimmed_secname[len])) + break; + ++osp; + } + if (osp == end_near_orphan_save) + return NULL; + if (!gld${EMULATION_NAME}_section_fits (s, osp->os)) + osp = far_orphan_save + (osp - near_orphan_save); + ASSERT ((s->flags & osp->flags) == osp->flags); + if (!link_info.relocatable) + secname = osp->name; + return lang_insert_orphan (s, secname, constraint, osp->os, osp, NULL, NULL); +} + +static void +gld${EMULATION_NAME}_before_allocation (void) +{ + if (link_info.relocatable + && !_bfd_elf_size_group_sections (&link_info)) + einfo ("%X%P: can not size group sections: %E\n"); + before_allocation_default (); +} + +static void +gld${EMULATION_NAME}_after_allocation (void) +{ + gld${EMULATION_NAME}_map_segments (FALSE); +} + +static void +gld${EMULATION_NAME}_finish (void) +{ + bfd *obfd = link_info.output_bfd; + Elf_Internal_Ehdr *o_ehdrp = elf_elfheader (obfd); + unsigned long flags = 0; + bfd *ibfd; + + for (ibfd = link_info.input_bfds; ibfd != NULL; ibfd = ibfd->link_next) { + Elf_Internal_Ehdr * i_ehdrp = elf_elfheader (ibfd); + + if (EF_MSP430_UNIARCH & i_ehdrp->e_flags) + flags |= i_ehdrp->e_flags; + } + if (EF_MSP430_UNIARCH & flags) { + int bfd_mach; + switch (flags & EF_MSP430_ARCH) + { + default: + case EF_MSP430_ARCH_430: + bfd_mach = bfd_mach_msp430; + break; + case EF_MSP430_ARCH_430X: + bfd_mach = bfd_mach_msp430x; + break; + } + bfd_default_set_arch_mach (obfd, bfd_arch_msp430, bfd_mach); + o_ehdrp->e_flags = flags; + } + finish_default(); +} +EOF +# Put these extra routines in ld_${EMULATION_NAME}_emulation +# +LDEMUL_AFTER_OPEN=gld${EMULATION_NAME}_after_open +LDEMUL_PLACE_ORPHAN=gld${EMULATION_NAME}_place_orphan +LDEMUL_BEFORE_ALLOCATION=gld${EMULATION_NAME}_before_allocation +LDEMUL_AFTER_ALLOCATION=gld${EMULATION_NAME}_after_allocation +LDEMUL_FINISH=gld${EMULATION_NAME}_finish diff --git binutils-2.22.orig/ld/scripttempl/elf32msp430.sc binutils-2.22/ld/scripttempl/elf32msp430.sc index cbffe48..c7bc137 100644 --- binutils-2.22.orig/ld/scripttempl/elf32msp430.sc +++ binutils-2.22/ld/scripttempl/elf32msp430.sc @@ -1,206 +1,255 @@ #!/bin/sh -HEAP_SECTION_MSP430=" " -HEAP_MEMORY_MSP430=" " - -if test ${GOT_HEAP_MSP-0} -ne 0 -then -HEAP_SECTION_MSP430=".heap ${RELOCATING-0} : - { - ${RELOCATING+ PROVIDE (__heap_data_start = .) ; } - *(.heap*) - ${RELOCATING+ PROVIDE (_heap_data_end = .) ; } - ${RELOCATING+. = ALIGN(2);} - ${RELOCATING+ PROVIDE (__heap_bottom = .) ; } - ${RELOCATING+ PROVIDE (__heap_top = ${HEAP_START} + ${HEAP_LENGTH}) ; } - } ${RELOCATING+ > heap}" -HEAP_MEMORY_MSP430="heap(rwx) : ORIGIN = $HEAP_START, LENGTH = $HEAP_LENGTH" -fi - - cat < text} - - .data ${RELOCATING-0} : ${RELOCATING+AT (ADDR (.text) + SIZEOF (.text))} + ${RELOCATING+ . = ALIGN(2);} + ${RELOCATING+ KEEP(*(.init .init.*)) } + ${RELOCATING+ KEEP(*(.init0)) /* Start here after reset. */ } + ${RELOCATING+ KEEP(*(.init1)) /* User definable. */ } + ${RELOCATING+ KEEP(*(.init2)) /* Initialize stack. */ } + ${RELOCATING+ KEEP(*(.init3)) /* Initialize hardware, user definable. */ } + ${RELOCATING+ KEEP(*(.init4)) /* Copy data to .data, clear bss. */ } + ${RELOCATING+ KEEP(*(.init5)) /* User definable. */ } + ${RELOCATING+ KEEP(*(.init6)) /* C++ constructors. */ } + ${RELOCATING+ KEEP(*(.init7)) /* User definable. */ } + ${RELOCATING+ KEEP(*(.init8)) /* User definable. */ } + ${RELOCATING+ KEEP(*(.init9)) /* Call main(). */ } + ${RELOCATING+ KEEP(*(.fini9)) /* Falls into here after main(). User definable. */ } + ${RELOCATING+ KEEP(*(.fini8)) /* User definable. */ } + ${RELOCATING+ KEEP(*(.fini7)) /* User definable. */ } + ${RELOCATING+ KEEP(*(.fini6)) /* C++ destructors. */ } + ${RELOCATING+ KEEP(*(.fini5)) /* User definable. */ } + ${RELOCATING+ KEEP(*(.fini4)) /* User definable. */ } + ${RELOCATING+ KEEP(*(.fini3)) /* User definable. */ } + ${RELOCATING+ KEEP(*(.fini2)) /* User definable. */ } + ${RELOCATING+ KEEP(*(.fini1)) /* User definable. */ } + ${RELOCATING+ KEEP(*(.fini0)) /* Infinite loop after program termination. */ } + ${RELOCATING+ KEEP(*(.fini .fini.*))} + + ${CONSTRUCTING+ . = ALIGN(2); } + ${CONSTRUCTING+ __ctors_start = .; } + ${CONSTRUCTING+ KEEP(*(.ctors)) } + ${CONSTRUCTING+ __ctors_end = .; } + ${CONSTRUCTING+ __dtors_start = .; } + ${CONSTRUCTING+ KEEP(*(.dtors)) } + ${CONSTRUCTING+ __dtors_end = .; } + + ${RELOCATING+ . = ALIGN(2);} + *(.text${RELOCATING+ .text.* .gnu.linkonce.t.*}) + *(.near.text${RELOCATING+ .near.text.*}) + } ${RELOCATING+ > REGION_TEXT} + + .rodata ${RELOCATING-0} : + { + ${RELOCATING+ . = ALIGN(2);} + *(.rodata${RELOCATING+ .rodata.* .gnu.linkonce.r.*}) + *(.near.rodata${RELOCATING+ .near.rodata.*}) + } ${RELOCATING+ > REGION_TEXT} + ${RELOCATING+ . = ALIGN(2);} + ${RELOCATING+ _etext = .;} /* Past last read-only (loadable) segment */ + + .data ${RELOCATING-0} : { - ${RELOCATING+ PROVIDE (__data_start = .) ; } - ${RELOCATING+. = ALIGN(2);} - *(.data) - ${RELOCATING+. = ALIGN(2);} - *(.gnu.linkonce.d*) - ${RELOCATING+. = ALIGN(2);} - ${RELOCATING+ _edata = . ; } - } ${RELOCATING+ > data} + ${RELOCATING+ . = ALIGN(2);} + ${RELOCATING+ __data_start = .; } + *(.data${RELOCATING+ .data.* .gnu.linkonce.d.*}) + *(.near.data${RELOCATING+ .near.data.*}) + ${RELOCATING+ . = ALIGN(2);} + ${RELOCATING+ _edata = .; } /* Past last read-write (loadable) segment */ + } ${RELOCATING+ > REGION_DATA AT > REGION_TEXT} + ${RELOCATING+ __data_load_start = LOADADDR(.data); } + ${RELOCATING+ __data_size = SIZEOF(.data); } - /* Bootloader. */ - .bootloader ${RELOCATING-0} : + .bss ${RELOCATING-0} : { - ${RELOCATING+ PROVIDE (__boot_start = .) ; } - *(.bootloader) - ${RELOCATING+. = ALIGN(2);} - *(.bootloader.*) - } ${RELOCATING+ > bootloader} - - /* Information memory. */ + ${RELOCATING+ __bss_start = .; } + *(.bss${RELOCATING+ .bss.*}) + *(.near.bss${RELOCATING+ .near.bss.*}) + *(COMMON) + ${RELOCATING+ . = ALIGN(2);} + ${RELOCATING+ __bss_end = .; } + } ${RELOCATING+ > REGION_DATA} + ${RELOCATING+ __bss_size = SIZEOF(.bss); } + + .noinit ${RELOCATING-0} : + { + ${RELOCATING+ . = ALIGN(2);} + ${RELOCATING+ __noinit_start = .; } + *(.noinit${RELOCATING+ .noinit.*}) + ${RELOCATING+ . = ALIGN(2);} + ${RELOCATING+ __noinit_end = .; } + } ${RELOCATING+ > REGION_DATA} + ${RELOCATING+ . = ALIGN(2);} + ${RELOCATING+ _end = .; } /* Past last write (loadable) segment */ + .infomem ${RELOCATING-0} : { - *(.infomem) - ${RELOCATING+. = ALIGN(2);} - *(.infomem.*) + ${RELOCATING+ . = ALIGN(2);} + *(.infomem${RELOCATING+ .infomem.*}) } ${RELOCATING+ > infomem} - /* Information memory (not loaded into MPU). */ .infomemnobits ${RELOCATING-0} : { - *(.infomemnobits) - ${RELOCATING+. = ALIGN(2);} - *(.infomemnobits.*) - } ${RELOCATING+ > infomemnobits} + ${RELOCATING+ . = ALIGN(2);} + *(.infomemnobits${RELOCATING+ .infomemnobits.*}) + } ${RELOCATING+ > infomem} - .bss ${RELOCATING+ SIZEOF(.data) + ADDR(.data)} : + .infoa ${RELOCATING-0} : { - ${RELOCATING+ PROVIDE (__bss_start = .) ; } - *(.bss) - *(COMMON) - ${RELOCATING+ PROVIDE (__bss_end = .) ; } - ${RELOCATING+ _end = . ; } - } ${RELOCATING+ > data} + ${RELOCATING+ . = ALIGN(2);} + *(.infoa${RELOCATING+ .infoa.*}) + } ${RELOCATING+ > infoa} - .noinit ${RELOCATING+ SIZEOF(.bss) + ADDR(.bss)} : + .infob ${RELOCATING-0} : { - ${RELOCATING+ PROVIDE (__noinit_start = .) ; } - *(.noinit) - *(COMMON) - ${RELOCATING+ PROVIDE (__noinit_end = .) ; } - ${RELOCATING+ _end = . ; } - } ${RELOCATING+ > data} + ${RELOCATING+ . = ALIGN(2);} + *(.infob${RELOCATING+ .infob.*}) + } ${RELOCATING+ > infob} - .vectors ${RELOCATING-0}: + .infoc ${RELOCATING-0} : { - ${RELOCATING+ PROVIDE (__vectors_start = .) ; } - *(.vectors*) - ${RELOCATING+ _vectors_end = . ; } + ${RELOCATING+ . = ALIGN(2);} + *(.infoc${RELOCATING+ .infoc.*}) + } ${RELOCATING+ > infoc} + + .infod ${RELOCATING-0} : + { + ${RELOCATING+ . = ALIGN(2);} + *(.infod${RELOCATING+ .infod.*}) + } ${RELOCATING+ > infod} + + /* Values placed in the first 32 entries of a 64-entry interrupt vector + * table. This exists because the FRAM chips place the BSL and JTAG + * passwords at specific offsets that technically fall within the + * interrupt table, but for which no MCU has a corresponding interrupt. + * See https://sourceforge.net/tracker/?func=detail&aid=3554291&group_id=42303&atid=432701 */ + PROVIDE(__vte_0 = 0xffff); + PROVIDE(__vte_1 = 0xffff); + PROVIDE(__vte_2 = 0xffff); + PROVIDE(__vte_3 = 0xffff); + PROVIDE(__vte_4 = 0xffff); + PROVIDE(__vte_5 = 0xffff); + PROVIDE(__vte_6 = 0xffff); + PROVIDE(__vte_7 = 0xffff); + PROVIDE(__vte_8 = 0xffff); + PROVIDE(__vte_9 = 0xffff); + PROVIDE(__vte_10 = 0xffff); + PROVIDE(__vte_11 = 0xffff); + PROVIDE(__vte_12 = 0xffff); + PROVIDE(__vte_13 = 0xffff); + PROVIDE(__vte_14 = 0xffff); + PROVIDE(__vte_15 = 0xffff); + PROVIDE(__vte_16 = 0xffff); + PROVIDE(__vte_17 = 0xffff); + PROVIDE(__vte_18 = 0xffff); + PROVIDE(__vte_19 = 0xffff); + PROVIDE(__vte_20 = 0xffff); + PROVIDE(__vte_21 = 0xffff); + PROVIDE(__vte_22 = 0xffff); + PROVIDE(__vte_23 = 0xffff); + PROVIDE(__vte_24 = 0xffff); + PROVIDE(__vte_25 = 0xffff); + PROVIDE(__vte_26 = 0xffff); + PROVIDE(__vte_27 = 0xffff); + PROVIDE(__vte_28 = 0xffff); + PROVIDE(__vte_29 = 0xffff); + PROVIDE(__vte_30 = 0xffff); + PROVIDE(__vte_31 = 0xffff); + .vectors ${RELOCATING-0} : + { + ${RELOCATING+ __vectors_start = .; } + KEEP(*(.vectors*)) + ${RELOCATING+ _vectors_end = .; } } ${RELOCATING+ > vectors} - ${HEAP_SECTION_MSP430} + /* Legacy section, prefer .far.text */ + .fartext ${RELOCATING-0} : + { + ${RELOCATING+ . = ALIGN(2);} + *(.fartext${RELOCATING+ .fartext.*}) + } ${RELOCATING+ > REGION_FAR_TEXT} + + .far.text ${RELOCATING-0} : + { + ${RELOCATING+ . = ALIGN(2);} + *(.far.text${RELOCATING+ .far.text.*}) + } ${RELOCATING+ > REGION_FAR_TEXT} + + .far.rodata ${RELOCATING-0} : + { + ${RELOCATING+ . = ALIGN(2);} + *(.far.rodata${RELOCATING+ .far.rodata.*}) + } ${RELOCATING+ > REGION_FAR_TEXT} + ${RELOCATING+ . = ALIGN(2);} + ${RELOCATING+ _efartext = .;} /* Past last read-only (loadable) segment */ + + .far.data ${RELOCATING-0} : + { + ${RELOCATING+ . = ALIGN(2);} + ${RELOCATING+ __far_data_start = .; } + *(.far.data${RELOCATING+ .far.data.*}) + ${RELOCATING+ . = ALIGN(2);} + ${RELOCATING+ _efardata = .; } /* Past last read-write (loadable) segment */ + } ${RELOCATING+ > REGION_FAR_DATA AT > REGION_FAR_TEXT} + ${RELOCATING+ __far_data_load_start = LOADADDR(.far.data); } + ${RELOCATING+ __far_data_size = SIZEOF(.far.data); } + + .far.bss ${RELOCATING-0} : + { + ${RELOCATING+ . = ALIGN(2);} + ${RELOCATING+ __far_bss_start = .; } + *(.far.bss${RELOCATING+ .far.bss.*}) + ${RELOCATING+ . = ALIGN(2);} + ${RELOCATING+ __far_bss_end = .; } + } ${RELOCATING+ > REGION_FAR_DATA} + ${RELOCATING+ __far_bss_size = SIZEOF(.far.bss); } + ${RELOCATING+ . = ALIGN(2);} + ${RELOCATING+ _far_end = .; } /* Past last write (loadable) segment */ /* Stabs for profiling information*/ .profiler 0 : { *(.profiler) } @@ -239,11 +288,13 @@ SECTIONS .debug_loc 0 : { *(.debug_loc) } .debug_macinfo 0 : { *(.debug_macinfo) } - PROVIDE (__stack = ${STACK}) ; - PROVIDE (__data_start_rom = _etext) ; - PROVIDE (__data_end_rom = _etext + SIZEOF (.data)) ; - PROVIDE (__noinit_start_rom = _etext + SIZEOF (.data)) ; - PROVIDE (__noinit_end_rom = _etext + SIZEOF (.data) + SIZEOF (.noinit)) ; - PROVIDE (__subdevice_has_heap = ${GOT_HEAP_MSP-0}) ; + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + + /* __stack is the only symbol that the user can override */ + ${RELOCATING+ PROVIDE (__stack = ORIGIN(ram) + LENGTH(ram));} + ${RELOCATING+ __data_start_rom = _etext;} + ${RELOCATING+ __data_end_rom = _etext + SIZEOF (.data);} } EOF diff --git binutils-2.22.orig/ld/scripttempl/elf32msp430_3.sc binutils-2.22/ld/scripttempl/elf32msp430_3.sc deleted file mode 100644 index 15eb517..0000000 --- binutils-2.22.orig/ld/scripttempl/elf32msp430_3.sc +++ /dev/null @@ -1,192 +0,0 @@ -cat < text} - - .data ${RELOCATING-0} : ${RELOCATING+AT (ADDR (.text) + SIZEOF (.text))} - { - ${RELOCATING+ PROVIDE (__data_start = .) ; } - *(.data) - *(.gnu.linkonce.d*) - ${RELOCATING+. = ALIGN(2);} - ${RELOCATING+ _edata = . ; } - } ${RELOCATING+ > data} - - .bss ${RELOCATING+ SIZEOF(.data) + ADDR(.data)} : - { - ${RELOCATING+ PROVIDE (__bss_start = .) ; } - *(.bss) - *(COMMON) - ${RELOCATING+ PROVIDE (__bss_end = .) ; } - ${RELOCATING+ _end = . ; } - } ${RELOCATING+ > data} - - .noinit ${RELOCATING+ SIZEOF(.bss) + ADDR(.bss)} : - { - ${RELOCATING+ PROVIDE (__noinit_start = .) ; } - *(.noinit) - *(COMMON) - ${RELOCATING+ PROVIDE (__noinit_end = .) ; } - ${RELOCATING+ _end = . ; } - } ${RELOCATING+ > data} - - .vectors ${RELOCATING-0}: - { - ${RELOCATING+ PROVIDE (__vectors_start = .) ; } - *(.vectors*) - ${RELOCATING+ _vectors_end = . ; } - } ${RELOCATING+ > vectors} - - /* Stabs debugging sections. */ - .stab 0 : { *(.stab) } - .stabstr 0 : { *(.stabstr) } - .stab.excl 0 : { *(.stab.excl) } - .stab.exclstr 0 : { *(.stab.exclstr) } - .stab.index 0 : { *(.stab.index) } - .stab.indexstr 0 : { *(.stab.indexstr) } - .comment 0 : { *(.comment) } - - /* DWARF debug sections. - Symbols in the DWARF debugging sections are relative to the beginning - of the section so we begin them at 0. */ - - /* DWARF 1 */ - .debug 0 : { *(.debug) } - .line 0 : { *(.line) } - - /* GNU DWARF 1 extensions */ - .debug_srcinfo 0 : { *(.debug_srcinfo) } - .debug_sfnames 0 : { *(.debug_sfnames) } - - /* DWARF 1.1 and DWARF 2 */ - .debug_aranges 0 : { *(.debug_aranges) } - .debug_pubnames 0 : { *(.debug_pubnames) } - - /* DWARF 2 */ - .debug_info 0 : { *(.debug_info) *(.gnu.linkonce.wi.*) } - .debug_abbrev 0 : { *(.debug_abbrev) } - .debug_line 0 : { *(.debug_line) } - .debug_frame 0 : { *(.debug_frame) } - .debug_str 0 : { *(.debug_str) } - .debug_loc 0 : { *(.debug_loc) } - .debug_macinfo 0 : { *(.debug_macinfo) } - - PROVIDE (__stack = ${STACK}) ; - PROVIDE (__data_start_rom = _etext) ; - PROVIDE (__data_end_rom = _etext + SIZEOF (.data)) ; - PROVIDE (__noinit_start_rom = _etext + SIZEOF (.data)) ; - PROVIDE (__noinit_end_rom = _etext + SIZEOF (.data) + SIZEOF (.noinit)) ; -} -EOF diff --git binutils-2.22.orig/opcodes/msp430-dis.c binutils-2.22/opcodes/msp430-dis.c index 9d7edbe..b789320 100644 --- binutils-2.22.orig/opcodes/msp430-dis.c +++ binutils-2.22/opcodes/msp430-dis.c @@ -34,11 +34,8 @@ #include "opcode/msp430.h" #undef DASM_SECTION - -#define PS(x) (0xffff & (x)) - static unsigned short -msp430dis_opcode (bfd_vma addr, disassemble_info *info) +msp430dis_opcode (bfd_vma addr, disassemble_info * info) { bfd_byte buffer[2]; int status; @@ -52,12 +49,174 @@ msp430dis_opcode (bfd_vma addr, disassemble_info *info) return bfd_getl16 (buffer); } +static unsigned short +msp430dis_operand (bfd_vma addr, disassemble_info * info, int reg, int am, + int *cmd_len) +{ + static int const op_length[][5] = { + /* PC SP r2 r3 rN AM */ + {0, 0, 0, 0, 0}, /* 0 = AM_Register: Rn */ + {2, 2, 2, 0, 2}, /* 1 = AM_Indexed: x(Rn) */ + {0, 0, 0, 0, 0}, /* 2 = AMs_IndirectRegister: @Rn */ + {2, 0, 0, 0, 0}, /* 3 = AMs_IndirectAutoIncrement: @Rn+ */ + }; + if (reg >= (int) (sizeof (op_length[0]) / sizeof (op_length[0][0]))) + reg = sizeof (op_length[0]) / sizeof (op_length[0][0]) - 1; + + if (op_length[am][reg]) + { + bfd_byte buffer[2]; + int status = info->read_memory_func (addr, buffer, 2, info); + if (status != 0) + { + info->memory_error_func (status, addr, info); + return -1; + } + *cmd_len += 2; + return bfd_getl16 (buffer); + } + return 0; +} + +typedef enum +{ + OP_OTHER = 0, + OP_DECIMAL = 0x03, + OP_16BIT = 0x04, + OP_20BIT = 0x05, + OP_MASK_BITS = 0x07, + OP_IS_HEX = 0x08, + OP_16BIT_HEX = OP_16BIT | OP_IS_HEX, + OP_20BIT_HEX = OP_20BIT | OP_IS_HEX, + OP_IS_430X_INSN = 0x10, +} operand_t; + +static void +msp430_decode_operand (int reg, int am, int op_addr, int dst, operand_t size, + char *op, char *comm) +{ + int is_hex = size & OP_IS_HEX; + int is_430x = size & OP_IS_430X_INSN; + size = size & OP_MASK_BITS; + + if (NULL == op) + return; + switch (am) + { + case AM_Register: + if (reg == REGNO_CG2) /* #0 */ + { + sprintf (op, "#0"); + sprintf (comm, "r3 As==00"); + } + else + sprintf (op, "r%d", reg); + break; + case AM_Indexed: + if (reg == REGNO_PC) /* Symbolic: ADDR */ + { + int mem_addr; + + mem_addr = op_addr + dst; + if (!is_430x && size == OP_16BIT) + { + if (MASK_16 (op_addr) == op_addr) + mem_addr = MASK_16 (mem_addr); + sprintf (comm, "PC rel. 0x%04x", MASK_16 (mem_addr)); + } + else + sprintf (comm, "PC rel. 0x%05x", MASK_20 (mem_addr)); + sprintf (op, "%d(r0)", dst); + } + else if (reg == REGNO_CG1) /* Absolute: &ADDR */ + { + if (size == OP_20BIT) + sprintf (op, "&0x%05x", MASK_20 (dst)); + else + sprintf (op, "&0x%04x", MASK_16 (dst)); + } + else if (reg == REGNO_CG2) /* #1 */ + { + sprintf (op, "#1"); + sprintf (comm, "r3 As==01"); + } + else /* Indexed: x(Rn) */ + { + sprintf (op, "%d(r%d)", dst, reg); + if (size == OP_20BIT) + sprintf (comm, "0x%05x(r%d)", MASK_20 (dst), reg); + else + sprintf (comm, "0x%04x(r%d)", MASK_16 (dst), reg); + } + break; + case AMs_IndirectRegister: + if (reg == REGNO_CG1) /* #4 */ + { + sprintf (op, "#4"); + sprintf (comm, "r2 As==10"); + } + else if (reg == REGNO_CG2) /* #2 */ + { + sprintf (op, "#2"); + sprintf (comm, "r3 As==10"); + } + else /* @Rn */ + sprintf (op, "@r%d", reg); + break; + case AMs_IndirectAutoIncrement: + switch (reg) + { + case REGNO_PC: /* #N */ + if (OP_16BIT == size) + { + if (is_hex) + sprintf (op, "#0x%04x", MASK_16 (dst)); + else + { + sprintf (op, "#%d", dst); + sprintf (comm, "#0x%04x", MASK_16 (dst)); + } + } + else if (OP_20BIT == size) + { + if (is_hex) + sprintf (op, "#0x%05x", MASK_20 (dst)); + else + { + sprintf (op, "#%d", dst); + sprintf (comm, "#0x%05x", MASK_20 (dst)); + } + } + else + sprintf (op, "#%d", dst); + break; + case REGNO_CG1: /* #8 */ + sprintf (op, "#8"); + sprintf (comm, "r2 As==11"); + break; + case REGNO_CG2: /* #-1 */ + sprintf (op, "#-1"); + sprintf (comm, "r3 As==11"); + break; + default: /* @Rn+ */ + sprintf (op, "@r%d+", reg); + break; + } + break; + } +} + +static void +msp430x_decode_operand (int reg, int am, int op_addr, int dst, operand_t size, + char *op, char *comm) +{ + msp430_decode_operand (reg, am, op_addr, dst, OP_IS_430X_INSN | size, op, comm); +} + static int -msp430_nooperands (struct msp430_opcode_s *opcode, +msp430_nooperands (struct msp430_opcode_s const *opcode, bfd_vma addr ATTRIBUTE_UNUSED, - unsigned short insn ATTRIBUTE_UNUSED, - char *comm, - int *cycles) + unsigned short insn ATTRIBUTE_UNUSED, char *comm) { /* Pop with constant. */ if (insn == 0x43b2) @@ -65,35 +224,27 @@ msp430_nooperands (struct msp430_opcode_s *opcode, if (insn == opcode->bin_opcode) return 2; - if (opcode->fmt == 0) + if (opcode_format (opcode) == FMT_EMULATED) { if ((insn & 0x0f00) != 3 || (insn & 0x0f00) != 2) return 0; strcpy (comm, "emulated..."); - *cycles = 1; } else - { - strcpy (comm, "return from interupt"); - *cycles = 5; - } + strcpy (comm, "return from interupt"); return 2; } static int -msp430_singleoperand (disassemble_info *info, - struct msp430_opcode_s *opcode, - bfd_vma addr, - unsigned short insn, - char *op, - char *comm, - int *cycles) +msp430_singleoperand (disassemble_info * info, + struct msp430_opcode_s const *opcode, + bfd_vma addr, unsigned short insn, char *op, char *comm) { int regs = 0, regd = 0; int ad = 0, as = 0; - int where = 0; + bfd_vma op_addr; int cmd_len = 2; short dst = 0; @@ -102,10 +253,11 @@ msp430_singleoperand (disassemble_info *info, as = (insn & 0x0030) >> 4; ad = (insn & 0x0080) >> 7; - switch (opcode->fmt) + op_addr = addr + cmd_len; + switch (opcode_format (opcode)) { - case 0: /* Emulated work with dst register. */ - if (regs != 2 && regs != 3 && regs != 1) + case FMT_EMULATED: /* Emulated work with dst register. */ + if (regs != REGNO_CG1 && regs != REGNO_CG2 && regs != REGNO_SP) return 0; /* Check if not clr insn. */ @@ -113,170 +265,33 @@ msp430_singleoperand (disassemble_info *info, return 0; /* Check if really inc, incd insns. */ - if ((opcode->bin_opcode & 0xff00) == 0x5300 && as == 3) + if ((opcode->bin_opcode & 0xff00) == 0x5300 + && as == AMs_IndirectAutoIncrement) return 0; - if (ad == 0) - { - *cycles = 1; - - /* Register. */ - if (regd == 0) - { - *cycles += 1; - sprintf (op, "r0"); - } - else if (regd == 1) - sprintf (op, "r1"); - - else if (regd == 2) - sprintf (op, "r2"); - - else - sprintf (op, "r%d", regd); - } - else /* ad == 1 msp430dis_opcode. */ - { - if (regd == 0) - { - /* PC relative. */ - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 2; - *cycles = 4; - sprintf (op, "0x%04x", dst); - sprintf (comm, "PC rel. abs addr 0x%04x", - PS ((short) (addr + 2) + dst)); - } - else if (regd == 2) - { - /* Absolute. */ - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 2; - *cycles = 4; - sprintf (op, "&0x%04x", PS (dst)); - } - else - { - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 2; - *cycles = 4; - sprintf (op, "%d(r%d)", dst, regd); - } - } + dst = msp430dis_operand (op_addr, info, regd, ad, &cmd_len); + msp430_decode_operand (regd, ad, op_addr, dst, OP_16BIT, op, comm); break; - case 2: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */ - if (as == 0) - { - if (regd == 3) - { - /* Constsnts. */ - sprintf (op, "#0"); - sprintf (comm, "r3 As==00"); - } - else - { - /* Register. */ - sprintf (op, "r%d", regd); - } - *cycles = 1; - } - else if (as == 2) - { - *cycles = 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); - } - } - 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) - { - *cycles = 3; - /* absolute. @pc+ */ - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 2; - sprintf (op, "#%d", dst); - sprintf (comm, "#0x%04x", PS (dst)); - } - else - { - *cycles = 3; - sprintf (op, "@r%d+", regd); - } - } - else if (as == 1) - { - *cycles = 4; - if (regd == 0) - { - /* PC relative. */ - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 2; - sprintf (op, "0x%04x", PS (dst)); - sprintf (comm, "PC rel. 0x%04x", - PS ((short) addr + 2 + dst)); - } - else if (regd == 2) - { - /* Absolute. */ - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 2; - sprintf (op, "&0x%04x", PS (dst)); - } - else if (regd == 3) - { - *cycles = 1; - sprintf (op, "#1"); - sprintf (comm, "r3 As==01"); - } - else - { - /* Indexd. */ - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 2; - sprintf (op, "%d(r%d)", dst, regd); - } - } + case FMT_SINGLE_OPERAND: /* rrc, push, call, swpb, rra, sxt, push, call, reti etc... */ + dst = msp430dis_operand (op_addr, info, regd, as, &cmd_len); + if (opcode_variant (opcode) != V_CALL) + msp430_decode_operand (regd, as, op_addr, dst, OP_16BIT, op, comm); + else + msp430_decode_operand (regd, as, op_addr, dst, OP_16BIT_HEX, + op, comm); break; - case 3: /* Jumps. */ - where = insn & 0x03ff; - if (where & 0x200) - where |= ~0x03ff; - if (where > 512 || where < -511) - return 0; - - where *= 2; - sprintf (op, "$%+-8d", where + 2); - sprintf (comm, "abs 0x%x", PS ((short) (addr) + 2 + where)); - *cycles = 2; - return 2; + case FMT_JUMP: /* Jumps. */ + /* sign extension, word addr to byte addr conversion */ + dst = (short) ((insn & 0x03ff) << 6) >> 5; + sprintf (op, "$%+-8d", dst + cmd_len); + if (MASK_16 (op_addr) == op_addr) + sprintf (comm, "abs 0x%x", MASK_16 ((int)op_addr + dst)); + else + sprintf (comm, "abs 0x%x", MASK_20 ((int)op_addr + dst)); break; + default: cmd_len = 0; } @@ -285,468 +300,538 @@ msp430_singleoperand (disassemble_info *info, } static int -msp430_doubleoperand (disassemble_info *info, - struct msp430_opcode_s *opcode, +msp430_doubleoperand (disassemble_info * info, + struct msp430_opcode_s const *opcode, bfd_vma addr, unsigned short insn, - char *op1, - char *op2, - char *comm1, - char *comm2, - int *cycles) + char *op1, char *op2, char *comm1, char *comm2) { int regs = 0, regd = 0; int ad = 0, as = 0; int cmd_len = 2; - short dst = 0; + bfd_vma ops_addr; + bfd_vma opd_addr; + short ops; + short opd; regd = insn & 0x0f; regs = (insn & 0x0f00) >> 8; as = (insn & 0x0030) >> 4; ad = (insn & 0x0080) >> 7; - if (opcode->fmt == 0) + ops_addr = addr + cmd_len; + if (opcode_format (opcode) == FMT_EMULATED) { /* Special case: rla and rlc are the only 2 emulated instructions that - fall into two operand instructions. */ + fall into two operand instructions. */ /* With dst, there are only: - Rm Register, - x(Rm) Indexed, - 0xXXXX Relative, - &0xXXXX Absolute + Rm Register, + x(Rm) Indexed, + 0xXXXX Relative, + &0xXXXX Absolute emulated_ins dst basic_ins dst, dst. */ if (regd != regs || as != ad) return 0; /* May be 'data' section. */ - if (ad == 0) + if (ad == 0 && regd == 3) /* #N */ { - /* Register mode. */ - if (regd == 3) - { - strcpy (comm1, _("Illegal as emulation instr")); - return -1; - } - - sprintf (op1, "r%d", regd); - *cycles = 1; + strcpy (comm1, _("Illegal as emulation instr")); + return -1; } - else /* ad == 1 */ - { - if (regd == 0) - { - /* PC relative, Symbolic. */ - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 4; - *cycles = 6; - sprintf (op1, "0x%04x", PS (dst)); - sprintf (comm1, "PC rel. 0x%04x", - PS ((short) addr + 2 + dst)); + ops = msp430dis_operand (ops_addr, info, regs, as, &cmd_len); + opd_addr = addr + cmd_len; + opd = msp430dis_operand (opd_addr, info, regd, ad, &cmd_len); - } - else if (regd == 2) - { - /* Absolute. */ - dst = msp430dis_opcode (addr + 2, info); - /* If the 'src' field is not the same as the dst - then this is not an rla instruction. */ - if (dst != msp430dis_opcode (addr + 4, info)) - return 0; - cmd_len += 4; - *cycles = 6; - sprintf (op1, "&0x%04x", PS (dst)); - } - else - { - /* Indexed. */ - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 4; - *cycles = 6; - sprintf (op1, "%d(r%d)", dst, regd); - } - } + /* If the 'src' field is not the same as the dst + then this is not an rla instruction. + TODO: That assertion is false for symbolics. */ + if (ops != opd) + return 0; + msp430_decode_operand (regs, as, ops_addr, ops, OP_16BIT, op1, comm1); *op2 = 0; *comm2 = 0; return cmd_len; } - /* Two operands exactly. */ - if (ad == 0 && regd == 3) + + if (ad == AM_Register && regd == REGNO_CG2) { - /* R2/R3 are illegal as dest: may be data section. */ + /* R3 is illegal as dest: may be data section. */ strcpy (comm1, _("Illegal as 2-op instr")); return -1; } + ops = msp430dis_operand (ops_addr, info, regs, as, &cmd_len); + opd_addr = addr + cmd_len; + opd = msp430dis_operand (opd_addr, info, regd, ad, &cmd_len); - /* Source. */ - if (as == 0) - { - *cycles = 1; - if (regs == 3) - { - /* Constsnts. */ - sprintf (op1, "#0"); - sprintf (comm1, "r3 As==00"); - } - else - { - /* Register. */ - sprintf (op1, "r%d", regs); - } - } - else if (as == 2) - { - *cycles = 1; + msp430_decode_operand (regs, as, ops_addr, ops, OP_16BIT, op1, comm1); + msp430_decode_operand (regd, ad, opd_addr, opd, OP_16BIT, op2, comm2); - 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; + return cmd_len; +} - /* Indexed register mode @Rn. */ - sprintf (op1, "@r%d", regs); - } - if (!regs) - *cycles = 3; - } - 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) - { - *cycles = 3; - /* Absolute. @pc+. */ - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 2; - sprintf (op1, "#%d", dst); - sprintf (comm1, "#0x%04x", PS (dst)); - } - else - { - *cycles = 2; - sprintf (op1, "@r%d+", regs); - } - } - else if (as == 1) - { - if (regs == 0) - { - *cycles = 4; - /* PC relative. */ - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 2; - sprintf (op1, "0x%04x", PS (dst)); - sprintf (comm1, "PC rel. 0x%04x", - PS ((short) addr + 2 + dst)); - } - else if (regs == 2) - { - *cycles = 2; - /* Absolute. */ - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 2; - sprintf (op1, "&0x%04x", PS (dst)); - sprintf (comm1, "0x%04x", PS (dst)); - } - else if (regs == 3) - { - *cycles = 1; - sprintf (op1, "#1"); - sprintf (comm1, "r3 As==01"); - } - else - { - *cycles = 3; - /* Indexed. */ - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 2; - sprintf (op1, "%d(r%d)", dst, regs); - } - } +static int +msp430_branchinstr (disassemble_info * info, + struct msp430_opcode_s const *opcode ATTRIBUTE_UNUSED, + bfd_vma addr ATTRIBUTE_UNUSED, + unsigned short insn, char *op1, char *comm1) +{ + int regs = (insn & 0x0f00) >> 8; + int as = (insn & 0x0030) >> 4; + int cmd_len = 2; + bfd_vma op_addr; + short dst; - /* Destination. Special care needed on addr + XXXX. */ + op_addr = addr + cmd_len; + dst = msp430dis_operand (op_addr, info, regs, as, &cmd_len); + msp430_decode_operand (regs, as, op_addr, dst, OP_16BIT_HEX, op1, comm1); - if (ad == 0) - { - /* Register. */ - if (regd == 0) - { - *cycles += 1; - sprintf (op2, "r0"); - } - else if (regd == 1) - sprintf (op2, "r1"); + return cmd_len; +} - else if (regd == 2) - sprintf (op2, "r2"); +static opwidth_t +msp430x_opwidth (unsigned int insn) +{ + insn &= NON_ADDR_OPERATION | BYTE_OPERATION_X; + + if (insn == (NON_ADDR_OPERATION | BYTE_OPERATION_X)) + return BYTE_OP; + if (insn == NON_ADDR_OPERATION) + return WORD_OP; + if (insn == BYTE_OPERATION_X) + return ADDR_OP; + /*NOTREACHED*/ return DEFAULT_OP; +} - else - sprintf (op2, "r%d", regd); - } - else /* ad == 1. */ - { - * cycles += 3; +static void +set_repeats (unsigned int insn, int *repeats) +{ + if (0 == (insn & 0x008f)) + return; + + /* Use non-negative number to represent Rn; use a negative number to + * represent an immediate count (note that the stored value is one + * less than the count). */ + if (insn & 0x0080) + *repeats = insn & 0xf; + else + *repeats = -(1 + (insn & 0xf)); +} - if (regd == 0) - { - /* PC relative. */ - *cycles += 1; - dst = msp430dis_opcode (addr + cmd_len, info); - sprintf (op2, "0x%04x", PS (dst)); - sprintf (comm2, "PC rel. 0x%04x", - PS ((short) addr + cmd_len + dst)); - cmd_len += 2; - } - else if (regd == 2) - { - /* Absolute. */ - dst = msp430dis_opcode (addr + cmd_len, info); - cmd_len += 2; - sprintf (op2, "&0x%04x", PS (dst)); - } - else - { - dst = msp430dis_opcode (addr + cmd_len, info); - cmd_len += 2; - sprintf (op2, "%d(r%d)", dst, regd); - } - } +static int +msp430x_singleoperand (disassemble_info * info, + struct msp430_opcode_s const *opcode, + bfd_vma addr, + unsigned int insn, char *op, char *comm, int *repeats) +{ + int reg = (insn >> 16) & 0xf; + int am = (insn >> 20) & 0x3; + int cmd_len = 4; + int dst = 0; + bfd_vma op_addr; + + op_addr = addr + cmd_len; + if (opcode_variant (opcode) < V_PUSHX) + if ((am == AMs_Immediate && reg == REGNO_PC) /* #N */ + || (am == AM_Register && reg == REGNO_CG2)) /* r3 */ + { + strcpy (comm, _("Illegal as 1-op instr")); + return -1; + } + + /* If register-mode extension set the repeat count */ + if (am == AM_Register) + set_repeats (insn, repeats); + + dst = msp430dis_operand (op_addr, info, reg, am, + &cmd_len) | ((insn & 0x0000000f) << 16); + /* BOGOSITY: sign extension */ + dst = (dst << 12) >> 12; + msp430x_decode_operand (reg, am, op_addr, dst, OP_20BIT, op, comm); return cmd_len; } static int -msp430_branchinstr (disassemble_info *info, - struct msp430_opcode_s *opcode ATTRIBUTE_UNUSED, - bfd_vma addr ATTRIBUTE_UNUSED, - unsigned short insn, - char *op1, - char *comm1, - int *cycles) +msp430x_exception (disassemble_info * info, + struct msp430_opcode_s const *opcode, + bfd_vma addr, + unsigned int insn, + char *op1, + char *op2, char *comm1, char *comm2, opwidth_t * op_width) { - int regs = 0, regd = 0; - int as = 0; + int reg = 0; int cmd_len = 2; - short dst = 0; + bfd_vma op_addr; + int n = 0; + int dst = 0; - regd = insn & 0x0f; - regs = (insn & 0x0f00) >> 8; - as = (insn & 0x0030) >> 4; - - if (regd != 0) /* Destination register is not a PC. */ - return 0; + reg = insn & 0xf; + op_addr = addr + cmd_len; - /* dst is a source register. */ - if (as == 0) + switch (opcode_variant (opcode)) { - /* Constants. */ - if (regs == 3) - { - *cycles = 1; - sprintf (op1, "#0"); - sprintf (comm1, "r3 As==00"); - } - else - { - /* Register. */ - *cycles = 1; - sprintf (op1, "r%d", regs); + case V_CALLA: + switch ((insn >> 4) & 0xf) + { + case 4: /* Rdst */ + msp430x_decode_operand (reg, AM_Register, 0, 0, OP_OTHER, op1, comm1); + break; + case 5: /* x(Rdst) */ + dst = msp430dis_operand (op_addr, info, reg, AM_Indexed, &cmd_len); + msp430x_decode_operand (reg, AM_Indexed, op_addr, dst, + OP_16BIT, op1, comm1); + break; + case 6: /* @Rdst */ + msp430x_decode_operand (reg, AMs_IndirectRegister, 0, 0, OP_OTHER, op1, + comm1); + break; + case 7: /* @Rdst+ */ + msp430x_decode_operand (reg, AMs_IndirectAutoIncrement, 0, 0, OP_OTHER, + op1, comm1); + break; + case 8: /* &abs20 */ + dst = msp430dis_operand (op_addr, info, REGNO_CG1, AM_Indexed, &cmd_len); + dst |= (insn & 0x000f) << 16; + msp430x_decode_operand (REGNO_CG1, AM_Symbolic, op_addr, + dst, OP_20BIT_HEX, op1, comm1); + break; + case 9: /* EDE */ + dst = msp430dis_operand (op_addr, info, REGNO_PC, AM_Indexed, &cmd_len); + dst |= (insn & 0x000f) << 16; + msp430x_decode_operand (REGNO_PC, AM_Indexed, op_addr, dst, + OP_20BIT, op1, comm1); + break; + case 0xb: /* #imm20 */ + dst = msp430dis_operand (op_addr, info, REGNO_PC, AMs_Immediate, &cmd_len); + dst |= (insn & 0x000f) << 16; + msp430x_decode_operand (REGNO_PC, AMs_IndirectAutoIncrement, + op_addr, dst, OP_20BIT_HEX, op1, comm1); + break; } + break; + case V_PUSHM: + n = ((insn >> 4) & 0xf) + 1; + msp430x_decode_operand (REGNO_PC, AMs_IndirectAutoIncrement, 0, n, OP_DECIMAL, op1, comm1); /* #N */ + msp430x_decode_operand (reg, AM_Register, 0, 0, OP_OTHER, op2, comm2); /* Rdst */ + if ((insn & 0x0100) == 0) + *op_width = ADDR_OP; + break; + case V_POPM: + n = ((insn >> 4) & 0xf) + 1; + reg = (reg + n - 1) & 0xf; + msp430x_decode_operand (REGNO_PC, AMs_IndirectAutoIncrement, 0, n, OP_DECIMAL, op1, comm1); /* #N */ + msp430x_decode_operand (reg, AM_Register, 0, 0, OP_OTHER, op2, comm2); /* Rdst */ + if ((insn & 0x0100) == 0) + *op_width = ADDR_OP; + break; + case V_ROTM: + n = ((insn >> 10) & 0x3) + 1; + msp430x_decode_operand (REGNO_PC, AMs_IndirectAutoIncrement, 0, n, OP_DECIMAL, op1, comm1); /* #N */ + msp430x_decode_operand (reg, AM_Register, 0, 0, OP_OTHER, op2, comm2); /* Rdst */ + if ((insn & 0x0010) == 0) + *op_width = ADDR_OP; + break; + default: + break; } - else if (as == 2) + return cmd_len; +} + +static int +msp430x_doubleoperand (disassemble_info * info, + struct msp430_opcode_s const *opcode, + bfd_vma addr, + unsigned int insn, + char *op1, + char *op2, + char *comm1, + char *comm2, opwidth_t * op_width, int *repeats) +{ + int regs, regd; + int as, ad; + int ops, opd; + int cmd_len = 4; + bfd_vma ops_addr; + bfd_vma opd_addr; + + regd = (insn >> 16) & 0xf; + regs = (insn >> 24) & 0xf; + as = (insn >> 20) & 0x3; + ad = (insn >> 23) & 0x1; + + ops_addr = addr + cmd_len; + + if (ad == AM_Register && regd == REGNO_CG2) { - 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); - } + /* R3 is illegal as dest: may be data section. */ + if (comm1) + strcpy (comm1, _("Illegal as 2-op instr")); + else if (comm2) + strcpy (comm2, _("Illegal as 2-op instr")); + return -1; } - else if (as == 3) + *op_width = msp430x_opwidth (insn); + + /* If register-mode extension set the repeat count */ + if (as == AM_Register && ad == AM_Register) + set_repeats (insn, repeats); + + ops = msp430dis_operand (ops_addr, info, regs, as, &cmd_len); + ops |= (insn & 0x00000780) << 9; + /* BOGOSITY: sign extension */ + ops = (ops << 12) >> 12; + + opd_addr = addr + cmd_len; + opd = msp430dis_operand (opd_addr, info, regd, ad, &cmd_len); + opd |= (insn & 0x0000000f) << 16; + /* BOGOSITY: sign extension */ + opd = (opd << 12) >> 12; + + msp430x_decode_operand (regs, as, ops_addr, ops, OP_20BIT, op1, comm1); + + if (opcode_variant (opcode) == V_X_SHIFT && ((0 == (as | ad) && ops != opd) /* non-register extension different ops */ + || regs != regd)) /* register extension different regs */ + return 0; + + msp430x_decode_operand (regd, ad, opd_addr, opd, OP_20BIT, op2, comm2); + + return cmd_len; +} + +static int +msp430x_address (disassemble_info * info, + bfd_vma addr, + unsigned short insn, + char *op1, char *op2, char *comm1, char *comm2) +{ + int cmd_len = 2; + bfd_vma op_addr; + int dst = 0; + typedef struct + { + int as, regs; + int ad, regd; + int length; + } + operands_t; + + static operands_t const operands_table[] = { + {2, -1, 0, -1, 0}, /* 0 @Rsrc, Rdst */ + {3, -1, 0, -1, 0}, /* 1 @Rsrc+, Rdst */ + {1, 2, 0, -1, 2}, /* 2 &abs20, Rdst */ + {1, -1, 0, -1, 2}, /* 3 x(Rsrc), Rdst */ + {0, 0, 0, 0, 0}, /* 4 */ + {0, 0, 0, 0, 0}, /* 5 */ + {0, -1, 1, 2, 2}, /* 6 Rsrc, &abs20 */ + {0, -1, 1, -1, 2}, /* 7 Rsrc, x(Rdst) */ + {3, 0, 0, -1, 2}, /* 8 #imm20, Rdst */ + {3, 0, 0, -1, 2}, /* 9 #imm20, Rdst */ + {3, 0, 0, -1, 2}, /* a #imm20, Rdst */ + {3, 0, 0, -1, 2}, /* b #imm20, Rdst */ + {0, -1, 0, -1, 0}, /* c Rsrc, Rdst */ + {0, -1, 0, -1, 0}, /* d Rsrc, Rdst */ + {0, -1, 0, -1, 0}, /* e Rsrc, Rdst */ + {0, -1, 0, -1, 0}, /* f Rsrc, Rdst */ + }; + operand_t size; + + op_addr = addr + cmd_len; + operands_t operands = operands_table[(insn >> 4) & 0xf]; + if (((insn >> 4) & 0xf) == 6) + dst = msp430dis_opcode (op_addr, info) | ((insn & 0x000f) << 16); + else if (((insn >> 4) & 0xb) == 3) + dst = (short) msp430dis_opcode (op_addr, info); + else if (operands.length != 0) + dst = msp430dis_opcode (op_addr, info) | ((insn & 0x0f00) << 8); + + if (operands.regs == -1) + operands.regs = (insn >> 8) & 0x000f; + if (operands.regd == -1) + operands.regd = (insn >> 0) & 0x000f; + + if (operands.regd == REGNO_CG2) { - 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) - { - /* Absolute. @pc+ */ - *cycles = 3; - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 2; - sprintf (op1, "#0x%04x", PS (dst)); - } - else - { - *cycles = 2; - sprintf (op1, "@r%d+", regs); - } + /* R3 is illegal as dest: may be data section. */ + if (comm1) + strcpy (comm1, _("Illegal as address instr")); + else if (comm2) + strcpy (comm2, _("Illegal as address instr")); + return -1; } - else if (as == 1) - { - * cycles = 3; + /* 3 and 7 are used for 16-bit indexed offsets */ + size = ((insn >> 4) & 0x0b) == 3 ? OP_16BIT_HEX : OP_20BIT_HEX; + msp430x_decode_operand (operands.regs, operands.as, op_addr, dst, + size, op1, comm1); + msp430x_decode_operand (operands.regd, operands.ad, op_addr, dst, + size, op2, comm2); + return cmd_len + operands.length; +} - if (regs == 0) - { - /* PC relative. */ - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 2; - (*cycles)++; - sprintf (op1, "0x%04x", PS (dst)); - sprintf (comm1, "PC rel. 0x%04x", - PS ((short) addr + 2 + dst)); - } - else if (regs == 2) - { - /* Absolute. */ - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 2; - sprintf (op1, "&0x%04x", PS (dst)); - } - else if (regs == 3) - { - (*cycles)--; - sprintf (op1, "#1"); - sprintf (comm1, "r3 As==01"); - } - else - { - /* Indexd. */ - dst = msp430dis_opcode (addr + 2, info); - cmd_len += 2; - sprintf (op1, "%d(r%d)", dst, regs); - } +static int +msp430x_emulated (disassemble_info * info, + struct msp430_opcode_s const *opcode, + bfd_vma addr, + unsigned int insn, + char *op1, char *comm1, opwidth_t * op_width, int *repeats) +{ + switch (opcode_variant (opcode)) + { + case V_NONE: + case V_X_SHIFT: /* emulated by double operand instruction */ + return msp430x_doubleoperand (info, opcode, addr, insn, (char *) 0, op1, + (char *) 0, comm1, op_width, repeats); + case V_RETA: /* reta, substituted by mova */ + return 2; + case V_MOVA: + case V_EMU_ADDR: /* substituted by other address instruction */ + return msp430x_address (info, addr, insn, (char *) 0, op1, + (char *) 0, comm1); + case V_BRA: /* bra, substituted by mova */ + return msp430x_address (info, addr, insn, op1, (char *) 0, + comm1, (char *) 0); + default: + break; } - - return cmd_len; + return 0; } int -print_insn_msp430 (bfd_vma addr, disassemble_info *info) +print_insn_msp430 (bfd_vma addr, disassemble_info * info) { void *stream = info->stream; fprintf_ftype prin = info->fprintf_func; - struct msp430_opcode_s *opcode; + struct msp430_opcode_s const *opcode; char op1[32], op2[32], comm1[64], comm2[64]; int cmd_len = 0; - unsigned short insn; - int cycles = 0; - char *bc = ""; - char dinfo[32]; /* Debug purposes. */ + unsigned int insn; + int repeats = 0; + int cpu = + (bfd_mach_msp430x == info->mach) ? MSP430_CPU_MSP430X : MSP430_CPU_MSP430; + + opwidth_t op_width = DEFAULT_OP; + static char const *width_modifier[] = { "", "", ".b", ".a" }; insn = msp430dis_opcode (addr, info); - sprintf (dinfo, "0x%04x", insn); - if (((int) addr & 0xffff) > 0xffdf) - { - (*prin) (stream, "interrupt service routine at 0x%04x", 0xffff & insn); - return 2; - } + /* Detect extension words */ + if (cpu >= MSP430_CPU_MSP430X && ((insn & 0xf800) == 0x1800)) + insn |= msp430dis_opcode (addr + 2, info) << 16; *comm1 = 0; *comm2 = 0; for (opcode = msp430_opcodes; opcode->name; opcode++) { - if ((insn & opcode->bin_mask) == opcode->bin_opcode - && opcode->bin_opcode != 0x9300) + if ((insn & opcode->bin_mask) == opcode->bin_opcode) { *op1 = 0; *op2 = 0; *comm1 = 0; *comm2 = 0; - /* r0 as destination. Ad should be zero. */ - if (opcode->insn_opnumb == 3 && (insn & 0x000f) == 0 - && (0x0080 & insn) == 0) + /* unsupported instruction */ + if (opcode_format (opcode) >= FMT_X && cpu < MSP430_CPU_MSP430X) + break; + + /* r0 as destination. Ad should be zero. Rdst=0 and Ad=0 are encoded in opcode & opcode_mask */ + if (opcode_format (opcode) == FMT_EMULATED + && opcode_variant (opcode) == V_BR) { cmd_len = - msp430_branchinstr (info, opcode, addr, insn, op1, comm1, - &cycles); + msp430_branchinstr (info, opcode, addr, insn, op1, comm1); if (cmd_len) break; } + if (opcode_format (opcode) < FMT_X) + switch (opcode->insn_opnumb) + { + case 0: + cmd_len = msp430_nooperands (opcode, addr, insn, comm1); + break; + case 2: + cmd_len = + msp430_doubleoperand (info, opcode, addr, insn, op1, op2, + comm1, comm2); + if (insn & BYTE_OPERATION) + op_width = BYTE_OP; + break; + case 1: + cmd_len = + msp430_singleoperand (info, opcode, addr, insn, op1, comm1); + if (insn & BYTE_OPERATION + && opcode_format (opcode) != FMT_JUMP) + op_width = BYTE_OP; + break; + default: + break; + } + else /* 430x instruction */ + switch (opcode_format (opcode)) + { + case FMT_X_SINGLE_OPERAND: + if (opcode_variant (opcode) == V_SWPSXT /* swpbx, sxtx */ + && (insn & (NON_ADDR_OPERATION | BYTE_OPERATION_X)) == 0) /* .a, special case */ + insn ^= BYTE_OPERATION_X; /* make A/L, B/W as ordinary */ + + op_width = msp430x_opwidth (insn); + + if (opcode_variant (opcode) == V_SWPSXT && op_width == BYTE_OP) /* swpbx, sxtx */ + strcpy (comm1, _("Illegal A/L, B/W bits setting")); + + cmd_len = + msp430x_singleoperand (info, opcode, addr, insn, op1, comm1, + &repeats); + break; + case FMT_X_EXCEPTION: + cmd_len = + msp430x_exception (info, opcode, addr, insn, op1, op2, + comm1, comm2, &op_width); + break; + case FMT_X_DOUBLE_OPERAND: + cmd_len = + msp430x_doubleoperand (info, opcode, addr, insn, op1, op2, + comm1, comm2, &op_width, &repeats); + break; + case FMT_X_EMULATED: + cmd_len = msp430x_emulated (info, opcode, addr, insn, op1, + comm1, &op_width, &repeats); + break; - switch (opcode->insn_opnumb) - { - case 0: - cmd_len = msp430_nooperands (opcode, addr, insn, comm1, &cycles); - break; - case 2: - cmd_len = - msp430_doubleoperand (info, opcode, addr, insn, op1, op2, - comm1, comm2, &cycles); - if (insn & BYTE_OPERATION) - bc = ".b"; - break; - case 1: - cmd_len = - msp430_singleoperand (info, opcode, addr, insn, op1, comm1, - &cycles); - if (insn & BYTE_OPERATION && opcode->fmt != 3) - bc = ".b"; - break; - default: - break; - } + case FMT_X_ADDRESS: + cmd_len = msp430x_address (info, addr, insn, op1, op2, + comm1, comm2); + break; + default: + break; + } } if (cmd_len) break; } - dinfo[5] = 0; - if (cmd_len < 1) { /* Unknown opcode, or invalid combination of operands. */ - (*prin) (stream, ".word 0x%04x; ????", PS (insn)); + (*prin) (stream, ".word 0x%04x; ????\t%s%s", MASK_16 (insn), comm1, + comm2); return 2; } - (*prin) (stream, "%s%s", opcode->name, bc); + + if (repeats) + { + if (repeats < 0) + (*prin) (stream, ".rpt\t#%d\n\t\t\t\t", -repeats); + else + (*prin) (stream, ".rpt\tr%d\n\t\t\t\t", repeats); + } + + (*prin) (stream, "%s%s", opcode->name, width_modifier[op_width]); if (*op1) (*prin) (stream, "\t%s", op1); @@ -765,23 +850,11 @@ print_insn_msp430 (bfd_vma addr, disassemble_info *info) if (*comm1 || *comm2) (*prin) (stream, ";"); - else if (cycles) - { - if (*op2) - (*prin) (stream, ";"); - else - { - if (strlen (op1) < 7) - (*prin) (stream, ";"); - else - (*prin) (stream, "\t;"); - } - } if (*comm1) (*prin) (stream, "%s", comm1); if (*comm1 && *comm2) - (*prin) (stream, ","); + (*prin) (stream, ", "); if (*comm2) - (*prin) (stream, " %s", comm2); + (*prin) (stream, "%s", comm2); return cmd_len; }