Adds support for writing values to AVR system I/O registers.
authorBarney Stratford <barney_stratford@fastmail.fm>
Mon, 7 Jul 2014 15:15:19 +0000 (16:15 +0100)
committerNick Clifton <nickc@redhat.com>
Mon, 7 Jul 2014 15:15:19 +0000 (16:15 +0100)
* elf32-avr.c: Handle R_AVR_PORT5 and R_AVR_PORT6.
* reloc.c: Add BFD_RELOC_AVR_PORT5 and BFD_RELOC_AVR_PORT6.
* bfd-in2.h: Regenerate.
* libbfd.h: Regenerate.

* avr.h: Add R_AVR_PORT5 and R_AVR_PORT6.

* config/tc-avr.c (avr_operand): Permit referring to r26-r31 by
name as [xyz][hl].  Permit using a symbol whoes name begins with
`r' to refer to a register.
Allow arbitrary expressions for the P and p operators.
(md_apply_fix): Check the BFD_RELOC_AVR_PORT5 and
BFD_RELOC_AVR_PORT6 relocations.

bfd/ChangeLog
bfd/bfd-in2.h
bfd/elf32-avr.c
bfd/libbfd.h
bfd/reloc.c
gas/ChangeLog
gas/config/tc-avr.c
include/elf/ChangeLog
include/elf/avr.h

index 014944fe608359463e5ea3801fd2928a63ab6dbb..f6bc88bd651723e95fe1174121ad238b96340666 100644 (file)
@@ -1,3 +1,10 @@
+2014-07-07  Barney Stratford  <barney_stratford@fastmail.fm>
+
+       * elf32-avr.c: Handle R_AVR_PORT5 and R_AVR_PORT6.
+       * reloc.c: Add BFD_RELOC_AVR_PORT5 and BFD_RELOC_AVR_PORT6.
+       * bfd-in2.h: Regenerate.
+       * libbfd.h: Regenerate.
+
 2014-07-04  Alan Modra  <amodra@gmail.com>
 
        * Makefile.am: Update "configure.in" comments.
index 9efc368021ad4d819b2117676c2961584419f78a..ec19492d906038358e7587fad5497f939d743be2 100644 (file)
@@ -4480,6 +4480,14 @@ value.  */
 lds and sts instructions supported only tiny core.  */
   BFD_RELOC_AVR_LDS_STS_16,
 
+/* This is a 6 bit reloc for the AVR that stores an I/O register
+number for the IN and OUT instructions  */
+  BFD_RELOC_AVR_PORT6,
+
+/* This is a 5 bit reloc for the AVR that stores an I/O register
+number for the SBIC, SBIS, SBI and CBI instructions  */
+  BFD_RELOC_AVR_PORT5,
+
 /* Renesas RL78 Relocations.  */
   BFD_RELOC_RL78_NEG8,
   BFD_RELOC_RL78_NEG16,
index 9ca0c464ee31756252eee8d87671c4e0c31c3b5d..54d67bf04031ada4602f3ab496efeedf63ada62d 100644 (file)
@@ -613,7 +613,34 @@ static reloc_howto_type elf_avr_howto_table[] =
         FALSE,                 /* partial_inplace */
         0xffff,                /* src_mask */
         0xffff,                /* dst_mask */
-        FALSE)                 /* pcrel_offset */
+        FALSE),                /* pcrel_offset */
+
+  HOWTO (R_AVR_PORT6,          /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        6,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_AVR_PORT6",         /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffff,              /* src_mask */
+        0xffffff,              /* dst_mask */
+        FALSE),                /* pcrel_offset */
+  HOWTO (R_AVR_PORT5,          /* type */
+        0,                     /* rightshift */
+        0,                     /* size (0 = byte, 1 = short, 2 = long) */
+        5,                     /* bitsize */
+        FALSE,                 /* pc_relative */
+        0,                     /* bitpos */
+        complain_overflow_dont,/* complain_on_overflow */
+        bfd_elf_generic_reloc, /* special_function */
+        "R_AVR_PORT5",         /* name */
+        FALSE,                 /* partial_inplace */
+        0xffffff,              /* src_mask */
+        0xffffff,              /* dst_mask */
+        FALSE)                 /* pcrel_offset */
 };
 
 /* Map BFD reloc types to AVR ELF reloc types.  */
@@ -659,7 +686,9 @@ static const struct avr_reloc_map avr_reloc_map[] =
   { BFD_RELOC_AVR_DIFF8,            R_AVR_DIFF8 },
   { BFD_RELOC_AVR_DIFF16,           R_AVR_DIFF16 },
   { BFD_RELOC_AVR_DIFF32,           R_AVR_DIFF32 },
-  { BFD_RELOC_AVR_LDS_STS_16,       R_AVR_LDS_STS_16}
+  { BFD_RELOC_AVR_LDS_STS_16,       R_AVR_LDS_STS_16},
+  { BFD_RELOC_AVR_PORT6,            R_AVR_PORT6},
+  { BFD_RELOC_AVR_PORT5,            R_AVR_PORT5}
 };
 
 /* Meant to be filled one day with the wrap around address for the
@@ -1248,6 +1277,26 @@ avr_final_link_relocate (reloc_howto_type *                 howto,
       bfd_put_16 (input_bfd, x, contents);
       break;
 
+    case R_AVR_PORT6:
+      contents += rel->r_offset;
+      srel = (bfd_signed_vma) relocation + rel->r_addend;
+      if ((srel & 0xffff) > 0x3f)
+        return bfd_reloc_outofrange;
+      x = bfd_get_16 (input_bfd, contents);
+      x = (x & 0xf9f0) | ((srel & 0x30) << 5) | (srel & 0x0f);
+      bfd_put_16 (input_bfd, x, contents);
+      break;
+
+    case R_AVR_PORT5:
+      contents += rel->r_offset;
+      srel = (bfd_signed_vma) relocation + rel->r_addend;
+      if ((srel & 0xffff) > 0x1f)
+        return bfd_reloc_outofrange;
+      x = bfd_get_16 (input_bfd, contents);
+      x = (x & 0xff07) | ((srel & 0x1f) << 3);
+      bfd_put_16 (input_bfd, x, contents);
+      break;
+
     default:
       r = _bfd_final_link_relocate (howto, input_bfd, input_section,
                                    contents, rel->r_offset,
index 9452d1207c6ff6451a005ef25bbb9aa07d7a8e1c..3cca8c9a55c16d9105e545f63c51ef27d91d65fe 100644 (file)
@@ -2042,6 +2042,8 @@ static const char *const bfd_reloc_code_real_names[] = { "@@uninitialized@@",
   "BFD_RELOC_AVR_DIFF16",
   "BFD_RELOC_AVR_DIFF32",
   "BFD_RELOC_AVR_LDS_STS_16",
+  "BFD_RELOC_AVR_PORT6",
+  "BFD_RELOC_AVR_PORT5",
   "BFD_RELOC_RL78_NEG8",
   "BFD_RELOC_RL78_NEG16",
   "BFD_RELOC_RL78_NEG24",
index 9a7796673df2deda92a1304527d607789dd9cc39..86ff2cd7a203f0bd492f66d132e5eb2effb4f3f9 100644 (file)
@@ -4794,6 +4794,16 @@ ENUM
 ENUMDOC
   This is a 7 bit reloc for the AVR that stores SRAM address for 16bit
   lds and sts instructions supported only tiny core.
+ENUM
+  BFD_RELOC_AVR_PORT6
+ENUMDOC
+  This is a 6 bit reloc for the AVR that stores an I/O register
+  number for the IN and OUT instructions
+ENUM
+  BFD_RELOC_AVR_PORT5
+ENUMDOC
+  This is a 5 bit reloc for the AVR that stores an I/O register
+  number for the SBIC, SBIS, SBI and CBI instructions
 ENUM
   BFD_RELOC_RL78_NEG8
 ENUMX
index f2f25f2d3a6829beb2e44ae00a9ce00c74606903..ec38771daa3eadfaa16a0d80b43777158e92af88 100644 (file)
@@ -1,3 +1,12 @@
+2014-07-07  Barney Stratford  <barney_stratford@fastmail.fm>
+
+       * config/tc-avr.c (avr_operand): Permit referring to r26-r31 by
+       name as [xyz][hl].  Permit using a symbol whoes name begins with
+       â€˜r’ to refer to a register.
+       Allow arbitrary expressions for the P and p operators.
+       (md_apply_fix): Check the BFD_RELOC_AVR_PORT5 and
+       BFD_RELOC_AVR_PORT6 relocations.
+
 2014-07-04  Alan Modra  <amodra@gmail.com>
 
        * doc/internals.texi: Update "configure.in" comments.
index 9ed7de8a54cebae4da34afccdaa72216d1dc8561..dfe66c68a72cd342b2c0ec3a53695df3251198af 100644 (file)
@@ -345,8 +345,8 @@ struct avr_opt_s
   int all_opcodes;  /* -mall-opcodes: accept all known AVR opcodes.  */
   int no_skip_bug;  /* -mno-skip-bug: no warnings for skipping 2-word insns.  */
   int no_wrap;      /* -mno-wrap: reject rjmp/rcall with 8K wrap-around.  */
-  int link_relax;   /* -mlink-relax: generate relocations for linker 
-                       relaxation. */
+  int link_relax;   /* -mlink-relax: generate relocations for linker
+                       relaxation.  */
 };
 
 static struct avr_opt_s avr_opt = { 0, 0, 0, 0 };
@@ -861,27 +861,40 @@ avr_operand (struct avr_opcodes_s *opcode,
     case 'r':
     case 'a':
     case 'v':
-      if (*str == 'r' || *str == 'R')
-        {
-          char r_name[20];
+      {
+        char * old_str = str;
+        char *lower;
+        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;
-        }
+        str = extract_word (str, r_name, sizeof (r_name));
+        for (lower = r_name; *lower; ++lower)
+         {
+           if (*lower >= 'A' && *lower <= 'Z')
+             *lower += 'a' - 'A';
+          }
+
+        if (r_name[0] == 'r' && ISDIGIT (r_name[1]) && r_name[2] == 0)
+          /* Single-digit register number, ie r0-r9.  */
+          op_mask = r_name[1] - '0';
+        else if (r_name[0] == 'r' && ISDIGIT (r_name[1])
+                && ISDIGIT (r_name[2]) && r_name[3] == 0)
+          /* Double-digit register number, ie r10 - r32.  */
+          op_mask = (r_name[1] - '0') * 10 + r_name[2] - '0';
+        else if (r_name[0] >= 'x' && r_name[0] <= 'z'
+                && (r_name[1] == 'l' || r_name[1] == 'h') && r_name[2] == 0)
+          /* Registers r26-r31 referred to by name, ie xl, xh, yl, yh, zl, zh.  */
+          op_mask = (r_name[0] - 'x') * 2 + (r_name[1] == 'h') + 26;
+        else if ((*op == 'v' || *op == 'w')
+                && r_name[0] >= 'x' && r_name[0] <= 'z' && r_name[1] == 0)
+          /* For the movw and addiw instructions, refer to registers x, y and z by name.  */
+          op_mask = (r_name[0] - 'x') * 2 + 26;
+        else
+          {
+            /* Numeric or symbolic constant register number.  */
+            op_mask = avr_get_constant (old_str, 31);
+            str = input_line_pointer;
+          }
+      }
 
       if (avr_mcu->mach == bfd_mach_avrtiny)
         {
@@ -1080,23 +1093,15 @@ avr_operand (struct avr_opcodes_s *opcode,
       break;
 
     case 'P':
-      {
-       unsigned int x;
-
-       x = avr_get_constant (str, 63);
-       str = input_line_pointer;
-       op_mask |= (x & 0xf) | ((x & 0x30) << 5);
-      }
+      str = parse_exp (str, &op_expr);
+      fix_new_exp (frag_now, where, opcode->insn_size * 2,
+                    &op_expr, FALSE, BFD_RELOC_AVR_PORT6);
       break;
 
     case 'p':
-      {
-       unsigned int x;
-
-       x = avr_get_constant (str, 31);
-       str = input_line_pointer;
-       op_mask |= x << 3;
-      }
+      str = parse_exp (str, &op_expr);
+      fix_new_exp (frag_now, where, opcode->insn_size * 2,
+                    &op_expr, FALSE, BFD_RELOC_AVR_PORT5);
       break;
 
     case 'E':
@@ -1237,7 +1242,7 @@ relaxable_section (asection *sec)
   return (sec->flags & SEC_DEBUGGING) == 0;
 }
 
-/* Does whatever the xtensa port does. */
+/* Does whatever the xtensa port does.  */
 int
 avr_validate_fix_sub (fixS *fix)
 {
@@ -1267,7 +1272,7 @@ avr_validate_fix_sub (fixS *fix)
 
 /* If linkrelax is turned on, and the symbol to relocate
    against is in a relaxable segment, don't compute the value -
-   generate a relocation instead. */
+   generate a relocation instead.  */
 int
 avr_force_relocation (fixS *fix)
 {
@@ -1310,8 +1315,8 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg)
          expression. fixP->fx_addsy holds the section start symbol,
          fixP->fx_offset holds sym2's offset, and fixP->fx_subsy
          holds sym1. Calculate the current difference and write value,
-         but leave fx_offset as is - during relaxation, 
-         fx_offset - value gives sym1's value */
+         but leave fx_offset as is - during relaxation,
+         fx_offset - value gives sym1's value */
 
        switch (fixP->fx_r_type)
          {
@@ -1340,7 +1345,7 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg)
 
   /* For the DIFF relocs, write the value into the object file while still
      keeping fx_done FALSE, as both the difference (recorded in the object file)
-     and the sym offset (part of fixP) are needed at link relax time */
+     and the sym offset (part of fixP) are needed at link relax time */
   where = (unsigned char *) fixP->fx_frag->fr_literal + fixP->fx_where;
   switch (fixP->fx_r_type)
     {
@@ -1548,6 +1553,20 @@ md_apply_fix (fixS *fixP, valueT * valP, segT seg)
          as_fatal (_("line %d: unknown relocation type: 0x%x"),
                    fixP->fx_line, fixP->fx_r_type);
          break;
+
+       case BFD_RELOC_AVR_PORT6:
+         if (value > 63)
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         _("operand out of range: %ld"), value);
+         bfd_putl16 ((bfd_vma) insn | ((value & 0x30) << 5) | (value & 0x0f), where);
+         break;
+
+       case BFD_RELOC_AVR_PORT5:
+         if (value > 31)
+           as_bad_where (fixP->fx_file, fixP->fx_line,
+                         _("operand out of range: %ld"), value);
+         bfd_putl16 ((bfd_vma) insn | ((value & 0x1f) << 3), where);
+         break;
        }
     }
   else
@@ -1628,9 +1647,9 @@ md_assemble (char *str)
 
   if (opcode && !avr_opt.all_opcodes)
     {
-      /* Check if the instruction's ISA bit is ON in the ISA bits of the part 
+      /* Check if the instruction's ISA bit is ON in the ISA bits of the part
          specified by the user.  If not look for other instructions
-        specifications with same mnemonic who's ISA bits matches. 
+        specifications with same mnemonic who's ISA bits matches.
 
          This requires include/opcode/avr.h to have the instructions with
          same mnenomic to be specified in sequence.  */
@@ -1638,15 +1657,15 @@ md_assemble (char *str)
       while ((opcode->isa & avr_mcu->isa) != opcode->isa)
         {
           opcode++;
-     
+
           if (opcode->name && strcmp(op, opcode->name))
             {
-              as_bad (_("illegal opcode %s for mcu %s"), 
+              as_bad (_("illegal opcode %s for mcu %s"),
                       opcode->name, avr_mcu->name);
               return;
             }
         }
-    } 
+    }
 
   if (opcode == NULL)
     {
@@ -1786,10 +1805,10 @@ avr_cons_fix_new (fragS *frag,
 static bfd_boolean
 mcu_has_3_byte_pc (void)
 {
-  int mach = avr_mcu->mach; 
+  int mach = avr_mcu->mach;
 
-  return mach == bfd_mach_avr6 
-    || mach == bfd_mach_avrxmega6 
+  return mach == bfd_mach_avr6
+    || mach == bfd_mach_avrxmega6
     || mach == bfd_mach_avrxmega7;
 }
 
@@ -1813,7 +1832,7 @@ avr_allow_local_subtract (expressionS * left,
                             expressionS * right,
                             segT section)
 {
-  /* If we are not in relaxation mode, subtraction is OK. */
+  /* If we are not in relaxation mode, subtraction is OK.  */
   if (!linkrelax)
     return TRUE;
 
index 2db10e1f56578105608383830b697c40f048cfc3..35d4f4ba53e1605e129539425a988276644b1914 100644 (file)
@@ -1,3 +1,7 @@
+2014-07-07  Barney Stratford  <barney_stratford@fastmail.fm>
+
+       * avr.h: Add R_AVR_PORT5 and R_AVR_PORT6.
+
 2014-07-01  Barney Stratford   <barney_stratford@fastmail.fm>
             Senthil Kumar Selvaraj  <senthil_kumar.selvaraj@atmel.com>
             Pitchumani Sivanupandi  <pitchumani.s@atmel.com>
index 0f3ed0333eeadb694c024d072a5433ab1508b788..f2f500d49a305c36cf9d2e7cb69b456d7dfbee14 100644 (file)
@@ -85,6 +85,8 @@ START_RELOC_NUMBERS (elf_avr_reloc_type)
      RELOC_NUMBER (R_AVR_DIFF16,               31)
      RELOC_NUMBER (R_AVR_DIFF32,               32)
      RELOC_NUMBER (R_AVR_LDS_STS_16,           33)
+     RELOC_NUMBER (R_AVR_PORT6,                34)
+     RELOC_NUMBER (R_AVR_PORT5,                35)
 END_RELOC_NUMBERS (R_AVR_max)
 
 #endif /* _ELF_AVR_H */