diff -rwu gcc/config/avr/avr.c gcc/config/avr/avr.c
--- gcc/config/avr/avr.c	2009-08-26 00:33:53.000000000 +0530
+++ gcc/config/avr/avr.c	2010-02-11 14:47:53.913569000 +0530
@@ -52,6 +52,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_OS_main_function_p (tree);
 static int avr_regs_to_save (HARD_REG_SET *);
@@ -112,17 +113,24 @@
 section *progmem_section;
 
 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 
@@ -140,7 +148,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 {
@@ -298,6 +313,35 @@
   { "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.  */
+  { "avrxmega2",    ARCH_AVRXMEGA2, NULL },
+  { "atxmega16a4",  ARCH_AVRXMEGA2, "__AVR_ATxmega16A4__" },
+  { "atxmega16d4",  ARCH_AVRXMEGA2, "__AVR_ATxmega16D4__" },
+  { "atxmega32d4",  ARCH_AVRXMEGA2, "__AVR_ATxmega32D4__" },
+    /* 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__" },
+  { "atxmega64d3",  ARCH_AVRXMEGA4, "__AVR_ATxmega64D3__" },
+    /* 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__" },
+  { "atxmega128d3", ARCH_AVRXMEGA6, "__AVR_ATxmega128D3__" },
+  { "atxmega192a3", ARCH_AVRXMEGA6, "__AVR_ATxmega192A3__" },
+  { "atxmega192d3", ARCH_AVRXMEGA6, "__AVR_ATxmega192D3__" },
+  { "atxmega256a3", ARCH_AVRXMEGA6, "__AVR_ATxmega256A3__" },
+  { "atxmega256a3b",ARCH_AVRXMEGA6, "__AVR_ATxmega256A3B__" },
+  { "atxmega256d3", ARCH_AVRXMEGA6, "__AVR_ATxmega256D3__" },
+    /* 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__" },
@@ -486,6 +530,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
@@ -684,6 +743,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);
   cfun->machine->is_OS_main = avr_OS_main_function_p (current_function_decl);
   
@@ -721,17 +781,48 @@
 
       /* 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;
+
+          /* 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;
+            }
+
+          /* 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;
+            }
+        }
 
       /* 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;
@@ -743,6 +834,41 @@
 
       /* Prevent any attempt to delete the setting of ZERO_REG!  */
       emit_use (zero_reg_rtx);
+	
+
+       /*
+       Clear RAMP? registers if used for data access in the interrupt/signal
+       context.  Do this after the zero register has been explictly cleared.
+       */
+       if (AVR_HAVE_RAMPX_Y_D)
+         {
+           /* 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;
+
+           if (TEST_HARD_REG_BIT (set, REG_X) && TEST_HARD_REG_BIT (set, REG_X + 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;
+             }
+
+           if (TEST_HARD_REG_BIT (set, REG_Y) && TEST_HARD_REG_BIT (set, REG_Y + 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;
+             }
+
+           if(AVR_HAVE_RAMPZ
+              && (TEST_HARD_REG_BIT (set, REG_Z) && TEST_HARD_REG_BIT (set, REG_Z + 1)))
+             {
+               /* 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;
+             }
+         }
+
     }
   if (minimize && (frame_pointer_needed 
 		   || (AVR_2_BYTE_PC && live_seq > 6)
@@ -1064,14 +1190,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.  */
@@ -1818,9 +1969,17 @@
 		return *l = 1, AS2 (out,__SP_L__,%A1);
               /* Use simple load of stack pointer if no interrupts are 
 		 used.  */
-	      else if (TARGET_NO_INTERRUPTS)
+	      else if (TARGET_NO_INTERRUPTS || (!AVR_XMEGA))
 		return *l = 2, (AS2 (out,__SP_H__,%B1) 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
@@ -1828,6 +1987,7 @@
 		      AS2 (out,__SREG__,__tmp_reg__) CR_TAB
 		      AS2 (out,__SP_L__,%A1));
 	    }
+	    }
 	  else if (test_hard_reg_class (STACK_REG, src))
 	    {
 	      *l = 2;	
@@ -1961,7 +2121,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__);
@@ -1969,7 +2129,8 @@
       if (optimize > 0 && io_address_operand (x, QImode))
 	{
 	  *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);
@@ -2157,8 +2318,9 @@
       if (optimize > 0 && io_address_operand (base, HImode))
 	{
 	  *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
@@ -2649,7 +2811,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);
@@ -2657,7 +2819,8 @@
       if (optimize > 0 && io_address_operand (x, QImode))
 	{
 	  *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);
@@ -2736,9 +2899,18 @@
       if (optimize > 0 && io_address_operand (base, HImode))
 	{
 	  *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));
+	}
+      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));
     }
@@ -2755,11 +2927,20 @@
 			      AS2 (adiw,r26,1)          CR_TAB
 			      AS2 (st,X,__tmp_reg__));
               else
+	        {
+                  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
             {
@@ -2767,14 +2948,27 @@
                 return *l=2, (AS2 (st,X+,%A1) CR_TAB
                               AS2 (st,X,%B1));
               else
+		{
+                  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
+        {
+	  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)
     {
@@ -2785,6 +2979,8 @@
 	  if (reg_base != REG_Y)
 	    fatal_insn ("incorrect insn:",insn);
 
+          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
@@ -2798,11 +2994,29 @@
 			  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)
             {
+	      if (!AVR_XMEGA)
+	        {
 	      *l = 7;
 	      return (AS2 (mov,__tmp_reg__,r26)  CR_TAB
 		      AS2 (mov,__zero_reg__,r27) CR_TAB
@@ -2812,21 +3026,57 @@
 		      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));
 	}
+	  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));
+            }
+	}
+	
+      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) */
+    {
+      if (mem_volatile_p && AVR_XMEGA)
+        return *l = 4, (AS2 (sbiw,%r0,2)    CR_TAB 
+                        AS2 (st,%p0+,%A1)   CR_TAB
+                        AS2 (st,%p0,%B1)    CR_TAB
+                        AS2 (sbiw,%r0,1));
+      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)
             {
@@ -4637,6 +4887,16 @@
         }
     }
 
+  else if (cfun->machine->is_nmi)
+   {
+     if (strncmp (name, "__vector", strlen ("__vector")) != 0)
+       {
+         warning_at (DECL_SOURCE_LOCATION (decl), 0,
+		     "%qs appears to be a misspelled nmi handler",
+                     name);
+       }
+   }
+
   ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function");
   ASM_OUTPUT_LABEL (file, name);
 }
@@ -4761,6 +5021,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 },
   { "OS_main",   0, 0, false, true,  true,   avr_handle_fntype_attribute },
@@ -4949,7 +5210,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);
@@ -6046,16 +6308,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 -rwu gcc/config/avr/avr.h gcc/config/avr/avr.h
--- gcc/config/avr/avr.h	2009-03-29 02:39:50.000000000 +0530
+++ gcc/config/avr/avr.h	2010-02-11 16:06:13.447503900 +0530
@@ -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;
 };
@@ -94,6 +97,17 @@
 	}					\
       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)
 
@@ -109,10 +123,19 @@
 #define AVR_HAVE_LPMX (avr_current_arch->have_movw_lpmx)
 #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 ()
@@ -861,6 +884,20 @@
   mmcu=m3000*|\
   mmcu=m3001*: -m avr5}\
 %{mmcu=atmega256*:-m avr6}\
+%{mmcu=atxmega16a4|\
+  mmcu=atxmega16d4|\
+  mmcu=atxmega32d4:-m avrxmega2}\
+%{mmcu=atxmega32a4:-m avrxmega3} \
+%{mmcu=atxmega64a3|\
+  mmcu=atxmega64d3:-m avrxmega4} \
+%{mmcu=atxmega64a1:-m avrxmega5} \
+%{mmcu=atxmega128a3|\
+  mmcu=atxmega128d3|\
+  mmcu=atxmega192a3|\
+  mmcu=atxmega192d3|\
+  mmcu=atxmega256a3*|\
+  mmcu=atxmega256d3:-m avrxmega6} \
+%{mmcu=atxmega128a1:-m avrxmega7} \
 %{mmcu=atmega324*|\
   mmcu=atmega325*|\
   mmcu=atmega328p|\
@@ -1050,7 +1087,23 @@
 %{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=at90usb1287:crtusb1287.o%s} \
+%{mmcu=avrxmega2|mmcu=atxmega32d4:crtx32d4.o%s} \
+%{mmcu=atxmega16a4:crtx16a4.o%s} \
+%{mmcu=atxmega16d4:crtx16d4.o%s} \
+%{mmcu=atxmega3|mmcu=atxmega32a4:crtx32a4.o%s} \
+%{mmcu=atxmega4|mmcu=atxmega64a3:crtx64a3.o%s} \
+%{mmcu=atxmega64d3:crtx64d3.o%s} \
+%{mmcu=atxmega5|mmcu=atxmega64a1:crtx64a1.o%s} \
+%{mmcu=atxmega6|mmcu=atxmega128a3:crtx128a3.o%s} \
+%{mmcu=atxmega128d3:crtx128d3.o%s}\
+%{mmcu=atxmega192a3:crtx192a3.o%s}\
+%{mmcu=atxmega192d3:crtx192d3.o%s}\
+%{mmcu=atxmega256a3:crtx256a3.o%s} \
+%{mmcu=atxmega256a3b:crtx256a3b.o%s} \
+%{mmcu=atxmega256d3:crtx256d3.o%s} \
+%{mmcu=atxmega7|mmcu=atxmega128a1:crtx128a1.o%s}"
 
 #define EXTRA_SPECS {"crt_binutils", CRT_BINUTILS_SPECS},
 
@@ -1110,6 +1163,10 @@
      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;
Only in gcc/config/avr: avr.h.rej
diff -rwu gcc/config/avr/avr.md gcc/config/avr/avr.md
--- gcc/config/avr/avr.md	2009-04-20 21:20:46.000000000 +0530
+++ gcc/config/avr/avr.md	2010-02-11 13:40:41.725363500 +0530
@@ -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)
@@ -2935,7 +2932,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")])
@@ -2947,7 +2945,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 -rwu gcc/config/avr/predicates.md gcc/config/avr/predicates.md
--- gcc/config/avr/predicates.md	2008-04-03 00:51:01.000000000 +0530
+++ gcc/config/avr/predicates.md	2010-02-11 16:19:39.252835600 +0530
@@ -45,17 +45,23 @@
 ;; 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 true if OP is a valid address of I/O space.
 (define_predicate "io_address_operand"
   (and (match_code "const_int")
-       (match_test "IN_RANGE((INTVAL (op)), 0x20, (0x60 - GET_MODE_SIZE(mode)))")))
+       (if_then_else (match_test "AVR_XMEGA") 
+       		(match_test "IN_RANGE((INTVAL (op)), 0x0, (0x40 - GET_MODE_SIZE(mode)))")
+       		(match_test "IN_RANGE((INTVAL (op)), 0x20, (0x60 - GET_MODE_SIZE(mode)))"))))
 
 ;; Return 1 if OP is the zero constant for MODE.
 (define_predicate "const0_operand"
diff -rwu gcc/config/avr/t-avr gcc/config/avr/t-avr
--- gcc/config/avr/t-avr	2009-03-29 02:39:50.000000000 +0530
+++ gcc/config/avr/t-avr	2010-02-11 15:05:37.940014300 +0530
@@ -38,8 +38,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=avrxmega2/mmcu=avrxmega3/mmcu=avrxmega4/mmcu=avrxmega5/mmcu=avrxmega6/mmcu=avrxmega7
+MULTILIB_DIRNAMES = avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 avrxmega2 avrxmega3 avrxmega4 avrxmega5 avrxmega6 avrxmega7
 
 # The many avr2 matches are not listed here - this is the default.
 MULTILIB_MATCHES = \
@@ -151,7 +151,24 @@
 	mmcu?avr51=mmcu?m3000s \
 	mmcu?avr51=mmcu?m3001b \
  	mmcu?avr6=mmcu?atmega2560 \
- 	mmcu?avr6=mmcu?atmega2561
+ 	mmcu?avr6=mmcu?atmega2561 \
+	mmcu?avr6=mmcu?atmega2560 \
+	mmcu?avr6=mmcu?atmega2561 \
+	mmcu?avrxmega2=mmcu?atxmega16a4 \
+	mmcu?avrxmega2=mmcu?atxmega16d4 \
+	mmcu?avrxmega2=mmcu?atxmega32d4 \
+	mmcu?avrxmega3=mmcu?atxmega32a4 \
+	mmcu?avrxmega4=mmcu?atxmega64a3 \
+	mmcu?avrxmega4=mmcu?atxmega64d3 \
+	mmcu?avrxmega5=mmcu?atxmega64a1 \
+	mmcu?avrxmega6=mmcu?atxmega128a3 \
+	mmcu?avrxmega6=mmcu?atxmega128d3 \
+	mmcu?avrxmega6=mmcu?atxmega192a3 \
+	mmcu?avrxmega6=mmcu?atxmega192d3 \
+	mmcu?avrxmega6=mmcu?atxmega256a3 \
+	mmcu?avrxmega6=mmcu?atxmega256a3b \
+	mmcu?avrxmega6=mmcu?atxmega256d3 \
+	mmcu?avrxmega7=mmcu?atxmega128a1
 
 MULTILIB_EXCEPTIONS =
 
--- gcc/config/avr/libgcc.S.old	2010-06-08 17:13:21.859375000 -0600
+++ gcc/config/avr/libgcc.S	2010-06-08 17:25:02.000000000 -0600
@@ -652,11 +652,19 @@ __prologue_saves__:
 	in	r29,__SP_H__
 	sub	r28,r26
 	sbc	r29,r27
+
+/* Restore stack pointer. */
+#if defined (__AVR_XMEGA__)
+	out	__SP_L__,r28
+	out	__SP_H__,r29
+#else
 	in	__tmp_reg__,__SREG__
 	cli
 	out	__SP_H__,r29
 	out	__SREG__,__tmp_reg__
 	out	__SP_L__,r28
+#endif
+
 #if defined (__AVR_HAVE_EIJMP_EICALL__)
 	eijmp
 #else
@@ -750,11 +758,18 @@ __epilogue_restores__:
 #endif /* defined (AVR_TINY) */
 	add	r28,r30
 	adc	r29,__zero_reg__
+	
+/* Restore stack pointer. */
+#if defined(__AVR_XMEGA__)
+	out	__SP_L__,r28
+	out	__SP_H__,r29
+#else
 	in	__tmp_reg__,__SREG__
 	cli
 	out	__SP_H__,r29
 	out	__SREG__,__tmp_reg__
 	out	__SP_L__,r28
+#endif	
 	mov_l	r28, r26
 	mov_h	r29, r27
 	ret
