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>
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
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.
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.
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/>. */
25 #define __zero_reg__ r1
26 #define __tmp_reg__ r0
30 #define __RAMPZ__ 0x3B
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. */
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. */
48 .macro mov_l r_dest, r_src
49 #if defined (__AVR_HAVE_MOVW__)
56 .macro mov_h r_dest, r_src
57 #if defined (__AVR_HAVE_MOVW__)
64 #if defined (__AVR_HAVE_JMP_CALL__)
84 .section .text.libgcc.mul, "ax", @progbits
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)
94 #define r_arg2 r22 /* multiplicand */
95 #define r_arg1 r24 /* multiplier */
96 #define r_res __tmp_reg__ /* result */
99 clr r_res ; clear result
103 add r_arg2,r_arg2 ; shift multiplicand
104 breq __mulqi3_exit ; while multiplicand != 0
106 brne __mulqi3_loop ; exit if multiplier = 0
108 mov r_arg1,r_res ; result to return register
116 #endif /* defined (L_mulqi3) */
118 #if defined (L_mulqihi3)
128 #endif /* defined (L_mulqihi3) */
130 #if defined (L_umulqihi3)
136 #endif /* defined (L_umulqihi3) */
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 */
150 clr r_resH ; clear result
151 clr r_resL ; clear result
155 add r_resL,r_arg2L ; result + multiplicand
158 add r_arg2L,r_arg2L ; shift multiplicand
161 cp r_arg2L,__zero_reg__
162 cpc r_arg2H,__zero_reg__
163 breq __mulhi3_exit ; while multiplicand != 0
165 lsr r_arg1H ; gets LSB of multiplier
168 brne __mulhi3_loop ; exit if multiplier = 0
170 mov r_arg1H,r_resH ; result to return register
182 #endif /* defined (L_mulhi3) */
184 /*******************************************************
185 Widening Multiplication 32 = 16 x 16 without MUL
186 *******************************************************/
188 #if defined (L_mulhisi3)
190 ;;; FIXME: This is dead code (noone calls it)
203 #endif /* defined (L_mulhisi3) */
205 #if defined (L_umulhisi3)
207 ;;; FIXME: This is dead code (noone calls it)
216 #endif /* defined (L_umulhisi3) */
218 #if defined (L_mulsi3)
219 /*******************************************************
220 Multiplication 32 x 32 without MUL
221 *******************************************************/
222 #define r_arg1L r22 /* multiplier Low */
225 #define r_arg1HH r25 /* multiplier High */
227 #define r_arg2L r18 /* multiplicand Low */
230 #define r_arg2HH r21 /* multiplicand High */
232 #define r_resL r26 /* result Low */
235 #define r_resHH r31 /* result High */
238 clr r_resHH ; clear result
239 clr r_resHL ; clear result
240 clr r_resH ; clear result
241 clr r_resL ; clear result
245 add r_resL,r_arg2L ; result + multiplicand
250 add r_arg2L,r_arg2L ; shift multiplicand
252 adc r_arg2HL,r_arg2HL
253 adc r_arg2HH,r_arg2HH
255 lsr r_arg1HH ; gets LSB of multiplier
262 brne __mulsi3_loop ; exit if multiplier = 0
264 mov_h r_arg1HH,r_resHH ; result to return register
265 mov_l r_arg1HL,r_resHL
286 #endif /* defined (L_mulsi3) */
288 #endif /* !defined (__AVR_HAVE_MUL__) */
289 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
291 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
292 #if defined (__AVR_HAVE_MUL__)
307 /*******************************************************
308 Widening Multiplication 32 = 16 x 16
309 *******************************************************/
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__
323 XJMP __usmulhisi3_tail
325 #endif /* L_mulhisi3 */
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__
336 DEFUN __usmulhisi3_tail
343 ENDF __usmulhisi3_tail
344 #endif /* L_usmulhisi3 */
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__
364 #endif /* L_umulhisi3 */
366 /*******************************************************
367 Widening Multiplication 32 = 16 x 32
368 *******************************************************/
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__
375 #ifdef __AVR_ERRATA_SKIP_JMP_CALL__
376 ;; Some cores have problem skipping 2-word instruction
381 #endif /* __AVR_HAVE_JMP_CALL__ */
386 ;;; R25:R22 = (one-extended long) R27:R26 * R21:R18
387 ;;; (C3:C0) = (one-extended long) A1:A0 * B3:B0
388 ;;; Clobbers: __tmp_reg__
391 ;; One-extend R27:R26 (A1:A0)
396 #endif /* L_mulshisi3 */
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__
414 #endif /* L_muluhisi3 */
416 /*******************************************************
417 Multiplication 32 x 32
418 *******************************************************/
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__
431 ;; A1:A0 now contains the high word of A
442 #endif /* L_mulsi3 */
457 #endif /* __AVR_HAVE_MUL__ */
458 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
461 .section .text.libgcc.div, "ax", @progbits
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 */
471 #if defined (L_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
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
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
489 #endif /* defined (L_udivmodqi4) */
491 #if defined (L_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
497 neg r_arg1 ; dividend negative : negate
499 neg r_arg2 ; divisor negative : negate
500 XCALL __udivmodqi4 ; do the unsigned div/mod
502 neg r_rem ; correct remainder sign
505 neg r_arg1 ; correct result sign
509 #endif /* defined (L_divmodqi4) */
517 /*******************************************************
518 Division 16 / 16 => (result + remainder)
519 *******************************************************/
520 #define r_remL r26 /* remainder Low */
521 #define r_remH r27 /* remainder High */
523 /* return: remainder */
524 #define r_arg1L r24 /* dividend Low */
525 #define r_arg1H r25 /* dividend High */
527 /* return: quotient */
528 #define r_arg2L r22 /* divisor Low */
529 #define r_arg2H r23 /* divisor High */
531 #define r_cnt r21 /* loop count */
533 #if defined (L_udivmodhi4)
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
540 rol r_remL ; shift dividend into remainder
542 cp r_remL,r_arg2L ; compare remainder & divisor
544 brcs __udivmodhi4_ep ; remainder < divisor
545 sub r_remL,r_arg2L ; restore remainder
548 rol r_arg1L ; shift dividend (with CARRY)
550 dec r_cnt ; decrement loop counter
551 brne __udivmodhi4_loop
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
561 #endif /* defined (L_udivmodhi4) */
563 #if defined (L_divmodhi4)
567 bst r_arg1H,7 ; store sign of dividend
568 mov __tmp_reg__,r_arg2H
570 com __tmp_reg__ ; r0.7 is sign of result
571 rcall __divmodhi4_neg1 ; dividend negative: negate
574 rcall __divmodhi4_neg2 ; divisor negative: negate
575 XCALL __udivmodhi4 ; do the unsigned div/mod
577 rcall __divmodhi4_neg2 ; correct remainder sign
578 brtc __divmodhi4_exit
580 ;; correct dividend/remainder sign
586 ;; correct divisor/result sign
593 #endif /* defined (L_divmodhi4) */
606 /*******************************************************
607 Division 24 / 24 => (result + remainder)
608 *******************************************************/
610 ;; A[0..2]: In: Dividend; Out: Quotient
615 ;; B[0..2]: In: Divisor; Out: Remainder
620 ;; C[0..2]: Expand remainder
621 #define C0 __zero_reg__
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
636 ; Clear remainder and carry. C0 is already 0
639 ; jump to entry point
640 rjmp __udivmodpsi4_start
642 ; shift dividend into remainder
646 ; compare remainder & divisor
650 brcs __udivmodpsi4_start ; remainder <= divisor
651 sub C0, B0 ; restore remainder
655 ; shift dividend (with CARRY)
659 ; decrement loop counter
661 brne __udivmodpsi4_loop
665 ; div/mod results to return registers
670 clr __zero_reg__ ; C0
673 #endif /* defined (L_udivmodpsi4) */
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
681 ; R0.7 will contain the sign of the result:
682 ; R0.7 = A.sign ^ B.sign
684 ; T-flag = sign of dividend
688 ; Adjust dividend's sign
689 rcall __divmodpsi4_negA
691 ; Adjust divisor's sign
693 rcall __divmodpsi4_negB
695 ; Do the unsigned div/mod
698 ; Adjust quotient's sign
700 rcall __divmodpsi4_negA
702 ; Adjust remainder's sign
703 brtc __divmodpsi4_end
706 ; Correct divisor/remainder sign
714 ; Correct dividend/quotient sign
725 #endif /* defined (L_divmodpsi4) */
741 /*******************************************************
742 Division 32 / 32 => (result + remainder)
743 *******************************************************/
744 #define r_remHH r31 /* remainder High */
747 #define r_remL r26 /* remainder Low */
749 /* return: remainder */
750 #define r_arg1HH r25 /* dividend High */
753 #define r_arg1L r22 /* dividend Low */
755 /* return: quotient */
756 #define r_arg2HH r21 /* divisor High */
759 #define r_arg2L r18 /* divisor Low */
761 #define r_cnt __zero_reg__ /* loop count (0 after the loop!) */
763 #if defined (L_udivmodsi4)
765 ldi r_remL, 33 ; init loop counter
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
773 rol r_remL ; shift dividend into remainder
777 cp r_remL,r_arg2L ; compare remainder & divisor
781 brcs __udivmodsi4_ep ; remainder <= divisor
782 sub r_remL,r_arg2L ; restore remainder
787 rol r_arg1L ; shift dividend (with CARRY)
791 dec r_cnt ; decrement loop counter
792 brne __udivmodsi4_loop
793 ; __zero_reg__ now restored (r_cnt == 0)
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
809 #endif /* defined (L_udivmodsi4) */
811 #if defined (L_divmodsi4)
813 mov __tmp_reg__,r_arg2HH
814 bst r_arg1HH,7 ; store sign of dividend
816 com __tmp_reg__ ; r0.7 is sign of result
817 rcall __divmodsi4_neg1 ; dividend negative: negate
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
826 ;; correct dividend/remainder sign
836 ;; correct divisor/quotient sign
847 #endif /* defined (L_divmodsi4) */
850 .section .text.libgcc.prologue, "ax", @progbits
852 /**********************************
853 * This is a prologue subroutine
854 **********************************/
855 #if defined (L_prologue)
857 DEFUN __prologue_saves__
880 in __tmp_reg__,__SREG__
883 out __SREG__,__tmp_reg__
885 #if defined (__AVR_HAVE_EIJMP_EICALL__)
891 ENDF __prologue_saves__
892 #endif /* defined (L_prologue) */
895 * This is an epilogue subroutine
897 #if defined (L_epilogue)
899 DEFUN __epilogue_restores__
920 in __tmp_reg__,__SREG__
923 out __SREG__,__tmp_reg__
928 ENDF __epilogue_restores__
929 #endif /* defined (L_epilogue) */
932 .section .fini9,"ax",@progbits
938 /* Code from .fini8 ... .fini1 sections inserted by ld script. */
940 .section .fini0,"ax",@progbits
944 #endif /* defined (L_exit) */
952 #endif /* defined (L_cleanup) */
955 .section .text.libgcc, "ax", @progbits
965 #if defined (__AVR_HAVE_LPMX__)
969 #if defined (__AVR_HAVE_EIJMP_EICALL__)
975 #else /* !HAVE_LPMX */
981 #if defined (__AVR_HAVE_EIJMP_EICALL__)
982 in __tmp_reg__, __EIND__
986 #endif /* !HAVE_LPMX */
988 #endif /* defined (L_tablejump) */
991 .section .init4,"ax",@progbits
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)
1001 rjmp .L__do_copy_data_start
1002 .L__do_copy_data_loop:
1005 .L__do_copy_data_start:
1006 cpi r26, lo8(__data_end)
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:
1019 rjmp .L__do_copy_data_start
1020 .L__do_copy_data_loop:
1024 brcs .L__do_copy_data_carry
1025 .L__do_copy_data_start:
1026 cpi r26, lo8(__data_end)
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__)
1044 .L__do_copy_data_start:
1045 cpi r26, lo8(__data_end)
1047 brne .L__do_copy_data_loop
1048 #endif /* !defined(__AVR_HAVE_ELPMX__) && !defined(__AVR_HAVE_ELPM__) */
1050 #endif /* L_copy_data */
1052 /* __do_clear_bss is only necessary if there is anything in .bss section. */
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
1063 .do_clear_bss_start:
1064 cpi r26, lo8(__bss_end)
1066 brne .do_clear_bss_loop
1068 #endif /* L_clear_bss */
1070 /* __do_global_ctors and __do_global_dtors are only necessary
1071 if there are any constructors/destructors. */
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:
1084 sbc r16, __zero_reg__
1088 XCALL __tablejump_elpm__
1089 .L__do_global_ctors_start:
1090 cpi r28, lo8(__ctors_start)
1092 ldi r24, hh8(__ctors_start)
1094 brne .L__do_global_ctors_loop
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:
1105 .L__do_global_ctors_start:
1106 cpi r28, lo8(__ctors_start)
1108 brne .L__do_global_ctors_loop
1109 #endif /* defined(__AVR_HAVE_RAMPZ__) */
1110 ENDF __do_global_ctors
1111 #endif /* L_ctors */
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:
1124 sbc r16, __zero_reg__
1128 XCALL __tablejump_elpm__
1129 .L__do_global_dtors_start:
1130 cpi r28, lo8(__dtors_end)
1132 ldi r24, hh8(__dtors_end)
1134 brne .L__do_global_dtors_loop
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:
1145 .L__do_global_dtors_start:
1146 cpi r28, lo8(__dtors_end)
1148 brne .L__do_global_dtors_loop
1149 #endif /* defined(__AVR_HAVE_RAMPZ__) */
1150 ENDF __do_global_dtors
1151 #endif /* L_dtors */
1153 .section .text.libgcc, "ax", @progbits
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+
1161 mov r30, __tmp_reg__
1162 #if defined (__AVR_HAVE_EIJMP_EICALL__)
1174 #if defined (__AVR_HAVE_EIJMP_EICALL__)
1175 in __tmp_reg__, __EIND__
1180 #endif /* defined (__AVR_HAVE_ELPM__) */
1181 ENDF __tablejump_elpm__
1182 #endif /* defined (L_tablejump_elpm) */
1184 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1185 ;; Loading n bytes from Flash; n = 3,4
1186 ;; R22... = Flash[Z]
1187 ;; Clobbers: __tmp_reg__
1189 #if (defined (L_load_3) \
1190 || defined (L_load_4)) \
1191 && !defined (__AVR_HAVE_LPMX__)
1199 .macro .load dest, n
1202 .if \dest != D0+\n-1
1209 #if defined (L_load_3)
1216 #endif /* L_load_3 */
1218 #if defined (L_load_4)
1226 #endif /* L_load_4 */
1228 #endif /* L_load_3 || L_load_3 */
1230 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1231 ;; Loading n bytes from Flash; n = 2,3,4
1232 ;; R22... = Flash[R21:Z]
1233 ;; Clobbers: __tmp_reg__, R21, R30, R31
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__)
1241 #if !defined (__AVR_HAVE_RAMPZ__)
1243 #endif /* have RAMPZ */
1251 ;; Register containing bits 16+ of the address
1255 .macro .xload dest, n
1258 .if \dest != D0+\n-1
1260 adc HHI8, __zero_reg__
1265 #if defined (L_xload_2)
1272 #endif /* L_xload_2 */
1274 #if defined (L_xload_3)
1282 #endif /* L_xload_3 */
1284 #if defined (L_xload_4)
1293 #endif /* L_xload_4 */
1295 #endif /* L_xload_{2|3|4} && ELPM */
1298 .section .text.libgcc.builtins, "ax", @progbits
1300 /**********************************
1301 * Find first set Bit (ffs)
1302 **********************************/
1304 #if defined (L_ffssi2)
1305 ;; find first set bit
1306 ;; r25:r24 = ffs32 (r25:r22)
1307 ;; clobbers: r22, r26
1325 #endif /* defined (L_ffssi2) */
1327 #if defined (L_ffshi2)
1328 ;; find first set bit
1329 ;; r25:r24 = ffs16 (r25:r24)
1333 #ifdef __AVR_ERRATA_SKIP_JMP_CALL__
1334 ;; Some cores have problem skipping 2-word instruction
1338 cpse r24, __zero_reg__
1339 #endif /* __AVR_HAVE_JMP_CALL__ */
1340 1: XJMP __loop_ffsqi2
1346 #endif /* defined (L_ffshi2) */
1348 #if defined (L_loop_ffsqi2)
1349 ;; Helper for ffshi2, ffssi2
1350 ;; r25:r24 = r26 + zero_extend16 (ffs8(r24))
1361 #endif /* defined (L_loop_ffsqi2) */
1364 /**********************************
1365 * Count trailing Zeros (ctz)
1366 **********************************/
1368 #if defined (L_ctzsi2)
1369 ;; count trailing zeros
1370 ;; r25:r24 = ctz32 (r25:r22)
1371 ;; clobbers: r26, r22
1373 ;; Note that ctz(0) in undefined for GCC
1379 #endif /* defined (L_ctzsi2) */
1381 #if defined (L_ctzhi2)
1382 ;; count trailing zeros
1383 ;; r25:r24 = ctz16 (r25:r24)
1386 ;; Note that ctz(0) in undefined for GCC
1392 #endif /* defined (L_ctzhi2) */
1395 /**********************************
1396 * Count leading Zeros (clz)
1397 **********************************/
1399 #if defined (L_clzdi2)
1400 ;; count leading zeros
1401 ;; r25:r24 = clz64 (r25:r18)
1402 ;; clobbers: r22, r23, r26
1415 #endif /* defined (L_clzdi2) */
1417 #if defined (L_clzsi2)
1418 ;; count leading zeros
1419 ;; r25:r24 = clz32 (r25:r22)
1431 #endif /* defined (L_clzsi2) */
1433 #if defined (L_clzhi2)
1434 ;; count leading zeros
1435 ;; r25:r24 = clz16 (r25:r24)
1457 #endif /* defined (L_clzhi2) */
1460 /**********************************
1462 **********************************/
1464 #if defined (L_paritydi2)
1465 ;; r25:r24 = parity64 (r25:r18)
1466 ;; clobbers: __tmp_reg__
1474 #endif /* defined (L_paritydi2) */
1476 #if defined (L_paritysi2)
1477 ;; r25:r24 = parity32 (r25:r22)
1478 ;; clobbers: __tmp_reg__
1484 #endif /* defined (L_paritysi2) */
1486 #if defined (L_parityhi2)
1487 ;; r25:r24 = parity16 (r25:r24)
1488 ;; clobbers: __tmp_reg__
1494 ;; r25:r24 = parity8 (r24)
1495 ;; clobbers: __tmp_reg__
1497 ;; parity is in r24[0..7]
1498 mov __tmp_reg__, r24
1500 eor r24, __tmp_reg__
1501 ;; parity is in r24[0..3]
1505 ;; parity is in r24[0,3]
1508 ;; parity is in r24[0]
1513 #endif /* defined (L_parityhi2) */
1516 /**********************************
1518 **********************************/
1520 #if defined (L_popcounthi2)
1522 ;; r25:r24 = popcount16 (r25:r24)
1523 ;; clobbers: __tmp_reg__
1533 DEFUN __popcounthi2_tail
1535 add r24, __tmp_reg__
1537 ENDF __popcounthi2_tail
1538 #endif /* defined (L_popcounthi2) */
1540 #if defined (L_popcountsi2)
1542 ;; r25:r24 = popcount32 (r25:r22)
1543 ;; clobbers: __tmp_reg__
1550 XJMP __popcounthi2_tail
1552 #endif /* defined (L_popcountsi2) */
1554 #if defined (L_popcountdi2)
1556 ;; r25:r24 = popcount64 (r25:r18)
1557 ;; clobbers: r22, r23, __tmp_reg__
1566 XJMP __popcounthi2_tail
1568 #endif /* defined (L_popcountdi2) */
1570 #if defined (L_popcountqi2)
1572 ;; r24 = popcount8 (r24)
1573 ;; clobbers: __tmp_reg__
1575 mov __tmp_reg__, r24
1579 adc r24, __zero_reg__
1581 adc r24, __zero_reg__
1583 adc r24, __zero_reg__
1585 adc r24, __zero_reg__
1587 adc r24, __zero_reg__
1589 adc r24, __tmp_reg__
1592 #endif /* defined (L_popcountqi2) */
1595 /**********************************
1597 **********************************/
1599 ;; swap two registers with different register number
1606 #if defined (L_bswapsi2)
1608 ;; r25:r22 = bswap32 (r25:r22)
1614 #endif /* defined (L_bswapsi2) */
1616 #if defined (L_bswapdi2)
1618 ;; r25:r18 = bswap64 (r25:r18)
1626 #endif /* defined (L_bswapdi2) */
1629 /**********************************
1631 **********************************/
1633 #if defined (L_ashrdi3)
1634 ;; Arithmetic shift right
1635 ;; r25:r18 = ashr64 (r25:r18, r17:r16)
1653 #endif /* defined (L_ashrdi3) */
1655 #if defined (L_lshrdi3)
1656 ;; Logic shift right
1657 ;; r25:r18 = lshr64 (r25:r18, r17:r16)
1675 #endif /* defined (L_lshrdi3) */
1677 #if defined (L_ashldi3)
1679 ;; r25:r18 = ashl64 (r25:r18, r17:r16)
1697 #endif /* defined (L_ashldi3) */
1700 .section .text.libgcc.fmul, "ax", @progbits
1702 /***********************************************************/
1703 ;;; Softmul versions of FMUL, FMULS and FMULSU to implement
1704 ;;; __builtin_avr_fmul* if !AVR_HAVE_MUL
1705 /***********************************************************/
1711 #define A0 __tmp_reg__
1714 ;;; r23:r22 = fmuls (r24, r25) like in FMULS instruction
1715 ;;; Clobbers: r24, r25, __tmp_reg__
1717 ;; A0.7 = negate result?
1725 #endif /* L_fmuls */
1728 ;;; r23:r22 = fmulsu (r24, r25) like in FMULSU instruction
1729 ;;; Clobbers: r24, r25, __tmp_reg__
1731 ;; A0.7 = negate result?
1736 ;; Helper for __fmuls and __fmulsu
1741 #ifdef __AVR_ERRATA_SKIP_JMP_CALL__
1742 ;; Some cores have problem skipping 2-word instruction
1747 #endif /* __AVR_HAVE_JMP_CALL__ */
1750 ;; C = -C iff A0.7 = 1
1756 #endif /* L_fmulsu */
1760 ;;; r22:r23 = fmul (r24, r25) like in FMUL instruction
1761 ;;; Clobbers: r24, r25, __tmp_reg__
1768 ;; 1.0 = 0x80, so test for bit 7 of B to see if A must to be added to C.