/* tc-avr.c -- Assembler code for the ATMEL AVR
- Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
+ Copyright 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
Contributed by Denis Chertykov <denisc@overta.ru>
This file is part of GAS, the GNU Assembler.
{"at43usb320",AVR_ISA_M103, bfd_mach_avr3},
{"at43usb355",AVR_ISA_M603, bfd_mach_avr3},
{"at76c711", AVR_ISA_M603, bfd_mach_avr3},
+ {"atmega48", AVR_ISA_M8, bfd_mach_avr4},
{"atmega8", AVR_ISA_M8, bfd_mach_avr4},
{"atmega83", AVR_ISA_M8, bfd_mach_avr4}, /* XXX -> m8535 */
{"atmega85", AVR_ISA_M8, bfd_mach_avr4}, /* XXX -> m8 */
+ {"atmega88", AVR_ISA_M8, bfd_mach_avr4},
{"atmega8515",AVR_ISA_M8, bfd_mach_avr4},
{"atmega8535",AVR_ISA_M8, bfd_mach_avr4},
+ {"attiny13", AVR_ISA_TINY2, bfd_mach_avr4},
+ {"attiny2313",AVR_ISA_TINY2, bfd_mach_avr4},
{"atmega16", AVR_ISA_M323, bfd_mach_avr5},
{"atmega161", AVR_ISA_M161, bfd_mach_avr5},
{"atmega162", AVR_ISA_M323, bfd_mach_avr5},
{"atmega163", AVR_ISA_M161, bfd_mach_avr5},
+ {"atmega165", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega168", AVR_ISA_M323, bfd_mach_avr5},
{"atmega169", AVR_ISA_M323, bfd_mach_avr5},
{"atmega32", AVR_ISA_M323, bfd_mach_avr5},
{"atmega323", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega325", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega3250",AVR_ISA_M323, bfd_mach_avr5},
{"atmega64", AVR_ISA_M323, bfd_mach_avr5},
{"atmega128", AVR_ISA_M128, bfd_mach_avr5},
+ {"atmega645", AVR_ISA_M323, bfd_mach_avr5},
+ {"atmega6450",AVR_ISA_M323, bfd_mach_avr5},
+ {"at90can128",AVR_ISA_M128, bfd_mach_avr5},
{"at94k", AVR_ISA_94K, bfd_mach_avr5},
{NULL, 0, 0}
};
/* 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))
+ 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"));
return bin;
}
+/* Parse for ldd/std offset */
+
+static void
+avr_offset_expression (expressionS *exp)
+{
+ char *str = input_line_pointer;
+ char *tmp;
+ char op[8];
+
+ 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 one instruction operand.
Return operand bitmask. Also fixups can be generated. */
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);
+ &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);
+ &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);
+ &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);
+ &op_expr, FALSE, BFD_RELOC_16);
break;
case 'M':
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;
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':
{
unsigned char *where;
unsigned long insn;
- long value = * (long *) valP;
+ long value = *valP;
if (fixP->fx_addsy == (symbolS *) NULL)
fixP->fx_done = 1;
{
segT s = S_GET_SEGMENT (fixP->fx_addsy);
- if (fixP->fx_addsy && (s == seg || s == absolute_section))
+ if (s == seg || s == absolute_section)
{
value += S_GET_VALUE (fixP->fx_addsy);
fixP->fx_done = 1;
}
}
- else
- {
- value = fixP->fx_offset;
- if (fixP->fx_subsy != (symbolS *) NULL)
- {
- if (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section)
- {
- value -= S_GET_VALUE (fixP->fx_subsy);
- fixP->fx_done = 1;
- }
- else
- {
- /* We don't actually support subtracting a symbol. */
- as_bad_where (fixP->fx_file, fixP->fx_line,
- _("expression too complex"));
- }
- }
- }
+ /* 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)
{
bfd_putl16 ((bfd_vma) (value >> 1), where);
break;
+ 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_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;
default:
break;
}
- fixP->fx_addnumber = value;
}
}
if (x < -255 || x > 255)
as_warn (_("constant out of 8-bit range: %d"), x);
}
- else
- as_warn (_("expression possibly out of 8-bit range"));
- return BFD_RELOC_AVR_LO8_LDI;
+ return BFD_RELOC_AVR_LDI;
}
/* Flag to pass `pm' mode between `avr_parse_cons_expression' and
if (exp_mod_pm == 0)
{
if (nbytes == 2)
- fix_new_exp (frag, where, nbytes, exp, false, BFD_RELOC_16);
+ 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);
}
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);
exp_mod_pm = 0;