diff -Naurp gcc/config/avr/avr.c gcc/config/avr/avr.c --- gcc/config/avr/avr.c 2011-10-27 16:55:55.000000000 +0530 +++ gcc/config/avr/avr.c 2011-10-27 17:00:24.000000000 +0530 @@ -52,6 +52,7 @@ static void avr_option_override (void); static int avr_naked_function_p (tree); static int interrupt_function_p (tree); static int signal_function_p (tree); +static int nmi_function_p (tree); static int avr_OS_task_function_p (tree); static int avr_OS_main_function_p (tree); static int avr_regs_to_save (HARD_REG_SET *); @@ -131,6 +132,7 @@ static const struct attribute_spec avr_a { "progmem", 0, 0, false, false, false, avr_handle_progmem_attribute }, { "signal", 0, 0, true, false, false, avr_handle_fndecl_attribute }, { "interrupt", 0, 0, true, false, false, avr_handle_fndecl_attribute }, + { "nmi", 0, 0, true, false, false, avr_handle_fndecl_attribute }, { "naked", 0, 0, false, true, true, avr_handle_fntype_attribute }, { "OS_task", 0, 0, false, true, true, avr_handle_fntype_attribute }, { "OS_main", 0, 0, false, true, true, avr_handle_fntype_attribute }, @@ -391,6 +393,21 @@ signal_function_p (tree func) 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 @@ -655,6 +672,7 @@ expand_prologue (void) cfun->machine->is_naked = avr_naked_function_p (current_function_decl); cfun->machine->is_interrupt = interrupt_function_p (current_function_decl); cfun->machine->is_signal = signal_function_p (current_function_decl); + cfun->machine->is_nmi = nmi_function_p (current_function_decl); cfun->machine->is_OS_task = avr_OS_task_function_p (current_function_decl); cfun->machine->is_OS_main = avr_OS_main_function_p (current_function_decl); cfun->machine->stack_usage = 0; @@ -688,9 +706,40 @@ 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 (SREG_ADDR))); + emit_move_insn (tmp_reg_rtx, gen_rtx_MEM (QImode, GEN_INT (AVR_SREG_ADDR))); emit_push_byte (TMP_REGNO, false); + /* Push RAMPD, RAMPX, RAMPY. */ + /* + Clear RAMP? registers if used for data access in the interrupt/signal + context. Do this after the zero register has been explictly cleared. + */ + if (AVR_HAVE_RAMPX_Y_D) + { + /* Push RAMPD. */ + emit_move_insn (tmp_reg_rtx, + gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPD_ADDR))); + emit_push_byte (TMP_REGNO, false); + + /* Push RAMPX. */ + if (TEST_HARD_REG_BIT (set, REG_X) && TEST_HARD_REG_BIT (set, REG_X + 1)) + { + emit_move_insn (tmp_reg_rtx, + gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPX_ADDR))); + emit_push_byte (TMP_REGNO, false); + } + + /* Push RAMPY. */ + if (TEST_HARD_REG_BIT (set, REG_Y) && TEST_HARD_REG_BIT (set, REG_Y + 1)) + { + emit_move_insn (tmp_reg_rtx, + gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPY_ADDR))); + emit_push_byte (TMP_REGNO, false); + } + + } + + /* Push RAMPZ. */ /* ??? There's no dwarf2 column reserved for RAMPZ. */ if (AVR_HAVE_RAMPZ @@ -698,7 +747,7 @@ expand_prologue (void) && TEST_HARD_REG_BIT (set, REG_Z + 1)) { emit_move_insn (tmp_reg_rtx, - gen_rtx_MEM (QImode, GEN_INT (RAMPZ_ADDR))); + gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPZ_ADDR))); emit_push_byte (TMP_REGNO, false); } @@ -707,6 +756,8 @@ expand_prologue (void) /* Prevent any attempt to delete the setting of ZERO_REG! */ emit_use (zero_reg_rtx); + + } if (minimize && (frame_pointer_needed || (AVR_2_BYTE_PC && live_seq > 6) @@ -829,14 +880,14 @@ expand_prologue (void) { emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); } - else if (TARGET_NO_INTERRUPTS + else if ((!AVR_XMEGA && TARGET_NO_INTERRUPTS ) || cfun->machine->is_signal || cfun->machine->is_OS_main) { emit_insn (gen_movhi_sp_r_irq_off (stack_pointer_rtx, frame_pointer_rtx)); } - else if (cfun->machine->is_interrupt) + else if (!AVR_XMEGA && cfun->machine->is_interrupt) { emit_insn (gen_movhi_sp_r_irq_on (stack_pointer_rtx, frame_pointer_rtx)); @@ -1018,13 +1069,13 @@ expand_epilogue (void) { emit_move_insn (stack_pointer_rtx, frame_pointer_rtx); } - else if (TARGET_NO_INTERRUPTS - || cfun->machine->is_signal) + else if ((!AVR_XMEGA && TARGET_NO_INTERRUPTS) + || (!AVR_XMEGA && cfun->machine->is_signal)) { emit_insn (gen_movhi_sp_r_irq_off (stack_pointer_rtx, frame_pointer_rtx)); } - else if (cfun->machine->is_interrupt) + else if (!AVR_XMEGA && cfun->machine->is_interrupt) { emit_insn (gen_movhi_sp_r_irq_on (stack_pointer_rtx, frame_pointer_rtx)); @@ -1082,14 +1133,38 @@ expand_epilogue (void) && TEST_HARD_REG_BIT (set, REG_Z + 1)) { emit_pop_byte (TMP_REGNO); - 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_pop_byte (TMP_REGNO); - 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. */ @@ -1880,9 +1955,17 @@ output_movhi (rtx insn, rtx operands[], return *l = 1, AS2 (out,__SP_L__,%A1); /* Use simple load of stack pointer if no interrupts are used. */ - else if (TARGET_NO_INTERRUPTS) + else if (!AVR_XMEGA && TARGET_NO_INTERRUPTS) return *l = 2, (AS2 (out,__SP_H__,%B1) CR_TAB AS2 (out,__SP_L__,%A1)); + if(AVR_XMEGA) + { + *l = 2; + return (AS2 (out,__SP_L__,%A1) CR_TAB + AS2 (out,__SP_H__,%B1)); + } + else + { *l = 5; return (AS2 (in,__tmp_reg__,__SREG__) CR_TAB "cli" CR_TAB @@ -1890,6 +1973,7 @@ output_movhi (rtx insn, rtx operands[], AS2 (out,__SREG__,__tmp_reg__) CR_TAB AS2 (out,__SP_L__,%A1)); } + } else if (test_hard_reg_class (STACK_REG, src)) { *l = 2; @@ -2023,7 +2107,7 @@ out_movqi_r_mr (rtx insn, rtx op[], int 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__); @@ -2031,7 +2115,8 @@ out_movqi_r_mr (rtx insn, rtx op[], int if (optimize > 0 && io_address_operand (x, QImode)) { *l = 1; - return AS2 (in,%0,%m1-0x20); + op[2] = GEN_INT(AVR_IO_OFFSET); + return AS2 (in,%0,%m1-%2); } *l = 2; return AS2 (lds,%0,%m1); @@ -2219,8 +2304,9 @@ out_movhi_r_mr (rtx insn, rtx op[], int if (optimize > 0 && io_address_operand (base, HImode)) { *l = 2; - return (AS2 (in,%A0,%m1-0x20) CR_TAB - AS2 (in,%B0,%m1+1-0x20)); + op[2] = GEN_INT(AVR_IO_OFFSET); + return (AS2 (in,%A0,%m1-%2) CR_TAB + AS2 (in,%B0,%m1+1-%2)); } *l = 4; return (AS2 (lds,%A0,%m1) CR_TAB @@ -2719,7 +2805,7 @@ out_movqi_mr_r (rtx insn, rtx op[], int 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); @@ -2727,7 +2813,8 @@ out_movqi_mr_r (rtx insn, rtx op[], int if (optimize > 0 && io_address_operand (x, QImode)) { *l = 1; - return AS2 (out,%m0-0x20,%1); + op[2] = GEN_INT(AVR_IO_OFFSET); + return AS2 (out,%m0-%2,%1); } *l = 2; return AS2 (sts,%m0,%1); @@ -2806,9 +2893,18 @@ out_movhi_mr_r (rtx insn, rtx op[], int if (optimize > 0 && io_address_operand (base, HImode)) { *l = 2; - return (AS2 (out,%m0+1-0x20,%B1) CR_TAB - AS2 (out,%m0-0x20,%A1)); + op[2] = GEN_INT(AVR_IO_OFFSET); + if (AVR_XMEGA) + return (AS2 (out,%A0-%2,%A1) CR_TAB + AS2 (out,%B0-%2,%B1)); + else + return (AS2 (out,%m0+1-%2,%B1) CR_TAB + AS2 (out,%m0-%2,%A1)); } + if (AVR_XMEGA) + return *l = 4, (AS2 (sts,%A0,%A1) CR_TAB + AS2 (sts,%B0,%B1)); + else return *l = 4, (AS2 (sts,%m0+1,%B1) CR_TAB AS2 (sts,%m0,%A1)); } @@ -2825,11 +2921,20 @@ out_movhi_mr_r (rtx insn, rtx op[], int AS2 (adiw,r26,1) CR_TAB AS2 (st,X,__tmp_reg__)); else + { + if (!AVR_XMEGA) return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB AS2 (adiw,r26,1) CR_TAB AS2 (st,X,__tmp_reg__) CR_TAB AS2 (sbiw,r26,1) CR_TAB AS2 (st,X,r26)); + else + return *l=5, (AS2 (mov,__tmp_reg__,r27) CR_TAB + AS2 (st,X,r26) CR_TAB + AS2 (adiw,r26,1) CR_TAB + AS2 (st,X,__tmp_reg__) CR_TAB + AS2 (sbiw,r26,1)); + } } else { @@ -2837,14 +2942,27 @@ out_movhi_mr_r (rtx insn, rtx op[], int return *l=2, (AS2 (st,X+,%A1) CR_TAB AS2 (st,X,%B1)); else + { + if (!AVR_XMEGA) return *l=3, (AS2 (adiw,r26,1) CR_TAB AS2 (st,X,%B1) CR_TAB AS2 (st,-X,%A1)); + else + return *l=3, (AS2 (st,X+,%A1) CR_TAB + AS2 (st,X,%B1) CR_TAB + AS2 (sbiw,r26,1)); + } } } else + { + if (!AVR_XMEGA) return *l=2, (AS2 (std,%0+1,%B1) CR_TAB AS2 (st,%0,%A1)); + else + return *l=2, (AS2 (st,%0,%A1) CR_TAB + AS2 (std,%0+1,%B1)); + } } else if (GET_CODE (base) == PLUS) { @@ -2855,6 +2973,8 @@ out_movhi_mr_r (rtx insn, rtx op[], int if (reg_base != REG_Y) fatal_insn ("incorrect insn:",insn); + if (!AVR_XMEGA) + { if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))) return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB AS2 (std,Y+63,%B1) CR_TAB @@ -2868,11 +2988,29 @@ out_movhi_mr_r (rtx insn, rtx op[], int AS2 (subi,r28,lo8(%o0)) CR_TAB AS2 (sbci,r29,hi8(%o0))); } + else + { + if (disp <= 63 + MAX_LD_OFFSET (GET_MODE (dest))) + return *l = 4, (AS2 (adiw,r28,%o0-62) CR_TAB + AS2 (std,Y+62,%A1) CR_TAB + AS2 (std,Y+63,%B1) CR_TAB + AS2 (sbiw,r28,%o0-62)); + + return *l = 6, (AS2 (subi,r28,lo8(-%o0)) CR_TAB + AS2 (sbci,r29,hi8(-%o0)) CR_TAB + AS2 (st,Y,%A1) CR_TAB + AS2 (std,Y+1,%B1) CR_TAB + AS2 (subi,r28,lo8(%o0)) CR_TAB + AS2 (sbci,r29,hi8(%o0))); + } + } if (reg_base == REG_X) { /* (X + d) = R */ if (reg_src == REG_X) { + if (!AVR_XMEGA) + { *l = 7; return (AS2 (mov,__tmp_reg__,r26) CR_TAB AS2 (mov,__zero_reg__,r27) CR_TAB @@ -2882,21 +3020,57 @@ out_movhi_mr_r (rtx insn, rtx op[], int AS1 (clr,__zero_reg__) CR_TAB AS2 (sbiw,r26,%o0)); } + else + { + *l = 7; + return (AS2 (mov,__tmp_reg__,r26) CR_TAB + AS2 (mov,__zero_reg__,r27) CR_TAB + AS2 (adiw,r26,%o0) CR_TAB + AS2 (st,X+,__tmp_reg__) CR_TAB + AS2 (st,X,__zero_reg__) CR_TAB + AS1 (clr,__zero_reg__) CR_TAB + AS2 (sbiw,r26,%o0+1)); + } + } + if (!AVR_XMEGA) + { *l = 4; return (AS2 (adiw,r26,%o0+1) CR_TAB AS2 (st,X,%B1) CR_TAB AS2 (st,-X,%A1) CR_TAB AS2 (sbiw,r26,%o0)); } + else + { + *l = 4; + return (AS2 (adiw,r26,%o0) CR_TAB + AS2 (st,X+,%A1) CR_TAB + AS2 (st,X,%B1) CR_TAB + AS2 (sbiw,r26,%o0+1)); + } + } + + if (!AVR_XMEGA) return *l=2, (AS2 (std,%B0,%B1) CR_TAB AS2 (std,%A0,%A1)); + else + return *l=2, (AS2 (std,%A0,%A1) CR_TAB + AS2 (std,%B0,%B1)); } else if (GET_CODE (base) == PRE_DEC) /* (--R) */ + { + if (mem_volatile_p && AVR_XMEGA) + return *l = 4, (AS2 (sbiw,%r0,2) CR_TAB + AS2 (st,%p0+,%A1) CR_TAB + AS2 (st,%p0,%B1) CR_TAB + AS2 (sbiw,%r0,1)); + else return *l=2, (AS2 (st,%0,%B1) CR_TAB AS2 (st,%0,%A1)); + } else if (GET_CODE (base) == POST_INC) /* (R++) */ { - if (mem_volatile_p) + if (mem_volatile_p && !AVR_XMEGA) { if (REGNO (XEXP (base, 0)) == REG_X) { @@ -5047,6 +5221,16 @@ avr_asm_declare_function_name (FILE *fil } } + else if (cfun->machine->is_nmi) + { + if (strncmp (name, "__vector", strlen ("__vector")) != 0) + { + warning_at (DECL_SOURCE_LOCATION (decl), 0, + "%qs appears to be a misspelled nmi handler", + name); + } + } + ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function"); ASM_OUTPUT_LABEL (file, name); } @@ -5387,7 +5571,8 @@ avr_file_start (void) /* 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); @@ -6527,16 +6712,17 @@ avr_out_sbxx_branch (rtx insn, rtx opera 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,%m1-0x20,%2), operands); + output_asm_insn (AS2 (sbis,%1-%4,%2), operands); else - output_asm_insn (AS2 (sbic,%m1-0x20,%2), operands); + output_asm_insn (AS2 (sbic,%1-%4,%2), operands); } else { - output_asm_insn (AS2 (in,__tmp_reg__,%m1-0x20), operands); + output_asm_insn (AS2 (in,__tmp_reg__,%1-%4), operands); if (comp == EQ) output_asm_insn (AS2 (sbrs,__tmp_reg__,%2), operands); else diff -Naurp gcc/config/avr/avr-c.c gcc/config/avr/avr-c.c --- gcc/config/avr/avr-c.c 2011-10-27 16:55:06.000000000 +0530 +++ gcc/config/avr/avr-c.c 2011-10-27 17:00:24.000000000 +0530 @@ -81,5 +81,18 @@ avr_cpu_cpp_builtins (struct cpp_reader if (TARGET_NO_INTERRUPTS) cpp_define (pfile, "__NO_INTERRUPTS__"); + + if (avr_current_arch->xmega) + { + cpp_define (pfile, "__AVR_XMEGA__"); + cpp_define (pfile, "__AVR_HAVE_SPMX__"); + } + if (avr_current_arch->have_rampx_y_d) + { + cpp_define (pfile, "__AVR_HAVE_RAMPX__"); + cpp_define (pfile, "__AVR_HAVE_RAMPY__"); + cpp_define (pfile, "__AVR_HAVE_RAMPD__"); + } + } diff -Naurp gcc/config/avr/avr-devices.c gcc/config/avr/avr-devices.c --- gcc/config/avr/avr-devices.c 2011-10-27 16:55:06.000000000 +0530 +++ gcc/config/avr/avr-devices.c 2011-10-27 17:00:24.000000000 +0530 @@ -36,7 +36,14 @@ const struct base_arch_s avr_arch_types[ { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=4", "avr4" }, { 0, 1, 1, 1, 0, 0, 0, 0, 0, 0x0060, "__AVR_ARCH__=5", "avr5" }, { 0, 1, 1, 1, 1, 1, 0, 0, 0, 0x0060, "__AVR_ARCH__=51", "avr51" }, - { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0x0060, "__AVR_ARCH__=6", "avr6" } + { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0x0060, "__AVR_ARCH__=6", "avr6" }, + { 0, 1, 0, 1, 0, 0, 0, 1, 0, 0x2000, "__AVR_ARCH__=101", "avrxmega1" }, + { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0x2000, "__AVR_ARCH__=102", "avrxmega2" }, + { 0, 1, 1, 1, 0, 0, 0, 1, 1, 0x2000, "__AVR_ARCH__=103", "avrxmega3" }, + { 0, 1, 1, 1, 1, 1, 0, 1, 0, 0x2000, "__AVR_ARCH__=104", "avrxmega4" }, + { 0, 1, 1, 1, 1, 1, 0, 1, 1, 0x2000, "__AVR_ARCH__=105", "avrxmega5" }, + { 0, 1, 1, 1, 1, 1, 1, 1, 0, 0x2000, "__AVR_ARCH__=106", "avrxmega6" }, + { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0x2000, "__AVR_ARCH__=107", "avrxmega7" } }; /* List of all known AVR MCU types - if updated, it has to be kept @@ -216,6 +223,38 @@ const struct mcu_type_s avr_mcu_types[] { "avr6", ARCH_AVR6, NULL, 0, 0x0200, "m2561" }, { "atmega2560", ARCH_AVR6, "__AVR_ATmega2560__", 0, 0x0200, "m2560" }, { "atmega2561", ARCH_AVR6, "__AVR_ATmega2561__", 0, 0x0200, "m2561" }, + /* Enhanced, == 256K. */ + /* Xmega, <= 8K FLASH. */ + /* Xmega, > 8K, <= 64K FLASH, <= 64K RAM. */ + { "avrxmega2", ARCH_AVRXMEGA2, NULL, 0, 0x2000, "x32a4" }, + { "atxmega16a4", ARCH_AVRXMEGA2, "__AVR_ATxmega16A4__", 0, 0x2000, "x16a4" }, + { "atxmega16d4", ARCH_AVRXMEGA2, "__AVR_ATxmega16D4__", 0, 0x2000, "x16d4" }, + { "atxmega32a4", ARCH_AVRXMEGA2, "__AVR_ATxmega32A4__", 0, 0x2000, "x32a4" }, + { "atxmega32d4", ARCH_AVRXMEGA2, "__AVR_ATxmega32D4__", 0, 0x2000, "x32d4" }, + { "atxmega32x1", ARCH_AVRXMEGA2, "__AVR_ATxmega32X1__", 0, 0x2000, "x32x1" }, + /* Xmega, > 8K, <= 64K FLASH, > 64K RAM. */ + /* { "avrxmega3", ARCH_AVRXMEGA3, NULL }, */ + /* Xmega, > 64K, <= 128K FLASH, <= 64K RAM. */ + { "avrxmega4", ARCH_AVRXMEGA4, NULL, 0, 0x2000, "x64d3" }, + { "atxmega64a3", ARCH_AVRXMEGA4, "__AVR_ATxmega64A3__", 0, 0x2000, "x64a3" }, + { "atxmega64d3", ARCH_AVRXMEGA4, "__AVR_ATxmega64D3__", 0, 0x2000, "x64d3" }, + /* Xmega, > 64K, <= 128K FLASH, > 64K RAM. */ + { "avrxmega5", ARCH_AVRXMEGA5, NULL, 0, 0x2000, "x64a1" }, + { "atxmega64a1", ARCH_AVRXMEGA5, "__AVR_ATxmega64A1__", 0, 0x2000, "x64a1" }, + { "atxmega64a1u", ARCH_AVRXMEGA5, "__AVR_ATxmega64A1U__", 0, 0x2000, "x64a1u" }, + /* Xmega, > 128K, <= 256K FLASH, <= 64K RAM. */ + { "avrxmega6", ARCH_AVRXMEGA6, NULL, 0, 0x2000, "x128a3" }, + { "atxmega128a3", ARCH_AVRXMEGA6, "__AVR_ATxmega128A3__", 0, 0x2000, "x128a3" }, + { "atxmega128d3", ARCH_AVRXMEGA6, "__AVR_ATxmega128D3__", 0, 0x2000, "x128d3" }, + { "atxmega192a3", ARCH_AVRXMEGA6, "__AVR_ATxmega192A3__", 0, 0x2000, "x192a3" }, + { "atxmega192d3", ARCH_AVRXMEGA6, "__AVR_ATxmega192D3__", 0, 0x2000, "x192d3" }, + { "atxmega256a3", ARCH_AVRXMEGA6, "__AVR_ATxmega256A3__", 0, 0x2000, "x256a3" }, + { "atxmega256a3b",ARCH_AVRXMEGA6, "__AVR_ATxmega256A3B__", 0, 0x2000, "x256a3b" }, + { "atxmega256d3", ARCH_AVRXMEGA6, "__AVR_ATxmega256D3__", 0, 0x2000, "x256d3" }, + /* Xmega, > 128K, <= 256K FLASH, > 64K RAM. */ + { "avrxmega7", ARCH_AVRXMEGA7, NULL, 0, 0x2000, "x128a1" }, + { "atxmega128a1", ARCH_AVRXMEGA7, "__AVR_ATxmega128A1__", 0, 0x2000, "x128a1" }, + { "atxmega128a1u", ARCH_AVRXMEGA7, "__AVR_ATxmega128A1U__", 0, 0x2000, "x128a1u" }, /* Assembler only. */ { "avr1", ARCH_AVR1, NULL, 0, 0x0060, "s1200" }, { "at90s1200", ARCH_AVR1, "__AVR_AT90S1200__", 0, 0x0060, "s1200" }, diff -Naurp gcc/config/avr/avr.h gcc/config/avr/avr.h --- gcc/config/avr/avr.h 2011-10-27 16:55:06.000000000 +0530 +++ gcc/config/avr/avr.h 2011-10-27 17:00:24.000000000 +0530 @@ -45,11 +45,11 @@ struct base_arch_s { /* Core have 'EICALL' and 'EIJMP' instructions. */ int have_eijmp_eicall; - /* Reserved for xmega architecture. */ - int reserved; + /* Core is in Xmega family. */ + int xmega; - /* Reserved for xmega architecture. */ - int reserved2; + /* Core have RAMPX, RAMPY and RAMPD registers. */ + int have_rampx_y_d; /* Default start of data section address for architecture. */ int default_data_section_start; @@ -75,7 +75,14 @@ enum avr_arch 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 { @@ -118,10 +125,18 @@ extern GTY(()) section *progmem_section; #define AVR_HAVE_RAMPZ (avr_current_arch->have_elpm) #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_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 BITS_BIG_ENDIAN 0 @@ -822,6 +837,10 @@ struct GTY(()) machine_function as specified by the "signal" attribute. */ int is_signal; + /* 'true' - if current function is a signal function + as specified by the "nmi" attribute. */ + int is_nmi; + /* 'true' - if current function is a 'task' function as specified by the "OS_task" attribute. */ int is_OS_task; diff -Naurp gcc/config/avr/avr.md gcc/config/avr/avr.md --- gcc/config/avr/avr.md 2011-10-27 16:55:55.000000000 +0530 +++ gcc/config/avr/avr.md 2011-10-27 17:00:24.000000000 +0530 @@ -48,9 +48,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) @@ -2969,7 +2966,8 @@ "(optimize > 0)" { operands[2] = GEN_INT (exact_log2 (~INTVAL (operands[1]) & 0xff)); - return AS2 (cbi,%m0-0x20,%2); + operands[3] = GEN_INT(AVR_IO_OFFSET); + return AS2 (cbi,%0-%3,%2); } [(set_attr "length" "1") (set_attr "cc" "none")]) @@ -2981,7 +2979,8 @@ "(optimize > 0)" { operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1]) & 0xff)); - return AS2 (sbi,%m0-0x20,%2); + operands[3] = GEN_INT(AVR_IO_OFFSET); + return AS2 (sbi,%0-%3,%2); } [(set_attr "length" "1") (set_attr "cc" "none")]) diff -Naurp gcc/config/avr/libgcc.S gcc/config/avr/libgcc.S --- gcc/config/avr/libgcc.S 2011-10-27 16:55:55.000000000 +0530 +++ gcc/config/avr/libgcc.S 2011-10-27 17:00:24.000000000 +0530 @@ -638,11 +638,19 @@ __prologue_saves__: in r29,__SP_H__ sub r28,r26 sbc r29,r27 + +/* Restore stack pointer. */ +#if defined (__AVR_XMEGA__) + out __SP_L__,r28 + out __SP_H__,r29 +#else in __tmp_reg__,__SREG__ cli out __SP_H__,r29 out __SREG__,__tmp_reg__ out __SP_L__,r28 +#endif + #if defined (__AVR_HAVE_EIJMP_EICALL__) eijmp #else @@ -680,11 +688,18 @@ __epilogue_restores__: ldd r27,Y+1 add r28,r30 adc r29,__zero_reg__ + +/* Restore stack pointer. */ +#if defined(__AVR_XMEGA__) + out __SP_L__,r28 + out __SP_H__,r29 +#else in __tmp_reg__,__SREG__ cli out __SP_H__,r29 out __SREG__,__tmp_reg__ out __SP_L__,r28 +#endif mov_l r28, r26 mov_h r29, r27 ret diff -Naurp gcc/config/avr/predicates.md gcc/config/avr/predicates.md --- gcc/config/avr/predicates.md 2011-10-27 16:55:06.000000000 +0530 +++ gcc/config/avr/predicates.md 2011-10-27 17:00:24.000000000 +0530 @@ -45,17 +45,23 @@ ;; Return true if OP is a valid address for lower half of I/O space. (define_predicate "low_io_address_operand" (and (match_code "const_int") - (match_test "IN_RANGE((INTVAL (op)), 0x20, 0x3F)"))) + (if_then_else (match_test "AVR_XMEGA") + (match_test "IN_RANGE((INTVAL (op)), 0x00, 0x1F)") + (match_test "IN_RANGE((INTVAL (op)), 0x20, 0x3F)")))) ;; Return true if OP is a valid address for high half of I/O space. (define_predicate "high_io_address_operand" (and (match_code "const_int") - (match_test "IN_RANGE((INTVAL (op)), 0x40, 0x5F)"))) + (if_then_else (match_test "AVR_XMEGA") + (match_test "IN_RANGE((INTVAL (op)), 0x20, 0x3F)") + (match_test "IN_RANGE((INTVAL (op)), 0x40, 0x5F)")))) ;; Return true if OP is a valid address of I/O space. (define_predicate "io_address_operand" (and (match_code "const_int") - (match_test "IN_RANGE((INTVAL (op)), 0x20, (0x60 - GET_MODE_SIZE(mode)))"))) + (if_then_else (match_test "AVR_XMEGA") + (match_test "IN_RANGE((INTVAL (op)), 0x0, (0x40 - GET_MODE_SIZE(mode)))") + (match_test "IN_RANGE((INTVAL (op)), 0x20, (0x60 - GET_MODE_SIZE(mode)))")))) ;; Return 1 if OP is the zero constant for MODE. (define_predicate "const0_operand" diff -Naurp gcc/config/avr/t-avr gcc/config/avr/t-avr --- gcc/config/avr/t-avr 2011-10-27 16:55:55.000000000 +0530 +++ gcc/config/avr/t-avr 2011-10-27 17:00:24.000000000 +0530 @@ -107,8 +107,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=avrxmega2/mmcu=avrxmega4/mmcu=avrxmega5/mmcu=avrxmega6/mmcu=avrxmega7 +MULTILIB_DIRNAMES = avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 avrxmega2 avrxmega4 avrxmega5 avrxmega6 avrxmega7 # The many avr2 matches are not listed here - this is the default. MULTILIB_MATCHES = \ @@ -252,7 +252,25 @@ 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?atxmega32d4 \ + mmcu?avrxmega2=mmcu?atxmega32a4 \ + 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?atxmega256d3 \ + mmcu?avrxmega7=mmcu?atxmega128a1 \ + mmcu?avrxmega7=mmcu?atxmega128a1u MULTILIB_EXCEPTIONS =