OSDN Git Service

7f3feeb23a40097fd75ded86dcf922c90811c307
[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 #if defined (__AVR_HAVE_JMP_CALL__)
56 #define XCALL call
57 #define XJMP  jmp
58 #else
59 #define XCALL rcall
60 #define XJMP  rjmp
61 #endif
62
63 .macro DEFUN name
64 .global \name
65 .func \name
66 \name:
67 .endm
68
69 .macro ENDF name
70 .size \name, .-\name
71 .endfunc
72 .endm
73
74 \f
75 /* Note: mulqi3, mulhi3 are open-coded on the enhanced core.  */
76 #if !defined (__AVR_HAVE_MUL__)
77 /*******************************************************
78                Multiplication  8 x 8
79 *******************************************************/
80 #if defined (L_mulqi3)
81
82 #define r_arg2  r22             /* multiplicand */
83 #define r_arg1  r24             /* multiplier */
84 #define r_res   __tmp_reg__     /* result */
85
86         .global __mulqi3
87         .func   __mulqi3
88 __mulqi3:
89         clr     r_res           ; clear result
90 __mulqi3_loop:
91         sbrc    r_arg1,0
92         add     r_res,r_arg2
93         add     r_arg2,r_arg2   ; shift multiplicand
94         breq    __mulqi3_exit   ; while multiplicand != 0
95         lsr     r_arg1          ; 
96         brne    __mulqi3_loop   ; exit if multiplier = 0
97 __mulqi3_exit:  
98         mov     r_arg1,r_res    ; result to return register
99         ret
100
101 #undef r_arg2  
102 #undef r_arg1  
103 #undef r_res   
104         
105 .endfunc
106 #endif  /* defined (L_mulqi3) */
107
108 #if defined (L_mulqihi3)
109         .global __mulqihi3
110         .func   __mulqihi3
111 __mulqihi3:
112         clr     r25
113         sbrc    r24, 7
114         dec     r25
115         clr     r23
116         sbrc    r22, 7
117         dec     r22
118         rjmp    __mulhi3
119         .endfunc
120 #endif /* defined (L_mulqihi3) */
121
122 #if defined (L_umulqihi3)
123         .global __umulqihi3
124         .func   __umulqihi3
125 __umulqihi3:
126         clr     r25
127         clr     r23
128         rjmp    __mulhi3
129         .endfunc
130 #endif /* defined (L_umulqihi3) */
131
132 /*******************************************************
133                Multiplication  16 x 16
134 *******************************************************/
135 #if defined (L_mulhi3)
136 #define r_arg1L r24             /* multiplier Low */
137 #define r_arg1H r25             /* multiplier High */
138 #define r_arg2L r22             /* multiplicand Low */
139 #define r_arg2H r23             /* multiplicand High */
140 #define r_resL  __tmp_reg__     /* result Low */
141 #define r_resH  r21             /* result High */
142
143         .global __mulhi3
144         .func   __mulhi3
145 __mulhi3:
146         clr     r_resH          ; clear result
147         clr     r_resL          ; clear result
148 __mulhi3_loop:
149         sbrs    r_arg1L,0
150         rjmp    __mulhi3_skip1
151         add     r_resL,r_arg2L  ; result + multiplicand
152         adc     r_resH,r_arg2H
153 __mulhi3_skip1: 
154         add     r_arg2L,r_arg2L ; shift multiplicand
155         adc     r_arg2H,r_arg2H
156
157         cp      r_arg2L,__zero_reg__
158         cpc     r_arg2H,__zero_reg__
159         breq    __mulhi3_exit   ; while multiplicand != 0
160
161         lsr     r_arg1H         ; gets LSB of multiplier
162         ror     r_arg1L
163         sbiw    r_arg1L,0
164         brne    __mulhi3_loop   ; exit if multiplier = 0
165 __mulhi3_exit:
166         mov     r_arg1H,r_resH  ; result to return register
167         mov     r_arg1L,r_resL
168         ret
169
170 #undef r_arg1L
171 #undef r_arg1H
172 #undef r_arg2L
173 #undef r_arg2H
174 #undef r_resL   
175 #undef r_resH 
176
177 .endfunc
178 #endif /* defined (L_mulhi3) */
179 #endif /* !defined (__AVR_HAVE_MUL__) */
180
181 /*******************************************************
182       Widening Multiplication  32 = 16 x 16
183 *******************************************************/
184                               
185 #if defined (L_mulhisi3)
186 DEFUN __mulhisi3
187 #if defined (__AVR_HAVE_MUL__)
188
189 ;; r25:r22 = r19:r18 * r21:r20
190
191 #define A0 18
192 #define B0 20
193 #define C0 22
194
195 #define A1 A0+1
196 #define B1 B0+1
197 #define C1 C0+1
198 #define C2 C0+2
199 #define C3 C0+3
200  
201     ; C = (signed)A1 * (signed)B1
202     muls  A1, B1
203     movw  C2, R0
204
205     ; C += A0 * B0
206     mul   A0, B0
207     movw  C0, R0
208
209     ; C += (signed)A1 * B0
210     mulsu A1, B0
211     sbci  C3, 0
212     add   C1, R0
213     adc   C2, R1
214     clr   __zero_reg__
215     adc   C3, __zero_reg__
216
217     ; C += (signed)B1 * A0
218     mulsu B1, A0
219     sbci  C3, 0
220     XJMP  __xmulhisi3_exit
221
222 #undef A0
223 #undef A1
224 #undef B0
225 #undef B1
226 #undef C0
227 #undef C1
228 #undef C2
229 #undef C3
230
231 #else /* !__AVR_HAVE_MUL__ */
232 ;;; FIXME: This is dead code (noone calls it)
233         mov_l   r18, r24
234         mov_h   r19, r25
235         clr     r24
236         sbrc    r23, 7
237         dec     r24
238         mov     r25, r24
239         clr     r20
240         sbrc    r19, 7
241         dec     r20
242         mov     r21, r20
243         XJMP    __mulsi3
244 #endif /* __AVR_HAVE_MUL__ */
245 ENDF __mulhisi3
246 #endif /* defined (L_mulhisi3) */
247
248 #if defined (L_umulhisi3)
249 DEFUN __umulhisi3
250 #if defined (__AVR_HAVE_MUL__)
251
252 ;; r25:r22 = r19:r18 * r21:r20
253
254 #define A0 18
255 #define B0 20
256 #define C0 22
257
258 #define A1 A0+1
259 #define B1 B0+1
260 #define C1 C0+1
261 #define C2 C0+2
262 #define C3 C0+3
263
264     ; C = A1 * B1
265     mul   A1, B1
266     movw  C2, R0
267
268     ; C += A0 * B0
269     mul   A0, B0
270     movw  C0, R0
271
272     ; C += A1 * B0
273     mul   A1, B0
274     add   C1, R0
275     adc   C2, R1
276     clr   __zero_reg__
277     adc   C3, __zero_reg__
278
279     ; C += B1 * A0
280     mul   B1, A0
281     XJMP  __xmulhisi3_exit
282
283 #undef A0
284 #undef A1
285 #undef B0
286 #undef B1
287 #undef C0
288 #undef C1
289 #undef C2
290 #undef C3
291
292 #else /* !__AVR_HAVE_MUL__ */
293 ;;; FIXME: This is dead code (noone calls it)
294         mov_l   r18, r24
295         mov_h   r19, r25
296         clr     r24
297         clr     r25
298         clr     r20
299         clr     r21
300         XJMP    __mulsi3
301 #endif /* __AVR_HAVE_MUL__ */
302 ENDF __umulhisi3
303 #endif /* defined (L_umulhisi3) */
304
305 #if defined (L_xmulhisi3_exit)
306
307 ;;; Helper for __mulhisi3 resp. __umulhisi3.
308
309 #define C0 22
310 #define C1 C0+1
311 #define C2 C0+2
312 #define C3 C0+3
313
314 DEFUN __xmulhisi3_exit
315     add   C1, R0
316     adc   C2, R1
317     clr   __zero_reg__
318     adc   C3, __zero_reg__
319     ret
320 ENDF __xmulhisi3_exit
321
322 #undef C0
323 #undef C1
324 #undef C2
325 #undef C3
326
327 #endif /* defined (L_xmulhisi3_exit) */
328
329 #if defined (L_mulsi3)
330 /*******************************************************
331                Multiplication  32 x 32
332 *******************************************************/
333 #define r_arg1L  r22            /* multiplier Low */
334 #define r_arg1H  r23
335 #define r_arg1HL r24
336 #define r_arg1HH r25            /* multiplier High */
337
338
339 #define r_arg2L  r18            /* multiplicand Low */
340 #define r_arg2H  r19    
341 #define r_arg2HL r20
342 #define r_arg2HH r21            /* multiplicand High */
343         
344 #define r_resL   r26            /* result Low */
345 #define r_resH   r27
346 #define r_resHL  r30
347 #define r_resHH  r31            /* result High */
348
349         
350         .global __mulsi3
351         .func   __mulsi3
352 __mulsi3:
353 #if defined (__AVR_HAVE_MUL__)
354         mul     r_arg1L, r_arg2L
355         movw    r_resL, r0
356         mul     r_arg1H, r_arg2H
357         movw    r_resHL, r0
358         mul     r_arg1HL, r_arg2L
359         add     r_resHL, r0
360         adc     r_resHH, r1
361         mul     r_arg1L, r_arg2HL
362         add     r_resHL, r0
363         adc     r_resHH, r1
364         mul     r_arg1HH, r_arg2L
365         add     r_resHH, r0
366         mul     r_arg1HL, r_arg2H
367         add     r_resHH, r0
368         mul     r_arg1H, r_arg2HL
369         add     r_resHH, r0
370         mul     r_arg1L, r_arg2HH
371         add     r_resHH, r0
372         clr     r_arg1HH        ; use instead of __zero_reg__ to add carry
373         mul     r_arg1H, r_arg2L
374         add     r_resH, r0
375         adc     r_resHL, r1
376         adc     r_resHH, r_arg1HH ; add carry
377         mul     r_arg1L, r_arg2H
378         add     r_resH, r0
379         adc     r_resHL, r1
380         adc     r_resHH, r_arg1HH ; add carry
381         movw    r_arg1L, r_resL
382         movw    r_arg1HL, r_resHL
383         clr     r1              ; __zero_reg__ clobbered by "mul"
384         ret
385 #else
386         clr     r_resHH         ; clear result
387         clr     r_resHL         ; clear result
388         clr     r_resH          ; clear result
389         clr     r_resL          ; clear result
390 __mulsi3_loop:
391         sbrs    r_arg1L,0
392         rjmp    __mulsi3_skip1
393         add     r_resL,r_arg2L          ; result + multiplicand
394         adc     r_resH,r_arg2H
395         adc     r_resHL,r_arg2HL
396         adc     r_resHH,r_arg2HH
397 __mulsi3_skip1:
398         add     r_arg2L,r_arg2L         ; shift multiplicand
399         adc     r_arg2H,r_arg2H
400         adc     r_arg2HL,r_arg2HL
401         adc     r_arg2HH,r_arg2HH
402         
403         lsr     r_arg1HH        ; gets LSB of multiplier
404         ror     r_arg1HL
405         ror     r_arg1H
406         ror     r_arg1L
407         brne    __mulsi3_loop
408         sbiw    r_arg1HL,0
409         cpc     r_arg1H,r_arg1L
410         brne    __mulsi3_loop           ; exit if multiplier = 0
411 __mulsi3_exit:
412         mov_h   r_arg1HH,r_resHH        ; result to return register
413         mov_l   r_arg1HL,r_resHL
414         mov_h   r_arg1H,r_resH
415         mov_l   r_arg1L,r_resL
416         ret
417 #endif /* defined (__AVR_HAVE_MUL__) */
418 #undef r_arg1L 
419 #undef r_arg1H 
420 #undef r_arg1HL
421 #undef r_arg1HH
422              
423              
424 #undef r_arg2L 
425 #undef r_arg2H 
426 #undef r_arg2HL
427 #undef r_arg2HH
428              
429 #undef r_resL  
430 #undef r_resH  
431 #undef r_resHL 
432 #undef r_resHH 
433
434 .endfunc
435 #endif /* defined (L_mulsi3) */
436         
437 /*******************************************************
438        Division 8 / 8 => (result + remainder)
439 *******************************************************/
440 #define r_rem   r25     /* remainder */
441 #define r_arg1  r24     /* dividend, quotient */
442 #define r_arg2  r22     /* divisor */
443 #define r_cnt   r23     /* loop count */
444
445 #if defined (L_udivmodqi4)
446         .global __udivmodqi4
447         .func   __udivmodqi4
448 __udivmodqi4:
449         sub     r_rem,r_rem     ; clear remainder and carry
450         ldi     r_cnt,9         ; init loop counter
451         rjmp    __udivmodqi4_ep ; jump to entry point
452 __udivmodqi4_loop:
453         rol     r_rem           ; shift dividend into remainder
454         cp      r_rem,r_arg2    ; compare remainder & divisor
455         brcs    __udivmodqi4_ep ; remainder <= divisor
456         sub     r_rem,r_arg2    ; restore remainder
457 __udivmodqi4_ep:
458         rol     r_arg1          ; shift dividend (with CARRY)
459         dec     r_cnt           ; decrement loop counter
460         brne    __udivmodqi4_loop
461         com     r_arg1          ; complement result 
462                                 ; because C flag was complemented in loop
463         ret
464         .endfunc
465 #endif /* defined (L_udivmodqi4) */
466
467 #if defined (L_divmodqi4)
468         .global __divmodqi4
469         .func   __divmodqi4
470 __divmodqi4:
471         bst     r_arg1,7        ; store sign of dividend
472         mov     __tmp_reg__,r_arg1
473         eor     __tmp_reg__,r_arg2; r0.7 is sign of result
474         sbrc    r_arg1,7
475         neg     r_arg1          ; dividend negative : negate
476         sbrc    r_arg2,7
477         neg     r_arg2          ; divisor negative : negate
478         rcall   __udivmodqi4    ; do the unsigned div/mod
479         brtc    __divmodqi4_1
480         neg     r_rem           ; correct remainder sign
481 __divmodqi4_1:
482         sbrc    __tmp_reg__,7
483         neg     r_arg1          ; correct result sign
484 __divmodqi4_exit:
485         ret
486         .endfunc
487 #endif /* defined (L_divmodqi4) */
488
489 #undef r_rem
490 #undef r_arg1
491 #undef r_arg2
492 #undef r_cnt
493         
494                 
495 /*******************************************************
496        Division 16 / 16 => (result + remainder)
497 *******************************************************/
498 #define r_remL  r26     /* remainder Low */
499 #define r_remH  r27     /* remainder High */
500
501 /* return: remainder */
502 #define r_arg1L r24     /* dividend Low */
503 #define r_arg1H r25     /* dividend High */
504
505 /* return: quotient */
506 #define r_arg2L r22     /* divisor Low */
507 #define r_arg2H r23     /* divisor High */
508         
509 #define r_cnt   r21     /* loop count */
510
511 #if defined (L_udivmodhi4)
512         .global __udivmodhi4
513         .func   __udivmodhi4
514 __udivmodhi4:
515         sub     r_remL,r_remL
516         sub     r_remH,r_remH   ; clear remainder and carry
517         ldi     r_cnt,17        ; init loop counter
518         rjmp    __udivmodhi4_ep ; jump to entry point
519 __udivmodhi4_loop:
520         rol     r_remL          ; shift dividend into remainder
521         rol     r_remH
522         cp      r_remL,r_arg2L  ; compare remainder & divisor
523         cpc     r_remH,r_arg2H
524         brcs    __udivmodhi4_ep ; remainder < divisor
525         sub     r_remL,r_arg2L  ; restore remainder
526         sbc     r_remH,r_arg2H
527 __udivmodhi4_ep:
528         rol     r_arg1L         ; shift dividend (with CARRY)
529         rol     r_arg1H
530         dec     r_cnt           ; decrement loop counter
531         brne    __udivmodhi4_loop
532         com     r_arg1L
533         com     r_arg1H
534 ; div/mod results to return registers, as for the div() function
535         mov_l   r_arg2L, r_arg1L        ; quotient
536         mov_h   r_arg2H, r_arg1H
537         mov_l   r_arg1L, r_remL         ; remainder
538         mov_h   r_arg1H, r_remH
539         ret
540         .endfunc
541 #endif /* defined (L_udivmodhi4) */
542
543 #if defined (L_divmodhi4)
544         .global __divmodhi4
545         .func   __divmodhi4
546 __divmodhi4:
547         .global _div
548 _div:
549         bst     r_arg1H,7       ; store sign of dividend
550         mov     __tmp_reg__,r_arg1H
551         eor     __tmp_reg__,r_arg2H   ; r0.7 is sign of result
552         rcall   __divmodhi4_neg1 ; dividend negative : negate
553         sbrc    r_arg2H,7
554         rcall   __divmodhi4_neg2 ; divisor negative : negate
555         rcall   __udivmodhi4    ; do the unsigned div/mod
556         rcall   __divmodhi4_neg1 ; correct remainder sign
557         tst     __tmp_reg__
558         brpl    __divmodhi4_exit
559 __divmodhi4_neg2:
560         com     r_arg2H
561         neg     r_arg2L         ; correct divisor/result sign
562         sbci    r_arg2H,0xff
563 __divmodhi4_exit:
564         ret
565 __divmodhi4_neg1:
566         brtc    __divmodhi4_exit
567         com     r_arg1H
568         neg     r_arg1L         ; correct dividend/remainder sign
569         sbci    r_arg1H,0xff
570         ret
571         .endfunc
572 #endif /* defined (L_divmodhi4) */
573
574 #undef r_remH  
575 #undef r_remL  
576              
577 #undef r_arg1H 
578 #undef r_arg1L 
579              
580 #undef r_arg2H 
581 #undef r_arg2L 
582                 
583 #undef r_cnt    
584         
585 /*******************************************************
586        Division 32 / 32 => (result + remainder)
587 *******************************************************/
588 #define r_remHH r31     /* remainder High */
589 #define r_remHL r30
590 #define r_remH  r27
591 #define r_remL  r26     /* remainder Low */
592
593 /* return: remainder */
594 #define r_arg1HH r25    /* dividend High */
595 #define r_arg1HL r24
596 #define r_arg1H  r23
597 #define r_arg1L  r22    /* dividend Low */
598
599 /* return: quotient */
600 #define r_arg2HH r21    /* divisor High */
601 #define r_arg2HL r20
602 #define r_arg2H  r19
603 #define r_arg2L  r18    /* divisor Low */
604         
605 #define r_cnt __zero_reg__  /* loop count (0 after the loop!) */
606
607 #if defined (L_udivmodsi4)
608         .global __udivmodsi4
609         .func   __udivmodsi4
610 __udivmodsi4:
611         ldi     r_remL, 33      ; init loop counter
612         mov     r_cnt, r_remL
613         sub     r_remL,r_remL
614         sub     r_remH,r_remH   ; clear remainder and carry
615         mov_l   r_remHL, r_remL
616         mov_h   r_remHH, r_remH
617         rjmp    __udivmodsi4_ep ; jump to entry point
618 __udivmodsi4_loop:
619         rol     r_remL          ; shift dividend into remainder
620         rol     r_remH
621         rol     r_remHL
622         rol     r_remHH
623         cp      r_remL,r_arg2L  ; compare remainder & divisor
624         cpc     r_remH,r_arg2H
625         cpc     r_remHL,r_arg2HL
626         cpc     r_remHH,r_arg2HH
627         brcs    __udivmodsi4_ep ; remainder <= divisor
628         sub     r_remL,r_arg2L  ; restore remainder
629         sbc     r_remH,r_arg2H
630         sbc     r_remHL,r_arg2HL
631         sbc     r_remHH,r_arg2HH
632 __udivmodsi4_ep:
633         rol     r_arg1L         ; shift dividend (with CARRY)
634         rol     r_arg1H
635         rol     r_arg1HL
636         rol     r_arg1HH
637         dec     r_cnt           ; decrement loop counter
638         brne    __udivmodsi4_loop
639                                 ; __zero_reg__ now restored (r_cnt == 0)
640         com     r_arg1L
641         com     r_arg1H
642         com     r_arg1HL
643         com     r_arg1HH
644 ; div/mod results to return registers, as for the ldiv() function
645         mov_l   r_arg2L,  r_arg1L       ; quotient
646         mov_h   r_arg2H,  r_arg1H
647         mov_l   r_arg2HL, r_arg1HL
648         mov_h   r_arg2HH, r_arg1HH
649         mov_l   r_arg1L,  r_remL        ; remainder
650         mov_h   r_arg1H,  r_remH
651         mov_l   r_arg1HL, r_remHL
652         mov_h   r_arg1HH, r_remHH
653         ret
654         .endfunc
655 #endif /* defined (L_udivmodsi4) */
656
657 #if defined (L_divmodsi4)
658         .global __divmodsi4
659         .func   __divmodsi4
660 __divmodsi4:
661         bst     r_arg1HH,7      ; store sign of dividend
662         mov     __tmp_reg__,r_arg1HH
663         eor     __tmp_reg__,r_arg2HH   ; r0.7 is sign of result
664         rcall   __divmodsi4_neg1 ; dividend negative : negate
665         sbrc    r_arg2HH,7
666         rcall   __divmodsi4_neg2 ; divisor negative : negate
667         rcall   __udivmodsi4    ; do the unsigned div/mod
668         rcall   __divmodsi4_neg1 ; correct remainder sign
669         rol     __tmp_reg__
670         brcc    __divmodsi4_exit
671 __divmodsi4_neg2:
672         com     r_arg2HH
673         com     r_arg2HL
674         com     r_arg2H
675         neg     r_arg2L         ; correct divisor/quotient sign
676         sbci    r_arg2H,0xff
677         sbci    r_arg2HL,0xff
678         sbci    r_arg2HH,0xff
679 __divmodsi4_exit:
680         ret
681 __divmodsi4_neg1:
682         brtc    __divmodsi4_exit
683         com     r_arg1HH
684         com     r_arg1HL
685         com     r_arg1H
686         neg     r_arg1L         ; correct dividend/remainder sign
687         sbci    r_arg1H, 0xff
688         sbci    r_arg1HL,0xff
689         sbci    r_arg1HH,0xff
690         ret
691         .endfunc
692 #endif /* defined (L_divmodsi4) */
693
694 /**********************************
695  * This is a prologue subroutine
696  **********************************/
697 #if defined (L_prologue)
698
699         .global __prologue_saves__
700         .func   __prologue_saves__
701 __prologue_saves__:
702         push r2
703         push r3
704         push r4
705         push r5
706         push r6
707         push r7
708         push r8
709         push r9
710         push r10
711         push r11
712         push r12
713         push r13
714         push r14
715         push r15
716         push r16
717         push r17
718         push r28
719         push r29
720         in      r28,__SP_L__
721         in      r29,__SP_H__
722         sub     r28,r26
723         sbc     r29,r27
724         in      __tmp_reg__,__SREG__
725         cli
726         out     __SP_H__,r29
727         out     __SREG__,__tmp_reg__
728         out     __SP_L__,r28
729 #if defined (__AVR_HAVE_EIJMP_EICALL__)
730         eijmp
731 #else
732         ijmp
733 #endif
734
735 .endfunc
736 #endif /* defined (L_prologue) */
737
738 /*
739  * This is an epilogue subroutine
740  */
741 #if defined (L_epilogue)
742
743         .global __epilogue_restores__
744         .func   __epilogue_restores__
745 __epilogue_restores__:
746         ldd     r2,Y+18
747         ldd     r3,Y+17
748         ldd     r4,Y+16
749         ldd     r5,Y+15
750         ldd     r6,Y+14
751         ldd     r7,Y+13
752         ldd     r8,Y+12
753         ldd     r9,Y+11
754         ldd     r10,Y+10
755         ldd     r11,Y+9
756         ldd     r12,Y+8
757         ldd     r13,Y+7
758         ldd     r14,Y+6
759         ldd     r15,Y+5
760         ldd     r16,Y+4
761         ldd     r17,Y+3
762         ldd     r26,Y+2
763         ldd     r27,Y+1
764         add     r28,r30
765         adc     r29,__zero_reg__
766         in      __tmp_reg__,__SREG__
767         cli
768         out     __SP_H__,r29
769         out     __SREG__,__tmp_reg__
770         out     __SP_L__,r28
771         mov_l   r28, r26
772         mov_h   r29, r27
773         ret
774 .endfunc
775 #endif /* defined (L_epilogue) */
776
777 #ifdef L_exit
778         .section .fini9,"ax",@progbits
779         .global _exit
780         .func   _exit
781 _exit:
782         .weak   exit
783 exit:
784         .endfunc
785
786         /* Code from .fini8 ... .fini1 sections inserted by ld script.  */
787
788         .section .fini0,"ax",@progbits
789         cli
790 __stop_program:
791         rjmp    __stop_program
792 #endif /* defined (L_exit) */
793
794 #ifdef L_cleanup
795         .weak   _cleanup
796         .func   _cleanup
797 _cleanup:
798         ret
799 .endfunc
800 #endif /* defined (L_cleanup) */
801
802 #ifdef L_tablejump
803         .global __tablejump2__
804         .func   __tablejump2__
805 __tablejump2__:
806         lsl     r30
807         rol     r31
808         .global __tablejump__
809 __tablejump__:
810 #if defined (__AVR_HAVE_LPMX__)
811         lpm     __tmp_reg__, Z+
812         lpm     r31, Z
813         mov     r30, __tmp_reg__
814
815 #if defined (__AVR_HAVE_EIJMP_EICALL__)
816         eijmp
817 #else
818         ijmp
819 #endif
820
821 #else
822         lpm
823         adiw    r30, 1
824         push    r0
825         lpm
826         push    r0
827 #if defined (__AVR_HAVE_EIJMP_EICALL__)
828         push    __zero_reg__
829 #endif
830         ret
831 #endif
832         .endfunc
833 #endif /* defined (L_tablejump) */
834
835 #ifdef L_copy_data
836         .section .init4,"ax",@progbits
837         .global __do_copy_data
838 __do_copy_data:
839 #if defined(__AVR_HAVE_ELPMX__)
840         ldi     r17, hi8(__data_end)
841         ldi     r26, lo8(__data_start)
842         ldi     r27, hi8(__data_start)
843         ldi     r30, lo8(__data_load_start)
844         ldi     r31, hi8(__data_load_start)
845         ldi     r16, hh8(__data_load_start)
846         out     __RAMPZ__, r16
847         rjmp    .L__do_copy_data_start
848 .L__do_copy_data_loop:
849         elpm    r0, Z+
850         st      X+, r0
851 .L__do_copy_data_start:
852         cpi     r26, lo8(__data_end)
853         cpc     r27, r17
854         brne    .L__do_copy_data_loop
855 #elif  !defined(__AVR_HAVE_ELPMX__) && defined(__AVR_HAVE_ELPM__)
856         ldi     r17, hi8(__data_end)
857         ldi     r26, lo8(__data_start)
858         ldi     r27, hi8(__data_start)
859         ldi     r30, lo8(__data_load_start)
860         ldi     r31, hi8(__data_load_start)
861         ldi     r16, hh8(__data_load_start - 0x10000)
862 .L__do_copy_data_carry:
863         inc     r16
864         out     __RAMPZ__, r16
865         rjmp    .L__do_copy_data_start
866 .L__do_copy_data_loop:
867         elpm
868         st      X+, r0
869         adiw    r30, 1
870         brcs    .L__do_copy_data_carry
871 .L__do_copy_data_start:
872         cpi     r26, lo8(__data_end)
873         cpc     r27, r17
874         brne    .L__do_copy_data_loop
875 #elif !defined(__AVR_HAVE_ELPMX__) && !defined(__AVR_HAVE_ELPM__)
876         ldi     r17, hi8(__data_end)
877         ldi     r26, lo8(__data_start)
878         ldi     r27, hi8(__data_start)
879         ldi     r30, lo8(__data_load_start)
880         ldi     r31, hi8(__data_load_start)
881         rjmp    .L__do_copy_data_start
882 .L__do_copy_data_loop:
883 #if defined (__AVR_HAVE_LPMX__)
884         lpm     r0, Z+
885 #else
886         lpm
887         adiw    r30, 1
888 #endif
889         st      X+, r0
890 .L__do_copy_data_start:
891         cpi     r26, lo8(__data_end)
892         cpc     r27, r17
893         brne    .L__do_copy_data_loop
894 #endif /* !defined(__AVR_HAVE_ELPMX__) && !defined(__AVR_HAVE_ELPM__) */
895 #endif /* L_copy_data */
896
897 /* __do_clear_bss is only necessary if there is anything in .bss section.  */
898
899 #ifdef L_clear_bss
900         .section .init4,"ax",@progbits
901         .global __do_clear_bss
902 __do_clear_bss:
903         ldi     r17, hi8(__bss_end)
904         ldi     r26, lo8(__bss_start)
905         ldi     r27, hi8(__bss_start)
906         rjmp    .do_clear_bss_start
907 .do_clear_bss_loop:
908         st      X+, __zero_reg__
909 .do_clear_bss_start:
910         cpi     r26, lo8(__bss_end)
911         cpc     r27, r17
912         brne    .do_clear_bss_loop
913 #endif /* L_clear_bss */
914
915 /* __do_global_ctors and __do_global_dtors are only necessary
916    if there are any constructors/destructors.  */
917
918 #ifdef L_ctors
919         .section .init6,"ax",@progbits
920         .global __do_global_ctors
921 #if defined(__AVR_HAVE_RAMPZ__)
922 __do_global_ctors:
923         ldi     r17, hi8(__ctors_start)
924         ldi     r28, lo8(__ctors_end)
925         ldi     r29, hi8(__ctors_end)
926         ldi     r16, hh8(__ctors_end)
927         rjmp    .L__do_global_ctors_start
928 .L__do_global_ctors_loop:
929         sbiw    r28, 2
930         sbc     r16, __zero_reg__
931         mov_h   r31, r29
932         mov_l   r30, r28
933         out     __RAMPZ__, r16
934         XCALL   __tablejump_elpm__
935 .L__do_global_ctors_start:
936         cpi     r28, lo8(__ctors_start)
937         cpc     r29, r17
938         ldi     r24, hh8(__ctors_start)
939         cpc     r16, r24
940         brne    .L__do_global_ctors_loop
941 #else
942 __do_global_ctors:
943         ldi     r17, hi8(__ctors_start)
944         ldi     r28, lo8(__ctors_end)
945         ldi     r29, hi8(__ctors_end)
946         rjmp    .L__do_global_ctors_start
947 .L__do_global_ctors_loop:
948         sbiw    r28, 2
949         mov_h   r31, r29
950         mov_l   r30, r28
951         XCALL   __tablejump__
952 .L__do_global_ctors_start:
953         cpi     r28, lo8(__ctors_start)
954         cpc     r29, r17
955         brne    .L__do_global_ctors_loop
956 #endif /* defined(__AVR_HAVE_RAMPZ__) */
957 #endif /* L_ctors */
958
959 #ifdef L_dtors
960         .section .fini6,"ax",@progbits
961         .global __do_global_dtors
962 #if defined(__AVR_HAVE_RAMPZ__)
963 __do_global_dtors:
964         ldi     r17, hi8(__dtors_end)
965         ldi     r28, lo8(__dtors_start)
966         ldi     r29, hi8(__dtors_start)
967         ldi     r16, hh8(__dtors_start)
968         rjmp    .L__do_global_dtors_start
969 .L__do_global_dtors_loop:
970         sbiw    r28, 2
971         sbc     r16, __zero_reg__
972         mov_h   r31, r29
973         mov_l   r30, r28
974         out     __RAMPZ__, r16
975         XCALL   __tablejump_elpm__
976 .L__do_global_dtors_start:
977         cpi     r28, lo8(__dtors_end)
978         cpc     r29, r17
979         ldi     r24, hh8(__dtors_end)
980         cpc     r16, r24
981         brne    .L__do_global_dtors_loop
982 #else
983 __do_global_dtors:
984         ldi     r17, hi8(__dtors_end)
985         ldi     r28, lo8(__dtors_start)
986         ldi     r29, hi8(__dtors_start)
987         rjmp    .L__do_global_dtors_start
988 .L__do_global_dtors_loop:
989         mov_h   r31, r29
990         mov_l   r30, r28
991         XCALL   __tablejump__
992         adiw    r28, 2
993 .L__do_global_dtors_start:
994         cpi     r28, lo8(__dtors_end)
995         cpc     r29, r17
996         brne    .L__do_global_dtors_loop
997 #endif /* defined(__AVR_HAVE_RAMPZ__) */
998 #endif /* L_dtors */
999
1000 #ifdef L_tablejump_elpm
1001         .global __tablejump_elpm__
1002         .func   __tablejump_elpm__
1003 __tablejump_elpm__:
1004 #if defined (__AVR_HAVE_ELPM__)
1005 #if defined (__AVR_HAVE_LPMX__)
1006         elpm    __tmp_reg__, Z+
1007         elpm    r31, Z
1008         mov     r30, __tmp_reg__
1009 #if defined (__AVR_HAVE_EIJMP_EICALL__)
1010         eijmp
1011 #else
1012         ijmp
1013 #endif
1014
1015 #else
1016         elpm
1017         adiw    r30, 1
1018         push    r0
1019         elpm
1020         push    r0
1021 #if defined (__AVR_HAVE_EIJMP_EICALL__)
1022         push    __zero_reg__
1023 #endif
1024         ret
1025 #endif
1026 #endif /* defined (__AVR_HAVE_ELPM__) */
1027         .endfunc
1028 #endif /* defined (L_tablejump_elpm) */
1029
1030 \f
1031 /**********************************
1032  * Find first set Bit (ffs)
1033  **********************************/
1034
1035 #if defined (L_ffssi2)
1036 ;; find first set bit
1037 ;; r25:r24 = ffs32 (r25:r22)
1038 ;; clobbers: r22, r26
1039 DEFUN __ffssi2
1040     clr  r26
1041     tst  r22
1042     brne 1f
1043     subi r26, -8
1044     or   r22, r23
1045     brne 1f
1046     subi r26, -8
1047     or   r22, r24
1048     brne 1f
1049     subi r26, -8
1050     or   r22, r25
1051     brne 1f
1052     ret
1053 1:  mov  r24, r22
1054     XJMP __loop_ffsqi2
1055 ENDF __ffssi2
1056 #endif /* defined (L_ffssi2) */
1057
1058 #if defined (L_ffshi2)
1059 ;; find first set bit
1060 ;; r25:r24 = ffs16 (r25:r24)
1061 ;; clobbers: r26
1062 DEFUN __ffshi2
1063     clr  r26
1064 #ifdef __AVR_HAVE_JMP_CALL__
1065     ;; Some cores have problem skipping 2-word instruction
1066     tst  r24
1067     breq 2f
1068 #else
1069     cpse r24, __zero_reg__
1070 #endif /* __AVR_HAVE_JMP_CALL__ */
1071 1:  XJMP __loop_ffsqi2
1072 2:  ldi  r26, 8
1073     or   r24, r25
1074     brne 1b
1075     ret
1076 ENDF __ffshi2
1077 #endif /* defined (L_ffshi2) */
1078
1079 #if defined (L_loop_ffsqi2)
1080 ;; Helper for ffshi2, ffssi2
1081 ;; r25:r24 = r26 + zero_extend16 (ffs8(r24))
1082 ;; r24 must be != 0
1083 ;; clobbers: r26
1084 DEFUN __loop_ffsqi2
1085     inc  r26
1086     lsr  r24
1087     brcc __loop_ffsqi2
1088     mov  r24, r26
1089     clr  r25
1090     ret    
1091 ENDF __loop_ffsqi2
1092 #endif /* defined (L_loop_ffsqi2) */
1093
1094 \f
1095 /**********************************
1096  * Count trailing Zeros (ctz)
1097  **********************************/
1098
1099 #if defined (L_ctzsi2)
1100 ;; count trailing zeros
1101 ;; r25:r24 = ctz32 (r25:r22)
1102 ;; clobbers: r26, r22
1103 ;; ctz(0) = 255
1104 ;; Note that ctz(0) in undefined for GCC
1105 DEFUN __ctzsi2
1106     XCALL __ffssi2
1107     dec  r24
1108     ret
1109 ENDF __ctzsi2
1110 #endif /* defined (L_ctzsi2) */
1111
1112 #if defined (L_ctzhi2)
1113 ;; count trailing zeros
1114 ;; r25:r24 = ctz16 (r25:r24)
1115 ;; clobbers: r26
1116 ;; ctz(0) = 255
1117 ;; Note that ctz(0) in undefined for GCC
1118 DEFUN __ctzhi2
1119     XCALL __ffshi2
1120     dec  r24
1121     ret
1122 ENDF __ctzhi2
1123 #endif /* defined (L_ctzhi2) */
1124
1125 \f
1126 /**********************************
1127  * Count leading Zeros (clz)
1128  **********************************/
1129
1130 #if defined (L_clzdi2)
1131 ;; count leading zeros
1132 ;; r25:r24 = clz64 (r25:r18)
1133 ;; clobbers: r22, r23, r26
1134 DEFUN __clzdi2
1135     XCALL __clzsi2
1136     sbrs r24, 5
1137     ret
1138     mov_l r22, r18
1139     mov_h r23, r19
1140     mov_l r24, r20
1141     mov_h r25, r21
1142     XCALL __clzsi2
1143     subi r24, -32
1144     ret
1145 ENDF __clzdi2
1146 #endif /* defined (L_clzdi2) */
1147
1148 #if defined (L_clzsi2)
1149 ;; count leading zeros
1150 ;; r25:r24 = clz32 (r25:r22)
1151 ;; clobbers: r26
1152 DEFUN __clzsi2
1153     XCALL __clzhi2
1154     sbrs r24, 4
1155     ret
1156     mov_l r24, r22
1157     mov_h r25, r23
1158     XCALL __clzhi2
1159     subi r24, -16
1160     ret
1161 ENDF __clzsi2
1162 #endif /* defined (L_clzsi2) */
1163
1164 #if defined (L_clzhi2)
1165 ;; count leading zeros
1166 ;; r25:r24 = clz16 (r25:r24)
1167 ;; clobbers: r26
1168 DEFUN __clzhi2
1169     clr  r26
1170     tst  r25
1171     brne 1f
1172     subi r26, -8
1173     or   r25, r24
1174     brne 1f
1175     ldi  r24, 16
1176     ret
1177 1:  cpi  r25, 16
1178     brsh 3f
1179     subi r26, -3
1180     swap r25
1181 2:  inc  r26
1182 3:  lsl  r25
1183     brcc 2b
1184     mov  r24, r26
1185     clr  r25
1186     ret
1187 ENDF __clzhi2
1188 #endif /* defined (L_clzhi2) */
1189
1190 \f
1191 /**********************************
1192  * Parity 
1193  **********************************/
1194
1195 #if defined (L_paritydi2)
1196 ;; r25:r24 = parity64 (r25:r18)
1197 ;; clobbers: __tmp_reg__
1198 DEFUN __paritydi2
1199     eor  r24, r18
1200     eor  r24, r19
1201     eor  r24, r20
1202     eor  r24, r21
1203     XJMP __paritysi2
1204 ENDF __paritydi2
1205 #endif /* defined (L_paritydi2) */
1206
1207 #if defined (L_paritysi2)
1208 ;; r25:r24 = parity32 (r25:r22)
1209 ;; clobbers: __tmp_reg__
1210 DEFUN __paritysi2
1211     eor  r24, r22
1212     eor  r24, r23
1213     XJMP __parityhi2
1214 ENDF __paritysi2
1215 #endif /* defined (L_paritysi2) */
1216
1217 #if defined (L_parityhi2)
1218 ;; r25:r24 = parity16 (r25:r24)
1219 ;; clobbers: __tmp_reg__
1220 DEFUN __parityhi2
1221     eor  r24, r25
1222 ;; FALLTHRU
1223 ENDF __parityhi2
1224
1225 ;; r25:r24 = parity8 (r24)
1226 ;; clobbers: __tmp_reg__
1227 DEFUN __parityqi2
1228     ;; parity is in r24[0..7]
1229     mov  __tmp_reg__, r24
1230     swap __tmp_reg__
1231     eor  r24, __tmp_reg__
1232     ;; parity is in r24[0..3]
1233     subi r24, -4
1234     andi r24, -5
1235     subi r24, -6
1236     ;; parity is in r24[0,3]
1237     sbrc r24, 3
1238     inc  r24
1239     ;; parity is in r24[0]
1240     andi r24, 1
1241     clr  r25
1242     ret
1243 ENDF __parityqi2
1244 #endif /* defined (L_parityhi2) */
1245
1246 \f
1247 /**********************************
1248  * Population Count
1249  **********************************/
1250
1251 #if defined (L_popcounthi2)
1252 ;; population count
1253 ;; r25:r24 = popcount16 (r25:r24)
1254 ;; clobbers: __tmp_reg__
1255 DEFUN __popcounthi2
1256     XCALL __popcountqi2
1257     push r24
1258     mov  r24, r25
1259     XCALL __popcountqi2
1260     clr  r25
1261     ;; FALLTHRU
1262 ENDF __popcounthi2
1263
1264 DEFUN __popcounthi2_tail
1265     pop   __tmp_reg__
1266     add   r24, __tmp_reg__
1267     ret
1268 ENDF __popcounthi2_tail
1269 #endif /* defined (L_popcounthi2) */
1270
1271 #if defined (L_popcountsi2)
1272 ;; population count
1273 ;; r25:r24 = popcount32 (r25:r22)
1274 ;; clobbers: __tmp_reg__
1275 DEFUN __popcountsi2
1276     XCALL __popcounthi2
1277     push  r24
1278     mov_l r24, r22
1279     mov_h r25, r23
1280     XCALL __popcounthi2
1281     XJMP  __popcounthi2_tail
1282 ENDF __popcountsi2
1283 #endif /* defined (L_popcountsi2) */
1284
1285 #if defined (L_popcountdi2)
1286 ;; population count
1287 ;; r25:r24 = popcount64 (r25:r18)
1288 ;; clobbers: r22, r23, __tmp_reg__
1289 DEFUN __popcountdi2
1290     XCALL __popcountsi2
1291     push  r24
1292     mov_l r22, r18
1293     mov_h r23, r19
1294     mov_l r24, r20
1295     mov_h r25, r21
1296     XCALL __popcountsi2
1297     XJMP  __popcounthi2_tail
1298 ENDF __popcountdi2
1299 #endif /* defined (L_popcountdi2) */
1300
1301 #if defined (L_popcountqi2)
1302 ;; population count
1303 ;; r24 = popcount8 (r24)
1304 ;; clobbers: __tmp_reg__
1305 DEFUN __popcountqi2
1306     mov  __tmp_reg__, r24
1307     andi r24, 1
1308     lsr  __tmp_reg__    
1309     lsr  __tmp_reg__    
1310     adc  r24, __zero_reg__
1311     lsr  __tmp_reg__    
1312     adc  r24, __zero_reg__
1313     lsr  __tmp_reg__    
1314     adc  r24, __zero_reg__
1315     lsr  __tmp_reg__    
1316     adc  r24, __zero_reg__
1317     lsr  __tmp_reg__    
1318     adc  r24, __zero_reg__
1319     lsr  __tmp_reg__    
1320     adc  r24, __tmp_reg__    
1321     ret    
1322 ENDF __popcountqi2
1323 #endif /* defined (L_popcountqi2) */
1324
1325 \f
1326 /**********************************
1327  * Swap bytes
1328  **********************************/
1329
1330 ;; swap two registers with different register number
1331 .macro bswap a, b
1332     eor \a, \b
1333     eor \b, \a
1334     eor \a, \b
1335 .endm
1336
1337 #if defined (L_bswapsi2)
1338 ;; swap bytes
1339 ;; r25:r22 = bswap32 (r25:r22)
1340 DEFUN __bswapsi2
1341     bswap r22, r25
1342     bswap r23, r24
1343     ret
1344 ENDF __bswapsi2
1345 #endif /* defined (L_bswapsi2) */
1346
1347 #if defined (L_bswapdi2)
1348 ;; swap bytes
1349 ;; r25:r18 = bswap64 (r25:r18)
1350 DEFUN __bswapdi2
1351     bswap r18, r25
1352     bswap r19, r24
1353     bswap r20, r23
1354     bswap r21, r22
1355     ret
1356 ENDF __bswapdi2
1357 #endif /* defined (L_bswapdi2) */
1358
1359 \f
1360 /**********************************
1361  * 64-bit shifts
1362  **********************************/
1363
1364 #if defined (L_ashrdi3)
1365 ;; Arithmetic shift right
1366 ;; r25:r18 = ashr64 (r25:r18, r17:r16)
1367 DEFUN __ashrdi3
1368     push r16
1369     andi r16, 63
1370     breq 2f
1371 1:  asr  r25
1372     ror  r24
1373     ror  r23
1374     ror  r22
1375     ror  r21
1376     ror  r20
1377     ror  r19
1378     ror  r18
1379     dec  r16
1380     brne 1b
1381 2:  pop  r16
1382     ret
1383 ENDF __ashrdi3
1384 #endif /* defined (L_ashrdi3) */
1385
1386 #if defined (L_lshrdi3)
1387 ;; Logic shift right
1388 ;; r25:r18 = lshr64 (r25:r18, r17:r16)
1389 DEFUN __lshrdi3
1390     push r16
1391     andi r16, 63
1392     breq 2f
1393 1:  lsr  r25
1394     ror  r24
1395     ror  r23
1396     ror  r22
1397     ror  r21
1398     ror  r20
1399     ror  r19
1400     ror  r18
1401     dec  r16
1402     brne 1b
1403 2:  pop  r16
1404     ret
1405 ENDF __lshrdi3
1406 #endif /* defined (L_lshrdi3) */
1407
1408 #if defined (L_ashldi3)
1409 ;; Shift left
1410 ;; r25:r18 = ashl64 (r25:r18, r17:r16)
1411 DEFUN __ashldi3
1412     push r16
1413     andi r16, 63
1414     breq 2f
1415 1:  lsl  r18
1416     rol  r19
1417     rol  r20
1418     rol  r21
1419     rol  r22
1420     rol  r23
1421     rol  r24
1422     rol  r25
1423     dec  r16
1424     brne 1b
1425 2:  pop  r16
1426     ret
1427 ENDF __ashldi3
1428 #endif /* defined (L_ashldi3) */
1429
1430
1431 /***********************************************************/    
1432 ;;; Softmul versions of FMUL, FMULS and FMULSU to implement
1433 ;;; __builtin_avr_fmul* if !AVR_HAVE_MUL
1434 /***********************************************************/    
1435
1436 #define A1 24
1437 #define B1 25
1438 #define C0 22
1439 #define C1 23
1440 #define A0 __tmp_reg__
1441
1442 #ifdef L_fmuls
1443 ;;; r23:r22 = fmuls (r24, r25) like in FMULS instruction
1444 ;;; Clobbers: r24, r25, __tmp_reg__
1445 DEFUN __fmuls
1446     ;; A0.7 = negate result?
1447     mov  A0, A1
1448     eor  A0, B1
1449     ;; B1 = |B1|
1450     sbrc B1, 7
1451     neg  B1
1452     XJMP __fmulsu_exit
1453 ENDF __fmuls
1454 #endif /* L_fmuls */
1455
1456 #ifdef L_fmulsu
1457 ;;; r23:r22 = fmulsu (r24, r25) like in FMULSU instruction
1458 ;;; Clobbers: r24, r25, __tmp_reg__
1459 DEFUN __fmulsu
1460     ;; A0.7 = negate result?
1461     mov  A0, A1
1462 ;; FALLTHRU
1463 ENDF __fmulsu
1464
1465 ;; Helper for __fmuls and __fmulsu
1466 DEFUN __fmulsu_exit
1467     ;; A1 = |A1|
1468     sbrc A1, 7
1469     neg  A1
1470 #ifdef __AVR_HAVE_JMP_CALL__
1471     ;; Some cores have problem skipping 2-word instruction
1472     tst  A0
1473     brmi 1f
1474 #else
1475     sbrs A0, 7
1476 #endif /* __AVR_HAVE_JMP_CALL__ */
1477     XJMP  __fmul
1478 1:  XCALL __fmul
1479     ;; C = -C iff A0.7 = 1
1480     com  C1
1481     neg  C0
1482     sbci C1, -1
1483     ret
1484 ENDF __fmulsu_exit
1485 #endif /* L_fmulsu */
1486
1487
1488 #ifdef L_fmul
1489 ;;; r22:r23 = fmul (r24, r25) like in FMUL instruction
1490 ;;; Clobbers: r24, r25, __tmp_reg__
1491 DEFUN __fmul
1492     ; clear result
1493     clr   C0
1494     clr   C1
1495     clr   A0
1496 1:  tst   B1
1497     ;; 1.0 = 0x80, so test for bit 7 of B to see if A must to be added to C.
1498 2:  brpl  3f
1499     ;; C += A
1500     add   C0, A0
1501     adc   C1, A1
1502 3:  ;; A >>= 1
1503     lsr   A1
1504     ror   A0
1505     ;; B <<= 1
1506     lsl   B1
1507     brne  2b
1508     ret
1509 ENDF __fmul
1510 #endif /* L_fmul */
1511
1512 #undef A0
1513 #undef A1
1514 #undef B1
1515 #undef C0
1516 #undef C1