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