Add support for the new R_AVR_LDI, R_AVR_6 and R_AVR_6_ADIW relocs for the
[deliverable/binutils-gdb.git] / gas / config / tc-avr.c
index bab0d2d5791546d8e7711c7a3df1843fcafdcd69..c0c2e3bdffaa64842881e761dedb46677311ec52 100644 (file)
@@ -1,6 +1,6 @@
 /* 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.
@@ -90,20 +90,31 @@ static struct mcu_type_s mcu_types[] =
   {"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}
 };
@@ -531,7 +542,8 @@ avr_operands (opcode, line)
       /* 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"));
 
@@ -545,6 +557,31 @@ avr_operands (opcode, line)
   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.  */
 
@@ -683,10 +720,11 @@ avr_operand (opcode, where, op, line)
        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;
@@ -694,25 +732,25 @@ avr_operand (opcode, where, op, line)
     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':
@@ -723,7 +761,7 @@ avr_operand (opcode, where, op, line)
        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;
 
@@ -738,13 +776,11 @@ 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':
@@ -833,7 +869,7 @@ md_apply_fix3 (fixP, valP, seg)
 {
   unsigned char *where;
   unsigned long insn;
-  long value = * (long *) valP;
+  long value = *valP;
 
   if (fixP->fx_addsy == (symbolS *) NULL)
     fixP->fx_done = 1;
@@ -842,31 +878,16 @@ md_apply_fix3 (fixP, valP, seg)
     {
       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)
     {
@@ -939,6 +960,27 @@ md_apply_fix3 (fixP, valP, seg)
          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;
@@ -1039,7 +1081,6 @@ md_apply_fix3 (fixP, valP, seg)
        default:
          break;
        }
-      fixP->fx_addnumber = value;
     }
 }
 
@@ -1231,10 +1272,8 @@ avr_ldi_expression (exp)
       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
@@ -1299,16 +1338,16 @@ avr_cons_fix_new (frag, where, nbytes, exp)
   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;
This page took 0.030787 seconds and 4 git commands to generate.