]> gcc.gnu.org Git - gcc.git/blob - gcc/config/avr/libgcc.S
avr.md ("*negsi2"): substitute %@ to __zero_reg__
[gcc.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 .section .text.libgcc, "ax", @progbits
36
37 /* Note: mulqi3, mulhi3 are open-coded on the enhanced core. */
38 #if !defined (__AVR_ENHANCED__)
39 /*******************************************************
40 Multiplication 8 x 8
41 *******************************************************/
42 #if defined (L_mulqi3)
43
44 #define r_arg2 r22 /* multiplicand */
45 #define r_arg1 r24 /* multiplier */
46 #define r_res __tmp_reg__ /* result */
47
48 .global __mulqi3
49 .func __mulqi3
50 __mulqi3:
51 clr r_res ; clear result
52 __mulqi3_loop:
53 sbrc r_arg1,0
54 add r_res,r_arg2
55 add r_arg2,r_arg2 ; shift multiplicand
56 breq __mulqi3_exit ; while multiplicand != 0
57 lsr r_arg1 ;
58 brne __mulqi3_loop ; exit if multiplier = 0
59 __mulqi3_exit:
60 mov r_arg1,r_res ; result to return register
61 ret
62
63 #undef r_arg2
64 #undef r_arg1
65 #undef r_res
66
67 .endfunc
68 #endif /* defined (L_mulqi3) */
69
70
71 /*******************************************************
72 Multiplication 16 x 16
73 *******************************************************/
74 #if defined (L_mulhi3)
75 #define r_arg1L r24 /* multiplier Low */
76 #define r_arg1H r25 /* multiplier High */
77 #define r_arg2L r22 /* multiplicand Low */
78 #define r_arg2H r23 /* multiplicand High */
79 #define r_resL r20 /* result Low */
80 #define r_resH r21 /* result High */
81
82 .global __mulhi3
83 .func __mulhi3
84 __mulhi3:
85 clr r_resH ; clear result
86 clr r_resL ; clear result
87 __mulhi3_loop:
88 sbrs r_arg1L,0
89 rjmp __mulhi3_skip1
90 add r_resL,r_arg2L ; result + multiplicand
91 adc r_resH,r_arg2H
92 __mulhi3_skip1:
93 add r_arg2L,r_arg2L ; shift multiplicand
94 adc r_arg2H,r_arg2H
95
96 cpc r_arg2L,__zero_reg__
97 breq __mulhi3_exit ; while multiplicand != 0
98
99 lsr r_arg1H ; gets LSB of multiplier
100 ror r_arg1L
101 cpc r_arg1H,__zero_reg__
102 brne __mulhi3_loop ; exit if multiplier = 0
103 __mulhi3_exit:
104 mov r_arg1H,r_resH ; result to return register
105 mov r_arg1L,r_resL
106 ret
107
108 #undef r_arg1L
109 #undef r_arg1H
110 #undef r_arg2L
111 #undef r_arg2H
112 #undef r_resL
113 #undef r_resH
114
115 .endfunc
116 #endif /* defined (L_mulhi3) */
117 #endif /* !defined (__AVR_ENHANCED__) */
118
119 #if defined (L_mulsi3)
120 /*******************************************************
121 Multiplication 32 x 32
122 *******************************************************/
123 #define r_arg1L r22 /* multiplier Low */
124 #define r_arg1H r23
125 #define r_arg1HL r24
126 #define r_arg1HH r25 /* multiplier High */
127
128
129 #define r_arg2L r18 /* multiplicand Low */
130 #define r_arg2H r19
131 #define r_arg2HL r20
132 #define r_arg2HH r21 /* multiplicand High */
133
134 #define r_resL r26 /* result Low */
135 #define r_resH r27
136 #define r_resHL r30
137 #define r_resHH r31 /* result High */
138
139
140 .global __mulsi3
141 .func __mulsi3
142 __mulsi3:
143 #if defined (__AVR_ENHANCED__)
144 mul r_arg1L, r_arg2L
145 movw r_resL, r0
146 mul r_arg1H, r_arg2H
147 movw r_resHL, r0
148 mul r_arg1HL, r_arg2L
149 add r_resHL, r0
150 adc r_resHH, r1
151 mul r_arg1L, r_arg2HL
152 add r_resHL, r0
153 adc r_resHH, r1
154 mul r_arg1HH, r_arg2L
155 add r_resHH, r0
156 mul r_arg1HL, r_arg2H
157 add r_resHH, r0
158 mul r_arg1H, r_arg2HL
159 add r_resHH, r0
160 mul r_arg1L, r_arg2HH
161 add r_resHH, r0
162 clr r_arg1HH ; use instead of __zero_reg__ to add carry
163 mul r_arg1H, r_arg2L
164 add r_resH, r0
165 adc r_resHL, r1
166 adc r_resHH, r_arg1HH ; add carry
167 mul r_arg1L, r_arg2H
168 add r_resH, r0
169 adc r_resHL, r1
170 adc r_resHH, r_arg1HH ; add carry
171 movw r_arg1L, r_resL
172 movw r_arg1HL, r_resHL
173 clr r1 ; __zero_reg__ clobbered by "mul"
174 ret
175 #else
176 clr r_resHH ; clear result
177 clr r_resHL ; clear result
178 clr r_resH ; clear result
179 clr r_resL ; clear result
180 __mulsi3_loop:
181 sbrs r_arg1L,0
182 rjmp __mulsi3_skip1
183 add r_resL,r_arg2L ; result + multiplicand
184 adc r_resH,r_arg2H
185 adc r_resHL,r_arg2HL
186 adc r_resHH,r_arg2HH
187 __mulsi3_skip1:
188 add r_arg2L,r_arg2L ; shift multiplicand
189 adc r_arg2H,r_arg2H
190 adc r_arg2HL,r_arg2HL
191 adc r_arg2HH,r_arg2HH
192
193 lsr r_arg1HH ; gets LSB of multiplier
194 ror r_arg1HL
195 ror r_arg1H
196 ror r_arg1L
197 brne __mulsi3_loop
198 sbiw r_arg1HL,0
199 cpc r_arg1H,r_arg1L
200 brne __mulsi3_loop ; exit if multiplier = 0
201 __mulsi3_exit:
202 mov r_arg1HH,r_resHH ; result to return register
203 mov r_arg1HL,r_resHL
204 mov r_arg1H,r_resH
205 mov r_arg1L,r_resL
206 ret
207 #endif /* !defined (__AVR_ENHANCED__) */
208 #undef r_arg1L
209 #undef r_arg1H
210 #undef r_arg1HL
211 #undef r_arg1HH
212
213
214 #undef r_arg2L
215 #undef r_arg2H
216 #undef r_arg2HL
217 #undef r_arg2HH
218
219 #undef r_resL
220 #undef r_resH
221 #undef r_resHL
222 #undef r_resHH
223
224 .endfunc
225 #endif /* defined (L_mulsi3) */
226
227 /*******************************************************
228 Division 8 / 8 => (result + remainder)
229 *******************************************************/
230 #define r_rem r26 /* remainder */
231 #define r_arg1 r24 /* dividend */
232 #define r_arg2 r22 /* divisor */
233 #define r_cnt r27 /* loop count */
234
235 #if defined (L_umodqi3)
236
237 .global __umodqi3
238 .func __umodqi3
239 __umodqi3:
240 clt
241 rcall __udivqi3
242 mov r24,r_rem
243 ret
244 .endfunc
245 #endif /* defined (L_umodqi3) */
246
247 #if defined (L_udivqi3)
248
249 .global __udivqi3
250 .func __udivqi3
251 __udivqi3:
252 clr __tmp_reg__
253 rjmp __divqi_raw
254 .endfunc
255 #endif /* defined (L_udivqi3) */
256
257 #if defined (L_modqi3)
258
259 .global __modqi3
260 .func __modqi3
261 __modqi3:
262 rcall __divqi3
263 mov r24,r_rem
264 ret
265 .endfunc
266 #endif /* defined (L_modqi3) */
267
268 #if defined (L_divqi3)
269
270 .global __divqi3
271 .func __divqi3
272 __divqi3:
273 bst r_arg1,7 ; store sign of divident
274 mov __tmp_reg__,r_arg1
275 eor __tmp_reg__,r_arg2; r0.7 is sign of result
276 sbrc r_arg1,7
277 neg r_arg1 ; divident negative : negate
278 sbrc r_arg2,7
279 neg r_arg2 ; divisor negative : negate
280 .global __divqi_raw
281 __divqi_raw:
282 sub r_rem,r_rem ; clear remainder and carry
283 ldi r_cnt,9 ; init loop counter
284 rjmp __divqi3_ep ; jump to entry point
285 __divqi3_loop:
286 rol r_rem ; shift dividend into remainder
287 cp r_rem,r_arg2 ; compare remainder & divisor
288 brcs __divqi3_ep ; remainder <= divisor
289 sub r_rem,r_arg2 ; restore remainder
290 __divqi3_ep:
291 rol r_arg1 ; shift dividend (with CARRY)
292 dec r_cnt ; decrement loop counter
293 brne __divqi3_loop ; loop
294 com r_arg1 ; complement result
295 ; because C flag was complemented in loop
296 brtc __divqi3_1
297 neg r_rem ; correct remainder sign
298 __divqi3_1:
299 sbrc __tmp_reg__,7
300 neg r_arg1 ; correct result sign
301 __divqi3_exit:
302 ret ; result already in r24 (r_arg1)
303 .endfunc
304 #endif /* defined (L_divqi3) */
305
306 #undef r_rem
307 #undef r_arg1
308 #undef r_arg2
309 #undef r_cnt
310
311
312 /*******************************************************
313 Division 16 / 16 => (result + remainder)
314 *******************************************************/
315 #define r_remL r26 /* remainder Low */
316 #define r_remH r27 /* remainder High */
317
318 #define r_arg1L r24 /* dividend Low */
319 #define r_arg1H r25 /* dividend High */
320
321 #define r_arg2L r22 /* divisor Low */
322 #define r_arg2H r23 /* divisor High */
323
324 #define r_cnt r21 /* loop count */
325 #if defined (L_umodhi3)
326 .global __umodhi3
327 .func __umodhi3
328 __umodhi3:
329 clt
330 rcall __udivhi3
331 .global __umodhi3_ret
332 __umodhi3_ret:
333 #if defined (__AVR_ENHANCED__)
334 movw r24, r_remL
335 #else
336 mov r24,r_remL
337 mov r25,r_remH
338 #endif
339 ret
340 .endfunc
341 #endif /* defined (L_umodhi3) */
342
343 #if defined (L_udivhi3)
344
345 .global __udivhi3
346 .func __udivhi3
347 __udivhi3:
348 clr __tmp_reg__
349 rjmp __divhi_raw
350 .endfunc
351 #endif /* defined (L_udivhi3) */
352
353 #if defined (L_modhi3)
354 .global __modhi3
355 .func __modhi3
356 __modhi3:
357 .global _div
358 _div:
359 rcall __divhi3
360 #if defined (__AVR_ENHANCED__)
361 movw r22, r24
362 #else
363 mov r22,r24 ; needed for div () function
364 mov r23,r25
365 #endif
366 rjmp __umodhi3_ret
367 .endfunc
368 #endif /* defined (L_modhi3) */
369
370
371 #if defined (L_divhi3)
372 .global __divhi3
373 .func __divhi3
374 __divhi3:
375 bst r_arg1H,7 ; store sign of divident
376 mov __tmp_reg__,r_arg1H
377 eor __tmp_reg__,r_arg2H ; r0.7 is sign of result
378 brtc __divhi3_skip1
379 com r_arg1H
380 neg r_arg1L ; divident negative : negate
381 sbci r_arg1H,0xff
382 __divhi3_skip1:
383 tst r_arg2H
384 brpl __divhi3_skip2
385 com r_arg2H
386 neg r_arg2L ; divisor negative : negate
387 sbci r_arg2H,0xff
388 __divhi3_skip2:
389 .global __divhi_raw
390 __divhi_raw:
391 sub r_remL,r_remL
392 sub r_remH,r_remH ; clear remainder and carry
393 ldi r_cnt,17 ; init loop counter
394 rjmp __divhi3_ep ; jump to entry point
395 __divhi3_loop:
396 rol r_remL ; shift dividend into remainder
397 rol r_remH
398 cp r_remL,r_arg2L ; compare remainder & divisor
399 cpc r_remH,r_arg2H
400 brcs __divhi3_ep ; remainder < divisor
401 sub r_remL,r_arg2L ; restore remainder
402 sbc r_remH,r_arg2H
403 __divhi3_ep:
404 rol r_arg1L ; shift dividend (with CARRY)
405 rol r_arg1H
406 dec r_cnt ; decrement loop counter
407 brne __divhi3_loop ; loop
408 brtc __divhi3_1
409 com r_remH
410 neg r_remL ; correct remainder sign
411 sbci r_remH,0xff
412 __divhi3_1:
413 tst __tmp_reg__
414 brpl __divhi3_exit
415 adiw r_arg1L,1 ; correct result sign
416 ret
417 __divhi3_exit:
418 com r_arg1L
419 com r_arg1H
420 ret
421 .endfunc
422 #endif /* defined (L_divhi3) */
423
424 #undef r_remH
425 #undef r_remL
426
427 #undef r_arg1H
428 #undef r_arg1L
429
430 #undef r_arg2H
431 #undef r_arg2L
432
433 #undef r_cnt
434
435 /*******************************************************
436 Division 32 / 32 => (result + remainder)
437 *******************************************************/
438 #define r_remHH r31 /* remainder High */
439 #define r_remHL r30
440 #define r_remH r27
441 #define r_remL r26 /* remainder Low */
442
443 #define r_arg1HH r25 /* dividend High */
444 #define r_arg1HL r24
445 #define r_arg1H r23
446 #define r_arg1L r22 /* dividend Low */
447
448 #define r_arg2HH r21 /* divisor High */
449 #define r_arg2HL r20
450 #define r_arg2H r19
451 #define r_arg2L r18 /* divisor Low */
452
453 #define r_cnt __zero_reg__ /* loop count (0 after the loop!) */
454
455 #if defined (L_umodsi3)
456
457 .global __umodsi3
458 .func __umodsi3
459 __umodsi3:
460 clt
461 rcall __udivsi3
462 .global __umodsi3_ret
463 __umodsi3_ret:
464 #if defined (__AVR_ENHANCED__)
465 movw r24, r_remHL
466 movw r22, r_remL
467 #else
468 mov r25,r_remHH
469 mov r24,r_remHL
470 mov r23,r_remH
471 mov r22,r_remL
472 #endif
473 ret
474 .endfunc
475 #endif /* defined (L_umodsi3) */
476
477 #if defined (L_udivsi3)
478
479 .global __udivsi3
480 .func __udivsi3
481 __udivsi3:
482 clr __tmp_reg__
483 rjmp __divsi_raw
484 .endfunc
485 #endif /* defined (L_udivsi3) */
486
487 #if defined (L_modsi3)
488
489 .global __modsi3
490 .func __modsi3
491 __modsi3:
492 .global _ldiv
493 _ldiv:
494 rcall __divsi3
495 #if defined (__AVR_ENHANCED__)
496 movw r18, r22
497 movw r20, r24
498 #else
499 mov r18,r22 /* Needed for ldiv */
500 mov r19,r23
501 mov r20,r24
502 mov r21,r25
503 #endif
504 rjmp __umodsi3_ret
505 .endfunc
506 #endif /* defined (L_modsi3) */
507
508 #if defined (L_divsi3)
509
510 .global __divsi3
511 .func __divsi3
512 __divsi3:
513 bst r_arg1HH,7 ; store sign of divident
514 mov __tmp_reg__,r_arg1HH
515 eor __tmp_reg__,r_arg2HH ; r0.7 is sign of result
516 brtc __divsi3_skip1
517 com r_arg1HH
518 com r_arg1HL
519 com r_arg1H
520 neg r_arg1L ; divident negative : negate
521 sbci r_arg1H, 0xff
522 sbci r_arg1HL,0xff
523 sbci r_arg1HH,0xff
524 __divsi3_skip1:
525 tst r_arg2HH
526 brpl __divsi3_skip2
527 com r_arg2HH
528 com r_arg2HL
529 com r_arg2H
530 neg r_arg2L ; divisor negative : negate
531 sbci r_arg2H, 0xff
532 sbci r_arg2HL,0xff
533 sbci r_arg2HH,0xff
534 __divsi3_skip2:
535 .global __divsi_raw
536 __divsi_raw:
537 ldi r_remL, 33 ; init loop counter
538 mov r_cnt, r_remL
539 sub r_remL,r_remL
540 sub r_remH,r_remH
541 #if defined (__AVR_ENHANCED__)
542 movw r_remHL, r_remL
543 #else
544 sub r_remHL,r_remHL
545 sub r_remHH,r_remHH ; clear remainder and carry
546 #endif
547 rjmp __divsi3_ep ; jump to entry point
548 __divsi3_loop:
549 rol r_remL ; shift dividend into remainder
550 rol r_remH
551 rol r_remHL
552 rol r_remHH
553 cp r_remL,r_arg2L ; compare remainder & divisor
554 cpc r_remH,r_arg2H
555 cpc r_remHL,r_arg2HL
556 cpc r_remHH,r_arg2HH
557 brcs __divsi3_ep ; remainder <= divisor
558 sub r_remL,r_arg2L ; restore remainder
559 sbc r_remH,r_arg2H
560 sbc r_remHL,r_arg2HL
561 sbc r_remHH,r_arg2HH
562 __divsi3_ep:
563 rol r_arg1L ; shift dividend (with CARRY)
564 rol r_arg1H
565 rol r_arg1HL
566 rol r_arg1HH
567 dec r_cnt ; decrement loop counter
568 brne __divsi3_loop ; loop
569 ; __zero_reg__ now restored (r_cnt == 0)
570 brtc __divsi3_1
571 com r_remHH
572 com r_remHL
573 com r_remH
574 neg r_remL ; correct remainder sign
575 sbci r_remH, 0xff
576 sbci r_remHL,0xff
577 sbci r_remHH,0xff
578 __divsi3_1:
579 rol __tmp_reg__
580 brcc __divsi3_exit
581 adc r_arg1L,__zero_reg__; correct result sign
582 adc r_arg1H,__zero_reg__
583 adc r_arg1HL,__zero_reg__
584 adc r_arg1HH,__zero_reg__
585 ret
586 __divsi3_exit:
587 com r_arg1L
588 com r_arg1H
589 com r_arg1HL
590 com r_arg1HH
591 ret
592 .endfunc
593 #endif /* defined (L_divsi3) */
594
595 /**********************************
596 * This is a prologue subroutine
597 **********************************/
598 #if defined (L_prologue)
599
600 .global __prologue_saves__
601 .func __prologue_saves__
602 __prologue_saves__:
603 push r2
604 push r3
605 push r4
606 push r5
607 push r6
608 push r7
609 push r8
610 push r9
611 push r10
612 push r11
613 push r12
614 push r13
615 push r14
616 push r15
617 push r16
618 push r17
619 push r28
620 push r29
621 in r28,__SP_L__
622 in r29,__SP_H__
623 sub r28,r26
624 sbc r29,r27
625 in __tmp_reg__,__SREG__
626 cli
627 out __SP_H__,r29
628 out __SREG__,__tmp_reg__
629 out __SP_L__,r28
630 ijmp
631 .endfunc
632 #endif /* defined (L_prologue) */
633
634 /*
635 * This is a epilogue subroutine
636 */
637 #if defined (L_epilogue)
638
639 .global __epilogue_restores__
640 .func __epilogue_restores__
641 __epilogue_restores__:
642 ldd r2,Y+18
643 ldd r3,Y+17
644 ldd r4,Y+16
645 ldd r5,Y+15
646 ldd r6,Y+14
647 ldd r7,Y+13
648 ldd r8,Y+12
649 ldd r9,Y+11
650 ldd r10,Y+10
651 ldd r11,Y+9
652 ldd r12,Y+8
653 ldd r13,Y+7
654 ldd r14,Y+6
655 ldd r15,Y+5
656 ldd r16,Y+4
657 ldd r17,Y+3
658 ldd r26,Y+2
659 ldd r27,Y+1
660 add r28,r30
661 adc r29,__zero_reg__
662 in __tmp_reg__,__SREG__
663 cli
664 out __SP_H__,r29
665 out __SREG__,__tmp_reg__
666 out __SP_L__,r28
667 #if defined (__AVR_ENHANCED__)
668 movw r28, r26
669 #else
670 mov r28,r26
671 mov r29,r27
672 #endif
673 ret
674 .endfunc
675 #endif /* defined (L_epilogue) */
676
677 #ifdef L_exit
678 .weak _exit
679 .func _exit
680 _exit:
681 rjmp _exit
682 .endfunc
683 #endif /* defined (L_exit) */
684
685 #ifdef L_cleanup
686 .weak _cleanup
687 .func _cleanup
688 _cleanup:
689 ret
690 .endfunc
691 #endif /* defined (L_cleanup) */
692
693 #ifdef L_tablejump
694 .global __tablejump__
695 .func __tablejump__
696 __tablejump__:
697 #if defined (__AVR_ENHANCED__)
698 lpm __tmp_reg__, Z+
699 lpm r31, Z
700 mov r30, __tmp_reg__
701 ijmp
702 #else
703 lpm
704 push r0
705 adiw r30, 1
706 lpm
707 push r0
708 ret
709 .endfunc
710 #endif
711 #endif /* defined (L_tablejump) */
712
This page took 0.066824 seconds and 5 git commands to generate.