OSDN Git Service

* config/avr/avr.c (avr_mcu_t): Add atmega32u4.
[pf3gnuchains/gcc-fork.git] / gcc / config / avr / libgcc.S
1 /*  -*- Mode: Asm -*-  */
2 /* Copyright (C) 1998, 1999, 2000, 2007, 2008 
3    Free Software Foundation, Inc.
4    Contributed by Denis Chertykov <denisc@overta.ru>
5
6 This file is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 In addition to the permissions in the GNU General Public License, the
12 Free Software Foundation gives you unlimited permission to link the
13 compiled version of this file into combinations with other programs,
14 and to distribute those combinations without any restriction coming
15 from the use of this file.  (The General Public License restrictions
16 do apply in other respects; for example, they cover modification of
17 the file, and distribution when not linked into a combine
18 executable.)
19
20 This file is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23 General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; see the file COPYING.  If not, write to
27 the Free Software Foundation, 51 Franklin Street, Fifth Floor,
28 Boston, MA 02110-1301, USA.  */
29
30 #define __zero_reg__ r1
31 #define __tmp_reg__ r0
32 #define __SREG__ 0x3f
33 #define __SP_H__ 0x3e
34 #define __SP_L__ 0x3d
35 #define __RAMPZ__ 0x3B
36
37 /* Most of the functions here are called directly from avr.md
38    patterns, instead of using the standard libcall mechanisms.
39    This can make better code because GCC knows exactly which
40    of the call-used registers (not all of them) are clobbered.  */
41
42         .section .text.libgcc, "ax", @progbits
43
44         .macro  mov_l  r_dest, r_src
45 #if defined (__AVR_HAVE_MOVW__)
46         movw    \r_dest, \r_src
47 #else
48         mov     \r_dest, \r_src
49 #endif
50         .endm
51
52         .macro  mov_h  r_dest, r_src
53 #if defined (__AVR_HAVE_MOVW__)
54         ; empty
55 #else
56         mov     \r_dest, \r_src
57 #endif
58         .endm
59
60 /* Note: mulqi3, mulhi3 are open-coded on the enhanced core.  */
61 #if !defined (__AVR_HAVE_MUL__)
62 /*******************************************************
63                Multiplication  8 x 8
64 *******************************************************/
65 #if defined (L_mulqi3)
66
67 #define r_arg2  r22             /* multiplicand */
68 #define r_arg1  r24             /* multiplier */
69 #define r_res   __tmp_reg__     /* result */
70
71         .global __mulqi3
72         .func   __mulqi3
73 __mulqi3:
74         clr     r_res           ; clear result
75 __mulqi3_loop:
76         sbrc    r_arg1,0
77         add     r_res,r_arg2
78         add     r_arg2,r_arg2   ; shift multiplicand
79         breq    __mulqi3_exit   ; while multiplicand != 0
80         lsr     r_arg1          ; 
81         brne    __mulqi3_loop   ; exit if multiplier = 0
82 __mulqi3_exit:  
83         mov     r_arg1,r_res    ; result to return register
84         ret
85
86 #undef r_arg2  
87 #undef r_arg1  
88 #undef r_res   
89         
90 .endfunc
91 #endif  /* defined (L_mulqi3) */
92
93 #if defined (L_mulqihi3)
94         .global __mulqihi3
95         .func   __mulqihi3
96 __mulqihi3:
97         clr     r25
98         sbrc    r24, 7
99         dec     r25
100         clr     r23
101         sbrc    r22, 7
102         dec     r22
103         rjmp    __mulhi3
104         .endfunc
105 #endif /* defined (L_mulqihi3) */
106
107 #if defined (L_umulqihi3)
108         .global __umulqihi3
109         .func   __umulqihi3
110 __umulqihi3:
111         clr     r25
112         clr     r23
113         rjmp    __mulhi3
114         .endfunc
115 #endif /* defined (L_umulqihi3) */
116
117 /*******************************************************
118                Multiplication  16 x 16
119 *******************************************************/
120 #if defined (L_mulhi3)
121 #define r_arg1L r24             /* multiplier Low */
122 #define r_arg1H r25             /* multiplier High */
123 #define r_arg2L r22             /* multiplicand Low */
124 #define r_arg2H r23             /* multiplicand High */
125 #define r_resL  __tmp_reg__     /* result Low */
126 #define r_resH  r21             /* result High */
127
128         .global __mulhi3
129         .func   __mulhi3
130 __mulhi3:
131         clr     r_resH          ; clear result
132         clr     r_resL          ; clear result
133 __mulhi3_loop:
134         sbrs    r_arg1L,0
135         rjmp    __mulhi3_skip1
136         add     r_resL,r_arg2L  ; result + multiplicand
137         adc     r_resH,r_arg2H
138 __mulhi3_skip1: 
139         add     r_arg2L,r_arg2L ; shift multiplicand
140         adc     r_arg2H,r_arg2H
141
142         cp      r_arg2L,__zero_reg__
143         cpc     r_arg2H,__zero_reg__
144         breq    __mulhi3_exit   ; while multiplicand != 0
145
146         lsr     r_arg1H         ; gets LSB of multiplier
147         ror     r_arg1L
148         sbiw    r_arg1L,0
149         brne    __mulhi3_loop   ; exit if multiplier = 0
150 __mulhi3_exit:
151         mov     r_arg1H,r_resH  ; result to return register
152         mov     r_arg1L,r_resL
153         ret
154
155 #undef r_arg1L
156 #undef r_arg1H
157 #undef r_arg2L
158 #undef r_arg2H
159 #undef r_resL   
160 #undef r_resH 
161
162 .endfunc
163 #endif /* defined (L_mulhi3) */
164 #endif /* !defined (__AVR_HAVE_MUL__) */
165
166 #if defined (L_mulhisi3)
167         .global __mulhisi3
168         .func   __mulhisi3
169 __mulhisi3:
170         mov_l   r18, r24
171         mov_h   r19, r25
172         clr     r24
173         sbrc    r23, 7
174         dec     r24
175         mov     r25, r24
176         clr     r20
177         sbrc    r19, 7
178         dec     r20
179         mov     r21, r20
180         rjmp    __mulsi3
181         .endfunc
182 #endif /* defined (L_mulhisi3) */
183
184 #if defined (L_umulhisi3)
185         .global __umulhisi3
186         .func   __umulhisi3
187 __umulhisi3:
188         mov_l   r18, r24
189         mov_h   r19, r25
190         clr     r24
191         clr     r25
192         clr     r20
193         clr     r21
194         rjmp    __mulsi3
195         .endfunc
196 #endif /* defined (L_umulhisi3) */
197
198 #if defined (L_mulsi3)
199 /*******************************************************
200                Multiplication  32 x 32
201 *******************************************************/
202 #define r_arg1L  r22            /* multiplier Low */
203 #define r_arg1H  r23
204 #define r_arg1HL r24
205 #define r_arg1HH r25            /* multiplier High */
206
207
208 #define r_arg2L  r18            /* multiplicand Low */
209 #define r_arg2H  r19    
210 #define r_arg2HL r20
211 #define r_arg2HH r21            /* multiplicand High */
212         
213 #define r_resL   r26            /* result Low */
214 #define r_resH   r27
215 #define r_resHL  r30
216 #define r_resHH  r31            /* result High */
217
218         
219         .global __mulsi3
220         .func   __mulsi3
221 __mulsi3:
222 #if defined (__AVR_HAVE_MUL__)
223         mul     r_arg1L, r_arg2L
224         movw    r_resL, r0
225         mul     r_arg1H, r_arg2H
226         movw    r_resHL, r0
227         mul     r_arg1HL, r_arg2L
228         add     r_resHL, r0
229         adc     r_resHH, r1
230         mul     r_arg1L, r_arg2HL
231         add     r_resHL, r0
232         adc     r_resHH, r1
233         mul     r_arg1HH, r_arg2L
234         add     r_resHH, r0
235         mul     r_arg1HL, r_arg2H
236         add     r_resHH, r0
237         mul     r_arg1H, r_arg2HL
238         add     r_resHH, r0
239         mul     r_arg1L, r_arg2HH
240         add     r_resHH, r0
241         clr     r_arg1HH        ; use instead of __zero_reg__ to add carry
242         mul     r_arg1H, r_arg2L
243         add     r_resH, r0
244         adc     r_resHL, r1
245         adc     r_resHH, r_arg1HH ; add carry
246         mul     r_arg1L, r_arg2H
247         add     r_resH, r0
248         adc     r_resHL, r1
249         adc     r_resHH, r_arg1HH ; add carry
250         movw    r_arg1L, r_resL
251         movw    r_arg1HL, r_resHL
252         clr     r1              ; __zero_reg__ clobbered by "mul"
253         ret
254 #else
255         clr     r_resHH         ; clear result
256         clr     r_resHL         ; clear result
257         clr     r_resH          ; clear result
258         clr     r_resL          ; clear result
259 __mulsi3_loop:
260         sbrs    r_arg1L,0
261         rjmp    __mulsi3_skip1
262         add     r_resL,r_arg2L          ; result + multiplicand
263         adc     r_resH,r_arg2H
264         adc     r_resHL,r_arg2HL
265         adc     r_resHH,r_arg2HH
266 __mulsi3_skip1:
267         add     r_arg2L,r_arg2L         ; shift multiplicand
268         adc     r_arg2H,r_arg2H
269         adc     r_arg2HL,r_arg2HL
270         adc     r_arg2HH,r_arg2HH
271         
272         lsr     r_arg1HH        ; gets LSB of multiplier
273         ror     r_arg1HL
274         ror     r_arg1H
275         ror     r_arg1L
276         brne    __mulsi3_loop
277         sbiw    r_arg1HL,0
278         cpc     r_arg1H,r_arg1L
279         brne    __mulsi3_loop           ; exit if multiplier = 0
280 __mulsi3_exit:
281         mov_h   r_arg1HH,r_resHH        ; result to return register
282         mov_l   r_arg1HL,r_resHL
283         mov_h   r_arg1H,r_resH
284         mov_l   r_arg1L,r_resL
285         ret
286 #endif /* defined (__AVR_HAVE_MUL__) */
287 #undef r_arg1L 
288 #undef r_arg1H 
289 #undef r_arg1HL
290 #undef r_arg1HH
291              
292              
293 #undef r_arg2L 
294 #undef r_arg2H 
295 #undef r_arg2HL
296 #undef r_arg2HH
297              
298 #undef r_resL  
299 #undef r_resH  
300 #undef r_resHL 
301 #undef r_resHH 
302
303 .endfunc
304 #endif /* defined (L_mulsi3) */
305         
306 /*******************************************************
307        Division 8 / 8 => (result + remainder)
308 *******************************************************/
309 #define r_rem   r25     /* remainder */
310 #define r_arg1  r24     /* dividend, quotient */
311 #define r_arg2  r22     /* divisor */
312 #define r_cnt   r23     /* loop count */
313
314 #if defined (L_udivmodqi4)
315         .global __udivmodqi4
316         .func   __udivmodqi4
317 __udivmodqi4:
318         sub     r_rem,r_rem     ; clear remainder and carry
319         ldi     r_cnt,9         ; init loop counter
320         rjmp    __udivmodqi4_ep ; jump to entry point
321 __udivmodqi4_loop:
322         rol     r_rem           ; shift dividend into remainder
323         cp      r_rem,r_arg2    ; compare remainder & divisor
324         brcs    __udivmodqi4_ep ; remainder <= divisor
325         sub     r_rem,r_arg2    ; restore remainder
326 __udivmodqi4_ep:
327         rol     r_arg1          ; shift dividend (with CARRY)
328         dec     r_cnt           ; decrement loop counter
329         brne    __udivmodqi4_loop
330         com     r_arg1          ; complement result 
331                                 ; because C flag was complemented in loop
332         ret
333         .endfunc
334 #endif /* defined (L_udivmodqi4) */
335
336 #if defined (L_divmodqi4)
337         .global __divmodqi4
338         .func   __divmodqi4
339 __divmodqi4:
340         bst     r_arg1,7        ; store sign of dividend
341         mov     __tmp_reg__,r_arg1
342         eor     __tmp_reg__,r_arg2; r0.7 is sign of result
343         sbrc    r_arg1,7
344         neg     r_arg1          ; dividend negative : negate
345         sbrc    r_arg2,7
346         neg     r_arg2          ; divisor negative : negate
347         rcall   __udivmodqi4    ; do the unsigned div/mod
348         brtc    __divmodqi4_1
349         neg     r_rem           ; correct remainder sign
350 __divmodqi4_1:
351         sbrc    __tmp_reg__,7
352         neg     r_arg1          ; correct result sign
353 __divmodqi4_exit:
354         ret
355         .endfunc
356 #endif /* defined (L_divmodqi4) */
357
358 #undef r_rem
359 #undef r_arg1
360 #undef r_arg2
361 #undef r_cnt
362         
363                 
364 /*******************************************************
365        Division 16 / 16 => (result + remainder)
366 *******************************************************/
367 #define r_remL  r26     /* remainder Low */
368 #define r_remH  r27     /* remainder High */
369
370 /* return: remainder */
371 #define r_arg1L r24     /* dividend Low */
372 #define r_arg1H r25     /* dividend High */
373
374 /* return: quotient */
375 #define r_arg2L r22     /* divisor Low */
376 #define r_arg2H r23     /* divisor High */
377         
378 #define r_cnt   r21     /* loop count */
379
380 #if defined (L_udivmodhi4)
381         .global __udivmodhi4
382         .func   __udivmodhi4
383 __udivmodhi4:
384         sub     r_remL,r_remL
385         sub     r_remH,r_remH   ; clear remainder and carry
386         ldi     r_cnt,17        ; init loop counter
387         rjmp    __udivmodhi4_ep ; jump to entry point
388 __udivmodhi4_loop:
389         rol     r_remL          ; shift dividend into remainder
390         rol     r_remH
391         cp      r_remL,r_arg2L  ; compare remainder & divisor
392         cpc     r_remH,r_arg2H
393         brcs    __udivmodhi4_ep ; remainder < divisor
394         sub     r_remL,r_arg2L  ; restore remainder
395         sbc     r_remH,r_arg2H
396 __udivmodhi4_ep:
397         rol     r_arg1L         ; shift dividend (with CARRY)
398         rol     r_arg1H
399         dec     r_cnt           ; decrement loop counter
400         brne    __udivmodhi4_loop
401         com     r_arg1L
402         com     r_arg1H
403 ; div/mod results to return registers, as for the div() function
404         mov_l   r_arg2L, r_arg1L        ; quotient
405         mov_h   r_arg2H, r_arg1H
406         mov_l   r_arg1L, r_remL         ; remainder
407         mov_h   r_arg1H, r_remH
408         ret
409         .endfunc
410 #endif /* defined (L_udivmodhi4) */
411
412 #if defined (L_divmodhi4)
413         .global __divmodhi4
414         .func   __divmodhi4
415 __divmodhi4:
416         .global _div
417 _div:
418         bst     r_arg1H,7       ; store sign of dividend
419         mov     __tmp_reg__,r_arg1H
420         eor     __tmp_reg__,r_arg2H   ; r0.7 is sign of result
421         rcall   __divmodhi4_neg1 ; dividend negative : negate
422         sbrc    r_arg2H,7
423         rcall   __divmodhi4_neg2 ; divisor negative : negate
424         rcall   __udivmodhi4    ; do the unsigned div/mod
425         rcall   __divmodhi4_neg1 ; correct remainder sign
426         tst     __tmp_reg__
427         brpl    __divmodhi4_exit
428 __divmodhi4_neg2:
429         com     r_arg2H
430         neg     r_arg2L         ; correct divisor/result sign
431         sbci    r_arg2H,0xff
432 __divmodhi4_exit:
433         ret
434 __divmodhi4_neg1:
435         brtc    __divmodhi4_exit
436         com     r_arg1H
437         neg     r_arg1L         ; correct dividend/remainder sign
438         sbci    r_arg1H,0xff
439         ret
440         .endfunc
441 #endif /* defined (L_divmodhi4) */
442
443 #undef r_remH  
444 #undef r_remL  
445              
446 #undef r_arg1H 
447 #undef r_arg1L 
448              
449 #undef r_arg2H 
450 #undef r_arg2L 
451                 
452 #undef r_cnt    
453         
454 /*******************************************************
455        Division 32 / 32 => (result + remainder)
456 *******************************************************/
457 #define r_remHH r31     /* remainder High */
458 #define r_remHL r30
459 #define r_remH  r27
460 #define r_remL  r26     /* remainder Low */
461
462 /* return: remainder */
463 #define r_arg1HH r25    /* dividend High */
464 #define r_arg1HL r24
465 #define r_arg1H  r23
466 #define r_arg1L  r22    /* dividend Low */
467
468 /* return: quotient */
469 #define r_arg2HH r21    /* divisor High */
470 #define r_arg2HL r20
471 #define r_arg2H  r19
472 #define r_arg2L  r18    /* divisor Low */
473         
474 #define r_cnt __zero_reg__  /* loop count (0 after the loop!) */
475
476 #if defined (L_udivmodsi4)
477         .global __udivmodsi4
478         .func   __udivmodsi4
479 __udivmodsi4:
480         ldi     r_remL, 33      ; init loop counter
481         mov     r_cnt, r_remL
482         sub     r_remL,r_remL
483         sub     r_remH,r_remH   ; clear remainder and carry
484         mov_l   r_remHL, r_remL
485         mov_h   r_remHH, r_remH
486         rjmp    __udivmodsi4_ep ; jump to entry point
487 __udivmodsi4_loop:
488         rol     r_remL          ; shift dividend into remainder
489         rol     r_remH
490         rol     r_remHL
491         rol     r_remHH
492         cp      r_remL,r_arg2L  ; compare remainder & divisor
493         cpc     r_remH,r_arg2H
494         cpc     r_remHL,r_arg2HL
495         cpc     r_remHH,r_arg2HH
496         brcs    __udivmodsi4_ep ; remainder <= divisor
497         sub     r_remL,r_arg2L  ; restore remainder
498         sbc     r_remH,r_arg2H
499         sbc     r_remHL,r_arg2HL
500         sbc     r_remHH,r_arg2HH
501 __udivmodsi4_ep:
502         rol     r_arg1L         ; shift dividend (with CARRY)
503         rol     r_arg1H
504         rol     r_arg1HL
505         rol     r_arg1HH
506         dec     r_cnt           ; decrement loop counter
507         brne    __udivmodsi4_loop
508                                 ; __zero_reg__ now restored (r_cnt == 0)
509         com     r_arg1L
510         com     r_arg1H
511         com     r_arg1HL
512         com     r_arg1HH
513 ; div/mod results to return registers, as for the ldiv() function
514         mov_l   r_arg2L,  r_arg1L       ; quotient
515         mov_h   r_arg2H,  r_arg1H
516         mov_l   r_arg2HL, r_arg1HL
517         mov_h   r_arg2HH, r_arg1HH
518         mov_l   r_arg1L,  r_remL        ; remainder
519         mov_h   r_arg1H,  r_remH
520         mov_l   r_arg1HL, r_remHL
521         mov_h   r_arg1HH, r_remHH
522         ret
523         .endfunc
524 #endif /* defined (L_udivmodsi4) */
525
526 #if defined (L_divmodsi4)
527         .global __divmodsi4
528         .func   __divmodsi4
529 __divmodsi4:
530         bst     r_arg1HH,7      ; store sign of dividend
531         mov     __tmp_reg__,r_arg1HH
532         eor     __tmp_reg__,r_arg2HH   ; r0.7 is sign of result
533         rcall   __divmodsi4_neg1 ; dividend negative : negate
534         sbrc    r_arg2HH,7
535         rcall   __divmodsi4_neg2 ; divisor negative : negate
536         rcall   __udivmodsi4    ; do the unsigned div/mod
537         rcall   __divmodsi4_neg1 ; correct remainder sign
538         rol     __tmp_reg__
539         brcc    __divmodsi4_exit
540 __divmodsi4_neg2:
541         com     r_arg2HH
542         com     r_arg2HL
543         com     r_arg2H
544         neg     r_arg2L         ; correct divisor/quotient sign
545         sbci    r_arg2H,0xff
546         sbci    r_arg2HL,0xff
547         sbci    r_arg2HH,0xff
548 __divmodsi4_exit:
549         ret
550 __divmodsi4_neg1:
551         brtc    __divmodsi4_exit
552         com     r_arg1HH
553         com     r_arg1HL
554         com     r_arg1H
555         neg     r_arg1L         ; correct dividend/remainder sign
556         sbci    r_arg1H, 0xff
557         sbci    r_arg1HL,0xff
558         sbci    r_arg1HH,0xff
559         ret
560         .endfunc
561 #endif /* defined (L_divmodsi4) */
562
563 /**********************************
564  * This is a prologue subroutine
565  **********************************/
566 #if defined (L_prologue)
567
568         .global __prologue_saves__
569         .func   __prologue_saves__
570 __prologue_saves__:
571         push r2
572         push r3
573         push r4
574         push r5
575         push r6
576         push r7
577         push r8
578         push r9
579         push r10
580         push r11
581         push r12
582         push r13
583         push r14
584         push r15
585         push r16
586         push r17
587         push r28
588         push r29
589         in      r28,__SP_L__
590         in      r29,__SP_H__
591         sub     r28,r26
592         sbc     r29,r27
593         in      __tmp_reg__,__SREG__
594         cli
595         out     __SP_H__,r29
596         out     __SREG__,__tmp_reg__
597         out     __SP_L__,r28
598 #if defined (__AVR_HAVE_EIJMP_EICALL__)
599         eijmp
600 #else
601         ijmp
602 #endif
603
604 .endfunc
605 #endif /* defined (L_prologue) */
606
607 /*
608  * This is an epilogue subroutine
609  */
610 #if defined (L_epilogue)
611
612         .global __epilogue_restores__
613         .func   __epilogue_restores__
614 __epilogue_restores__:
615         ldd     r2,Y+18
616         ldd     r3,Y+17
617         ldd     r4,Y+16
618         ldd     r5,Y+15
619         ldd     r6,Y+14
620         ldd     r7,Y+13
621         ldd     r8,Y+12
622         ldd     r9,Y+11
623         ldd     r10,Y+10
624         ldd     r11,Y+9
625         ldd     r12,Y+8
626         ldd     r13,Y+7
627         ldd     r14,Y+6
628         ldd     r15,Y+5
629         ldd     r16,Y+4
630         ldd     r17,Y+3
631         ldd     r26,Y+2
632         ldd     r27,Y+1
633         add     r28,r30
634         adc     r29,__zero_reg__
635         in      __tmp_reg__,__SREG__
636         cli
637         out     __SP_H__,r29
638         out     __SREG__,__tmp_reg__
639         out     __SP_L__,r28
640         mov_l   r28, r26
641         mov_h   r29, r27
642         ret
643 .endfunc
644 #endif /* defined (L_epilogue) */
645
646 #ifdef L_exit
647         .section .fini9,"ax",@progbits
648         .global _exit
649         .func   _exit
650 _exit:
651         .weak   exit
652 exit:
653
654         /* Code from .fini8 ... .fini1 sections inserted by ld script.  */
655
656         .section .fini0,"ax",@progbits
657         cli
658 __stop_program:
659         rjmp    __stop_program
660         .endfunc
661 #endif /* defined (L_exit) */
662
663 #ifdef L_cleanup
664         .weak   _cleanup
665         .func   _cleanup
666 _cleanup:
667         ret
668 .endfunc
669 #endif /* defined (L_cleanup) */
670
671 #ifdef L_tablejump
672         .global __tablejump2__
673         .func   __tablejump2__
674 __tablejump2__:
675         lsl     r30
676         rol     r31
677         .global __tablejump__
678 __tablejump__:
679 #if defined (__AVR_HAVE_LPMX__)
680         lpm     __tmp_reg__, Z+
681         lpm     r31, Z
682         mov     r30, __tmp_reg__
683
684 #if defined (__AVR_HAVE_EIJMP_EICALL__)
685         eijmp
686 #else
687         ijmp
688 #endif
689
690 #else
691         lpm
692         adiw    r30, 1
693         push    r0
694         lpm
695         push    r0
696 #if defined (__AVR_HAVE_EIJMP_EICALL__)
697         push    __zero_reg__
698 #endif
699         ret
700 #endif
701         .endfunc
702 #endif /* defined (L_tablejump) */
703
704 #ifdef L_copy_data
705         .section .init4,"ax",@progbits
706         .global __do_copy_data
707 __do_copy_data:
708 #if defined(__AVR_HAVE_ELPMX__)
709         ldi     r17, hi8(__data_end)
710         ldi     r26, lo8(__data_start)
711         ldi     r27, hi8(__data_start)
712         ldi     r30, lo8(__data_load_start)
713         ldi     r31, hi8(__data_load_start)
714         ldi     r16, hh8(__data_load_start)
715         out     __RAMPZ__, r16
716         rjmp    .L__do_copy_data_start
717 .L__do_copy_data_loop:
718         elpm    r0, Z+
719         st      X+, r0
720 .L__do_copy_data_start:
721         cpi     r26, lo8(__data_end)
722         cpc     r27, r17
723         brne    .L__do_copy_data_loop
724 #elif  !defined(__AVR_HAVE_ELPMX__) && defined(__AVR_HAVE_ELPM__)
725         ldi     r17, hi8(__data_end)
726         ldi     r26, lo8(__data_start)
727         ldi     r27, hi8(__data_start)
728         ldi     r30, lo8(__data_load_start)
729         ldi     r31, hi8(__data_load_start)
730         ldi     r16, hh8(__data_load_start - 0x10000)
731 .L__do_copy_data_carry:
732         inc     r16
733         out     __RAMPZ__, r16
734         rjmp    .L__do_copy_data_start
735 .L__do_copy_data_loop:
736         elpm
737         st      X+, r0
738         adiw    r30, 1
739         brcs    .L__do_copy_data_carry
740 .L__do_copy_data_start:
741         cpi     r26, lo8(__data_end)
742         cpc     r27, r17
743         brne    .L__do_copy_data_loop
744 #elif !defined(__AVR_HAVE_ELPMX__) && !defined(__AVR_HAVE_ELPM__)
745         ldi     r17, hi8(__data_end)
746         ldi     r26, lo8(__data_start)
747         ldi     r27, hi8(__data_start)
748         ldi     r30, lo8(__data_load_start)
749         ldi     r31, hi8(__data_load_start)
750         rjmp    .L__do_copy_data_start
751 .L__do_copy_data_loop:
752 #if defined (__AVR_HAVE_LPMX__)
753         lpm     r0, Z+
754 #else
755         lpm
756         adiw    r30, 1
757 #endif
758         st      X+, r0
759 .L__do_copy_data_start:
760         cpi     r26, lo8(__data_end)
761         cpc     r27, r17
762         brne    .L__do_copy_data_loop
763 #endif /* !defined(__AVR_HAVE_ELPMX__) && !defined(__AVR_HAVE_ELPM__) */
764 #endif /* L_copy_data */
765
766 /* __do_clear_bss is only necessary if there is anything in .bss section.  */
767
768 #ifdef L_clear_bss
769         .section .init4,"ax",@progbits
770         .global __do_clear_bss
771 __do_clear_bss:
772         ldi     r17, hi8(__bss_end)
773         ldi     r26, lo8(__bss_start)
774         ldi     r27, hi8(__bss_start)
775         rjmp    .do_clear_bss_start
776 .do_clear_bss_loop:
777         st      X+, __zero_reg__
778 .do_clear_bss_start:
779         cpi     r26, lo8(__bss_end)
780         cpc     r27, r17
781         brne    .do_clear_bss_loop
782 #endif /* L_clear_bss */
783
784 /* __do_global_ctors and __do_global_dtors are only necessary
785    if there are any constructors/destructors.  */
786
787 #if defined (__AVR_HAVE_JMP_CALL__)
788 #define XCALL call
789 #else
790 #define XCALL rcall
791 #endif
792
793 #ifdef L_ctors
794         .section .init6,"ax",@progbits
795         .global __do_global_ctors
796 __do_global_ctors:
797         ldi     r17, hi8(__ctors_start)
798         ldi     r28, lo8(__ctors_end)
799         ldi     r29, hi8(__ctors_end)
800         rjmp    .do_global_ctors_start
801 .do_global_ctors_loop:
802         sbiw    r28, 2
803         mov_h   r31, r29
804         mov_l   r30, r28
805         XCALL   __tablejump__
806 .do_global_ctors_start:
807         cpi     r28, lo8(__ctors_start)
808         cpc     r29, r17
809         brne    .do_global_ctors_loop
810 #endif /* L_ctors */
811
812 #ifdef L_dtors
813         .section .fini6,"ax",@progbits
814         .global __do_global_dtors
815 __do_global_dtors:
816         ldi     r17, hi8(__dtors_end)
817         ldi     r28, lo8(__dtors_start)
818         ldi     r29, hi8(__dtors_start)
819         rjmp    .do_global_dtors_start
820 .do_global_dtors_loop:
821         mov_h   r31, r29
822         mov_l   r30, r28
823         XCALL   __tablejump__
824         adiw    r28, 2
825 .do_global_dtors_start:
826         cpi     r28, lo8(__dtors_end)
827         cpc     r29, r17
828         brne    .do_global_dtors_loop
829 #endif /* L_dtors */
830