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