avr-c.c (avr_cpu_cpp_builtins): Don't define __MEMX for avrtiny.
authorJoern Rennecke <joern.rennecke@embecosm.com>
Tue, 21 Oct 2014 20:12:01 +0000 (20:12 +0000)
committerJoern Rennecke <amylaar@gcc.gnu.org>
Tue, 21 Oct 2014 20:12:01 +0000 (21:12 +0100)
gcc:

2014-10-21  Joern Rennecke  <joern.rennecke@embecosm.com>
    Vidya Praveen <vidya.praveen@atmel.com>
    Praveen Kumar Kaushik <Praveen_Kumar.Kaushik@atmel.com>
    Senthil Kumar Selvaraj <Senthil_Kumar.Selvaraj@atmel.com>
    Pitchumani Sivanupandi <Pitchumani.S@atmel.com>

* config/avr/avr-c.c (avr_cpu_cpp_builtins): Don't define
__MEMX for avrtiny.
* config/avr/avr.c (avr_insert_attributes): Reject __memx for avrtiny.
(avr_nonconst_pointer_addrspace): Likewise.
* config/avr/avr.h (AVR_HAVE_LPM): Define.

Added AVRTINY architecture to avr target.
* config/avr/avr-arch.h (avr_arch): Added AVRTINY architecture.
(base_arch_s): member added for AVRTINY architecture.
* config/avr/avr.c: Added TINY_ADIW, TINY_SBIW macros as AVRTINY
alternate for adiw/sbiw instructions. Added AVR_TMP_REGNO and
AVR_ZERO_REGNO macros for tmp and zero registers. Replaced TMP_REGNO
and ZERO_REGNO occurrences by AVR_TMP_REGNO and AVR_ZERO_REGNO
respectively. LAST_CALLEE_SAVED_REG macro added for the last register
in callee saved register list.
(avr_option_override): CCP address updated for AVRTINY.
(avr_init_expanders): tmp and zero rtx initialized as per arch.
Reset avr_have_dimode if AVRTINY.
(sequent_regs_live): Use LAST_CALLEE_SAVED_REG instead magic number.
(emit_push_sfr): Use AVR_TMP_REGNO for tmp register number.
(avr_prologue_setup_frame): Don't minimize prologue if AVRTINY.
Use LAST_CALLEE_SAVED_REG to refer last callee saved register.
(expand_epilogue): Likewise.
(avr_print_operand): Print CCP address in case of AVRTINY also.
<TBD>bad address
(function_arg_regno_p): Check different register list for arguments
if AVRTINY.
(init_cumulative_args): Check for AVRTINY to update number of argument
registers.
(tiny_valid_direct_memory_access_range): New function. Return false if
direct memory access range is not in accepted range for AVRTINY.
(avr_out_movqi_r_mr_reg_disp_tiny): New function to handle register
indirect load (with displacement) for AVRTINY.
(out_movqi_r_mr): Updated instruction length for AVRTINY. Call
avr_out_movqi_r_mr_reg_disp_tiny for load from reg+displacement.
(avr_out_movhi_r_mr_reg_no_disp_tiny): New function to handle register
indirect load (no displacement) for AVRTINY.
(avr_out_movhi_r_mr_reg_disp_tiny): New function to handle register
indirect load (with displacement) for AVRTINY.
(avr_out_movhi_r_mr_pre_dec_tiny): New function to handle register
indirect load for pre-decrement address.
(out_movhi_r_mr): In case of AVRTINY, call tiny register indirect load
functions. Update instruction length for AVRTINY.
(avr_out_movsi_r_mr_reg_no_disp_tiny): New function. Likewise, for
SImode.
(avr_out_movsi_r_mr_reg_disp_tiny): New function. Likewise, for SImode.
(out_movsi_r_mr): Likewise, for SImode.
(avr_out_movsi_mr_r_reg_no_disp_tiny): New function to handle register
indirect store (no displacement) for AVRTINY.
(avr_out_movsi_mr_r_reg_disp_tiny): New function to handle register
indirect store (with displacement) for AVRTINY.
(out_movsi_mr_r): Emit out insn for IO address store. Update store
instruction's size for AVRTINY. For AVRTINY, call tiny SImode indirect
store functions.
(avr_out_load_psi_reg_no_disp_tiny): New function to handle register
indirect load (no displacement) for PSImode in AVRTINY.
(avr_out_load_psi_reg_disp_tiny): New function to handle register
indirect load (with displacement) for PSImode in AVRTINY.
(avr_out_load_psi): Call PSImode register indirect load functions for
AVRTINY. Update instruction length for AVRTINY.
(avr_out_store_psi_reg_no_disp_tiny): New function to handle register
indirect store (no displacement) for PSImode in AVRTINY.
(avr_out_store_psi_reg_disp_tiny): New function to handle register
indirect store (with displacement) for PSImode in AVRTINY.
(avr_out_store_psi): Update instruction length for AVRTINY. Call tiny
register indirect store functions for AVRTINY.
(avr_out_movqi_mr_r_reg_disp_tiny): New function to handle QImode
register indirect store (with displacement) for AVRTINY.
(out_movqi_mr_r): Update instruction length for AVRTINY. Call tiny
register indirect store function for QImode in AVRTINY.
(avr_out_movhi_mr_r_xmega): Update instruction length for AVRTINY.
(avr_out_movhi_mr_r_reg_no_disp_tiny): New function to handle register
indirect store (no displacement) for HImode in AVRTINY.
(avr_out_movhi_mr_r_reg_disp_tiny): New function to handle register
indirect store (with displacement) for HImode in AVRTINY.
(avr_out_movhi_mr_r_post_inc_tiny): New function to handle register
indirect store for post-increment address in HImode.
(out_movhi_mr_r): Update instruction length for AVRTINY. Call tiny
register indirect store function for HImode in AVRTINY.
(avr_out_compare): Use TINY_SBIW/ TINY_ADIW in place of sbiw/adiw
in case of AVRTINY.
(order_regs_for_local_alloc): Updated register allocation order for
AVRTINY.
(avr_conditional_register_usage): New function. It is a target hook
(TARGET_CONDITIONAL_REGISTER_USAGE) function which updates fixed, call
used registers list and register allocation order for AVRTINY.
(avr_return_in_memory): Update return value size for AVRTINY.
* config/avr/avr-c.c (avr_cpu_cpp_builtins): Added builtin macros
for AVRTINY arch and tiny program memory base address.
* config/avr/avr-devices.c (avr_arch_types): Added AVRTINY arch.
(avr_texinfo): Added description for AVRTINY arch.
* config/avr/avr.h: Added macro to identify AVRTINY arch. Updated
STATIC_CHAIN_REGNUM for AVRTINY.
* config/avr/avr-mcus.def: Added AVRTINY arch devices.
* config/avr/avr.md: Added constants for tmp/ zero registers in
AVRTINY. Attributes for AVRTINY added.
(mov<mode>): Move src/ dest address to register if it is not in AVRTINY
memory access range.
(mov<mode>_insn): Avoid QImode direct load for AVRTINY if address not
in AVRTINY memory access range.
(*mov<mode>): Likewise for HImode and SImode.
(*movsf): Likewise for SFmode.
(delay_cycles_2): Updated instructions to be emitted as AVRTINY does
not have sbiw.
* config/avr/avr-protos.h: Added function prototype for
tiny_valid_direct_memory_access_range.
* config/avr/avr-tables.opt: Regenerate.
* gcc/config/avr/t-multilib: Regenerate.
* doc/avr-mmcu.texi: Regenerate.

gcc/testsuite:

2014-10-21  Joern Rennecke  <joern.rennecke@embecosm.com>

* gcc.target/avr/tiny-memx.c: New test.

* gcc.target/avr/tiny-caller-save.c: New test.

libgcc:

2014-10-21  Joern Rennecke  <joern.rennecke@embecosm.com>
    Vidya Praveen <vidya.praveen@atmel.com>
    Praveen Kumar Kaushik <Praveen_Kumar.Kaushik@atmel.com>
    Senthil Kumar Selvaraj <Senthil_Kumar.Selvaraj@atmel.com>
    Pitchumani Sivanupandi <Pitchumani.S@atmel.com>

* config/avr/lib1funcs.S (__do_global_dtors): Go back to descending
order.

Updated library functions for AVRTINY arch.
* config/avr/lib1funcs.S: Updated zero/tmp regs for AVRTINY.
Replaced occurrences of r0/r1 with tmp/zero reg macros.
Added wsubi/ wadi macros that expands conditionally as sbiw/ adiw
or AVRTINY equivalent. Replaced occurrences of sbiw/adiw with
wsubi/wadi macors.
(__mulsi3_helper): Update stack, preserve callee saved regs and
argument from stack. Restore callee save registers.
(__mulpsi3): Likewise.
(__muldi3, __udivmodsi4, __divmodsi4, __negsi2, __umoddi3, __udivmod64,
__moddi3, __adddi3, __adddi3_s8, __subdi3, __cmpdi2, __cmpdi2_s8,
__negdi2, __prologue_saves__, __epilogue_restores__): Excluded for
AVRTINY.
(__tablejump2__): Added lpm equivalent instructions for AVRTINY.
(__do_copy_data): Added new definition for AVRTINY.
(__do_clear_bss): Replace r17 by r18 to preserve zero reg for AVRTINY.
(__load_3, __load_4, __xload_1, __xload_2, __xload_3,
__xload_4, __movmemx_qi, __movmemx_hi): Excluded for AVRTINY.
* config/avr/lib1funcs-fixed.S: Replaced occurrences of r0/r1 with
tmp/zero reg macros. Replaced occurrences of sbiw/adiw with wsubi/wadi
macors.
   * config/avr/t-avr (LIB1ASMFUNCS): Remove unsupported functions for
AVRTINY.

Fix broken long multiplication on tiny arch.

Co-Authored-By: Pitchumani Sivanupandi <pitchumani.s@atmel.com>
Co-Authored-By: Praveen Kumar Kaushik <Praveen_Kumar.Kaushik@atmel.com>
Co-Authored-By: Senthil Kumar Selvaraj <Senthil_Kumar.Selvaraj@atmel.com>
Co-Authored-By: Vidya Praveen <vidya.praveen@atmel.com>
From-SVN: r216525

19 files changed:
gcc/ChangeLog
gcc/config/avr/avr-arch.h
gcc/config/avr/avr-c.c
gcc/config/avr/avr-devices.c
gcc/config/avr/avr-mcus.def
gcc/config/avr/avr-protos.h
gcc/config/avr/avr-tables.opt
gcc/config/avr/avr.c
gcc/config/avr/avr.h
gcc/config/avr/avr.md
gcc/config/avr/t-multilib
gcc/doc/avr-mmcu.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/avr/tiny-caller-save.c [new file with mode: 0644]
gcc/testsuite/gcc.target/avr/tiny-memx.c [new file with mode: 0644]
libgcc/ChangeLog
libgcc/config/avr/lib1funcs-fixed.S
libgcc/config/avr/lib1funcs.S
libgcc/config/avr/t-avr

index 4e9f64d694a14590041d71a8933d76358043832a..6d5e2cc908d1e1212d9eac3d9b489d9fd225916a 100644 (file)
@@ -1,3 +1,119 @@
+2014-10-21  Joern Rennecke  <joern.rennecke@embecosm.com>
+           Vidya Praveen <vidya.praveen@atmel.com>
+           Praveen Kumar Kaushik <Praveen_Kumar.Kaushik@atmel.com>
+           Senthil Kumar Selvaraj <Senthil_Kumar.Selvaraj@atmel.com>
+           Pitchumani Sivanupandi <Pitchumani.S@atmel.com>
+
+       * config/avr/avr-c.c (avr_cpu_cpp_builtins): Don't define
+       __MEMX for avrtiny.
+       * config/avr/avr.c (avr_insert_attributes): Reject __memx for avrtiny.
+       (avr_nonconst_pointer_addrspace): Likewise.
+       * config/avr/avr.h (AVR_HAVE_LPM): Define.
+
+       Added AVRTINY architecture to avr target.
+       * config/avr/avr-arch.h (avr_arch): Added AVRTINY architecture.
+       (base_arch_s): member added for AVRTINY architecture.
+       * config/avr/avr.c: Added TINY_ADIW, TINY_SBIW macros as AVRTINY
+       alternate for adiw/sbiw instructions. Added AVR_TMP_REGNO and
+       AVR_ZERO_REGNO macros for tmp and zero registers. Replaced TMP_REGNO
+       and ZERO_REGNO occurrences by AVR_TMP_REGNO and AVR_ZERO_REGNO
+       respectively. LAST_CALLEE_SAVED_REG macro added for the last register
+       in callee saved register list.
+       (avr_option_override): CCP address updated for AVRTINY.
+       (avr_init_expanders): tmp and zero rtx initialized as per arch.
+       Reset avr_have_dimode if AVRTINY.
+       (sequent_regs_live): Use LAST_CALLEE_SAVED_REG instead magic number.
+       (emit_push_sfr): Use AVR_TMP_REGNO for tmp register number.
+       (avr_prologue_setup_frame): Don't minimize prologue if AVRTINY.
+       Use LAST_CALLEE_SAVED_REG to refer last callee saved register.
+       (expand_epilogue): Likewise.
+       (avr_print_operand): Print CCP address in case of AVRTINY also.
+       <TBD>bad address
+       (function_arg_regno_p): Check different register list for arguments
+       if AVRTINY.
+       (init_cumulative_args): Check for AVRTINY to update number of argument
+       registers.
+       (tiny_valid_direct_memory_access_range): New function. Return false if
+       direct memory access range is not in accepted range for AVRTINY.
+       (avr_out_movqi_r_mr_reg_disp_tiny): New function to handle register
+       indirect load (with displacement) for AVRTINY.
+       (out_movqi_r_mr): Updated instruction length for AVRTINY. Call
+       avr_out_movqi_r_mr_reg_disp_tiny for load from reg+displacement.
+       (avr_out_movhi_r_mr_reg_no_disp_tiny): New function to handle register
+       indirect load (no displacement) for AVRTINY.
+       (avr_out_movhi_r_mr_reg_disp_tiny): New function to handle register
+       indirect load (with displacement) for AVRTINY.
+       (avr_out_movhi_r_mr_pre_dec_tiny): New function to handle register
+       indirect load for pre-decrement address.
+       (out_movhi_r_mr): In case of AVRTINY, call tiny register indirect load
+       functions. Update instruction length for AVRTINY.
+       (avr_out_movsi_r_mr_reg_no_disp_tiny): New function. Likewise, for
+       SImode.
+       (avr_out_movsi_r_mr_reg_disp_tiny): New function. Likewise, for SImode.
+       (out_movsi_r_mr): Likewise, for SImode.
+       (avr_out_movsi_mr_r_reg_no_disp_tiny): New function to handle register
+       indirect store (no displacement) for AVRTINY.
+       (avr_out_movsi_mr_r_reg_disp_tiny): New function to handle register
+       indirect store (with displacement) for AVRTINY.
+       (out_movsi_mr_r): Emit out insn for IO address store. Update store
+       instruction's size for AVRTINY. For AVRTINY, call tiny SImode indirect
+       store functions.
+       (avr_out_load_psi_reg_no_disp_tiny): New function to handle register
+       indirect load (no displacement) for PSImode in AVRTINY.
+       (avr_out_load_psi_reg_disp_tiny): New function to handle register
+       indirect load (with displacement) for PSImode in AVRTINY.
+       (avr_out_load_psi): Call PSImode register indirect load functions for
+       AVRTINY. Update instruction length for AVRTINY.
+       (avr_out_store_psi_reg_no_disp_tiny): New function to handle register
+       indirect store (no displacement) for PSImode in AVRTINY.
+       (avr_out_store_psi_reg_disp_tiny): New function to handle register
+       indirect store (with displacement) for PSImode in AVRTINY.
+       (avr_out_store_psi): Update instruction length for AVRTINY. Call tiny
+       register indirect store functions for AVRTINY.
+       (avr_out_movqi_mr_r_reg_disp_tiny): New function to handle QImode
+       register indirect store (with displacement) for AVRTINY.
+       (out_movqi_mr_r): Update instruction length for AVRTINY. Call tiny
+       register indirect store function for QImode in AVRTINY.
+       (avr_out_movhi_mr_r_xmega): Update instruction length for AVRTINY.
+       (avr_out_movhi_mr_r_reg_no_disp_tiny): New function to handle register
+       indirect store (no displacement) for HImode in AVRTINY.
+       (avr_out_movhi_mr_r_reg_disp_tiny): New function to handle register
+       indirect store (with displacement) for HImode in AVRTINY.
+       (avr_out_movhi_mr_r_post_inc_tiny): New function to handle register
+       indirect store for post-increment address in HImode.
+       (out_movhi_mr_r): Update instruction length for AVRTINY. Call tiny
+       register indirect store function for HImode in AVRTINY.
+       (avr_out_compare): Use TINY_SBIW/ TINY_ADIW in place of sbiw/adiw
+       in case of AVRTINY.
+       (order_regs_for_local_alloc): Updated register allocation order for
+       AVRTINY.
+       (avr_conditional_register_usage): New function. It is a target hook
+       (TARGET_CONDITIONAL_REGISTER_USAGE) function which updates fixed, call
+       used registers list and register allocation order for AVRTINY.
+       (avr_return_in_memory): Update return value size for AVRTINY.
+       * config/avr/avr-c.c (avr_cpu_cpp_builtins): Added builtin macros
+       for AVRTINY arch and tiny program memory base address.
+       * config/avr/avr-devices.c (avr_arch_types): Added AVRTINY arch.
+       (avr_texinfo): Added description for AVRTINY arch.
+       * config/avr/avr.h: Added macro to identify AVRTINY arch. Updated
+       STATIC_CHAIN_REGNUM for AVRTINY.
+       * config/avr/avr-mcus.def: Added AVRTINY arch devices.
+       * config/avr/avr.md: Added constants for tmp/ zero registers in
+       AVRTINY. Attributes for AVRTINY added.
+       (mov<mode>): Move src/ dest address to register if it is not in AVRTINY
+       memory access range.
+       (mov<mode>_insn): Avoid QImode direct load for AVRTINY if address not
+       in AVRTINY memory access range.
+       (*mov<mode>): Likewise for HImode and SImode.
+       (*movsf): Likewise for SFmode.
+       (delay_cycles_2): Updated instructions to be emitted as AVRTINY does
+       not have sbiw.
+       * config/avr/avr-protos.h: Added function prototype for
+       tiny_valid_direct_memory_access_range.
+       * config/avr/avr-tables.opt: Regenerate.
+       * gcc/config/avr/t-multilib: Regenerate.
+       * doc/avr-mmcu.texi: Regenerate.
+
 2014-10-21  Andrew Pinski  <apinski@cavium.com>
 
        * doc/invoke.texi (AARCH64/mtune): Document thunderx as an
index 4e368affc16757e2d25bcdd104edb8aff6fd8cd6..168793efccb2c4f7bd708ee202194ccc59b89d39 100644 (file)
@@ -37,6 +37,7 @@ enum avr_arch
   ARCH_AVR5,
   ARCH_AVR51,
   ARCH_AVR6,
+  ARCH_AVRTINY,
   ARCH_AVRXMEGA2,
   ARCH_AVRXMEGA4,
   ARCH_AVRXMEGA5,
@@ -77,6 +78,9 @@ typedef struct
      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;
 
index d5c40e6b34ab450c76b75a6c0ceec57d4b7e953f..f66f36186f7758e133cbd2a586ba4a9939655d03 100644 (file)
@@ -321,6 +321,23 @@ avr_cpu_cpp_builtins (struct cpp_reader *pfile)
     }
   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__");
@@ -376,7 +393,10 @@ avr_cpu_cpp_builtins (struct cpp_reader *pfile)
             /* Only supply __FLASH<n> macro if the address space is reasonable
                for this target.  The address space qualifier itself is still
                supported, but using it will throw an error.  */
-            && avr_addrspace[i].segment < avr_n_flash)
+            && avr_addrspace[i].segment < avr_n_flash
+           /* Only support __MEMX macro if we have LPM.  */
+           && (AVR_HAVE_LPM || avr_addrspace[i].pointer_size <= 2))
+
           {
             const char *name = avr_addrspace[i].name;
             char *Name = (char*) alloca (1 + strlen (name));
index 9044d713d89d7b00d438936abb319ce8280b2cd3..a926d2055cb4688cfe72be6b8d4e72b490d2be1b 100644 (file)
@@ -31,29 +31,30 @@ const avr_arch_t
 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   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, 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 avr_arch_info_t
@@ -85,6 +86,9 @@ avr_texinfo[] =
   { ARCH_AVR6,
     "``Enhanced'' devices with 3-byte PC, i.e.@: with more than 128@tie{}KiB "
     "of program memory." },
+  { ARCH_AVRTINY,
+    "``TINY'' Tiny core devices with 512@tie{}B up to 4@tie{}KiB of "
+    "program memory." },
   { ARCH_AVRXMEGA2,
     "``XMEGA'' devices with more than 8@tie{}KiB and up to 64@tie{}KiB "
     "of program memory." },
index acec6a5c7a1d4d81ce32780bb927118a705c68e7..e890149f158b2ca1e74254183dd1bf2c43710924 100644 (file)
@@ -326,6 +326,14 @@ AVR_MCU ("avrxmega7",        ARCH_AVRXMEGA7, AVR_ISA_NONE, NULL,
 AVR_MCU ("atxmega128a1",     ARCH_AVRXMEGA7, AVR_ISA_NONE, "__AVR_ATxmega128A1__",     0x2000, 0x0, 3, "x128a1")
 AVR_MCU ("atxmega128a1u",    ARCH_AVRXMEGA7, AVR_ISA_RMW,  "__AVR_ATxmega128A1U__",    0x2000, 0x0, 3, "x128a1u")
 AVR_MCU ("atxmega128a4u",    ARCH_AVRXMEGA7, AVR_ISA_RMW,  "__AVR_ATxmega128A4U__",    0x2000, 0x0, 3, "x128a4u")
+/* Tiny family */
+AVR_MCU ("avrtiny",          ARCH_AVRTINY,   AVR_ISA_NONE, NULL,                       0x0040, 0x0, 1, "tn10")
+AVR_MCU ("attiny4",          ARCH_AVRTINY,   AVR_ISA_NONE, "__AVR_ATtiny4__",          0x0040, 0x0, 1, "tn4")
+AVR_MCU ("attiny5",          ARCH_AVRTINY,   AVR_ISA_NONE, "__AVR_ATtiny5__",          0x0040, 0x0, 1, "tn5")
+AVR_MCU ("attiny9",          ARCH_AVRTINY,   AVR_ISA_NONE, "__AVR_ATtiny9__",          0x0040, 0x0, 1, "tn9") 
+AVR_MCU ("attiny10",         ARCH_AVRTINY,   AVR_ISA_NONE, "__AVR_ATtiny10__",         0x0040, 0x0, 1, "tn10")
+AVR_MCU ("attiny20",         ARCH_AVRTINY,   AVR_ISA_NONE, "__AVR_ATtiny20__",         0x0040, 0x0, 1, "tn20")
+AVR_MCU ("attiny40",         ARCH_AVRTINY,   AVR_ISA_NONE, "__AVR_ATtiny40__",         0x0040, 0x0, 1, "tn40")
 /* Assembler only.  */
 AVR_MCU ("avr1",                 ARCH_AVR1, AVR_ISA_NONE, NULL,                        0x0060, 0x0, 1, "s1200")
 AVR_MCU ("at90s1200",            ARCH_AVR1, AVR_ISA_NONE, "__AVR_AT90S1200__",         0x0060, 0x0, 1, "s1200")
index d0784042ef465fdea8f716060bae70e3469b4472..6342c087d4a76d1afc939ffc8701b0d27cc0a829 100644 (file)
@@ -46,6 +46,7 @@ extern void avr_init_cumulative_args (CUMULATIVE_ARGS*, tree, rtx, tree);
 
 #ifdef RTX_CODE
 extern int avr_hard_regno_call_part_clobbered (unsigned, enum machine_mode);
+extern bool tiny_valid_direct_memory_access_range(rtx, enum machine_mode);
 extern const char *output_movqi (rtx_insn *insn, rtx operands[], int *l);
 extern const char *output_movhi (rtx_insn *insn, rtx operands[], int *l);
 extern const char *output_movsisf (rtx_insn *insn, rtx operands[], int *l);
index 4de0dbd750e008b855b189b20aa35c3ff7348462..c7e72c2ad7734db607dd955ce6b805e4da86c770 100644 (file)
@@ -65,6 +65,9 @@ Enum(avr_arch) String(avrxmega6) Value(ARCH_AVRXMEGA6)
 EnumValue
 Enum(avr_arch) String(avrxmega7) Value(ARCH_AVRXMEGA7)
 
+EnumValue
+Enum(avr_arch) String(avrtiny) Value(ARCH_AVRTINY)
+
 EnumValue
 Enum(avr_arch) String(avr1) Value(ARCH_AVR1)
 
index 704c6f7b35e3b572efe65325c76b3783180191b0..6c781c9466d7f334e2abccdc692c76699b1ac429 100644 (file)
   ((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[ADDR_SPACE_COUNT] =
@@ -156,6 +167,9 @@ static bool avr_rtx_costs (rtx, int, int, int, int*, bool);
 /* 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 ? 19 : 17)
+
 /* Implicit target register of LPM instruction (R0) */
 extern GTY(()) rtx lpm_reg_rtx;
 rtx lpm_reg_rtx;
@@ -365,7 +379,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;
@@ -397,8 +411,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);
 
@@ -410,6 +424,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; 
 }
 
 
@@ -918,7 +937,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])
         {
@@ -1031,7 +1050,7 @@ emit_push_sfr (rtx sfr, bool frame_related_p, bool clr_p)
     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)
     {
@@ -1057,7 +1076,8 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set)
                    && 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
@@ -1094,11 +1114,11 @@ avr_prologue_setup_frame (HOST_WIDE_INT size, HARD_REG_SET set)
       /* 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;
 
@@ -1338,10 +1358,10 @@ avr_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.  */
@@ -1483,7 +1503,8 @@ avr_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
@@ -1641,14 +1662,14 @@ avr_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)
@@ -2130,10 +2151,14 @@ avr_print_operand_punct_valid_p (unsigned char code)
 static void
 avr_print_operand (FILE *file, rtx x, int code)
 {
-  int abcd = 0;
+  int abcd = 0, ef = 0, ij = 0;
 
   if (code >= 'A' && code <= 'D')
     abcd = code - 'A';
+  else if (code == 'E' || code == 'F')
+    ef = code - 'E';
+  else if (code == 'I' || code == 'J')
+    ij = code - 'I';
 
   if (code == '~')
     {
@@ -2170,6 +2195,16 @@ avr_print_operand (FILE *file, rtx x, int code)
       else
         fatal_insn ("operands to %T/%t must be reg + const_int:", x);
     }
+  else if (code == 'E' || code == 'F')
+    {
+      rtx op = XEXP(x, 0);
+      fprintf (file, reg_names[REGNO (op) + ef]);
+    }
+  else if (code == 'I' || code == 'J')
+    {
+      rtx op = XEXP(XEXP(x, 0), 0);
+      fprintf (file, reg_names[REGNO (op) + ij]);
+    }
   else if (REG_P (x))
     {
       if (x == zero_reg_rtx)
@@ -2196,7 +2231,7 @@ avr_print_operand (FILE *file, rtx x, int code)
             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__");
@@ -2239,6 +2274,13 @@ avr_print_operand (FILE *file, rtx x, int code)
 
           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)
@@ -2596,7 +2638,7 @@ avr_simplify_comparison_p (enum machine_mode mode, RTX_CODE op, rtx x)
 int
 avr_function_arg_regno_p(int r)
 {
-  return (r >= 8 && r <= 25);
+  return (AVR_TINY ? r >= 20 && r <= 25 : r >= 8 && r <= 25);
 }
 
 
@@ -2608,7 +2650,7 @@ void
 avr_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;
@@ -3144,6 +3186,35 @@ avr_out_xload (rtx_insn *insn ATTRIBUTE_UNUSED, rtx *op, int *plen)
   return "";
 }
 
+/*
+AVRTC-579
+if operand is symbol or constant expression with value > 0xbf
+  return false, otherwise true
+This check is used to avoid lds/sts instruction with invalid memory
+access range (valid range 0x40..0xbf). For io operand range 0x0..0x3f,
+in/out instruction will be generated.
+*/
+bool tiny_valid_direct_memory_access_range(rtx op, enum machine_mode mode)
+{
+  rtx x;
+
+  if (!AVR_TINY)
+    return true;
+
+  x = XEXP(op,0);
+
+  if (MEM_P(op) && x && (GET_CODE(x) == SYMBOL_REF))
+  {
+    return false;
+  }
+  if (MEM_P(op) && x && (CONSTANT_ADDRESS_P (x)) &&
+     !(IN_RANGE (INTVAL (x), 0, 0xC0 - GET_MODE_SIZE (mode))))
+  {
+    return false;
+  }
+
+  return true;
+}
 
 const char*
 output_movqi (rtx_insn *insn, rtx operands[], int *plen)
@@ -3272,6 +3343,24 @@ output_movhi (rtx_insn *insn, rtx xop[], int *plen)
   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 *insn, rtx op[], int *plen)
+{
+  rtx dest = op[0];
+  rtx src = op[1];
+  rtx x = XEXP (src, 0);
+
+  avr_asm_len (TINY_ADIW (%I1, %J1, %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 (%I1, %J1, %o1), op, plen, 2);
+
+  return "";
+}
+
 static const char*
 out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen)
 {
@@ -3281,11 +3370,13 @@ out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen)
 
   if (CONSTANT_ADDRESS_P (x))
     {
+      int n_words = AVR_TINY ? 1 : 2;
       return optimize > 0 && io_address_operand (x, QImode)
         ? avr_asm_len ("in %0,%i1", op, plen, -1)
-        : avr_asm_len ("lds %0,%m1", op, plen, -2);
+        : avr_asm_len ("lds %0,%m1", op, plen, -n_words);
     }
-  else if (GET_CODE (x) == PLUS
+
+  if (GET_CODE (x) == PLUS
            && REG_P (XEXP (x, 0))
            && CONST_INT_P (XEXP (x, 1)))
     {
@@ -3293,6 +3384,9 @@ out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen)
 
       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)
         {
           if (REGNO (XEXP (x, 0)) != REG_Y)
@@ -3332,6 +3426,82 @@ out_movqi_r_mr (rtx_insn *insn, rtx op[], int *plen)
   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);
+
+  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 (%E1, %F1, 1) CR_TAB                       
+          "ld %B0,%1"             CR_TAB                        
+          TINY_SBIW (%E1, %F1, 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));
+
+  if (reg_base == reg_dest)
+  {
+      return avr_asm_len (TINY_ADIW (%I1, %J1, %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 (%I1, %J1, %o1) CR_TAB
+              "ld %A0,%b1+"             CR_TAB
+              "ld %B0,%b1"              CR_TAB
+              TINY_SBIW (%I1, %J1, %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 *insn, rtx op[], int *plen)
+{
+  int mem_volatile_p = 0;
+  rtx dest = op[0];
+  rtx src = op[1];
+  rtx base = XEXP (src, 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 (%I1, %J1, 2)  CR_TAB
+          "ld %A0,%p1+"   CR_TAB
+          "ld %B0,%p1"    CR_TAB
+          TINY_SBIW (%I1, %J1, 1), op, plen, -6);
+}
+
 static const char*
 out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen)
 {
@@ -3346,6 +3516,9 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen)
 
   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
@@ -3368,6 +3541,9 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen)
       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)
@@ -3379,7 +3555,7 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen)
                            "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
@@ -3413,6 +3589,9 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen)
     }
   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);
 
@@ -3440,18 +3619,112 @@ out_movhi_r_mr (rtx_insn *insn, rtx op[], int *plen)
     }
   else if (CONSTANT_ADDRESS_P (base))
     {
+      int n_words = AVR_TINY ? 2 : 4;
       return optimize > 0 && io_address_operand (base, HImode)
         ? avr_asm_len ("in %A0,%i1" CR_TAB
                        "in %B0,%i1+1", op, plen, -2)
 
         : avr_asm_len ("lds %A0,%m1" CR_TAB
-                       "lds %B0,%m1+1", op, plen, -4);
+                       "lds %B0,%m1+1", op, plen, -n_words);
     }
 
   fatal_insn ("unknown move insn:",insn);
   return "";
 }
 
+static const char*
+avr_out_movsi_r_mr_reg_no_disp_tiny (rtx_insn *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);
+
+  if (reg_dest == reg_base)
+    {
+         /* "ld r26,-X" is undefined */
+      return *l=9, (TINY_ADIW (%E1, %F1, 3) CR_TAB
+                    "ld %D0,%1"             CR_TAB
+                    "ld %C0,-%1"            CR_TAB
+                    "ld __tmp_reg__,-%1"   CR_TAB
+                    TINY_SBIW (%E1, %F1, 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 (%E1, %F1, 3));
+    }
+}
+
+static const char*
+avr_out_movsi_r_mr_reg_disp_tiny (rtx_insn *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));
+
+  if (reg_dest == reg_base)
+    {
+         /* "ld r26,-X" is undefined */
+      return *l=9, (TINY_ADIW (%I1, %J1, %o1+3) CR_TAB
+                    "ld %D0,%b1"                 CR_TAB
+                    "ld %C0,-%b1"                CR_TAB
+                    "ld __tmp_reg__,-%b1"        CR_TAB
+                    TINY_SBIW (%I1, %J1, 1)     CR_TAB
+                    "ld %A0,%b1"                 CR_TAB
+                    "mov %B0,__tmp_reg__");
+    }
+  else if (reg_dest == reg_base - 2)
+    {
+      return *l=7, (TINY_ADIW (%I1, %J1, %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 (%I1, %J1, %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 (%I1, %J1, %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 (%I1, %J1, %o1+3));
+    }
+}
+
 static const char*
 out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l)
 {
@@ -3467,6 +3740,9 @@ out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l)
 
   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)
@@ -3521,6 +3797,9 @@ out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l)
     {
       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)
@@ -3604,15 +3883,133 @@ out_movsi_r_mr (rtx_insn *insn, rtx op[], int *l)
                  "ld %C0,%1" CR_TAB
                  "ld %D0,%1");
   else if (CONSTANT_ADDRESS_P (base))
-    return *l=8, ("lds %A0,%m1"   CR_TAB
+    {
+      if (io_address_operand (base, SImode))
+        {
+          *l = 4;
+          return ("in %A0,%i1"   CR_TAB
+                  "in %B0,%i1+1" CR_TAB
+                  "in %C0,%i1+2" CR_TAB
+                  "in %D0,%i1+3");
+        }
+      else
+        {
+          *l = AVR_TINY ? 4 : 8;
+          return ("lds %A0,%m1"   CR_TAB
                   "lds %B0,%m1+1" CR_TAB
                   "lds %C0,%m1+2" CR_TAB
                   "lds %D0,%m1+3");
+        }
+    }
 
   fatal_insn ("unknown move insn:",insn);
   return "";
 }
 
+static const char*
+avr_out_movsi_mr_r_reg_no_disp_tiny (rtx_insn *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);
+  
+  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 (%E0, %F0, 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 (%E0, %F0, 1) CR_TAB
+                        "st %0+,__tmp_reg__"    CR_TAB
+                        "st %0+,%C1"            CR_TAB
+                        "st %0+,%D1"            CR_TAB
+                        TINY_SBIW (%E0, %F0, 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 (%E0, %F0, 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 (%E0, %F0, 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);
+
+  if (reg_base == reg_src)
+    {
+         *l = 11;
+         return ("mov __tmp_reg__,%A2"        CR_TAB
+                     "mov __zero_reg__,%B2"       CR_TAB
+              TINY_ADIW (%I0, %J0, %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 (%I0, %J0, %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 (%I0, %J0, %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 (%I0, %J0, %o0+3));
+           }
+  *l = 8;
+  return (TINY_ADIW (%I0, %J0, %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 (%I0, %J0, %o0+3));
+}
+
 static const char*
 out_movsi_mr_r (rtx_insn *insn, rtx op[], int *l)
 {
@@ -3627,12 +4024,29 @@ out_movsi_mr_r (rtx_insn *insn, rtx op[], int *l)
     l = &tmp;
 
   if (CONSTANT_ADDRESS_P (base))
-    return *l=8,("sts %m0,%A1" CR_TAB
-                 "sts %m0+1,%B1" CR_TAB
-                 "sts %m0+2,%C1" CR_TAB
-                 "sts %m0+3,%D1");
+    {
+      if (io_address_operand (base, SImode))
+        {
+          return *l=4,("out %i0, %A1"  CR_TAB
+                       "out %i0+1,%B1" CR_TAB
+                       "out %i0+2,%C1" CR_TAB
+                       "out %i0+3,%D1");
+        }
+      else
+        {
+          *l = AVR_TINY ? 4 : 8;
+          return ("sts %m0,%A1"   CR_TAB
+                  "sts %m0+1,%B1" CR_TAB
+                  "sts %m0+2,%C1" CR_TAB
+                  "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)
@@ -3689,6 +4103,10 @@ out_movsi_mr_r (rtx_insn *insn, rtx op[], int *l)
   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)))
        {
@@ -3848,6 +4266,73 @@ output_movsisf (rtx_insn *insn, rtx operands[], int *l)
 
 /* Handle loads of 24-bit types from memory to register.  */
 
+static const char*
+avr_out_load_psi_reg_no_disp_tiny (rtx_insn *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);
+
+  if (reg_base == reg_dest)
+    {
+      return avr_asm_len (TINY_ADIW (%E1, %F1, 2)   CR_TAB
+                          "ld %C0,%1"               CR_TAB
+                          "ld __tmp_reg__,-%1"     CR_TAB
+                          TINY_SBIW (%E1, %F1, 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 (%E1, %F1, 2), op, plen, 2);
+        }
+      return "";
+    }
+}
+
+static const char*
+avr_out_load_psi_reg_disp_tiny (rtx_insn *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);
+
+  reg_base = true_regnum (XEXP (base, 0));
+  if (reg_base == reg_dest)
+    {
+      return avr_asm_len (TINY_ADIW (%I1, %J1, %o1+2) CR_TAB
+                          "ld %C0,%b1"                CR_TAB
+                          "ld __tmp_reg__,-%b1"       CR_TAB
+                          TINY_SBIW (%I1, %J1, 1)     CR_TAB
+                          "ld %A0,%b1"                CR_TAB
+                          "mov %B0,__tmp_reg__", op, plen, -8);
+   }
+  else
+    {
+      avr_asm_len (TINY_ADIW (%I1, %J1, %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 (%I1, %J1, %o1+2), op, plen, 2);
+      
+      return "";
+    }
+}
+
 static const char*
 avr_out_load_psi (rtx_insn *insn, rtx *op, int *plen)
 {
@@ -3859,6 +4344,9 @@ avr_out_load_psi (rtx_insn *insn, rtx *op, int *plen)
 
   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)
@@ -3901,6 +4389,9 @@ avr_out_load_psi (rtx_insn *insn, rtx *op, int *plen)
     {
       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)))
         {
           if (REGNO (XEXP (base, 0)) != REG_Y)
@@ -3969,14 +4460,94 @@ avr_out_load_psi (rtx_insn *insn, rtx *op, int *plen)
                         "ld %C0,%1", op, plen, -3);
 
   else if (CONSTANT_ADDRESS_P (base))
-    return avr_asm_len ("lds %A0,%m1" CR_TAB
-                        "lds %B0,%m1+1" CR_TAB
-                        "lds %C0,%m1+2", op, plen , -6);
+    {
+      int n_words = AVR_TINY ? 3 : 6;
+      return avr_asm_len ("lds %A0,%m1" CR_TAB
+                          "lds %B0,%m1+1" CR_TAB
+                          "lds %C0,%m1+2", op, plen , -n_words);
+    }
 
   fatal_insn ("unknown move insn:",insn);
   return "";
 }
 
+
+static const char*
+avr_out_store_psi_reg_no_disp_tiny (rtx_insn *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);
+
+  if (reg_base == reg_src)
+    {
+      avr_asm_len ("st %0,%A1"              CR_TAB
+                   "mov __tmp_reg__,%B1"    CR_TAB
+                   TINY_ADIW (%E0, %F0, 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 (%E0, %F0, 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 (%E0, %F0, 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);
+
+  if (reg_src == reg_base)
+    {
+      return avr_asm_len ("mov __tmp_reg__,%A1"          CR_TAB
+                          "mov __zero_reg__,%B1"         CR_TAB
+                          TINY_ADIW (%I0, %J0, %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 (%I0, %J0, %o0+2), op, plen, -10);
+    }
+  else if (reg_src == reg_base - 2)
+    {
+      return avr_asm_len ("mov __tmp_reg__,%C1"          CR_TAB  
+                          TINY_ADIW (%I0, %J0, %o0)      CR_TAB
+                          "st %b0+,%A1"                  CR_TAB
+                          "st %b0+,%B1"                  CR_TAB
+                          "st %b0,__tmp_reg__"           CR_TAB
+                          TINY_SBIW (%I0, %J0, %o0+2), op, plen, -8);
+    }
+
+  return avr_asm_len (TINY_ADIW (%I0, %J0, %o0)      CR_TAB
+                          "st %b0+,%A1"                  CR_TAB
+                          "st %b0+,%B1"                  CR_TAB
+                          "st %b0,%C1"                   CR_TAB
+                          TINY_SBIW (%I0, %J0, %o0+2), op, plen, -7);
+}
+
 /* Handle store of 24-bit type from register or zero to memory.  */
 
 static const char*
@@ -3988,12 +4559,18 @@ avr_out_store_psi (rtx_insn *insn, rtx *op, int *plen)
   int reg_base = true_regnum (base);
 
   if (CONSTANT_ADDRESS_P (base))
-    return avr_asm_len ("sts %m0,%A1"   CR_TAB
-                        "sts %m0+1,%B1" CR_TAB
-                        "sts %m0+2,%C1", op, plen, -6);
+    {
+      int n_words = AVR_TINY ? 3 : 6;
+      return avr_asm_len ("sts %m0,%A1"   CR_TAB
+                          "sts %m0+1,%B1" CR_TAB
+                          "sts %m0+2,%C1", op, plen, -n_words);
+    }
 
   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));
@@ -4015,6 +4592,10 @@ avr_out_store_psi (rtx_insn *insn, rtx *op, int *plen)
   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)))
@@ -4131,6 +4712,30 @@ avr_out_movpsi (rtx_insn *insn, rtx *op, int *plen)
   return "";
 }
 
+static const char*
+avr_out_movqi_mr_r_reg_disp_tiny (rtx_insn *insn, rtx op[], int *plen)
+{
+  rtx dest = op[0];
+  rtx src = op[1];
+  rtx x = XEXP (dest, 0);
+
+  if (reg_overlap_mentioned_p (src, XEXP (x, 0)))
+    {
+      avr_asm_len ("mov __tmp_reg__,%1"      CR_TAB
+                   TINY_ADIW (%I0, %J0, %o0) CR_TAB
+                   "st %b0,__tmp_reg__", op, plen, -4);
+    }
+    else
+    {
+      avr_asm_len (TINY_ADIW (%I0, %J0, %o0) CR_TAB
+          "st %b0,%1" , op, plen, -3);
+    }
+
+  if (!reg_unused_after (insn, XEXP (x,0)))
+      avr_asm_len (TINY_SBIW (%I0, %J0, %o0), op, plen, 2);
+
+  return "";
+}
 
 static const char*
 out_movqi_mr_r (rtx_insn *insn, rtx op[], int *plen)
@@ -4141,9 +4746,10 @@ out_movqi_mr_r (rtx_insn *insn, rtx op[], int *plen)
 
   if (CONSTANT_ADDRESS_P (x))
     {
+      int n_words = AVR_TINY ? 1 : 2;
       return optimize > 0 && io_address_operand (x, QImode)
         ? avr_asm_len ("out %i0,%1", op, plen, -1)
-        : avr_asm_len ("sts %m0,%1", op, plen, -2);
+        : avr_asm_len ("sts %m0,%1", op, plen, -n_words);
     }
   else if (GET_CODE (x) == PLUS
            && REG_P (XEXP (x, 0))
@@ -4153,6 +4759,9 @@ out_movqi_mr_r (rtx_insn *insn, rtx op[], int *plen)
 
       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)
@@ -4213,12 +4822,15 @@ avr_out_movhi_mr_r_xmega (rtx_insn *insn, rtx op[], int *plen)
   int mem_volatile_p = MEM_VOLATILE_P (dest);
 
   if (CONSTANT_ADDRESS_P (base))
-    return optimize > 0 && io_address_operand (base, HImode)
-      ? avr_asm_len ("out %i0,%A1" CR_TAB
-                     "out %i0+1,%B1", op, plen, -2)
+    {
+      int n_words = AVR_TINY ? 2 : 4;
+      return optimize > 0 && io_address_operand (base, HImode)
+        ? avr_asm_len ("out %i0,%A1" CR_TAB
+                       "out %i0+1,%B1", op, plen, -2)
 
-      : avr_asm_len ("sts %m0,%A1" CR_TAB
-                     "sts %m0+1,%B1", op, plen, -4);
+        : avr_asm_len ("sts %m0,%A1" CR_TAB
+                       "sts %m0+1,%B1", op, plen, -n_words);
+    }
 
   if (reg_base > 0)
     {
@@ -4307,6 +4919,70 @@ avr_out_movhi_mr_r_xmega (rtx_insn *insn, rtx op[], int *plen)
   return "";
 }
 
+static const char*
+avr_out_movhi_mr_r_reg_no_disp_tiny (rtx_insn *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);
+
+  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 (%E0, %F0, 1) CR_TAB
+                       "st %0,__tmp_reg__", op, plen, -5)
+        : avr_asm_len ("mov __tmp_reg__,%B1"   CR_TAB
+                       TINY_ADIW (%E0, %F0, 1) CR_TAB
+                       "st %0,__tmp_reg__"      CR_TAB
+                       TINY_SBIW (%E0, %F0, 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 (%E0, %F0, 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);
+
+  return reg_src == reg_base
+        ? avr_asm_len ("mov __tmp_reg__,%A1"          CR_TAB
+                       "mov __zero_reg__,%B1"         CR_TAB
+                       TINY_ADIW (%I0, %J0, %o0+1)    CR_TAB
+                       "st %b0,__zero_reg__"          CR_TAB
+                       "st -%b0,__tmp_reg__"          CR_TAB
+                       "clr __zero_reg__"             CR_TAB
+                       TINY_SBIW (%I0, %J0, %o0), op, plen, -9) 
+
+        : avr_asm_len (TINY_ADIW (%I0, %J0, %o0+1) CR_TAB
+                       "st %b0,%B1"                CR_TAB
+                       "st -%b0,%A1"               CR_TAB
+                       TINY_SBIW (%I0, %J0, %o0), op, plen, -6);
+}
+
+static const char*
+avr_out_movhi_mr_r_post_inc_tiny (rtx op[], int *plen)
+{
+  return avr_asm_len (TINY_ADIW (%I0, %J0, 1)  CR_TAB
+                      "st %p0,%B1"    CR_TAB
+                      "st -%p0,%A1"   CR_TAB
+                      TINY_ADIW (%I0, %J0, 2), op, plen, -6);
+}
 
 static const char*
 out_movhi_mr_r (rtx_insn *insn, rtx op[], int *plen)
@@ -4328,15 +5004,21 @@ out_movhi_mr_r (rtx_insn *insn, rtx op[], int *plen)
   mem_volatile_p = MEM_VOLATILE_P (dest);
 
   if (CONSTANT_ADDRESS_P (base))
-    return optimize > 0 && io_address_operand (base, HImode)
-      ? avr_asm_len ("out %i0+1,%B1" CR_TAB
-                     "out %i0,%A1", op, plen, -2)
+    {
+      int n_words = AVR_TINY ? 2 : 4;
+      return optimize > 0 && io_address_operand (base, HImode)
+        ? avr_asm_len ("out %i0+1,%B1" CR_TAB
+                       "out %i0,%A1", op, plen, -2)
 
-      : avr_asm_len ("sts %m0+1,%B1" CR_TAB
-                     "sts %m0,%A1", op, plen, -4);
+        : avr_asm_len ("sts %m0+1,%B1" CR_TAB
+                       "sts %m0,%A1", op, plen, -n_words);
+    }
 
   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);
@@ -4365,6 +5047,10 @@ out_movhi_mr_r (rtx_insn *insn, rtx op[], int *plen)
   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)))
         {
@@ -4414,6 +5100,9 @@ out_movhi_mr_r (rtx_insn *insn, rtx op[], int *plen)
         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
                        "st X,%B1"    CR_TAB
@@ -4596,7 +5285,11 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen)
               && (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;
             }
@@ -4606,7 +5299,9 @@ avr_out_compare (rtx_insn *insn, rtx *xop, int *plen)
               && 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);
             }
         }
 
@@ -8070,7 +8765,8 @@ avr_assemble_integer (rtx x, unsigned int size, int aligned_p)
 static bool
 avr_class_likely_spilled_p (reg_class_t c)
 {
-  return (c != ALL_REGS && c != ADDW_REGS);
+  return (c != ALL_REGS &&
+           (AVR_TINY ? 1 : c != ADDW_REGS));
 }
 
 
@@ -8343,7 +9039,9 @@ avr_nonconst_pointer_addrspace (tree typ)
 
       if (!ADDR_SPACE_GENERIC_P (as)
           && (!TYPE_READONLY (target)
-              || avr_addrspace[as].segment >= avr_n_flash))
+              || avr_addrspace[as].segment >= avr_n_flash
+             /* Also refuse __memx address space if we can't support it.  */
+             || (!AVR_HAVE_LPM && avr_addrspace[as].pointer_size > 2)))
         {
           return as;
         }
@@ -8465,6 +9163,12 @@ avr_insert_attributes (tree node, tree *attributes)
                  " beyond flash of %qs",
                  node, avr_addrspace[as].name, avr_current_device->name);
         }
+      else if (!AVR_HAVE_LPM && avr_addrspace[as].pointer_size > 2)
+       {
+          error ("variable %q+D located in address space %qs"
+                 " which is not supported by %qs",
+                 node, avr_addrspace[as].name, avr_current_arch->arch_name);
+       }
 
       if (!TYPE_READONLY (node0)
           && !TREE_READONLY (node))
@@ -8901,10 +9605,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);
 }
 
 
@@ -8951,6 +9655,18 @@ avr_adjust_reg_alloc_order (void)
       0, 1,
       32, 33, 34, 35
   };
+  static const int tiny_order_0[] = {
+    20, 21,
+    22, 23,
+    24, 25,
+    30, 31,
+    26, 27,
+    28, 29,
+    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, 22, 23, 24, 25,
@@ -8960,6 +9676,17 @@ avr_adjust_reg_alloc_order (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, 21, 20, 19, 18,
@@ -8970,9 +9697,14 @@ avr_adjust_reg_alloc_order (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_0 : order_2) :
+                                       (AVR_TINY ? tiny_order_0 : order_0));
+
   for (i = 0; i < ARRAY_SIZE (order_0); ++i)
       reg_alloc_order[i] = order[i];
 }
@@ -10657,7 +11389,7 @@ output_reload_in_const (rtx *op, rtx clobber_reg, int *len, bool clear_p)
         {
           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;
@@ -10859,6 +11591,49 @@ avr_output_addr_vec_elt (FILE *stream, int value)
     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]);
+  }
+}
 
 /* Implement `TARGET_HARD_REGNO_SCRATCH_OK'.  */
 /* Returns true if SCRATCH are safe to be allocated as a scratch
@@ -11013,13 +11788,20 @@ avr_asm_out_dtor (rtx symbol, int priority)
 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;
+  }
 }
 
 
@@ -12639,6 +13421,9 @@ avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *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
index de2bcd171c89899e0cb5b687905f4be870b0655f..ba31cd08fc576953b63b9a89a3a16908729f8884 100644 (file)
@@ -63,6 +63,7 @@ enum
 #define AVR_HAVE_JMP_CALL (avr_current_arch->have_jmp_call)
 #define AVR_HAVE_MUL (avr_current_arch->have_mul)
 #define AVR_HAVE_MOVW (avr_current_arch->have_movw_lpmx)
+#define AVR_HAVE_LPM (!AVR_TINY)
 #define AVR_HAVE_LPMX (avr_current_arch->have_movw_lpmx)
 #define AVR_HAVE_ELPM (avr_current_arch->have_elpm)
 #define AVR_HAVE_ELPMX (avr_current_arch->have_elpmx)
@@ -99,6 +100,7 @@ FIXME: DRIVER_SELF_SPECS has changed.
 #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
@@ -305,7 +307,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, STACK_POINTER_REGNUM},              \
index 3f3d6eb195c88f7d5712035f795e1019032c22c5..06e1cb0abe6bd71b81236be2045557e0f64821c9 100644 (file)
 ;;  B  Add 1 to REG number, MEM address or CONST_INT.
 ;;  C  Add 2.
 ;;  D  Add 3.
+;;  E  reg number in XEXP(x, 0).
+;;  F  Add 1 to reg number.
+;;  I  reg number in XEXP(XEXP(x, 0), 0).
+;;  J  Add 1 to reg number.
 ;;  j  Branch condition.
 ;;  k  Reverse branch condition.
 ;;..m..Constant Direct Data memory address.
    (ZERO_REGNO  1)      ; zero register r1
    ])
 
+(define_constants
+  [ (TMP_REGNO_TINY 16)  ; r16 is temp register for AVR_TINY
+    (ZERO_REGNO_TINY 17) ; r17 is zero register for AVR_TINY
+  ])
+
 (define_c_enum "unspec"
   [UNSPEC_STRLEN
    UNSPEC_MOVMEM
 ;; 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"))
 
               (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)))
 
 
         emit_insn (gen_load<mode>_libgcc (dest, src));
         DONE;
       }
+
+    /* AVRTC-579
+    if the source operand expression is out of range for 'lds' instruction
+      copy source operand expression to register
+    For tiny core, LDS instruction's memory access range limited to 0x40..0xbf
+    */
+    if (!tiny_valid_direct_memory_access_range(src,<MODE>mode))
+      {
+        rtx srcx = XEXP(src,0);
+        operands[1] = src = replace_equiv_address (src,copy_to_mode_reg (GET_MODE(srcx),srcx));
+        emit_move_insn(dest,src);
+        DONE;
+      }
+
+    /* AVRTC-579
+    if the destination operand expression is out of range for 'sts' instruction
+      copy destination operand expression to register
+    For tiny core, STS instruction's memory access range limited to 0x40..0xbf
+    */
+    if (!tiny_valid_direct_memory_access_range(dest,<MODE>mode))
+    {
+      rtx destx = XEXP(dest,0);
+      operands[0] = dest = replace_equiv_address (dest,copy_to_mode_reg (GET_MODE(destx),destx));
+      emit_move_insn(dest,src);
+      DONE;
+    }
+
   })
 
 ;;========================================================================
 (define_insn "mov<mode>_insn"
   [(set (match_operand:ALL1 0 "nonimmediate_operand" "=r    ,d    ,Qm   ,r ,q,r,*r")
         (match_operand:ALL1 1 "nox_general_operand"   "r Y00,n Ynn,r Y00,Qm,r,q,i"))]
-  "register_operand (operands[0], <MODE>mode)
-   || reg_or_0_operand (operands[1], <MODE>mode)"
+  "(register_operand (operands[0], <MODE>mode)
+   || reg_or_0_operand (operands[1], <MODE>mode)) &&
+   /* skip if operands are out of lds/sts memory access range(0x40..0xbf)
+   though access range is checked during define_expand, it is required
+   here to avoid merging rtls during combine pass */
+   tiny_valid_direct_memory_access_range(operands[0],QImode) &&
+   tiny_valid_direct_memory_access_range(operands[1],QImode)"
   {
     return output_movqi (insn, operands, NULL);
   }
 (define_insn "*mov<mode>"
   [(set (match_operand:ALL2 0 "nonimmediate_operand" "=r,r  ,r,m    ,d,*r,q,r")
         (match_operand:ALL2 1 "nox_general_operand"   "r,Y00,m,r Y00,i,i ,r,q"))]
-  "register_operand (operands[0], <MODE>mode)
-   || reg_or_0_operand (operands[1], <MODE>mode)"
+  "(register_operand (operands[0], <MODE>mode)
+   || reg_or_0_operand (operands[1], <MODE>mode)) &&
+   /* skip if operands are out of lds/sts memory access range(0x40..0xbf)
+   though access range is checked during define_expand, it is required
+   here to avoid merging rtls during combine pass */
+   tiny_valid_direct_memory_access_range(operands[0],HImode) &&
+   tiny_valid_direct_memory_access_range(operands[1],HImode)"
   {
     return output_movhi (insn, operands, NULL);
   }
 (define_insn "*mov<mode>"
   [(set (match_operand:ALL4 0 "nonimmediate_operand" "=r,r  ,r ,Qm   ,!d,r")
         (match_operand:ALL4 1 "nox_general_operand"   "r,Y00,Qm,r Y00,i ,i"))]
-  "register_operand (operands[0], <MODE>mode)
-   || reg_or_0_operand (operands[1], <MODE>mode)"
+  "(register_operand (operands[0], <MODE>mode)
+   || reg_or_0_operand (operands[1], <MODE>mode)) &&
+   /* skip if operands are out of lds/sts memory access range(0x40..0xbf)
+   though access range is checked during define_expand, it is required
+   here to avoid merging rtls during combine pass */
+   tiny_valid_direct_memory_access_range(operands[0],SImode) &&
+   tiny_valid_direct_memory_access_range(operands[1],SImode)"
   {
     return output_movsisf (insn, operands, NULL);
   }
 (define_insn "*movsf"
   [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,r ,Qm,!d,r")
         (match_operand:SF 1 "nox_general_operand"   "r,G,Qm,rG,F ,F"))]
-  "register_operand (operands[0], SFmode)
-   || reg_or_0_operand (operands[1], SFmode)"
+  "(register_operand (operands[0], SFmode)
+   || reg_or_0_operand (operands[1], SFmode)) &&
+   /* skip if operands are out of lds/sts memory access range(0x40..0xbf)
+   though access range is checked during define_expand, it is required
+   here to avoid merging rtls during combine pass */
+   tiny_valid_direct_memory_access_range(operands[0],SFmode) &&
+   tiny_valid_direct_memory_access_range(operands[1],SFmode)"
   {
     return output_movsisf (insn, operands, NULL);
   }
    (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"
index 9aee17bfda83b4b60814be40b4982d272f1a3a6c..89d0036fbddb69fe9c13999f186307857c50b121 100644 (file)
@@ -21,9 +21,9 @@
 # along with GCC; see the file COPYING3.  If not see
 # <http://www.gnu.org/licenses/>.
 
-MULTILIB_OPTIONS = march=avr2/march=avr25/march=avr3/march=avr31/march=avr35/march=avr4/march=avr5/march=avr51/march=avr6/march=avrxmega2/march=avrxmega4/march=avrxmega5/march=avrxmega6/march=avrxmega7 msp8
+MULTILIB_OPTIONS = march=avr2/march=avr25/march=avr3/march=avr31/march=avr35/march=avr4/march=avr5/march=avr51/march=avr6/march=avrxmega2/march=avrxmega4/march=avrxmega5/march=avrxmega6/march=avrxmega7/march=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 = \
        march=avr3/msp8 \
@@ -37,4 +37,5 @@ MULTILIB_EXCEPTIONS = \
        march=avrxmega4/msp8 \
        march=avrxmega5/msp8 \
        march=avrxmega6/msp8 \
-       march=avrxmega7/msp8
+       march=avrxmega7/msp8 \
+       march=avrtiny/msp8
index e3701503e98bac1efc91e8ce840b7ca528832888..468dda0133cd3e388a89dcad4ee377269803a5d2 100644 (file)
 ``XMEGA'' devices with more than 128@tie{}KiB of program memory and more than 64@tie{}KiB of RAM.
 @*@var{mcu}@tie{}= @code{atxmega128a1}, @code{atxmega128a1u}, @code{atxmega128a4u}.
 
+@item avrtiny
+``TINY'' Tiny core devices with 512@tie{}B up to 4@tie{}KiB of program memory.
+@*@var{mcu}@tie{}= @code{attiny10}, @code{attiny20}, @code{attiny4}, @code{attiny40}, @code{attiny5}, @code{attiny9}.
+
 @item avr1
 This ISA is implemented by the minimal AVR core and supported for assembler only.
 @*@var{mcu}@tie{}= @code{attiny11}, @code{attiny12}, @code{attiny15}, @code{attiny28}, @code{at90s1200}.
index 04affb7c2a555d24e26fbc32a62b384fac05e87c..7db3ce4e5b06fcdddaece0ec91c6bca8eab1a110 100644 (file)
@@ -1,3 +1,9 @@
+2014-10-21  Joern Rennecke  <joern.rennecke@embecosm.com>
+
+       * gcc.target/avr/tiny-memx.c: New test.
+
+       * gcc.target/avr/tiny-caller-save.c: New test.
+
 2014-10-21  Jiong Wang  <jiong.wang@arm.com>
 
        * gcc.target/arm/20031108-1.c (Proc_7): Add explicit declaration.
diff --git a/gcc/testsuite/gcc.target/avr/tiny-caller-save.c b/gcc/testsuite/gcc.target/avr/tiny-caller-save.c
new file mode 100644 (file)
index 0000000..0e46ee0
--- /dev/null
@@ -0,0 +1,78 @@
+/* { dg-do compile } */
+/* { dg-options "-march=avrtiny -gdwarf -Os" } */
+
+/* This is a stripped down piece of libgcc2.c that triggerd an ICE for avr with
+   "-march=avrtiny -g -Os"; replace_reg_with_saved_mem would generate:
+   (concatn:SI [
+                    (reg:SI 18 r18)
+                    (reg:SI 19 r19)
+                    (mem/c:QI (plus:HI (reg/f:HI 28 r28)
+                            (const_int 43 [0x2b])) [6  S1 A8])
+                    (mem/c:QI (plus:HI (reg/f:HI 28 r28)
+                            (const_int 44 [0x2c])) [6  S1 A8])
+                ]) */
+
+typedef int SItype __attribute__ ((mode (SI)));
+typedef unsigned int USItype __attribute__ ((mode (SI)));
+typedef int DItype __attribute__ ((mode (DI)));
+typedef unsigned int UDItype __attribute__ ((mode (DI)));
+struct DWstruct
+{
+  SItype low, high;
+};
+typedef union
+{
+  struct DWstruct s;
+  DItype ll;
+} DWunion;
+
+UDItype
+__udivmoddi4 (UDItype n, UDItype d)
+{
+  const DWunion nn = {.ll = n };
+  const DWunion dd = {.ll = d };
+  USItype d0, d1, n2;
+  USItype q0;
+
+  d0 = dd.s.low;
+  d1 = dd.s.high;
+  n2 = nn.s.high;
+
+      USItype m0;
+
+      do
+       {
+         USItype __d1, __d0, __q1, __q0;
+         USItype __r1, __m;
+         __d1 = ((USItype) (d1) >> 16);
+         __d0 = ((USItype) (d1) & (((USItype) 1 << 16) - 1));
+         __r1 = (n2) % __d1;
+         __q1 = (n2) / __d1;
+         __m = (USItype) __q1 *__d0;
+         __r1 -= __m;
+         __q0 = __r1 / __d1;
+         (q0) = (USItype) __q1 *((USItype) 1 << 16) | __q0;
+       }
+      while (0);
+      do
+       {
+         USItype __x0, __x1, __x2;
+         USItype __ul, __vl, __uh, __vh;
+         __ul = ((USItype) (q0) & (((USItype) 1 << 16) - 1));
+         __uh = ((USItype) (q0) >> 16);
+         __vl = ((USItype) (d0) & (((USItype) 1 << 16) - 1));
+         __vh = ((USItype) (d0) >> 16);
+         __x0 = (USItype) __ul *__vl;
+         __x1 = (USItype) __ul *__vh;
+         __x2 = (USItype) __uh *__vl;
+         __x1 += ((USItype) (__x0) >> 16);
+         __x1 += __x2;
+         (m0) =
+           ((USItype) (__x1) & (((USItype) 1 << 16) - 1)) *
+           ((USItype) 1 << 16) +
+           ((USItype) (__x0) & (((USItype) 1 << 16) - 1));
+       }
+      while (0);
+
+return m0;
+}
diff --git a/gcc/testsuite/gcc.target/avr/tiny-memx.c b/gcc/testsuite/gcc.target/avr/tiny-memx.c
new file mode 100644 (file)
index 0000000..3ad164d
--- /dev/null
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-march=avrtiny" } */
+
+const __memx char ascmonth[] = "Jan"; /* { dg-error "not supported" } */
index 7364f93780f323e2964d9832265127e0e5f84333..a87aa3354cf881c4d91a5216f3f79309c93e263e 100644 (file)
@@ -1,3 +1,38 @@
+2014-10-21  Joern Rennecke  <joern.rennecke@embecosm.com>
+           Vidya Praveen <vidya.praveen@atmel.com>
+           Praveen Kumar Kaushik <Praveen_Kumar.Kaushik@atmel.com>
+           Senthil Kumar Selvaraj <Senthil_Kumar.Selvaraj@atmel.com>
+           Pitchumani Sivanupandi <Pitchumani.S@atmel.com>
+
+       * config/avr/lib1funcs.S (__do_global_dtors): Go back to descending
+       order.
+
+       Updated library functions for AVRTINY arch.
+       * config/avr/lib1funcs.S: Updated zero/tmp regs for AVRTINY.
+       Replaced occurrences of r0/r1 with tmp/zero reg macros.
+       Added wsubi/ wadi macros that expands conditionally as sbiw/ adiw
+       or AVRTINY equivalent. Replaced occurrences of sbiw/adiw with
+       wsubi/wadi macors.
+       (__mulsi3_helper): Update stack, preserve callee saved regs and
+       argument from stack. Restore callee save registers.
+       (__mulpsi3): Likewise.
+       (__muldi3, __udivmodsi4, __divmodsi4, __negsi2, __umoddi3, __udivmod64,
+       __moddi3, __adddi3, __adddi3_s8, __subdi3, __cmpdi2, __cmpdi2_s8,
+       __negdi2, __prologue_saves__, __epilogue_restores__): Excluded for 
+       AVRTINY.
+       (__tablejump2__): Added lpm equivalent instructions for AVRTINY.
+       (__do_copy_data): Added new definition for AVRTINY.
+       (__do_clear_bss): Replace r17 by r18 to preserve zero reg for AVRTINY.
+       (__load_3, __load_4, __xload_1, __xload_2, __xload_3,
+       __xload_4, __movmemx_qi, __movmemx_hi): Excluded for AVRTINY.
+       * config/avr/lib1funcs-fixed.S: Replaced occurrences of r0/r1 with
+       tmp/zero reg macros. Replaced occurrences of sbiw/adiw with wsubi/wadi
+       macors.
+          * config/avr/t-avr (LIB1ASMFUNCS): Remove unsupported functions for
+       AVRTINY.
+
+       Fix broken long multiplication on tiny arch.         
+
 2014-10-09  Joseph Myers  <joseph@codesourcery.com>
 
        * soft-fp/double.h: Update from glibc.
index 8f3ed92010d94444cc55fd647cd50c453ca72aef..ae4dcf0fe8a002bc5373f8a129b063db1424ce77 100644 (file)
 ;; Fixed point library routines for AVR
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
+#if defined __AVR_TINY__
+#define __zero_reg__ r17
+#define __tmp_reg__ r16
+#else                                                                                                                                              
+#define __zero_reg__ r1
+#define __tmp_reg__ r0
+#endif
+
 .section .text.libgcc.fixed, "ax", @progbits
 
+#ifndef __AVR_TINY__
+
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Conversions to float
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1913,3 +1923,5 @@ DEFUN __ret
     ret
 ENDF  __ret
 #endif /* L_ret */
+
+#endif /* if not __AVR_TINY__ */
index 080e250cd616318549388ac24e2a0a9a18bcac80..0205d833ecb36972196aa7533e5517ae849ef607 100644 (file)
@@ -21,8 +21,13 @@ a copy of the GCC Runtime Library Exception along with this program;
 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 <http://www.gnu.org/licenses/>.  */
 
+#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
@@ -126,6 +131,24 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 
 ;; Support function entry and exit for convenience
 
+.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 waddi r_arg1, i_arg2
+#if defined (__AVR_TINY__)
+    subi \r_arg1,   lo8(-\i_arg2)
+    sbci \r_arg1+1, hi8(-\i_arg2)
+#else
+    adiw \r_arg1, \i_arg2
+#endif
+.endm
+
 .macro DEFUN name
 .global \name
 .func \name
@@ -146,7 +169,11 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 .endm
 
 ;; Skip next instruction, typically a jump target
+#if defined(__AVR_TINY__)
 #define skip cpse 0,0
+#else
+#define skip cpse 16,16
+#endif
 
 ;; Negate a 2-byte value held in consecutive registers
 .macro NEG2  reg
@@ -219,16 +246,16 @@ ENDF __mulqi3
     Multiplication  16 x 16  without MUL
 *******************************************************/
 
-#define A0  r22
-#define A1  r23
-#define B0  r24
-#define BB0 r20
-#define B1  r25
+#define A0  22
+#define A1  23
+#define B0  24
+#define BB0 20
+#define B1  25
 ;; Output overlaps input, thus expand result in CC0/1
-#define C0  r24
-#define C1  r25
+#define C0  24
+#define C1  25
 #define CC0  __tmp_reg__
-#define CC1  R21
+#define CC1  21
 
 #if defined (L_umulqihi3)
 ;;; R25:R24 = (unsigned int) R22 * (unsigned int) R24
@@ -294,7 +321,7 @@ DEFUN __mulhi3
     rol     B1
 3:
     ;; If B == 0 we are ready
-    sbiw    B0, 0
+    wsubi   B0, 0
     breq 9f
 
     ;; Carry = n-th bit of A
@@ -402,6 +429,18 @@ ENDF __mulhisi3
 
 #if defined (L_mulsi3)
 DEFUN __mulsi3
+#if defined (__AVR_TINY__)
+    in     r26, __SP_L__ ; safe to use X, as it is CC0/CC1
+    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+
+    ld     B3, X
+#endif
     ;; Clear result
     clr     CC2
     clr     CC3
@@ -427,12 +466,17 @@ DEFUN __mulsi3_helper
     ;; Only continue if  A != 0
     sbci    A1, 0
     brne 2b
-    sbiw    A2, 0
+    wsubi   A2, 0
     brne 2b
 
     ;; All bits of A are consumed:  Copy result to return register C
     wmov    C0, CC0
     wmov    C2, CC2
+#if defined (__AVR_TINY__)
+    pop     B1      ; restore callee saved regs
+    pop     B0 
+#endif  /* defined (__AVR_TINY__) */
+
     ret
 ENDF __mulsi3_helper
 #endif /* L_mulsi3 */
@@ -682,9 +726,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
 
@@ -692,6 +739,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__
@@ -718,6 +776,10 @@ DEFUN __mulpsi3
     mov     A2, C2
 
     clr     __zero_reg__
+#if defined (__AVR_TINY__)
+    pop B1
+    pop B0
+#endif /* (__AVR_TINY__) */
     ret
 ENDF __mulpsi3
 
@@ -809,8 +871,8 @@ ENDF __mulsqipsi3
 #define B6  B0+6
 #define B7  B0+7
 
+#ifndef __AVR_TINY__
 #if defined (__AVR_HAVE_MUL__)
-
 ;; Define C[] for convenience
 ;; Notice that parts of C[] overlap A[] respective B[]
 #define C0  16
@@ -1012,6 +1074,7 @@ ENDF __muldi3
 
 #endif /* L_muldi3 */
 #endif /* HAVE_MUL */
+#endif /* if not __AVR_TINY__ */
 
 #undef B7
 #undef B6
@@ -1169,7 +1232,7 @@ ENDF __mulsidi3
 /**********************************************************
     Widening Multiplication 64 = 32 x 32  without  MUL
 **********************************************************/
-
+#ifndef __AVR_TINY__ /* if not __AVR_TINY__ */
 #if defined (L_mulsidi3) && !defined (__AVR_HAVE_MUL__)
 #define A0 18
 #define A1 A0+1
@@ -1265,7 +1328,7 @@ ENDF __umulsidi3
 #undef BB3
 #undef Mask
 #endif /* L_mulsidi3 && !HAVE_MUL */
-
+#endif /* if not __AVR_TINY__ */
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        
 \f
@@ -1437,7 +1500,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
 
@@ -1672,6 +1735,10 @@ ENDF __negsi2
 #undef r_arg2L
 #undef r_cnt
 
+/* *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
@@ -2087,12 +2154,15 @@ ENDF __negdi2
 #undef A1
 #undef A0
 
+#endif /* !defined (__AVR_TINY__) */
+
 \f
 .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
@@ -2194,6 +2264,7 @@ DEFUN __epilogue_restores__
        ret
 ENDF __epilogue_restores__
 #endif /* defined (L_epilogue) */
+#endif /* !defined (__AVR_TINY__) */
 
 #ifdef L_exit
        .section .fini9,"ax",@progbits
@@ -2259,6 +2330,12 @@ DEFUN __tablejump2__
     lpm     r31, Z
     mov     r30, __tmp_reg__
     ijmp
+#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
     lpm
     push    r0
@@ -2270,6 +2347,26 @@ DEFUN __tablejump2__
 ENDF __tablejump2__
 #endif /* L_tablejump2 */
 
+#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
@@ -2335,13 +2432,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
@@ -2349,7 +2447,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 */
@@ -2357,10 +2455,16 @@ ENDF __do_clear_bss
 /* __do_global_ctors and __do_global_dtors are only necessary
    if there are any constructors/destructors.  */
 
+#if defined(__AVR_TINY__)
+#define cdtors_tst_reg r18
+#else
+#define cdtors_tst_reg r17
+#endif
+
 #ifdef L_ctors
        .section .init6,"ax",@progbits
 DEFUN __do_global_ctors
-    ldi     r17, pm_hi8(__ctors_start)
+    ldi     cdtors_tst_reg, pm_hi8(__ctors_start)
     ldi     r28, pm_lo8(__ctors_end)
     ldi     r29, pm_hi8(__ctors_end)
 #ifdef __AVR_HAVE_EIJMP_EICALL__
@@ -2368,7 +2472,7 @@ DEFUN __do_global_ctors
 #endif /* HAVE_EIJMP */
     rjmp    .L__do_global_ctors_start
 .L__do_global_ctors_loop:
-    sbiw    r28, 1
+    wsubi   28, 1
 #ifdef __AVR_HAVE_EIJMP_EICALL__
     sbc     r16, __zero_reg__
     mov     r24, r16
@@ -2378,7 +2482,7 @@ DEFUN __do_global_ctors
     XCALL   __tablejump2__
 .L__do_global_ctors_start:
     cpi     r28, pm_lo8(__ctors_start)
-    cpc     r29, r17
+    cpc     r29, cdtors_tst_reg
 #ifdef __AVR_HAVE_EIJMP_EICALL__
     ldi     r24, pm_hh8(__ctors_start)
     cpc     r16, r24
@@ -2390,27 +2494,27 @@ ENDF __do_global_ctors
 #ifdef L_dtors
        .section .fini6,"ax",@progbits
 DEFUN __do_global_dtors
-    ldi     r17, pm_hi8(__dtors_start)
-    ldi     r28, pm_lo8(__dtors_end)
-    ldi     r29, pm_hi8(__dtors_end)
+    ldi     cdtors_tst_reg, pm_hi8(__dtors_end)
+    ldi     r28, pm_lo8(__dtors_start)
+    ldi     r29, pm_hi8(__dtors_start)
 #ifdef __AVR_HAVE_EIJMP_EICALL__
-    ldi     r16, pm_hh8(__dtors_end)
+    ldi     r16, pm_hh8(__dtors_start)
 #endif /* HAVE_EIJMP */
     rjmp    .L__do_global_dtors_start
 .L__do_global_dtors_loop:
-    sbiw    r28, 1
+    waddi   28, 1
 #ifdef __AVR_HAVE_EIJMP_EICALL__
-    sbc     r16, __zero_reg__
+    adc     r16, __zero_reg__
     mov     r24, r16
 #endif /* HAVE_EIJMP */
     mov_h   r31, r29
     mov_l   r30, r28
     XCALL   __tablejump2__
 .L__do_global_dtors_start:
-    cpi     r28, pm_lo8(__dtors_start)
-    cpc     r29, r17
+    cpi     r28, pm_lo8(__dtors_end)
+    cpc     r29, cdtors_tst_reg
 #ifdef __AVR_HAVE_EIJMP_EICALL__
-    ldi     r24, pm_hh8(__dtors_start)
+    ldi     r24, pm_hh8(__dtors_end)
     cpc     r16, r24
 #endif /* HAVE_EIJMP */
     brne    .L__do_global_dtors_loop
@@ -2419,6 +2523,7 @@ ENDF __do_global_dtors
 
 .section .text.libgcc, "ax", @progbits
 
+#if !defined (__AVR_TINY__)
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Loading n bytes from Flash; n = 3,4
 ;; R22... = Flash[Z]
@@ -2464,7 +2569,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
@@ -2590,7 +2697,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
@@ -2662,6 +2771,7 @@ ENDF __movmemx_hi
 #undef LOOP
 
 #endif /* L_movmemx */
+#endif /* !defined (__AVR_TINY__) */ 
 
 \f
 .section .text.libgcc.builtins, "ax", @progbits
index 1f7356968aacb4993b33882ee13a2c914a34d553..c420c5d8fb98da89002b5145a32e056b3135cfc4 100644 (file)
@@ -3,12 +3,7 @@ LIB1ASMFUNCS = \
        _mulqi3 \
        _mulhi3 \
        _mulqihi3 _umulqihi3 \
-       _mulpsi3 _mulsqipsi3 \
-       _mulhisi3 \
-       _umulhisi3 \
-       _usmulhisi3 \
-       _muluhisi3 \
-       _mulshisi3 \
+       _mulpsi3 \
        _mulsi3 \
        _udivmodqi4 \
        _divmodqi4 \
@@ -17,19 +12,10 @@ LIB1ASMFUNCS = \
        _divmodpsi4 _udivmodpsi4 \
        _udivmodsi4 \
        _divmodsi4 \
-       _divdi3 _udivdi3 \
-       _muldi3 _muldi3_6 \
-       _mulsidi3 _umulsidi3 \
-       _udivmod64 \
-       _negsi2 _negdi2 \
-       _prologue \
-       _epilogue \
+       _negsi2 \
        _exit \
        _cleanup \
        _tablejump2 \
-       _load_3 _load_4 \
-       _xload_1 _xload_2 _xload_3 _xload_4 \
-       _movmemx \
        _copy_data \
        _clear_bss \
        _ctors \
@@ -39,24 +25,54 @@ 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
+# _load ad _xload variations - expect lpm and elpm support
+# _movmemx - expects elpm/lpm
+
+ifneq ($(MULTIFLAGS),-mmcu=avrtiny)
+LIB1ASMFUNCS += \
+    _mulsqipsi3 \
+       _mulhisi3 \
+       _umulhisi3 \
+       _usmulhisi3 \
+       _muluhisi3 \
+       _mulshisi3 \
+    _muldi3 _muldi3_6 \
+    _mulsidi3 _umulsidi3 \
+       _divdi3 _udivdi3 \
+       _udivmod64 \
+       _negdi2 \
+       _prologue \
+       _epilogue \
+       _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
 
 # Fixed point routines in avr/lib1funcs-fixed.S
+ifneq ($(MULTIFLAGS),-mmcu=avrtiny)
 LIB1ASMFUNCS += \
        _fractqqsf _fractuqqsf \
        _fracthqsf _fractuhqsf _fracthasf _fractuhasf \
@@ -87,8 +103,8 @@ LIB1ASMFUNCS += \
        _round_x8 \
        _rounddq3 _roundudq3 \
        _roundda3 _rounduda3 \
-       _roundta3 _rounduta3 \
-
+       _roundta3 _rounduta3
+endif
 
 LIB2FUNCS_EXCLUDE = \
        _moddi3 _umoddi3 \