X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gas%2Fconfig%2Ftc-avr.c;h=67d72d97c0fb21fa98000ff1958c99cacf42d5ec;hb=87975d2a60adf249212c1c031abb4dd0dbb800ac;hp=98a69a2063b9f9fcb0064db6b321f1d5eb126d37;hpb=df13624506adcef32e6bea7d4f7785b9c8e1cf0b;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/config/tc-avr.c b/gas/config/tc-avr.c index 98a69a2063..67d72d97c0 100644 --- a/gas/config/tc-avr.c +++ b/gas/config/tc-avr.c @@ -1,13 +1,14 @@ /* tc-avr.c -- Assembler code for the ATMEL AVR - Copyright (C) 1999, 2000 Free Software Foundation, Inc. + Copyright 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009, + 2010 Free Software Foundation, Inc. Contributed by Denis Chertykov This file is part of GAS, the GNU Assembler. GAS 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 2, or (at your option) + the Free Software Foundation; either version 3, or (at your option) any later version. GAS is distributed in the hope that it will be useful, @@ -17,41 +18,35 @@ You should have received a copy of the GNU General Public License along with GAS; see the file COPYING. If not, write to - the Free Software Foundation, 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + the Free Software Foundation, 51 Franklin Street - Fifth Floor, + Boston, MA 02110-1301, USA. */ -#include -#include #include "as.h" +#include "safe-ctype.h" #include "subsegs.h" +struct avr_opcodes_s +{ + char * name; + char * constraints; + 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}, + +struct avr_opcodes_s avr_opcodes[] = +{ + #include "opcode/avr.h" + {NULL, NULL, 0, 0, 0} +}; + const char comment_chars[] = ";"; const char line_comment_chars[] = "#"; const char line_separator_chars[] = "$"; -#define AVR_ISA_1200 0x0001 /* in the beginning there was ... */ -#define AVR_ISA_LPM 0x0002 /* device has LPM */ -#define AVR_ISA_LPMX 0x0004 /* device has LPM Rd,Z[+] */ -#define AVR_ISA_SRAM 0x0008 /* device has SRAM (LD, ST, PUSH, POP, ...) */ -#define AVR_ISA_WRAP 0x0010 /* device has exactly 8K program memory */ -#define AVR_ISA_MEGA 0x0020 /* device has >8K program memory (JMP, CALL) */ -#define AVR_ISA_MUL 0x0040 /* device has new core (MUL, MOVW, ...) */ -#define AVR_ISA_ELPM 0x0080 /* device has >64K program memory (ELPM) */ -#define AVR_ISA_ELPMX 0x0100 /* device has ELPM Rd,Z[+] (none yet) */ -#define AVR_ISA_SPM 0x0200 /* device can program itself (<=64K) */ -#define AVR_ISA_ESPM 0x0400 /* device can program itself (>64K, none yet) */ -#define AVR_ISA_EIND 0x0800 /* device has >128K program memory (none yet) */ - -#define AVR_ISA_TINY1 (AVR_ISA_1200 | AVR_ISA_LPM) -#define AVR_ISA_2xxx (AVR_ISA_TINY1 | AVR_ISA_SRAM) -#define AVR_ISA_85xx (AVR_ISA_2xxx | AVR_ISA_WRAP) -#define AVR_ISA_M603 (AVR_ISA_2xxx | AVR_ISA_MEGA) -#define AVR_ISA_M103 (AVR_ISA_M603 | AVR_ISA_ELPM) -#define AVR_ISA_M161 (AVR_ISA_M603 | AVR_ISA_MUL | AVR_ISA_LPMX | AVR_ISA_SPM) -#define AVR_ISA_94K (AVR_ISA_M603 | AVR_ISA_MUL | AVR_ISA_LPMX) - -#define AVR_ISA_ALL 0xFFFF - const char *md_shortopts = "m:"; struct mcu_type_s { @@ -60,46 +55,209 @@ struct mcu_type_s int mach; }; +/* XXX - devices that don't seem to exist (renamed, replaced with larger + ones, or planned but never produced), left here for compatibility. */ + static struct mcu_type_s mcu_types[] = { - {"avr1", AVR_ISA_TINY1, bfd_mach_avr1}, - {"avr2", AVR_ISA_85xx, bfd_mach_avr2}, - {"avr3", AVR_ISA_M103, bfd_mach_avr3}, - {"avr4", AVR_ISA_ALL, bfd_mach_avr4}, - {"at90s1200", AVR_ISA_1200, bfd_mach_avr1}, - {"attiny10", AVR_ISA_TINY1, bfd_mach_avr1}, - {"attiny11", AVR_ISA_TINY1, bfd_mach_avr1}, - {"attiny12", AVR_ISA_TINY1, bfd_mach_avr1}, - {"attiny15", AVR_ISA_TINY1, bfd_mach_avr1}, - {"attiny28", AVR_ISA_TINY1, bfd_mach_avr1}, - {"at90s2313", AVR_ISA_2xxx, bfd_mach_avr2}, - {"at90s2323", AVR_ISA_2xxx, bfd_mach_avr2}, - {"at90s2333", AVR_ISA_2xxx, bfd_mach_avr2}, - {"attiny22" , AVR_ISA_2xxx, bfd_mach_avr2}, - {"at90s2343", AVR_ISA_2xxx, bfd_mach_avr2}, - {"at90s4433", AVR_ISA_2xxx, bfd_mach_avr2}, - {"at90s4414", AVR_ISA_2xxx, bfd_mach_avr2}, - {"at90s4434", AVR_ISA_2xxx, bfd_mach_avr2}, - {"at90s8515", AVR_ISA_85xx, bfd_mach_avr2}, - {"at90s8535", AVR_ISA_85xx, bfd_mach_avr2}, - {"at90c8534", AVR_ISA_85xx, bfd_mach_avr2}, - {"atmega603", AVR_ISA_M603, bfd_mach_avr3}, - {"atmega103", AVR_ISA_M103, bfd_mach_avr3}, - {"atmega161", AVR_ISA_M161, bfd_mach_avr4}, - {"at94k10", AVR_ISA_94K, bfd_mach_avr4}, - {"at94k20", AVR_ISA_94K, bfd_mach_avr4}, - {"at94k40", AVR_ISA_94K, bfd_mach_avr4}, + {"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. */ + {"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 + 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 + 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}, + {"at90s1200", AVR_ISA_1200, bfd_mach_avr1}, + {"attiny11", AVR_ISA_AVR1, bfd_mach_avr1}, + {"attiny12", AVR_ISA_AVR1, bfd_mach_avr1}, + {"attiny15", AVR_ISA_AVR1, bfd_mach_avr1}, + {"attiny28", AVR_ISA_AVR1, bfd_mach_avr1}, + {"at90s2313", AVR_ISA_AVR2, bfd_mach_avr2}, + {"at90s2323", AVR_ISA_AVR2, bfd_mach_avr2}, + {"at90s2333", AVR_ISA_AVR2, bfd_mach_avr2}, /* XXX -> 4433 */ + {"at90s2343", AVR_ISA_AVR2, bfd_mach_avr2}, + {"attiny22", AVR_ISA_AVR2, bfd_mach_avr2}, /* XXX -> 2343 */ + {"attiny26", AVR_ISA_2xxe, bfd_mach_avr2}, + {"at90s4414", AVR_ISA_AVR2, bfd_mach_avr2}, /* XXX -> 8515 */ + {"at90s4433", AVR_ISA_AVR2, bfd_mach_avr2}, + {"at90s4434", AVR_ISA_AVR2, bfd_mach_avr2}, /* XXX -> 8535 */ + {"at90s8515", AVR_ISA_AVR2, bfd_mach_avr2}, + {"at90c8534", AVR_ISA_AVR2, bfd_mach_avr2}, + {"at90s8535", AVR_ISA_AVR2, bfd_mach_avr2}, + {"attiny13", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny13a", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny2313", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny2313a",AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny24", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny24a", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny4313", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny44", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny44a", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny84", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny84a", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny25", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny45", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny85", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny261", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny261a", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny461", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny461a", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny861", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny861a", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny87", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny43u", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny48", AVR_ISA_AVR25, bfd_mach_avr25}, + {"attiny88", 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}, + {"at43usb320", AVR_ISA_AVR31, bfd_mach_avr31}, + {"attiny167", AVR_ISA_AVR35, bfd_mach_avr35}, + {"at90usb82", AVR_ISA_AVR35, bfd_mach_avr35}, + {"at90usb162", 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}, + {"atmega8", AVR_ISA_M8, bfd_mach_avr4}, + {"atmega48", AVR_ISA_AVR4, bfd_mach_avr4}, + {"atmega48a", 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}, + {"atmega88p", AVR_ISA_AVR4, bfd_mach_avr4}, + {"atmega88pa", AVR_ISA_AVR4, bfd_mach_avr4}, + {"atmega8515", AVR_ISA_M8, bfd_mach_avr4}, + {"atmega8535", AVR_ISA_M8, bfd_mach_avr4}, + {"atmega8hva", AVR_ISA_AVR4, bfd_mach_avr4}, + {"at90pwm1", AVR_ISA_AVR4, bfd_mach_avr4}, + {"at90pwm2", AVR_ISA_AVR4, bfd_mach_avr4}, + {"at90pwm2b", AVR_ISA_AVR4, bfd_mach_avr4}, + {"at90pwm3", AVR_ISA_AVR4, bfd_mach_avr4}, + {"at90pwm3b", AVR_ISA_AVR4, bfd_mach_avr4}, + {"at90pwm81", AVR_ISA_AVR4, bfd_mach_avr4}, + {"atmega16", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega16a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega161", AVR_ISA_M161, bfd_mach_avr5}, + {"atmega162", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega163", AVR_ISA_M161, bfd_mach_avr5}, + {"atmega164a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega164p", 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}, + {"atmega168", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega168a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega168p", 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}, + {"atmega323", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega324a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega324p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega324pa",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega325", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega325a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega325p", 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}, + {"atmega328", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega328p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega329", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega329a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega329p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega329pa",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega3290", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega3290a",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega3290p",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega406", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega64", 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}, + {"atmega644p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega644pa",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega645", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega645a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega645p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega649", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega649a", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega649p", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega6450", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega6450a",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega6450p",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega6490", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega6490a",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega6490p",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega16hva",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega16hva2",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega16hvb",AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega32hvb",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}, + {"at90pwm216", AVR_ISA_AVR5, bfd_mach_avr5}, + {"at90pwm316", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega32c1", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega64c1", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega16m1", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega32m1", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega64m1", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega16u4", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega32u4", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega32u6", AVR_ISA_AVR5, bfd_mach_avr5}, + {"at90usb646", AVR_ISA_AVR5, bfd_mach_avr5}, + {"at90usb647", AVR_ISA_AVR5, bfd_mach_avr5}, + {"at90scr100", AVR_ISA_AVR5, bfd_mach_avr5}, + {"at94k", AVR_ISA_94K, bfd_mach_avr5}, + {"m3000", AVR_ISA_AVR5, bfd_mach_avr5}, + {"atmega128", AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega1280", AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega1281", AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega1284p",AVR_ISA_AVR51, bfd_mach_avr51}, + {"atmega128rfa1",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}, {NULL, 0, 0} }; - /* Current MCU type. */ -static struct mcu_type_s default_mcu = {"avr2", AVR_ISA_2xxx,bfd_mach_avr2}; -static struct mcu_type_s *avr_mcu = &default_mcu; +static struct mcu_type_s default_mcu = {"avr2", AVR_ISA_AVR2, bfd_mach_avr2}; +static struct mcu_type_s * avr_mcu = & default_mcu; + +/* AVR target-specific switches. */ +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. */ +}; + +static struct avr_opt_s avr_opt = { 0, 0, 0 }; const char EXP_CHARS[] = "eE"; const char FLT_CHARS[] = "dD"; -static void avr_set_arch (int dummy); + +static void avr_set_arch (int); /* The target specific pseudo-ops which we support. */ const pseudo_typeS md_pseudo_table[] = @@ -109,238 +267,95 @@ const pseudo_typeS md_pseudo_table[] = }; #define LDI_IMMEDIATE(x) (((x) & 0xf) | (((x) << 4) & 0xf00)) -#define REGISTER_P(x) ((x) == 'r' \ - || (x) == 'd' \ - || (x) == 'w' \ - || (x) == 'a' \ - || (x) == 'v') -struct avr_opcodes_s -{ - char *name; - char *constraints; - char *opcode; - int insn_size; /* in words */ - int isa; - unsigned int bin_opcode; -}; - -static char * skip_space (char * s); -static char * extract_word (char *from, char *to, int limit); -static unsigned int avr_operand (struct avr_opcodes_s *opcode, - int where, char *op, char **line); -static unsigned int avr_operands (struct avr_opcodes_s *opcode, char **line); -static unsigned int avr_get_constant (char * str, int max); -static char *parse_exp (char *s, expressionS * op); -static bfd_reloc_code_real_type avr_ldi_expression (expressionS *exp); -long md_pcrel_from_section PARAMS ((fixS *, segT)); - - -/* constraint letters - r - any register - d - `ldi' register (r16-r31) - v - `movw' even register (r0, r2, ..., r28, r30) - a - `fmul' register (r16-r23) - w - `adiw' register (r24,r26,r28,r30) - e - pointer registers (X,Y,Z) - b - base pointer register and displacement ([YZ]+disp) - z - Z pointer register (for [e]lpm Rd,Z[+]) - M - immediate value from 0 to 255 - n - immediate value from 0 to 255 ( n = ~M ). Relocation impossible - s - immediate value from 0 to 7 - P - Port address value from 0 to 64. (in, out) - p - Port address value from 0 to 32. (cbi, sbi, sbic, sbis) - K - immediate value from 0 to 64 (used in `adiw', `sbiw') - i - immediate value - l - signed pc relative offset from -64 to 63 - L - signed pc relative offset from -2048 to 2047 - h - absolut code address (call, jmp) - S - immediate value from 0 to 7 (S = s << 4) -*/ - -struct avr_opcodes_s avr_opcodes[] = -{ - {"adc", "r,r", "000111rdddddrrrr", 1, AVR_ISA_1200, 0x1c00}, - {"add", "r,r", "000011rdddddrrrr", 1, AVR_ISA_1200, 0x0c00}, - {"and", "r,r", "001000rdddddrrrr", 1, AVR_ISA_1200, 0x2000}, - {"cp", "r,r", "000101rdddddrrrr", 1, AVR_ISA_1200, 0x1400}, - {"cpc", "r,r", "000001rdddddrrrr", 1, AVR_ISA_1200, 0x0400}, - {"cpse", "r,r", "000100rdddddrrrr", 1, AVR_ISA_1200, 0x1000}, - {"eor", "r,r", "001001rdddddrrrr", 1, AVR_ISA_1200, 0x2400}, - {"mov", "r,r", "001011rdddddrrrr", 1, AVR_ISA_1200, 0x2c00}, - {"mul", "r,r", "100111rdddddrrrr", 1, AVR_ISA_MUL, 0x9c00}, - {"or", "r,r", "001010rdddddrrrr", 1, AVR_ISA_1200, 0x2800}, - {"sbc", "r,r", "000010rdddddrrrr", 1, AVR_ISA_1200, 0x0800}, - {"sub", "r,r", "000110rdddddrrrr", 1, AVR_ISA_1200, 0x1800}, - - {"clr", "r=r", "001001rdddddrrrr", 1, AVR_ISA_1200, 0x2400}, - {"lsl", "r=r", "000011rdddddrrrr", 1, AVR_ISA_1200, 0x0c00}, - {"rol", "r=r", "000111rdddddrrrr", 1, AVR_ISA_1200, 0x1c00}, - {"tst", "r=r", "001000rdddddrrrr", 1, AVR_ISA_1200, 0x2000}, - - {"andi", "d,M", "0111KKKKddddKKKK", 1, AVR_ISA_1200, 0x7000}, - /*XXX special case*/ - {"cbr", "d,n", "0111KKKKddddKKKK", 1, AVR_ISA_1200, 0x7000}, - {"cpi", "d,M", "0011KKKKddddKKKK", 1, AVR_ISA_1200, 0x3000}, - {"ldi", "d,M", "1110KKKKddddKKKK", 1, AVR_ISA_1200, 0xe000}, - {"ori", "d,M", "0110KKKKddddKKKK", 1, AVR_ISA_1200, 0x6000}, - {"sbci", "d,M", "0100KKKKddddKKKK", 1, AVR_ISA_1200, 0x4000}, - {"sbr", "d,M", "0110KKKKddddKKKK", 1, AVR_ISA_1200, 0x6000}, - {"subi", "d,M", "0101KKKKddddKKKK", 1, AVR_ISA_1200, 0x5000}, - - {"sbrc", "r,s", "1111110rrrrr0sss", 1, AVR_ISA_1200, 0xfc00}, - {"sbrs", "r,s", "1111111rrrrr0sss", 1, AVR_ISA_1200, 0xfe00}, - {"bld", "r,s", "1111100ddddd0sss", 1, AVR_ISA_1200, 0xf800}, - {"bst", "r,s", "1111101ddddd0sss", 1, AVR_ISA_1200, 0xfa00}, - - {"in", "r,P", "10110PPdddddPPPP", 1, AVR_ISA_1200, 0xb000}, - {"out", "P,r", "10111PPrrrrrPPPP", 1, AVR_ISA_1200, 0xb800}, - - {"adiw", "w,K", "10010110KKddKKKK", 1, AVR_ISA_2xxx, 0x9600}, - {"sbiw", "w,K", "10010111KKddKKKK", 1, AVR_ISA_2xxx, 0x9700}, - - {"cbi", "p,s", "10011000pppppsss", 1, AVR_ISA_1200, 0x9800}, - {"sbi", "p,s", "10011010pppppsss", 1, AVR_ISA_1200, 0x9a00}, - {"sbic", "p,s", "10011001pppppsss", 1, AVR_ISA_1200, 0x9900}, - {"sbis", "p,s", "10011011pppppsss", 1, AVR_ISA_1200, 0x9b00}, - - /* ee = {X=11,Y=10,Z=00, 0} */ - {"ld", "r,e", "100!000dddddee-+", 1, AVR_ISA_2xxx, 0x8000}, - {"st", "e,r", "100!001rrrrree-+", 1, AVR_ISA_2xxx, 0x8200}, - {"ldd", "r,b", "10o0oo0dddddbooo", 1, AVR_ISA_2xxx, 0x8000}, - {"std", "b,r", "10o0oo1rrrrrbooo", 1, AVR_ISA_2xxx, 0x8200}, - {"sts", "i,r", "1001001ddddd0000", 2, AVR_ISA_2xxx, 0x9200}, - {"lds", "r,i", "1001000ddddd0000", 2, AVR_ISA_2xxx, 0x9000}, - - {"brbc", "s,l", "111101lllllllsss", 1, AVR_ISA_1200, 0xf400}, - {"brbs", "s,l", "111100lllllllsss", 1, AVR_ISA_1200, 0xf000}, - - {"brcc", "l", "111101lllllll000", 1, AVR_ISA_1200, 0xf400}, - {"brcs", "l", "111100lllllll000", 1, AVR_ISA_1200, 0xf000}, - {"breq", "l", "111100lllllll001", 1, AVR_ISA_1200, 0xf001}, - {"brge", "l", "111101lllllll100", 1, AVR_ISA_1200, 0xf404}, - {"brhc", "l", "111101lllllll101", 1, AVR_ISA_1200, 0xf405}, - {"brhs", "l", "111100lllllll101", 1, AVR_ISA_1200, 0xf005}, - {"brid", "l", "111101lllllll111", 1, AVR_ISA_1200, 0xf407}, - {"brie", "l", "111100lllllll111", 1, AVR_ISA_1200, 0xf007}, - {"brlo", "l", "111100lllllll000", 1, AVR_ISA_1200, 0xf000}, - {"brlt", "l", "111100lllllll100", 1, AVR_ISA_1200, 0xf004}, - {"brmi", "l", "111100lllllll010", 1, AVR_ISA_1200, 0xf002}, - {"brne", "l", "111101lllllll001", 1, AVR_ISA_1200, 0xf401}, - {"brpl", "l", "111101lllllll010", 1, AVR_ISA_1200, 0xf402}, - {"brsh", "l", "111101lllllll000", 1, AVR_ISA_1200, 0xf400}, - {"brtc", "l", "111101lllllll110", 1, AVR_ISA_1200, 0xf406}, - {"brts", "l", "111100lllllll110", 1, AVR_ISA_1200, 0xf006}, - {"brvc", "l", "111101lllllll011", 1, AVR_ISA_1200, 0xf403}, - {"brvs", "l", "111100lllllll011", 1, AVR_ISA_1200, 0xf003}, - - {"rcall", "L", "1101LLLLLLLLLLLL", 1, AVR_ISA_1200, 0xd000}, - {"rjmp", "L", "1100LLLLLLLLLLLL", 1, AVR_ISA_1200, 0xc000}, - - {"call", "h", "1001010hhhhh111h", 2, AVR_ISA_MEGA, 0x940e}, - {"jmp", "h", "1001010hhhhh110h", 2, AVR_ISA_MEGA, 0x940c}, - - {"asr", "r", "1001010rrrrr0101", 1, AVR_ISA_1200, 0x9405}, - {"com", "r", "1001010rrrrr0000", 1, AVR_ISA_1200, 0x9400}, - {"dec", "r", "1001010rrrrr1010", 1, AVR_ISA_1200, 0x940a}, - {"inc", "r", "1001010rrrrr0011", 1, AVR_ISA_1200, 0x9403}, - {"lsr", "r", "1001010rrrrr0110", 1, AVR_ISA_1200, 0x9406}, - {"neg", "r", "1001010rrrrr0001", 1, AVR_ISA_1200, 0x9401}, - {"pop", "r", "1001000rrrrr1111", 1, AVR_ISA_2xxx, 0x900f}, - {"push", "r", "1001001rrrrr1111", 1, AVR_ISA_2xxx, 0x920f}, - {"ror", "r", "1001010rrrrr0111", 1, AVR_ISA_1200, 0x9407}, - {"ser", "d", "11101111dddd1111", 1, AVR_ISA_1200, 0xef0f}, - {"swap", "r", "1001010rrrrr0010", 1, AVR_ISA_1200, 0x9402}, - - {"bclr", "S", "100101001SSS1000", 1, AVR_ISA_1200, 0x9488}, - {"bset", "S", "100101000SSS1000", 1, AVR_ISA_1200, 0x9408}, - - {"clc", "", "1001010010001000", 1, AVR_ISA_1200, 0x9488}, - {"clh", "", "1001010011011000", 1, AVR_ISA_1200, 0x94d8}, - {"cli", "", "1001010011111000", 1, AVR_ISA_1200, 0x94f8}, - {"cln", "", "1001010010101000", 1, AVR_ISA_1200, 0x94a8}, - {"cls", "", "1001010011001000", 1, AVR_ISA_1200, 0x94c8}, - {"clt", "", "1001010011101000", 1, AVR_ISA_1200, 0x94e8}, - {"clv", "", "1001010010111000", 1, AVR_ISA_1200, 0x94b8}, - {"clz", "", "1001010010011000", 1, AVR_ISA_1200, 0x9498}, - {"icall","", "1001010100001001", 1, AVR_ISA_2xxx, 0x9509}, - {"ijmp", "", "1001010000001001", 1, AVR_ISA_2xxx, 0x9409}, - {"lpm", "", "1001010111001000", 1, AVR_ISA_TINY1,0x95c8}, - {"nop", "", "0000000000000000", 1, AVR_ISA_1200, 0x0000}, - {"ret", "", "1001010100001000", 1, AVR_ISA_1200, 0x9508}, - {"reti", "", "1001010100011000", 1, AVR_ISA_1200, 0x9518}, - {"sec", "", "1001010000001000", 1, AVR_ISA_1200, 0x9408}, - {"seh", "", "1001010001011000", 1, AVR_ISA_1200, 0x9458}, - {"sei", "", "1001010001111000", 1, AVR_ISA_1200, 0x9478}, - {"sen", "", "1001010000101000", 1, AVR_ISA_1200, 0x9428}, - {"ses", "", "1001010001001000", 1, AVR_ISA_1200, 0x9448}, - {"set", "", "1001010001101000", 1, AVR_ISA_1200, 0x9468}, - {"sev", "", "1001010000111000", 1, AVR_ISA_1200, 0x9438}, - {"sez", "", "1001010000011000", 1, AVR_ISA_1200, 0x9418}, - {"sleep","", "1001010110001000", 1, AVR_ISA_1200, 0x9588}, - {"wdr", "", "1001010110101000", 1, AVR_ISA_1200, 0x95a8}, - {"elpm", "", "1001010111011000", 1, AVR_ISA_ELPM, 0x95d8}, - {"spm", "", "1001010111101000", 1, AVR_ISA_SPM, 0x95e8}, - {"movw", "v,v", "00000001ddddrrrr", 1, AVR_ISA_MUL, 0x0100}, - {"muls", "d,d", "00000010ddddrrrr", 1, AVR_ISA_MUL, 0x0200}, - {"mulsu","a,a", "000000110ddd0rrr", 1, AVR_ISA_MUL, 0x0300}, - {"fmul", "a,a", "000000110ddd1rrr", 1, AVR_ISA_MUL, 0x0308}, - {"fmuls","a,a", "000000111ddd0rrr", 1, AVR_ISA_MUL, 0x0380}, - {"fmulsu","a,a","000000111ddd1rrr", 1, AVR_ISA_MUL, 0x0388}, - {"lpmx", "r,z", "1001000ddddd010+", 1, AVR_ISA_LPMX, 0x9004}, - /* these are for devices that don't exists yet */ - /* >64K program memory, new core */ - {"elpmx","r,z", "1001000ddddd011+", 1, AVR_ISA_ELPMX,0x9006}, - {"espm", "", "1001010111111000", 1, AVR_ISA_ESPM, 0x95f8}, - /* >128K program memory (PC = EIND:Z) */ - {"eicall", "", "1001010100011001", 1, AVR_ISA_EIND, 0x9519}, - {"eijmp", "", "1001010000011001", 1, AVR_ISA_EIND, 0x9419}, - {NULL, NULL, NULL, 0, 0, 0} -}; - - - -#define EXP_MOD_NAME(i) exp_mod[i].name -#define EXP_MOD_RELOC(i) exp_mod[i].reloc -#define EXP_MOD_NEG_RELOC(i) exp_mod[i].neg_reloc -#define HAVE_PM_P(i) exp_mod[i].have_pm +#define EXP_MOD_NAME(i) exp_mod[i].name +#define EXP_MOD_RELOC(i) exp_mod[i].reloc +#define EXP_MOD_NEG_RELOC(i) exp_mod[i].neg_reloc +#define HAVE_PM_P(i) exp_mod[i].have_pm struct exp_mod_s { - char * name; - bfd_reloc_code_real_type reloc; - bfd_reloc_code_real_type neg_reloc; - int have_pm; + char * name; + bfd_reloc_code_real_type reloc; + bfd_reloc_code_real_type neg_reloc; + int have_pm; }; -static struct exp_mod_s exp_mod[] = { +static struct exp_mod_s exp_mod[] = +{ {"hh8", BFD_RELOC_AVR_HH8_LDI, BFD_RELOC_AVR_HH8_LDI_NEG, 1}, {"pm_hh8", BFD_RELOC_AVR_HH8_LDI_PM, BFD_RELOC_AVR_HH8_LDI_PM_NEG, 0}, {"hi8", BFD_RELOC_AVR_HI8_LDI, BFD_RELOC_AVR_HI8_LDI_NEG, 1}, {"pm_hi8", BFD_RELOC_AVR_HI8_LDI_PM, BFD_RELOC_AVR_HI8_LDI_PM_NEG, 0}, {"lo8", BFD_RELOC_AVR_LO8_LDI, BFD_RELOC_AVR_LO8_LDI_NEG, 1}, {"pm_lo8", BFD_RELOC_AVR_LO8_LDI_PM, BFD_RELOC_AVR_LO8_LDI_PM_NEG, 0}, - {"hlo8", -BFD_RELOC_AVR_LO8_LDI, -BFD_RELOC_AVR_LO8_LDI_NEG, 0}, - {"hhi8", -BFD_RELOC_AVR_HI8_LDI, -BFD_RELOC_AVR_HI8_LDI_NEG, 0}, + {"hlo8", BFD_RELOC_AVR_HH8_LDI, BFD_RELOC_AVR_HH8_LDI_NEG, 0}, + {"hhi8", BFD_RELOC_AVR_MS8_LDI, BFD_RELOC_AVR_MS8_LDI_NEG, 0}, }; +/* A union used to store indicies into the exp_mod[] array + in a hash table which expects void * data types. */ +typedef union +{ + void * ptr; + int index; +} mod_index; + /* Opcode hash table. */ static struct hash_control *avr_hash; /* Reloc modifiers hash control (hh8,hi8,lo8,pm_xx). */ static struct hash_control *avr_mod_hash; -#define OPTION_MMCU (OPTION_MD_BASE + 1) +#define OPTION_MMCU 'm' +enum options +{ + OPTION_ALL_OPCODES = OPTION_MD_BASE + 1, + OPTION_NO_SKIP_BUG, + OPTION_NO_WRAP +}; -struct option md_longopts[] = { - {"mmcu", required_argument, NULL, 'm'}, - {NULL, no_argument, NULL, 0} +struct option md_longopts[] = +{ + { "mmcu", required_argument, NULL, OPTION_MMCU }, + { "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 }, + { NULL, no_argument, NULL, 0 } }; -size_t md_longopts_size = sizeof(md_longopts); + +size_t md_longopts_size = sizeof (md_longopts); + +/* Display nicely formatted list of known MCU names. */ + +static void +show_mcu_list (FILE *stream) +{ + int i, x; + + fprintf (stream, _("Known MCU names:")); + x = 1000; + + for (i = 0; mcu_types[i].name; i++) + { + int len = strlen (mcu_types[i].name); + + x += len + 1; + + if (x < 75) + fprintf (stream, " %s", mcu_types[i].name); + else + { + fprintf (stream, "\n %s", mcu_types[i].name); + x = len + 2; + } + } + + fprintf (stream, "\n"); +} static inline char * -skip_space (s) - char * s; +skip_space (char *s) { while (*s == ' ' || *s == '\t') ++s; @@ -348,296 +363,369 @@ skip_space (s) } /* Extract one word from FROM and copy it to TO. */ + static char * extract_word (char *from, char *to, int limit) { - char *op_start; char *op_end; int size = 0; /* Drop leading whitespace. */ from = skip_space (from); *to = 0; + /* Find the op code end. */ - for (op_start = op_end = from; *op_end != 0 && is_part_of_name(*op_end); ) + for (op_end = from; *op_end != 0 && is_part_of_name (*op_end);) { to[size++] = *op_end++; if (size + 1 >= limit) break; } + to[size] = 0; return op_end; } int -md_estimate_size_before_relax (fragp, seg) - fragS *fragp ATTRIBUTE_UNUSED; - asection *seg ATTRIBUTE_UNUSED; +md_estimate_size_before_relax (fragS *fragp ATTRIBUTE_UNUSED, + asection *seg ATTRIBUTE_UNUSED) { abort (); return 0; } void -md_show_usage (stream) - FILE *stream; +md_show_usage (FILE *stream) { - fprintf - (stream, - _ ("AVR options:\n" + fprintf (stream, + _("AVR options:\n" " -mmcu=[avr-name] select microcontroller variant\n" " [avr-name] can be:\n" - " avr1 - AT90S1200\n" - " avr2 - AT90S2xxx, AT90S4xxx, AT90S85xx, ATtiny22\n" - " avr3 - ATmega103 or ATmega603\n" - " avr4 - ATmega161\n" + " avr1 - classic AVR core without data RAM\n" + " avr2 - classic AVR core with up to 8K program memory\n" + " avr25 - classic AVR core with up to 8K program memory\n" + " plus the MOVW instruction\n" + " avr3 - classic AVR core with up to 64K program memory\n" + " avr31 - classic AVR core with up to 128K program memory\n" + " avr35 - classic AVR core with up to 64K program memory\n" + " plus the MOVW instruction\n" + " avr4 - enhanced AVR core with up to 8K program memory\n" + " 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")); + 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")); + show_mcu_list (stream); } static void -avr_set_arch (dummy) - int dummy ATTRIBUTE_UNUSED; +avr_set_arch (int dummy ATTRIBUTE_UNUSED) { - char * str; - str = (char *)alloca (20); + char str[20]; + input_line_pointer = extract_word (input_line_pointer, str, 20); - md_parse_option ('m', str); + md_parse_option (OPTION_MMCU, str); bfd_set_arch_mach (stdoutput, TARGET_ARCH, avr_mcu->mach); } int -md_parse_option (c, arg) - int c; - char *arg; +md_parse_option (int c, char *arg) { - char *t = alloca (strlen (arg) + 1); - char *s = t; - char *arg1 = arg; - do - *t = tolower (*arg1++); - while (*t++); - - if (c == 'm') + switch (c) { - int i; + case OPTION_MMCU: + { + int i; + char *s = alloca (strlen (arg) + 1); - for (i = 0; mcu_types[i].name; ++i) - if (strcmp (mcu_types[i].name, s) == 0) - break; + { + char *t = s; + char *arg1 = arg; - if (!mcu_types[i].name) - as_fatal (_ ("unknown MCU: %s\n"), arg); - if (avr_mcu == &default_mcu) - avr_mcu = &mcu_types[i]; - else - as_fatal (_ ("redefinition of mcu type `%s'"), mcu_types[i].name); + do + *t = TOLOWER (*arg1++); + while (*t++); + } + + for (i = 0; mcu_types[i].name; ++i) + if (strcmp (mcu_types[i].name, s) == 0) + break; + + if (!mcu_types[i].name) + { + show_mcu_list (stderr); + as_fatal (_("unknown MCU: %s\n"), arg); + } + + /* It is OK to redefine mcu type within the same avr[1-5] bfd machine + 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]; + else + as_fatal (_("redefinition of mcu type `%s' to `%s'"), + avr_mcu->name, mcu_types[i].name); + return 1; + } + case OPTION_ALL_OPCODES: + avr_opt.all_opcodes = 1; + return 1; + case OPTION_NO_SKIP_BUG: + avr_opt.no_skip_bug = 1; + return 1; + case OPTION_NO_WRAP: + avr_opt.no_wrap = 1; return 1; } + return 0; } symbolS * -md_undefined_symbol(name) - char *name ATTRIBUTE_UNUSED; +md_undefined_symbol (char *name ATTRIBUTE_UNUSED) { - return 0; + return NULL; } -/* Convert a string pointed to by input_line_pointer into a floating point - constant of type `type', and store the appropriate bytes to `*litP'. - The number of LITTLENUMS emitted is stored in `*sizeP'. Returns NULL if - OK, or an error message otherwise. */ char * -md_atof (type, litP, sizeP) - int type; - char *litP; - int *sizeP; +md_atof (int type, char *litP, int *sizeP) { - int prec; - LITTLENUM_TYPE words[4]; - LITTLENUM_TYPE *wordP; - char *t; - - switch (type) - { - case 'f': - prec = 2; - break; - case 'd': - prec = 4; - break; - default: - *sizeP = 0; - return _("bad call to md_atof"); - } - - t = atof_ieee (input_line_pointer, type, words); - if (t) - input_line_pointer = t; - - *sizeP = prec * sizeof (LITTLENUM_TYPE); - /* This loop outputs the LITTLENUMs in REVERSE order. */ - for (wordP = words + prec - 1; prec--;) - { - md_number_to_chars (litP, (valueT) (*wordP--), sizeof (LITTLENUM_TYPE)); - litP += sizeof (LITTLENUM_TYPE); - } - return NULL; + return ieee_md_atof (type, litP, sizeP, FALSE); } void -md_convert_frag (abfd, sec, fragP) - bfd *abfd ATTRIBUTE_UNUSED; - asection *sec ATTRIBUTE_UNUSED; - fragS *fragP ATTRIBUTE_UNUSED; +md_convert_frag (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec ATTRIBUTE_UNUSED, + fragS *fragP ATTRIBUTE_UNUSED) { abort (); } - void -md_begin () +md_begin (void) { unsigned int i; struct avr_opcodes_s *opcode; - avr_hash = hash_new(); + + avr_hash = hash_new (); /* Insert unique names into hash table. This hash table then provides a quick index to the first opcode with a particular name in the opcode table. */ - for (opcode = avr_opcodes; opcode->name; opcode++) hash_insert (avr_hash, opcode->name, (char *) opcode); avr_mod_hash = hash_new (); - for (i = 0; i < sizeof (exp_mod) / sizeof (exp_mod[0]); ++i) - hash_insert (avr_mod_hash, EXP_MOD_NAME(i), (void*)(i+10)); - + for (i = 0; i < ARRAY_SIZE (exp_mod); ++i) + { + mod_index m; + + m.index = i + 10; + hash_insert (avr_mod_hash, EXP_MOD_NAME (i), m.ptr); + } + bfd_set_arch_mach (stdoutput, TARGET_ARCH, avr_mcu->mach); } - /* Resolve STR as a constant expression and return the result. - If result greater than MAX then error. */ + If result greater than MAX then error. */ static unsigned int -avr_get_constant (str, max) - char * str; - int max; +avr_get_constant (char *str, int max) { expressionS ex; + str = skip_space (str); input_line_pointer = str; - expression (&ex); + expression (& ex); if (ex.X_op != O_constant) as_bad (_("constant value required")); if (ex.X_add_number > max || ex.X_add_number < 0) - as_bad (_("number must be less than %d"), max+1); + as_bad (_("number must be positive and less than %d"), max + 1); + return ex.X_add_number; } +/* Parse for ldd/std offset. */ -/* Parse instruction operands. - Returns binary opcode. */ +static void +avr_offset_expression (expressionS *exp) +{ + char *str = input_line_pointer; + char *tmp; + char op[8]; -static unsigned int -avr_operands (opcode, line) - struct avr_opcodes_s *opcode; - char **line; + tmp = str; + str = extract_word (str, op, sizeof (op)); + + input_line_pointer = tmp; + expression (exp); + + /* Warn about expressions that fail to use lo8 (). */ + if (exp->X_op == O_constant) + { + int x = exp->X_add_number; + + if (x < -255 || x > 255) + as_warn (_("constant out of 8-bit range: %d"), x); + } +} + +/* Parse ordinary expression. */ + +static char * +parse_exp (char *s, expressionS *op) { - char *op = opcode->constraints; - unsigned int bin = opcode->bin_opcode; - char *frag = frag_more (opcode->insn_size * 2); - char *str = *line; - int where = frag - frag_now->fr_literal; - static unsigned int prev = 0; /* previous opcode */ + input_line_pointer = s; + expression (op); + if (op->X_op == O_absent) + as_bad (_("missing operand")); + return input_line_pointer; +} - /* Opcode have operands. */ - if (*op) +/* Parse special expressions (needed for LDI command): + xx8 (address) + xx8 (-address) + pm_xx8 (address) + pm_xx8 (-address) + where xx is: hh, hi, lo. */ + +static bfd_reloc_code_real_type +avr_ldi_expression (expressionS *exp) +{ + char *str = input_line_pointer; + char *tmp; + char op[8]; + int mod; + int linker_stubs_should_be_generated = 0; + + tmp = str; + + str = extract_word (str, op, sizeof (op)); + + if (op[0]) { - unsigned int reg1 = 0; - unsigned int reg2 = 0; - int reg1_present = 0; - int reg2_present = 0; + mod_index m; - /* Parse first operand. */ - if (REGISTER_P (*op)) - reg1_present = 1; - reg1 = avr_operand (opcode, where, op, &str); - ++op; + m.ptr = hash_find (avr_mod_hash, op); + mod = m.index; - /* Parse second operand. */ - if (*op) + if (mod) { - if (*op == ',') - ++op; - if (*op == '=') - { - reg2 = reg1; - reg2_present = 1; - } - else + int closes = 0; + + mod -= 10; + str = skip_space (str); + + if (*str == '(') { - if (REGISTER_P (*op)) - reg2_present = 1; + bfd_reloc_code_real_type reloc_to_return; + int neg_p = 0; - str = skip_space (str); - if (*str++ != ',') - as_bad (_ ("`,' required")); - str = skip_space (str); + ++str; - reg2 = avr_operand (opcode, where, op, &str); + if (strncmp ("pm(", str, 3) == 0 + || strncmp ("gs(",str,3) == 0 + || strncmp ("-(gs(",str,5) == 0 + || strncmp ("-(pm(", str, 5) == 0) + { + if (HAVE_PM_P (mod)) + { + ++mod; + ++closes; + } + else + as_bad (_("illegal expression")); + if (str[0] == 'g' || str[2] == 'g') + linker_stubs_should_be_generated = 1; + + if (*str == '-') + { + neg_p = 1; + ++closes; + str += 5; + } + else + str += 3; + } + + if (*str == '-' && *(str + 1) == '(') + { + neg_p ^= 1; + ++closes; + str += 2; + } + + input_line_pointer = str; + expression (exp); + + do + { + if (*input_line_pointer != ')') + { + as_bad (_("`)' required")); + break; + } + input_line_pointer++; + } + while (closes--); + + reloc_to_return = + neg_p ? EXP_MOD_NEG_RELOC (mod) : EXP_MOD_RELOC (mod); + if (linker_stubs_should_be_generated) + { + switch (reloc_to_return) + { + case BFD_RELOC_AVR_LO8_LDI_PM: + reloc_to_return = BFD_RELOC_AVR_LO8_LDI_GS; + break; + case BFD_RELOC_AVR_HI8_LDI_PM: + reloc_to_return = BFD_RELOC_AVR_HI8_LDI_GS; + break; + + default: + /* PR 5523: Do not generate a warning here, + legitimate code can trigger this case. */ + break; + } + } + return reloc_to_return; } - if (reg1_present && reg2_present) - reg2 = (reg2 & 0xf) | ((reg2 << 5) & 0x200); - else if (reg2_present) - reg2 <<= 4; } - if (reg1_present) - reg1 <<= 4; - bin |= reg1 | reg2; } - /* detect undefined combinations (like lpm r31,Z+) */ - if (((bin & 0xFDEF) == 0x91AD) || ((bin & 0xFDEF) == 0x91AE) || - ((bin & 0xFDEF) == 0x91C9) || ((bin & 0xFDEF) == 0x91CA) || - ((bin & 0xFDEF) == 0x91E1) || ((bin & 0xFDEF) == 0x91E2) || - ((bin & 0xFFED) == 0x91E5)) - as_warn( _("undefined combination of operands")); - - if (opcode->insn_size == 2) + input_line_pointer = tmp; + expression (exp); + + /* Warn about expressions that fail to use lo8 (). */ + if (exp->X_op == O_constant) { - /* warn if previous opcode was cpse/sbic/sbis/sbrc/sbrs - (AVR core bug) */ - if ((prev & 0xFC00) == 0x1000 - || (prev & 0xFD00) == 0x9900 - || (prev & 0xFC08) == 0xFC00) - as_warn (_("skipping two-word instruction")); - - bfd_putl32 ((bfd_vma)bin, frag); + int x = exp->X_add_number; + + if (x < -255 || x > 255) + as_warn (_("constant out of 8-bit range: %d"), x); } - else - bfd_putl16 ((bfd_vma)bin, frag); - prev = bin; - *line = str; - return bin; + return BFD_RELOC_AVR_LDI; } - /* Parse one instruction operand. - Returns operand bitmask. Also fixups can be generated. */ - + Return operand bitmask. Also fixups can be generated. */ + static unsigned int -avr_operand (opcode, where, op, line) - struct avr_opcodes_s *opcode; - int where; - char *op; - char **line; +avr_operand (struct avr_opcodes_s *opcode, + int where, + char *op, + char **line) { expressionS op_expr; unsigned int op_mask = 0; @@ -651,177 +739,177 @@ avr_operand (opcode, where, op, line) case 'r': case 'a': case 'v': - { - op_mask = -1; - - if (*str == 'r' || *str == 'R') - { - char r_name[20]; - - str = extract_word (str, r_name, sizeof (r_name)); - 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; - } - - if (op_mask <= 31) - { - switch (*op) - { - case 'a': - if (op_mask < 16 || op_mask > 23) - as_bad (_ ("register r16-r23 required")); - op_mask -= 16; - break; - - case 'd': - if (op_mask < 16) - as_bad (_ ("register number above 15 required")); - op_mask -= 16; - break; - - case 'v': - if (op_mask & 1) - as_bad (_ ("even register number required")); - op_mask >>= 1; - break; - - case 'w': - op_mask -= 24; - if (op_mask & 1 || op_mask > 6) - as_bad (_ ("register r24,r26,r28 or r30 required")); - op_mask >>= 1; - break; - } - break; - } - as_bad (_ ("register name or number from 0 to 31 required")); - } + 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'; + } + } + else + { + op_mask = avr_get_constant (str, 31); + str = input_line_pointer; + } + + if (op_mask <= 31) + { + switch (*op) + { + case 'a': + if (op_mask < 16 || op_mask > 23) + as_bad (_("register r16-r23 required")); + op_mask -= 16; + break; + + case 'd': + if (op_mask < 16) + as_bad (_("register number above 15 required")); + op_mask -= 16; + break; + + case 'v': + if (op_mask & 1) + as_bad (_("even register number required")); + op_mask >>= 1; + break; + + case 'w': + if ((op_mask & 1) || op_mask < 24) + as_bad (_("register r24, r26, r28 or r30 required")); + op_mask = (op_mask - 24) >> 1; + break; + } + break; + } + as_bad (_("register name or number from 0 to 31 required")); break; case 'e': { char c; + if (*str == '-') { - str = skip_space (str+1); + str = skip_space (str + 1); op_mask = 0x1002; } - c = tolower (*str); + c = TOLOWER (*str); if (c == 'x') op_mask |= 0x100c; else if (c == 'y') op_mask |= 0x8; else if (c != 'z') - as_bad (_ ("pointer register (X,Y or Z) required")); + as_bad (_("pointer register (X, Y or Z) required")); - str = skip_space (str+1); + str = skip_space (str + 1); if (*str == '+') { ++str; if (op_mask & 2) - as_bad (_ ("cannot both predecrement and postincrement")); + as_bad (_("cannot both predecrement and postincrement")); op_mask |= 0x1001; } + + /* avr1 can do "ld r,Z" and "st Z,r" but no other pointer + registers, no predecrement, no postincrement. */ + if (!avr_opt.all_opcodes && (op_mask & 0x100F) + && !(avr_mcu->isa & AVR_ISA_SRAM)) + as_bad (_("addressing mode not supported")); } break; case 'z': - { - if (*str == '-') - as_bad (_ ("can't predecrement")); + if (*str == '-') + as_bad (_("can't predecrement")); + + if (! (*str == 'z' || *str == 'Z')) + as_bad (_("pointer register Z required")); - if (! (*str == 'z' || *str == 'Z')) - as_bad (_ ("pointer register Z required")); + str = skip_space (str + 1); - str = skip_space (str + 1); - if (*str == '+') - { - ++str; - op_mask |= 1; - } - } + if (*str == '+') + { + ++str; + op_mask |= 1; + } + + /* attiny26 can do "lpm" and "lpm r,Z" but not "lpm r,Z+". */ + if (!avr_opt.all_opcodes + && (op_mask & 0x0001) + && !(avr_mcu->isa & AVR_ISA_MOVW)) + as_bad (_("postincrement not supported")); break; case 'b': { - char c = tolower (*str++); + char c = TOLOWER (*str++); + if (c == 'y') op_mask |= 0x8; else if (c != 'z') - as_bad (_ ("pointer register (Y or Z) required")); + as_bad (_("pointer register (Y or Z) required")); str = skip_space (str); if (*str++ == '+') { - unsigned int x; - x = avr_get_constant (str, 63); + input_line_pointer = str; + avr_offset_expression (& op_expr); str = input_line_pointer; - op_mask |= (x & 7) | ((x & (3 << 3)) << 7) | ((x & (1 << 5)) << 8); + fix_new_exp (frag_now, where, 3, + &op_expr, FALSE, BFD_RELOC_AVR_6); } } break; case 'h': - { - str = parse_exp (str, &op_expr); - fix_new_exp (frag_now, where, opcode->insn_size * 2, - &op_expr, false, BFD_RELOC_AVR_CALL); - - } + str = parse_exp (str, &op_expr); + fix_new_exp (frag_now, where, opcode->insn_size * 2, + &op_expr, FALSE, BFD_RELOC_AVR_CALL); break; case 'L': - { - str = parse_exp (str, &op_expr); - fix_new_exp (frag_now, where, opcode->insn_size * 2, - &op_expr, true, BFD_RELOC_AVR_13_PCREL); - - } + str = parse_exp (str, &op_expr); + fix_new_exp (frag_now, where, opcode->insn_size * 2, + &op_expr, TRUE, BFD_RELOC_AVR_13_PCREL); break; case 'l': - { - str = parse_exp (str, &op_expr); - fix_new_exp (frag_now, where, opcode->insn_size * 2, - &op_expr, true, BFD_RELOC_AVR_7_PCREL); - - } + str = parse_exp (str, &op_expr); + fix_new_exp (frag_now, where, opcode->insn_size * 2, + &op_expr, TRUE, BFD_RELOC_AVR_7_PCREL); break; case 'i': - { - str = parse_exp (str, &op_expr); - fix_new_exp (frag_now, where+2, opcode->insn_size * 2, - &op_expr, false, BFD_RELOC_16); - - } + str = parse_exp (str, &op_expr); + fix_new_exp (frag_now, where + 2, opcode->insn_size * 2, + &op_expr, FALSE, BFD_RELOC_16); break; case 'M': { bfd_reloc_code_real_type r_type; - input_line_pointer = str; - r_type = avr_ldi_expression (&op_expr); - str = input_line_pointer; + + input_line_pointer = str; + r_type = avr_ldi_expression (&op_expr); + str = input_line_pointer; fix_new_exp (frag_now, where, 3, - &op_expr, false, r_type); + &op_expr, FALSE, r_type); } break; case 'n': { unsigned int x; + x = ~avr_get_constant (str, 255); str = input_line_pointer; op_mask |= (x & 0xf) | ((x << 4) & 0xf00); @@ -829,18 +917,18 @@ avr_operand (opcode, where, op, line) break; case 'K': - { - unsigned int x; - x = avr_get_constant (str, 63); - str = input_line_pointer; - op_mask |= (x & 0xf) | ((x & 0x30) << 2); - } + input_line_pointer = str; + avr_offset_expression (& op_expr); + str = input_line_pointer; + fix_new_exp (frag_now, where, 3, + & op_expr, FALSE, BFD_RELOC_AVR_6_ADIW); break; case 'S': case 's': { unsigned int x; + x = avr_get_constant (str, 7); str = input_line_pointer; if (*op == 'S') @@ -852,6 +940,7 @@ avr_operand (opcode, where, op, line) case 'P': { unsigned int x; + x = avr_get_constant (str, 63); str = input_line_pointer; op_mask |= (x & 0xf) | ((x & 0x30) << 5); @@ -861,24 +950,113 @@ avr_operand (opcode, where, op, line) case 'p': { unsigned int x; + x = avr_get_constant (str, 31); str = input_line_pointer; op_mask |= x << 3; } break; + + case '?': + break; + default: - as_bad (_ ("unknown constraint `%c'"), *op); + as_bad (_("unknown constraint `%c'"), *op); } + *line = str; return op_mask; } +/* Parse instruction operands. + Return binary opcode. */ + +static unsigned int +avr_operands (struct avr_opcodes_s *opcode, char **line) +{ + char *op = opcode->constraints; + unsigned int bin = opcode->bin_opcode; + char *frag = frag_more (opcode->insn_size * 2); + char *str = *line; + int where = frag - frag_now->fr_literal; + static unsigned int prev = 0; /* Previous opcode. */ + + /* Opcode have operands. */ + if (*op) + { + unsigned int reg1 = 0; + unsigned int reg2 = 0; + int reg1_present = 0; + int reg2_present = 0; + + /* Parse first operand. */ + if (REGISTER_P (*op)) + reg1_present = 1; + reg1 = avr_operand (opcode, where, op, &str); + ++op; + + /* Parse second operand. */ + if (*op) + { + if (*op == ',') + ++op; + + if (*op == '=') + { + reg2 = reg1; + reg2_present = 1; + } + else + { + if (REGISTER_P (*op)) + reg2_present = 1; + + str = skip_space (str); + if (*str++ != ',') + as_bad (_("`,' required")); + str = skip_space (str); + + reg2 = avr_operand (opcode, where, op, &str); + } + + if (reg1_present && reg2_present) + reg2 = (reg2 & 0xf) | ((reg2 << 5) & 0x200); + else if (reg2_present) + reg2 <<= 4; + } + if (reg1_present) + reg1 <<= 4; + bin |= reg1 | reg2; + } + + /* Detect undefined combinations (like ld r31,Z+). */ + if (!avr_opt.all_opcodes && AVR_UNDEF_P (bin)) + as_warn (_("undefined combination of operands")); + + if (opcode->insn_size == 2) + { + /* Warn if the previous opcode was cpse/sbic/sbis/sbrc/sbrs + (AVR core bug, fixed in the newer devices). */ + if (!(avr_opt.no_skip_bug || + (avr_mcu->isa & (AVR_ISA_MUL | AVR_ISA_MOVW))) + && AVR_SKIP_P (prev)) + as_warn (_("skipping two-word instruction")); + + bfd_putl32 ((bfd_vma) bin, frag); + } + else + bfd_putl16 ((bfd_vma) bin, frag); + + prev = bin; + *line = str; + return bin; +} + /* GAS will call this function for each section at the end of the assembly, to permit the CPU backend to adjust the alignment of a section. */ + valueT -md_section_align (seg, addr) - asection *seg; - valueT addr; +md_section_align (asection *seg, valueT addr) { int align = bfd_get_section_alignment (stdoutput, seg); return ((addr + (1 << align) - 1) & (-1 << align)); @@ -889,68 +1067,50 @@ md_section_align (seg, addr) 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. */ + long -md_pcrel_from_section (fixp, sec) - fixS *fixp; - segT sec; +md_pcrel_from_section (fixS *fixp, segT sec) { - if (fixp->fx_addsy != (symbolS *)NULL + 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; } /* GAS will call this for each fixup. It should store the correct - value in the object file. */ -int -md_apply_fix3 (fixp, valuep, seg) - fixS *fixp; - valueT *valuep; - segT seg; + value in the object file. */ + +void +md_apply_fix (fixS *fixP, valueT * valP, segT seg) { unsigned char *where; unsigned long insn; - long value; + long value = *valP; - if (fixp->fx_addsy == (symbolS *) NULL) - { - value = *valuep; - fixp->fx_done = 1; - } - else if (fixp->fx_pcrel) - { - segT s = S_GET_SEGMENT (fixp->fx_addsy); - if (fixp->fx_addsy && (s == seg || s == absolute_section)) - { - value = S_GET_VALUE (fixp->fx_addsy) + *valuep; - fixp->fx_done = 1; - } - else - value = *valuep; - } - else + if (fixP->fx_addsy == (symbolS *) NULL) + fixP->fx_done = 1; + + else if (fixP->fx_pcrel) { - value = fixp->fx_offset; - if (fixp->fx_subsy != (symbolS *) NULL) + segT s = S_GET_SEGMENT (fixP->fx_addsy); + + if (s == seg || s == absolute_section) { - 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")); - } + value += S_GET_VALUE (fixP->fx_addsy); + fixP->fx_done = 1; } } - switch (fixp->fx_r_type) + + /* 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")); + + switch (fixP->fx_r_type) { default: - fixp->fx_no_overflow = 1; + fixP->fx_no_overflow = 1; break; case BFD_RELOC_AVR_7_PCREL: case BFD_RELOC_AVR_13_PCREL: @@ -960,24 +1120,26 @@ md_apply_fix3 (fixp, valuep, seg) break; } - if (fixp->fx_done) + if (fixP->fx_done) { /* Fetch the instruction, insert the fully resolved operand value, and stuff the instruction back again. */ - where = fixp->fx_frag->fr_literal + fixp->fx_where; + where = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where; insn = bfd_getl16 (where); - switch (fixp->fx_r_type) + switch (fixP->fx_r_type) { case BFD_RELOC_AVR_7_PCREL: if (value & 1) - as_bad_where (fixp->fx_file, fixp->fx_line, + as_bad_where (fixP->fx_file, fixP->fx_line, _("odd address operand: %ld"), value); + /* Instruction addresses are always right-shifted by 1. */ value >>= 1; --value; /* Correct PC. */ + if (value < -64 || value > 63) - as_bad_where (fixp->fx_file, fixp->fx_line, + as_bad_where (fixP->fx_file, fixP->fx_line, _("operand out of range: %ld"), value); value = (value << 3) & 0x3f8; bfd_putl16 ((bfd_vma) (value | insn), where); @@ -985,23 +1147,18 @@ md_apply_fix3 (fixp, valuep, seg) case BFD_RELOC_AVR_13_PCREL: if (value & 1) - as_bad_where (fixp->fx_file, fixp->fx_line, + as_bad_where (fixP->fx_file, fixP->fx_line, _("odd address operand: %ld"), value); + /* Instruction addresses are always right-shifted by 1. */ value >>= 1; --value; /* Correct PC. */ if (value < -2048 || value > 2047) { - if (avr_mcu->isa & AVR_ISA_WRAP) - { - if (value > 2047) - value -= 4096; - else - value += 4096; - } - else - as_bad_where (fixp->fx_file, fixp->fx_line, + /* No wrap for devices with >8K of program memory. */ + if ((avr_mcu->isa & AVR_ISA_MEGA) || avr_opt.no_wrap) + as_bad_where (fixP->fx_file, fixP->fx_line, _("operand out of range: %ld"), value); } @@ -1017,23 +1174,47 @@ md_apply_fix3 (fixp, valuep, seg) bfd_putl16 ((bfd_vma) value, where); break; + case BFD_RELOC_8: + if (value > 255 || value < -128) + as_warn_where (fixP->fx_file, fixP->fx_line, + _("operand out of range: %ld"), value); + *where = value; + break; + case BFD_RELOC_AVR_16_PM: - bfd_putl16 ((bfd_vma) (value>>1), where); + bfd_putl16 ((bfd_vma) (value >> 1), where); break; - case BFD_RELOC_AVR_LO8_LDI: + case BFD_RELOC_AVR_LDI: + if (value > 255) + as_bad_where (fixP->fx_file, fixP->fx_line, + _("operand out of range: %ld"), value); bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (value), where); break; - case -BFD_RELOC_AVR_LO8_LDI: - bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (value >> 16), where); + 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); + break; + + case BFD_RELOC_AVR_6_ADIW: + 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 & 0xf) | ((value & 0x30) << 2), where); + break; + + case BFD_RELOC_AVR_LO8_LDI: + bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (value), where); break; case BFD_RELOC_AVR_HI8_LDI: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (value >> 8), where); break; - case -BFD_RELOC_AVR_HI8_LDI: + case BFD_RELOC_AVR_MS8_LDI: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (value >> 24), where); break; @@ -1045,15 +1226,11 @@ md_apply_fix3 (fixp, valuep, seg) bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (-value), where); break; - case -BFD_RELOC_AVR_LO8_LDI_NEG: - bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (-value >> 16), where); - break; - case BFD_RELOC_AVR_HI8_LDI_NEG: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (-value >> 8), where); break; - case -BFD_RELOC_AVR_HI8_LDI_NEG: + case BFD_RELOC_AVR_MS8_LDI_NEG: bfd_putl16 ((bfd_vma) insn | LDI_IMMEDIATE (-value >> 24), where); break; @@ -1088,64 +1265,86 @@ md_apply_fix3 (fixp, valuep, seg) case BFD_RELOC_AVR_CALL: { unsigned long x; + x = bfd_getl16 (where); if (value & 1) - as_bad_where (fixp->fx_file, fixp->fx_line, + as_bad_where (fixP->fx_file, fixP->fx_line, _("odd address operand: %ld"), value); value >>= 1; x |= ((value & 0x10000) | ((value << 3) & 0x1f00000)) >> 16; bfd_putl16 ((bfd_vma) x, where); - bfd_putl16 ((bfd_vma) (value & 0xffff), where+2); + bfd_putl16 ((bfd_vma) (value & 0xffff), where + 2); } break; 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"), + fixP->fx_line, fixP->fx_r_type); break; } } else { - switch (fixp->fx_r_type) + switch ((int) fixP->fx_r_type) { case -BFD_RELOC_AVR_HI8_LDI_NEG: case -BFD_RELOC_AVR_HI8_LDI: case -BFD_RELOC_AVR_LO8_LDI_NEG: case -BFD_RELOC_AVR_LO8_LDI: - as_bad_where (fixp->fx_file, fixp->fx_line, + as_bad_where (fixP->fx_file, fixP->fx_line, _("only constant expression allowed")); - fixp->fx_done = 1; + fixP->fx_done = 1; break; default: break; } - fixp->fx_addnumber = value; } - return 0; } - -/* A `BFD_ASSEMBLER' GAS will call this to generate a reloc. GAS - will pass the resulting reloc to `bfd_install_relocation'. This - currently works poorly, as `bfd_install_relocation' often does the - wrong thing, and instances of `tc_gen_reloc' have been written to - work around the problems, which in turns makes it difficult to fix - `bfd_install_relocation'. */ +/* GAS will call this to generate a reloc, passing the resulting reloc + to `bfd_install_relocation'. This currently works poorly, as + `bfd_install_relocation' often does the wrong thing, and instances of + `tc_gen_reloc' have been written to work around the problems, which + in turns makes it difficult to fix `bfd_install_relocation'. */ /* If while processing a fixup, a reloc really needs to be created then it is done here. */ arelent * -tc_gen_reloc (seg, fixp) - asection *seg ATTRIBUTE_UNUSED; - fixS *fixp; +tc_gen_reloc (asection *seg ATTRIBUTE_UNUSED, + fixS *fixp) { arelent *reloc; - reloc = (arelent *) xmalloc (sizeof (arelent)); + if (fixp->fx_addsy && fixp->fx_subsy) + { + 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); + + return NULL; + } - reloc->sym_ptr_ptr = (asymbol **) xmalloc (sizeof (asymbol *)); + reloc = xmalloc (sizeof (arelent)); + + reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *)); *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy); reloc->address = fixp->fx_frag->fr_address + fixp->fx_where; @@ -1153,8 +1352,8 @@ tc_gen_reloc (seg, fixp) if (reloc->howto == (reloc_howto_type *) NULL) { as_bad_where (fixp->fx_file, fixp->fx_line, - _("reloc %d not supported by object file format"), - (int)fixp->fx_r_type); + _("reloc %d not supported by object file format"), + (int) fixp->fx_r_type); return NULL; } @@ -1167,160 +1366,61 @@ tc_gen_reloc (seg, fixp) return reloc; } - void -md_assemble (str) - char *str; +md_assemble (char *str) { - struct avr_opcodes_s * opcode; + struct avr_opcodes_s *opcode; char op[11]; - str = skip_space (extract_word (str, op, sizeof(op))); + str = skip_space (extract_word (str, op, sizeof (op))); if (!op[0]) - as_bad (_ ("can't find opcode ")); + as_bad (_("can't find opcode ")); opcode = (struct avr_opcodes_s *) hash_find (avr_hash, op); if (opcode == NULL) { - as_bad (_ ("unknown opcode `%s'"), op); + as_bad (_("unknown opcode `%s'"), op); return; } /* Special case for opcodes with optional operands (lpm, elpm) - - version with operands is listed in avr_opcodes[] with "x" suffix. */ - - if (*str && !(*opcode->constraints)) - { - struct avr_opcodes_s *opc1; + version with operands exists in avr_opcodes[] in the next entry. */ - /* known opcode, so strlen(op) <= 6 and strcat() should be safe */ - strcat(op, "x"); - opc1 = (struct avr_opcodes_s *) hash_find (avr_hash, op); + if (*str && *opcode->constraints == '?') + ++opcode; - /* if unknown, just forget it and use the original opcode */ - if (opc1) - opcode = opc1; - } + 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); - if ((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, but that is wrong. Our caller assumes we don't change it. */ { char *t = input_line_pointer; + avr_operands (opcode, &str); if (*skip_space (str)) - as_bad (_ ("garbage at end of line")); + as_bad (_("garbage at end of line")); input_line_pointer = t; } } -/* Parse ordinary expression. */ -static char * -parse_exp (s, op) - char *s; - expressionS * op; -{ - input_line_pointer = s; - expression (op); - if (op->X_op == O_absent) - as_bad (_("missing operand")); - return input_line_pointer; -} - - -/* Parse special expressions (needed for LDI command): - xx8 (address) - xx8 (-address) - pm_xx8 (address) - pm_xx8 (-address) - where xx is: hh, hi, lo -*/ -static bfd_reloc_code_real_type -avr_ldi_expression (exp) - expressionS *exp; -{ - char *str = input_line_pointer; - char *tmp; - char op[8]; - int mod; - tmp = str; - - str = extract_word (str, op, sizeof (op)); - if (op[0]) - { - mod = (int) hash_find (avr_mod_hash, op); - if (mod) - { - int closes = 0; - mod -= 10; - str = skip_space (str); - if (*str == '(') - { - int neg_p = 0; - ++str; - if (strncmp ("pm(", str, 3) == 0 - || strncmp ("-(pm(", str, 5) == 0) - { - if (HAVE_PM_P(mod)) - { - ++mod; - ++closes; - } - else - as_bad (_ ("illegal expression")); - if (*str == '-') - { - neg_p = 1; - ++closes; - str += 5; - } - else - str += 3; - } - if (*str == '-' && *(str + 1) == '(') - { - neg_p ^= 1; - ++closes; - str += 2; - } - input_line_pointer = str; - expression (exp); - do - { - if (*input_line_pointer != ')') - { - as_bad (_ ("`)' required")); - break; - } - input_line_pointer++; - } - while (closes--); - return neg_p ? EXP_MOD_NEG_RELOC (mod) : EXP_MOD_RELOC (mod); - } - } - } - input_line_pointer = tmp; - expression (exp); - return BFD_RELOC_AVR_LO8_LDI; -} - /* Flag to pass `pm' mode between `avr_parse_cons_expression' and - `avr_cons_fix_new' */ + `avr_cons_fix_new'. */ static int exp_mod_pm = 0; /* Parse special CONS expression: pm (expression) - which is used for addressing to a program memory. - Relocation: BFD_RELOC_AVR_16_PM */ + or alternatively: gs (expression). + These are used for addressing program memory. + Relocation: BFD_RELOC_AVR_16_PM. */ + void -avr_parse_cons_expression (exp, nbytes) - expressionS *exp; - int nbytes; +avr_parse_cons_expression (expressionS *exp, int nbytes) { - char * tmp; + char *tmp; exp_mod_pm = 0; @@ -1328,53 +1428,63 @@ avr_parse_cons_expression (exp, nbytes) if (nbytes == 2) { - char * pm_name = "pm"; - int len = strlen (pm_name); - if (strncasecmp (input_line_pointer, pm_name, len) == 0) + char *pm_name1 = "pm"; + char *pm_name2 = "gs"; + int len = strlen (pm_name1); + /* len must be the same for both pm identifiers. */ + + if (strncasecmp (input_line_pointer, pm_name1, len) == 0 + || strncasecmp (input_line_pointer, pm_name2, 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; else { - as_bad (_ ("`)' required")); + as_bad (_("`)' required")); exp_mod_pm = 0; } + return; } + input_line_pointer = tmp; } } + expression (exp); } void -avr_cons_fix_new(frag, where, nbytes, exp) - fragS *frag; - int where; - int nbytes; - expressionS *exp; +avr_cons_fix_new (fragS *frag, + int where, + int nbytes, + expressionS *exp) { if (exp_mod_pm == 0) { - if (nbytes == 2) - fix_new_exp (frag, where, nbytes, exp, false, BFD_RELOC_16); + if (nbytes == 1) + fix_new_exp (frag, where, nbytes, exp, FALSE, BFD_RELOC_8); + else if (nbytes == 2) + fix_new_exp (frag, where, nbytes, exp, FALSE, BFD_RELOC_16); else if (nbytes == 4) - fix_new_exp (frag, where, nbytes, exp, false, BFD_RELOC_32); + fix_new_exp (frag, where, nbytes, exp, FALSE, BFD_RELOC_32); else - as_bad (_ ("illegal %srelocation size: %d"), "", nbytes); + as_bad (_("illegal %srelocation size: %d"), "", nbytes); } else { if (nbytes == 2) - fix_new_exp (frag, where, nbytes, exp, false, BFD_RELOC_AVR_16_PM); + fix_new_exp (frag, where, nbytes, exp, FALSE, BFD_RELOC_AVR_16_PM); else - as_bad (_ ("illegal %srelocation size: %d"), "`pm' ", nbytes); + as_bad (_("illegal %srelocation size: %d"), "`pm' ", nbytes); exp_mod_pm = 0; } }