X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-avr.c;h=9ed7de8a54cebae4da34afccdaa72216d1dc8561;hb=f36e88862f94c15a88fa27df7af906ad75a42e7f;hp=4214d6148c4e2f00503950d1cf98024572b9f6ff;hpb=4fb8d1c60ac887a0e835e9c7dfe5cffd7f1cb3dd;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-avr.c b/gas/config/tc-avr.c index 4214d6148c..9ed7de8a54 100644 --- a/gas/config/tc-avr.c +++ b/gas/config/tc-avr.c @@ -1,7 +1,6 @@ /* tc-avr.c -- Assembler code for the ATMEL AVR - Copyright 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009, - 2010 Free Software Foundation, Inc. + Copyright (C) 1999-2014 Free Software Foundation, Inc. Contributed by Denis Chertykov This file is part of GAS, the GNU Assembler. @@ -24,23 +23,27 @@ #include "as.h" #include "safe-ctype.h" #include "subsegs.h" +#include "dwarf2dbg.h" +#include "dw2gencfi.h" + struct avr_opcodes_s { char * name; char * constraints; + char * opcode; int insn_size; /* In words. */ int isa; unsigned int bin_opcode; }; #define AVR_INSN(NAME, CONSTR, OPCODE, SIZE, ISA, BIN) \ -{#NAME, CONSTR, SIZE, ISA, BIN}, +{#NAME, CONSTR, OPCODE, SIZE, ISA, BIN}, struct avr_opcodes_s avr_opcodes[] = { #include "opcode/avr.h" - {NULL, NULL, 0, 0, 0} + {NULL, NULL, NULL, 0, 0, 0} }; const char comment_chars[] = ";"; @@ -62,23 +65,31 @@ static struct mcu_type_s mcu_types[] = { {"avr1", AVR_ISA_AVR1, bfd_mach_avr1}, /* TODO: insruction set for avr2 architecture should be AVR_ISA_AVR2, - but set to AVR_ISA_AVR25 for some following version - of GCC (from 4.3) for backward compatibility. */ + but set to AVR_ISA_AVR25 for some following version + of GCC (from 4.3) for backward compatibility. */ {"avr2", AVR_ISA_AVR25, bfd_mach_avr2}, {"avr25", AVR_ISA_AVR25, bfd_mach_avr25}, -/* TODO: insruction set for avr3 architecture should be AVR_ISA_AVR3, - but set to AVR_ISA_AVR3_ALL for some following version +/* TODO: insruction set for avr3 architecture should be AVR_ISA_AVR3, + but set to AVR_ISA_AVR3_ALL for some following version of GCC (from 4.3) for backward compatibility. */ {"avr3", AVR_ISA_AVR3_ALL, bfd_mach_avr3}, {"avr31", AVR_ISA_AVR31, bfd_mach_avr31}, {"avr35", AVR_ISA_AVR35, bfd_mach_avr35}, {"avr4", AVR_ISA_AVR4, bfd_mach_avr4}, -/* TODO: insruction set for avr5 architecture should be AVR_ISA_AVR5, - but set to AVR_ISA_AVR51 for some following version +/* TODO: insruction set for avr5 architecture should be AVR_ISA_AVR5, + but set to AVR_ISA_AVR51 for some following version of GCC (from 4.3) for backward compatibility. */ {"avr5", AVR_ISA_AVR51, bfd_mach_avr5}, {"avr51", AVR_ISA_AVR51, bfd_mach_avr51}, {"avr6", AVR_ISA_AVR6, bfd_mach_avr6}, + {"avrxmega1", AVR_ISA_XMEGA, bfd_mach_avrxmega1}, + {"avrxmega2", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"avrxmega3", AVR_ISA_XMEGA, bfd_mach_avrxmega3}, + {"avrxmega4", AVR_ISA_XMEGA, bfd_mach_avrxmega4}, + {"avrxmega5", AVR_ISA_XMEGA, bfd_mach_avrxmega5}, + {"avrxmega6", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"avrxmega7", AVR_ISA_XMEGA, bfd_mach_avrxmega7}, + {"avrtiny", AVR_ISA_AVRTINY, bfd_mach_avrtiny}, {"at90s1200", AVR_ISA_1200, bfd_mach_avr1}, {"attiny11", AVR_ISA_AVR1, bfd_mach_avr1}, {"attiny12", AVR_ISA_AVR1, bfd_mach_avr1}, @@ -96,6 +107,7 @@ static struct mcu_type_s mcu_types[] = {"at90s8515", AVR_ISA_AVR2, bfd_mach_avr2}, {"at90c8534", AVR_ISA_AVR2, bfd_mach_avr2}, {"at90s8535", AVR_ISA_AVR2, bfd_mach_avr2}, + {"ata5272", AVR_ISA_AVR25, bfd_mach_avr25}, {"attiny13", AVR_ISA_AVR25, bfd_mach_avr25}, {"attiny13a", AVR_ISA_AVR25, bfd_mach_avr25}, {"attiny2313", AVR_ISA_AVR25, bfd_mach_avr25}, @@ -120,8 +132,8 @@ static struct mcu_type_s mcu_types[] = {"attiny43u", AVR_ISA_AVR25, bfd_mach_avr25}, {"attiny48", AVR_ISA_AVR25, bfd_mach_avr25}, {"attiny88", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny828", AVR_ISA_AVR25, bfd_mach_avr25}, {"at86rf401", AVR_ISA_RF401, bfd_mach_avr25}, - {"ata6289", AVR_ISA_AVR25, bfd_mach_avr25}, {"at43usb355", AVR_ISA_AVR3, bfd_mach_avr3}, {"at76c711", AVR_ISA_AVR3, bfd_mach_avr3}, {"atmega103", AVR_ISA_AVR31, bfd_mach_avr31}, @@ -129,12 +141,19 @@ static struct mcu_type_s mcu_types[] = {"attiny167", AVR_ISA_AVR35, bfd_mach_avr35}, {"at90usb82", AVR_ISA_AVR35, bfd_mach_avr35}, {"at90usb162", AVR_ISA_AVR35, bfd_mach_avr35}, + {"ata5505", AVR_ISA_AVR35, bfd_mach_avr35}, {"atmega8u2", AVR_ISA_AVR35, bfd_mach_avr35}, {"atmega16u2", AVR_ISA_AVR35, bfd_mach_avr35}, {"atmega32u2", AVR_ISA_AVR35, bfd_mach_avr35}, + {"attiny1634", AVR_ISA_AVR35, bfd_mach_avr35}, {"atmega8", AVR_ISA_M8, bfd_mach_avr4}, + {"ata6289", AVR_ISA_AVR4, bfd_mach_avr4}, + {"atmega8a", AVR_ISA_M8, bfd_mach_avr4}, + {"ata6285", AVR_ISA_AVR4, bfd_mach_avr4}, + {"ata6286", AVR_ISA_AVR4, bfd_mach_avr4}, {"atmega48", AVR_ISA_AVR4, bfd_mach_avr4}, {"atmega48a", AVR_ISA_AVR4, bfd_mach_avr4}, + {"atmega48pa", AVR_ISA_AVR4, bfd_mach_avr4}, {"atmega48p", AVR_ISA_AVR4, bfd_mach_avr4}, {"atmega88", AVR_ISA_AVR4, bfd_mach_avr4}, {"atmega88a", AVR_ISA_AVR4, bfd_mach_avr4}, @@ -149,6 +168,9 @@ static struct mcu_type_s mcu_types[] = {"at90pwm3", AVR_ISA_AVR4, bfd_mach_avr4}, {"at90pwm3b", AVR_ISA_AVR4, bfd_mach_avr4}, {"at90pwm81", AVR_ISA_AVR4, bfd_mach_avr4}, + {"at90pwm161", AVR_ISA_AVR5, bfd_mach_avr5}, + {"ata5790", AVR_ISA_AVR5, bfd_mach_avr5}, + {"ata5795", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega16", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega16a", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega161", AVR_ISA_M161, bfd_mach_avr5}, @@ -156,17 +178,21 @@ static struct mcu_type_s mcu_types[] = {"atmega163", AVR_ISA_M161, bfd_mach_avr5}, {"atmega164a", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega164p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega164pa",AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega165", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega165a", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega165p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega165pa",AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega168", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega168a", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega168p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega168pa",AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega169", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega169a", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega169p", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega169pa",AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega32", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega32a", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega323", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega324a", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega324p", AVR_ISA_AVR5, bfd_mach_avr5}, @@ -174,9 +200,11 @@ static struct mcu_type_s mcu_types[] = {"atmega325", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega325a", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega325p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega325pa",AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega3250", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega3250a",AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega3250p",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega3250pa",AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega328", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega328p", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega329", AVR_ISA_AVR5, bfd_mach_avr5}, @@ -186,8 +214,12 @@ static struct mcu_type_s mcu_types[] = {"atmega3290", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega3290a",AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega3290p",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega3290pa",AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega406", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega64rfr2", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega644rfr2",AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega64", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega64a", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega640", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega644", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega644a", AVR_ISA_AVR5, bfd_mach_avr5}, @@ -205,13 +237,18 @@ static struct mcu_type_s mcu_types[] = {"atmega6490", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega6490a",AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega6490p",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega64rfr2",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega644rfr2",AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega16hva",AVR_ISA_AVR5, bfd_mach_avr5}, - {"atmega16hva2",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega16hva2",AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega16hvb",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega16hvbrevb",AVR_ISA_AVR5,bfd_mach_avr5}, {"atmega32hvb",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega32hvbrevb",AVR_ISA_AVR5,bfd_mach_avr5}, {"atmega64hve",AVR_ISA_AVR5, bfd_mach_avr5}, {"at90can32" , AVR_ISA_AVR5, bfd_mach_avr5}, {"at90can64" , AVR_ISA_AVR5, bfd_mach_avr5}, + {"at90pwm161", AVR_ISA_AVR5, bfd_mach_avr5}, {"at90pwm216", AVR_ISA_AVR5, bfd_mach_avr5}, {"at90pwm316", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega32c1", AVR_ISA_AVR5, bfd_mach_avr5}, @@ -228,20 +265,78 @@ static struct mcu_type_s mcu_types[] = {"at94k", AVR_ISA_94K, bfd_mach_avr5}, {"m3000", AVR_ISA_AVR5, bfd_mach_avr5}, {"atmega128", AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega128a", AVR_ISA_AVR51, bfd_mach_avr51}, {"atmega1280", AVR_ISA_AVR51, bfd_mach_avr51}, {"atmega1281", AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega1284", AVR_ISA_AVR51, bfd_mach_avr51}, {"atmega1284p",AVR_ISA_AVR51, bfd_mach_avr51}, {"atmega128rfa1",AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega128rfr2",AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega1284rfr2",AVR_ISA_AVR51, bfd_mach_avr51}, {"at90can128", AVR_ISA_AVR51, bfd_mach_avr51}, {"at90usb1286",AVR_ISA_AVR51, bfd_mach_avr51}, {"at90usb1287",AVR_ISA_AVR51, bfd_mach_avr51}, {"atmega2560", AVR_ISA_AVR6, bfd_mach_avr6}, {"atmega2561", AVR_ISA_AVR6, bfd_mach_avr6}, + {"atmega256rfr2", AVR_ISA_AVR6, bfd_mach_avr6}, + {"atmega2564rfr2", AVR_ISA_AVR6, bfd_mach_avr6}, + {"atxmega16a4", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"atxmega16a4u",AVR_ISA_XMEGAU, bfd_mach_avrxmega2}, + {"atxmega16c4", AVR_ISA_XMEGAU, bfd_mach_avrxmega2}, + {"atxmega16d4", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"atxmega32a4", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"atxmega32a4u",AVR_ISA_XMEGAU, bfd_mach_avrxmega2}, + {"atxmega32c4", AVR_ISA_XMEGAU, bfd_mach_avrxmega2}, + {"atxmega32d4", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"atxmega32e5", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"atxmega16e5", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"atxmega8e5", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"atxmega32x1", AVR_ISA_XMEGA, bfd_mach_avrxmega2}, + {"atxmega64a3", AVR_ISA_XMEGA, bfd_mach_avrxmega4}, + {"atxmega64a3u",AVR_ISA_XMEGAU, bfd_mach_avrxmega4}, + {"atxmega64a4u",AVR_ISA_XMEGAU, bfd_mach_avrxmega4}, + {"atxmega64b1", AVR_ISA_XMEGAU, bfd_mach_avrxmega4}, + {"atxmega64b3", AVR_ISA_XMEGAU, bfd_mach_avrxmega4}, + {"atxmega64c3", AVR_ISA_XMEGAU, bfd_mach_avrxmega4}, + {"atxmega64d3", AVR_ISA_XMEGA, bfd_mach_avrxmega4}, + {"atxmega64d4", AVR_ISA_XMEGA, bfd_mach_avrxmega4}, + {"atxmega64a1", AVR_ISA_XMEGA, bfd_mach_avrxmega5}, + {"atxmega64a1u",AVR_ISA_XMEGAU, bfd_mach_avrxmega5}, + {"atxmega128a3", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega128a3u",AVR_ISA_XMEGAU,bfd_mach_avrxmega6}, + {"atxmega128b1", AVR_ISA_XMEGAU, bfd_mach_avrxmega6}, + {"atxmega128b3", AVR_ISA_XMEGAU,bfd_mach_avrxmega6}, + {"atxmega128c3", AVR_ISA_XMEGAU,bfd_mach_avrxmega6}, + {"atxmega128d3", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega128d4", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega192a3", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega192a3u",AVR_ISA_XMEGAU,bfd_mach_avrxmega6}, + {"atxmega192c3", AVR_ISA_XMEGAU, bfd_mach_avrxmega6}, + {"atxmega192d3", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega256a3", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega256a3u",AVR_ISA_XMEGAU,bfd_mach_avrxmega6}, + {"atxmega256a3b",AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega256a3bu",AVR_ISA_XMEGAU, bfd_mach_avrxmega6}, + {"atxmega256c3", AVR_ISA_XMEGAU,bfd_mach_avrxmega6}, + {"atxmega256d3", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega384c3", AVR_ISA_XMEGAU,bfd_mach_avrxmega6}, + {"atxmega384d3", AVR_ISA_XMEGA, bfd_mach_avrxmega6}, + {"atxmega128a1", AVR_ISA_XMEGA, bfd_mach_avrxmega7}, + {"atxmega128a1u", AVR_ISA_XMEGAU, bfd_mach_avrxmega7}, + {"atxmega128a4u", AVR_ISA_XMEGAU, bfd_mach_avrxmega7}, + {"attiny4", AVR_ISA_AVRTINY, bfd_mach_avrtiny}, + {"attiny5", AVR_ISA_AVRTINY, bfd_mach_avrtiny}, + {"attiny9", AVR_ISA_AVRTINY, bfd_mach_avrtiny}, + {"attiny10", AVR_ISA_AVRTINY, bfd_mach_avrtiny}, + {"attiny20", AVR_ISA_AVRTINY, bfd_mach_avrtiny}, + {"attiny40", AVR_ISA_AVRTINY, bfd_mach_avrtiny}, {NULL, 0, 0} }; + /* Current MCU type. */ static struct mcu_type_s default_mcu = {"avr2", AVR_ISA_AVR2, bfd_mach_avr2}; +static struct mcu_type_s specified_mcu; static struct mcu_type_s * avr_mcu = & default_mcu; /* AVR target-specific switches. */ @@ -250,9 +345,11 @@ struct avr_opt_s int all_opcodes; /* -mall-opcodes: accept all known AVR opcodes. */ int no_skip_bug; /* -mno-skip-bug: no warnings for skipping 2-word insns. */ int no_wrap; /* -mno-wrap: reject rjmp/rcall with 8K wrap-around. */ + int link_relax; /* -mlink-relax: generate relocations for linker + relaxation. */ }; -static struct avr_opt_s avr_opt = { 0, 0, 0 }; +static struct avr_opt_s avr_opt = { 0, 0, 0, 0 }; const char EXP_CHARS[] = "eE"; const char FLT_CHARS[] = "dD"; @@ -312,7 +409,9 @@ enum options { OPTION_ALL_OPCODES = OPTION_MD_BASE + 1, OPTION_NO_SKIP_BUG, - OPTION_NO_WRAP + OPTION_NO_WRAP, + OPTION_ISA_RMW, + OPTION_LINK_RELAX }; struct option md_longopts[] = @@ -321,6 +420,8 @@ struct option md_longopts[] = { "mall-opcodes", no_argument, NULL, OPTION_ALL_OPCODES }, { "mno-skip-bug", no_argument, NULL, OPTION_NO_SKIP_BUG }, { "mno-wrap", no_argument, NULL, OPTION_NO_WRAP }, + { "mrmw", no_argument, NULL, OPTION_ISA_RMW }, + { "mlink-relax", no_argument, NULL, OPTION_LINK_RELAX }, { NULL, no_argument, NULL, 0 } }; @@ -413,13 +514,22 @@ md_show_usage (FILE *stream) " avr5 - enhanced AVR core with up to 64K program memory\n" " avr51 - enhanced AVR core with up to 128K program memory\n" " avr6 - enhanced AVR core with up to 256K program memory\n" - " or immediate microcontroller name.\n")); + " avrxmega2 - XMEGA, > 8K, < 64K FLASH, < 64K RAM\n" + " avrxmega3 - XMEGA, > 8K, <= 64K FLASH, > 64K RAM\n" + " avrxmega4 - XMEGA, > 64K, <= 128K FLASH, <= 64K RAM\n" + " avrxmega5 - XMEGA, > 64K, <= 128K FLASH, > 64K RAM\n" + " avrxmega6 - XMEGA, > 128K, <= 256K FLASH, <= 64K RAM\n" + " avrxmega7 - XMEGA, > 128K, <= 256K FLASH, > 64K RAM\n" + " avrtiny - AVR Tiny core with 16 gp registers\n")); fprintf (stream, _(" -mall-opcodes accept all AVR opcodes, even if not supported by MCU\n" " -mno-skip-bug disable warnings for skipping two-word instructions\n" " (default for avr4, avr5)\n" " -mno-wrap reject rjmp/rcall instructions with 8K wrap-around\n" - " (default for avr3, avr5)\n")); + " (default for avr3, avr5)\n" + " -mrmw accept Read-Modify-Write instructions\n" + " -mlink-relax generate relocations for linker relaxation\n" + )); show_mcu_list (stream); } @@ -466,7 +576,12 @@ md_parse_option (int c, char *arg) type - this for allows passing -mmcu=... via gcc ASM_SPEC as well as .arch ... in the asm output at the same time. */ if (avr_mcu == &default_mcu || avr_mcu->mach == mcu_types[i].mach) - avr_mcu = &mcu_types[i]; + { + specified_mcu.name = mcu_types[i].name; + specified_mcu.isa |= mcu_types[i].isa; + specified_mcu.mach = mcu_types[i].mach; + avr_mcu = &specified_mcu; + } else as_fatal (_("redefinition of mcu type `%s' to `%s'"), avr_mcu->name, mcu_types[i].name); @@ -481,6 +596,12 @@ md_parse_option (int c, char *arg) case OPTION_NO_WRAP: avr_opt.no_wrap = 1; return 1; + case OPTION_ISA_RMW: + specified_mcu.isa |= AVR_ISA_RMW; + return 1; + case OPTION_LINK_RELAX: + avr_opt.link_relax = 1; + return 1; } return 0; @@ -531,6 +652,7 @@ md_begin (void) } bfd_set_arch_mach (stdoutput, TARGET_ARCH, avr_mcu->mach); + linkrelax = avr_opt.link_relax; } /* Resolve STR as a constant expression and return the result. @@ -740,29 +862,41 @@ avr_operand (struct avr_opcodes_s *opcode, case 'a': case 'v': if (*str == 'r' || *str == 'R') - { - char r_name[20]; - - str = extract_word (str, r_name, sizeof (r_name)); - op_mask = 0xff; - if (ISDIGIT (r_name[1])) - { - if (r_name[2] == '\0') - op_mask = r_name[1] - '0'; - else if (r_name[1] != '0' - && ISDIGIT (r_name[2]) - && r_name[3] == '\0') - op_mask = (r_name[1] - '0') * 10 + r_name[2] - '0'; - } - } + { + char r_name[20]; + + str = extract_word (str, r_name, sizeof (r_name)); + op_mask = 0xff; + if (ISDIGIT (r_name[1])) + { + if (r_name[2] == '\0') + op_mask = r_name[1] - '0'; + else if (r_name[1] != '0' + && ISDIGIT (r_name[2]) + && r_name[3] == '\0') + op_mask = (r_name[1] - '0') * 10 + r_name[2] - '0'; + } + } else - { - op_mask = avr_get_constant (str, 31); - str = input_line_pointer; - } + { + op_mask = avr_get_constant (str, 31); + str = input_line_pointer; + } + + if (avr_mcu->mach == bfd_mach_avrtiny) + { + if (op_mask < 16 || op_mask > 31) + { + as_bad (_("register name or number from 16 to 31 required")); + break; + } + } + else if (op_mask > 31) + { + as_bad (_("register name or number from 0 to 31 required")); + break; + } - if (op_mask <= 31) - { switch (*op) { case 'a': @@ -790,9 +924,6 @@ avr_operand (struct avr_opcodes_s *opcode, break; } break; - } - as_bad (_("register name or number from 0 to 31 required")); - break; case 'e': { @@ -840,7 +971,12 @@ avr_operand (struct avr_opcodes_s *opcode, if (*str == '+') { ++str; - op_mask |= 1; + char *s; + for (s = opcode->opcode; *s; ++s) + { + if (*s == '+') + op_mask |= (1 << (15 - (s - opcode->opcode))); + } } /* attiny26 can do "lpm" and "lpm r,Z" but not "lpm r,Z+". */ @@ -894,6 +1030,12 @@ avr_operand (struct avr_opcodes_s *opcode, &op_expr, FALSE, BFD_RELOC_16); break; + case 'j': + str = parse_exp (str, &op_expr); + fix_new_exp (frag_now, where, opcode->insn_size * 2, + &op_expr, FALSE, BFD_RELOC_AVR_LDS_STS_16); + break; + case 'M': { bfd_reloc_code_real_type r_type; @@ -957,6 +1099,16 @@ avr_operand (struct avr_opcodes_s *opcode, } break; + case 'E': + { + unsigned int x; + + x = avr_get_constant (str, 15); + str = input_line_pointer; + op_mask |= (x << 4); + } + break; + case '?': break; @@ -1079,6 +1231,53 @@ md_pcrel_from_section (fixS *fixp, segT sec) return fixp->fx_frag->fr_address + fixp->fx_where; } +static bfd_boolean +relaxable_section (asection *sec) +{ + return (sec->flags & SEC_DEBUGGING) == 0; +} + +/* Does whatever the xtensa port does. */ +int +avr_validate_fix_sub (fixS *fix) +{ + segT add_symbol_segment, sub_symbol_segment; + + /* The difference of two symbols should be resolved by the assembler when + linkrelax is not set. If the linker may relax the section containing + the symbols, then an Xtensa DIFF relocation must be generated so that + the linker knows to adjust the difference value. */ + if (!linkrelax || fix->fx_addsy == NULL) + return 0; + + /* Make sure both symbols are in the same segment, and that segment is + "normal" and relaxable. If the segment is not "normal", then the + fix is not valid. If the segment is not "relaxable", then the fix + should have been handled earlier. */ + add_symbol_segment = S_GET_SEGMENT (fix->fx_addsy); + if (! SEG_NORMAL (add_symbol_segment) || + ! relaxable_section (add_symbol_segment)) + return 0; + + sub_symbol_segment = S_GET_SEGMENT (fix->fx_subsy); + return (sub_symbol_segment == add_symbol_segment); +} + +/* TC_FORCE_RELOCATION hook */ + +/* If linkrelax is turned on, and the symbol to relocate + against is in a relaxable segment, don't compute the value - + generate a relocation instead. */ +int +avr_force_relocation (fixS *fix) +{ + if (linkrelax && fix->fx_addsy + && relaxable_section (S_GET_SEGMENT (fix->fx_addsy))) + return 1; + + return generic_force_reloc (fix); +} + /* GAS will call this for each fixup. It should store the correct value in the object file. */ @@ -1102,11 +1301,47 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg) fixP->fx_done = 1; } } - + else if (linkrelax && fixP->fx_subsy) + { + /* For a subtraction relocation expression, generate one + of the DIFF relocs, with the value being the difference. + Note that a sym1 - sym2 expression is adjusted into a + section_start_sym + sym4_offset_from_section_start - sym1 + expression. fixP->fx_addsy holds the section start symbol, + fixP->fx_offset holds sym2's offset, and fixP->fx_subsy + holds sym1. Calculate the current difference and write value, + but leave fx_offset as is - during relaxation, + fx_offset - value gives sym1's value */ + + switch (fixP->fx_r_type) + { + case BFD_RELOC_8: + fixP->fx_r_type = BFD_RELOC_AVR_DIFF8; + break; + case BFD_RELOC_16: + fixP->fx_r_type = BFD_RELOC_AVR_DIFF16; + break; + case BFD_RELOC_32: + fixP->fx_r_type = BFD_RELOC_AVR_DIFF32; + break; + default: + as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); + break; + } + + value = S_GET_VALUE (fixP->fx_addsy) + + fixP->fx_offset - S_GET_VALUE (fixP->fx_subsy); + + fixP->fx_subsy = NULL; + } /* We don't actually support subtracting a symbol. */ if (fixP->fx_subsy != (symbolS *) NULL) as_bad_where (fixP->fx_file, fixP->fx_line, _("expression too complex")); + /* For the DIFF relocs, write the value into the object file while still + keeping fx_done FALSE, as both the difference (recorded in the object file) + and the sym offset (part of fixP) are needed at link relax time */ + where = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where; switch (fixP->fx_r_type) { default: @@ -1116,6 +1351,16 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg) case BFD_RELOC_AVR_13_PCREL: case BFD_RELOC_32: case BFD_RELOC_16: + break; + case BFD_RELOC_AVR_DIFF8: + *where = value; + break; + case BFD_RELOC_AVR_DIFF16: + bfd_putl16 ((bfd_vma) value, where); + break; + case BFD_RELOC_AVR_DIFF32: + bfd_putl32 ((bfd_vma) value, where); + break; case BFD_RELOC_AVR_CALL: break; } @@ -1167,7 +1412,7 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg) break; case BFD_RELOC_32: - bfd_putl16 ((bfd_vma) value, where); + bfd_putl32 ((bfd_vma) value, where); break; case BFD_RELOC_16: @@ -1192,11 +1437,21 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg) bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (value), where); break; + case BFD_RELOC_AVR_LDS_STS_16: + if ((value < 0x40) || (value > 0xBF)) + as_warn_where (fixP->fx_file, fixP->fx_line, + _("operand out of range: 0x%lx"), + (unsigned long)value); + insn |= ((value & 0xF) | ((value & 0x30) << 5) | ((value & 0x40) << 2)); + bfd_putl16 ((bfd_vma) insn, where); + break; + case BFD_RELOC_AVR_6: if ((value > 63) || (value < 0)) as_bad_where (fixP->fx_file, fixP->fx_line, _("operand out of range: %ld"), value); - bfd_putl16 ((bfd_vma) insn | ((value & 7) | ((value & (3 << 3)) << 7) | ((value & (1 << 5)) << 8)), where); + bfd_putl16 ((bfd_vma) insn | ((value & 7) | ((value & (3 << 3)) << 7) + | ((value & (1 << 5)) << 8)), where); break; case BFD_RELOC_AVR_6_ADIW: @@ -1277,7 +1532,19 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg) } break; - default: + case BFD_RELOC_AVR_8_LO: + *where = 0xff & value; + break; + + case BFD_RELOC_AVR_8_HI: + *where = 0xff & (value >> 8); + break; + + case BFD_RELOC_AVR_8_HLO: + *where = 0xff & (value >> 16); + break; + + default: as_fatal (_("line %d: unknown relocation type: 0x%x"), fixP->fx_line, fixP->fx_r_type); break; @@ -1316,29 +1583,9 @@ tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, { arelent *reloc; - if (fixp->fx_addsy && fixp->fx_subsy) + if (fixp->fx_subsy != NULL) { - long value = 0; - - if ((S_GET_SEGMENT (fixp->fx_addsy) != S_GET_SEGMENT (fixp->fx_subsy)) - || S_GET_SEGMENT (fixp->fx_addsy) == undefined_section) - { - as_bad_where (fixp->fx_file, fixp->fx_line, - "Difference of symbols in different sections is not supported"); - return NULL; - } - - /* We are dealing with two symbols defined in the same section. - Let us fix-up them here. */ - value += S_GET_VALUE (fixp->fx_addsy); - value -= S_GET_VALUE (fixp->fx_subsy); - - /* When fx_addsy and fx_subsy both are zero, md_apply_fix - only takes it's second operands for the fixup value. */ - fixp->fx_addsy = NULL; - fixp->fx_subsy = NULL; - md_apply_fix (fixp, (valueT *) &value, NULL); - + as_bad_where (fixp->fx_file, fixp->fx_line, _("expression too complex")); return NULL; } @@ -1379,6 +1626,28 @@ md_assemble (char *str) opcode = (struct avr_opcodes_s *) hash_find (avr_hash, op); + if (opcode && !avr_opt.all_opcodes) + { + /* Check if the instruction's ISA bit is ON in the ISA bits of the part + specified by the user. If not look for other instructions + specifications with same mnemonic who's ISA bits matches. + + This requires include/opcode/avr.h to have the instructions with + same mnenomic to be specified in sequence. */ + + while ((opcode->isa & avr_mcu->isa) != opcode->isa) + { + opcode++; + + if (opcode->name && strcmp(op, opcode->name)) + { + as_bad (_("illegal opcode %s for mcu %s"), + opcode->name, avr_mcu->name); + return; + } + } + } + if (opcode == NULL) { as_bad (_("unknown opcode `%s'"), op); @@ -1391,9 +1660,6 @@ md_assemble (char *str) if (*str && *opcode->constraints == '?') ++opcode; - if (!avr_opt.all_opcodes && (opcode->isa & avr_mcu->isa) != opcode->isa) - as_bad (_("illegal opcode %s for mcu %s"), opcode->name, avr_mcu->name); - dwarf2_emit_insn (0); /* We used to set input_line_pointer to the result of get_operands, @@ -1408,68 +1674,90 @@ md_assemble (char *str) } } -/* Flag to pass `pm' mode between `avr_parse_cons_expression' and - `avr_cons_fix_new'. */ -static int exp_mod_pm = 0; +const exp_mod_data_t exp_mod_data[] = +{ + /* Default, must be first. */ + { "", 0, BFD_RELOC_16, "" }, + /* Divides by 2 to get word address. Generate Stub. */ + { "gs", 2, BFD_RELOC_AVR_16_PM, "`gs' " }, + { "pm", 2, BFD_RELOC_AVR_16_PM, "`pm' " }, + /* The following are used together with avr-gcc's __memx address space + in order to initialize a 24-bit pointer variable with a 24-bit address. + For address in flash, hlo8 will contain the flash segment if the + symbol is located in flash. If the symbol is located in RAM; hlo8 + will contain 0x80 which matches avr-gcc's notion of how 24-bit RAM/flash + addresses linearize address space. */ + { "lo8", 1, BFD_RELOC_AVR_8_LO, "`lo8' " }, + { "hi8", 1, BFD_RELOC_AVR_8_HI, "`hi8' " }, + { "hlo8", 1, BFD_RELOC_AVR_8_HLO, "`hlo8' " }, + { "hh8", 1, BFD_RELOC_AVR_8_HLO, "`hh8' " }, + /* End of list. */ + { NULL, 0, 0, NULL } +}; -/* Parse special CONS expression: pm (expression) - or alternatively: gs (expression). - These are used for addressing program memory. - Relocation: BFD_RELOC_AVR_16_PM. */ +/* Parse special CONS expression: pm (expression) or alternatively + gs (expression). These are used for addressing program memory. Moreover, + define lo8 (expression), hi8 (expression) and hlo8 (expression). */ -void +const exp_mod_data_t * avr_parse_cons_expression (expressionS *exp, int nbytes) { + const exp_mod_data_t *pexp = &exp_mod_data[0]; char *tmp; - exp_mod_pm = 0; - tmp = input_line_pointer = skip_space (input_line_pointer); - if (nbytes == 2) + /* The first entry of exp_mod_data[] contains an entry if no + expression modifier is present. Skip it. */ + + for (pexp++; pexp->name; pexp++) { - char *pm_name1 = "pm"; - char *pm_name2 = "gs"; - int len = strlen (pm_name1); - /* len must be the same for both pm identifiers. */ + int len = strlen (pexp->name); - if (strncasecmp (input_line_pointer, pm_name1, len) == 0 - || strncasecmp (input_line_pointer, pm_name2, len) == 0) + if (nbytes == pexp->nbytes + && strncasecmp (input_line_pointer, pexp->name, len) == 0) { input_line_pointer = skip_space (input_line_pointer + len); if (*input_line_pointer == '(') { input_line_pointer = skip_space (input_line_pointer + 1); - exp_mod_pm = 1; expression (exp); if (*input_line_pointer == ')') - ++input_line_pointer; + { + ++input_line_pointer; + return pexp; + } else { as_bad (_("`)' required")); - exp_mod_pm = 0; + return &exp_mod_data[0]; } - - return; } input_line_pointer = tmp; + + break; } } expression (exp); + return &exp_mod_data[0]; } void avr_cons_fix_new (fragS *frag, int where, int nbytes, - expressionS *exp) + expressionS *exp, + const exp_mod_data_t *pexp_mod_data) { - if (exp_mod_pm == 0) + int bad = 0; + + switch (pexp_mod_data->reloc) { + default: if (nbytes == 1) fix_new_exp (frag, where, nbytes, exp, FALSE, BFD_RELOC_8); else if (nbytes == 2) @@ -1477,14 +1765,67 @@ avr_cons_fix_new (fragS *frag, else if (nbytes == 4) fix_new_exp (frag, where, nbytes, exp, FALSE, BFD_RELOC_32); else - as_bad (_("illegal %srelocation size: %d"), "", nbytes); - } - else - { - if (nbytes == 2) - fix_new_exp (frag, where, nbytes, exp, FALSE, BFD_RELOC_AVR_16_PM); + bad = 1; + break; + + case BFD_RELOC_AVR_16_PM: + case BFD_RELOC_AVR_8_LO: + case BFD_RELOC_AVR_8_HI: + case BFD_RELOC_AVR_8_HLO: + if (nbytes == pexp_mod_data->nbytes) + fix_new_exp (frag, where, nbytes, exp, FALSE, pexp_mod_data->reloc); else - as_bad (_("illegal %srelocation size: %d"), "`pm' ", nbytes); - exp_mod_pm = 0; + bad = 1; + break; } + + if (bad) + as_bad (_("illegal %srelocation size: %d"), pexp_mod_data->error, nbytes); +} + +static bfd_boolean +mcu_has_3_byte_pc (void) +{ + int mach = avr_mcu->mach; + + return mach == bfd_mach_avr6 + || mach == bfd_mach_avrxmega6 + || mach == bfd_mach_avrxmega7; +} + +void +tc_cfi_frame_initial_instructions (void) +{ + /* AVR6 pushes 3 bytes for calls. */ + int return_size = (mcu_has_3_byte_pc () ? 3 : 2); + + /* The CFA is the caller's stack location before the call insn. */ + /* Note that the stack pointer is dwarf register number 32. */ + cfi_add_CFA_def_cfa (32, return_size); + + /* Note that AVR consistently uses post-decrement, which means that things + do not line up the same way as for targers that use pre-decrement. */ + cfi_add_CFA_offset (DWARF2_DEFAULT_RETURN_COLUMN, 1-return_size); +} + +bfd_boolean +avr_allow_local_subtract (expressionS * left, + expressionS * right, + segT section) +{ + /* If we are not in relaxation mode, subtraction is OK. */ + if (!linkrelax) + return TRUE; + + /* If the symbols are not in a code section then they are OK. */ + if ((section->flags & SEC_CODE) == 0) + return TRUE; + + if (left->X_add_symbol == right->X_add_symbol) + return TRUE; + + /* We have to assume that there may be instructions between the + two symbols and that relaxation may increase the distance between + them. */ + return FALSE; }