OSDN Git Service

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