OSDN Git Service

* config/avr/avr.c (ret_cond_branch): New argument (reverse) added.
[pf3gnuchains/gcc-fork.git] / gcc / config / avr / libgcc.S
1 /*  -*- Mode: Asm -*-  */
2 /* Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
3    Contributed by Denis Chertykov <denisc@overta.ru>
4
5 This file is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option) any
8 later version.
9
10 In addition to the permissions in the GNU General Public License, the
11 Free Software Foundation gives you unlimited permission to link the
12 compiled version of this file into combinations with other programs,
13 and to distribute those combinations without any restriction coming
14 from the use of this file.  (The General Public License restrictions
15 do apply in other respects; for example, they cover modification of
16 the file, and distribution when not linked into a combine
17 executable.)
18
19 This file is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; see the file COPYING.  If not, write to
26 the Free Software Foundation, 59 Temple Place - Suite 330,
27 Boston, MA 02111-1307, 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_ENHANCED__)
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_ENHANCED__)
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         cpc     r_arg2L,__zero_reg__
141         breq    __mulhi3_exit   ; while multiplicand != 0
142
143         lsr     r_arg1H         ; gets LSB of multiplier
144         ror     r_arg1L
145         cpc     r_arg1H,__zero_reg__
146         brne    __mulhi3_loop   ; exit if multiplier = 0
147 __mulhi3_exit:
148         mov     r_arg1H,r_resH  ; result to return register
149         mov     r_arg1L,r_resL
150         ret
151
152 #undef r_arg1L
153 #undef r_arg1H
154 #undef r_arg2L
155 #undef r_arg2H
156 #undef r_resL   
157 #undef r_resH 
158
159 .endfunc
160 #endif /* defined (L_mulhi3) */
161 #endif /* !defined (__AVR_ENHANCED__) */
162
163 #if defined (L_mulhisi3)
164         .global __mulhisi3
165         .func   __mulhisi3
166 __mulhisi3:
167         mov_l   r18, r24
168         mov_h   r19, r25
169         clr     r24
170         sbrc    r23, 7
171         dec     r24
172         mov     r25, r24
173         clr     r20
174         sbrc    r19, 7
175         dec     r20
176         mov     r21, r20
177         rjmp    __mulsi3
178         .endfunc
179 #endif /* defined (L_mulhisi3) */
180
181 #if defined (L_umulhisi3)
182         .global __umulhisi3
183         .func   __umulhisi3
184 __umulhisi3:
185         mov_l   r18, r24
186         mov_h   r19, r25
187         clr     r24
188         clr     r25
189         clr     r20
190         clr     r21
191         rjmp    __mulsi3
192         .endfunc
193 #endif /* defined (L_umulhisi3) */
194
195 #if defined (L_mulsi3)
196 /*******************************************************
197                Multiplication  32 x 32
198 *******************************************************/
199 #define r_arg1L  r22            /* multiplier Low */
200 #define r_arg1H  r23
201 #define r_arg1HL r24
202 #define r_arg1HH r25            /* multiplier High */
203
204
205 #define r_arg2L  r18            /* multiplicand Low */
206 #define r_arg2H  r19    
207 #define r_arg2HL r20
208 #define r_arg2HH r21            /* multiplicand High */
209         
210 #define r_resL   r26            /* result Low */
211 #define r_resH   r27
212 #define r_resHL  r30
213 #define r_resHH  r31            /* result High */
214
215         
216         .global __mulsi3
217         .func   __mulsi3
218 __mulsi3:
219 #if defined (__AVR_ENHANCED__)
220         mul     r_arg1L, r_arg2L
221         movw    r_resL, r0
222         mul     r_arg1H, r_arg2H
223         movw    r_resHL, r0
224         mul     r_arg1HL, r_arg2L
225         add     r_resHL, r0
226         adc     r_resHH, r1
227         mul     r_arg1L, r_arg2HL
228         add     r_resHL, r0
229         adc     r_resHH, r1
230         mul     r_arg1HH, r_arg2L
231         add     r_resHH, r0
232         mul     r_arg1HL, r_arg2H
233         add     r_resHH, r0
234         mul     r_arg1H, r_arg2HL
235         add     r_resHH, r0
236         mul     r_arg1L, r_arg2HH
237         add     r_resHH, r0
238         clr     r_arg1HH        ; use instead of __zero_reg__ to add carry
239         mul     r_arg1H, r_arg2L
240         add     r_resH, r0
241         adc     r_resHL, r1
242         adc     r_resHH, r_arg1HH ; add carry
243         mul     r_arg1L, r_arg2H
244         add     r_resH, r0
245         adc     r_resHL, r1
246         adc     r_resHH, r_arg1HH ; add carry
247         movw    r_arg1L, r_resL
248         movw    r_arg1HL, r_resHL
249         clr     r1              ; __zero_reg__ clobbered by "mul"
250         ret
251 #else
252         clr     r_resHH         ; clear result
253         clr     r_resHL         ; clear result
254         clr     r_resH          ; clear result
255         clr     r_resL          ; clear result
256 __mulsi3_loop:
257         sbrs    r_arg1L,0
258         rjmp    __mulsi3_skip1
259         add     r_resL,r_arg2L          ; result + multiplicand
260         adc     r_resH,r_arg2H
261         adc     r_resHL,r_arg2HL
262         adc     r_resHH,r_arg2HH
263 __mulsi3_skip1:
264         add     r_arg2L,r_arg2L         ; shift multiplicand
265         adc     r_arg2H,r_arg2H
266         adc     r_arg2HL,r_arg2HL
267         adc     r_arg2HH,r_arg2HH
268         
269         lsr     r_arg1HH        ; gets LSB of multiplier
270         ror     r_arg1HL
271         ror     r_arg1H
272         ror     r_arg1L
273         brne    __mulsi3_loop
274         sbiw    r_arg1HL,0
275         cpc     r_arg1H,r_arg1L
276         brne    __mulsi3_loop           ; exit if multiplier = 0
277 __mulsi3_exit:
278         mov     r_arg1HH,r_resHH        ; result to return register
279         mov     r_arg1HL,r_resHL
280         mov     r_arg1H,r_resH
281         mov     r_arg1L,r_resL
282         ret
283 #endif /* !defined (__AVR_ENHANCED__) */
284 #undef r_arg1L 
285 #undef r_arg1H 
286 #undef r_arg1HL
287 #undef r_arg1HH
288              
289              
290 #undef r_arg2L 
291 #undef r_arg2H 
292 #undef r_arg2HL
293 #undef r_arg2HH
294              
295 #undef r_resL  
296 #undef r_resH  
297 #undef r_resHL 
298 #undef r_resHH 
299
300 .endfunc
301 #endif /* defined (L_mulsi3) */
302         
303 /*******************************************************
304        Division 8 / 8 => (result + remainder)
305 *******************************************************/
306 #define r_rem   r25     /* remainder */
307 #define r_arg1  r24     /* dividend, quotient */
308 #define r_arg2  r22     /* divisor */
309 #define r_cnt   r23     /* loop count */
310
311 #if defined (L_udivmodqi4)
312         .global __udivmodqi4
313         .func   __udivmodqi4
314 __udivmodqi4:
315         sub     r_rem,r_rem     ; clear remainder and carry
316         ldi     r_cnt,9         ; init loop counter
317         rjmp    __udivmodqi4_ep ; jump to entry point
318 __udivmodqi4_loop:
319         rol     r_rem           ; shift dividend into remainder
320         cp      r_rem,r_arg2    ; compare remainder & divisor
321         brcs    __udivmodqi4_ep ; remainder <= divisor
322         sub     r_rem,r_arg2    ; restore remainder
323 __udivmodqi4_ep:
324         rol     r_arg1          ; shift dividend (with CARRY)
325         dec     r_cnt           ; decrement loop counter
326         brne    __udivmodqi4_loop
327         com     r_arg1          ; complement result 
328                                 ; because C flag was complemented in loop
329         ret
330         .endfunc
331 #endif /* defined (L_udivmodqi4) */
332
333 #if defined (L_divmodqi4)
334         .global __divmodqi4
335         .func   __divmodqi4
336 __divmodqi4:
337         bst     r_arg1,7        ; store sign of dividend
338         mov     __tmp_reg__,r_arg1
339         eor     __tmp_reg__,r_arg2; r0.7 is sign of result
340         sbrc    r_arg1,7
341         neg     r_arg1          ; dividend negative : negate
342         sbrc    r_arg2,7
343         neg     r_arg2          ; divisor negative : negate
344         rcall   __udivmodqi4    ; do the unsigned div/mod
345         brtc    __divmodqi4_1
346         neg     r_rem           ; correct remainder sign
347 __divmodqi4_1:
348         sbrc    __tmp_reg__,7
349         neg     r_arg1          ; correct result sign
350 __divmodqi4_exit:
351         ret
352         .endfunc
353 #endif /* defined (L_divmodqi4) */
354
355 #undef r_rem
356 #undef r_arg1
357 #undef r_arg2
358 #undef r_cnt
359         
360                 
361 /*******************************************************
362        Division 16 / 16 => (result + remainder)
363 *******************************************************/
364 #define r_remL  r26     /* remainder Low */
365 #define r_remH  r27     /* remainder High */
366
367 /* return: remainder */
368 #define r_arg1L r24     /* dividend Low */
369 #define r_arg1H r25     /* dividend High */
370
371 /* return: quotient */
372 #define r_arg2L r22     /* divisor Low */
373 #define r_arg2H r23     /* divisor High */
374         
375 #define r_cnt   r21     /* loop count */
376
377 #if defined (L_udivmodhi4)
378         .global __udivmodhi4
379         .func   __udivmodhi4
380 __udivmodhi4:
381         sub     r_remL,r_remL
382         sub     r_remH,r_remH   ; clear remainder and carry
383         ldi     r_cnt,17        ; init loop counter
384         rjmp    __udivmodhi4_ep ; jump to entry point
385 __udivmodhi4_loop:
386         rol     r_remL          ; shift dividend into remainder
387         rol     r_remH
388         cp      r_remL,r_arg2L  ; compare remainder & divisor
389         cpc     r_remH,r_arg2H
390         brcs    __udivmodhi4_ep ; remainder < divisor
391         sub     r_remL,r_arg2L  ; restore remainder
392         sbc     r_remH,r_arg2H
393 __udivmodhi4_ep:
394         rol     r_arg1L         ; shift dividend (with CARRY)
395         rol     r_arg1H
396         dec     r_cnt           ; decrement loop counter
397         brne    __udivmodhi4_loop
398         com     r_arg1L
399         com     r_arg1H
400 ; div/mod results to return registers, as for the div() function
401         mov_l   r_arg2L, r_arg1L        ; quotient
402         mov_h   r_arg2H, r_arg1H
403         mov_l   r_arg1L, r_remL         ; remainder
404         mov_h   r_arg1H, r_remH
405         ret
406         .endfunc
407 #endif /* defined (L_udivmodhi4) */
408
409 #if defined (L_divmodhi4)
410         .global __divmodhi4
411         .func   __divmodhi4
412 __divmodhi4:
413         .global _div
414 _div:
415         bst     r_arg1H,7       ; store sign of dividend
416         mov     __tmp_reg__,r_arg1H
417         eor     __tmp_reg__,r_arg2H   ; r0.7 is sign of result
418         rcall   __divmodhi4_neg1 ; dividend negative : negate
419         sbrc    r_arg2H,7
420         rcall   __divmodhi4_neg2 ; divisor negative : negate
421         rcall   __udivmodhi4    ; do the unsigned div/mod
422         rcall   __divmodhi4_neg1 ; correct remainder sign
423         tst     __tmp_reg__
424         brpl    __divmodhi4_exit
425 __divmodhi4_neg2:
426         com     r_arg2H
427         neg     r_arg2L         ; correct divisor/result sign
428         sbci    r_arg2H,0xff
429 __divmodhi4_exit:
430         ret
431 __divmodhi4_neg1:
432         brtc    __divmodhi4_exit
433         com     r_arg1H
434         neg     r_arg1L         ; correct dividend/remainder sign
435         sbci    r_arg1H,0xff
436         ret
437         .endfunc
438 #endif /* defined (L_divmodhi4) */
439
440 #undef r_remH  
441 #undef r_remL  
442              
443 #undef r_arg1H 
444 #undef r_arg1L 
445              
446 #undef r_arg2H 
447 #undef r_arg2L 
448                 
449 #undef r_cnt    
450         
451 /*******************************************************
452        Division 32 / 32 => (result + remainder)
453 *******************************************************/
454 #define r_remHH r31     /* remainder High */
455 #define r_remHL r30
456 #define r_remH  r27
457 #define r_remL  r26     /* remainder Low */
458
459 /* return: remainder */
460 #define r_arg1HH r25    /* dividend High */
461 #define r_arg1HL r24
462 #define r_arg1H  r23
463 #define r_arg1L  r22    /* dividend Low */
464
465 /* return: quotient */
466 #define r_arg2HH r21    /* divisor High */
467 #define r_arg2HL r20
468 #define r_arg2H  r19
469 #define r_arg2L  r18    /* divisor Low */
470         
471 #define r_cnt __zero_reg__  /* loop count (0 after the loop!) */
472
473 #if defined (L_udivmodsi4)
474         .global __udivmodsi4
475         .func   __udivmodsi4
476 __udivmodsi4:
477         ldi     r_remL, 33      ; init loop counter
478         mov     r_cnt, r_remL
479         sub     r_remL,r_remL
480         sub     r_remH,r_remH   ; clear remainder and carry
481         mov_l   r_remHL, r_remL
482         mov_h   r_remHH, r_remH
483         rjmp    __udivmodsi4_ep ; jump to entry point
484 __udivmodsi4_loop:
485         rol     r_remL          ; shift dividend into remainder
486         rol     r_remH
487         rol     r_remHL
488         rol     r_remHH
489         cp      r_remL,r_arg2L  ; compare remainder & divisor
490         cpc     r_remH,r_arg2H
491         cpc     r_remHL,r_arg2HL
492         cpc     r_remHH,r_arg2HH
493         brcs    __udivmodsi4_ep ; remainder <= divisor
494         sub     r_remL,r_arg2L  ; restore remainder
495         sbc     r_remH,r_arg2H
496         sbc     r_remHL,r_arg2HL
497         sbc     r_remHH,r_arg2HH
498 __udivmodsi4_ep:
499         rol     r_arg1L         ; shift dividend (with CARRY)
500         rol     r_arg1H
501         rol     r_arg1HL
502         rol     r_arg1HH
503         dec     r_cnt           ; decrement loop counter
504         brne    __udivmodsi4_loop
505                                 ; __zero_reg__ now restored (r_cnt == 0)
506         com     r_arg1L
507         com     r_arg1H
508         com     r_arg1HL
509         com     r_arg1HH
510 ; div/mod results to return registers, as for the ldiv() function
511         mov_l   r_arg2L,  r_arg1L       ; quotient
512         mov_h   r_arg2H,  r_arg1H
513         mov_l   r_arg2HL, r_arg1HL
514         mov_h   r_arg2HH, r_arg1HH
515         mov_l   r_arg1L,  r_remL        ; remainder
516         mov_h   r_arg1H,  r_remH
517         mov_l   r_arg1HL, r_remHL
518         mov_h   r_arg1HH, r_remHH
519         ret
520         .endfunc
521 #endif /* defined (L_udivmodsi4) */
522
523 #if defined (L_divmodsi4)
524         .global __divmodsi4
525         .func   __divmodsi4
526 __divmodsi4:
527         bst     r_arg1HH,7      ; store sign of dividend
528         mov     __tmp_reg__,r_arg1HH
529         eor     __tmp_reg__,r_arg2HH   ; r0.7 is sign of result
530         rcall   __divmodsi4_neg1 ; dividend negative : negate
531         sbrc    r_arg2HH,7
532         rcall   __divmodsi4_neg2 ; divisor negative : negate
533         rcall   __udivmodsi4    ; do the unsigned div/mod
534         rcall   __divmodsi4_neg1 ; correct remainder sign
535         rol     __tmp_reg__
536         brcc    __divmodsi4_exit
537 __divmodsi4_neg2:
538         com     r_arg2HH
539         com     r_arg2HL
540         com     r_arg2H
541         neg     r_arg2L         ; correct divisor/quotient sign
542         sbci    r_arg2H,0xff
543         sbci    r_arg2HL,0xff
544         sbci    r_arg2HH,0xff
545 __divmodsi4_exit:
546         ret
547 __divmodsi4_neg1:
548         brtc    __divmodsi4_exit
549         com     r_arg1HH
550         com     r_arg1HL
551         com     r_arg1H
552         neg     r_arg1L         ; correct dividend/remainder sign
553         sbci    r_arg1H, 0xff
554         sbci    r_arg1HL,0xff
555         sbci    r_arg1HH,0xff
556         ret
557         .endfunc
558 #endif /* defined (L_divmodsi4) */
559
560 /**********************************
561  * This is a prologue subroutine
562  **********************************/
563 #if defined (L_prologue)
564
565         .global __prologue_saves__
566         .func   __prologue_saves__
567 __prologue_saves__:
568         push r2
569         push r3
570         push r4
571         push r5
572         push r6
573         push r7
574         push r8
575         push r9
576         push r10
577         push r11
578         push r12
579         push r13
580         push r14
581         push r15
582         push r16
583         push r17
584         push r28
585         push r29
586         in      r28,__SP_L__
587         in      r29,__SP_H__
588         sub     r28,r26
589         sbc     r29,r27
590         in      __tmp_reg__,__SREG__
591         cli
592         out     __SP_H__,r29
593         out     __SREG__,__tmp_reg__
594         out     __SP_L__,r28
595         ijmp
596 .endfunc
597 #endif /* defined (L_prologue) */
598
599 /*
600  * This is an epilogue subroutine
601  */
602 #if defined (L_epilogue)
603
604         .global __epilogue_restores__
605         .func   __epilogue_restores__
606 __epilogue_restores__:
607         ldd     r2,Y+18
608         ldd     r3,Y+17
609         ldd     r4,Y+16
610         ldd     r5,Y+15
611         ldd     r6,Y+14
612         ldd     r7,Y+13
613         ldd     r8,Y+12
614         ldd     r9,Y+11
615         ldd     r10,Y+10
616         ldd     r11,Y+9
617         ldd     r12,Y+8
618         ldd     r13,Y+7
619         ldd     r14,Y+6
620         ldd     r15,Y+5
621         ldd     r16,Y+4
622         ldd     r17,Y+3
623         ldd     r26,Y+2
624         ldd     r27,Y+1
625         add     r28,r30
626         adc     r29,__zero_reg__
627         in      __tmp_reg__,__SREG__
628         cli
629         out     __SP_H__,r29
630         out     __SREG__,__tmp_reg__
631         out     __SP_L__,r28
632         mov_l   r28, r26
633         mov_h   r29, r27
634         ret
635 .endfunc
636 #endif /* defined (L_epilogue) */
637
638 #ifdef L_exit
639         .weak   _exit
640         .func   _exit
641 _exit:
642         rjmp    _exit
643 .endfunc
644 #endif /* defined (L_exit) */
645
646 #ifdef L_cleanup
647         .weak   _cleanup
648         .func   _cleanup
649 _cleanup:
650         ret
651 .endfunc
652 #endif /* defined (L_cleanup) */
653
654 #ifdef L_tablejump
655         .global __tablejump2__
656         .func   __tablejump2__
657 __tablejump2__:
658         lsl     r30
659         rol     r31
660 #if defined (__AVR_ENHANCED__)
661         lpm     __tmp_reg__, Z+
662         lpm     r31, Z
663         mov     r30, __tmp_reg__
664         ijmp
665 #else
666         lpm
667         push    r0
668         inc     r30     ; table is word aligned, no carry to high byte
669         lpm
670         push    r0
671         ret
672 #endif
673 .endfunc
674 #endif /* defined (L_tablejump) */
675