aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/avr/libgcc.S
blob: 10fa12e1aade994049ef00c6e30082d7fc3f8a44 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
/*  -*- Mode: Asm -*-  */
/* Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
   Contributed by Denis Chertykov <denisc@overta.ru>

This file is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.

In addition to the permissions in the GNU General Public License, the
Free Software Foundation gives you unlimited permission to link the
compiled version of this file into combinations with other programs,
and to distribute those combinations without any restriction coming
from the use of this file.  (The General Public License restrictions
do apply in other respects; for example, they cover modification of
the file, and distribution when not linked into a combine
executable.)

This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */

#define __zero_reg__ r1
#define __tmp_reg__ r0
#define __SREG__ 0x3f
#define __SP_H__ 0x3e
#define __SP_L__ 0x3d

	.section .text.libgcc, "ax", @progbits
	
/*******************************************************
               Multiplication  8 x 8
*******************************************************/
#if defined (Lmulqi3)

#define	r_arg2	r25		/* multiplicand */
#define	r_arg1 	r24		/* multiplier */
#define r_res	__tmp_reg__	/* result */

	.global	_mulqi3
	.func	_mulqi3
_mulqi3:

	.global	_umulqi3
_umulqi3:
	clr	r_res		; clear result
__mulqi3_loop:
	sbrc	r_arg1,0
	add	r_res,r_arg2
	add	r_arg2,r_arg2	; shift multiplicand
	breq	__mulqi3_exit	; while multiplicand != 0
	lsr	r_arg1		; 
	brne	__mulqi3_loop	; exit if multiplier = 0
__mulqi3_exit:	
	mov	r_arg1,r_res	; result to return register
	ret

#undef r_arg2  
#undef r_arg1  
#undef r_res   
	
.endfunc
#endif 	/* defined (Lmulqi3) */


/*******************************************************
               Multiplication  16 x 16
*******************************************************/
#if defined (Lmulhi3)
#define	r_arg1L	r24		/* multiplier Low */
#define	r_arg1H	r25		/* multiplier High */
#define	r_arg2L	r22		/* multiplicand Low */
#define	r_arg2H	r23		/* multiplicand High */
#define r_resL	r20		/* result Low */
#define r_resH  r21		/* result High */

	.global	_mulhi3
	.func	_mulhi3
_mulhi3:

	.global	_umulhi3
_umulhi3:
	
	clr	r_resH		; clear result
	clr	r_resL		; clear result
__mulhi3_loop:
	sbrs	r_arg1L,0
	rjmp	__mulhi3_skip1
	add	r_resL,r_arg2L	; result + multiplicand
	adc	r_resH,r_arg2H
__mulhi3_skip1:	
	add	r_arg2L,r_arg2L	; shift multiplicand
	adc	r_arg2H,r_arg2H

	cpc	r_arg2L,__zero_reg__
	breq	__mulhi3_exit	; while multiplicand != 0

	lsr	r_arg1H		; gets LSB of multiplier
	ror	r_arg1L
	cpc	r_arg1H,__zero_reg__
	brne	__mulhi3_loop	; exit if multiplier = 0
__mulhi3_exit:
	mov	r_arg1H,r_resH	; result to return register
	mov	r_arg1L,r_resL
	ret

#undef r_arg1L
#undef r_arg1H
#undef r_arg2L
#undef r_arg2H
#undef r_resL 	
#undef r_resH 

.endfunc
#endif /* defined (Lmulhi3) */

#if defined (Lmulsi3)
/*******************************************************
               Multiplication  32 x 32
*******************************************************/
#define r_arg1L  r22		/* multiplier Low */
#define r_arg1H  r23
#define	r_arg1HL r24
#define	r_arg1HH r25		/* multiplier High */


#define	r_arg2L  r18		/* multiplicand Low */
#define	r_arg2H  r19	
#define	r_arg2HL r20
#define	r_arg2HH r21		/* multiplicand High */
	
#define r_resL	 r26		/* result Low */
#define r_resH   r27
#define r_resHL	 r30
#define r_resHH  r31		/* result High */

	
	.global	_mulsi3
	.func	_mulsi3
_mulsi3:

	.global	_umulsi3
_umulsi3:
	clr	r_resHH		; clear result
	clr	r_resHL		; clear result
	clr	r_resH		; clear result
	clr	r_resL		; clear result
__mulsi3_loop:
	sbrs	r_arg1L,0
	rjmp	__mulsi3_skip1
	add	r_resL,r_arg2L		; result + multiplicand
	adc	r_resH,r_arg2H
	adc	r_resHL,r_arg2HL
	adc	r_resHH,r_arg2HH
__mulsi3_skip1:
	add	r_arg2L,r_arg2L		; shift multiplicand
	adc	r_arg2H,r_arg2H
	adc	r_arg2HL,r_arg2HL
	adc	r_arg2HH,r_arg2HH
	
	lsr	r_arg1HH	; gets LSB of multiplier
	ror	r_arg1HL
	ror	r_arg1H
	ror	r_arg1L
	brne	__mulsi3_loop
	sbiw	r_arg1HL,0
	cpc	r_arg1H,r_arg1L
	brne	__mulsi3_loop		; exit if multiplier = 0
__mulsi3_exit:
	mov	r_arg1HH,r_resHH	; result to return register
	mov	r_arg1HL,r_resHL
	mov	r_arg1H,r_resH
	mov	r_arg1L,r_resL
	ret
#undef r_arg1L 
#undef r_arg1H 
#undef r_arg1HL
#undef r_arg1HH
             
             
#undef r_arg2L 
#undef r_arg2H 
#undef r_arg2HL
#undef r_arg2HH
             
#undef r_resL  
#undef r_resH  
#undef r_resHL 
#undef r_resHH 

.endfunc
#endif /* defined (Lmulsi3) */
	
/*******************************************************
       Division 8 / 8 => (result + remainder)
*******************************************************/
#define	r_rem	r26	/* remainder */
#define	r_arg1	r25	/* dividend */
#define	r_arg2	r24	/* divisor */
#define	r_cnt	r27	/* loop count */

#if defined (Lumodqi3)

	.global	_umodqi3
	.func	_umodqi3
_umodqi3:
	clt
	rcall	_udivqi3
	mov	r24,r_rem
	ret
.endfunc
#endif /* defined (Lumodqi3) */
	
#if defined (Ludivqi3)

	.global	_udivqi3
	.func	_udivqi3
_udivqi3:
	clr	__tmp_reg__
	rjmp	_divqi_raw
.endfunc
#endif /* defined (Ludivqi3) */

#if defined (Lmodqi3)
	
	.global	_moqhi3
	.func	_moqhi3
_modqi3:
	rcall	_divqi3
	mov	r24,r_rem
	ret
.endfunc
#endif /* defined (Lmodqi3) */

#if defined (Ldivqi3)

	.global	_divqi3
	.func	_divqi3
_divqi3:
        bst     r_arg1,7	; store sign of divident
        mov     __tmp_reg__,r_arg1
        eor     __tmp_reg__,r_arg2; r0.7 is sign of result
        sbrc	r_arg1,7
        neg     r_arg1		; divident negative : negate
        sbrc	r_arg2,7
        neg     r_arg2		; divisor negative : negate
	.global	_divqi_raw
_divqi_raw:	
	sub	r_rem,r_rem	; clear remainder and carry
	ldi	r_cnt,9		; init loop counter
	rjmp	__divqi3_ep	; jump to entry point
__divqi3_loop:
        rol	r_rem		; shift dividend into remainder
        cp	r_rem,r_arg2	; compare remainder & divisor
        brcs	__divqi3_ep	; remainder <= divisor
        sub	r_rem,r_arg2	; restore remainder
__divqi3_ep:
        rol	r_arg1		; shift dividend (with CARRY)
        dec	r_cnt		; decrement loop counter
        brne	__divqi3_loop	; loop
	com	r_arg1		; complement result 
				; because C flag was complemented in loop
	brtc	__divqi3_1
	neg	r_rem		; correct remainder sign
__divqi3_1:
	sbrc	__tmp_reg__,7
	neg	r_arg1		; correct result sign
__divqi3_exit:
	mov	r24,r_arg1	; put result to return register
	ret
.endfunc
#endif /* defined (Ldivqi3) */

#undef r_rem
#undef r_arg1
#undef r_arg2
#undef r_cnt
	
		
/*******************************************************
       Division 16 / 16 => (result + remainder)
*******************************************************/
#define	r_remL	r26	/* remainder Low */
#define	r_remH	r27	/* remainder High */
	
#define	r_arg1L	r24	/* dividend Low */
#define	r_arg1H	r25	/* dividend High */
	
#define	r_arg2L	r22	/* divisor Low */
#define	r_arg2H	r23	/* divisor High */
	
#define	r_cnt	r21	/* loop count */
#if defined (Lumodhi3)
	
	.global	_umodhi3
	.func	_umodhi3
_umodhi3:
	clt
	rcall	_udivhi3
	.global	_umodhi3_ret
_umodhi3_ret:
	mov	r24,r_remL
	mov	r25,r_remH
	ret
.endfunc
#endif /* defined (Lumodhi3) */
	
#if defined (Ludivhi3)
	
	.global	_udivhi3
	.func	_udivhi3
_udivhi3:
	clr	__tmp_reg__
	rjmp	_divhi_raw
.endfunc
#endif /* defined (Ludivhi3) */

#if defined (Lmodhi3)
	
	.global	_modhi3
	.func	_modhi3
_modhi3:
	.global	_div
_div:
	rcall	_divhi3
	mov	r22,r24		; needed for div () function
	mov	r23,r25
	rjmp	_umodhi3_ret
.endfunc
#endif /* defined (Lmodhi3) */
	
	
#if defined (Ldivhi3)
	
	.global	_divhi3
	.func	_divhi3
_divhi3:
        bst     r_arg1H,7	; store sign of divident
        mov     __tmp_reg__,r_arg1H
        eor     __tmp_reg__,r_arg2H   ; r0.7 is sign of result
	brtc	__divhi3_skip1
	com	r_arg1H
        neg     r_arg1L		; divident negative : negate
	sbci	r_arg1H,0xff
__divhi3_skip1:
        tst	r_arg2H
	brpl	__divhi3_skip2
	com	r_arg2H
        neg     r_arg2L		; divisor negative : negate
	sbci	r_arg2H,0xff
__divhi3_skip2:
	.global	_divhi_raw
_divhi_raw:
	sub	r_remL,r_remL
	sub	r_remH,r_remH		; clear remainder and carry
	ldi	r_cnt,17	; init loop counter
	rjmp	__divhi3_ep	; jump to entry point
__divhi3_loop:
        rol	r_remL		; shift dividend into remainder
	rol	r_remH
        cp	r_remL,r_arg2L	; compare remainder & divisor
	cpc	r_remH,r_arg2H
        brcs	__divhi3_ep	; remainder < divisor
        sub	r_remL,r_arg2L	; restore remainder
        sbc	r_remH,r_arg2H
__divhi3_ep:
        rol	r_arg1L		; shift dividend (with CARRY)
        rol	r_arg1H
        dec	r_cnt		; decrement loop counter
        brne	__divhi3_loop	; loop
	brtc	__divhi3_1
	com	r_remH
	neg	r_remL		; correct remainder sign
	sbci	r_remH,0xff
__divhi3_1:
	tst	__tmp_reg__
	brpl	__divhi3_exit
	adiw	r_arg1L,1	; correct result sign
	ret
__divhi3_exit:
	com	r_arg1L
	com	r_arg1H
	ret
.endfunc
#endif /* defined (Ldivhi3) */
	
#undef r_remH  
#undef r_remL  
             
#undef r_arg1H 
#undef r_arg1L 
             
#undef r_arg2H 
#undef r_arg2L 
             	
#undef r_cnt   	
	
/*******************************************************
       Division 32 / 32 => (result + remainder)
*******************************************************/
#define	r_remHH	r31	/* remainder High */
#define	r_remHL	r30
#define	r_remH	r27
#define	r_remL	r26	/* remainder Low */
	
#define	r_arg1HH r25	/* dividend High */
#define	r_arg1HL r24
#define	r_arg1H  r23
#define	r_arg1L  r22	/* dividend Low */
	
#define	r_arg2HH r21	/* divisor High */
#define	r_arg2HL r20
#define	r_arg2H  r19
#define	r_arg2L  r18	/* divisor Low */
	
#define	r_cnt	r17	/* loop count */

#if defined (Lumodsi3)

	.global	_umodsi3
	.func	_umodsi3
_umodsi3:
	clt
	rcall	_udivsi3
	.global	_umodsi3_ret
_umodsi3_ret:
	mov	r25,r_remHH
	mov	r24,r_remHL
	mov	r23,r_remH
	mov	r22,r_remL
	.global	_cleanup
_cleanup:
	ret
.endfunc
#endif /* defined (Lumodsi3) */
	
#if defined (Ludivsi3)

	.global	_udivsi3
	.func	_udivsi3
_udivsi3:
	clr	__tmp_reg__
	rjmp	_divsi_raw
.endfunc
#endif /* defined (Ludivsi3) */

#if defined (Lmodsi3)
	
	.global	_modsi3
	.func	_modsi3
_modsi3:
	.global	_ldiv
_ldiv:
	rcall	_divsi3
	mov	r18,r22		/* Needed for ldiv */
	mov	r19,r23
	mov	r20,r24
	mov	r21,r25
	rjmp	_umodsi3_ret
.endfunc
#endif /* defined (Lmodsi3) */

#if defined (Ldivsi3)

	.global	_divsi3
	.func	_divsi3
_divsi3:
        bst     r_arg1HH,7	; store sign of divident
        mov     __tmp_reg__,r_arg1HH
        eor     __tmp_reg__,r_arg2HH   ; r0.7 is sign of result
	brtc	__divsi3_skip1
	com	r_arg1HH
	com	r_arg1HL
	com	r_arg1H
        neg     r_arg1L		; divident negative : negate
	sbci	r_arg1H, 0xff
	sbci	r_arg1HL,0xff
	sbci	r_arg1HH,0xff
__divsi3_skip1:
        tst	r_arg2HH
	brpl	__divsi3_skip2
	com	r_arg2HH
	com	r_arg2HL
	com	r_arg2H
        neg     r_arg2L		; divisor negative : negate
	sbci	r_arg2H, 0xff
	sbci	r_arg2HL,0xff
	sbci	r_arg2HH,0xff
__divsi3_skip2:
	.global	_divsi_raw
_divsi_raw:
	push	r_cnt
	sub	r_remL,r_remL
	sub	r_remH,r_remH
	sub	r_remHL,r_remHL
	sub	r_remHH,r_remHH	; clear remainder and carry
	ldi	r_cnt,33	; init loop counter
	rjmp	__divsi3_ep	; jump to entry point
__divsi3_loop:
        rol	r_remL		; shift dividend into remainder
	rol	r_remH
	rol	r_remHL
	rol	r_remHH
        cp	r_remL,r_arg2L	; compare remainder & divisor
	cpc	r_remH,r_arg2H
	cpc	r_remHL,r_arg2HL
	cpc	r_remHH,r_arg2HH
        brcs	__divsi3_ep	; remainder <= divisor
        sub	r_remL,r_arg2L	; restore remainder
        sbc	r_remH,r_arg2H
        sbc	r_remHL,r_arg2HL
        sbc	r_remHH,r_arg2HH
__divsi3_ep:
        rol	r_arg1L		; shift dividend (with CARRY)
        rol	r_arg1H
        rol	r_arg1HL
        rol	r_arg1HH
        dec	r_cnt		; decrement loop counter
        brne	__divsi3_loop	; loop
	pop	r_cnt
	brtc	__divsi3_1
	com	r_remHH
	com	r_remHL
	com	r_remH
	neg	r_remL		; correct remainder sign
	sbci	r_remH, 0xff
	sbci	r_remHL,0xff
	sbci	r_remHH,0xff
__divsi3_1:
	rol	__tmp_reg__
	brcc	__divsi3_exit
	adc	r_arg1L,__zero_reg__; correct result sign
	adc	r_arg1H,__zero_reg__
	adc	r_arg1HL,__zero_reg__
	adc	r_arg1HH,__zero_reg__
	ret
__divsi3_exit:
	com	r_arg1L
	com	r_arg1H
	com	r_arg1HL
	com	r_arg1HH
	ret
.endfunc
#endif /* defined (Ldivsi3) */

/**********************************
 * This is a prologue subroutine
 **********************************/
#if defined (Lprologue)

	.global	__prologue_saves__
	.func	__prologue_saves__
__prologue_saves__:
	push r2
	push r3
	push r4
	push r5
	push r6
	push r7
	push r8
	push r9
	push r10
	push r11
	push r12
	push r13
	push r14
	push r15
	push r16
	push r17
	push r28
	push r29
	in	r28,__SP_L__
	in	r29,__SP_H__
	sbiw r26,0
	breq _prologue_end
	sub	r28,r26
	sbc	r29,r27
	in	__tmp_reg__,__SREG__
	cli
	out	__SP_L__,r28
	out	__SREG__,__tmp_reg__
	out	__SP_H__,r29
_prologue_end:
	ijmp
.endfunc
#endif /* defined (Lprologue) */

/*
 * This is a epilogue subroutine
 */
#if defined (Lepilogue)

	.global	__epilogue_restores__
	.func	__epilogue_restores__
__epilogue_restores__:
	ldd	r2,Y+18
	ldd	r3,Y+17
	ldd	r4,Y+16
	ldd	r5,Y+15
	ldd	r6,Y+14
	ldd	r7,Y+13
	ldd	r8,Y+12
	ldd	r9,Y+11
	ldd	r10,Y+10
	ldd	r11,Y+9
	ldd	r12,Y+8
	ldd	r13,Y+7
	ldd	r14,Y+6
	ldd	r15,Y+5
	ldd	r16,Y+4
	ldd	r17,Y+3
	ldd	r26,Y+2
	ldd	r27,Y+1
	add	r28,r30
	adc	r29,__zero_reg__
	in	__tmp_reg__,__SREG__
	cli
	out	__SP_L__,r28
	out	__SREG__,__tmp_reg__
	out	__SP_H__,r29
	mov	r28,r26
	mov	r29,r27
	ret
#endif /* defined (Lepilogue) */

#ifdef L__exit
	.global	_exit
	.func	_exit
_exit:
	rjmp	_exit
.endfunc
#endif