--- ./gcc/config/avr/avr.c.orig 2010-03-08 12:55:13.000000000 +0100 +++ ./gcc/config/avr/avr.c 2010-03-08 12:55:36.000000000 +0100 @@ -55,6 +55,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); @@ -131,17 +132,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 @@ -159,7 +167,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 { @@ -349,6 +364,35 @@ { "avr6", ARCH_AVR6, NULL }, { "atmega2560", ARCH_AVR6, "__AVR_ATmega2560__" }, { "atmega2561", ARCH_AVR6, "__AVR_ATmega2561__" }, + /* Enhanced, == 256K. */ + /* Xmega, <= 8K FLASH. */ + /* Xmega, > 8K, <= 64K FLASH, <= 64K RAM. */ + { "avrxmega2", ARCH_AVRXMEGA2, NULL }, + { "atxmega16a4", ARCH_AVRXMEGA2, "__AVR_ATxmega16A4__" }, + { "atxmega16d4", ARCH_AVRXMEGA2, "__AVR_ATxmega16D4__" }, + { "atxmega32d4", ARCH_AVRXMEGA2, "__AVR_ATxmega32D4__" }, + /* Xmega, > 8K, <= 64K FLASH, > 64K RAM. */ + { "avrxmega3", ARCH_AVRXMEGA3, NULL }, + { "atxmega32a4", ARCH_AVRXMEGA3, "__AVR_ATxmega32A4__" }, + /* Xmega, > 64K, <= 128K FLASH, <= 64K RAM. */ + { "avrxmega4", ARCH_AVRXMEGA4, NULL }, + { "atxmega64a3", ARCH_AVRXMEGA4, "__AVR_ATxmega64A3__" }, + { "atxmega64d3", ARCH_AVRXMEGA4, "__AVR_ATxmega64D3__" }, + /* Xmega, > 64K, <= 128K FLASH, > 64K RAM. */ + { "avrxmega5", ARCH_AVRXMEGA5, NULL }, + { "atxmega64a1", ARCH_AVRXMEGA5, "__AVR_ATxmega64A1__" }, + /* Xmega, > 128K, <= 256K FLASH, <= 64K RAM. */ + { "avrxmega6", ARCH_AVRXMEGA6, NULL }, + { "atxmega128a3", ARCH_AVRXMEGA6, "__AVR_ATxmega128A3__" }, + { "atxmega128d3", ARCH_AVRXMEGA6, "__AVR_ATxmega128D3__" }, + { "atxmega192a3", ARCH_AVRXMEGA6, "__AVR_ATxmega192A3__" }, + { "atxmega192d3", ARCH_AVRXMEGA6, "__AVR_ATxmega192D3__" }, + { "atxmega256a3", ARCH_AVRXMEGA6, "__AVR_ATxmega256A3__" }, + { "atxmega256a3b",ARCH_AVRXMEGA6, "__AVR_ATxmega256A3B__" }, + { "atxmega256d3", ARCH_AVRXMEGA6, "__AVR_ATxmega256D3__" }, + /* Xmega, > 128K, <= 256K FLASH, > 64K RAM. */ + { "avrxmega7", ARCH_AVRXMEGA7, NULL }, + { "atxmega128a1", ARCH_AVRXMEGA7, "__AVR_ATxmega128A1__" }, /* Assembler only. */ { "avr1", ARCH_AVR1, NULL }, { "at90s1200", ARCH_AVR1, "__AVR_AT90S1200__" }, @@ -531,6 +575,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 @@ -690,6 +749,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. */ @@ -725,17 +785,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; @@ -744,9 +835,46 @@ /* Clear zero reg. */ insn = emit_move_insn (zero_reg_rtx, const0_rtx); RTX_FRAME_RELATED_P (insn) = 1; - + /* Prevent any attempt to delete the setting of ZERO_REG! */ emit_insn (gen_rtx_USE (VOIDmode, zero_reg_rtx)); + + /* + Clear RAMP? registers if used for data access in the interrupt/signal + context. Do this after the zero register has been explictly cleared. + */ + if (AVR_HAVE_RAMPX_Y_D) + { + /* Set RAMPD to 0. */ + insn = emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPD_ADDR)), + const0_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + + if (TEST_HARD_REG_BIT (set, REG_X) && TEST_HARD_REG_BIT (set, REG_X + 1)) + { + /* Set RAMPX to 0. */ + insn = emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPX_ADDR)), + const0_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + } + + if (TEST_HARD_REG_BIT (set, REG_Y) && TEST_HARD_REG_BIT (set, REG_Y + 1)) + { + /* Set RAMPY to 0. */ + insn = emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPY_ADDR)), + const0_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + } + + if(AVR_HAVE_RAMPZ + && (TEST_HARD_REG_BIT (set, REG_Z) && TEST_HARD_REG_BIT (set, REG_Z + 1))) + { + /* Set RAMPZ to 0. */ + insn = emit_move_insn (gen_rtx_MEM (QImode, GEN_INT (AVR_RAMPZ_ADDR)), + const0_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + } + } } if (minimize && (frame_pointer_needed || (AVR_2_BYTE_PC && live_seq > 6) @@ -1010,14 +1138,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. */ @@ -1786,8 +1939,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))) { @@ -1796,7 +1950,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)) { @@ -1806,12 +1961,21 @@ "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 = 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 + 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)) { @@ -1946,7 +2110,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__); @@ -1954,7 +2118,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); @@ -2142,8 +2307,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 @@ -2634,7 +2800,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); @@ -2642,7 +2808,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); @@ -2721,11 +2888,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,%A1) CR_TAB + AS2 (out,%B0-%2,%B1)); + 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) { @@ -2740,11 +2916,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 { @@ -2752,14 +2937,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) { @@ -2770,48 +2968,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) { @@ -2832,7 +3086,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 ""; @@ -4712,6 +4966,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 } @@ -4800,6 +5055,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; @@ -4994,7 +5257,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); @@ -5888,15 +6152,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 * @@ -6074,16 +6341,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 --- ./gcc/config/avr/avr.h.orig 2010-03-08 12:55:09.000000000 +0100 +++ ./gcc/config/avr/avr.h 2010-03-08 12:55:36.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 () @@ -935,6 +965,20 @@ mmcu=m3000*|\ mmcu=m3001*: -m avr5}\ %{mmcu=atmega256*:-m avr6}\ +%{mmcu=atxmega16a4|\ + mmcu=atxmega16d4|\ + mmcu=atxmega32d4:-m avrxmega2}\ +%{mmcu=atxmega32a4:-m avrxmega3} \ +%{mmcu=atxmega64a3|\ + mmcu=atxmega64d3:-m avrxmega4} \ +%{mmcu=atxmega64a1:-m avrxmega5} \ +%{mmcu=atxmega128a3|\ + mmcu=atxmega128d3|\ + mmcu=atxmega192a3|\ + mmcu=atxmega192d3|\ + mmcu=atxmega256a3*|\ + mmcu=atxmega256d3:-m avrxmega6} \ +%{mmcu=atxmega128a1:-m avrxmega7} \ %{mmcu=atmega324a|\ mmcu=atmega324p|\ mmcu=atmega324pa|\ @@ -1190,7 +1234,22 @@ %{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=avrxmega2|mmcu=atxmega32d4:crtx32d4.o%s} \ +%{mmcu=atxmega16a4:crtx16a4.o%s} \ +%{mmcu=atxmega16d4:crtx16d4.o%s} \ +%{mmcu=atxmega3|mmcu=atxmega32a4:crtx32a4.o%s} \ +%{mmcu=atxmega4|mmcu=atxmega64a3:crtx64a3.o%s} \ +%{mmcu=atxmega64d3:crtx64d3.o%s} \ +%{mmcu=atxmega5|mmcu=atxmega64a1:crtx64a1.o%s} \ +%{mmcu=atxmega6|mmcu=atxmega128a3:crtx128a3.o%s} \ +%{mmcu=atxmega128d3:crtx128d3.o%s}\ +%{mmcu=atxmega192a3:crtx192a3.o%s}\ +%{mmcu=atxmega192d3:crtx192d3.o%s}\ +%{mmcu=atxmega256a3:crtx256a3.o%s} \ +%{mmcu=atxmega256a3b:crtx256a3b.o%s} \ +%{mmcu=atxmega256d3:crtx256d3.o%s} \ +%{mmcu=atxmega7|mmcu=atxmega128a1:crtx128a1.o%s}" #define EXTRA_SPECS {"crt_binutils", CRT_BINUTILS_SPECS}, @@ -1252,8 +1311,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/t-avr.orig 2010-03-08 12:55:09.000000000 +0100 +++ ./gcc/config/avr/t-avr 2010-03-08 12:55:36.000000000 +0100 @@ -37,8 +37,8 @@ FPBIT = fp-bit.c -MULTILIB_OPTIONS = mmcu=avr2/mmcu=avr25/mmcu=avr3/mmcu=avr31/mmcu=avr35/mmcu=avr4/mmcu=avr5/mmcu=avr51/mmcu=avr6 -MULTILIB_DIRNAMES = avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 +MULTILIB_OPTIONS = mmcu=avr2/mmcu=avr25/mmcu=avr3/mmcu=avr31/mmcu=avr35/mmcu=avr4/mmcu=avr5/mmcu=avr51/mmcu=avr6/mmcu=avrxmega2/mmcu=avrxmega3/mmcu=avrxmega4/mmcu=avrxmega5/mmcu=avrxmega6/mmcu=avrxmega7 +MULTILIB_DIRNAMES = avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 avrxmega2 avrxmega3 avrxmega4 avrxmega5 avrxmega6 avrxmega7 # The many avr2 matches are not listed here - this is the default. MULTILIB_MATCHES = \ @@ -182,7 +182,22 @@ mmcu?avr51=mmcu?m3000s \ mmcu?avr51=mmcu?m3001b \ 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?avrxmega3=mmcu?atxmega32a4 \ + mmcu?avrxmega4=mmcu?atxmega64a3 \ + mmcu?avrxmega4=mmcu?atxmega64d3 \ + mmcu?avrxmega5=mmcu?atxmega64a1 \ + mmcu?avrxmega6=mmcu?atxmega128a3 \ + mmcu?avrxmega6=mmcu?atxmega128d3 \ + mmcu?avrxmega6=mmcu?atxmega192a3 \ + mmcu?avrxmega6=mmcu?atxmega192d3 \ + mmcu?avrxmega6=mmcu?atxmega256a3 \ + mmcu?avrxmega6=mmcu?atxmega256a3b \ + mmcu?avrxmega6=mmcu?atxmega256d3 \ + mmcu?avrxmega7=mmcu?atxmega128a1 MULTILIB_EXCEPTIONS = LIBGCC = stmp-multilib --- ./gcc/config/avr/avr.md.orig 2010-03-08 12:54:57.000000000 +0100 +++ ./gcc/config/avr/avr.md 2010-03-08 12:55:36.000000000 +0100 @@ -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_SWAP 2) @@ -2677,7 +2674,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")]) @@ -2689,7 +2687,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")]) --- ./gcc/config/avr/predicates.md.orig 2010-03-08 12:54:57.000000000 +0100 +++ ./gcc/config/avr/predicates.md 2010-03-08 12:55:36.000000000 +0100 @@ -50,12 +50,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"