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
/*******************************************************
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
|