Add support for ia64-hpux target.
[binutils-gdb.git] / gas / config / tc-avr.c
index 1f824fd8ffb84a3638575fc5ebac1164490ce78a..0a85533bfd0612671296769475421cd152234417 100644 (file)
@@ -1,6 +1,6 @@
 /* tc-avr.c -- Assembler code for the ATMEL AVR
 
-   Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+   Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
    Contributed by Denis Chertykov <denisc@overta.ru>
 
    This file is part of GAS, the GNU Assembler.
@@ -21,8 +21,8 @@
    Boston, MA 02111-1307, USA.  */
 
 #include <stdio.h>
-#include <ctype.h>
 #include "as.h"
+#include "safe-ctype.h"
 #include "subsegs.h"
 
 struct avr_opcodes_s
@@ -55,37 +55,49 @@ 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.
+   TODO: hide them in show_mcu_list output?  */
+
 static struct mcu_type_s mcu_types[] =
 {
   {"avr1",      AVR_ISA_TINY1,    bfd_mach_avr1},
   {"avr2",      AVR_ISA_2xxx,     bfd_mach_avr2},
   {"avr3",      AVR_ISA_M103,     bfd_mach_avr3},
-  {"avr4",      AVR_ISA_M83,      bfd_mach_avr4},
+  {"avr4",      AVR_ISA_M8      bfd_mach_avr4},
   {"avr5",      AVR_ISA_ALL,      bfd_mach_avr5},
   {"at90s1200", AVR_ISA_1200,     bfd_mach_avr1},
-  {"attiny10",  AVR_ISA_TINY1,    bfd_mach_avr1},
+  {"attiny10",  AVR_ISA_TINY1,    bfd_mach_avr1}, /* XXX -> tn11 */
   {"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},
+  {"at90s2333", AVR_ISA_2xxx,     bfd_mach_avr2}, /* XXX -> 4433 */
   {"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},
+  {"at90s4414", AVR_ISA_2xxx,     bfd_mach_avr2}, /* XXX -> 8515 */
+  {"at90s4434", AVR_ISA_2xxx,     bfd_mach_avr2}, /* XXX -> 8535 */
   {"at90s8515", AVR_ISA_2xxx,     bfd_mach_avr2},
   {"at90s8535", AVR_ISA_2xxx,     bfd_mach_avr2},
   {"at90c8534", AVR_ISA_2xxx,     bfd_mach_avr2},
-  {"atmega603", AVR_ISA_M603,     bfd_mach_avr3},
+  {"atmega603", AVR_ISA_M603,     bfd_mach_avr3}, /* XXX -> m103 */
   {"atmega103", AVR_ISA_M103,     bfd_mach_avr3},
-  {"atmega83",  AVR_ISA_M83,      bfd_mach_avr4},
-  {"atmega85",  AVR_ISA_M83,      bfd_mach_avr4},
+  {"at43usb320",AVR_ISA_M103,     bfd_mach_avr3},
+  {"at76c711",  AVR_ISA_M603,     bfd_mach_avr3},
+  {"atmega8",   AVR_ISA_M8,       bfd_mach_avr4},
+  {"atmega83",  AVR_ISA_M8,       bfd_mach_avr4}, /* XXX -> m163 */
+  {"atmega85",  AVR_ISA_M8,       bfd_mach_avr4}, /* XXX -> m8 */
+  {"atmega16",  AVR_ISA_M323,     bfd_mach_avr5},
   {"atmega161", AVR_ISA_M161,     bfd_mach_avr5},
   {"atmega163", AVR_ISA_M161,     bfd_mach_avr5},
-  {"atmega32",  AVR_ISA_M161,     bfd_mach_avr5},
+  {"atmega32",  AVR_ISA_M323,     bfd_mach_avr5},
+  {"atmega323", AVR_ISA_M323,     bfd_mach_avr5},
+  {"atmega64",  AVR_ISA_M323,     bfd_mach_avr5},
+  {"atmega128", AVR_ISA_M128,     bfd_mach_avr5},
+  {"at43usb355",AVR_ISA_94K,      bfd_mach_avr5},
   {"at94k",     AVR_ISA_94K,      bfd_mach_avr5},
   {NULL, 0, 0}
 };
@@ -184,13 +196,13 @@ show_mcu_list (stream)
 
   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
@@ -199,7 +211,7 @@ show_mcu_list (stream)
          x = len + 2;
        }
     }
-  
+
   fprintf (stream, "\n");
 }
 
@@ -232,7 +244,7 @@ extract_word (char *from, char *to, int limit)
       if (size + 1 >= limit)
        break;
     }
-  
+
   to[size] = 0;
   return op_end;
 }
@@ -274,7 +286,7 @@ avr_set_arch (dummy)
      int dummy ATTRIBUTE_UNUSED;
 {
   char *str;
-  
+
   str = (char *) alloca (20);
   input_line_pointer = extract_word (input_line_pointer, str, 20);
   md_parse_option (OPTION_MMCU, str);
@@ -298,7 +310,7 @@ md_parse_option (c, arg)
          char *arg1 = arg;
 
          do
-           *t = tolower (*arg1++);
+           *t = TOLOWER (*arg1++);
          while (*t++);
        }
 
@@ -332,7 +344,7 @@ md_parse_option (c, arg)
       avr_opt.no_wrap = 1;
       return 1;
     }
-  
+
   return 0;
 }
 
@@ -377,14 +389,14 @@ md_atof (type, litP, sizeP)
     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;
 }
 
@@ -436,7 +448,7 @@ avr_get_constant (str, max)
 
   if (ex.X_add_number > max || ex.X_add_number < 0)
     as_bad (_("number must be less than %d"), max + 1);
-  
+
   return ex.X_add_number;
 }
 
@@ -474,7 +486,7 @@ avr_operands (opcode, line)
        {
          if (*op == ',')
            ++op;
-         
+
          if (*op == '=')
            {
              reg2 = reg1;
@@ -493,7 +505,7 @@ avr_operands (opcode, line)
              reg2 = avr_operand (opcode, where, op, &str);
 
            }
-         
+
          if (reg1_present && reg2_present)
            reg2 = (reg2 & 0xf) | ((reg2 << 5) & 0x200);
          else if (reg2_present)
@@ -552,15 +564,15 @@ avr_operand (opcode, where, op, line)
       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 (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])
+                      && ISDIGIT (r_name[2])
                       && r_name[3] == '\0')
                op_mask = (r_name[1] - '0') * 10 + r_name[2] - '0';
            }
@@ -570,7 +582,7 @@ avr_operand (opcode, where, op, line)
          op_mask = avr_get_constant (str, 31);
          str = input_line_pointer;
        }
-      
+
       if (op_mask <= 31)
        {
          switch (*op)
@@ -580,19 +592,19 @@ avr_operand (opcode, where, op, line)
                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"));
@@ -607,13 +619,13 @@ avr_operand (opcode, where, op, line)
     case 'e':
       {
        char c;
-       
+
        if (*str == '-')
          {
            str = skip_space (str + 1);
            op_mask = 0x1002;
          }
-       c = tolower (*str);
+       c = TOLOWER (*str);
        if (c == 'x')
          op_mask |= 0x100c;
        else if (c == 'y')
@@ -641,10 +653,10 @@ avr_operand (opcode, where, op, line)
     case 'z':
       if (*str == '-')
        as_bad (_("can't predecrement"));
-      
+
       if (! (*str == 'z' || *str == 'Z'))
        as_bad (_("pointer register Z required"));
-      
+
       str = skip_space (str + 1);
 
       if (*str == '+')
@@ -656,8 +668,8 @@ avr_operand (opcode, where, op, line)
 
     case 'b':
       {
-       char c = tolower (*str++);
-       
+       char c = TOLOWER (*str++);
+
        if (c == 'y')
          op_mask |= 0x8;
        else if (c != 'z')
@@ -700,7 +712,7 @@ avr_operand (opcode, where, op, line)
     case 'M':
       {
        bfd_reloc_code_real_type r_type;
-       
+
        input_line_pointer = str;
        r_type = avr_ldi_expression (&op_expr);
        str = input_line_pointer;
@@ -712,7 +724,7 @@ avr_operand (opcode, where, op, line)
     case 'n':
       {
        unsigned int x;
-       
+
        x = ~avr_get_constant (str, 255);
        str = input_line_pointer;
        op_mask |= (x & 0xf) | ((x << 4) & 0xf00);
@@ -722,7 +734,7 @@ avr_operand (opcode, where, op, line)
     case 'K':
       {
        unsigned int x;
-       
+
        x = avr_get_constant (str, 63);
        str = input_line_pointer;
        op_mask |= (x & 0xf) | ((x & 0x30) << 2);
@@ -733,7 +745,7 @@ avr_operand (opcode, where, op, line)
     case 's':
       {
        unsigned int x;
-       
+
        x = avr_get_constant (str, 7);
        str = input_line_pointer;
        if (*op == 'S')
@@ -745,7 +757,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);
@@ -755,20 +767,20 @@ 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);
     }
-  
+
   *line = str;
   return op_mask;
 }
@@ -800,64 +812,60 @@ md_pcrel_from_section (fixp, sec)
       && (!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;
+void
+md_apply_fix3 (fixP, valP, seg)
+     fixS *fixP;
+     valueT * valP;
      segT seg;
 {
   unsigned char *where;
   unsigned long insn;
-  long value;
+  long value = * (long *) valP;
 
-  if (fixp->fx_addsy == (symbolS *) NULL)
-    {
-      value = *valuep;
-      fixp->fx_done = 1;
-    }
-  else if (fixp->fx_pcrel)
+  if (fixP->fx_addsy == (symbolS *) NULL)
+    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))
+      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;
+         value += S_GET_VALUE (fixP->fx_addsy);
+         fixP->fx_done = 1;
        }
-      else
-       value = *valuep;
     }
   else
     {
-      value = fixp->fx_offset;
-      
-      if (fixp->fx_subsy != (symbolS *) NULL)
+      value = fixP->fx_offset;
+
+      if (fixP->fx_subsy != (symbolS *) NULL)
        {
-         if (S_GET_SEGMENT (fixp->fx_subsy) == absolute_section)
+         if (S_GET_SEGMENT (fixP->fx_subsy) == absolute_section)
            {
-             value -= S_GET_VALUE (fixp->fx_subsy);
-             fixp->fx_done = 1;
+             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,
+             as_bad_where (fixP->fx_file, fixP->fx_line,
                            _("expression too complex"));
            }
        }
     }
-  
-  switch (fixp->fx_r_type)
+
+  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:
@@ -867,26 +875,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 = 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);
@@ -894,9 +902,9 @@ 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.  */
@@ -905,7 +913,7 @@ md_apply_fix3 (fixp, valuep, seg)
            {
              /* 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,
+               as_bad_where (fixP->fx_file, fixP->fx_line,
                              _("operand out of range: %ld"), value);
            }
 
@@ -992,10 +1000,10 @@ 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;
@@ -1006,28 +1014,27 @@ md_apply_fix3 (fixp, valuep, seg)
 
        default:
          as_fatal (_("line %d: unknown relocation type: 0x%x"),
-                   fixp->fx_line, fixp->fx_r_type);
+                   fixP->fx_line, fixP->fx_r_type);
          break;
        }
     }
   else
     {
-      switch (fixp->fx_r_type)
+      switch (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;
+      fixP->fx_addnumber = value;
     }
-  return 0;
 }
 
 /* A `BFD_ASSEMBLER' GAS will call this to generate a reloc.  GAS
@@ -1143,24 +1150,24 @@ avr_ldi_expression (exp)
   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)
                {
@@ -1171,7 +1178,7 @@ avr_ldi_expression (exp)
                    }
                  else
                    as_bad (_("illegal expression"));
-                 
+
                  if (*str == '-')
                    {
                      neg_p = 1;
@@ -1181,17 +1188,17 @@ avr_ldi_expression (exp)
                  else
                    str += 3;
                }
-             
+
              if (*str == '-' && *(str + 1) == '(')
                {
                  neg_p ^= 1;
                  ++closes;
                  str += 2;
                }
-             
+
              input_line_pointer = str;
              expression (exp);
-             
+
              do
                {
                  if (*input_line_pointer != ')')
@@ -1202,12 +1209,12 @@ avr_ldi_expression (exp)
                  input_line_pointer++;
                }
              while (closes--);
-             
+
              return neg_p ? EXP_MOD_NEG_RELOC (mod) : EXP_MOD_RELOC (mod);
            }
        }
     }
-  
+
   input_line_pointer = tmp;
   expression (exp);
 
@@ -1247,17 +1254,17 @@ avr_parse_cons_expression (exp, nbytes)
     {
       char *pm_name = "pm";
       int len = strlen (pm_name);
-      
+
       if (strncasecmp (input_line_pointer, pm_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;
              else
@@ -1265,14 +1272,14 @@ avr_parse_cons_expression (exp, nbytes)
                  as_bad (_("`)' required"));
                  exp_mod_pm = 0;
                }
-             
+
              return;
            }
-         
+
          input_line_pointer = tmp;
        }
     }
-  
+
   expression (exp);
 }