diff mbox

[AVR] Add xmega support

Message ID 4F3AAD5D.2080103@gjlay.de
State New
Headers show

Commit Message

Georg-Johann Lay Feb. 14, 2012, 6:52 p.m. UTC
This patch adds support for xmega cores and does the following:

* Add architectures avrxmega2/4/5/6/7 to avr-devices.c

* Add some xmega MCUs to avr-mcus.def

* Add new function avr.c:avr_out_movhi_mr_r_xmega that works similar
  to out_movhi_mr_r except that the low byte is output first.
  Rationale is that writing SP_L triggers an atomic block of
  4 ticks so that no IRQ-disabling is needed when setting SP.

* Similar rationale behind changes to __prologue_saves__
  and __epilogue_restores__ from libgcc.

* ISR pro- and epilogue save/restore RAMPD/X/Y/Z as needed.

* At file start, definitions for CCP/RAMPD/X/Y are printed.

* While printing asm, RAMPD/X/Y are detected and printed by
  their name instead of by their I/O address.

* Some built-in defines are added

The architecture names and MCU assignments follow binutils
./gas/config/tc-avr.c
so that the compiler is in sync with binutils.
I don't see a reason to have both avrxmega2 and avrxmega4 because
from the compiler's perspective they are the same; but that's
obviously how things are implemented.

There is no native support for big-RAM devices and I can hardly
image GCC (in particular IRA/reload) can cope with a modelling of
3-byte RAM pointers. But that's a different story...

It might be easier for the compiler if crucial SFRs are not modelled by
MEM but as REG instead, but for that change I don't know enough
about debugging formats and impact on gdb.

Maybe Richard can comment on that?

Ok for trunk?

Johann


libgcc/
	Anatoly Sokolov
	Eric Weddington
	* config/avr/lib1funcs.S (__prologue_saves__): Handle AVR_XMEGA
	(__epilogue_restores__): Ditto.

gcc/
	Anatoly Sokolov
	Eric Weddington
	* config/avr/avr-devices.c (avr_arch_types): Add avrxmega2,
	avrxmega4, avrxmega5, avrxmega6, avrxmega7.
	Rewrite initializers for .macro.
	
	* config/avr/avr-mcus.def (AVR_MCU): Add known MCUs:
	avrxmega2: atxmega16a4, atxmega16d4, atxmega16x1, atxmega32a4
	atxmega32d4, atxmega32x1.
	avrxmega4: atxmega64a3, atxmega64d3.
	avrxmega5: atxmega64a1, atxmega64a1u.
	avrxmega6: atxmega128a3, atxmega128d3, atxmega192a3, atxmega192d3,
	atxmega256a3, atxmega256a3b, atxmega256a3bu, atxmega256d3.
	avrxmega7: atxmega128a1, atxmega128a1u.

	* config/avr/multilib.h: Regenerate.
	* config/avr/t-multilib: Regenerate.
	* config/avr/avr-tables.opt: Regenerate.

	* config/avr/avr.h (enum avr_arch): Add: ARCH_AVRXMEGA2,
	ARCH_AVRXMEGA4,	ARCH_AVRXMEGA5, ARCH_AVRXMEGA6, ARCH_AVRXMEGA7.
	(struct base_arch_s): Rename reserved to xmega_p.
	Rename reserved2 to have_rampd.
	(AVR_XMEGA): New define.
	(AVR_HAVE_RAMPD, AVR_HAVE_RAMPX, AVR_HAVE_RAMPY): New defines.
	(AVR_HAVE_RAMPZ): Change definition to fit xmega.

	* config/avr/predicates.md (io_address_operand): Take into
	account SFR offset.
	(low_io_address_operand): Ditto.
	(high_io_address_operand): Ditto.
	
	* config/avr/avr.md (isa): Add alternatives no_xmega, xmega.
	(enabled, movhi_sp_r): Use them.

	* config/avr/avr-c.c (avr_cpu_cpp_builtins): Use
	cpp_define_formatted to built-in define __AVR_ARCH__.
	(__AVR_XMEGA__): New built-in define.
	(__AVR_HAVE_RAMPD__): New built-in define.
	(__AVR_HAVE_RAMPX__): New built-in define.
	(__AVR_HAVE_RAMPY__): New built-in define.
	(__AVR_HAVE_RAMPZ__): Change condition when to built-in define it.

	* config/avr/avr.c (avr_addr_t): Add ccp, rampd, rampx, rampy.
	(avr_option_override): Initialize them.
	(sreg_rtx, rampd_rtx, rampx_rtx, rampy_rtx): New GTY rtx.
	(avr_init_expanders): Initialize them. No more block several calls.
	(emit_push_sfr): New static function.
	(avr_prologue_setup_frame): Use it to push SREG, RAMPD/X/Y/Z as needed.
	Handle AVR_XMEGA.
	(expand_epilogue): Handle AVR_XMEGA. Pop RAMPD/X/Y/Z as needed.
	(avr_print_operand): Print addreeses as symbols for
	RAMPX, RAMPY, RAMPD, CCP.
	(output_movhi): Handle AVR_XMEGA when writing to SP.
	(avr_out_movhi_mr_r_xmega): New static function.
	(out_movhi_mr_r): Forward to avr_out_movhi_mr_r_xmega for AVR_XMEGA.
	(avr_file_start): Print symbol defines for __RAMPX__,  __RAMPY__,
	__RAMPD__,  __CCP__ as needed.

Comments

Weddington, Eric Feb. 14, 2012, 7:44 p.m. UTC | #1
> -----Original Message-----
> From: Georg-Johann Lay
> Sent: Tuesday, February 14, 2012 11:52 AM
> To: gcc-patches@gcc.gnu.org
> Cc: Weddington, Eric; Denis Chertykov; Anatoly Sokolov
> Subject: [Patch,AVR] Add xmega support
> 
> This patch adds support for xmega cores and does the following:

Please commit. And thanks! :-)

Eric
Georg-Johann Lay Feb. 14, 2012, 8:28 p.m. UTC | #2
Weddington, Eric schrieb:
> 
>>
>>This patch adds support for xmega cores and does the following:
> 
> Please commit. And thanks! :-)
> 
> Eric

As I wrote, the device <-> core assignments are the same as in
./gas/config/tc-avr.c:

http://sourceware.org/cgi-bin/cvsweb.cgi/src/gas/config/tc-avr.c?rev=1.79&content-type=text/x-cvsweb-markup&cvsroot=src

which I don't understand. The assignments are:

avrxmega2: ELPM=0, RAMPD=0, EIND=0
     atxmega16a4
     atxmega16d4
     atxmega16x1
     atxmega32a4
     atxmega32d4
     atxmega32x1

avrxmega4: ELPM=0, RAMPD=0, EIND=0
     atxmega64a3
     atxmega64d3

avrxmega5: ELPM=0, RAMPD=1, EIND=0
     atxmega64a1
     atxmega64a1u

avrxmega6: ELPM=1, RAMPD=0, EIND=0/1
     atxmega128a3
     atxmega128b1
     atxmega128d3
     atxmega192a3
     atxmega192d3
     atxmega256a3
     atxmega256a3b
     atxmega256a3bu
     atxmega256d3

avrxmega7: ELPM=1, RAMPD=1, EIND=0
     atxmega128a1
     atxmega128a1u

Thus:

* xmega2 and xmega4 are duplicates of each other
* xmega6 mixes devices with EIND (>128 KiB Flash)
   with non-EIND (<= KiB Flash) devices.

There are 8 combinations in the ELPM x RAMPD x EIND
cross product. As EIND implies ELPM, 6 combinations remain:

ELPM=0, RAMPD=0, EIND=0 -> xmega2 = xmega4
ELPM=0, RAMPD=1, EIND=0 -> xmega5
ELPM=1, RAMPD=0, EIND=0 -> xmega6 *clash*
ELPM=1, RAMPD=0, EIND=1 -> xmega6 *clash*
ELPM=1, RAMPD=1, EIND=0 -> xmega7
ELPM=1, RAMPD=1, EIND=1 -> ---

Can you shed some light on that?

The current non-xmega architectures assume that only
devices with the same amount of flash segments are
present in one archirecture. This is no more true with
192 KiB devices that have 3 segments and are in the same
arch with 4-segment and/or 2-segment devices.

An ISA-question: Is xmega ISA binary upward
compatible to respective non-xmega, i.e. can the
same ISA simulator be used, for example?

The patches are untested because avrtest does not
support xmega. Would you run tests and compare results
for ATmega128 against, for example ATXmega128A3?
There should be no differences and the same out-of-flash
or out-of-ram crashes.

Do you have an update for avrtest?
I had a look into it but it's complete mess because GPRs are
accessed by their RAM address and it would take some time to
clean up that mess.

Johann
Richard Henderson Feb. 14, 2012, 9:39 p.m. UTC | #3
On 02/14/2012 10:52 AM, Georg-Johann Lay wrote:
> It might be easier for the compiler if crucial SFRs are not modelled by
> MEM but as REG instead, but for that change I don't know enough
> about debugging formats and impact on gdb.
> 
> Maybe Richard can comment on that?

It's almost certainly going to be easier for the compiler to model
the cpu internal registers as registers.  The fact that they're 
actually accessed via memory-map is implementation detail that
should almost certainly *not* be exposed.

Dunno what to do about gdb.  Probably update the cpu model in a
similar fashion.


r~
diff mbox

Patch

Index: libgcc/config/avr/lib1funcs.S
===================================================================
--- libgcc/config/avr/lib1funcs.S	(revision 183939)
+++ libgcc/config/avr/lib1funcs.S	(working copy)
@@ -1696,6 +1696,13 @@  DEFUN __prologue_saves__
 	sub	r28,r26
 	out	__SP_L__,r28
 	clr	r29
+#elif defined (__AVR__XMEGA__)
+	in	r28,__SP_L__
+	in	r29,__SP_H__
+	sub	r28,r26
+	sbc	r29,r27
+	out	__SP_L__,r28
+	out	__SP_H__,r29
 #else
 	in	r28,__SP_L__
 	in	r29,__SP_H__
@@ -1745,6 +1752,13 @@  DEFUN __epilogue_restores__
 	add	r28,r30
 	out	__SP_L__,r28
 	mov	r28, r26
+#elif defined (__AVR__XMEGA__)
+	ldd  r27,Y+1
+	add  r28,r30
+	adc  r29,__zero_reg__
+	out  __SP_L__,r28
+	out  __SP_H__,r29
+	wmov 28, 26
 #else
 	ldd	r27,Y+1
 	add	r28,r30
Index: gcc/config/avr/predicates.md
===================================================================
--- gcc/config/avr/predicates.md	(revision 184156)
+++ gcc/config/avr/predicates.md	(working copy)
@@ -45,17 +45,20 @@  (define_predicate "stack_register_operan
 ;; 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)")))
+       (match_test "IN_RANGE (INTVAL (op) - avr_current_arch->sfr_offset,
+                              0, 0x1f)")))
 
 ;; 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)")))
+       (match_test "IN_RANGE (INTVAL (op) - avr_current_arch->sfr_offset,
+                              0x20, 0x3F)")))
 
 ;; 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)))")))
+       (match_test "IN_RANGE (INTVAL (op) - avr_current_arch->sfr_offset,
+                              0, 0x40 - GET_MODE_SIZE (mode))")))
 
 ;; Return 1 if OP is a general operand not in flash memory
 (define_predicate "nop_general_operand"
Index: gcc/config/avr/t-multilib
===================================================================
--- gcc/config/avr/t-multilib	(revision 184156)
+++ gcc/config/avr/t-multilib	(working copy)
@@ -21,9 +21,9 @@ 
 # along with GCC; see the file COPYING3.  If not see
 # <http://www.gnu.org/licenses/>.
 
-MULTILIB_OPTIONS = mmcu=avr2/mmcu=avr25/mmcu=avr3/mmcu=avr31/mmcu=avr35/mmcu=avr4/mmcu=avr5/mmcu=avr51/mmcu=avr6 mtiny-stack
+MULTILIB_OPTIONS = mmcu=avr2/mmcu=avr25/mmcu=avr3/mmcu=avr31/mmcu=avr35/mmcu=avr4/mmcu=avr5/mmcu=avr51/mmcu=avr6/mmcu=avrxmega2/mmcu=avrxmega4/mmcu=avrxmega5/mmcu=avrxmega6/mmcu=avrxmega7 mtiny-stack
 
-MULTILIB_DIRNAMES =  avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 tiny-stack avr25/tiny-stack
+MULTILIB_DIRNAMES =  avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 avrxmega2 avrxmega4 avrxmega5 avrxmega6 avrxmega7 tiny-stack avr25/tiny-stack
 
 MULTILIB_EXCEPTIONS = \
 	mmcu=avr3/mtiny-stack \
@@ -32,7 +32,12 @@  MULTILIB_EXCEPTIONS = \
 	mmcu=avr4/mtiny-stack \
 	mmcu=avr5/mtiny-stack \
 	mmcu=avr51/mtiny-stack \
-	mmcu=avr6/mtiny-stack
+	mmcu=avr6/mtiny-stack \
+	mmcu=avrxmega2/mtiny-stack \
+	mmcu=avrxmega4/mtiny-stack \
+	mmcu=avrxmega5/mtiny-stack \
+	mmcu=avrxmega6/mtiny-stack \
+	mmcu=avrxmega7/mtiny-stack
 
 MULTILIB_MATCHES = \
 	mmcu?at90s2313=mmcu?at90s2313 \
@@ -189,4 +194,24 @@  MULTILIB_MATCHES = \
 	mmcu?avr51=mmcu?at90usb1286 \
 	mmcu?avr51=mmcu?at90usb1287 \
 	mmcu?avr6=mmcu?atmega2560 \
-	mmcu?avr6=mmcu?atmega2561
+	mmcu?avr6=mmcu?atmega2561 \
+	mmcu?avrxmega2=mmcu?atxmega16a4 \
+	mmcu?avrxmega2=mmcu?atxmega16d4 \
+	mmcu?avrxmega2=mmcu?atxmega16x1 \
+	mmcu?avrxmega2=mmcu?atxmega32a4 \
+	mmcu?avrxmega2=mmcu?atxmega32d4 \
+	mmcu?avrxmega2=mmcu?atxmega32x1 \
+	mmcu?avrxmega4=mmcu?atxmega64a3 \
+	mmcu?avrxmega4=mmcu?atxmega64d3 \
+	mmcu?avrxmega5=mmcu?atxmega64a1 \
+	mmcu?avrxmega5=mmcu?atxmega64a1u \
+	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?atxmega256a3bu \
+	mmcu?avrxmega6=mmcu?atxmega256d3 \
+	mmcu?avrxmega7=mmcu?atxmega128a1 \
+	mmcu?avrxmega7=mmcu?atxmega128a1u
Index: gcc/config/avr/avr.md
===================================================================
--- gcc/config/avr/avr.md	(revision 184156)
+++ gcc/config/avr/avr.md	(working copy)
@@ -155,9 +155,10 @@  (define_attr "adjust_len"
 ;; ijmp : ISA has no EICALL/EIJMP        eijmp : ISA has EICALL/EIJMP
 ;; lpm  : ISA has no LPMX                lpmx  : ISA has LPMX
 ;; elpm : ISA has ELPM but no ELPMX      elpmx : ISA has ELPMX
+;; no_xmega: non-XMEGA core              xmega : XMEGA core
 
 (define_attr "isa"
-  "mov,movw, rjmp,jmp, ijmp,eijmp, lpm,lpmx, elpm,elpmx,
+  "mov,movw, rjmp,jmp, ijmp,eijmp, lpm,lpmx, elpm,elpmx, no_xmega,xmega,
    standard"
   (const_string "standard"))
 
@@ -204,6 +205,14 @@  (define_attr "enabled" ""
          (and (eq_attr "isa" "elpmx")
               (match_test "AVR_HAVE_ELPMX"))
          (const_int 1)
+
+         (and (eq_attr "isa" "xmega")
+              (match_test "AVR_XMEGA"))
+         (const_int 1)
+
+         (and (eq_attr "isa" "no_xmega")
+              (match_test "!AVR_XMEGA"))
+         (const_int 1)
          ] (const_int 0)))
 
 
@@ -580,15 +589,17 @@  (define_peephole2
 ;; handled by generic movhi insn.
 
 (define_insn "movhi_sp_r"
-  [(set (match_operand:HI 0 "stack_register_operand"                "=q,q")
-        (unspec_volatile:HI [(match_operand:HI 1 "register_operand"  "r,r")
-                             (match_operand:HI 2 "const_int_operand" "L,P")]
+  [(set (match_operand:HI 0 "stack_register_operand"                "=q,q,q")
+        (unspec_volatile:HI [(match_operand:HI 1 "register_operand"  "r,r,r")
+                             (match_operand:HI 2 "const_int_operand" "L,P,LP")]
                             UNSPECV_WRITE_SP))]
   "!AVR_HAVE_8BIT_SP"
   "@
 	out __SP_H__,%B1\;out __SP_L__,%A1
-	cli\;out __SP_H__,%B1\;sei\;out __SP_L__,%A1"
-  [(set_attr "length" "2,4")
+	cli\;out __SP_H__,%B1\;sei\;out __SP_L__,%A1
+	out __SP_L__,%A1\;out __SP_H__,%B1"
+  [(set_attr "length" "2,4,2")
+   (set_attr "isa" "no_xmega,no_xmega,xmega")
    (set_attr "cc" "none")])
 
 (define_peephole2
Index: gcc/config/avr/avr-c.c
===================================================================
--- gcc/config/avr/avr-c.c	(revision 184156)
+++ gcc/config/avr/avr-c.c	(working copy)
@@ -77,23 +77,21 @@  avr_cpu_cpp_builtins (struct cpp_reader
   builtin_define_std ("AVR");
 
   if (avr_current_arch->macro)
-    cpp_define (pfile, avr_current_arch->macro);
+    cpp_define_formatted (pfile, "__AVR_ARCH__=%s", avr_current_arch->macro);
   if (avr_extra_arch_macro)
     cpp_define (pfile, avr_extra_arch_macro);
-  if (avr_current_arch->have_elpm)
-    cpp_define (pfile, "__AVR_HAVE_RAMPZ__");
-  if (avr_current_arch->have_elpm)
-    cpp_define (pfile, "__AVR_HAVE_ELPM__");
-  if (avr_current_arch->have_elpmx)
-    cpp_define (pfile, "__AVR_HAVE_ELPMX__");
-  if (avr_current_arch->have_movw_lpmx)
-    {
-      cpp_define (pfile, "__AVR_HAVE_MOVW__");
-      cpp_define (pfile, "__AVR_HAVE_LPMX__");
-    }
+  if (AVR_HAVE_RAMPD)    cpp_define (pfile, "__AVR_HAVE_RAMPD__");
+  if (AVR_HAVE_RAMPX)    cpp_define (pfile, "__AVR_HAVE_RAMPX__");
+  if (AVR_HAVE_RAMPY)    cpp_define (pfile, "__AVR_HAVE_RAMPY__");
+  if (AVR_HAVE_RAMPZ)    cpp_define (pfile, "__AVR_HAVE_RAMPZ__");
+  if (AVR_HAVE_ELPM)     cpp_define (pfile, "__AVR_HAVE_ELPM__");
+  if (AVR_HAVE_ELPMX)    cpp_define (pfile, "__AVR_HAVE_ELPMX__");
+  if (AVR_HAVE_MOVW)     cpp_define (pfile, "__AVR_HAVE_MOVW__");
+  if (AVR_HAVE_LPMX)     cpp_define (pfile, "__AVR_HAVE_LPMX__");
+
   if (avr_current_arch->asm_only)
     cpp_define (pfile, "__AVR_ASM_ONLY__");
-  if (avr_current_arch->have_mul)
+  if (AVR_HAVE_MUL)
     {
       cpp_define (pfile, "__AVR_ENHANCED__");
       cpp_define (pfile, "__AVR_HAVE_MUL__");
@@ -103,6 +101,8 @@  avr_cpu_cpp_builtins (struct cpp_reader
       cpp_define (pfile, "__AVR_MEGA__");
       cpp_define (pfile, "__AVR_HAVE_JMP_CALL__");
     }
+  if (AVR_XMEGA)
+    cpp_define (pfile, "__AVR_XMEGA__");
   if (avr_current_arch->have_eijmp_eicall)
     {
       cpp_define (pfile, "__AVR_HAVE_EIJMP_EICALL__");
Index: gcc/config/avr/avr-devices.c
===================================================================
--- gcc/config/avr/avr-devices.c	(revision 184156)
+++ gcc/config/avr/avr-devices.c	(working copy)
@@ -32,21 +32,27 @@  avr_arch_types[] =
   /* unknown device specified */
   { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, 1, NULL,              "avr2"  },
   /*
-    A  M  J  LM E  E  E         d S   S O  # F
-    S  U  M  PO L  L  I         a t   F ff 6 l 
-    M  L  P  MV P  P  J  -  -   t a   R s  4 a   
-             XW M  M  M         a r     e    s
-                   X  P           t     t  k h  */
-  { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=1",  "avr1"  },
-  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=2",  "avr2"  },
-  { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=25", "avr25" },
-  { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=3",  "avr3"  },
-  { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0x0060, 32, 2, "__AVR_ARCH__=31", "avr31" },
-  { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=35", "avr35" },
-  { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=4",  "avr4"  },
-  { 0, 1, 1, 1, 0, 0, 0, 0, 0, 0x0060, 32, 1, "__AVR_ARCH__=5",  "avr5"  },
-  { 0, 1, 1, 1, 1, 1, 0, 0, 0, 0x0060, 32, 2, "__AVR_ARCH__=51", "avr51" },
-  { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0x0060, 32, 4, "__AVR_ARCH__=6",  "avr6"  }
+    A  M  J  LM E  E  E  X  R   d S   S O  # F  A
+    S  U  M  PO L  L  I  M  A   a t   F ff 6 l  r
+    M  L  P  MV P  P  J  E  M   t a   R s  4 a  c 
+             XW M  M  M  G  P   a r     e    s  h
+                   X  P  A  D     t     t  k h  ID   */
+  { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, 1,  "1",   "avr1"  },
+  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, 1,  "2",   "avr2"  },
+  { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0x0060, 32, 1,  "25",  "avr25" },
+  { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0x0060, 32, 1,  "3",   "avr3"  },
+  { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0x0060, 32, 2,  "31",  "avr31" },
+  { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0x0060, 32, 1,  "35",  "avr35" },
+  { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0x0060, 32, 1,  "4",   "avr4"  },
+  { 0, 1, 1, 1, 0, 0, 0, 0, 0, 0x0060, 32, 1,  "5",   "avr5"  },
+  { 0, 1, 1, 1, 1, 1, 0, 0, 0, 0x0060, 32, 2,  "51",  "avr51" },
+  { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0x0060, 32, 4,  "6",   "avr6"  },
+
+  { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0x2000,  0, 1,  "102", "avrxmega2" },
+  { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0x2000,  0, 1,  "104", "avrxmega4" }, /* Same */
+  { 0, 1, 1, 1, 0, 0, 0, 1, 1, 0x2000,  0, 1,  "105", "avrxmega5" },
+  { 0, 1, 1, 1, 1, 1, 1, 1, 0, 0x2000,  0, 4,  "106", "avrxmega6" },
+  { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0x2000,  0, 4,  "107", "avrxmega7" }
 };
 
 const struct mcu_type_s avr_mcu_types[] = {
Index: gcc/config/avr/avr-mcus.def
===================================================================
--- gcc/config/avr/avr-mcus.def	(revision 184156)
+++ gcc/config/avr/avr-mcus.def	(working copy)
@@ -201,6 +201,36 @@  AVR_MCU ("at90usb1287",          ARCH_AV
 AVR_MCU ("avr6",                 ARCH_AVR6, NULL,                        0, 0, 0x0200, "m2561")
 AVR_MCU ("atmega2560",           ARCH_AVR6, "__AVR_ATmega2560__",        0, 0, 0x0200, "m2560")
 AVR_MCU ("atmega2561",           ARCH_AVR6, "__AVR_ATmega2561__",        0, 0, 0x0200, "m2561")
+/* Xmega, 16K <= Flash < 64K, RAM <= 64K */
+AVR_MCU ("avrxmega2",        ARCH_AVRXMEGA2, NULL,                       0, 0, 0x2000, "x32a4")
+AVR_MCU ("atxmega16a4",      ARCH_AVRXMEGA2, "__AVR_ATxmega16A4__",      0, 0, 0x2000, "x16a4")
+AVR_MCU ("atxmega16d4",      ARCH_AVRXMEGA2, "__AVR_ATxmega16D4__",      0, 0, 0x2000, "x16d4")
+AVR_MCU ("atxmega16x1",      ARCH_AVRXMEGA2, "__AVR_ATxmega16X1__",      0, 0, 0x2000, "x16x1")
+AVR_MCU ("atxmega32a4",      ARCH_AVRXMEGA2, "__AVR_ATxmega32A4__",      0, 0, 0x2000, "x32a4")
+AVR_MCU ("atxmega32d4",      ARCH_AVRXMEGA2, "__AVR_ATxmega32D4__",      0, 0, 0x2000, "x32d4")
+AVR_MCU ("atxmega32x1",      ARCH_AVRXMEGA2, "__AVR_ATxmega32X1__",      0, 0, 0x2000, "x32x1")
+/* Xmega, Flash == 64K, RAM <= 64K */
+AVR_MCU ("avrxmega4",        ARCH_AVRXMEGA4, NULL,                       0, 0, 0x2000, "x64a4")
+AVR_MCU ("atxmega64a3",      ARCH_AVRXMEGA4, "__AVR_ATxmega64A3__",      0, 0, 0x2000, "x64a3")
+AVR_MCU ("atxmega64d3",      ARCH_AVRXMEGA4, "__AVR_ATxmega64D3__",      0, 0, 0x2000, "x64d3")
+/* Xmega, Flash == 64K, RAM > 64K */
+AVR_MCU ("avrxmega5",        ARCH_AVRXMEGA5, NULL,                       0, 0, 0x2000, "x64a1")
+AVR_MCU ("atxmega64a1",      ARCH_AVRXMEGA5, "__AVR_ATxmega64A1__",      0, 0, 0x2000, "x64a1")
+AVR_MCU ("atxmega64a1u",     ARCH_AVRXMEGA5, "__AVR_ATxmega64A1U__",     0, 0, 0x2000, "x64a1u")
+/* Xmega, 128K <= Flash <= 256K, RAM <= 64K */
+AVR_MCU ("avrxmega6",        ARCH_AVRXMEGA6, NULL,                       0, 0, 0x2000, "x128a3")
+AVR_MCU ("atxmega128a3",     ARCH_AVRXMEGA6, "__AVR_ATxmega128A3__",     0, 0, 0x2000, "x128a3")
+AVR_MCU ("atxmega128d3",     ARCH_AVRXMEGA6, "__AVR_ATxmega128D3__",     0, 0, 0x2000, "x128d3")
+AVR_MCU ("atxmega192a3",     ARCH_AVRXMEGA6, "__AVR_ATxmega192A3__",     0, 0, 0x2000, "x192a3")
+AVR_MCU ("atxmega192d3",     ARCH_AVRXMEGA6, "__AVR_ATxmega192D3__",     0, 0, 0x2000, "x192d3")
+AVR_MCU ("atxmega256a3",     ARCH_AVRXMEGA6, "__AVR_ATxmega256A3__",     0, 0, 0x2000, "x256a3")
+AVR_MCU ("atxmega256a3b",    ARCH_AVRXMEGA6, "__AVR_ATxmega256A3B__",    0, 0, 0x2000, "x256a3b")
+AVR_MCU ("atxmega256a3bu",   ARCH_AVRXMEGA6, "__AVR_ATxmega256A3BU__",   0, 0, 0x2000, "x256a3bu")
+AVR_MCU ("atxmega256d3",     ARCH_AVRXMEGA6, "__AVR_ATxmega256D3__",     0, 0, 0x2000, "x256d3")
+/* Xmega, 128K <= Flash <= 256K, RAM > 64K RAM.  */
+AVR_MCU ("avrxmega7",        ARCH_AVRXMEGA7, NULL,                       0, 0, 0x2000, "x128a1")
+AVR_MCU ("atxmega128a1",     ARCH_AVRXMEGA7, "__AVR_ATxmega128A1__",     0, 0, 0x2000, "x128a1")
+AVR_MCU ("atxmega128a1u",    ARCH_AVRXMEGA7, "__AVR_ATxmega128A1U__",    0, 0, 0x2000, "x128a1u")
 /* Assembler only.  */
 AVR_MCU ("avr1",                 ARCH_AVR1, NULL,                        0, 0, 0x0060, "s1200")
 AVR_MCU ("at90s1200",            ARCH_AVR1, "__AVR_AT90S1200__",         0, 0, 0x0060, "s1200")
Index: gcc/config/avr/avr-tables.opt
===================================================================
--- gcc/config/avr/avr-tables.opt	(revision 184156)
+++ gcc/config/avr/avr-tables.opt	(working copy)
@@ -504,20 +504,95 @@  EnumValue
 Enum(avr_mcu) String(atmega2561) Value(159)
 
 EnumValue
-Enum(avr_mcu) String(avr1) Value(160)
+Enum(avr_mcu) String(avrxmega2) Value(160)
 
 EnumValue
-Enum(avr_mcu) String(at90s1200) Value(161)
+Enum(avr_mcu) String(atxmega16a4) Value(161)
 
 EnumValue
-Enum(avr_mcu) String(attiny11) Value(162)
+Enum(avr_mcu) String(atxmega16d4) Value(162)
 
 EnumValue
-Enum(avr_mcu) String(attiny12) Value(163)
+Enum(avr_mcu) String(atxmega16x1) Value(163)
 
 EnumValue
-Enum(avr_mcu) String(attiny15) Value(164)
+Enum(avr_mcu) String(atxmega32a4) Value(164)
 
 EnumValue
-Enum(avr_mcu) String(attiny28) Value(165)
+Enum(avr_mcu) String(atxmega32d4) Value(165)
+
+EnumValue
+Enum(avr_mcu) String(atxmega32x1) Value(166)
+
+EnumValue
+Enum(avr_mcu) String(avrxmega4) Value(167)
+
+EnumValue
+Enum(avr_mcu) String(atxmega64a3) Value(168)
+
+EnumValue
+Enum(avr_mcu) String(atxmega64d3) Value(169)
+
+EnumValue
+Enum(avr_mcu) String(avrxmega5) Value(170)
+
+EnumValue
+Enum(avr_mcu) String(atxmega64a1) Value(171)
+
+EnumValue
+Enum(avr_mcu) String(atxmega64a1u) Value(172)
+
+EnumValue
+Enum(avr_mcu) String(avrxmega6) Value(173)
+
+EnumValue
+Enum(avr_mcu) String(atxmega128a3) Value(174)
+
+EnumValue
+Enum(avr_mcu) String(atxmega128d3) Value(175)
+
+EnumValue
+Enum(avr_mcu) String(atxmega192a3) Value(176)
+
+EnumValue
+Enum(avr_mcu) String(atxmega192d3) Value(177)
+
+EnumValue
+Enum(avr_mcu) String(atxmega256a3) Value(178)
+
+EnumValue
+Enum(avr_mcu) String(atxmega256a3b) Value(179)
+
+EnumValue
+Enum(avr_mcu) String(atxmega256a3bu) Value(180)
+
+EnumValue
+Enum(avr_mcu) String(atxmega256d3) Value(181)
+
+EnumValue
+Enum(avr_mcu) String(avrxmega7) Value(182)
+
+EnumValue
+Enum(avr_mcu) String(atxmega128a1) Value(183)
+
+EnumValue
+Enum(avr_mcu) String(atxmega128a1u) Value(184)
+
+EnumValue
+Enum(avr_mcu) String(avr1) Value(185)
+
+EnumValue
+Enum(avr_mcu) String(at90s1200) Value(186)
+
+EnumValue
+Enum(avr_mcu) String(attiny11) Value(187)
+
+EnumValue
+Enum(avr_mcu) String(attiny12) Value(188)
+
+EnumValue
+Enum(avr_mcu) String(attiny15) Value(189)
+
+EnumValue
+Enum(avr_mcu) String(attiny28) Value(190)
 
Index: gcc/config/avr/multilib.h
===================================================================
--- gcc/config/avr/multilib.h	(revision 184156)
+++ gcc/config/avr/multilib.h	(working copy)
@@ -44,19 +44,24 @@  static const char* const avr_multilib_ra
   "avr25/tiny-stack mmcu=attiny261;",
   "avr25/tiny-stack mmcu=attiny261a;",
 
-  ". !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mtiny-stack !mmcu=at90s2313 !mmcu=at90s2323 !mmcu=at90s2333 !mmcu=at90s2343 !mmcu=attiny22 !mmcu=attiny26 !mmcu=at90s4433 !mmcu=attiny13 !mmcu=attiny13a !mmcu=attiny2313 !mmcu=attiny2313a !mmcu=attiny24 !mmcu=attiny24a !mmcu=attiny25 !mmcu=attiny261 !mmcu=attiny261a;",
-  "avr2 mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mtiny-stack;",
-  "avr25 !mmcu=avr2 mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mtiny-stack;",
-  "avr3 !mmcu=avr2 !mmcu=avr25 mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6;",
-  "avr31 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6;",
-  "avr35 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6;",
-  "avr4 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6;",
-  "avr5 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 mmcu=avr5 !mmcu=avr51 !mmcu=avr6;",
-  "avr51 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 mmcu=avr51 !mmcu=avr6;",
-  "avr6 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 mmcu=avr6;",
-  "tiny-stack !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 mtiny-stack;",
-  "avr2/tiny-stack mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 mtiny-stack;",
-  "avr25/tiny-stack !mmcu=avr2 mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 mtiny-stack;",
+  ". !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mmcu=avrxmega2 !mmcu=avrxmega4 !mmcu=avrxmega5 !mmcu=avrxmega6 !mmcu=avrxmega7 !mtiny-stack !mmcu=at90s2313 !mmcu=at90s2323 !mmcu=at90s2333 !mmcu=at90s2343 !mmcu=attiny22 !mmcu=attiny26 !mmcu=at90s4433 !mmcu=attiny13 !mmcu=attiny13a !mmcu=attiny2313 !mmcu=attiny2313a !mmcu=attiny24 !mmcu=attiny24a !mmcu=attiny25 !mmcu=attiny261 !mmcu=attiny261a;",
+  "avr2 mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mmcu=avrxmega2 !mmcu=avrxmega4 !mmcu=avrxmega5 !mmcu=avrxmega6 !mmcu=avrxmega7 !mtiny-stack;",
+  "avr25 !mmcu=avr2 mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mmcu=avrxmega2 !mmcu=avrxmega4 !mmcu=avrxmega5 !mmcu=avrxmega6 !mmcu=avrxmega7 !mtiny-stack;",
+  "avr3 !mmcu=avr2 !mmcu=avr25 mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mmcu=avrxmega2 !mmcu=avrxmega4 !mmcu=avrxmega5 !mmcu=avrxmega6 !mmcu=avrxmega7;",
+  "avr31 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mmcu=avrxmega2 !mmcu=avrxmega4 !mmcu=avrxmega5 !mmcu=avrxmega6 !mmcu=avrxmega7;",
+  "avr35 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mmcu=avrxmega2 !mmcu=avrxmega4 !mmcu=avrxmega5 !mmcu=avrxmega6 !mmcu=avrxmega7;",
+  "avr4 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mmcu=avrxmega2 !mmcu=avrxmega4 !mmcu=avrxmega5 !mmcu=avrxmega6 !mmcu=avrxmega7;",
+  "avr5 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mmcu=avrxmega2 !mmcu=avrxmega4 !mmcu=avrxmega5 !mmcu=avrxmega6 !mmcu=avrxmega7;",
+  "avr51 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 mmcu=avr51 !mmcu=avr6 !mmcu=avrxmega2 !mmcu=avrxmega4 !mmcu=avrxmega5 !mmcu=avrxmega6 !mmcu=avrxmega7;",
+  "avr6 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 mmcu=avr6 !mmcu=avrxmega2 !mmcu=avrxmega4 !mmcu=avrxmega5 !mmcu=avrxmega6 !mmcu=avrxmega7;",
+  "avrxmega2 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 mmcu=avrxmega2 !mmcu=avrxmega4 !mmcu=avrxmega5 !mmcu=avrxmega6 !mmcu=avrxmega7;",
+  "avrxmega4 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mmcu=avrxmega2 mmcu=avrxmega4 !mmcu=avrxmega5 !mmcu=avrxmega6 !mmcu=avrxmega7;",
+  "avrxmega5 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mmcu=avrxmega2 !mmcu=avrxmega4 mmcu=avrxmega5 !mmcu=avrxmega6 !mmcu=avrxmega7;",
+  "avrxmega6 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mmcu=avrxmega2 !mmcu=avrxmega4 !mmcu=avrxmega5 mmcu=avrxmega6 !mmcu=avrxmega7;",
+  "avrxmega7 !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mmcu=avrxmega2 !mmcu=avrxmega4 !mmcu=avrxmega5 !mmcu=avrxmega6 mmcu=avrxmega7;",
+  "tiny-stack !mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mmcu=avrxmega2 !mmcu=avrxmega4 !mmcu=avrxmega5 !mmcu=avrxmega6 !mmcu=avrxmega7 mtiny-stack;",
+  "avr2/tiny-stack mmcu=avr2 !mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mmcu=avrxmega2 !mmcu=avrxmega4 !mmcu=avrxmega5 !mmcu=avrxmega6 !mmcu=avrxmega7 mtiny-stack;",
+  "avr25/tiny-stack !mmcu=avr2 mmcu=avr25 !mmcu=avr3 !mmcu=avr31 !mmcu=avr35 !mmcu=avr4 !mmcu=avr5 !mmcu=avr51 !mmcu=avr6 !mmcu=avrxmega2 !mmcu=avrxmega4 !mmcu=avrxmega5 !mmcu=avrxmega6 !mmcu=avrxmega7 mtiny-stack;",
 
   NULL
 };
Index: gcc/config/avr/avr.c
===================================================================
--- gcc/config/avr/avr.c	(revision 184156)
+++ gcc/config/avr/avr.c	(working copy)
@@ -112,6 +112,12 @@  typedef struct
   /* SREG: The pocessor status */
   int sreg;
 
+  /* RAMPX, RAMPY, RAMPD and CCP of XMEGA */
+  int ccp;
+  int rampd;
+  int rampx;
+  int rampy;
+
   /* RAMPZ: The high byte of 24-bit address used with ELPM */ 
   int rampz;
 
@@ -177,8 +183,18 @@  rtx zero_reg_rtx;
 extern GTY(()) rtx all_regs_rtx[32];
 rtx all_regs_rtx[32];
 
-/* RAMPZ special function register */
+/* SREG, the processor status */
+extern GTY(()) rtx sreg_rtx;
+rtx sreg_rtx;
+
+/* RAMP* special function registers */
+extern GTY(()) rtx rampd_rtx;
+extern GTY(()) rtx rampx_rtx;
+extern GTY(()) rtx rampy_rtx;
 extern GTY(()) rtx rampz_rtx;
+rtx rampd_rtx;
+rtx rampx_rtx;
+rtx rampy_rtx;
 rtx rampz_rtx;
 
 /* RTX containing the strings "" and "e", respectively */
@@ -421,6 +437,11 @@  avr_option_override (void)
   /* RAMPZ: Address' high part when loading via ELPM */
   avr_addr.rampz = 0x3B + avr_current_arch->sfr_offset;
 
+  avr_addr.rampy = 0x3A + avr_current_arch->sfr_offset;
+  avr_addr.rampx = 0x39 + avr_current_arch->sfr_offset;
+  avr_addr.rampd = 0x38 + avr_current_arch->sfr_offset;
+  avr_addr.ccp = 0x34 + avr_current_arch->sfr_offset;
+
   /* SP: Stack Pointer (SP_H:SP_L) */
   avr_addr.sp_l = 0x3D + avr_current_arch->sfr_offset;
   avr_addr.sp_h = avr_addr.sp_l + 1;
@@ -447,13 +468,6 @@  avr_init_expanders (void)
 {
   int regno;
 
-  static bool done = false;
-
-  if (done)
-    return;
-  else
-    done = true;
-
   for (regno = 0; regno < 32; regno ++)
     all_regs_rtx[regno] = gen_rtx_REG (QImode, regno);
 
@@ -463,6 +477,10 @@  avr_init_expanders (void)
 
   lpm_addr_reg_rtx = gen_rtx_REG (HImode, REG_Z);
 
+  sreg_rtx = gen_rtx_MEM (QImode, GEN_INT (avr_addr.sreg));
+  rampd_rtx = gen_rtx_MEM (QImode, GEN_INT (avr_addr.rampd));
+  rampx_rtx = gen_rtx_MEM (QImode, GEN_INT (avr_addr.rampx));
+  rampy_rtx = gen_rtx_MEM (QImode, GEN_INT (avr_addr.rampy));
   rampz_rtx = gen_rtx_MEM (QImode, GEN_INT (avr_addr.rampz));
 
   xstring_empty = gen_rtx_CONST_STRING (VOIDmode, "");
@@ -900,6 +918,35 @@  emit_push_byte (unsigned regno, bool fra
   cfun->machine->stack_usage++;
 }
 
+
+/*  Helper for expand_prologue.  Emit a push of a SFR via tmp_reg.
+    SFR is a MEM representing the memory location of the SFR.
+    If CLR_P then clear the SFR after the push using zero_reg.  */
+
+static void
+emit_push_sfr (rtx sfr, bool frame_related_p, bool clr_p)
+{
+  rtx insn;
+  
+  gcc_assert (MEM_P (sfr));
+
+  /* IN __tmp_reg__, IO(SFR) */
+  insn = emit_move_insn (tmp_reg_rtx, sfr);
+  if (frame_related_p)
+    RTX_FRAME_RELATED_P (insn) = 1;
+  
+  /* PUSH __tmp_reg__ */
+  emit_push_byte (TMP_REGNO, frame_related_p);
+
+  if (clr_p)
+    {
+      /* OUT IO(SFR), __zero_reg__ */
+      insn = emit_move_insn (sfr, const0_rtx);
+      if (frame_related_p)
+        RTX_FRAME_RELATED_P (insn) = 1;
+    }
+}
+
 static void
 avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set)
 {
@@ -1058,7 +1105,7 @@  avr_prologue_setup_frame (HOST_WIDE_INT
              changed the CFA to the frame pointer this operation
              need not be annotated if frame pointer is needed.  */
               
-          if (AVR_HAVE_8BIT_SP)
+          if (AVR_HAVE_8BIT_SP || AVR_XMEGA)
             {
               insn = emit_move_insn (stack_pointer_rtx, fp);
             }
@@ -1163,26 +1210,42 @@  expand_prologue (void)
 
       /* Push SREG.  */
       /* ??? There's no dwarf2 column reserved for SREG.  */
-      emit_move_insn (tmp_reg_rtx,
-                      gen_rtx_MEM (QImode, GEN_INT (avr_addr.sreg)));
-      emit_push_byte (TMP_REGNO, false);
+      emit_push_sfr (sreg_rtx, false, false /* clr */);
 
-      /* Push RAMPZ.  */
-      /* ??? There's no dwarf2 column reserved for RAMPZ.  */
-      if (AVR_HAVE_RAMPZ 
-          && TEST_HARD_REG_BIT (set, REG_Z)
-          && TEST_HARD_REG_BIT (set, REG_Z + 1))
-        {
-          emit_move_insn (tmp_reg_rtx, rampz_rtx);
-          emit_push_byte (TMP_REGNO, false);
-        }
-        
       /* Clear zero reg.  */
       emit_move_insn (zero_reg_rtx, const0_rtx);
 
       /* Prevent any attempt to delete the setting of ZERO_REG!  */
       emit_use (zero_reg_rtx);
-    }
+
+      /* Push and clear RAMPD/X/Y/Z if present and low-part register is used.
+         ??? There are no dwarf2 columns reserved for RAMPD/X/Y/Z.  */
+      
+      if (AVR_HAVE_RAMPD)
+        emit_push_sfr (rampd_rtx, false /* frame-related */, true /* clr */);
+
+      if (AVR_HAVE_RAMPX
+          && TEST_HARD_REG_BIT (set, REG_X)
+          && TEST_HARD_REG_BIT (set, REG_X + 1))
+        {
+          emit_push_sfr (rampx_rtx, false /* frame-related */, true /* clr */);
+        }
+
+      if (AVR_HAVE_RAMPY
+          && (frame_pointer_needed
+              || (TEST_HARD_REG_BIT (set, REG_Y)
+                  && TEST_HARD_REG_BIT (set, REG_Y + 1))))
+        {
+          emit_push_sfr (rampy_rtx, false /* frame-related */, true /* clr */);
+        }
+
+      if (AVR_HAVE_RAMPZ 
+          && TEST_HARD_REG_BIT (set, REG_Z)
+          && TEST_HARD_REG_BIT (set, REG_Z + 1))
+        {
+          emit_push_sfr (rampz_rtx, false /* frame-related */, true /* clr */);
+        }
+    }  /* is_interrupt is_signal */
 
   avr_prologue_setup_frame (size, set);
   
@@ -1341,7 +1404,7 @@  expand_epilogue (bool sibcall_p)
 
       /* Copy to stack pointer.  */
               
-      if (AVR_HAVE_8BIT_SP)
+      if (AVR_HAVE_8BIT_SP || AVR_XMEGA)
         {
           emit_move_insn (stack_pointer_rtx, fp);
         }
@@ -1404,9 +1467,27 @@  expand_epilogue (bool sibcall_p)
 
   if (isr_p)
     {
-      /* Restore RAMPZ using tmp reg as scratch.  */
+      /* Restore RAMPZ/Y/X/D using tmp_reg as scratch.
+         The conditions to restore them must be tha same as in prologue.  */
       
-      if (AVR_HAVE_RAMPZ 
+      if (AVR_HAVE_RAMPX
+          && TEST_HARD_REG_BIT (set, REG_X)
+          && TEST_HARD_REG_BIT (set, REG_X + 1))
+        {
+          emit_pop_byte (TMP_REGNO);
+          emit_move_insn (rampx_rtx, tmp_reg_rtx);
+        }
+
+      if (AVR_HAVE_RAMPY
+          && (frame_pointer_needed
+              || (TEST_HARD_REG_BIT (set, REG_Y)
+                  && TEST_HARD_REG_BIT (set, REG_Y + 1))))
+        {
+          emit_pop_byte (TMP_REGNO);
+          emit_move_insn (rampy_rtx, tmp_reg_rtx);
+        }
+
+      if (AVR_HAVE_RAMPZ
           && TEST_HARD_REG_BIT (set, REG_Z)
           && TEST_HARD_REG_BIT (set, REG_Z + 1))
         {
@@ -1414,11 +1495,16 @@  expand_epilogue (bool sibcall_p)
           emit_move_insn (rampz_rtx, tmp_reg_rtx);
         }
 
-      /* Restore SREG using tmp reg as scratch.  */
+      if (AVR_HAVE_RAMPD)
+        {
+          emit_pop_byte (TMP_REGNO);
+          emit_move_insn (rampd_rtx, tmp_reg_rtx);
+        }
+
+      /* Restore SREG using tmp_reg as scratch.  */
       
       emit_pop_byte (TMP_REGNO);
-      emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (avr_addr.sreg)), 
-                      tmp_reg_rtx);
+      emit_move_insn (sreg_rtx, tmp_reg_rtx);
 
       /* Restore tmp REG.  */
       emit_pop_byte (TMP_REGNO);
@@ -1900,7 +1986,16 @@  avr_print_operand (FILE *file, rtx x, in
       else if (low_io_address_operand (x, VOIDmode)
                || high_io_address_operand (x, VOIDmode))
         {
-          if (ival == avr_addr.rampz)       fprintf (file, "__RAMPZ__");
+          if (AVR_HAVE_RAMPZ && ival == avr_addr.rampz)
+            fprintf (file, "__RAMPZ__");
+          else if (AVR_HAVE_RAMPY && ival == avr_addr.rampy)
+            fprintf (file, "__RAMPY__");
+          else if (AVR_HAVE_RAMPX && ival == avr_addr.rampx)
+            fprintf (file, "__RAMPX__");
+          else if (AVR_HAVE_RAMPD && ival == avr_addr.rampd)
+            fprintf (file, "__RAMPD__");
+          else if (AVR_XMEGA && ival == avr_addr.ccp)
+            fprintf (file, "__CCP__");
           else if (ival == avr_addr.sreg)   fprintf (file, "__SREG__");
           else if (ival == avr_addr.sp_l)   fprintf (file, "__SP_L__");
           else if (ival == avr_addr.sp_h)   fprintf (file, "__SP_H__");
@@ -2898,6 +2993,10 @@  output_movhi (rtx insn, rtx xop[], int *
             {
               if (AVR_HAVE_8BIT_SP)
                 return avr_asm_len ("out __SP_L__,%A1", xop, plen, -1);
+
+              if (AVR_XMEGA)
+                return avr_asm_len ("out __SP_L__,%A1" CR_TAB
+                                    "out __SP_H__,%B1", xop, plen, -2);
               
               /* Use simple load of SP if no interrupts are  used.  */
               
@@ -3872,6 +3971,118 @@  out_movqi_mr_r (rtx insn, rtx op[], int
   return avr_asm_len ("st %0,%1", op, plen, -1);
 }
 
+
+/* Helper for the next function for XMEGA.  It does the same
+   but with low byte first.  */
+
+static const char*
+avr_out_movhi_mr_r_xmega (rtx insn, rtx op[], int *plen)
+{
+  rtx dest = op[0];
+  rtx src = op[1];
+  rtx base = XEXP (dest, 0);
+  int reg_base = true_regnum (base);
+  int reg_src = true_regnum (src);
+  /* "volatile" forces writing high byte first, even if less efficient,
+     for correct operation with 16-bit I/O registers.  */
+  int mem_volatile_p = MEM_VOLATILE_P (dest);
+
+  if (CONSTANT_ADDRESS_P (base))
+    return optimize > 0 && io_address_operand (base, HImode)
+      ? avr_asm_len ("out %i0,%A1" CR_TAB
+                     "out %i0+1,%B1", op, plen, -2)
+
+      : avr_asm_len ("sts %m0,%A1" CR_TAB
+                     "sts %m0+1,%B1", op, plen, -4);
+  
+  if (reg_base > 0)
+    {
+      if (reg_base != REG_X)
+        return avr_asm_len ("st %0,%A1" CR_TAB
+                            "std %0+1,%B1", op, plen, -2);
+      
+      if (reg_src == REG_X)
+        /* "st X+,r26" and "st -X,r26" are undefined.  */
+        avr_asm_len ("mov __tmp_reg__,r27" CR_TAB
+                     "st X,r26"            CR_TAB
+                     "adiw r26,1"          CR_TAB
+                     "st X,__tmp_reg__", op, plen, -4);
+      else
+        avr_asm_len ("st X+,%A1" CR_TAB
+                     "st X,%B1", op, plen, -2);
+            
+      return reg_unused_after (insn, src)
+        ? ""
+        : avr_asm_len ("sbiw r26,1", op, plen, 1);
+    }
+  else if (GET_CODE (base) == PLUS)
+    {
+      int disp = INTVAL (XEXP (base, 1));
+      reg_base = REGNO (XEXP (base, 0));
+      if (disp > MAX_LD_OFFSET (GET_MODE (dest)))
+        {
+          if (reg_base != REG_Y)
+            fatal_insn ("incorrect insn:",insn);
+          
+          return disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))
+            ? avr_asm_len ("adiw r28,%o0-62" CR_TAB
+                           "std Y+62,%A1"    CR_TAB
+                           "std Y+63,%B1"    CR_TAB
+                           "sbiw r28,%o0-62", op, plen, -4)
+
+            : avr_asm_len ("subi r28,lo8(-%o0)" CR_TAB
+                           "sbci r29,hi8(-%o0)" CR_TAB
+                           "st Y,%A1"           CR_TAB
+                           "std Y+1,%B1"        CR_TAB
+                           "subi r28,lo8(%o0)"  CR_TAB
+                           "sbci r29,hi8(%o0)", op, plen, -6);
+        }
+      
+      if (reg_base != REG_X)
+        return avr_asm_len ("std %A0,%A1" CR_TAB
+                            "std %B0,%B1", op, plen, -2);
+      /* (X + d) = R */
+      return reg_src == REG_X
+        ? avr_asm_len ("mov __tmp_reg__,r26"  CR_TAB
+                       "mov __zero_reg__,r27" CR_TAB
+                       "adiw r26,%o0"         CR_TAB
+                       "st X+,__tmp_reg__"    CR_TAB
+                       "st X,__zero_reg__"    CR_TAB
+                       "clr __zero_reg__"     CR_TAB
+                       "sbiw r26,%o0+1", op, plen, -7)
+
+        : avr_asm_len ("adiw r26,%o0" CR_TAB
+                       "st X+,%A1"    CR_TAB
+                       "st X,%B1"     CR_TAB
+                       "sbiw r26,%o0+1", op, plen, -4);
+    }
+  else if (GET_CODE (base) == PRE_DEC) /* (--R) */
+    {
+      if (!mem_volatile_p)
+        return avr_asm_len ("st %0,%B1" CR_TAB
+                            "st %0,%A1", op, plen, -2);
+
+      return REGNO (XEXP (base, 0)) == REG_X
+        ? avr_asm_len ("sbiw r26,2"  CR_TAB
+                       "st X+,%A1"   CR_TAB
+                       "st X,%B1"    CR_TAB
+                       "sbiw r26,1", op, plen, -4)
+
+        : avr_asm_len ("sbiw %r0,2"  CR_TAB
+                       "st %p0,%A1"  CR_TAB
+                       "std %p0+1,%B1", op, plen, -3);
+    }
+  else if (GET_CODE (base) == POST_INC) /* (R++) */
+    {
+      return avr_asm_len ("st %0,%A1"  CR_TAB
+                          "st %0,%B1", op, plen, -2);
+      
+    }
+  fatal_insn ("unknown move insn:",insn);
+  return "";
+}
+
+
 static const char*
 out_movhi_mr_r (rtx insn, rtx op[], int *plen)
 {
@@ -3884,6 +4095,9 @@  out_movhi_mr_r (rtx insn, rtx op[], int
      for correct operation with 16-bit I/O registers.  */
   int mem_volatile_p = MEM_VOLATILE_P (dest);
 
+  if (AVR_XMEGA)
+    return avr_out_movhi_mr_r_xmega (insn, op, plen);
+
   if (CONSTANT_ADDRESS_P (base))
     return optimize > 0 && io_address_operand (base, HImode)
       ? avr_asm_len ("out %i0+1,%B1" CR_TAB
@@ -7329,7 +7543,16 @@  avr_file_start (void)
 
   fprintf (asm_out_file, "__SP_L__ = 0x%02x\n", avr_addr.sp_l - sfr_offset);
   fprintf (asm_out_file, "__SREG__ = 0x%02x\n", avr_addr.sreg - sfr_offset);
-  fprintf (asm_out_file, "__RAMPZ__ = 0x%02x\n", avr_addr.rampz - sfr_offset);
+  if (AVR_HAVE_RAMPZ)
+    fprintf (asm_out_file, "__RAMPZ__ = 0x%02x\n", avr_addr.rampz - sfr_offset);
+  if (AVR_HAVE_RAMPY)
+    fprintf (asm_out_file, "__RAMPY__ = 0x%02x\n", avr_addr.rampy - sfr_offset);
+  if (AVR_HAVE_RAMPX)
+    fprintf (asm_out_file, "__RAMPX__ = 0x%02x\n", avr_addr.rampx - sfr_offset);
+  if (AVR_HAVE_RAMPD)
+    fprintf (asm_out_file, "__RAMPD__ = 0x%02x\n", avr_addr.rampd - sfr_offset);
+  if (AVR_XMEGA)
+    fprintf (asm_out_file, "__CCP__ = 0x%02x\n", avr_addr.ccp - sfr_offset);
   fprintf (asm_out_file, "__tmp_reg__ = %d\n", TMP_REGNO);
   fprintf (asm_out_file, "__zero_reg__ = %d\n", ZERO_REGNO);
 }
Index: gcc/config/avr/avr.h
===================================================================
--- gcc/config/avr/avr.h	(revision 184156)
+++ gcc/config/avr/avr.h	(working copy)
@@ -46,11 +46,12 @@  struct base_arch_s
   /* Core have 'EICALL' and 'EIJMP' instructions.  */
   int have_eijmp_eicall;
 
-  /* Reserved for xmega architecture.  */
-  int reserved;
+  /* This is an XMEGA core.  */
+  int xmega_p;
 
-  /* Reserved for xmega architecture.  */
-  int reserved2;
+  /* This core has the RAMPD special function register
+     and thus also the RAMPX, RAMPY and RAMPZ registers.  */
+  int have_rampd;
   
   /* Default start of data section address for architecture.  */
   int default_data_section_start;
@@ -62,6 +63,7 @@  struct base_arch_s
   /* Number of 64k segments in the flash.  */
   int n_segments;
 
+  /* Architecture id to built-in define __AVR_ARCH__ (NULL -> no macro) */
   const char *const macro;
   
   /* Architecture name.  */
@@ -83,7 +85,12 @@  enum avr_arch
   ARCH_AVR4,
   ARCH_AVR5,
   ARCH_AVR51,
-  ARCH_AVR6
+  ARCH_AVR6,
+  ARCH_AVRXMEGA2,
+  ARCH_AVRXMEGA4,
+  ARCH_AVRXMEGA5,
+  ARCH_AVRXMEGA6,
+  ARCH_AVRXMEGA7
 };
 
 struct mcu_type_s {
@@ -175,13 +182,19 @@  enum
 #define AVR_HAVE_LPMX (avr_current_arch->have_movw_lpmx)
 #define AVR_HAVE_ELPM (avr_current_arch->have_elpm)
 #define AVR_HAVE_ELPMX (avr_current_arch->have_elpmx)
-#define AVR_HAVE_RAMPZ (avr_current_arch->have_elpm)
+#define AVR_HAVE_RAMPD (avr_current_arch->have_rampd)
+#define AVR_HAVE_RAMPX (avr_current_arch->have_rampd)
+#define AVR_HAVE_RAMPY (avr_current_arch->have_rampd)
+#define AVR_HAVE_RAMPZ (avr_current_arch->have_elpm             \
+                        || avr_current_arch->have_rampd)
 #define AVR_HAVE_EIJMP_EICALL (avr_current_arch->have_eijmp_eicall)
 #define AVR_HAVE_8BIT_SP (avr_current_device->short_sp || TARGET_TINY_STACK)
 
 #define AVR_2_BYTE_PC (!AVR_HAVE_EIJMP_EICALL)
 #define AVR_3_BYTE_PC (AVR_HAVE_EIJMP_EICALL)
 
+#define AVR_XMEGA (avr_current_arch->xmega_p)
+
 #define BITS_BIG_ENDIAN 0
 #define BYTES_BIG_ENDIAN 0
 #define WORDS_BIG_ENDIAN 0