diff options
Diffstat (limited to 'devel/avr-gcc/files/patch-xmega')
-rw-r--r-- | devel/avr-gcc/files/patch-xmega | 812 |
1 files changed, 812 insertions, 0 deletions
diff --git a/devel/avr-gcc/files/patch-xmega b/devel/avr-gcc/files/patch-xmega new file mode 100644 index 000000000000..b1913b8bca76 --- /dev/null +++ b/devel/avr-gcc/files/patch-xmega @@ -0,0 +1,812 @@ +--- gcc/config/avr/avr.md.orig 2008-06-08 10:24:28.171355800 -0600 ++++ gcc/config/avr/avr.md 2008-06-08 10:29:58.610141800 -0600 +@@ -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) +@@ -2681,7 +2678,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")]) +@@ -2693,7 +2691,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")]) +Index: gcc/config/avr/predicates.md +=================================================================== +--- gcc/config/avr/predicates.md (revision 132445) ++++ gcc/config/avr/predicates.md (working copy) +@@ -45,12 +45,16 @@ + ;; Return true if OP is a valid address for lower half of I/O space. + (define_predicate "low_io_address_operand" + (and (match_code "const_int") +- (match_test "IN_RANGE((INTVAL (op)), 0x20, 0x3F)"))) ++ (if_then_else (match_test "AVR_XMEGA") ++ (match_test "IN_RANGE((INTVAL (op)), 0x00, 0x1F)") ++ (match_test "IN_RANGE((INTVAL (op)), 0x20, 0x3F)")))) + + ;; Return true if OP is a valid address for high half of I/O space. + (define_predicate "high_io_address_operand" + (and (match_code "const_int") +- (match_test "IN_RANGE((INTVAL (op)), 0x40, 0x5F)"))) ++ (if_then_else (match_test "AVR_XMEGA") ++ (match_test "IN_RANGE((INTVAL (op)), 0x20, 0x3F)") ++ (match_test "IN_RANGE((INTVAL (op)), 0x40, 0x5F)")))) + + ;; Return 1 if OP is the zero constant for MODE. + (define_predicate "const0_operand" +--- gcc/config/avr/t-avr.orig 2008-02-19 17:25:31.546827500 -0700 ++++ gcc/config/avr/t-avr 2008-02-20 09:22:51.709554900 -0700 +@@ -37,8 +37,8 @@ fp-bit.c: $(srcdir)/config/fp-bit.c $(sr + + 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=avrxmega4/mmcu=avrxmega5/mmcu=avrxmega6/mmcu=avrxmega7 ++MULTILIB_DIRNAMES = avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 avrxmega4 avrxmega5 avrxmega6 avrxmega7 + + # The many avr2 matches are not listed here - this is the default. + MULTILIB_MATCHES = \ +@@ -125,7 +125,13 @@ MULTILIB_MATCHES = \ + mmcu?avr51=mmcu?at90usb1286 \ + mmcu?avr51=mmcu?at90usb1287 \ + mmcu?avr6=mmcu?atmega2560 \ +- mmcu?avr6=mmcu?atmega2561 ++ mmcu?avr6=mmcu?atmega2561 \ ++ mmcu?avrxmega4=mmcu?atxmega64a3 \ ++ mmcu?avrxmega5=mmcu?atxmega64a1 \ ++ mmcu?avrxmega6=mmcu?atxmega128a3 \ ++ mmcu?avrxmega6=mmcu?atxmega256a3 \ ++ mmcu?avrxmega6=mmcu?atxmega256a3b \ ++ mmcu?avrxmega7=mmcu?atxmega128a1 + + MULTILIB_EXCEPTIONS = + +--- gcc/config/avr/avr.h.orig 2009-01-26 17:47:48.000000000 +0100 ++++ gcc/config/avr/avr.h 2009-01-26 17:56:22.000000000 +0100 +@@ -44,8 +44,11 @@ + /* Core have 'EICALL' and 'EIJMP' instructions. */ + int have_eijmp_eicall; + +- /* Reserved. */ +- int reserved; ++ /* Core is in Xmega family. */ ++ int xmega; ++ ++ /* Core have RAMPX, RAMPY and RAMPD registers. */ ++ int have_rampx_y_d; + + const char *const macro; + }; +@@ -68,6 +71,13 @@ + builtin_define ("__AVR_HAVE_ELPMX__"); \ + if (avr_have_movw_lpmx_p) \ + builtin_define ("__AVR_HAVE_MOVW__"); \ ++ if (avr_current_arch->have_elpm) \ ++ { \ ++ builtin_define ("__AVR_HAVE_RAMPZ__");\ ++ builtin_define ("__AVR_HAVE_ELPM__"); \ ++ } \ ++ if (avr_current_arch->have_elpmx) \ ++ builtin_define ("__AVR_HAVE_ELPMX__"); \ + if (avr_have_movw_lpmx_p) \ + builtin_define ("__AVR_HAVE_LPMX__"); \ + if (avr_asm_only_p) \ +@@ -88,6 +98,17 @@ + builtin_define ("__AVR_HAVE_EIJMP_EICALL__"); \ + if (TARGET_NO_INTERRUPTS) \ + builtin_define ("__NO_INTERRUPTS__"); \ ++ if (avr_current_arch->xmega) \ ++ { \ ++ builtin_define ("__AVR_XMEGA__"); \ ++ builtin_define ("__AVR_HAVE_SPMX__"); \ ++ } \ ++ if (avr_current_arch->have_rampx_y_d) \ ++ { \ ++ builtin_define ("__AVR_HAVE_RAMPX__");\ ++ builtin_define ("__AVR_HAVE_RAMPY__");\ ++ builtin_define ("__AVR_HAVE_RAMPD__");\ ++ } \ + } \ + while (0) + +@@ -107,10 +128,19 @@ + #define AVR_HAVE_LPMX (avr_have_movw_lpmx_p) + #define AVR_HAVE_RAMPZ (avr_current_arch->have_elpm) + #define AVR_HAVE_EIJMP_EICALL (avr_current_arch->have_eijmp_eicall) ++#define AVR_XMEGA (avr_current_arch->xmega) ++#define AVR_HAVE_RAMPX_Y_D (avr_current_arch->have_rampx_y_d) + + #define AVR_2_BYTE_PC (!AVR_HAVE_EIJMP_EICALL) + #define AVR_3_BYTE_PC (AVR_HAVE_EIJMP_EICALL) + ++#define AVR_IO_OFFSET (AVR_XMEGA ? 0 : 0x20) ++#define AVR_RAMPD_ADDR (AVR_XMEGA ? 0x38 : 0) ++#define AVR_RAMPX_ADDR (AVR_XMEGA ? 0x39 : 0) ++#define AVR_RAMPY_ADDR (AVR_XMEGA ? 0x3A : 0) ++#define AVR_RAMPZ_ADDR (AVR_XMEGA ? 0x3B : 0x5B) ++#define AVR_SREG_ADDR (AVR_XMEGA ? 0x3F: 0x5F) ++ + #define TARGET_VERSION fprintf (stderr, " (GNU assembler syntax)"); + + #define OVERRIDE_OPTIONS avr_override_options () +@@ -848,6 +878,11 @@ + mmcu=m3000*|\ + mmcu=m3001*: -m avr5}\ + %{mmcu=atmega256*:-m avr6}\ ++%{mmcu=atxmega64a3:-m avrxmega4} \ ++%{mmcu=atxmega64a1:-m avrxmega5} \ ++%{mmcu=atxmega128a3| \ ++ mmcu=atxmega256a3*:-m avrxmega6} \ ++%{mmcu=atxmega128a1:-m avrxmega7} \ + %{mmcu=atmega324*|\ + mmcu=atmega325*|\ + mmcu=atmega328p|\ +@@ -1024,7 +1059,13 @@ + %{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=atxmega4|mmcu=atxmega64a3:crtx64a3.o%s} \ ++%{mmcu=atxmega5|mmcu=atxmega64a1:crtx64a1.o%s} \ ++%{mmcu=atxmega6|mmcu=atxmega128a3:crtx128a3.o%s} \ ++%{mmcu=atxmega256a3:crtx256a3.o%s} \ ++%{mmcu=atxmega256a3b:crtx256a3b.o%s} \ ++%{mmcu=atxmega7|mmcu=atxmega128a1:crtx128a1.o%s}" + + #define EXTRA_SPECS {"crt_binutils", CRT_BINUTILS_SPECS}, + +@@ -1086,8 +1127,12 @@ + /* 'true' - if current function is a signal function + as specified by the "signal" attribute. */ + int is_signal; +- ++ + /* 'true' - if current function is a signal function ++ as specified by the "nmi" attribute. */ ++ int is_nmi; ++ ++ /* 'true' - if current function is a task function + as specified by the "OS_task" attribute. */ + int is_OS_task; + }; +--- gcc/config/avr/avr.c.orig 2009-01-26 17:44:48.000000000 +0100 ++++ gcc/config/avr/avr.c 2009-01-26 17:54:54.000000000 +0100 +@@ -51,6 +51,7 @@ + static int avr_naked_function_p (tree); + static int interrupt_function_p (tree); + static int signal_function_p (tree); ++static int nmi_function_p (tree); + static int avr_OS_task_function_p (tree); + static int avr_regs_to_save (HARD_REG_SET *); + static int sequent_regs_live (void); +@@ -118,17 +119,24 @@ + int avr_have_movw_lpmx_p = 0; + + static const struct base_arch_s avr_arch_types[] = { +- { 1, 0, 0, 0, 0, 0, 0, 0, NULL }, /* unknown device specified */ +- { 1, 0, 0, 0, 0, 0, 0, 0, "__AVR_ARCH__=1" }, +- { 0, 0, 0, 0, 0, 0, 0, 0, "__AVR_ARCH__=2" }, +- { 0, 0, 0, 1, 0, 0, 0, 0, "__AVR_ARCH__=25" }, +- { 0, 0, 1, 0, 0, 0, 0, 0, "__AVR_ARCH__=3" }, +- { 0, 0, 1, 0, 1, 0, 0, 0, "__AVR_ARCH__=31" }, +- { 0, 0, 1, 1, 0, 0, 0, 0, "__AVR_ARCH__=35" }, +- { 0, 1, 0, 1, 0, 0, 0, 0, "__AVR_ARCH__=4" }, +- { 0, 1, 1, 1, 0, 0, 0, 0, "__AVR_ARCH__=5" }, +- { 0, 1, 1, 1, 1, 1, 0, 0, "__AVR_ARCH__=51" }, +- { 0, 1, 1, 1, 1, 1, 1, 0, "__AVR_ARCH__=6" } ++ { 1, 0, 0, 0, 0, 0, 0, 0, 0, NULL }, /* Unknown device specified. */ ++ { 1, 0, 0, 0, 0, 0, 0, 0, 0, "__AVR_ARCH__=1" }, ++ { 0, 0, 0, 0, 0, 0, 0, 0, 0, "__AVR_ARCH__=2" }, ++ { 0, 0, 0, 1, 0, 0, 0, 0, 0, "__AVR_ARCH__=25" }, ++ { 0, 0, 1, 0, 0, 0, 0, 0, 0, "__AVR_ARCH__=3" }, ++ { 0, 0, 1, 0, 1, 0, 0, 0, 0, "__AVR_ARCH__=31" }, ++ { 0, 0, 1, 1, 0, 0, 0, 0, 0, "__AVR_ARCH__=35" }, ++ { 0, 1, 0, 1, 0, 0, 0, 0, 0, "__AVR_ARCH__=4" }, ++ { 0, 1, 1, 1, 0, 0, 0, 0, 0, "__AVR_ARCH__=5" }, ++ { 0, 1, 1, 1, 1, 1, 0, 0, 0, "__AVR_ARCH__=51" }, ++ { 0, 1, 1, 1, 1, 1, 1, 0, 0, "__AVR_ARCH__=6" }, ++ { 0, 1, 0, 1, 0, 0, 0, 1, 0, "__AVR_ARCH__=101" }, ++ { 0, 1, 1, 1, 0, 0, 0, 1, 0, "__AVR_ARCH__=102" }, ++ { 0, 1, 1, 1, 0, 0, 0, 1, 1, "__AVR_ARCH__=103" }, ++ { 0, 1, 1, 1, 1, 1, 0, 1, 0, "__AVR_ARCH__=104" }, ++ { 0, 1, 1, 1, 1, 1, 0, 1, 1, "__AVR_ARCH__=105" }, ++ { 0, 1, 1, 1, 1, 1, 1, 1, 0, "__AVR_ARCH__=106" }, ++ { 0, 1, 1, 1, 1, 1, 1, 1, 1, "__AVR_ARCH__=107" } + }; + + /* These names are used as the index into the avr_arch_types[] table +@@ -146,7 +154,14 @@ + ARCH_AVR4, + ARCH_AVR5, + ARCH_AVR51, +- ARCH_AVR6 ++ ARCH_AVR6, ++ ARCH_AVRXMEGA1, ++ ARCH_AVRXMEGA2, ++ ARCH_AVRXMEGA3, ++ ARCH_AVRXMEGA4, ++ ARCH_AVRXMEGA5, ++ ARCH_AVRXMEGA6, ++ ARCH_AVRXMEGA7 + }; + + struct mcu_type_s { +@@ -297,6 +312,24 @@ + { "avr6", ARCH_AVR6, NULL }, + { "atmega2560", ARCH_AVR6, "__AVR_ATmega2560__" }, + { "atmega2561", ARCH_AVR6, "__AVR_ATmega2561__" }, ++ /* Enhanced, == 256K. */ ++ /* Xmega, <= 8K FLASH. */ ++ /* Xmega, > 8K, <= 64K FLASH, <= 64K RAM. */ ++ /* Xmega, > 8K, <= 64K FLASH, > 64K RAM. */ ++ /* Xmega, > 64K, <= 128K FLASH, <= 64K RAM. */ ++ { "avrxmega4", ARCH_AVRXMEGA4, NULL }, ++ { "atxmega64a3", ARCH_AVRXMEGA4, "__AVR_ATxmega64A3__" }, ++ /* Xmega, > 64K, <= 128K FLASH, > 64K RAM. */ ++ { "avrxmega5", ARCH_AVRXMEGA5, NULL }, ++ { "atxmega64a1", ARCH_AVRXMEGA5, "__AVR_ATxmega64A1__" }, ++ /* Xmega, > 128K, <= 256K FLASH, <= 64K RAM. */ ++ { "avrxmega6", ARCH_AVRXMEGA6, NULL }, ++ { "atxmega128a3", ARCH_AVRXMEGA6, "__AVR_ATxmega128A3__" }, ++ { "atxmega256a3", ARCH_AVRXMEGA6, "__AVR_ATxmega256A3__" }, ++ { "atxmega256a3b",ARCH_AVRXMEGA6, "__AVR_ATxmega256A3B__" }, ++ /* Xmega, > 128K, <= 256K FLASH, > 64K RAM. */ ++ { "avrxmega7", ARCH_AVRXMEGA7, NULL }, ++ { "atxmega128a1", ARCH_AVRXMEGA7, "__AVR_ATxmega128A1__" }, + /* Assembler only. */ + { "avr1", ARCH_AVR1, NULL }, + { "at90s1200", ARCH_AVR1, "__AVR_AT90S1200__" }, +@@ -470,6 +503,21 @@ + return a != NULL_TREE; + } + ++/* Return nonzero if FUNC is a nmi function as specified ++ by the "nmi" attribute. */ ++ ++static int ++nmi_function_p (tree func) ++{ ++ tree a; ++ ++ if (TREE_CODE (func) != FUNCTION_DECL) ++ return 0; ++ ++ a = lookup_attribute ("nmi", DECL_ATTRIBUTES (func)); ++ return a != NULL_TREE; ++} ++ + /* Return nonzero if FUNC is a OS_task function. */ + + static int +@@ -629,6 +677,7 @@ + cfun->machine->is_naked = avr_naked_function_p (current_function_decl); + cfun->machine->is_interrupt = interrupt_function_p (current_function_decl); + cfun->machine->is_signal = signal_function_p (current_function_decl); ++ cfun->machine->is_nmi = nmi_function_p (current_function_decl); + cfun->machine->is_OS_task = avr_OS_task_function_p (current_function_decl); + + /* Prologue: naked. */ +@@ -664,17 +713,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; +@@ -949,14 +1029,39 @@ + && (TEST_HARD_REG_BIT (set, REG_Z) && TEST_HARD_REG_BIT (set, REG_Z + 1))) + { + emit_insn (gen_popqi (tmp_reg_rtx)); +- emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(RAMPZ_ADDR)), ++ emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(AVR_RAMPZ_ADDR)), + tmp_reg_rtx); + } + ++ /* Restore RAMPY, RAMPX, RAMPD using tmp reg as scratch. */ ++ if (AVR_HAVE_RAMPX_Y_D) ++ { ++ /* Pop RAMPY. */ ++ if (TEST_HARD_REG_BIT (set, REG_Y) && TEST_HARD_REG_BIT (set, REG_Y + 1)) ++ { ++ emit_insn (gen_popqi (tmp_reg_rtx)); ++ emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPY_ADDR)), ++ tmp_reg_rtx); ++ } ++ ++ /* Pop RAMPX. */ ++ if (TEST_HARD_REG_BIT (set, REG_X) && TEST_HARD_REG_BIT (set, REG_X + 1)) ++ { ++ emit_insn (gen_popqi (tmp_reg_rtx)); ++ emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPX_ADDR)), ++ tmp_reg_rtx); ++ } ++ ++ /* Pop RAMPD. */ ++ emit_insn (gen_popqi (tmp_reg_rtx)); ++ emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPD_ADDR)), ++ tmp_reg_rtx); ++ } ++ + /* Restore SREG using tmp reg as scratch. */ + emit_insn (gen_popqi (tmp_reg_rtx)); + +- emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(SREG_ADDR)), ++ emit_move_insn (gen_rtx_MEM(QImode, GEN_INT(AVR_SREG_ADDR)), + tmp_reg_rtx); + + /* Restore tmp REG. */ +@@ -1725,8 +1830,9 @@ + } + /* Use simple load of stack pointer if no interrupts are used + or inside main or signal function prologue where they disabled. */ +- else if (TARGET_NO_INTERRUPTS +- || (reload_completed ++ else if (TARGET_NO_INTERRUPTS ++ || (!AVR_XMEGA ++ && reload_completed + && cfun->machine->is_signal + && prologue_epilogue_contains (insn))) + { +@@ -1735,7 +1841,8 @@ + AS2 (out,__SP_L__,%A1)); + } + /* In interrupt prolog we know interrupts are enabled. */ +- else if (reload_completed ++ else if (!AVR_XMEGA ++ && reload_completed + && cfun->machine->is_interrupt + && prologue_epilogue_contains (insn)) + { +@@ -1745,12 +1852,25 @@ + "sei" CR_TAB + AS2 (out,__SP_L__,%A1)); + } +- *l = 5; +- return (AS2 (in,__tmp_reg__,__SREG__) CR_TAB +- "cli" CR_TAB +- AS2 (out,__SP_H__,%B1) CR_TAB +- AS2 (out,__SREG__,__tmp_reg__) CR_TAB +- AS2 (out,__SP_L__,%A1)); ++ if(AVR_XMEGA) ++ { ++ *l = 6; ++ return (AS2 (mov,__tmp_reg__,r24) CR_TAB ++ AS2 (ldi,r24,0xD8) CR_TAB ++ AS2 (out,__CCP__,r24) CR_TAB ++ AS2 (out,__SP_H__,%B1) CR_TAB ++ AS2 (out,__SP_L__,%A1) CR_TAB ++ AS2 (mov,r24,__tmp_reg__)); ++ } ++ else ++ { ++ *l = 5; ++ return (AS2 (in,__tmp_reg__,__SREG__) CR_TAB ++ "cli" CR_TAB ++ AS2 (out,__SP_H__,%B1) CR_TAB ++ AS2 (out,__SREG__,__tmp_reg__) CR_TAB ++ AS2 (out,__SP_L__,%A1)); ++ } + } + else if (test_hard_reg_class (STACK_REG, src)) + { +@@ -1885,7 +2005,7 @@ + + if (CONSTANT_ADDRESS_P (x)) + { +- if (CONST_INT_P (x) && INTVAL (x) == SREG_ADDR) ++ if (CONST_INT_P (x) && INTVAL (x) == AVR_SREG_ADDR) + { + *l = 1; + return AS2 (in,%0,__SREG__); +@@ -1893,7 +2013,8 @@ + if (avr_io_address_p (x, 1)) + { + *l = 1; +- return AS2 (in,%0,%1-0x20); ++ op[2] = GEN_INT(AVR_IO_OFFSET); ++ return AS2 (in,%0,%1-%2); + } + *l = 2; + return AS2 (lds,%0,%1); +@@ -2081,8 +2202,9 @@ + if (avr_io_address_p (base, 2)) + { + *l = 2; +- return (AS2 (in,%A0,%A1-0x20) CR_TAB +- AS2 (in,%B0,%B1-0x20)); ++ op[2] = GEN_INT(AVR_IO_OFFSET); ++ return (AS2 (in,%A0,%A1-%2) CR_TAB ++ AS2 (in,%B0,%B1-%2)); + } + *l = 4; + return (AS2 (lds,%A0,%A1) CR_TAB +@@ -2573,7 +2695,7 @@ + + if (CONSTANT_ADDRESS_P (x)) + { +- if (CONST_INT_P (x) && INTVAL (x) == SREG_ADDR) ++ if (CONST_INT_P (x) && INTVAL (x) == AVR_SREG_ADDR) + { + *l = 1; + return AS2 (out,__SREG__,%1); +@@ -2581,7 +2703,8 @@ + if (avr_io_address_p (x, 1)) + { + *l = 1; +- return AS2 (out,%0-0x20,%1); ++ op[2] = GEN_INT(AVR_IO_OFFSET); ++ return AS2 (out,%0-%2,%1); + } + *l = 2; + return AS2 (sts,%0,%1); +@@ -2660,11 +2783,20 @@ + if (avr_io_address_p (base, 2)) + { + *l = 2; +- return (AS2 (out,%B0-0x20,%B1) CR_TAB +- AS2 (out,%A0-0x20,%A1)); ++ op[2] = GEN_INT(AVR_IO_OFFSET); ++ if (AVR_XMEGA) ++ return (AS2 (out,%A0-%2,%B1) CR_TAB ++ AS2 (out,%B0-%2,%A1)); ++ else ++ return (AS2 (out,%B0-%2,%B1) CR_TAB ++ AS2 (out,%A0-%2,%A1)); + } +- return *l = 4, (AS2 (sts,%B0,%B1) CR_TAB +- AS2 (sts,%A0,%A1)); ++ if (AVR_XMEGA) ++ return *l = 4, (AS2 (sts,%A0,%A1) CR_TAB ++ AS2 (sts,%B0,%B1)); ++ else ++ return *l = 4, (AS2 (sts,%B0,%B1) CR_TAB ++ AS2 (sts,%A0,%A1)); + } + if (reg_base > 0) + { +@@ -2679,11 +2811,20 @@ + AS2 (adiw,r26,1) CR_TAB + AS2 (st,X,__tmp_reg__)); + else +- return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB +- AS2 (adiw,r26,1) CR_TAB +- AS2 (st,X,__tmp_reg__) CR_TAB +- AS2 (sbiw,r26,1) CR_TAB +- AS2 (st,X,r26)); ++ { ++ if (!AVR_XMEGA) ++ return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB ++ AS2 (adiw,r26,1) CR_TAB ++ AS2 (st,X,__tmp_reg__) CR_TAB ++ AS2 (sbiw,r26,1) CR_TAB ++ AS2 (st,X,r26)); ++ else ++ return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB ++ AS2 (st,X,r26) CR_TAB ++ AS2 (adiw,r26,1) CR_TAB ++ AS2 (st,X,__tmp_reg__) CR_TAB ++ AS2 (sbiw,r26,1)); ++ } + } + else + { +@@ -2691,14 +2832,27 @@ + return *l=2, (AS2 (st,X+,%A1) CR_TAB + AS2 (st,X,%B1)); + else +- return *l=3, (AS2 (adiw,r26,1) CR_TAB +- AS2 (st,X,%B1) CR_TAB +- AS2 (st,-X,%A1)); ++ { ++ if (!AVR_XMEGA) ++ return *l=3, (AS2 (adiw,r26,1) CR_TAB ++ AS2 (st,X,%B1) CR_TAB ++ AS2 (st,-X,%A1)); ++ else ++ return *l=3, (AS2 (st,X+,%A1) CR_TAB ++ AS2 (st,X,%B1) CR_TAB ++ AS2 (sbiw,r26,1)); ++ } + } + } + else +- return *l=2, (AS2 (std,%0+1,%B1) CR_TAB +- AS2 (st,%0,%A1)); ++ { ++ if (!AVR_XMEGA) ++ return *l=2, (AS2 (std,%0+1,%B1) CR_TAB ++ AS2 (st,%0,%A1)); ++ else ++ return *l=2, (AS2 (st,%0,%A1) CR_TAB ++ AS2 (std,%0+1,%B1)); ++ } + } + else if (GET_CODE (base) == PLUS) + { +@@ -2709,48 +2863,104 @@ + if (reg_base != REG_Y) + fatal_insn ("incorrect insn:",insn); + +- if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))) +- return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB +- AS2 (std,Y+63,%B1) CR_TAB +- AS2 (std,Y+62,%A1) CR_TAB +- AS2 (sbiw,r28,%o0-62)); +- +- return *l = 6, (AS2 (subi,r28,lo8(-%o0)) CR_TAB +- AS2 (sbci,r29,hi8(-%o0)) CR_TAB +- AS2 (std,Y+1,%B1) CR_TAB +- AS2 (st,Y,%A1) CR_TAB +- AS2 (subi,r28,lo8(%o0)) CR_TAB +- AS2 (sbci,r29,hi8(%o0))); ++ if (!AVR_XMEGA) ++ { ++ if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))) ++ return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB ++ AS2 (std,Y+63,%B1) CR_TAB ++ AS2 (std,Y+62,%A1) CR_TAB ++ AS2 (sbiw,r28,%o0-62)); ++ ++ return *l = 6, (AS2 (subi,r28,lo8(-%o0)) CR_TAB ++ AS2 (sbci,r29,hi8(-%o0)) CR_TAB ++ AS2 (std,Y+1,%B1) CR_TAB ++ AS2 (st,Y,%A1) CR_TAB ++ AS2 (subi,r28,lo8(%o0)) CR_TAB ++ AS2 (sbci,r29,hi8(%o0))); ++ } ++ else ++ { ++ if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))) ++ return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB ++ AS2 (std,Y+62,%A1) CR_TAB ++ AS2 (std,Y+63,%B1) CR_TAB ++ AS2 (sbiw,r28,%o0-62)); ++ ++ return *l = 6, (AS2 (subi,r28,lo8(-%o0)) CR_TAB ++ AS2 (sbci,r29,hi8(-%o0)) CR_TAB ++ AS2 (st,Y,%A1) CR_TAB ++ AS2 (std,Y+1,%B1) CR_TAB ++ AS2 (subi,r28,lo8(%o0)) CR_TAB ++ AS2 (sbci,r29,hi8(%o0))); ++ } + } + if (reg_base == REG_X) + { + /* (X + d) = R */ + if (reg_src == REG_X) + { +- *l = 7; +- return (AS2 (mov,__tmp_reg__,r26) CR_TAB +- AS2 (mov,__zero_reg__,r27) CR_TAB +- AS2 (adiw,r26,%o0+1) CR_TAB +- AS2 (st,X,__zero_reg__) CR_TAB +- AS2 (st,-X,__tmp_reg__) CR_TAB +- AS1 (clr,__zero_reg__) CR_TAB ++ if (!AVR_XMEGA) ++ { ++ *l = 7; ++ return (AS2 (mov,__tmp_reg__,r26) CR_TAB ++ AS2 (mov,__zero_reg__,r27) CR_TAB ++ AS2 (adiw,r26,%o0+1) CR_TAB ++ AS2 (st,X,__zero_reg__) CR_TAB ++ AS2 (st,-X,__tmp_reg__) CR_TAB ++ AS1 (clr,__zero_reg__) CR_TAB ++ AS2 (sbiw,r26,%o0)); ++ } ++ else ++ { ++ *l = 7; ++ return (AS2 (mov,__tmp_reg__,r26) CR_TAB ++ AS2 (mov,__zero_reg__,r27) CR_TAB ++ AS2 (adiw,r26,%o0) CR_TAB ++ AS2 (st,X+,__tmp_reg__) CR_TAB ++ AS2 (st,X,__zero_reg__) CR_TAB ++ AS1 (clr,__zero_reg__) CR_TAB ++ AS2 (sbiw,r26,%o0+1)); ++ } ++ } ++ if (!AVR_XMEGA) ++ { ++ *l = 4; ++ return (AS2 (adiw,r26,%o0+1) CR_TAB ++ AS2 (st,X,%B1) CR_TAB ++ AS2 (st,-X,%A1) CR_TAB + AS2 (sbiw,r26,%o0)); + } +- *l = 4; +- return (AS2 (adiw,r26,%o0+1) CR_TAB +- AS2 (st,X,%B1) CR_TAB +- AS2 (st,-X,%A1) CR_TAB +- AS2 (sbiw,r26,%o0)); ++ else ++ { ++ *l = 4; ++ return (AS2 (adiw,r26,%o0) CR_TAB ++ AS2 (st,X+,%A1) CR_TAB ++ AS2 (st,X,%B1) CR_TAB ++ AS2 (sbiw,r26,%o0+1)); ++ } + } +- return *l=2, (AS2 (std,%B0,%B1) CR_TAB +- AS2 (std,%A0,%A1)); ++ ++ if (!AVR_XMEGA) ++ return *l=2, (AS2 (std,%B0,%B1) CR_TAB ++ AS2 (std,%A0,%A1)); ++ else ++ return *l=2, (AS2 (std,%A0,%A1) CR_TAB ++ AS2 (std,%B0,%B1)); + } + else if (GET_CODE (base) == PRE_DEC) /* (--R) */ +- return *l=2, (AS2 (st,%0,%B1) CR_TAB +- AS2 (st,%0,%A1)); ++ { ++ if (mem_volatile_p && AVR_XMEGA) ++ return *l = 4, (AS2 (sbiw,%r0,1) CR_TAB ++ AS2 (st,%p0+,%A1) CR_TAB ++ AS2 (st,%p0,%B1) CR_TAB ++ AS2 (sbiw,%r0,2)); ++ else ++ return *l=2, (AS2 (st,%0,%B1) CR_TAB ++ AS2 (st,%0,%A1)); ++ } + else if (GET_CODE (base) == POST_INC) /* (R++) */ + { +- if (mem_volatile_p) ++ if (mem_volatile_p && !AVR_XMEGA) + { + if (REGNO (XEXP (base, 0)) == REG_X) + { +@@ -2771,7 +2981,7 @@ + + *l = 2; + return (AS2 (st,%0,%A1) CR_TAB +- AS2 (st,%0,%B1)); ++ AS2 (st,%0,%B1)); + } + fatal_insn ("unknown move insn:",insn); + return ""; +@@ -4651,6 +4861,7 @@ + { "progmem", 0, 0, false, false, false, avr_handle_progmem_attribute }, + { "signal", 0, 0, true, false, false, avr_handle_fndecl_attribute }, + { "interrupt", 0, 0, true, false, false, avr_handle_fndecl_attribute }, ++ { "nmi", 0, 0, true, false, false, avr_handle_fndecl_attribute }, + { "naked", 0, 0, false, true, true, avr_handle_fntype_attribute }, + { "OS_task", 0, 0, false, true, true, avr_handle_fntype_attribute }, + { NULL, 0, 0, false, false, false, NULL } +@@ -4739,6 +4950,14 @@ + func_name); + } + } ++ else if (strncmp (attr, "nmi", strlen ("nmi")) == 0) ++ { ++ if (strncmp (func_name, "__vector", strlen ("__vector")) != 0) ++ { ++ warning (0, "%qs appears to be a misspelled nmi handler", ++ func_name); ++ } ++ } + } + + return NULL_TREE; +@@ -4864,7 +5083,8 @@ + /* fprintf (asm_out_file, "\t.arch %s\n", avr_mcu_name);*/ + fputs ("__SREG__ = 0x3f\n" + "__SP_H__ = 0x3e\n" +- "__SP_L__ = 0x3d\n", asm_out_file); ++ "__SP_L__ = 0x3d\n" ++ "__CCP__ = 0x34\n", asm_out_file); + + fputs ("__tmp_reg__ = 0\n" + "__zero_reg__ = 1\n", asm_out_file); +@@ -5754,15 +5974,18 @@ + return !(regno & 1); + } + +-/* Returns 1 if X is a valid address for an I/O register of size SIZE +- (1 or 2). Used for lds/sts -> in/out optimization. Add 0x20 to SIZE +- to check for the lower half of I/O space (for cbi/sbi/sbic/sbis). */ ++/* Returns 1 if X is a valid address for an I/O register of size SIZE ++ (1 or 2). Used for lds/sts -> in/out optimization. */ + + int + avr_io_address_p (rtx x, int size) + { +- return (optimize > 0 && GET_CODE (x) == CONST_INT +- && INTVAL (x) >= 0x20 && INTVAL (x) <= 0x60 - size); ++ if(AVR_XMEGA) ++ return (optimize > 0 && GET_CODE (x) == CONST_INT ++ && INTVAL (x) >= 0 && INTVAL (x) <= 0x40 - size); ++ else ++ return (optimize > 0 && GET_CODE (x) == CONST_INT ++ && INTVAL (x) >= 0x20 && INTVAL (x) <= 0x60 - size); + } + + const char * +@@ -5940,16 +6163,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 |