This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch,AVR] Add xmega support


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.

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

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]