File gcc-patch-xmega.diff of Package wrightflyer

diff -ur ../gcc-4.3.2.orig/gcc/config/avr/avr.c ./gcc/config/avr/avr.c
--- ../gcc-4.3.2.orig/gcc/config/avr/avr.c	2009-08-11 14:17:06.000000000 +0200
+++ ./gcc/config/avr/avr.c	2009-08-11 14:38:44.000000000 +0200
@@ -51,6 +51,7 @@
 static int avr_naked_function_p (tree);
 static int interrupt_function_p (tree);
 static int signal_function_p (tree);
+static int nmi_function_p (tree);
 static int avr_OS_task_function_p (tree);
 static int avr_regs_to_save (HARD_REG_SET *);
 static int sequent_regs_live (void);
@@ -118,17 +119,24 @@
 int avr_have_movw_lpmx_p = 0;
 
 static const struct base_arch_s avr_arch_types[] = {
-  { 1, 0, 0, 0, 0, 0, 0, 0, NULL },  /* unknown device specified */
-  { 1, 0, 0, 0, 0, 0, 0, 0, "__AVR_ARCH__=1"   },
-  { 0, 0, 0, 0, 0, 0, 0, 0, "__AVR_ARCH__=2"   },
-  { 0, 0, 0, 1, 0, 0, 0, 0, "__AVR_ARCH__=25"  },
-  { 0, 0, 1, 0, 0, 0, 0, 0, "__AVR_ARCH__=3"   },
-  { 0, 0, 1, 0, 1, 0, 0, 0, "__AVR_ARCH__=31"  },
-  { 0, 0, 1, 1, 0, 0, 0, 0, "__AVR_ARCH__=35"  },
-  { 0, 1, 0, 1, 0, 0, 0, 0, "__AVR_ARCH__=4"   },
-  { 0, 1, 1, 1, 0, 0, 0, 0, "__AVR_ARCH__=5"   },
-  { 0, 1, 1, 1, 1, 1, 0, 0, "__AVR_ARCH__=51"  },
-  { 0, 1, 1, 1, 1, 1, 1, 0, "__AVR_ARCH__=6"   }
+  { 1, 0, 0, 0, 0, 0, 0, 0, 0, NULL },  /* Unknown device specified.  */
+  { 1, 0, 0, 0, 0, 0, 0, 0, 0, "__AVR_ARCH__=1"   },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, "__AVR_ARCH__=2"   },
+  { 0, 0, 0, 1, 0, 0, 0, 0, 0, "__AVR_ARCH__=25"  },
+  { 0, 0, 1, 0, 0, 0, 0, 0, 0, "__AVR_ARCH__=3"   },
+  { 0, 0, 1, 0, 1, 0, 0, 0, 0, "__AVR_ARCH__=31"  },
+  { 0, 0, 1, 1, 0, 0, 0, 0, 0, "__AVR_ARCH__=35"  },
+  { 0, 1, 0, 1, 0, 0, 0, 0, 0, "__AVR_ARCH__=4"   },
+  { 0, 1, 1, 1, 0, 0, 0, 0, 0, "__AVR_ARCH__=5"   },
+  { 0, 1, 1, 1, 1, 1, 0, 0, 0, "__AVR_ARCH__=51"  },
+  { 0, 1, 1, 1, 1, 1, 1, 0, 0, "__AVR_ARCH__=6"   },
+  { 0, 1, 0, 1, 0, 0, 0, 1, 0, "__AVR_ARCH__=101" },
+  { 0, 1, 1, 1, 0, 0, 0, 1, 0, "__AVR_ARCH__=102" },
+  { 0, 1, 1, 1, 0, 0, 0, 1, 1, "__AVR_ARCH__=103" },
+  { 0, 1, 1, 1, 1, 1, 0, 1, 0, "__AVR_ARCH__=104" },
+  { 0, 1, 1, 1, 1, 1, 0, 1, 1, "__AVR_ARCH__=105" },
+  { 0, 1, 1, 1, 1, 1, 1, 1, 0, "__AVR_ARCH__=106" },  
+  { 0, 1, 1, 1, 1, 1, 1, 1, 1, "__AVR_ARCH__=107" }
 };
 
 /* These names are used as the index into the avr_arch_types[] table 
@@ -146,7 +154,14 @@
   ARCH_AVR4,
   ARCH_AVR5,
   ARCH_AVR51,
-  ARCH_AVR6
+  ARCH_AVR6,
+  ARCH_AVRXMEGA1,
+  ARCH_AVRXMEGA2,
+  ARCH_AVRXMEGA3,
+  ARCH_AVRXMEGA4,
+  ARCH_AVRXMEGA5,
+  ARCH_AVRXMEGA6,
+  ARCH_AVRXMEGA7
 };
 
 struct mcu_type_s {
@@ -297,6 +312,26 @@
   { "avr6",         ARCH_AVR6, NULL },
   { "atmega2560",   ARCH_AVR6, "__AVR_ATmega2560__" },
   { "atmega2561",   ARCH_AVR6, "__AVR_ATmega2561__" },
+    /* Enhanced, == 256K.  */
+    /* Xmega, <= 8K FLASH.  */
+    /* Xmega, > 8K, <= 64K FLASH, <= 64K RAM.  */
+    /* Xmega, > 8K, <= 64K FLASH, > 64K RAM.  */
+  { "avrxmega3",    ARCH_AVRXMEGA3, NULL },
+  { "atxmega32a4",  ARCH_AVRXMEGA3, "__AVR_ATxmega32A4__" },
+    /* Xmega, > 64K, <= 128K FLASH, <= 64K RAM.  */
+  { "avrxmega4",    ARCH_AVRXMEGA4, NULL },
+  { "atxmega64a3",  ARCH_AVRXMEGA4, "__AVR_ATxmega64A3__" },
+    /* Xmega, > 64K, <= 128K FLASH, > 64K RAM.  */
+  { "avrxmega5",    ARCH_AVRXMEGA5, NULL },
+  { "atxmega64a1",  ARCH_AVRXMEGA5, "__AVR_ATxmega64A1__" },
+    /* Xmega, > 128K, <= 256K FLASH, <= 64K RAM.  */
+  { "avrxmega6",    ARCH_AVRXMEGA6, NULL },
+  { "atxmega128a3", ARCH_AVRXMEGA6, "__AVR_ATxmega128A3__" },
+  { "atxmega256a3", ARCH_AVRXMEGA6, "__AVR_ATxmega256A3__" },
+  { "atxmega256a3b",ARCH_AVRXMEGA6, "__AVR_ATxmega256A3B__" },
+    /* Xmega, > 128K, <= 256K FLASH, > 64K RAM.  */
+  { "avrxmega7",    ARCH_AVRXMEGA7, NULL },
+  { "atxmega128a1", ARCH_AVRXMEGA7, "__AVR_ATxmega128A1__" },
     /* Assembler only.  */
   { "avr1",         ARCH_AVR1, NULL },
   { "at90s1200",    ARCH_AVR1, "__AVR_AT90S1200__" },
@@ -470,6 +505,21 @@
   return a != NULL_TREE;
 }
 
+/* Return nonzero if FUNC is a nmi function as specified
+   by the "nmi" attribute.  */
+
+static int
+nmi_function_p (tree func)
+{
+  tree a;
+
+  if (TREE_CODE (func) != FUNCTION_DECL)
+    return 0;
+
+  a = lookup_attribute ("nmi", DECL_ATTRIBUTES (func));
+  return a != NULL_TREE;
+}
+
 /* Return nonzero if FUNC is a OS_task function.  */
 
 static int
@@ -629,6 +679,7 @@
   cfun->machine->is_naked = avr_naked_function_p (current_function_decl);
   cfun->machine->is_interrupt = interrupt_function_p (current_function_decl);
   cfun->machine->is_signal = signal_function_p (current_function_decl);
+  cfun->machine->is_nmi = nmi_function_p (current_function_decl);
   cfun->machine->is_OS_task = avr_OS_task_function_p (current_function_decl);
   
   /* Prologue: naked.  */
@@ -664,20 +715,78 @@
 
       /* Push SREG.  */
       insn = emit_move_insn (tmp_reg_rtx, 
-                             gen_rtx_MEM (QImode, GEN_INT (SREG_ADDR)));
+                             gen_rtx_MEM (QImode, GEN_INT (AVR_SREG_ADDR)));
       RTX_FRAME_RELATED_P (insn) = 1;
       insn = emit_move_insn (pushbyte, tmp_reg_rtx);
       RTX_FRAME_RELATED_P (insn) = 1;
 
+      /* Push RAMPD, RAMPX, RAMPY. */
+      if (AVR_HAVE_RAMPX_Y_D)
+        {
+          /* Push RAMPD. */
+          insn = emit_move_insn (tmp_reg_rtx, 
+                                 gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPD_ADDR)));
+          RTX_FRAME_RELATED_P (insn) = 1;
+          insn = emit_move_insn (pushbyte, tmp_reg_rtx);
+          RTX_FRAME_RELATED_P (insn) = 1;
+
+          /* Set RAMPD to 0. */
+          insn = emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPD_ADDR)),
+                                 const0_rtx);
+          RTX_FRAME_RELATED_P (insn) = 1;
+
+          /* Push RAMPX. */
+          if (TEST_HARD_REG_BIT (set, REG_X) && TEST_HARD_REG_BIT (set, REG_X + 1))
+            {
+              insn = emit_move_insn (tmp_reg_rtx, 
+                                     gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPX_ADDR)));
+              RTX_FRAME_RELATED_P (insn) = 1;
+              insn = emit_move_insn (pushbyte, tmp_reg_rtx);
+              RTX_FRAME_RELATED_P (insn) = 1;
+
+              /* Set RAMPX to 0. */
+              insn = emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPX_ADDR)),
+                                     const0_rtx);
+              RTX_FRAME_RELATED_P (insn) = 1;
+            }
+
+          /* Push RAMPY. */
+          if (TEST_HARD_REG_BIT (set, REG_Y) && TEST_HARD_REG_BIT (set, REG_Y + 1))
+            {
+              insn = emit_move_insn (tmp_reg_rtx, 
+                                     gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPY_ADDR)));
+              RTX_FRAME_RELATED_P (insn) = 1;
+              insn = emit_move_insn (pushbyte, tmp_reg_rtx);
+              RTX_FRAME_RELATED_P (insn) = 1;
+
+              /* Set RAMPY to 0. */
+              insn = emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPY_ADDR)),
+                                     const0_rtx);
+              RTX_FRAME_RELATED_P (insn) = 1;
+            }
+        }
+
       /* Push RAMPZ.  */
       if(AVR_HAVE_RAMPZ 
          && (TEST_HARD_REG_BIT (set, REG_Z) && TEST_HARD_REG_BIT (set, REG_Z + 1)))
         {
           insn = emit_move_insn (tmp_reg_rtx, 
-                                 gen_rtx_MEM (QImode, GEN_INT (RAMPZ_ADDR)));
+                                 gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPZ_ADDR)));
           RTX_FRAME_RELATED_P (insn) = 1;
           insn = emit_move_insn (pushbyte, tmp_reg_rtx);
           RTX_FRAME_RELATED_P (insn) = 1;
+
+          /* 
+          Clearing the RAMPZ register is needed only if it is used for data
+          space access.
+          */
+          if (AVR_HAVE_RAMPX_Y_D)
+            {
+              /* Set RAMPZ to 0. */
+              insn = emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPZ_ADDR)),
+                                 const0_rtx);
+              RTX_FRAME_RELATED_P (insn) = 1;
+            }
         }
 	
       /* Clear zero reg.  */
@@ -949,14 +1058,39 @@
              && (TEST_HARD_REG_BIT (set, REG_Z) && TEST_HARD_REG_BIT (set, REG_Z + 1)))
             {
 	      emit_insn (gen_popqi (tmp_reg_rtx));
-	      emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(RAMPZ_ADDR)), 
+	      emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(AVR_RAMPZ_ADDR)), 
 			      tmp_reg_rtx);
 	    }
 
+          /* Restore RAMPY, RAMPX, RAMPD using tmp reg as scratch. */
+          if (AVR_HAVE_RAMPX_Y_D)
+            {
+              /* Pop RAMPY. */
+              if (TEST_HARD_REG_BIT (set, REG_Y) && TEST_HARD_REG_BIT (set, REG_Y + 1))
+                {
+                  emit_insn (gen_popqi (tmp_reg_rtx));
+                  emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPY_ADDR)),
+                                  tmp_reg_rtx);
+                }
+
+              /* Pop RAMPX. */
+              if (TEST_HARD_REG_BIT (set, REG_X) && TEST_HARD_REG_BIT (set, REG_X + 1))
+                {
+                  emit_insn (gen_popqi (tmp_reg_rtx));
+                  emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPX_ADDR)),
+                                  tmp_reg_rtx);
+                }
+
+              /* Pop RAMPD. */
+              emit_insn (gen_popqi (tmp_reg_rtx));
+              emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPD_ADDR)),
+                              tmp_reg_rtx);
+            }
+
           /* Restore SREG using tmp reg as scratch.  */
           emit_insn (gen_popqi (tmp_reg_rtx));
       
-          emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(SREG_ADDR)), 
+          emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(AVR_SREG_ADDR)), 
 			  tmp_reg_rtx);
 
           /* Restore tmp REG.  */
@@ -1725,8 +1859,9 @@
 		}
               /*  Use simple load of stack pointer if no interrupts are used
               or inside main or signal function prologue where they disabled.  */
-	      else if (TARGET_NO_INTERRUPTS 
-                        || (reload_completed 
+	      else if (TARGET_NO_INTERRUPTS
+                        || (!AVR_XMEGA
+			    && reload_completed 
                             && cfun->machine->is_signal 
                             && prologue_epilogue_contains (insn)))
                 {
@@ -1735,7 +1870,8 @@
                           AS2 (out,__SP_L__,%A1));
                 }
               /*  In interrupt prolog we know interrupts are enabled.  */
-              else if (reload_completed 
+              else if (!AVR_XMEGA
+			&& reload_completed 
                         && cfun->machine->is_interrupt
                         && prologue_epilogue_contains (insn))
                 {
@@ -1745,12 +1881,21 @@
                            "sei"                   CR_TAB
                            AS2 (out,__SP_L__,%A1));
                 }
-	      *l = 5;
-	      return (AS2 (in,__tmp_reg__,__SREG__)  CR_TAB
-		      "cli"                          CR_TAB
-		      AS2 (out,__SP_H__,%B1)         CR_TAB
-		      AS2 (out,__SREG__,__tmp_reg__) CR_TAB
-		      AS2 (out,__SP_L__,%A1));
+	      if(AVR_XMEGA)
+	        {
+		  *l = 2;
+		  return (AS2 (out,__SP_L__,%A1)  CR_TAB
+			  AS2 (out,__SP_H__,%B1));
+		}
+	      else
+	        {
+		  *l = 5;
+		  return (AS2 (in,__tmp_reg__,__SREG__)  CR_TAB
+			  "cli"                          CR_TAB
+			  AS2 (out,__SP_H__,%B1)         CR_TAB
+			  AS2 (out,__SREG__,__tmp_reg__) CR_TAB
+			  AS2 (out,__SP_L__,%A1));
+		}
 	    }
 	  else if (test_hard_reg_class (STACK_REG, src))
 	    {
@@ -1885,7 +2030,7 @@
   
   if (CONSTANT_ADDRESS_P (x))
     {
-      if (CONST_INT_P (x) && INTVAL (x) == SREG_ADDR)
+      if (CONST_INT_P (x) && INTVAL (x) == AVR_SREG_ADDR)
 	{
 	  *l = 1;
 	  return AS2 (in,%0,__SREG__);
@@ -1893,7 +2038,8 @@
       if (avr_io_address_p (x, 1))
 	{
 	  *l = 1;
-	  return AS2 (in,%0,%1-0x20);
+	  op[2] = GEN_INT(AVR_IO_OFFSET);
+	  return AS2 (in,%0,%1-%2);
 	}
       *l = 2;
       return AS2 (lds,%0,%1);
@@ -2081,8 +2227,9 @@
       if (avr_io_address_p (base, 2))
 	{
 	  *l = 2;
-	  return (AS2 (in,%A0,%A1-0x20) CR_TAB
-		  AS2 (in,%B0,%B1-0x20));
+	  op[2] = GEN_INT(AVR_IO_OFFSET);
+	  return (AS2 (in,%A0,%A1-%2) CR_TAB
+		  AS2 (in,%B0,%B1-%2));
 	}
       *l = 4;
       return (AS2 (lds,%A0,%A1) CR_TAB
@@ -2573,7 +2720,7 @@
   
   if (CONSTANT_ADDRESS_P (x))
     {
-      if (CONST_INT_P (x) && INTVAL (x) == SREG_ADDR)
+      if (CONST_INT_P (x) && INTVAL (x) == AVR_SREG_ADDR)
 	{
 	  *l = 1;
 	  return AS2 (out,__SREG__,%1);
@@ -2581,7 +2728,8 @@
       if (avr_io_address_p (x, 1))
 	{
 	  *l = 1;
-	  return AS2 (out,%0-0x20,%1);
+	  op[2] = GEN_INT(AVR_IO_OFFSET);
+	  return AS2 (out,%0-%2,%1);
 	}
       *l = 2;
       return AS2 (sts,%0,%1);
@@ -2660,11 +2808,20 @@
       if (avr_io_address_p (base, 2))
 	{
 	  *l = 2;
-	  return (AS2 (out,%B0-0x20,%B1) CR_TAB
-		  AS2 (out,%A0-0x20,%A1));
+	  op[2] = GEN_INT(AVR_IO_OFFSET);
+          if (AVR_XMEGA)
+	    return (AS2 (out,%A0-%2,%A1) CR_TAB
+		    AS2 (out,%B0-%2,%B1));
+	  else
+	    return (AS2 (out,%B0-%2,%B1) CR_TAB
+		    AS2 (out,%A0-%2,%A1));
 	}
-      return *l = 4, (AS2 (sts,%B0,%B1) CR_TAB
-		      AS2 (sts,%A0,%A1));
+      if (AVR_XMEGA)
+        return *l = 4, (AS2 (sts,%A0,%A1) CR_TAB
+			AS2 (sts,%B0,%B1));
+      else
+        return *l = 4, (AS2 (sts,%B0,%B1) CR_TAB
+			AS2 (sts,%A0,%A1));
     }
   if (reg_base > 0)
     {
@@ -2679,11 +2836,20 @@
 			      AS2 (adiw,r26,1)          CR_TAB
 			      AS2 (st,X,__tmp_reg__));
               else
-		return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB
-			      AS2 (adiw,r26,1)          CR_TAB
-			      AS2 (st,X,__tmp_reg__)    CR_TAB
-                              AS2 (sbiw,r26,1)          CR_TAB
-                              AS2 (st,X,r26));
+	        {
+                  if (!AVR_XMEGA)
+		    return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB
+			          AS2 (adiw,r26,1)          CR_TAB
+			          AS2 (st,X,__tmp_reg__)    CR_TAB
+                                  AS2 (sbiw,r26,1)          CR_TAB
+                                  AS2 (st,X,r26));
+		  else
+ 		    return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB
+			          AS2 (st,X,r26)            CR_TAB
+ 			          AS2 (adiw,r26,1)          CR_TAB
+ 			          AS2 (st,X,__tmp_reg__)    CR_TAB
+			          AS2 (sbiw,r26,1));
+		}
             }
           else
             {
@@ -2691,14 +2857,27 @@
                 return *l=2, (AS2 (st,X+,%A1) CR_TAB
                               AS2 (st,X,%B1));
               else
-                return *l=3, (AS2 (adiw,r26,1) CR_TAB
-                              AS2 (st,X,%B1)   CR_TAB
-                              AS2 (st,-X,%A1));
+		{
+                  if (!AVR_XMEGA)
+                    return *l=3, (AS2 (adiw,r26,1) CR_TAB
+                                  AS2 (st,X,%B1)   CR_TAB
+                                  AS2 (st,-X,%A1));
+	          else
+                    return *l=3, (AS2 (st,X+,%A1) CR_TAB
+                                  AS2 (st,X,%B1) CR_TAB
+                                  AS2 (sbiw,r26,1));
+		}
             }
         }
       else
-        return  *l=2, (AS2 (std,%0+1,%B1) CR_TAB
-                       AS2 (st,%0,%A1));
+        {
+	  if (!AVR_XMEGA)
+            return  *l=2, (AS2 (std,%0+1,%B1) CR_TAB
+                           AS2 (st,%0,%A1));
+	  else
+            return  *l=2, (AS2 (st,%0,%A1)    CR_TAB
+                           AS2 (std,%0+1,%B1));
+        }
     }
   else if (GET_CODE (base) == PLUS)
     {
@@ -2709,48 +2888,104 @@
 	  if (reg_base != REG_Y)
 	    fatal_insn ("incorrect insn:",insn);
 
-	  if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
-	    return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB
-			    AS2 (std,Y+63,%B1)    CR_TAB
-			    AS2 (std,Y+62,%A1)    CR_TAB
-			    AS2 (sbiw,r28,%o0-62));
-
-	  return *l = 6, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
-			  AS2 (sbci,r29,hi8(-%o0)) CR_TAB
-			  AS2 (std,Y+1,%B1)        CR_TAB
-			  AS2 (st,Y,%A1)           CR_TAB
-			  AS2 (subi,r28,lo8(%o0))  CR_TAB
-			  AS2 (sbci,r29,hi8(%o0)));
+          if (!AVR_XMEGA)
+            {
+	      if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
+	        return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB
+			        AS2 (std,Y+63,%B1)    CR_TAB
+			        AS2 (std,Y+62,%A1)    CR_TAB
+			        AS2 (sbiw,r28,%o0-62));
+
+	      return *l = 6, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
+			      AS2 (sbci,r29,hi8(-%o0)) CR_TAB
+			      AS2 (std,Y+1,%B1)        CR_TAB
+			      AS2 (st,Y,%A1)           CR_TAB
+			      AS2 (subi,r28,lo8(%o0))  CR_TAB
+			      AS2 (sbci,r29,hi8(%o0)));
+            }
+	  else
+	    {
+ 	      if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest)))
+ 	        return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB
+			        AS2 (std,Y+62,%A1)    CR_TAB
+ 			        AS2 (std,Y+63,%B1)    CR_TAB
+ 			        AS2 (sbiw,r28,%o0-62));
+ 
+ 	      return *l = 6, (AS2 (subi,r28,lo8(-%o0)) CR_TAB
+ 			      AS2 (sbci,r29,hi8(-%o0)) CR_TAB
+			      AS2 (st,Y,%A1)           CR_TAB
+ 			      AS2 (std,Y+1,%B1)        CR_TAB
+ 			      AS2 (subi,r28,lo8(%o0))  CR_TAB
+ 			      AS2 (sbci,r29,hi8(%o0)));
+ 	    }
 	}
       if (reg_base == REG_X)
 	{
 	  /* (X + d) = R */
 	  if (reg_src == REG_X)
             {
-	      *l = 7;
-	      return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
-		      AS2 (mov,__zero_reg__,r27) CR_TAB
-                      AS2 (adiw,r26,%o0+1)       CR_TAB
-		      AS2 (st,X,__zero_reg__)    CR_TAB
-		      AS2 (st,-X,__tmp_reg__)    CR_TAB
-		      AS1 (clr,__zero_reg__)     CR_TAB
+	      if (!AVR_XMEGA)
+	        {
+	          *l = 7; 
+	          return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
+		          AS2 (mov,__zero_reg__,r27) CR_TAB
+                          AS2 (adiw,r26,%o0+1)       CR_TAB
+		          AS2 (st,X,__zero_reg__)    CR_TAB
+		          AS2 (st,-X,__tmp_reg__)    CR_TAB
+		          AS1 (clr,__zero_reg__)     CR_TAB
+                          AS2 (sbiw,r26,%o0));
+		}
+	      else
+	        {
+ 	          *l = 7;
+ 	          return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
+ 		          AS2 (mov,__zero_reg__,r27) CR_TAB
+		          AS2 (adiw,r26,%o0)         CR_TAB
+		          AS2 (st,X+,__tmp_reg__)    CR_TAB
+ 		          AS2 (st,X,__zero_reg__)    CR_TAB
+ 		          AS1 (clr,__zero_reg__)     CR_TAB
+		          AS2 (sbiw,r26,%o0+1));
+	        }
+	    }
+	  if (!AVR_XMEGA)
+            {	    
+	      *l = 4;
+              return (AS2 (adiw,r26,%o0+1) CR_TAB
+                      AS2 (st,X,%B1)       CR_TAB
+                      AS2 (st,-X,%A1)      CR_TAB
                       AS2 (sbiw,r26,%o0));
 	    }
-	  *l = 4;
-          return (AS2 (adiw,r26,%o0+1) CR_TAB
-                  AS2 (st,X,%B1)       CR_TAB
-                  AS2 (st,-X,%A1)      CR_TAB
-                  AS2 (sbiw,r26,%o0));
+	  else
+	    {
+ 	      *l = 4;
+	      return (AS2 (adiw,r26,%o0) CR_TAB
+		      AS2 (st,X+,%A1)    CR_TAB
+		      AS2 (st,X,%B1)     CR_TAB
+		      AS2 (sbiw,r26,%o0+1));
+            }
 	}
-      return *l=2, (AS2 (std,%B0,%B1)    CR_TAB
-                    AS2 (std,%A0,%A1));
+	
+      if (!AVR_XMEGA)
+        return *l=2, (AS2 (std,%B0,%B1)    CR_TAB
+                      AS2 (std,%A0,%A1));
+      else
+        return *l=2, (AS2 (std,%A0,%A1)    CR_TAB
+	              AS2 (std,%B0,%B1));
     }
   else if (GET_CODE (base) == PRE_DEC) /* (--R) */
-    return *l=2, (AS2 (st,%0,%B1) CR_TAB
-		  AS2 (st,%0,%A1));
+    {
+      if (mem_volatile_p && AVR_XMEGA)
+        return *l = 4, (AS2 (sbiw,%r0,1)    CR_TAB 
+                        AS2 (st,%p0+,%A1)   CR_TAB
+                        AS2 (st,%p0,%B1)    CR_TAB
+                        AS2 (sbiw,%r0,2));
+      else
+        return *l=2, (AS2 (st,%0,%B1) CR_TAB
+		      AS2 (st,%0,%A1));
+    }
   else if (GET_CODE (base) == POST_INC) /* (R++) */
     {
-      if (mem_volatile_p)
+      if (mem_volatile_p && !AVR_XMEGA)
         {
           if (REGNO (XEXP (base, 0)) == REG_X)
             {
@@ -2771,7 +3006,7 @@
 
       *l = 2;
       return (AS2 (st,%0,%A1)  CR_TAB
-            AS2 (st,%0,%B1));
+              AS2 (st,%0,%B1));
     }
   fatal_insn ("unknown move insn:",insn);
   return "";
@@ -4651,6 +4886,7 @@
   { "progmem",   0, 0, false, false, false,  avr_handle_progmem_attribute },
   { "signal",    0, 0, true,  false, false,  avr_handle_fndecl_attribute },
   { "interrupt", 0, 0, true,  false, false,  avr_handle_fndecl_attribute },
+  { "nmi",       0, 0, true,  false, false,  avr_handle_fndecl_attribute },
   { "naked",     0, 0, false, true,  true,   avr_handle_fntype_attribute },
   { "OS_task",   0, 0, false, true,  true,   avr_handle_fntype_attribute },
   { NULL,        0, 0, false, false, false, NULL }
@@ -4739,6 +4975,14 @@
                        func_name);
             }
         }
+      else if (strncmp (attr, "nmi", strlen ("nmi")) == 0)
+        {
+          if (strncmp (func_name, "__vector", strlen ("__vector")) != 0)
+            {
+              warning (0, "%qs appears to be a misspelled nmi handler",
+                       func_name);
+            }
+        }
     }
 
   return NULL_TREE;
@@ -4864,7 +5108,8 @@
 /*  fprintf (asm_out_file, "\t.arch %s\n", avr_mcu_name);*/
   fputs ("__SREG__ = 0x3f\n"
 	 "__SP_H__ = 0x3e\n"
-	 "__SP_L__ = 0x3d\n", asm_out_file);
+	 "__SP_L__ = 0x3d\n"
+	 "__CCP__  = 0x34\n", asm_out_file);
   
   fputs ("__tmp_reg__ = 0\n" 
          "__zero_reg__ = 1\n", asm_out_file);
@@ -5754,15 +5999,18 @@
   return !(regno & 1);
 }
 
-/* Returns 1 if X is a valid address for an I/O register of size SIZE
-   (1 or 2).  Used for lds/sts -> in/out optimization.  Add 0x20 to SIZE
-   to check for the lower half of I/O space (for cbi/sbi/sbic/sbis).  */
+/* Returns 1 if X is a valid address for an I/O register of size SIZE 
+   (1 or 2).  Used for lds/sts -> in/out optimization.  */
 
 int
 avr_io_address_p (rtx x, int size)
 {
-  return (optimize > 0 && GET_CODE (x) == CONST_INT
-	  && INTVAL (x) >= 0x20 && INTVAL (x) <= 0x60 - size);
+  if(AVR_XMEGA)
+    return (optimize > 0 && GET_CODE (x) == CONST_INT
+	    && INTVAL (x) >= 0 && INTVAL (x) <= 0x40 - size);
+  else
+    return (optimize > 0 && GET_CODE (x) == CONST_INT
+	    && INTVAL (x) >= 0x20 && INTVAL (x) <= 0x60 - size);
 }
 
 const char *
@@ -5940,16 +6188,17 @@
 
   if (GET_CODE (operands[1]) == CONST_INT)
     {
-      if (INTVAL (operands[1]) < 0x40)
+      operands[4] = GEN_INT(AVR_IO_OFFSET); /* operands[3] is for the jump */
+      if (low_io_address_operand (operands[1], VOIDmode))
 	{
 	  if (comp == EQ)
-	    output_asm_insn (AS2 (sbis,%1-0x20,%2), operands);
+	    output_asm_insn (AS2 (sbis,%1-%4,%2), operands);
 	  else
-	    output_asm_insn (AS2 (sbic,%1-0x20,%2), operands);
+	    output_asm_insn (AS2 (sbic,%1-%4,%2), operands);
 	}
       else
 	{
-	  output_asm_insn (AS2 (in,__tmp_reg__,%1-0x20), operands);
+	  output_asm_insn (AS2 (in,__tmp_reg__,%1-%4), operands);
 	  if (comp == EQ)
 	    output_asm_insn (AS2 (sbrs,__tmp_reg__,%2), operands);
 	  else
diff -ur ../gcc-4.3.2.orig/gcc/config/avr/avr.h ./gcc/config/avr/avr.h
--- ../gcc-4.3.2.orig/gcc/config/avr/avr.h	2009-08-11 14:17:06.000000000 +0200
+++ ./gcc/config/avr/avr.h	2009-08-11 14:40:01.000000000 +0200
@@ -44,8 +44,11 @@
   /* Core have 'EICALL' and 'EIJMP' instructions.  */
   int have_eijmp_eicall;
 
-  /* Reserved. */
-  int reserved;
+  /* Core is in Xmega family.  */
+  int xmega;
+
+  /* Core have RAMPX, RAMPY and RAMPD registers.  */
+  int have_rampx_y_d;
   
   const char *const macro;
 };
@@ -68,6 +71,13 @@
 	builtin_define ("__AVR_HAVE_ELPMX__");	\
       if (avr_have_movw_lpmx_p)			\
 	builtin_define ("__AVR_HAVE_MOVW__");	\
+      if (avr_current_arch->have_elpm)		\
+        {					\
+	  builtin_define ("__AVR_HAVE_RAMPZ__");\
+	  builtin_define ("__AVR_HAVE_ELPM__");	\
+	}					\
+      if (avr_current_arch->have_elpmx)		\
+	builtin_define ("__AVR_HAVE_ELPMX__");	\
       if (avr_have_movw_lpmx_p)			\
 	builtin_define ("__AVR_HAVE_LPMX__");	\
       if (avr_asm_only_p)			\
@@ -88,6 +98,17 @@
 	builtin_define ("__AVR_HAVE_EIJMP_EICALL__"); \
       if (TARGET_NO_INTERRUPTS)			\
 	builtin_define ("__NO_INTERRUPTS__");	\
+      if (avr_current_arch->xmega)              \
+	{					\
+	  builtin_define ("__AVR_XMEGA__");     \
+	  builtin_define ("__AVR_HAVE_SPMX__"); \
+	}					\
+      if (avr_current_arch->have_rampx_y_d)     \
+	{					\
+	  builtin_define ("__AVR_HAVE_RAMPX__");\
+	  builtin_define ("__AVR_HAVE_RAMPY__");\
+	  builtin_define ("__AVR_HAVE_RAMPD__");\
+	}					\
     }						\
   while (0)
 
@@ -107,10 +128,19 @@
 #define AVR_HAVE_LPMX (avr_have_movw_lpmx_p)
 #define AVR_HAVE_RAMPZ (avr_current_arch->have_elpm)
 #define AVR_HAVE_EIJMP_EICALL (avr_current_arch->have_eijmp_eicall)
+#define AVR_XMEGA (avr_current_arch->xmega)
+#define AVR_HAVE_RAMPX_Y_D (avr_current_arch->have_rampx_y_d)
 
 #define AVR_2_BYTE_PC (!AVR_HAVE_EIJMP_EICALL)
 #define AVR_3_BYTE_PC (AVR_HAVE_EIJMP_EICALL)
 
+#define AVR_IO_OFFSET (AVR_XMEGA ? 0 : 0x20)
+#define AVR_RAMPD_ADDR (AVR_XMEGA ? 0x38 : 0)
+#define AVR_RAMPX_ADDR (AVR_XMEGA ? 0x39 : 0)
+#define AVR_RAMPY_ADDR (AVR_XMEGA ? 0x3A : 0)
+#define AVR_RAMPZ_ADDR (AVR_XMEGA ? 0x3B : 0x5B)
+#define AVR_SREG_ADDR (AVR_XMEGA ? 0x3F: 0x5F)
+
 #define TARGET_VERSION fprintf (stderr, " (GNU assembler syntax)");
 
 #define OVERRIDE_OPTIONS avr_override_options ()
@@ -848,6 +878,12 @@
   mmcu=m3000*|\
   mmcu=m3001*: -m avr5}\
 %{mmcu=atmega256*:-m avr6}\
+%{mmcu=atxmega32a4:-m avrxmega3} \
+%{mmcu=atxmega64a3:-m avrxmega4} \
+%{mmcu=atxmega64a1:-m avrxmega5} \
+%{mmcu=atxmega128a3| \
+  mmcu=atxmega256a3*:-m avrxmega6} \
+%{mmcu=atxmega128a1:-m avrxmega7} \
 %{mmcu=atmega324*|\
   mmcu=atmega325*|\
   mmcu=atmega328p|\
@@ -1024,7 +1060,15 @@
 %{mmcu=m3000s:crtm3000s.o%s} \
 %{mmcu=m3001b:crtm3001b.o%s} \
 %{mmcu=atmega2560|mmcu=avr6:crtm2560.o%s} \
-%{mmcu=atmega2561:crtm2561.o%s}"
+%{mmcu=atmega2561:crtm2561.o%s} \
+%{mmcu=atxmega3|mmcu=atxmega32a4:crtx32a4.o%s} \
+%{mmcu=atxmega4|mmcu=atxmega64a3:crtx64a3.o%s} \
+%{mmcu=atxmega5|mmcu=atxmega64a1:crtx64a1.o%s} \
+%{mmcu=atxmega6|mmcu=atxmega128a3:crtx128a3.o%s} \
+%{mmcu=atxmega256a3:crtx256a3.o%s} \
+%{mmcu=atxmega256a3b:crtx256a3b.o%s} \
+%{mmcu=atxmega7|mmcu=atxmega128a1:crtx128a1.o%s}"
+
 
 #define EXTRA_SPECS {"crt_binutils", CRT_BINUTILS_SPECS},
 
@@ -1086,8 +1130,12 @@
   /* 'true' - if current function is a signal function 
      as specified by the "signal" attribute.  */
   int is_signal;
-  
+
   /* 'true' - if current function is a signal function 
+     as specified by the "nmi" attribute.  */
+  int is_nmi;
+  
+  /* 'true' - if current function is a task function 
      as specified by the "OS_task" attribute.  */
   int is_OS_task;
 };
diff -ur ../gcc-4.3.2.orig/gcc/config/avr/avr.md ./gcc/config/avr/avr.md
--- ../gcc-4.3.2.orig/gcc/config/avr/avr.md	2009-08-11 14:16:22.000000000 +0200
+++ ./gcc/config/avr/avr.md	2009-08-11 14:34:10.000000000 +0200
@@ -47,9 +47,6 @@
    (TMP_REGNO	0)	; temporary register r0
    (ZERO_REGNO	1)	; zero register r1
    
-   (SREG_ADDR   0x5F)
-   (RAMPZ_ADDR  0x5B)
-   
    (UNSPEC_STRLEN	0)
    (UNSPEC_INDEX_JMP	1)
    (UNSPEC_SEI		2)
@@ -2669,7 +2666,8 @@
   "(optimize > 0)"
 {
   operands[2] = GEN_INT (exact_log2 (~INTVAL (operands[1]) & 0xff));
-  return AS2 (cbi,%0-0x20,%2);
+  operands[3] = GEN_INT(AVR_IO_OFFSET);
+  return AS2 (cbi,%0-%3,%2);
 }
   [(set_attr "length" "1")
    (set_attr "cc" "none")])
@@ -2681,7 +2679,8 @@
   "(optimize > 0)"
 {
   operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1]) & 0xff));
-  return AS2 (sbi,%0-0x20,%2);
+  operands[3] = GEN_INT(AVR_IO_OFFSET);
+  return AS2 (sbi,%0-%3,%2);
 }
   [(set_attr "length" "1")
    (set_attr "cc" "none")])
diff -ur ../gcc-4.3.2.orig/gcc/config/avr/predicates.md ./gcc/config/avr/predicates.md
--- ../gcc-4.3.2.orig/gcc/config/avr/predicates.md	2007-08-02 12:49:31.000000000 +0200
+++ ./gcc/config/avr/predicates.md	2009-08-11 14:34:10.000000000 +0200
@@ -45,12 +45,16 @@
 ;; Return true if OP is a valid address for lower half of I/O space.
 (define_predicate "low_io_address_operand"
   (and (match_code "const_int")
-       (match_test "IN_RANGE((INTVAL (op)), 0x20, 0x3F)")))
+       (if_then_else (match_test "AVR_XMEGA") 
+                     (match_test "IN_RANGE((INTVAL (op)), 0x00, 0x1F)")
+	             (match_test "IN_RANGE((INTVAL (op)), 0x20, 0x3F)"))))
 
 ;; Return true if OP is a valid address for high half of I/O space.
 (define_predicate "high_io_address_operand"
   (and (match_code "const_int")
-       (match_test "IN_RANGE((INTVAL (op)), 0x40, 0x5F)")))
+       (if_then_else (match_test "AVR_XMEGA") 
+                     (match_test "IN_RANGE((INTVAL (op)), 0x20, 0x3F)")
+	             (match_test "IN_RANGE((INTVAL (op)), 0x40, 0x5F)"))))
 
 ;; Return 1 if OP is the zero constant for MODE.
 (define_predicate "const0_operand"
diff -ur ../gcc-4.3.2.orig/gcc/config/avr/t-avr ./gcc/config/avr/t-avr
--- ../gcc-4.3.2.orig/gcc/config/avr/t-avr	2009-08-11 14:17:06.000000000 +0200
+++ ./gcc/config/avr/t-avr	2009-08-11 14:39:16.000000000 +0200
@@ -37,8 +37,8 @@
 
 FPBIT = fp-bit.c
 
-MULTILIB_OPTIONS = mmcu=avr2/mmcu=avr25/mmcu=avr3/mmcu=avr31/mmcu=avr35/mmcu=avr4/mmcu=avr5/mmcu=avr51/mmcu=avr6
-MULTILIB_DIRNAMES = avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6
+MULTILIB_OPTIONS = mmcu=avr2/mmcu=avr25/mmcu=avr3/mmcu=avr31/mmcu=avr35/mmcu=avr4/mmcu=avr5/mmcu=avr51/mmcu=avr6/mmcu=avrxmega3/mmcu=avrxmega4/mmcu=avrxmega5/mmcu=avrxmega6/mmcu=avrxmega7
+MULTILIB_DIRNAMES = avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 avrxmega3 avrxmega4 avrxmega5 avrxmega6 avrxmega7
 
 # The many avr2 matches are not listed here - this is the default.
 MULTILIB_MATCHES = \
@@ -143,7 +143,15 @@
 	mmcu?avr51=mmcu?m3000s \
 	mmcu?avr51=mmcu?m3001b \
  	mmcu?avr6=mmcu?atmega2560 \
- 	mmcu?avr6=mmcu?atmega2561
+ 	mmcu?avr6=mmcu?atmega2561 \
+	mmcu?avrxmega3=mmcu?atxmega32a4 \
+	mmcu?avrxmega4=mmcu?atxmega64a3 \
+	mmcu?avrxmega5=mmcu?atxmega64a1 \
+	mmcu?avrxmega6=mmcu?atxmega128a3 \
+	mmcu?avrxmega6=mmcu?atxmega256a3 \
+	mmcu?avrxmega6=mmcu?atxmega256a3b \
+	mmcu?avrxmega7=mmcu?atxmega128a1
+
 
 MULTILIB_EXCEPTIONS =
 
openSUSE Build Service is sponsored by