1 /* -*- Mode: Asm -*- */
2 /* Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
3 Contributed by Denis Chertykov <denisc@overta.ru>
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
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
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.
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. */
29 #define __zero_reg__ r1
30 #define __tmp_reg__ r0
35 .section .text.libgcc, "ax", @progbits
37 /* Note: mulqi3, mulhi3 are open-coded on the enhanced core. */
38 #if !defined (__AVR_ENHANCED__)
39 /*******************************************************
41 *******************************************************/
42 #if defined (L_mulqi3)
44 #define r_arg2 r22 /* multiplicand */
45 #define r_arg1 r24 /* multiplier */
46 #define r_res __tmp_reg__ /* result */
51 clr r_res ; clear result
55 add r_arg2,r_arg2 ; shift multiplicand
56 breq __mulqi3_exit ; while multiplicand != 0
58 brne __mulqi3_loop ; exit if multiplier = 0
60 mov r_arg1,r_res ; result to return register
68 #endif /* defined (L_mulqi3) */
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 */
85 clr r_resH ; clear result
86 clr r_resL ; clear result
90 add r_resL,r_arg2L ; result + multiplicand
93 add r_arg2L,r_arg2L ; shift multiplicand
96 cpc r_arg2L,__zero_reg__
97 breq __mulhi3_exit ; while multiplicand != 0
99 lsr r_arg1H ; gets LSB of multiplier
101 cpc r_arg1H,__zero_reg__
102 brne __mulhi3_loop ; exit if multiplier = 0
104 mov r_arg1H,r_resH ; result to return register
116 #endif /* defined (L_mulhi3) */
117 #endif /* !defined (__AVR_ENHANCED__) */
119 #if defined (L_mulsi3)
120 /*******************************************************
121 Multiplication 32 x 32
122 *******************************************************/
123 #define r_arg1L r22 /* multiplier Low */
126 #define r_arg1HH r25 /* multiplier High */
129 #define r_arg2L r18 /* multiplicand Low */
132 #define r_arg2HH r21 /* multiplicand High */
134 #define r_resL r26 /* result Low */
137 #define r_resHH r31 /* result High */
143 #if defined (__AVR_ENHANCED__)
148 mul r_arg1HL, r_arg2L
151 mul r_arg1L, r_arg2HL
154 mul r_arg1HH, r_arg2L
156 mul r_arg1HL, r_arg2H
158 mul r_arg1H, r_arg2HL
160 mul r_arg1L, r_arg2HH
162 clr r_arg1HH ; use instead of __zero_reg__ to add carry
166 adc r_resHH, r_arg1HH ; add carry
170 adc r_resHH, r_arg1HH ; add carry
172 movw r_arg1HL, r_resHL
173 clr r1 ; __zero_reg__ clobbered by "mul"
176 clr r_resHH ; clear result
177 clr r_resHL ; clear result
178 clr r_resH ; clear result
179 clr r_resL ; clear result
183 add r_resL,r_arg2L ; result + multiplicand
188 add r_arg2L,r_arg2L ; shift multiplicand
190 adc r_arg2HL,r_arg2HL
191 adc r_arg2HH,r_arg2HH
193 lsr r_arg1HH ; gets LSB of multiplier
200 brne __mulsi3_loop ; exit if multiplier = 0
202 mov r_arg1HH,r_resHH ; result to return register
207 #endif /* !defined (__AVR_ENHANCED__) */
225 #endif /* defined (L_mulsi3) */
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 */
235 #if defined (L_umodqi3)
245 #endif /* defined (L_umodqi3) */
247 #if defined (L_udivqi3)
255 #endif /* defined (L_udivqi3) */
257 #if defined (L_modqi3)
266 #endif /* defined (L_modqi3) */
268 #if defined (L_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
277 neg r_arg1 ; divident negative : negate
279 neg r_arg2 ; divisor negative : negate
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
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
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
297 neg r_rem ; correct remainder sign
300 neg r_arg1 ; correct result sign
302 ret ; result already in r24 (r_arg1)
304 #endif /* defined (L_divqi3) */
312 /*******************************************************
313 Division 16 / 16 => (result + remainder)
314 *******************************************************/
315 #define r_remL r26 /* remainder Low */
316 #define r_remH r27 /* remainder High */
318 #define r_arg1L r24 /* dividend Low */
319 #define r_arg1H r25 /* dividend High */
321 #define r_arg2L r22 /* divisor Low */
322 #define r_arg2H r23 /* divisor High */
324 #define r_cnt r21 /* loop count */
325 #if defined (L_umodhi3)
331 .global __umodhi3_ret
333 #if defined (__AVR_ENHANCED__)
341 #endif /* defined (L_umodhi3) */
343 #if defined (L_udivhi3)
351 #endif /* defined (L_udivhi3) */
353 #if defined (L_modhi3)
360 #if defined (__AVR_ENHANCED__)
363 mov r22,r24 ; needed for div () function
368 #endif /* defined (L_modhi3) */
371 #if defined (L_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
380 neg r_arg1L ; divident negative : negate
386 neg r_arg2L ; divisor negative : negate
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
396 rol r_remL ; shift dividend into remainder
398 cp r_remL,r_arg2L ; compare remainder & divisor
400 brcs __divhi3_ep ; remainder < divisor
401 sub r_remL,r_arg2L ; restore remainder
404 rol r_arg1L ; shift dividend (with CARRY)
406 dec r_cnt ; decrement loop counter
407 brne __divhi3_loop ; loop
410 neg r_remL ; correct remainder sign
415 adiw r_arg1L,1 ; correct result sign
422 #endif /* defined (L_divhi3) */
435 /*******************************************************
436 Division 32 / 32 => (result + remainder)
437 *******************************************************/
438 #define r_remHH r31 /* remainder High */
441 #define r_remL r26 /* remainder Low */
443 #define r_arg1HH r25 /* dividend High */
446 #define r_arg1L r22 /* dividend Low */
448 #define r_arg2HH r21 /* divisor High */
451 #define r_arg2L r18 /* divisor Low */
453 #define r_cnt __zero_reg__ /* loop count (0 after the loop!) */
455 #if defined (L_umodsi3)
462 .global __umodsi3_ret
464 #if defined (__AVR_ENHANCED__)
475 #endif /* defined (L_umodsi3) */
477 #if defined (L_udivsi3)
485 #endif /* defined (L_udivsi3) */
487 #if defined (L_modsi3)
495 #if defined (__AVR_ENHANCED__)
499 mov r18,r22 /* Needed for ldiv */
506 #endif /* defined (L_modsi3) */
508 #if defined (L_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
520 neg r_arg1L ; divident negative : negate
530 neg r_arg2L ; divisor negative : negate
537 ldi r_remL, 33 ; init loop counter
541 #if defined (__AVR_ENHANCED__)
545 sub r_remHH,r_remHH ; clear remainder and carry
547 rjmp __divsi3_ep ; jump to entry point
549 rol r_remL ; shift dividend into remainder
553 cp r_remL,r_arg2L ; compare remainder & divisor
557 brcs __divsi3_ep ; remainder <= divisor
558 sub r_remL,r_arg2L ; restore remainder
563 rol r_arg1L ; shift dividend (with CARRY)
567 dec r_cnt ; decrement loop counter
568 brne __divsi3_loop ; loop
569 ; __zero_reg__ now restored (r_cnt == 0)
574 neg r_remL ; correct remainder sign
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__
593 #endif /* defined (L_divsi3) */
595 /**********************************
596 * This is a prologue subroutine
597 **********************************/
598 #if defined (L_prologue)
600 .global __prologue_saves__
601 .func __prologue_saves__
625 in __tmp_reg__,__SREG__
628 out __SREG__,__tmp_reg__
632 #endif /* defined (L_prologue) */
635 * This is a epilogue subroutine
637 #if defined (L_epilogue)
639 .global __epilogue_restores__
640 .func __epilogue_restores__
641 __epilogue_restores__:
662 in __tmp_reg__,__SREG__
665 out __SREG__,__tmp_reg__
667 #if defined (__AVR_ENHANCED__)
675 #endif /* defined (L_epilogue) */
683 #endif /* defined (L_exit) */
691 #endif /* defined (L_cleanup) */
694 .global __tablejump__
697 #if defined (__AVR_ENHANCED__)
711 #endif /* defined (L_tablejump) */