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 \