diff -Naurp gcc/config/avr/avr.c gcc/config/avr/avr.c --- gcc/config/avr/avr.c 2013-01-21 18:26:07.000000000 +0530 +++ gcc/config/avr/avr.c 2013-01-21 18:40:04.000000000 +0530 @@ -78,6 +78,17 @@ ((SYMBOL_REF_FLAGS (sym) & AVR_SYMBOL_FLAG_PROGMEM) \ / SYMBOL_FLAG_MACH_DEP) +#define TINY_ADIW(REG1, REG2, I) \ + "subi " #REG1 ",lo8(-(" #I "))" CR_TAB \ + "sbci " #REG2 ",hi8(-(" #I "))" + +#define TINY_SBIW(REG1, REG2, I) \ + "subi " #REG1 ",lo8((" #I "))" CR_TAB \ + "sbci " #REG2 ",hi8((" #I "))" + +#define AVR_TMP_REGNO (AVR_TINY ? TMP_REGNO_TINY : TMP_REGNO) +#define AVR_ZERO_REGNO (AVR_TINY ? ZERO_REGNO_TINY : ZERO_REGNO) + /* Known address spaces. The order must be the same as in the respective enum from avr.h (or designated initialized must be used). */ const avr_addrspace_t avr_addrspace[] = @@ -157,6 +168,9 @@ static bool avr_rtx_costs (rtx, int, int /* Allocate registers from r25 to r8 for parameters for function calls. */ #define FIRST_CUM_REG 26 +/* Last call saved register */ +#define LAST_CALLEE_SAVED_REG (AVR_TINY ? 21 : 17) + /* Implicit target register of LPM instruction (R0) */ extern GTY(()) rtx lpm_reg_rtx; rtx lpm_reg_rtx; @@ -306,7 +320,7 @@ avr_option_override (void) 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; + avr_addr.ccp = (AVR_TINY ? 0x3C : 0x34) + avr_current_arch->sfr_offset; /* SP: Stack Pointer (SP_H:SP_L) */ avr_addr.sp_l = 0x3D + avr_current_arch->sfr_offset; @@ -338,8 +352,8 @@ avr_init_expanders (void) all_regs_rtx[regno] = gen_rtx_REG (QImode, regno); lpm_reg_rtx = all_regs_rtx[LPM_REGNO]; - tmp_reg_rtx = all_regs_rtx[TMP_REGNO]; - zero_reg_rtx = all_regs_rtx[ZERO_REGNO]; + tmp_reg_rtx = all_regs_rtx[AVR_TMP_REGNO]; + zero_reg_rtx = all_regs_rtx[AVR_ZERO_REGNO]; lpm_addr_reg_rtx = gen_rtx_REG (HImode, REG_Z); @@ -351,6 +365,11 @@ avr_init_expanders (void) xstring_empty = gen_rtx_CONST_STRING (VOIDmode, ""); xstring_e = gen_rtx_CONST_STRING (VOIDmode, "e"); + + /* TINY core does not have regs r10-r16, but avr-dimode.md expects them + to be present */ + if (AVR_TINY) + avr_have_dimode = false; } @@ -792,7 +811,7 @@ sequent_regs_live (void) int live_seq=0; int cur_seq=0; - for (reg = 0; reg < 18; ++reg) + for (reg = 0; reg <= LAST_CALLEE_SAVED_REG; ++reg) { if (fixed_regs[reg]) { @@ -903,7 +922,7 @@ emit_push_sfr (rtx sfr, bool frame_relat RTX_FRAME_RELATED_P (insn) = 1; /* PUSH __tmp_reg__ */ - emit_push_byte (TMP_REGNO, frame_related_p); + emit_push_byte (AVR_TMP_REGNO, frame_related_p); if (clr_p) { @@ -929,7 +948,8 @@ avr_prologue_setup_frame (HOST_WIDE_INT && live_seq && !isr_p && !cfun->machine->is_OS_task - && !cfun->machine->is_OS_main); + && !cfun->machine->is_OS_main + && !AVR_TINY); if (minimize && (frame_pointer_needed @@ -966,11 +986,11 @@ avr_prologue_setup_frame (HOST_WIDE_INT /* Note that live_seq always contains r28+r29, but the other registers to be saved are all below 18. */ - first_reg = 18 - (live_seq - 2); + first_reg = (LAST_CALLEE_SAVED_REG + 1) - (live_seq - 2); for (reg = 29, offset = -live_seq + 1; reg >= first_reg; - reg = (reg == 28 ? 17 : reg - 1), ++offset) + reg = (reg == 28 ? LAST_CALLEE_SAVED_REG : reg - 1), ++offset) { rtx m, r; @@ -1201,10 +1221,10 @@ expand_prologue (void) emit_insn (gen_enable_interrupt ()); /* Push zero reg. */ - emit_push_byte (ZERO_REGNO, true); + emit_push_byte (AVR_ZERO_REGNO, true); /* Push tmp reg. */ - emit_push_byte (TMP_REGNO, true); + emit_push_byte (AVR_TMP_REGNO, true); /* Push SREG. */ /* ??? There's no dwarf2 column reserved for SREG. */ @@ -1344,7 +1364,8 @@ expand_epilogue (bool sibcall_p) && live_seq && !isr_p && !cfun->machine->is_OS_task - && !cfun->machine->is_OS_main); + && !cfun->machine->is_OS_main + && !AVR_TINY); if (minimize && (live_seq > 4 @@ -1502,14 +1523,14 @@ expand_epilogue (bool sibcall_p) /* Restore SREG using tmp_reg as scratch. */ - emit_pop_byte (TMP_REGNO); + emit_pop_byte (AVR_TMP_REGNO); emit_move_insn (sreg_rtx, tmp_reg_rtx); /* Restore tmp REG. */ - emit_pop_byte (TMP_REGNO); + emit_pop_byte (AVR_TMP_REGNO); /* Restore zero REG. */ - emit_pop_byte (ZERO_REGNO); + emit_pop_byte (AVR_ZERO_REGNO); } if (!sibcall_p) @@ -2009,7 +2030,7 @@ avr_print_operand (FILE *file, rtx x, in fprintf (file, "__RAMPX__"); else if (AVR_HAVE_RAMPD && ival == avr_addr.rampd) fprintf (file, "__RAMPD__"); - else if (AVR_XMEGA && ival == avr_addr.ccp) + else if ((AVR_XMEGA || AVR_TINY) && 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__"); @@ -2052,6 +2073,13 @@ avr_print_operand (FILE *file, rtx x, in avr_print_operand (file, XEXP (addr, 1), 0); } + else if (code == 'b') + { + if (GET_CODE (addr) != PLUS) + fatal_insn ("bad address, not (reg+disp):", addr); + + avr_print_operand_address (file, XEXP (addr, 0)); + } else if (code == 'p' || code == 'r') { if (GET_CODE (addr) != POST_INC && GET_CODE (addr) != PRE_DEC) @@ -2392,7 +2420,7 @@ avr_simplify_comparison_p (enum machine_ int function_arg_regno_p(int r) { - return (r >= 8 && r <= 25); + return (AVR_TINY ? r >= 20 && r <= 25 : r >= 8 && r <= 25); } /* Initializing the variable cum for the state at the beginning @@ -2402,7 +2430,7 @@ void init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname, tree fndecl ATTRIBUTE_UNUSED) { - cum->nregs = 18; + cum->nregs = AVR_TINY ? 6 : 18; cum->regno = FIRST_CUM_REG; if (!libname && stdarg_p (fntype)) cum->nregs = 0; @@ -2900,6 +2928,25 @@ output_movhi (rtx insn, rtx xop[], int * return ""; } +/* Same as out_movqi_r_mr, but TINY does not have ADIW or SBIW */ +static const char* +avr_out_movqi_r_mr_reg_disp_tiny (rtx insn, rtx op[], int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx x = XEXP (src, 0); + op[2] = XEXP(x, 0); + + avr_asm_len (TINY_ADIW (%A2, %B2, %o1) CR_TAB + "ld %0,%b1" , op, plen, -3); + + if (!reg_overlap_mentioned_p (dest, XEXP (x,0)) + && !reg_unused_after (insn, XEXP (x,0))) + avr_asm_len (TINY_SBIW (%A2, %B2, %o1), op, plen, 2); + + return ""; +} + static const char* out_movqi_r_mr (rtx insn, rtx op[], int *plen) { @@ -2913,13 +2960,18 @@ out_movqi_r_mr (rtx insn, rtx op[], int ? avr_asm_len ("in %0,%i1", op, plen, -1) : avr_asm_len ("lds %0,%m1", op, plen, -2); } - else if (GET_CODE (x) == PLUS + + + if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1))) { /* memory access by reg+disp */ int disp = INTVAL (XEXP (x, 1)); + + if (AVR_TINY) + return avr_out_movqi_r_mr_reg_disp_tiny (insn, op, plen); if (disp - GET_MODE_SIZE (GET_MODE (src)) >= 63) { @@ -2941,25 +2993,105 @@ out_movqi_r_mr (rtx insn, rtx op[], int { /* This is a paranoid case LEGITIMIZE_RELOAD_ADDRESS must exclude it but I have this situation with extremal optimizing options. */ - - avr_asm_len ("adiw r26,%o1" CR_TAB - "ld %0,X", op, plen, -2); + + avr_asm_len ("adiw r26, %o1" CR_TAB + "ld %0,X", op, plen, -2); if (!reg_overlap_mentioned_p (dest, XEXP (x,0)) && !reg_unused_after (insn, XEXP (x,0))) { - avr_asm_len ("sbiw r26,%o1", op, plen, 1); + avr_asm_len ("sbiw r26, %o1", op, plen, 1); } return ""; } - return avr_asm_len ("ldd %0,%1", op, plen, -1); + return avr_asm_len ("ldd %0,%1", op, plen, -1); } return avr_asm_len ("ld %0,%1", op, plen, -1); } +/* Same as movhi_r_mr, but TINY does not have ADIW, SBIW and LDD */ +static const char* +avr_out_movhi_r_mr_reg_no_disp_tiny (rtx op[], int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (src, 0); + + int reg_dest = true_regnum (dest); + int reg_base = true_regnum (base); + + op[2] = base; + + if (reg_dest == reg_base) /* R = (R) */ + return avr_asm_len ("ld __tmp_reg__,%1+" CR_TAB + "ld %B0,%1" CR_TAB + "mov %A0,__tmp_reg__", op, plen, -3); + + return avr_asm_len ("ld %A0,%1" CR_TAB + TINY_ADIW (%A2, %B2, 1) CR_TAB + "ld %B0,%1" CR_TAB + TINY_SBIW (%A2, %B2, 1), op, plen, -6); + +} + +/* Same as movhi_r_mr, but TINY does not have ADIW, SBIW and LDD */ +static const char* +avr_out_movhi_r_mr_reg_disp_tiny (rtx op[], int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (src, 0); + + int reg_dest = true_regnum (dest); + int reg_base = true_regnum (XEXP (base, 0)); + op[2] = XEXP (base, 0); + + if (reg_base == reg_dest) + { + return avr_asm_len (TINY_ADIW (%A2, %B2, %o1) CR_TAB + "ld __tmp_reg__,%b1+" CR_TAB + "ld %B0,%b1" CR_TAB + "mov %A0,__tmp_reg__", op, plen, -5); + } + else + { + return avr_asm_len (TINY_ADIW (%A2, %B2, %o1) CR_TAB + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1" CR_TAB + TINY_SBIW (%A2, %B2, %o1+1), op, plen, -6); + } +} + +/* Same as movhi_r_mr, but TINY does not have ADIW, SBIW and LDD */ +static const char* +avr_out_movhi_r_mr_pre_dec_tiny (rtx insn, rtx op[], int *plen) +{ + int mem_volatile_p = 0; + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (src, 0); + op[2] = XEXP (base, 0); + + /* "volatile" forces reading low byte first, even if less efficient, + for correct operation with 16-bit I/O registers. */ + mem_volatile_p = MEM_VOLATILE_P (src); + + if (reg_overlap_mentioned_p (dest, XEXP (base, 0))) + fatal_insn ("incorrect insn:", insn); + + if (!mem_volatile_p) + return avr_asm_len ("ld %B0,%1" CR_TAB + "ld %A0,%1", op, plen, -2); + + return avr_asm_len (TINY_SBIW (%A2, %B2, 2) CR_TAB + "ld %A0,%p1+" CR_TAB + "ld %B0,%p1" CR_TAB + TINY_SBIW (%A2, %B2, 1), op, plen, -6); +} + static const char* out_movhi_r_mr (rtx insn, rtx op[], int *plen) { @@ -2974,20 +3106,27 @@ out_movhi_r_mr (rtx insn, rtx op[], int if (reg_base > 0) { + if (AVR_TINY) + return avr_out_movhi_r_mr_reg_no_disp_tiny (op, plen); + if (reg_dest == reg_base) /* R = (R) */ return avr_asm_len ("ld __tmp_reg__,%1+" CR_TAB "ld %B0,%1" CR_TAB "mov %A0,__tmp_reg__", op, plen, -3); if (reg_base != REG_X) + { return avr_asm_len ("ld %A0,%1" CR_TAB - "ldd %B0,%1+1", op, plen, -2); - + "ldd %B0,%1+1", op, plen, -2); + } + avr_asm_len ("ld %A0,X+" CR_TAB "ld %B0,X", op, plen, -2); if (!reg_unused_after (insn, base)) + { avr_asm_len ("sbiw r26,1", op, plen, 1); + } return ""; } @@ -2996,6 +3135,9 @@ out_movhi_r_mr (rtx insn, rtx op[], int int disp = INTVAL (XEXP (base, 1)); int reg_base = true_regnum (XEXP (base, 0)); + if (AVR_TINY) + return avr_out_movhi_r_mr_reg_disp_tiny (op, plen); + if (disp > MAX_LD_OFFSET (GET_MODE (src))) { if (REGNO (XEXP (base, 0)) != REG_Y) @@ -3007,7 +3149,7 @@ out_movhi_r_mr (rtx insn, rtx op[], int "ldd %B0,Y+63" CR_TAB "sbiw r28,%o1-62", op, plen, -4) - : avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB + : avr_asm_len ("subi r28,lo8(-%o1)" CR_TAB "sbci r29,hi8(-%o1)" CR_TAB "ld %A0,Y" CR_TAB "ldd %B0,Y+1" CR_TAB @@ -3041,6 +3183,9 @@ out_movhi_r_mr (rtx insn, rtx op[], int } else if (GET_CODE (base) == PRE_DEC) /* (--R) */ { + if (AVR_TINY) + return avr_out_movhi_r_mr_pre_dec_tiny (insn, op, plen); + if (reg_overlap_mentioned_p (dest, XEXP (base, 0))) fatal_insn ("incorrect insn:", insn); @@ -3081,6 +3226,101 @@ out_movhi_r_mr (rtx insn, rtx op[], int } static const char* +avr_out_movsi_r_mr_reg_no_disp_tiny (rtx insn, rtx op[], int *l) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (src, 0); + int reg_dest = true_regnum (dest); + int reg_base = true_regnum (base); + op[2] = base; + + if (reg_dest == reg_base) + { + /* "ld r26,-X" is undefined */ + return *l=9, (TINY_ADIW (%A2, %B2, 3) CR_TAB + "ld %D0,%1" CR_TAB + "ld %C0,-%1" CR_TAB + "ld __tmp_reg__,-%1" CR_TAB + TINY_SBIW (%A2, %B2, 1) CR_TAB + "ld %A0,%1" CR_TAB + "mov %B0,__tmp_reg__"); + } + else if (reg_dest == reg_base - 2) + { + return *l=5, ("ld %A0,%1+" CR_TAB + "ld %B0,%1+" CR_TAB + "ld __tmp_reg__,%1+" CR_TAB + "ld %D0,%1" CR_TAB + "mov %C0,__tmp_reg__"); + } + else if (reg_unused_after (insn, base)) + { + return *l=4, ("ld %A0,%1+" CR_TAB + "ld %B0,%1+" CR_TAB + "ld %C0,%1+" CR_TAB + "ld %D0,%1"); + } + else + { + return *l=6, ("ld %A0,%1+" CR_TAB + "ld %B0,%1+" CR_TAB + "ld %C0,%1+" CR_TAB + "ld %D0,%1" CR_TAB + TINY_SBIW (%A2, %B2, 3)); + } +} + +static const char* +avr_out_movsi_r_mr_reg_disp_tiny (rtx insn, rtx op[], int *l) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (src, 0); + int reg_dest = true_regnum (dest); + int reg_base = true_regnum (XEXP (base, 0)); + op[2] = XEXP (base, 0); + + if (reg_dest == reg_base) + { + /* "ld r26,-X" is undefined */ + return *l=9, (TINY_ADIW (%A2, %B2, %o1+3) CR_TAB + "ld %D0,%b1" CR_TAB + "ld %C0,-%b1" CR_TAB + "ld __tmp_reg__,-%b1" CR_TAB + TINY_SBIW (%A2, %B2, 1) CR_TAB + "ld %A0,%b1" CR_TAB + "mov %B0,__tmp_reg__"); + } + else if (reg_dest == reg_base - 2) + { + return *l=7, (TINY_ADIW (%A2, %B2, %o1) CR_TAB + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1+" CR_TAB + "ld __tmp_reg__,%b1+" CR_TAB + "ld %D0,%b1" CR_TAB + "mov %C0,__tmp_reg__"); + } + else if (reg_unused_after (insn, XEXP (base, 0))) + { + return *l=6, (TINY_ADIW (%A2, %B2, %o1) CR_TAB + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1+" CR_TAB + "ld %C0,%b1+" CR_TAB + "ld %D0,%b1"); + } + else + { + return *l=8, (TINY_ADIW (%A2, %B2, %o1) CR_TAB + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1+" CR_TAB + "ld %C0,%b1+" CR_TAB + "ld %D0,%b1" CR_TAB + TINY_SBIW (%A2, %B2, %o1+3)); + } +} + +static const char* out_movsi_r_mr (rtx insn, rtx op[], int *l) { rtx dest = op[0]; @@ -3095,6 +3335,9 @@ out_movsi_r_mr (rtx insn, rtx op[], int if (reg_base > 0) { + if (AVR_TINY) + return avr_out_movsi_r_mr_reg_no_disp_tiny (insn, op, l); + if (reg_base == REG_X) /* (R26) */ { if (reg_dest == REG_X) @@ -3149,6 +3392,9 @@ out_movsi_r_mr (rtx insn, rtx op[], int { int disp = INTVAL (XEXP (base, 1)); + if (AVR_TINY) + return avr_out_movsi_r_mr_reg_disp_tiny (insn, op, l); + if (disp > MAX_LD_OFFSET (GET_MODE (src))) { if (REGNO (XEXP (base, 0)) != REG_Y) @@ -3242,6 +3488,113 @@ out_movsi_r_mr (rtx insn, rtx op[], int } static const char* +avr_out_movsi_mr_r_reg_no_disp_tiny (rtx insn, rtx op[], int *l) +{ + 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); + op[2] = base; + + if (reg_base == reg_src) + { + /* "ld r26,-X" is undefined */ + if (reg_unused_after (insn, base)) + { + return *l=7, ("mov __tmp_reg__, %B1" CR_TAB + "st %0,%A1" CR_TAB + TINY_ADIW (%A2, %B2, 1) CR_TAB + "st %0+,__tmp_reg__" CR_TAB + "st %0+,%C1" CR_TAB + "st %0+,%D1"); + } + else + { + return *l=9, ("mov __tmp_reg__, %B1" CR_TAB + "st %0,%A1" CR_TAB + TINY_ADIW (%A2, %B2, 1) CR_TAB + "st %0+,__tmp_reg__" CR_TAB + "st %0+,%C1" CR_TAB + "st %0+,%D1" CR_TAB + TINY_SBIW (%A2, %B2, 3)); + } + } + else if (reg_base == reg_src + 2) + { + if (reg_unused_after (insn, base)) + return *l=7, ("mov __zero_reg__,%C1" CR_TAB + "mov __tmp_reg__,%D1" CR_TAB + "st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0+,__zero_reg__" CR_TAB + "st %0,__tmp_reg__" CR_TAB + "clr __zero_reg__"); + else + return *l=9, ("mov __zero_reg__,%C1" CR_TAB + "mov __tmp_reg__,%D1" CR_TAB + "st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0+,__zero_reg__" CR_TAB + "st %0,__tmp_reg__" CR_TAB + "clr __zero_reg__" CR_TAB + TINY_SBIW (%A2, %B2, 3)); + } + + return *l=6, ("st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0+,%C1" CR_TAB + "st %0,%D1" CR_TAB + TINY_SBIW (%A2, %B2, 3)); +} + +static const char* +avr_out_movsi_mr_r_reg_disp_tiny (rtx op[], int *l) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (dest, 0); + int reg_base = REGNO (XEXP (base, 0)); + int reg_src =true_regnum (src); + + op[2] = XEXP (base, 0); + + if (reg_base == reg_src) + { + *l = 11; + return ("mov __tmp_reg__,%A2" CR_TAB + "mov __zero_reg__,%B2" CR_TAB + TINY_ADIW (%A2, %B2, %o0) CR_TAB + "st %b0+,__tmp_reg__" CR_TAB + "st %b0+,__zero_reg__" CR_TAB + "st %b0+,%C2" CR_TAB + "st %b0,%D2" CR_TAB + "clr __zero_reg__" CR_TAB + TINY_SBIW (%A2, %B2, %o0+3)); + } + else if (reg_src == reg_base - 2) + { + *l = 11; + return ("mov __tmp_reg__,%C2" CR_TAB + "mov __zero_reg__,%D2" CR_TAB + TINY_ADIW (%A2, %B2, %o0) CR_TAB + "st %b0+,%A0" CR_TAB + "st %b0+,%B0" CR_TAB + "st %b0+,__tmp_reg__" CR_TAB + "st %b0,__zero_reg__" CR_TAB + "clr __zero_reg__" CR_TAB + TINY_SBIW (%A2, %B2, %o0+3)); + } + *l = 8; + return (TINY_ADIW (%A2, %B2, %o0) CR_TAB + "st %b0+,%A1" CR_TAB + "st %b0+,%B1" CR_TAB + "st %b0+,%C1" CR_TAB + "st %b0,%D1" CR_TAB + TINY_SBIW (%A2, %B2, %o0+3)); +} + +static const char* out_movsi_mr_r (rtx insn, rtx op[], int *l) { rtx dest = op[0]; @@ -3261,6 +3614,9 @@ out_movsi_mr_r (rtx insn, rtx op[], int "sts %m0+3,%D1"); if (reg_base > 0) /* (r) */ { + if (AVR_TINY) + return avr_out_movsi_mr_r_reg_no_disp_tiny (insn, op, l); + if (reg_base == REG_X) /* (R26) */ { if (reg_src == REG_X) @@ -3317,6 +3673,10 @@ out_movsi_mr_r (rtx insn, rtx op[], int else if (GET_CODE (base) == PLUS) /* (R + i) */ { int disp = INTVAL (XEXP (base, 1)); + + if (AVR_TINY) + return avr_out_movsi_mr_r_reg_disp_tiny (op, l); + reg_base = REGNO (XEXP (base, 0)); if (disp > MAX_LD_OFFSET (GET_MODE (dest))) { @@ -3476,6 +3836,75 @@ output_movsisf (rtx insn, rtx operands[] /* Handle loads of 24-bit types from memory to register. */ static const char* +avr_out_load_psi_reg_no_disp_tiny (rtx insn, rtx *op, int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (src, 0); + int reg_dest = true_regnum (dest); + int reg_base = true_regnum (base); + op[2] = base; + + if (reg_base == reg_dest) + { + return avr_asm_len (TINY_ADIW (%A2, %B2, 2) CR_TAB + "ld %C0,%1" CR_TAB + "ld __tmp_reg__,-%1" CR_TAB + TINY_SBIW (%A2, %B2, 1) CR_TAB + "ld %A0,%1" CR_TAB + "mov %B0,__tmp_reg__", op, plen, -8); + } + else + { + return avr_asm_len ("ld %A0,%1+" CR_TAB + "ld %B0,%1+" CR_TAB + "ld %C0,%1", op, plen, -3); + + if (reg_dest != reg_base - 2 && + !reg_unused_after (insn, base)) + { + avr_asm_len (TINY_SBIW (%A2, %B2, 2), op, plen, 2); + } + return ""; + } +} + +static const char* +avr_out_load_psi_reg_disp_tiny (rtx insn, rtx *op, int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (src, 0); + int reg_dest = true_regnum (dest); + int reg_base = true_regnum (base); + op[2] = XEXP (base, 0); + + reg_base = true_regnum (XEXP (base, 0)); + if (reg_base == reg_dest) + { + return avr_asm_len (TINY_ADIW (%A2, %B2, %o1+2) CR_TAB + "ld %C0,%b1" CR_TAB + "ld __tmp_reg__,-%b1" CR_TAB + TINY_SBIW (%A2, %B2, 1) CR_TAB + "ld %A0,%b1" CR_TAB + "mov %B0,__tmp_reg__", op, plen, -8); + } + else + { + avr_asm_len (TINY_ADIW (%A2, %B2, %o1) CR_TAB + "ld %A0,%b1+" CR_TAB + "ld %B0,%b1+" CR_TAB + "ld %C0,%b1", op, plen, -5); + + if (reg_dest != (reg_base - 2) + && !reg_unused_after (insn, XEXP (base, 0))) + avr_asm_len (TINY_SBIW (%A2, %B2, %o1+2), op, plen, 2); + + return ""; + } +} + +static const char* avr_out_load_psi (rtx insn, rtx *op, int *plen) { rtx dest = op[0]; @@ -3486,6 +3915,9 @@ avr_out_load_psi (rtx insn, rtx *op, int if (reg_base > 0) { + if (AVR_TINY) + return avr_out_load_psi_reg_no_disp_tiny (insn, op, plen); + if (reg_base == REG_X) /* (R26) */ { if (reg_dest == REG_X) @@ -3527,6 +3959,9 @@ avr_out_load_psi (rtx insn, rtx *op, int else if (GET_CODE (base) == PLUS) /* (R + i) */ { int disp = INTVAL (XEXP (base, 1)); + + if (AVR_TINY) + return avr_out_load_psi_reg_disp_tiny (insn, op, plen); if (disp > MAX_LD_OFFSET (GET_MODE (src))) { @@ -3604,6 +4039,85 @@ avr_out_load_psi (rtx insn, rtx *op, int return ""; } + +static const char* +avr_out_store_psi_reg_no_disp_tiny (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); + op[2] = base; + + if (reg_base == reg_src) + { + avr_asm_len ("st %0,%A1" CR_TAB + "mov __tmp_reg__,%B1" CR_TAB + TINY_ADIW (%A2, %B2, 1) CR_TAB /* st X+, r27 is undefined */ + "st %0+,__tmp_reg__" CR_TAB + "st %0,%C1", op, plen, -6); + + } + else if (reg_src == reg_base - 2) + { + avr_asm_len ("st %0,%A1" CR_TAB + "mov __tmp_reg__,%C1" CR_TAB + TINY_ADIW (%A2, %B2, 1) CR_TAB + "st %0+,%B1" CR_TAB + "st %0,__tmp_reg__", op, plen, 6); + } + else + { + avr_asm_len ("st %0+,%A1" CR_TAB + "st %0+,%B1" CR_TAB + "st %0,%C1", op, plen, -3); + } + + if (!reg_unused_after (insn, base)) + avr_asm_len (TINY_SBIW (%A2, %B2, 2), op, plen, 2); + + return ""; +} + +static const char* +avr_out_store_psi_reg_disp_tiny (rtx *op, int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (dest, 0); + int reg_base = REGNO (XEXP (base, 0)); + int reg_src = true_regnum (src); + op[2] = XEXP (base, 0); + + if (reg_src == reg_base) + { + return avr_asm_len ("mov __tmp_reg__,%A1" CR_TAB + "mov __zero_reg__,%B1" CR_TAB + TINY_ADIW (%A2, %B2, %o0) CR_TAB + "st %b0+,__tmp_reg__" CR_TAB + "st %b0+,__zero_reg__" CR_TAB + "st %b0,%C1" CR_TAB + "clr __zero_reg__" CR_TAB + TINY_SBIW (%A2, %B2, %o0+2), op, plen, -10); + } + else if (reg_src == reg_base - 2) + { + return avr_asm_len ("mov __tmp_reg__,%C1" CR_TAB + TINY_ADIW (%A2, %B2, %o0) CR_TAB + "st %b0+,%A1" CR_TAB + "st %b0+,%B1" CR_TAB + "st %b0,__tmp_reg__" CR_TAB + TINY_SBIW (%A2, %B2, %o0+2), op, plen, -8); + } + + return avr_asm_len (TINY_ADIW (%A2, %B2, %o0) CR_TAB + "st %b0+,%A1" CR_TAB + "st %b0+,%B1" CR_TAB + "st %b0,%C1" CR_TAB + TINY_SBIW (%A2, %B2, %o0+2), op, plen, -7); +} + /* Handle store of 24-bit type from register or zero to memory. */ static const char* @@ -3621,6 +4135,9 @@ avr_out_store_psi (rtx insn, rtx *op, in if (reg_base > 0) /* (r) */ { + if (AVR_TINY) + return avr_out_store_psi_reg_no_disp_tiny (insn, op, plen); + if (reg_base == REG_X) /* (R26) */ { gcc_assert (!reg_overlap_mentioned_p (base, src)); @@ -3642,6 +4159,10 @@ avr_out_store_psi (rtx insn, rtx *op, in else if (GET_CODE (base) == PLUS) /* (R + i) */ { int disp = INTVAL (XEXP (base, 1)); + + if (AVR_TINY) + return avr_out_store_psi_reg_disp_tiny (op, plen); + reg_base = REGNO (XEXP (base, 0)); if (disp > MAX_LD_OFFSET (GET_MODE (dest))) @@ -3758,6 +4279,31 @@ avr_out_movpsi (rtx insn, rtx *op, int * return ""; } +static const char* +avr_out_movqi_mr_r_reg_disp_tiny (rtx insn, rtx op[], int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx x = XEXP (dest, 0); + op[2] = XEXP (x, 0); + + if (reg_overlap_mentioned_p (src, XEXP (x, 0))) + { + avr_asm_len ("mov __tmp_reg__,%1" CR_TAB + TINY_ADIW (%A2, %B2, %o0) CR_TAB + "st %b0,__tmp_reg__", op, plen, -4); + } + else + { + avr_asm_len (TINY_ADIW (%A2, %B2, %o0) CR_TAB + "st %b0,%1" , op, plen, -3); + } + + if (!reg_unused_after (insn, XEXP (x,0))) + avr_asm_len (TINY_SBIW (%A2, %B2, %o0), op, plen, 2); + + return ""; +} static const char* out_movqi_mr_r (rtx insn, rtx op[], int *plen) @@ -3780,6 +4326,9 @@ out_movqi_mr_r (rtx insn, rtx op[], int int disp = INTVAL (XEXP (x, 1)); + if (AVR_TINY) + return avr_out_movqi_mr_r_reg_disp_tiny (insn, op, plen); + if (disp - GET_MODE_SIZE (GET_MODE (dest)) >= 63) { if (REGNO (XEXP (x, 0)) != REG_Y) @@ -3934,6 +4483,76 @@ avr_out_movhi_mr_r_xmega (rtx insn, rtx return ""; } +static const char* +avr_out_movhi_mr_r_reg_no_disp_tiny (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); + int mem_volatile_p = MEM_VOLATILE_P (dest); + op[2] = base; + + if (reg_base == reg_src) + { + return !mem_volatile_p && reg_unused_after (insn, src) + ? avr_asm_len ("mov __tmp_reg__,%B1" CR_TAB + "st %0,%A1" CR_TAB + TINY_ADIW (%A2, %B2, 1) CR_TAB + "st %0,__tmp_reg__", op, plen, -5) + : avr_asm_len ("mov __tmp_reg__,%B1" CR_TAB + TINY_ADIW (%A2, %B2, 1) CR_TAB + "st %0,__tmp_reg__" CR_TAB + TINY_SBIW (%A2, %B2, 1) CR_TAB + "st %0, %A1", op, plen, -7); + } + + return !mem_volatile_p && reg_unused_after (insn, base) + ? avr_asm_len ("st %0+,%A1" CR_TAB + "st %0,%B1", op, plen, -2) + : avr_asm_len (TINY_ADIW (%A2, %B2, 1) CR_TAB + "st %0,%B1" CR_TAB + "st -%0,%A1", op, plen, -4); +} + +static const char* +avr_out_movhi_mr_r_reg_disp_tiny (rtx op[], int *plen) +{ + rtx dest = op[0]; + rtx src = op[1]; + rtx base = XEXP (dest, 0); + int reg_base = REGNO (XEXP (base, 0)); + int reg_src = true_regnum (src); + op[2] = XEXP (base, 0); + + return reg_src == reg_base + ? avr_asm_len ("mov __tmp_reg__,%A1" CR_TAB + "mov __zero_reg__,%B1" CR_TAB + TINY_ADIW (%A2, %B2, %o0+1) CR_TAB + "st %b0,__zero_reg__" CR_TAB + "st -%b0,__tmp_reg__" CR_TAB + "clr __zero_reg__" CR_TAB + TINY_SBIW (%A2, %B2, %o0), op, plen, -9) + + : avr_asm_len (TINY_ADIW (%A2, %B2, %o0+1) CR_TAB + "st %b0,%B1" CR_TAB + "st -%b0,%A1" CR_TAB + TINY_SBIW (%A2, %B2, %o0), op, plen, -6); +} + +static const char* +avr_out_movhi_mr_r_post_inc_tiny (rtx op[], int *plen) +{ + rtx dest = op[0]; + rtx base = XEXP (dest, 0); + op[2] = XEXP (base, 0); + + return avr_asm_len (TINY_ADIW (%A2, %B2, 1) CR_TAB + "st %p0,%B1" CR_TAB + "st -%p0,%A1" CR_TAB + TINY_ADIW (%A2, %B2, 2), op, plen, -6); +} static const char* out_movhi_mr_r (rtx insn, rtx op[], int *plen) @@ -3964,6 +4583,9 @@ out_movhi_mr_r (rtx insn, rtx op[], int if (reg_base > 0) { + if (AVR_TINY) + return avr_out_movhi_mr_r_reg_no_disp_tiny (insn, op, plen); + if (reg_base != REG_X) return avr_asm_len ("std %0+1,%B1" CR_TAB "st %0,%A1", op, plen, -2); @@ -3992,6 +4614,10 @@ out_movhi_mr_r (rtx insn, rtx op[], int else if (GET_CODE (base) == PLUS) { int disp = INTVAL (XEXP (base, 1)); + + if (AVR_TINY) + return avr_out_movhi_mr_r_reg_disp_tiny (op, plen); + reg_base = REGNO (XEXP (base, 0)); if (disp > MAX_LD_OFFSET (GET_MODE (dest))) { @@ -4040,6 +4666,8 @@ out_movhi_mr_r (rtx insn, rtx op[], int if (!mem_volatile_p) return avr_asm_len ("st %0,%A1" CR_TAB "st %0,%B1", op, plen, -2); + if (AVR_TINY) + return avr_out_movhi_mr_r_post_inc_tiny (op, plen); return REGNO (XEXP (base, 0)) == REG_X ? avr_asm_len ("adiw r26,1" CR_TAB @@ -4212,7 +4840,11 @@ avr_out_compare (rtx insn, rtx *xop, int && (val8 == 0 || reg_unused_after (insn, xreg))) { - avr_asm_len ("sbiw %0,%1", xop, plen, 1); + if (AVR_TINY) + avr_asm_len (TINY_SBIW (%A0, %B0, %1), xop, plen, 2); + else + avr_asm_len ("sbiw %0,%1", xop, plen, 1); + i++; continue; } @@ -4222,7 +4854,9 @@ avr_out_compare (rtx insn, rtx *xop, int && compare_eq_p (insn) && reg_unused_after (insn, xreg)) { - return avr_asm_len ("adiw %0,%n1", xop, plen, 1); + return AVR_TINY + ? avr_asm_len (TINY_ADIW (%A0, %B0, %n1), xop, plen, 2) + : avr_asm_len ("adiw %0,%n1", xop, plen, 1); } } @@ -7411,10 +8045,10 @@ avr_file_start (void) 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) + if (AVR_XMEGA || AVR_TINY) 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); + fprintf (asm_out_file, "__tmp_reg__ = %d\n", AVR_TMP_REGNO); + fprintf (asm_out_file, "__zero_reg__ = %d\n", AVR_ZERO_REGNO); } @@ -7461,6 +8095,17 @@ order_regs_for_local_alloc (void) 0,1, 32,33,34,35 }; + static const int tiny_order_0[] = { + 24,25, + 22,23, + 30,31, + 26,27, + 28,29, + 21,20,19,18, + 16,17, + 32,33,34,35, + 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 + }; static const int order_1[] = { 18,19, 20,21, @@ -7473,6 +8118,17 @@ order_regs_for_local_alloc (void) 0,1, 32,33,34,35 }; + static const int tiny_order_1[] = { + 22,23, + 24,25, + 30,31, + 26,27, + 28,29, + 21,20,19,18, + 16,17, + 32,33,34,35, + 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 + }; static const int order_2[] = { 25,24, 23,22, @@ -7487,9 +8143,14 @@ order_regs_for_local_alloc (void) 32,33,34,35 }; - const int *order = (TARGET_ORDER_1 ? order_1 : - TARGET_ORDER_2 ? order_2 : - order_0); + /* + Select specific register allocation order. Tiny Core (attiny4/5/9/10/20/40) + devices has only 16 registers, so different allocation order should be used + */ + const int *order = (TARGET_ORDER_1 ? (AVR_TINY ? tiny_order_1 : order_1) : + TARGET_ORDER_2 ? (AVR_TINY ? tiny_order_1 : order_2) : + (AVR_TINY ? tiny_order_0 : order_0)); + for (i=0; i < ARRAY_SIZE (order_0); ++i) reg_alloc_order[i] = order[i]; } @@ -9151,7 +9812,7 @@ output_reload_in_const (rtx *op, rtx clo { if (!clear_p) avr_asm_len (ldreg_p ? "ldi %0,0" - : ZERO_REGNO == REGNO (xdest[n]) ? "clr %0" + : AVR_ZERO_REGNO == REGNO (xdest[n]) ? "clr %0" : "mov %0,__zero_reg__", &xdest[n], len, 1); continue; @@ -9350,6 +10011,50 @@ avr_output_addr_vec_elt (FILE *stream, i fprintf (stream, "\trjmp .L%d\n", value); } +static void +avr_conditional_register_usage(void) { + + if (AVR_TINY) { + unsigned int i; + + const int tiny_reg_alloc_order[] = { + 24,25, + 22,23, + 30,31, + 26,27, + 28,29, + 21,20,19,18, + 16,17, + 32,33,34,35, + 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 + }; + + /* Set R0-R17 as fixed registers. Reset R0-R17 in call used register list + - R0-R15 are not available in Tiny Core devices + - R16 and R17 are fixed registers + */ + for (i = 0; i <= 17; i++) { + fixed_regs[i] = 1; + call_used_regs[i] = 1; + } + + /* Set R18 to R21 as callee saved registers + - R18, R19, R20 and R21 are the callee saved registers in Tiny Core devices + */ + for (i = 18; i <= LAST_CALLEE_SAVED_REG; i++) { + call_used_regs[i] = 0; + } + + /*update register allocation order for Tiny Core devices */ + for (i=0; i < ARRAY_SIZE (tiny_reg_alloc_order); i++) { + reg_alloc_order[i] = tiny_reg_alloc_order[i]; + } + + CLEAR_HARD_REG_SET(reg_class_contents[(int)ADDW_REGS]); + CLEAR_HARD_REG_SET(reg_class_contents[(int)NO_LD_REGS]); + } +} + /* Returns true if SCRATCH are safe to be allocated as a scratch registers (for a define_peephole2) in the current function. */ @@ -9495,13 +10200,20 @@ avr_asm_out_dtor (rtx symbol, int priori static bool avr_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) { - if (TYPE_MODE (type) == BLKmode) - { - HOST_WIDE_INT size = int_size_in_bytes (type); - return (size == -1 || size > 8); - } + HOST_WIDE_INT size = int_size_in_bytes (type); + HOST_WIDE_INT ret_size_limit = AVR_TINY ? 4 : 8; + + /* In avr, there are 8 return registers. But, for Tiny Core + (attiny4/5/9/10/20/40) devices, only 4 registers available. + Return true if size is unknown or greater than the limit */ + if ((size == -1) || (size > ret_size_limit)) + { + return true; + } else + { return false; + } } /* Worker function for CASE_VALUES_THRESHOLD. */ @@ -10949,6 +11661,9 @@ avr_fold_builtin (tree fndecl, int n_arg #undef TARGET_BUILTIN_SETJMP_FRAME_VALUE #define TARGET_BUILTIN_SETJMP_FRAME_VALUE avr_builtin_setjmp_frame_value +#undef TARGET_CONDITIONAL_REGISTER_USAGE +#define TARGET_CONDITIONAL_REGISTER_USAGE avr_conditional_register_usage + #undef TARGET_HARD_REGNO_SCRATCH_OK #define TARGET_HARD_REGNO_SCRATCH_OK avr_hard_regno_scratch_ok #undef TARGET_CASE_VALUES_THRESHOLD diff -Naurp gcc/config/avr/avr-c.c gcc/config/avr/avr-c.c --- gcc/config/avr/avr-c.c 2012-09-05 17:49:47.000000000 +0530 +++ gcc/config/avr/avr-c.c 2013-01-21 18:40:04.000000000 +0530 @@ -113,6 +113,23 @@ avr_cpu_cpp_builtins (struct cpp_reader } if (AVR_XMEGA) cpp_define (pfile, "__AVR_XMEGA__"); + + if (AVR_TINY) + { + cpp_define (pfile, "__AVR_TINY__"); + + /* Define macro "__AVR_TINY_PM_BASE_ADDRESS__" with mapped program memory + start address. This macro shall be referred where mapped program memory + is accessed. (Eg. copying data section (do_copy_data) contents to data + memory region. + NOTE: + Program memory of AVR_TINY devices can not be accessed directly, it has + been mapped to the data memory. For AVR_TINY devices (ATtiny4/ 5/ 9/ 10/ + 20 and 40) mapped program memory starts at 0x4000. + */ + cpp_define (pfile, "__AVR_TINY_PM_BASE_ADDRESS__=0x4000"); + } + if (avr_current_arch->have_eijmp_eicall) { cpp_define (pfile, "__AVR_HAVE_EIJMP_EICALL__"); diff -Naurp gcc/config/avr/avr-devices.c gcc/config/avr/avr-devices.c --- gcc/config/avr/avr-devices.c 2012-08-06 20:04:27.000000000 +0530 +++ gcc/config/avr/avr-devices.c 2013-01-21 18:40:04.000000000 +0530 @@ -30,29 +30,30 @@ const struct base_arch_s avr_arch_types[] = { /* unknown device specified */ - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, NULL, "avr2" }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, NULL, "avr2" }, /* - A M J LM E E E X R d S S O A - S U M PO L L I M A a t F ff r - M L P MV P P J E M t a R s c - XW M M M G P a r e h - X P A D t t ID */ - { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, "1", "avr1" }, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, "2", "avr2" }, - { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0x0060, 32, "25", "avr25" }, - { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0x0060, 32, "3", "avr3" }, - { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0x0060, 32, "31", "avr31" }, - { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0x0060, 32, "35", "avr35" }, - { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0x0060, 32, "4", "avr4" }, - { 0, 1, 1, 1, 0, 0, 0, 0, 0, 0x0060, 32, "5", "avr5" }, - { 0, 1, 1, 1, 1, 1, 0, 0, 0, 0x0060, 32, "51", "avr51" }, - { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0x0060, 32, "6", "avr6" }, + A M J LM E E E X R T d S S O A + S U M PO L L I M A I a t F ff r + M L P MV P P J E M N t a R s c + XW M M M G P Y a r e h + X P A D t t ID */ + { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, "1", "avr1" }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, "2", "avr2" }, + { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0x0060, 32, "25", "avr25" }, + { 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0x0060, 32, "3", "avr3" }, + { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0x0060, 32, "31", "avr31" }, + { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0x0060, 32, "35", "avr35" }, + { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0x0060, 32, "4", "avr4" }, + { 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0x0060, 32, "5", "avr5" }, + { 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0x0060, 32, "51", "avr51" }, + { 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0x0060, 32, "6", "avr6" }, - { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0x2000, 0, "102", "avrxmega2" }, - { 0, 1, 1, 1, 1, 1, 0, 1, 0, 0x2000, 0, "104", "avrxmega4" }, - { 0, 1, 1, 1, 1, 1, 0, 1, 1, 0x2000, 0, "105", "avrxmega5" }, - { 0, 1, 1, 1, 1, 1, 1, 1, 0, 0x2000, 0, "106", "avrxmega6" }, - { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0x2000, 0, "107", "avrxmega7" } + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0x0040, 0, "100", "avrtiny" }, + { 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0x2000, 0, "102", "avrxmega2" }, + { 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0x2000, 0, "104", "avrxmega4" }, + { 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0x2000, 0, "105", "avrxmega5" }, + { 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0x2000, 0, "106", "avrxmega6" }, + { 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0x2000, 0, "107", "avrxmega7" } }; const struct mcu_type_s avr_mcu_types[] = { diff -Naurp gcc/config/avr/avr.h gcc/config/avr/avr.h --- gcc/config/avr/avr.h 2013-01-21 18:26:07.000000000 +0530 +++ gcc/config/avr/avr.h 2013-01-21 18:40:04.000000000 +0530 @@ -52,6 +52,9 @@ struct base_arch_s /* This core has the RAMPD special function register and thus also the RAMPX, RAMPY and RAMPZ registers. */ int have_rampd; + + /* This is a TINY core. */ + int tiny_p; /* Default start of data section address for architecture. */ int default_data_section_start; @@ -83,6 +86,7 @@ enum avr_arch ARCH_AVR5, ARCH_AVR51, ARCH_AVR6, + ARCH_AVRTINY, ARCH_AVRXMEGA2, ARCH_AVRXMEGA4, ARCH_AVRXMEGA5, @@ -213,6 +217,7 @@ enum #define AVR_3_BYTE_PC (AVR_HAVE_EIJMP_EICALL) #define AVR_XMEGA (avr_current_arch->xmega_p) +#define AVR_TINY (avr_current_arch->tiny_p) #define BITS_BIG_ENDIAN 0 #define BYTES_BIG_ENDIAN 0 @@ -342,7 +347,6 @@ enum reg_class { ALL_REGS, LIM_REG_CLASSES }; - #define N_REG_CLASSES (int)LIM_REG_CLASSES #define REG_CLASS_NAMES { \ @@ -417,7 +421,7 @@ enum reg_class { #define ARG_POINTER_REGNUM 34 -#define STATIC_CHAIN_REGNUM 2 +#define STATIC_CHAIN_REGNUM ((AVR_TINY) ? 18 :2) #define ELIMINABLE_REGS { \ {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \ diff -Naurp gcc/config/avr/avr-mcus.def gcc/config/avr/avr-mcus.def --- gcc/config/avr/avr-mcus.def 2012-09-10 16:16:27.000000000 +0530 +++ gcc/config/avr/avr-mcus.def 2013-01-21 18:40:04.000000000 +0530 @@ -231,6 +231,14 @@ AVR_MCU ("atxmega256d3", ARCH_AVRXME AVR_MCU ("avrxmega7", ARCH_AVRXMEGA7, NULL, 0, 0, 0x2000, 3, "x128a1") AVR_MCU ("atxmega128a1", ARCH_AVRXMEGA7, "__AVR_ATxmega128A1__", 0, 0, 0x2000, 3, "x128a1") AVR_MCU ("atxmega128a1u", ARCH_AVRXMEGA7, "__AVR_ATxmega128A1U__", 0, 0, 0x2000, 3, "x128a1u") +/* Tiny family */ +AVR_MCU ("avrtiny", ARCH_AVRTINY, NULL, 0, 0, 0x0040, 1, "tn10") +AVR_MCU ("attiny4", ARCH_AVRTINY, "__AVR_ATtiny4__", 0, 0, 0x0040, 1, "tn4") +AVR_MCU ("attiny5", ARCH_AVRTINY, "__AVR_ATtiny5__", 0, 0, 0x0040, 1, "tn5") +AVR_MCU ("attiny9", ARCH_AVRTINY, "__AVR_ATtiny9__", 0, 0, 0x0040, 1, "tn9") +AVR_MCU ("attiny10", ARCH_AVRTINY, "__AVR_ATtiny10__", 0, 0, 0x0040, 1, "tn10") +AVR_MCU ("attiny20", ARCH_AVRTINY, "__AVR_ATtiny20__", 0, 0, 0x0040, 1, "tn20") +AVR_MCU ("attiny40", ARCH_AVRTINY, "__AVR_ATtiny40__", 0, 0, 0x0040, 1, "tn40") /* Assembler only. */ AVR_MCU ("avr1", ARCH_AVR1, NULL, 0, 0, 0x0060, 1, "s1200") AVR_MCU ("at90s1200", ARCH_AVR1, "__AVR_AT90S1200__", 0, 0, 0x0060, 1, "s1200") diff -Naurp gcc/config/avr/avr.md gcc/config/avr/avr.md --- gcc/config/avr/avr.md 2012-03-22 20:36:57.000000000 +0530 +++ gcc/config/avr/avr.md 2013-01-21 18:40:04.000000000 +0530 @@ -59,6 +59,11 @@ (ZERO_REGNO 1) ; zero register r1 ]) +(define_constants + [ (TMP_REGNO_TINY 16) ; r16 is temp register for TINY10 + (ZERO_REGNO_TINY 17) ; r17 is zero register for TINY10 + ]) + (define_c_enum "unspec" [UNSPEC_STRLEN UNSPEC_MOVMEM @@ -158,9 +163,10 @@ ;; 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 +;; no_tiny: non-TINY core tiny : TINY core (define_attr "isa" - "mov,movw, rjmp,jmp, ijmp,eijmp, lpm,lpmx, elpm,elpmx, no_xmega,xmega, + "mov,movw, rjmp,jmp, ijmp,eijmp, lpm,lpmx, elpm,elpmx, no_xmega,xmega, no_tiny,tiny, standard" (const_string "standard")) @@ -212,9 +218,18 @@ (match_test "AVR_XMEGA")) (const_int 1) + (and (eq_attr "isa" "tiny") + (match_test "AVR_TINY")) + (const_int 1) + (and (eq_attr "isa" "no_xmega") (match_test "!AVR_XMEGA")) (const_int 1) + + (and (eq_attr "isa" "no_tiny") + (match_test "!AVR_TINY")) + (const_int 1) + ] (const_int 0))) @@ -5413,18 +5428,18 @@ (set_attr "cc" "clobber")]) (define_insn "delay_cycles_2" - [(unspec_volatile [(match_operand:HI 0 "const_int_operand" "n") + [(unspec_volatile [(match_operand:HI 0 "const_int_operand" "n,n") (const_int 2)] UNSPECV_DELAY_CYCLES) (set (match_operand:BLK 1 "" "") (unspec_volatile:BLK [(match_dup 1)] UNSPECV_MEMORY_BARRIER)) - (clobber (match_scratch:HI 2 "=&w"))] + (clobber (match_scratch:HI 2 "=&w,&d"))] "" - "ldi %A2,lo8(%0) - ldi %B2,hi8(%0) - 1: sbiw %A2,1 - brne 1b" - [(set_attr "length" "4") + "@ + ldi %A2,lo8(%0)\;ldi %B2,hi8(%0)\;1: sbiw %A2,1\;brne 1b + ldi %A2,lo8(%0)\;ldi %B2,hi8(%0)\;1: subi %A2,1\;sbci %B2,0\;brne 1b" + [(set_attr "length" "4,5") + (set_attr "isa" "no_tiny,tiny") (set_attr "cc" "clobber")]) (define_insn "delay_cycles_3" diff -Naurp gcc/config/avr/avr-tables.opt gcc/config/avr/avr-tables.opt --- gcc/config/avr/avr-tables.opt 2012-09-20 12:53:55.000000000 +0530 +++ gcc/config/avr/avr-tables.opt 2013-01-21 18:40:04.000000000 +0530 @@ -579,20 +579,41 @@ EnumValue Enum(avr_mcu) String(atxmega128a1u) Value(184) EnumValue -Enum(avr_mcu) String(avr1) Value(185) +Enum(avr_mcu) String(avrtiny) Value(185) EnumValue -Enum(avr_mcu) String(at90s1200) Value(186) +Enum(avr_mcu) String(attiny4) Value(186) EnumValue -Enum(avr_mcu) String(attiny11) Value(187) +Enum(avr_mcu) String(attiny5) Value(187) EnumValue -Enum(avr_mcu) String(attiny12) Value(188) +Enum(avr_mcu) String(attiny9) Value(188) EnumValue -Enum(avr_mcu) String(attiny15) Value(189) +Enum(avr_mcu) String(attiny10) Value(189) EnumValue -Enum(avr_mcu) String(attiny28) Value(190) +Enum(avr_mcu) String(attiny20) Value(190) + +EnumValue +Enum(avr_mcu) String(attiny40) Value(191) + +EnumValue +Enum(avr_mcu) String(avr1) Value(192) + +EnumValue +Enum(avr_mcu) String(at90s1200) Value(193) + +EnumValue +Enum(avr_mcu) String(attiny11) Value(194) + +EnumValue +Enum(avr_mcu) String(attiny12) Value(195) + +EnumValue +Enum(avr_mcu) String(attiny15) Value(196) + +EnumValue +Enum(avr_mcu) String(attiny28) Value(197) diff -Naurp gcc/config/avr/t-multilib gcc/config/avr/t-multilib --- gcc/config/avr/t-multilib 2012-09-20 12:53:55.000000000 +0530 +++ gcc/config/avr/t-multilib 2013-01-21 18:40:04.000000000 +0530 @@ -21,9 +21,9 @@ # along with GCC; see the file COPYING3. If not see # . -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 msp8 +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/mmcu=avrtiny msp8 -MULTILIB_DIRNAMES = avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 avrxmega2 avrxmega4 avrxmega5 avrxmega6 avrxmega7 tiny-stack avr25/tiny-stack +MULTILIB_DIRNAMES = avr2 avr25 avr3 avr31 avr35 avr4 avr5 avr51 avr6 avrxmega2 avrxmega4 avrxmega5 avrxmega6 avrxmega7 avrtiny tiny-stack avr25/tiny-stack MULTILIB_EXCEPTIONS = \ mmcu=avr3/msp8 \ @@ -37,7 +37,8 @@ MULTILIB_EXCEPTIONS = \ mmcu=avrxmega4/msp8 \ mmcu=avrxmega5/msp8 \ mmcu=avrxmega6/msp8 \ - mmcu=avrxmega7/msp8 + mmcu=avrxmega7/msp8 \ + mmcu=avrtiny/msp8 MULTILIB_MATCHES = \ mmcu?avr2=mmcu?at90s2313 \ @@ -210,4 +211,10 @@ MULTILIB_MATCHES = \ mmcu?avrxmega6=mmcu?atxmega256a3bu \ mmcu?avrxmega6=mmcu?atxmega256d3 \ mmcu?avrxmega7=mmcu?atxmega128a1 \ - mmcu?avrxmega7=mmcu?atxmega128a1u + mmcu?avrxmega7=mmcu?atxmega128a1u \ + mmcu?avrtiny=mmcu?attiny4 \ + mmcu?avrtiny=mmcu?attiny5 \ + mmcu?avrtiny=mmcu?attiny9 \ + mmcu?avrtiny=mmcu?attiny10 \ + mmcu?avrtiny=mmcu?attiny20 \ + mmcu?avrtiny=mmcu?attiny40 diff -Naurp libgcc/config/avr/lib1funcs.S libgcc/config/avr/lib1funcs.S --- libgcc/config/avr/lib1funcs.S 2012-03-28 14:34:11.000000000 +0530 +++ libgcc/config/avr/lib1funcs.S 2013-01-21 18:58:03.000000000 +0530 @@ -22,8 +22,13 @@ a copy of the GCC Runtime Library Except see the files COPYING3 and COPYING.RUNTIME respectively. If not, see . */ +#if defined (__AVR_TINY__) +#define __zero_reg__ r17 +#define __tmp_reg__ r16 +#else #define __zero_reg__ r1 #define __tmp_reg__ r0 +#endif #define __SREG__ 0x3f #if defined (__AVR_HAVE_SPH__) #define __SP_H__ 0x3e @@ -80,6 +85,15 @@ see the files COPYING3 and COPYING.RUNTI #define XJMP rjmp #endif +.macro wsubi r_arg1, i_arg2 +#if defined (__AVR_TINY__) + subi \r_arg1, lo8(\i_arg2) + sbci \r_arg1+1, hi8(\i_arg2) +#else + sbiw \r_arg1, \i_arg2 +#endif +.endm + .macro DEFUN name .global \name .func \name @@ -150,12 +164,12 @@ ENDF __umulqihi3 Multiplication 16 x 16 without MUL *******************************************************/ #if defined (L_mulhi3) -#define r_arg1L r24 /* multiplier Low */ -#define r_arg1H r25 /* multiplier High */ -#define r_arg2L r22 /* multiplicand Low */ -#define r_arg2H r23 /* multiplicand High */ +#define r_arg1L 24 /* multiplier Low */ +#define r_arg1H 25 /* multiplier High */ +#define r_arg2L 22 /* multiplicand Low */ +#define r_arg2H 23 /* multiplicand High */ #define r_resL __tmp_reg__ /* result Low */ -#define r_resH r21 /* result High */ +#define r_resH 21 /* result High */ DEFUN __mulhi3 clr r_resH ; clear result @@ -175,7 +189,7 @@ __mulhi3_skip1: lsr r_arg1H ; gets LSB of multiplier ror r_arg1L - sbiw r_arg1L,0 + wsubi r_arg1L,0 brne __mulhi3_loop ; exit if multiplier = 0 __mulhi3_exit: mov r_arg1H,r_resH ; result to return register @@ -230,22 +244,34 @@ ENDF __umulhisi3 /******************************************************* Multiplication 32 x 32 without MUL *******************************************************/ -#define r_arg1L r22 /* multiplier Low */ -#define r_arg1H r23 -#define r_arg1HL r24 -#define r_arg1HH r25 /* multiplier High */ - -#define r_arg2L r18 /* multiplicand Low */ -#define r_arg2H r19 -#define r_arg2HL r20 -#define r_arg2HH r21 /* multiplicand High */ +#define r_arg1L 22 /* multiplier Low */ +#define r_arg1H 23 +#define r_arg1HL 24 +#define r_arg1HH 25 /* multiplier High */ + +#define r_arg2L 18 /* multiplicand Low */ +#define r_arg2H 19 +#define r_arg2HL 20 +#define r_arg2HH 21 /* multiplicand High */ -#define r_resL r26 /* result Low */ -#define r_resH r27 -#define r_resHL r30 -#define r_resHH r31 /* result High */ +#define r_resL 26 /* result Low */ +#define r_resH 27 +#define r_resHL 30 +#define r_resHH 31 /* result High */ DEFUN __mulsi3 +#if defined (__AVR_TINY__) + in r26,__SP_L__ ; safe to use X, as it is r_resL/H + in r27,__SP_H__ + subi r26, lo8(-3) ; Add 3 to point past return address + sbci r27, hi8(-3) + push r_arg2L ; save callee saved regs + push r_arg2H + ld r_arg2L,X+ ; load from caller stack + ld r_arg2H,X+ + ld r_arg2HL,X+ + ld r_arg2HH,X +#endif /* defined (__AVR_TINY__) */ clr r_resHH ; clear result clr r_resHL ; clear result clr r_resH ; clear result @@ -268,7 +294,7 @@ __mulsi3_skip1: ror r_arg1H ror r_arg1L brne __mulsi3_loop - sbiw r_arg1HL,0 + wsubi r_arg1HL,0 cpc r_arg1H,r_arg1L brne __mulsi3_loop ; exit if multiplier = 0 __mulsi3_exit: @@ -276,6 +302,10 @@ __mulsi3_exit: mov_l r_arg1HL,r_resHL mov_h r_arg1H,r_resH mov_l r_arg1L,r_resL +#if defined (__AVR_TINY__) + pop r_arg2H ; restore callee saved regs + pop r_arg2L +#endif /* defined (__AVR_TINY__) */ ret ENDF __mulsi3 @@ -514,9 +544,12 @@ ENDF __mulpsi3 #undef C0 #else /* !HAVE_MUL */ - ;; C[0..2]: Expand Result +#if defined (__AVR_TINY__) +#define C0 16 +#else #define C0 0 +#endif /* defined (__AVR_TINY__) */ #define C1 C0+1 #define C2 21 @@ -524,6 +557,17 @@ ENDF __mulpsi3 ;; Clobbers: __tmp_reg__, R18, R19, R20, R21 DEFUN __mulpsi3 +#if defined (__AVR_TINY__) + in r26,__SP_L__ + in r27,__SP_H__ + subi r26, lo8(-3) ; Add 3 to point past return address + sbci r27, hi8(-3) + push B0 ; save callee saved regs + push B1 + ld B0,X+ ; load from caller stack + ld B1,X+ + ld B2,X+ +#endif /* defined (__AVR_TINY__) */ ;; C[] = 0 clr __tmp_reg__ @@ -550,6 +594,10 @@ DEFUN __mulpsi3 mov A2, C2 clr __zero_reg__ +#if defined (__AVR_TINY__) + pop B1 + pop B0 +#endif /* (__AVR_TINY__) */ ret ENDF __mulpsi3 @@ -618,6 +666,7 @@ ENDF __mulsqipsi3 Multiplication 64 x 64 *******************************************************/ +#if !defined (__AVR_TINY__) #if defined (L_muldi3) ;; A[] = A[] * B[] @@ -855,6 +904,7 @@ ENDF __muldi3 #undef A0 #endif /* L_muldi3 */ +#endif /* !defined (__AVR_TINY__) */ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -1027,7 +1077,7 @@ ENDF __divmodhi4 #define r_cnt 21 #if defined (L_udivmodpsi4) -;; R24:R22 = R24:R22 udiv R20:R18 +;; R24:R22 = R24:R24 udiv R20:R18 ;; R20:R18 = R24:R22 umod R20:R18 ;; Clobbers: R21, R25, R26 @@ -1248,6 +1298,10 @@ ENDF __divmodsi4 #endif /* defined (L_divmodsi4) */ +/* *di routines use registers below R19 and won't work with tiny arch + right now. */ + +#if !defined (__AVR_TINY__) /******************************************************* Division 64 / 64 Modulo 64 % 64 @@ -1665,12 +1719,15 @@ ENDF __negdi2 #undef A1 #undef A0 +#endif /* !defined (__AVR_TINY__) */ + .section .text.libgcc.prologue, "ax", @progbits /********************************** * This is a prologue subroutine **********************************/ +#if !defined (__AVR_TINY__) #if defined (L_prologue) ;; This function does not clobber T-flag; 64-bit division relies on it @@ -1776,6 +1833,7 @@ DEFUN __epilogue_restores__ ret ENDF __epilogue_restores__ #endif /* defined (L_epilogue) */ +#endif /* !defined (__AVR_TINY__) */ #ifdef L_exit .section .fini9,"ax",@progbits @@ -1820,8 +1878,13 @@ DEFUN __tablejump__ #else ijmp #endif - -#else /* !HAVE_LPMX */ +#elif defined (__AVR_TINY__) + wsubi 30, -(__AVR_TINY_PM_BASE_ADDRESS__) ; Add PM offset to Z + ld __tmp_reg__, Z+ + ld r31, Z ; Use ld instead of lpm to load Z + mov r30, __tmp_reg__ + ijmp +#else /* !HAVE_LPMX && !AVR_TINY */ lpm adiw r30, 1 push r0 @@ -1836,6 +1899,26 @@ DEFUN __tablejump__ ENDF __tablejump__ #endif /* defined (L_tablejump) */ +#if defined(__AVR_TINY__) +#ifdef L_copy_data + .section .init4,"ax",@progbits + .global __do_copy_data +__do_copy_data: + ldi r18, hi8(__data_end) + ldi r26, lo8(__data_start) + ldi r27, hi8(__data_start) + ldi r30, lo8(__data_load_start + __AVR_TINY_PM_BASE_ADDRESS__) + ldi r31, hi8(__data_load_start + __AVR_TINY_PM_BASE_ADDRESS__) + rjmp .L__do_copy_data_start +.L__do_copy_data_loop: + ld r19, z+ + st X+, r19 +.L__do_copy_data_start: + cpi r26, lo8(__data_end) + cpc r27, r18 + brne .L__do_copy_data_loop +#endif +#else #ifdef L_copy_data .section .init4,"ax",@progbits DEFUN __do_copy_data @@ -1901,13 +1984,14 @@ DEFUN __do_copy_data #endif /* ELPM && RAMPD */ ENDF __do_copy_data #endif /* L_copy_data */ +#endif /* !defined (__AVR_TINY__) */ /* __do_clear_bss is only necessary if there is anything in .bss section. */ #ifdef L_clear_bss .section .init4,"ax",@progbits DEFUN __do_clear_bss - ldi r17, hi8(__bss_end) + ldi r18, hi8(__bss_end) ldi r26, lo8(__bss_start) ldi r27, hi8(__bss_start) rjmp .do_clear_bss_start @@ -1915,7 +1999,7 @@ DEFUN __do_clear_bss st X+, __zero_reg__ .do_clear_bss_start: cpi r26, lo8(__bss_end) - cpc r27, r17 + cpc r27, r18 brne .do_clear_bss_loop ENDF __do_clear_bss #endif /* L_clear_bss */ @@ -1951,7 +2035,7 @@ DEFUN __do_global_ctors ldi r29, hi8(__ctors_end) rjmp .L__do_global_ctors_start .L__do_global_ctors_loop: - sbiw r28, 2 + wsubi r28, 2 mov_h r31, r29 mov_l r30, r28 XCALL __tablejump__ @@ -1994,7 +2078,11 @@ DEFUN __do_global_dtors mov_h r31, r29 mov_l r30, r28 XCALL __tablejump__ - adiw r28, 2 +#if defined (__AVR_TINY__) + wsubi r28, -2 +#else + adiw r28, 2 +#endif .L__do_global_dtors_start: cpi r28, lo8(__dtors_end) cpc r29, r17 @@ -2005,6 +2093,7 @@ ENDF __do_global_dtors .section .text.libgcc, "ax", @progbits +#if !defined (__AVR_TINY__) #ifdef L_tablejump_elpm DEFUN __tablejump_elpm__ #if defined (__AVR_HAVE_ELPMX__) @@ -2035,7 +2124,9 @@ DEFUN __tablejump_elpm__ #endif ENDF __tablejump_elpm__ #endif /* defined (L_tablejump_elpm) */ +#endif /* !defined (__AVR_TINY__) */ +#if !defined (__AVR_TINY__) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Loading n bytes from Flash; n = 3,4 ;; R22... = Flash[Z] @@ -2081,7 +2172,9 @@ ENDF __load_4 #endif /* L_load_4 */ #endif /* L_load_3 || L_load_3 */ +#endif /* !defined (__AVR_TINY__) */ +#if !defined (__AVR_TINY__) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Loading n bytes from Flash or RAM; n = 1,2,3,4 ;; R22... = Flash[R21:Z] or RAM[Z] depending on R21.7 @@ -2207,7 +2300,9 @@ ENDF __xload_4 #endif /* L_xload_4 */ #endif /* L_xload_{1|2|3|4} */ +#endif /* if !defined (__AVR_TINY__) */ +#if !defined (__AVR_TINY__) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; memcopy from Address Space __pgmx to RAM ;; R23:Z = Source Address @@ -2279,6 +2374,7 @@ ENDF __movmemx_hi #undef LOOP #endif /* L_movmemx */ +#endif /* !defined (__AVR_TINY__) */ .section .text.libgcc.builtins, "ax", @progbits diff -Naurp libgcc/config/avr/t-avr libgcc/config/avr/t-avr --- libgcc/config/avr/t-avr 2012-01-10 15:12:10.000000000 +0530 +++ libgcc/config/avr/t-avr 2013-01-21 18:40:04.000000000 +0530 @@ -1,13 +1,9 @@ LIB1ASMSRC = avr/lib1funcs.S + LIB1ASMFUNCS = \ _mulqi3 \ _mulhi3 \ - _mulpsi3 _mulsqipsi3 \ - _mulhisi3 \ - _umulhisi3 \ - _usmulhisi3 \ - _muluhisi3 \ - _mulshisi3 \ + _mulpsi3 \ _mulsi3 \ _udivmodqi4 \ _divmodqi4 \ @@ -16,19 +12,9 @@ LIB1ASMFUNCS = \ _divmodpsi4 _udivmodpsi4 \ _udivmodsi4 \ _divmodsi4 \ - _divdi3 _udivdi3 \ - _muldi3 \ - _udivmod64 \ - _negdi2 \ - _prologue \ - _epilogue \ _exit \ _cleanup \ _tablejump \ - _tablejump_elpm \ - _load_3 _load_4 \ - _xload_1 _xload_2 _xload_3 _xload_4 \ - _movmemx \ _copy_data \ _clear_bss \ _ctors \ @@ -38,22 +24,52 @@ LIB1ASMFUNCS = \ _loop_ffsqi2 \ _ctzsi2 \ _ctzhi2 \ - _clzdi2 \ _clzsi2 \ _clzhi2 \ - _paritydi2 \ _paritysi2 \ _parityhi2 \ _popcounthi2 \ _popcountsi2 \ - _popcountdi2 \ _popcountqi2 \ _bswapsi2 \ + _fmul _fmuls _fmulsu + +# The below functions either use registers that are not present +# in tiny core, or use a different register conventions (don't save +# callee saved regs, for example) +# _mulhisi3 and variations - clobber R18, R19 +# All *di funcs - use regs < R16 or expect args in regs < R20 +# _prologue and _epilogue save registers < R16 +# _tablejump/_tablejump_elmp - expect lpm and elpm support +# _load ad _xload variations - expect lpm and elpm support +# _movmemx - expects elpm/lpm + +ifneq ($(MULTIFLAGS),-mmcu=avrtiny) +LIB1ASMFUNCS += \ + _mulsqipsi3 \ + _mulhisi3 \ + _umulhisi3 \ + _usmulhisi3 \ + _muluhisi3 \ + _mulshisi3 \ + _divdi3 _udivdi3 \ + _muldi3 \ + _udivmod64 \ + _negdi2 \ + _prologue \ + _epilogue \ + _tablejump_elpm \ + _load_3 _load_4 \ + _xload_1 _xload_2 _xload_3 _xload_4 \ + _movmemx \ + _clzdi2 \ + _paritydi2 \ + _popcountdi2 \ _bswapdi2 \ _ashldi3 _ashrdi3 _lshrdi3 _rotldi3 \ _adddi3 _adddi3_s8 _subdi3 \ - _cmpdi2 _cmpdi2_s8 \ - _fmul _fmuls _fmulsu + _cmpdi2 _cmpdi2_s8 +endif LIB2FUNCS_EXCLUDE = \ _moddi3 _umoddi3 \