]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/config/avr/libgcc.S
Licensing changes to GPLv3 resp. GPLv3 with GCC Runtime Exception.
[thirdparty/gcc.git] / gcc / config / avr / libgcc.S
CommitLineData
90e7678c 1/* -*- Mode: Asm -*- */
33faafca 2/* Copyright (C) 1998, 1999, 2000, 2007, 2008, 2009
0a84fec6 3 Free Software Foundation, Inc.
90e7678c
DC
4 Contributed by Denis Chertykov <denisc@overta.ru>
5
6This file is free software; you can redistribute it and/or modify it
7under the terms of the GNU General Public License as published by the
748086b7 8Free Software Foundation; either version 3, or (at your option) any
90e7678c
DC
9later version.
10
90e7678c
DC
11This file is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14General Public License for more details.
15
748086b7
JJ
16Under Section 7 of GPL version 3, you are granted additional
17permissions described in the GCC Runtime Library Exception, version
183.1, as published by the Free Software Foundation.
19
20You should have received a copy of the GNU General Public License and
21a copy of the GCC Runtime Library Exception along with this program;
22see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
23<http://www.gnu.org/licenses/>. */
90e7678c 24
90e7678c
DC
25#define __zero_reg__ r1
26#define __tmp_reg__ r0
27#define __SREG__ 0x3f
28#define __SP_H__ 0x3e
29#define __SP_L__ 0x3d
34d02d17 30#define __RAMPZ__ 0x3B
90e7678c 31
1d26ac96
MM
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
3f8a8c68 37 .section .text.libgcc, "ax", @progbits
bad3869a 38
1d26ac96 39 .macro mov_l r_dest, r_src
7ed9c001 40#if defined (__AVR_HAVE_MOVW__)
1d26ac96
MM
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
7ed9c001 48#if defined (__AVR_HAVE_MOVW__)
1d26ac96
MM
49 ; empty
50#else
51 mov \r_dest, \r_src
52#endif
53 .endm
54
bad3869a 55/* Note: mulqi3, mulhi3 are open-coded on the enhanced core. */
dd6d1f8c 56#if !defined (__AVR_HAVE_MUL__)
90e7678c
DC
57/*******************************************************
58 Multiplication 8 x 8
59*******************************************************/
bad3869a 60#if defined (L_mulqi3)
90e7678c 61
c4984bad 62#define r_arg2 r22 /* multiplicand */
90e7678c
DC
63#define r_arg1 r24 /* multiplier */
64#define r_res __tmp_reg__ /* result */
65
bad3869a
MM
66 .global __mulqi3
67 .func __mulqi3
68__mulqi3:
90e7678c
DC
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
cdd9eb8f 85.endfunc
bad3869a 86#endif /* defined (L_mulqi3) */
90e7678c 87
1d26ac96
MM
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) */
90e7678c
DC
111
112/*******************************************************
113 Multiplication 16 x 16
114*******************************************************/
bad3869a 115#if defined (L_mulhi3)
90e7678c
DC
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 */
1d26ac96 120#define r_resL __tmp_reg__ /* result Low */
90e7678c
DC
121#define r_resH r21 /* result High */
122
bad3869a
MM
123 .global __mulhi3
124 .func __mulhi3
125__mulhi3:
90e7678c
DC
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
500164d2
MM
137 cp r_arg2L,__zero_reg__
138 cpc r_arg2H,__zero_reg__
90e7678c
DC
139 breq __mulhi3_exit ; while multiplicand != 0
140
141 lsr r_arg1H ; gets LSB of multiplier
142 ror r_arg1L
7656d28a 143 sbiw r_arg1L,0
90e7678c
DC
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
cdd9eb8f 157.endfunc
bad3869a 158#endif /* defined (L_mulhi3) */
dd6d1f8c 159#endif /* !defined (__AVR_HAVE_MUL__) */
90e7678c 160
1d26ac96
MM
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
bad3869a 193#if defined (L_mulsi3)
90e7678c
DC
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
bad3869a
MM
214 .global __mulsi3
215 .func __mulsi3
216__mulsi3:
dd6d1f8c 217#if defined (__AVR_HAVE_MUL__)
bad3869a
MM
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
90e7678c
DC
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:
7ed9c001
DC
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
90e7678c 280 ret
dd6d1f8c 281#endif /* defined (__AVR_HAVE_MUL__) */
90e7678c
DC
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
cdd9eb8f 298.endfunc
bad3869a 299#endif /* defined (L_mulsi3) */
90e7678c
DC
300
301/*******************************************************
302 Division 8 / 8 => (result + remainder)
303*******************************************************/
1d26ac96
MM
304#define r_rem r25 /* remainder */
305#define r_arg1 r24 /* dividend, quotient */
c4984bad 306#define r_arg2 r22 /* divisor */
1d26ac96 307#define r_cnt r23 /* loop count */
90e7678c 308
1d26ac96
MM
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
90e7678c 327 ret
1d26ac96
MM
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
90e7678c
DC
336 mov __tmp_reg__,r_arg1
337 eor __tmp_reg__,r_arg2; r0.7 is sign of result
338 sbrc r_arg1,7
1d26ac96 339 neg r_arg1 ; dividend negative : negate
90e7678c 340 sbrc r_arg2,7
1d26ac96
MM
341 neg r_arg2 ; divisor negative : negate
342 rcall __udivmodqi4 ; do the unsigned div/mod
343 brtc __divmodqi4_1
90e7678c 344 neg r_rem ; correct remainder sign
1d26ac96 345__divmodqi4_1:
90e7678c
DC
346 sbrc __tmp_reg__,7
347 neg r_arg1 ; correct result sign
1d26ac96
MM
348__divmodqi4_exit:
349 ret
350 .endfunc
351#endif /* defined (L_divmodqi4) */
90e7678c
DC
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 */
1d26ac96
MM
364
365/* return: remainder */
90e7678c
DC
366#define r_arg1L r24 /* dividend Low */
367#define r_arg1H r25 /* dividend High */
1d26ac96
MM
368
369/* return: quotient */
90e7678c
DC
370#define r_arg2L r22 /* divisor Low */
371#define r_arg2H r23 /* divisor High */
372
373#define r_cnt r21 /* loop count */
90e7678c 374
1d26ac96
MM
375#if defined (L_udivmodhi4)
376 .global __udivmodhi4
377 .func __udivmodhi4
378__udivmodhi4:
90e7678c 379 sub r_remL,r_remL
1d26ac96 380 sub r_remH,r_remH ; clear remainder and carry
90e7678c 381 ldi r_cnt,17 ; init loop counter
1d26ac96
MM
382 rjmp __udivmodhi4_ep ; jump to entry point
383__udivmodhi4_loop:
90e7678c
DC
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
1d26ac96 388 brcs __udivmodhi4_ep ; remainder < divisor
90e7678c
DC
389 sub r_remL,r_arg2L ; restore remainder
390 sbc r_remH,r_arg2H
1d26ac96 391__udivmodhi4_ep:
90e7678c
DC
392 rol r_arg1L ; shift dividend (with CARRY)
393 rol r_arg1H
394 dec r_cnt ; decrement loop counter
1d26ac96
MM
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
90e7678c 421 tst __tmp_reg__
1d26ac96
MM
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:
90e7678c 428 ret
1d26ac96
MM
429__divmodhi4_neg1:
430 brtc __divmodhi4_exit
90e7678c 431 com r_arg1H
1d26ac96
MM
432 neg r_arg1L ; correct dividend/remainder sign
433 sbci r_arg1H,0xff
90e7678c 434 ret
1d26ac96
MM
435 .endfunc
436#endif /* defined (L_divmodhi4) */
437
90e7678c
DC
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 */
1d26ac96
MM
456
457/* return: remainder */
90e7678c
DC
458#define r_arg1HH r25 /* dividend High */
459#define r_arg1HL r24
460#define r_arg1H r23
461#define r_arg1L r22 /* dividend Low */
1d26ac96
MM
462
463/* return: quotient */
90e7678c
DC
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
bad3869a 469#define r_cnt __zero_reg__ /* loop count (0 after the loop!) */
90e7678c 470
1d26ac96
MM
471#if defined (L_udivmodsi4)
472 .global __udivmodsi4
473 .func __udivmodsi4
474__udivmodsi4:
bad3869a
MM
475 ldi r_remL, 33 ; init loop counter
476 mov r_cnt, r_remL
90e7678c 477 sub r_remL,r_remL
1d26ac96
MM
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:
90e7678c
DC
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
1d26ac96 491 brcs __udivmodsi4_ep ; remainder <= divisor
90e7678c
DC
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
1d26ac96 496__udivmodsi4_ep:
90e7678c
DC
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
1d26ac96 502 brne __udivmodsi4_loop
bad3869a 503 ; __zero_reg__ now restored (r_cnt == 0)
90e7678c
DC
504 com r_arg1L
505 com r_arg1H
506 com r_arg1HL
507 com r_arg1HH
1d26ac96
MM
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
90e7678c 517 ret
1d26ac96
MM
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) */
90e7678c
DC
557
558/**********************************
559 * This is a prologue subroutine
560 **********************************/
bad3869a 561#if defined (L_prologue)
90e7678c 562
cdd9eb8f
DC
563 .global __prologue_saves__
564 .func __prologue_saves__
565__prologue_saves__:
90e7678c
DC
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__
90e7678c
DC
586 sub r28,r26
587 sbc r29,r27
588 in __tmp_reg__,__SREG__
589 cli
90e7678c 590 out __SP_H__,r29
78cf8279
MM
591 out __SREG__,__tmp_reg__
592 out __SP_L__,r28
693092fb
BH
593#if defined (__AVR_HAVE_EIJMP_EICALL__)
594 eijmp
595#else
90e7678c 596 ijmp
693092fb
BH
597#endif
598
cdd9eb8f 599.endfunc
bad3869a 600#endif /* defined (L_prologue) */
90e7678c
DC
601
602/*
56b871c1 603 * This is an epilogue subroutine
90e7678c 604 */
bad3869a 605#if defined (L_epilogue)
90e7678c 606
cdd9eb8f
DC
607 .global __epilogue_restores__
608 .func __epilogue_restores__
609__epilogue_restores__:
90e7678c
DC
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
90e7678c 632 out __SP_H__,r29
78cf8279
MM
633 out __SREG__,__tmp_reg__
634 out __SP_L__,r28
1d26ac96
MM
635 mov_l r28, r26
636 mov_h r29, r27
90e7678c 637 ret
6bec29c9
DC
638.endfunc
639#endif /* defined (L_epilogue) */
90e7678c 640
6bec29c9 641#ifdef L_exit
9af145ae
MM
642 .section .fini9,"ax",@progbits
643 .global _exit
cdd9eb8f
DC
644 .func _exit
645_exit:
9af145ae
MM
646 .weak exit
647exit:
648
649 /* Code from .fini8 ... .fini1 sections inserted by ld script. */
650
651 .section .fini0,"ax",@progbits
0a84fec6 652 cli
9af145ae
MM
653__stop_program:
654 rjmp __stop_program
655 .endfunc
6bec29c9
DC
656#endif /* defined (L_exit) */
657
658#ifdef L_cleanup
c4984bad 659 .weak _cleanup
6bec29c9 660 .func _cleanup
c4984bad
MM
661_cleanup:
662 ret
cdd9eb8f 663.endfunc
6bec29c9
DC
664#endif /* defined (L_cleanup) */
665
666#ifdef L_tablejump
1268b05f
MM
667 .global __tablejump2__
668 .func __tablejump2__
669__tablejump2__:
670 lsl r30
671 rol r31
9af145ae
MM
672 .global __tablejump__
673__tablejump__:
dd6d1f8c 674#if defined (__AVR_HAVE_LPMX__)
6bec29c9
DC
675 lpm __tmp_reg__, Z+
676 lpm r31, Z
677 mov r30, __tmp_reg__
693092fb
BH
678
679#if defined (__AVR_HAVE_EIJMP_EICALL__)
680 eijmp
681#else
6bec29c9 682 ijmp
693092fb
BH
683#endif
684
6bec29c9
DC
685#else
686 lpm
9af145ae 687 adiw r30, 1
6bec29c9 688 push r0
6bec29c9
DC
689 lpm
690 push r0
693092fb
BH
691#if defined (__AVR_HAVE_EIJMP_EICALL__)
692 push __zero_reg__
693#endif
6bec29c9 694 ret
cdd9eb8f 695#endif
9af145ae 696 .endfunc
6bec29c9 697#endif /* defined (L_tablejump) */
bad3869a 698
9af145ae
MM
699#ifdef L_copy_data
700 .section .init4,"ax",@progbits
701 .global __do_copy_data
702__do_copy_data:
34d02d17
AS
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__)
9af145ae
MM
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)
34d02d17
AS
745 rjmp .L__do_copy_data_start
746.L__do_copy_data_loop:
7ed9c001 747#if defined (__AVR_HAVE_LPMX__)
9af145ae
MM
748 lpm r0, Z+
749#else
750 lpm
751 adiw r30, 1
752#endif
753 st X+, r0
34d02d17 754.L__do_copy_data_start:
9af145ae
MM
755 cpi r26, lo8(__data_end)
756 cpc r27, r17
34d02d17
AS
757 brne .L__do_copy_data_loop
758#endif /* !defined(__AVR_HAVE_ELPMX__) && !defined(__AVR_HAVE_ELPM__) */
9af145ae
MM
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
5dc77808 782#if defined (__AVR_HAVE_JMP_CALL__)
9af145ae
MM
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
33faafca 791#if defined(__AVR_HAVE_RAMPZ__)
9af145ae
MM
792__do_global_ctors:
793 ldi r17, hi8(__ctors_start)
33faafca 794 ldi r16, hh8(__ctors_start)
9af145ae
MM
795 ldi r28, lo8(__ctors_end)
796 ldi r29, hi8(__ctors_end)
33faafca
AS
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:
9af145ae
MM
818 sbiw r28, 2
819 mov_h r31, r29
820 mov_l r30, r28
821 XCALL __tablejump__
33faafca 822.L__do_global_ctors_start:
9af145ae
MM
823 cpi r28, lo8(__ctors_start)
824 cpc r29, r17
33faafca
AS
825 brne .L__do_global_ctors_loop
826#endif /* defined(__AVR_HAVE_RAMPZ__) */
9af145ae
MM
827#endif /* L_ctors */
828
829#ifdef L_dtors
830 .section .fini6,"ax",@progbits
831 .global __do_global_dtors
33faafca 832#if defined(__AVR_HAVE_RAMPZ__)
9af145ae
MM
833__do_global_dtors:
834 ldi r17, hi8(__dtors_end)
33faafca 835 ldi r16, hh8(__dtors_end)
9af145ae
MM
836 ldi r28, lo8(__dtors_start)
837 ldi r29, hi8(__dtors_start)
33faafca
AS
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:
9af145ae
MM
859 mov_h r31, r29
860 mov_l r30, r28
861 XCALL __tablejump__
862 adiw r28, 2
33faafca 863.L__do_global_dtors_start:
9af145ae
MM
864 cpi r28, lo8(__dtors_end)
865 cpc r29, r17
33faafca
AS
866 brne .L__do_global_dtors_loop
867#endif /* defined(__AVR_HAVE_RAMPZ__) */
9af145ae
MM
868#endif /* L_dtors */
869
33faafca
AS
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