/* -*- Mode: Asm -*- */
-/* Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+/* Copyright (C) 1998, 1999, 2000, 2007, 2008, 2009
+ Free Software Foundation, Inc.
Contributed by Denis Chertykov <denisc@overta.ru>
This file is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
-Free Software Foundation; either version 2, or (at your option) any
+Free Software Foundation; either version 3, or (at your option) any
later version.
-In addition to the permissions in the GNU General Public License, the
-Free Software Foundation gives you unlimited permission to link the
-compiled version of this file into combinations with other programs,
-and to distribute those combinations without any restriction coming
-from the use of this file. (The General Public License restrictions
-do apply in other respects; for example, they cover modification of
-the file, and distribution when not linked into a combine
-executable.)
-
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
-You should have received a copy of the GNU General Public License
-along with this program; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+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/>. */
#define __zero_reg__ r1
#define __tmp_reg__ r0
#define __SREG__ 0x3f
#define __SP_H__ 0x3e
#define __SP_L__ 0x3d
+#define __RAMPZ__ 0x3B
/* Most of the functions here are called directly from avr.md
patterns, instead of using the standard libcall mechanisms.
.section .text.libgcc, "ax", @progbits
.macro mov_l r_dest, r_src
-#if defined (__AVR_ENHANCED__)
+#if defined (__AVR_HAVE_MOVW__)
movw \r_dest, \r_src
#else
mov \r_dest, \r_src
.endm
.macro mov_h r_dest, r_src
-#if defined (__AVR_ENHANCED__)
+#if defined (__AVR_HAVE_MOVW__)
; empty
#else
mov \r_dest, \r_src
.endm
/* Note: mulqi3, mulhi3 are open-coded on the enhanced core. */
-#if !defined (__AVR_ENHANCED__)
+#if !defined (__AVR_HAVE_MUL__)
/*******************************************************
Multiplication 8 x 8
*******************************************************/
.endfunc
#endif /* defined (L_mulhi3) */
-#endif /* !defined (__AVR_ENHANCED__) */
+#endif /* !defined (__AVR_HAVE_MUL__) */
#if defined (L_mulhisi3)
.global __mulhisi3
.global __mulsi3
.func __mulsi3
__mulsi3:
-#if defined (__AVR_ENHANCED__)
+#if defined (__AVR_HAVE_MUL__)
mul r_arg1L, r_arg2L
movw r_resL, r0
mul r_arg1H, r_arg2H
cpc r_arg1H,r_arg1L
brne __mulsi3_loop ; exit if multiplier = 0
__mulsi3_exit:
- mov r_arg1HH,r_resHH ; result to return register
- mov r_arg1HL,r_resHL
- mov r_arg1H,r_resH
- mov r_arg1L,r_resL
+ mov_h r_arg1HH,r_resHH ; result to return register
+ mov_l r_arg1HL,r_resHL
+ mov_h r_arg1H,r_resH
+ mov_l r_arg1L,r_resL
ret
-#endif /* !defined (__AVR_ENHANCED__) */
+#endif /* defined (__AVR_HAVE_MUL__) */
#undef r_arg1L
#undef r_arg1H
#undef r_arg1HL
out __SP_H__,r29
out __SREG__,__tmp_reg__
out __SP_L__,r28
+#if defined (__AVR_HAVE_EIJMP_EICALL__)
+ eijmp
+#else
ijmp
+#endif
+
.endfunc
#endif /* defined (L_prologue) */
#endif /* defined (L_epilogue) */
#ifdef L_exit
- .weak _exit
+ .section .fini9,"ax",@progbits
+ .global _exit
.func _exit
_exit:
- rjmp _exit
-.endfunc
+ .weak exit
+exit:
+
+ /* Code from .fini8 ... .fini1 sections inserted by ld script. */
+
+ .section .fini0,"ax",@progbits
+ cli
+__stop_program:
+ rjmp __stop_program
+ .endfunc
#endif /* defined (L_exit) */
#ifdef L_cleanup
__tablejump2__:
lsl r30
rol r31
-#if defined (__AVR_ENHANCED__)
+ .global __tablejump__
+__tablejump__:
+#if defined (__AVR_HAVE_LPMX__)
lpm __tmp_reg__, Z+
lpm r31, Z
mov r30, __tmp_reg__
+
+#if defined (__AVR_HAVE_EIJMP_EICALL__)
+ eijmp
+#else
ijmp
+#endif
+
#else
lpm
+ adiw r30, 1
push r0
- inc r30 ; table is word aligned, no carry to high byte
lpm
push r0
+#if defined (__AVR_HAVE_EIJMP_EICALL__)
+ push __zero_reg__
+#endif
ret
#endif
-.endfunc
+ .endfunc
#endif /* defined (L_tablejump) */
+#ifdef L_copy_data
+ .section .init4,"ax",@progbits
+ .global __do_copy_data
+__do_copy_data:
+#if defined(__AVR_HAVE_ELPMX__)
+ ldi r17, hi8(__data_end)
+ ldi r26, lo8(__data_start)
+ ldi r27, hi8(__data_start)
+ ldi r30, lo8(__data_load_start)
+ ldi r31, hi8(__data_load_start)
+ ldi r16, hh8(__data_load_start)
+ out __RAMPZ__, r16
+ rjmp .L__do_copy_data_start
+.L__do_copy_data_loop:
+ elpm r0, Z+
+ st X+, r0
+.L__do_copy_data_start:
+ cpi r26, lo8(__data_end)
+ cpc r27, r17
+ brne .L__do_copy_data_loop
+#elif !defined(__AVR_HAVE_ELPMX__) && defined(__AVR_HAVE_ELPM__)
+ ldi r17, hi8(__data_end)
+ ldi r26, lo8(__data_start)
+ ldi r27, hi8(__data_start)
+ ldi r30, lo8(__data_load_start)
+ ldi r31, hi8(__data_load_start)
+ ldi r16, hh8(__data_load_start - 0x10000)
+.L__do_copy_data_carry:
+ inc r16
+ out __RAMPZ__, r16
+ rjmp .L__do_copy_data_start
+.L__do_copy_data_loop:
+ elpm
+ st X+, r0
+ adiw r30, 1
+ brcs .L__do_copy_data_carry
+.L__do_copy_data_start:
+ cpi r26, lo8(__data_end)
+ cpc r27, r17
+ brne .L__do_copy_data_loop
+#elif !defined(__AVR_HAVE_ELPMX__) && !defined(__AVR_HAVE_ELPM__)
+ ldi r17, hi8(__data_end)
+ ldi r26, lo8(__data_start)
+ ldi r27, hi8(__data_start)
+ ldi r30, lo8(__data_load_start)
+ ldi r31, hi8(__data_load_start)
+ rjmp .L__do_copy_data_start
+.L__do_copy_data_loop:
+#if defined (__AVR_HAVE_LPMX__)
+ lpm r0, Z+
+#else
+ lpm
+ adiw r30, 1
+#endif
+ st X+, r0
+.L__do_copy_data_start:
+ cpi r26, lo8(__data_end)
+ cpc r27, r17
+ brne .L__do_copy_data_loop
+#endif /* !defined(__AVR_HAVE_ELPMX__) && !defined(__AVR_HAVE_ELPM__) */
+#endif /* L_copy_data */
+
+/* __do_clear_bss is only necessary if there is anything in .bss section. */
+
+#ifdef L_clear_bss
+ .section .init4,"ax",@progbits
+ .global __do_clear_bss
+__do_clear_bss:
+ ldi r17, hi8(__bss_end)
+ ldi r26, lo8(__bss_start)
+ ldi r27, hi8(__bss_start)
+ rjmp .do_clear_bss_start
+.do_clear_bss_loop:
+ st X+, __zero_reg__
+.do_clear_bss_start:
+ cpi r26, lo8(__bss_end)
+ cpc r27, r17
+ brne .do_clear_bss_loop
+#endif /* L_clear_bss */
+
+/* __do_global_ctors and __do_global_dtors are only necessary
+ if there are any constructors/destructors. */
+
+#if defined (__AVR_HAVE_JMP_CALL__)
+#define XCALL call
+#else
+#define XCALL rcall
+#endif
+
+#ifdef L_ctors
+ .section .init6,"ax",@progbits
+ .global __do_global_ctors
+#if defined(__AVR_HAVE_RAMPZ__)
+__do_global_ctors:
+ ldi r17, hi8(__ctors_start)
+ ldi r16, hh8(__ctors_start)
+ ldi r28, lo8(__ctors_end)
+ ldi r29, hi8(__ctors_end)
+ ldi r20, hh8(__ctors_end)
+ rjmp .L__do_global_ctors_start
+.L__do_global_ctors_loop:
+ sbiw r28, 2
+ sbc r20, __zero_reg__
+ mov_h r31, r29
+ mov_l r30, r28
+ out __RAMPZ__, r20
+ XCALL __tablejump_elpm__
+.L__do_global_ctors_start:
+ cpi r28, lo8(__ctors_start)
+ cpc r29, r17
+ cpc r20, r16
+ brne .L__do_global_ctors_loop
+#else
+__do_global_ctors:
+ ldi r17, hi8(__ctors_start)
+ ldi r28, lo8(__ctors_end)
+ ldi r29, hi8(__ctors_end)
+ rjmp .L__do_global_ctors_start
+.L__do_global_ctors_loop:
+ sbiw r28, 2
+ mov_h r31, r29
+ mov_l r30, r28
+ XCALL __tablejump__
+.L__do_global_ctors_start:
+ cpi r28, lo8(__ctors_start)
+ cpc r29, r17
+ brne .L__do_global_ctors_loop
+#endif /* defined(__AVR_HAVE_RAMPZ__) */
+#endif /* L_ctors */
+
+#ifdef L_dtors
+ .section .fini6,"ax",@progbits
+ .global __do_global_dtors
+#if defined(__AVR_HAVE_RAMPZ__)
+__do_global_dtors:
+ ldi r17, hi8(__dtors_end)
+ ldi r16, hh8(__dtors_end)
+ ldi r28, lo8(__dtors_start)
+ ldi r29, hi8(__dtors_start)
+ ldi r20, hh8(__dtors_start)
+ rjmp .L__do_global_dtors_start
+.L__do_global_dtors_loop:
+ sbiw r28, 2
+ sbc r20, __zero_reg__
+ mov_h r31, r29
+ mov_l r30, r28
+ out __RAMPZ__, r20
+ XCALL __tablejump_elpm__
+.L__do_global_dtors_start:
+ cpi r28, lo8(__dtors_end)
+ cpc r29, r17
+ cpc r20, r16
+ brne .L__do_global_dtors_loop
+#else
+__do_global_dtors:
+ ldi r17, hi8(__dtors_end)
+ ldi r28, lo8(__dtors_start)
+ ldi r29, hi8(__dtors_start)
+ rjmp .L__do_global_dtors_start
+.L__do_global_dtors_loop:
+ mov_h r31, r29
+ mov_l r30, r28
+ XCALL __tablejump__
+ adiw r28, 2
+.L__do_global_dtors_start:
+ cpi r28, lo8(__dtors_end)
+ cpc r29, r17
+ brne .L__do_global_dtors_loop
+#endif /* defined(__AVR_HAVE_RAMPZ__) */
+#endif /* L_dtors */
+
+#ifdef L_tablejump_elpm
+ .global __tablejump_elpm__
+ .func __tablejump_elpm__
+__tablejump_elpm__:
+#if defined (__AVR_HAVE_ELPM__)
+#if defined (__AVR_HAVE_LPMX__)
+ elpm __tmp_reg__, Z+
+ elpm r31, Z
+ mov r30, __tmp_reg__
+#if defined (__AVR_HAVE_EIJMP_EICALL__)
+ eijmp
+#else
+ ijmp
+#endif
+
+#else
+ elpm
+ adiw r30, 1
+ push r0
+ elpm
+ push r0
+#if defined (__AVR_HAVE_EIJMP_EICALL__)
+ push __zero_reg__
+#endif
+ ret
+#endif
+#endif /* defined (__AVR_HAVE_ELPM__) */
+ .endfunc
+#endif /* defined (L_tablejump_elpm) */
+