]> git.ipfire.org Git - thirdparty/gcc.git/blob - libgcc/config/rl78/divmodsi.S
Update copyright years.
[thirdparty/gcc.git] / libgcc / config / rl78 / divmodsi.S
1 /* SImode div/mod functions for the GCC support library for the Renesas RL78 processors.
2 Copyright (C) 2012-2021 Free Software Foundation, Inc.
3 Contributed by Red Hat.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published
9 by the Free Software Foundation; either version 3, or (at your
10 option) any later version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 License for more details.
16
17 Under Section 7 of GPL version 3, you are granted additional
18 permissions described in the GCC Runtime Library Exception, version
19 3.1, as published by the Free Software Foundation.
20
21 You should have received a copy of the GNU General Public License and
22 a copy of the GCC Runtime Library Exception along with this program;
23 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
24 <http://www.gnu.org/licenses/>. */
25
26 #include "vregs.h"
27
28 #if defined __RL78_MUL_G14__
29
30 START_FUNC ___divsi3
31 ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
32
33 ;; Load and test for a negative denumerator.
34 movw ax, [sp+8]
35 movw de, ax
36 movw ax, [sp+10]
37 mov1 cy, a.7
38 movw hl, ax
39 bc $__div_neg_den
40
41 ;; Load and test for a negative numerator.
42 movw ax, [sp+6]
43 mov1 cy, a.7
44 movw bc, ax
45 movw ax, [sp+4]
46 bc $__div_neg_num
47
48 ;; Neither are negative - we can use the unsigned divide instruction.
49 __div_no_convert:
50 push psw
51 di
52 divwu
53 pop psw
54
55 movw r8, ax
56 movw ax, bc
57 movw r10, ax
58 ret
59
60 __div_neg_den:
61 ;; Negate the denumerator (which is in HLDE)
62 clrw ax
63 subw ax, de
64 movw de, ax
65 clrw ax
66 sknc
67 decw ax
68 subw ax, hl
69 movw hl, ax
70
71 ;; Load and test for a negative numerator.
72 movw ax, [sp+6]
73 mov1 cy, a.7
74 movw bc, ax
75 movw ax, [sp+4]
76 ;; If it is not negative then we perform the division and then negate the result.
77 bnc $__div_then_convert
78
79 ;; Otherwise we negate the numerator and then go with a straightforward unsigned division.
80 ;; The negation is complicated because AX, BC, DE and HL are already in use.
81 ;; ax: numL bc: numH r8: r10:
82 xchw ax, bc
83 ;; ax: numH bc: numL r8: r10:
84 movw r8, ax
85 ;; ax: bc: numL r8: numH r10:
86 clrw ax
87 ;; ax: 0 bc: numL r8: numH r10:
88 subw ax, bc
89 ;; ax: -numL bc: r8: numH r10:
90 movw r10, ax
91 ;; ax: bc: r8: numH r10: -numL
92 movw ax, r8
93 ;; ax: numH bc: r8: r10: -numL
94 movw bc, ax
95 ;; ax: bc: numH r8: r10: -numL
96 clrw ax
97 ;; ax: 0 bc: numH r8: r10: -numL
98 sknc
99 decw ax
100 ;; ax: -1 bc: numH r8: r10: -numL
101 subw ax, bc
102 ;; ax: -numH bc: r8: r10: -numL
103 movw bc, ax
104 ;; ax: bc: -numH r8: r10: -numL
105 movw ax, r10
106 ;; ax: -numL bc: -numH r8: r10:
107 br $!__div_no_convert
108
109 __div_neg_num:
110 ;; Negate the numerator (which is in BCAX)
111 ;; We know that the denumerator is positive.
112 ;; Note - we temporarily overwrite DE. We know that we can safely load it again off the stack again.
113 movw de, ax
114 clrw ax
115 subw ax, de
116 movw de, ax
117 clrw ax
118 sknc
119 decw ax
120 subw ax, bc
121 movw bc, ax
122
123 movw ax, [sp+8]
124 xchw ax, de
125
126 __div_then_convert:
127 push psw
128 di
129 divwu
130 pop psw
131
132 ;; Negate result (in BCAX) and transfer into r8,r10
133 movw de, ax
134 clrw ax
135 subw ax, de
136 movw r8, ax
137 clrw ax
138 sknc
139 decw ax
140 subw ax, bc
141 movw r10, ax
142 ret
143
144 END_FUNC ___divsi3
145
146 ;----------------------------------------------------------------------
147
148 START_FUNC ___udivsi3
149 ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
150 ;; Used when compiling with -Os specified.
151
152 movw ax, [sp+10]
153 movw hl, ax
154 movw ax, [sp+8]
155 movw de, ax
156 movw ax, [sp+6]
157 movw bc, ax
158 movw ax, [sp+4]
159 push psw ; Save the current interrupt status
160 di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E
161 divwu ; bcax = bcax / hlde
162 pop psw ; Restore saved interrupt status
163 movw r8, ax
164 movw ax, bc
165 movw r10, ax
166 ret
167
168 END_FUNC ___udivsi3
169
170 ;----------------------------------------------------------------------
171
172 START_FUNC ___modsi3
173 ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
174
175 ;; Load and test for a negative denumerator.
176 movw ax, [sp+8]
177 movw de, ax
178 movw ax, [sp+10]
179 mov1 cy, a.7
180 movw hl, ax
181 bc $__mod_neg_den
182
183 ;; Load and test for a negative numerator.
184 movw ax, [sp+6]
185 mov1 cy, a.7
186 movw bc, ax
187 movw ax, [sp+4]
188 bc $__mod_neg_num
189
190 ;; Neither are negative - we can use the unsigned divide instruction.
191 __mod_no_convert:
192 push psw
193 di
194 divwu
195 pop psw
196
197 movw ax, de
198 movw r8, ax
199 movw ax, hl
200 movw r10, ax
201 ret
202
203 __mod_neg_den:
204 ;; Negate the denumerator (which is in HLDE)
205 clrw ax
206 subw ax, de
207 movw de, ax
208 clrw ax
209 sknc
210 decw ax
211 subw ax, hl
212 movw hl, ax
213
214 ;; Load and test for a negative numerator.
215 movw ax, [sp+6]
216 mov1 cy, a.7
217 movw bc, ax
218 movw ax, [sp+4]
219 ;; If it is not negative then we perform the modulo operation without conversion
220 bnc $__mod_no_convert
221
222 ;; Otherwise we negate the numerator and then go with a modulo followed by negation.
223 ;; The negation is complicated because AX, BC, DE and HL are already in use.
224 xchw ax, bc
225 movw r8, ax
226 clrw ax
227 subw ax, bc
228 movw r10, ax
229 movw ax, r8
230 movw bc, ax
231 clrw ax
232 sknc
233 decw ax
234 subw ax, bc
235 movw bc, ax
236 movw ax, r10
237 br $!__mod_then_convert
238
239 __mod_neg_num:
240 ;; Negate the numerator (which is in BCAX)
241 ;; We know that the denumerator is positive.
242 ;; Note - we temporarily overwrite DE. We know that we can safely load it again off the stack again.
243 movw de, ax
244 clrw ax
245 subw ax, de
246 movw de, ax
247 clrw ax
248 sknc
249 decw ax
250 subw ax, bc
251 movw bc, ax
252
253 movw ax, [sp+8]
254 xchw ax, de
255
256 __mod_then_convert:
257 push psw
258 di
259 divwu
260 pop psw
261
262 ;; Negate result (in HLDE) and transfer into r8,r10
263 clrw ax
264 subw ax, de
265 movw r8, ax
266 clrw ax
267 sknc
268 decw ax
269 subw ax, hl
270 movw r10, ax
271 ret
272
273 END_FUNC ___modsi3
274
275 ;----------------------------------------------------------------------
276
277 START_FUNC ___umodsi3
278 ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
279 ;; Used when compiling with -Os specified.
280
281 movw ax, [sp+10]
282 movw hl, ax
283 movw ax, [sp+8]
284 movw de, ax
285 movw ax, [sp+6]
286 movw bc, ax
287 movw ax, [sp+4]
288 push psw ; Save the current interrupt status
289 di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E
290 divwu ; hlde = bcax %% hlde
291 pop psw ; Restore saved interrupt status
292 movw ax, de
293 movw r8, ax
294 movw ax, hl
295 movw r10, ax
296 ret
297
298 END_FUNC ___umodsi3
299
300 ;----------------------------------------------------------------------
301
302 #elif defined __RL78_MUL_G13__
303
304 ;----------------------------------------------------------------------
305
306 ;; Hardware registers. Note - these values match the silicon, not the documentation.
307 MDAL = 0xffff0
308 MDAH = 0xffff2
309 MDBL = 0xffff6
310 MDBH = 0xffff4
311 MDCL = 0xf00e0
312 MDCH = 0xf00e2
313 MDUC = 0xf00e8
314
315 .macro _Negate low, high
316 movw ax, \low
317 movw bc, ax
318 clrw ax
319 subw ax, bc
320 movw \low, ax
321 movw ax, \high
322 movw bc, ax
323 clrw ax
324 sknc
325 decw ax
326 subw ax, bc
327 movw \high, ax
328 .endm
329
330 ;----------------------------------------------------------------------
331
332 START_FUNC ___divsi3
333 ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
334
335 mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
336 mov !MDUC, a ; This preps the peripheral for division without interrupt generation
337
338 ;; Load and test for a negative denumerator.
339 movw ax, [sp+8]
340 movw MDBL, ax
341 movw ax, [sp+10]
342 mov1 cy, a.7
343 movw MDBH, ax
344 bc $__div_neg_den
345
346 ;; Load and test for a negative numerator.
347 movw ax, [sp+6]
348 mov1 cy, a.7
349 movw MDAH, ax
350 movw ax, [sp+4]
351 movw MDAL, ax
352 bc $__div_neg_num
353
354 ;; Neither are negative - we can use the unsigned divide hardware.
355 __div_no_convert:
356 mov a, #0xC1 ; Set the DIVST bit in MDUC
357 mov !MDUC, a ; This starts the division op
358
359 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
360 bt a.0, $1b
361
362 movw ax, MDAL ; Read the result
363 movw r8, ax
364 movw ax, MDAH
365 movw r10, ax
366 ret
367
368 __div_neg_den:
369 ;; Negate the denumerator (which is in MDBL/MDBH)
370 _Negate MDBL MDBH
371
372 ;; Load and test for a negative numerator.
373 movw ax, [sp+6]
374 mov1 cy, a.7
375 movw MDAH, ax
376 movw ax, [sp+4]
377 movw MDAL, ax
378 ;; If it is not negative then we perform the division and then negate the result.
379 bnc $__div_then_convert
380
381 ;; Otherwise we negate the numerator and then go with a straightforward unsigned division.
382 _Negate MDAL MDAH
383 br $!__div_no_convert
384
385 __div_neg_num:
386 ;; Negate the numerator (which is in MDAL/MDAH)
387 ;; We know that the denumerator is positive.
388 _Negate MDAL MDAH
389
390 __div_then_convert:
391 mov a, #0xC1 ; Set the DIVST bit in MDUC
392 mov !MDUC, a ; This starts the division op
393
394 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
395 bt a.0, $1b
396
397 ;; Negate result and transfer into r8,r10
398 _Negate MDAL MDAH ; FIXME: This could be coded more efficiently.
399 movw r10, ax
400 movw ax, MDAL
401 movw r8, ax
402
403 ret
404
405 END_FUNC ___divsi3
406
407 ;----------------------------------------------------------------------
408
409 START_FUNC ___modsi3
410 ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
411
412 mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
413 mov !MDUC, a ; This preps the peripheral for division without interrupt generation
414
415 ;; Load and test for a negative denumerator.
416 movw ax, [sp+8]
417 movw MDBL, ax
418 movw ax, [sp+10]
419 mov1 cy, a.7
420 movw MDBH, ax
421 bc $__mod_neg_den
422
423 ;; Load and test for a negative numerator.
424 movw ax, [sp+6]
425 mov1 cy, a.7
426 movw MDAH, ax
427 movw ax, [sp+4]
428 movw MDAL, ax
429 bc $__mod_neg_num
430
431 ;; Neither are negative - we can use the unsigned divide hardware
432 __mod_no_convert:
433 mov a, #0xC1 ; Set the DIVST bit in MDUC
434 mov !MDUC, a ; This starts the division op
435
436 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
437 bt a.0, $1b
438
439 movw ax, !MDCL ; Read the remainder
440 movw r8, ax
441 movw ax, !MDCH
442 movw r10, ax
443 ret
444
445 __mod_neg_den:
446 ;; Negate the denumerator (which is in MDBL/MDBH)
447 _Negate MDBL MDBH
448
449 ;; Load and test for a negative numerator.
450 movw ax, [sp+6]
451 mov1 cy, a.7
452 movw MDAH, ax
453 movw ax, [sp+4]
454 movw MDAL, ax
455 ;; If it is not negative then we perform the modulo operation without conversion
456 bnc $__mod_no_convert
457
458 ;; Otherwise we negate the numerator and then go with a modulo followed by negation.
459 _Negate MDAL MDAH
460 br $!__mod_then_convert
461
462 __mod_neg_num:
463 ;; Negate the numerator (which is in MDAL/MDAH)
464 ;; We know that the denumerator is positive.
465 _Negate MDAL MDAH
466
467 __mod_then_convert:
468 mov a, #0xC1 ; Set the DIVST bit in MDUC
469 mov !MDUC, a ; This starts the division op
470
471 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
472 bt a.0, $1b
473
474 movw ax, !MDCL
475 movw bc, ax
476 clrw ax
477 subw ax, bc
478 movw r8, ax
479 movw ax, !MDCH
480 movw bc, ax
481 clrw ax
482 sknc
483 decw ax
484 subw ax, bc
485 movw r10, ax
486 ret
487
488 END_FUNC ___modsi3
489
490 ;----------------------------------------------------------------------
491
492 START_FUNC ___udivsi3
493 ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
494 ;; Used when compilng with -Os specified.
495
496 mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
497 mov !MDUC, a ; This preps the peripheral for division without interrupt generation
498
499 movw ax, [sp+4] ; Load the divisor
500 movw MDAL, ax
501 movw ax, [sp+6]
502 movw MDAH, ax
503 movw ax, [sp+8] ; Load the dividend
504 movw MDBL, ax
505 movw ax, [sp+10]
506 movw MDBH, ax
507
508 mov a, #0xC1 ; Set the DIVST bit in MDUC
509 mov !MDUC, a ; This starts the division op
510
511 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
512 bt a.0, $1b
513
514 movw ax, !MDAL ; Read the result
515 movw r8, ax
516 movw ax, !MDAH
517 movw r10, ax
518 ret
519
520 END_FUNC ___udivsi3
521
522 ;----------------------------------------------------------------------
523
524 START_FUNC ___umodsi3
525 ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
526 ;; Used when compilng with -Os specified.
527 ;; Note - hardware address match the silicon, not the documentation
528
529 mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
530 mov !MDUC, a ; This preps the peripheral for division without interrupt generation
531
532 movw ax, [sp+4] ; Load the divisor
533 movw MDAL, ax
534 movw ax, [sp+6]
535 movw MDAH, ax
536 movw ax, [sp+8] ; Load the dividend
537 movw MDBL, ax
538 movw ax, [sp+10]
539 movw MDBH, ax
540
541 mov a, #0xC1 ; Set the DIVST bit in MDUC
542 mov !MDUC, a ; This starts the division op
543
544 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
545 bt a.0, $1b
546
547 movw ax, !MDCL ; Read the remainder
548 movw r8, ax
549 movw ax, !MDCH
550 movw r10, ax
551 ret
552
553 END_FUNC ___umodsi3
554
555 ;----------------------------------------------------------------------
556
557 #elif defined __RL78_MUL_NONE__
558
559 .macro MAKE_GENERIC which,need_result
560
561 .if \need_result
562 quot = r8
563 num = r12
564 den = r16
565 bit = r20
566 .else
567 num = r8
568 quot = r12
569 den = r16
570 bit = r20
571 .endif
572
573 quotH = quot+2
574 quotL = quot
575 quotB0 = quot
576 quotB1 = quot+1
577 quotB2 = quot+2
578 quotB3 = quot+3
579
580 numH = num+2
581 numL = num
582 numB0 = num
583 numB1 = num+1
584 numB2 = num+2
585 numB3 = num+3
586
587 #define denH bc
588 denL = den
589 denB0 = den
590 denB1 = den+1
591 #define denB2 c
592 #define denB3 b
593
594 bitH = bit+2
595 bitL = bit
596 bitB0 = bit
597 bitB1 = bit+1
598 bitB2 = bit+2
599 bitB3 = bit+3
600
601 ;----------------------------------------------------------------------
602
603 START_FUNC __generic_sidivmod\which
604
605 num_lt_den\which:
606 .if \need_result
607 movw r8, #0
608 movw r10, #0
609 .else
610 movw ax, [sp+8]
611 movw r8, ax
612 movw ax, [sp+10]
613 movw r10, ax
614 .endif
615 ret
616
617 shift_den_bit16\which:
618 movw ax, denL
619 movw denH, ax
620 movw denL, #0
621 .if \need_result
622 movw ax, bitL
623 movw bitH, ax
624 movw bitL, #0
625 .else
626 mov a, bit
627 add a, #16
628 mov bit, a
629 .endif
630 br $shift_den_bit\which
631
632 ;; These routines leave DE alone - the signed functions use DE
633 ;; to store sign information that must remain intact
634
635 .if \need_result
636 .global __generic_sidiv
637 __generic_sidiv:
638
639 .else
640
641 .global __generic_simod
642 __generic_simod:
643
644 .endif
645
646 ;; (quot,rem) = 8[sp] /% 12[sp]
647
648 movw hl, sp
649 movw ax, [hl+14] ; denH
650 cmpw ax, [hl+10] ; numH
651 movw ax, [hl+12] ; denL
652 sknz
653 cmpw ax, [hl+8] ; numL
654 bh $num_lt_den\which
655
656 #ifdef __RL78_G10__
657 movw ax, denL
658 push ax
659 movw ax, bitL
660 push ax
661 movw ax, bitH
662 push ax
663 #else
664 sel rb2
665 push ax ; denL
666 ; push bc ; denH
667 push de ; bitL
668 push hl ; bitH - stored in BC
669 sel rb0
670 #endif
671
672 ;; (quot,rem) = 16[sp] /% 20[sp]
673
674 ;; copy numerator
675 movw ax, [hl+8]
676 movw numL, ax
677 movw ax, [hl+10]
678 movw numH, ax
679
680 ;; copy denomonator
681 movw ax, [hl+12]
682 movw denL, ax
683 movw ax, [hl+14]
684 movw denH, ax
685
686 movw ax, denL
687 or a, denB2
688 or a, denB3 ; not x
689 cmpw ax, #0
690 bnz $den_not_zero\which
691 .if \need_result
692 movw quotL, #0
693 movw quotH, #0
694 .else
695 movw numL, #0
696 movw numH, #0
697 .endif
698 br $!main_loop_done_himode\which
699
700 den_not_zero\which:
701 .if \need_result
702 ;; zero out quot
703 movw quotL, #0
704 movw quotH, #0
705 .endif
706
707 ;; initialize bit to 1
708 movw bitL, #1
709 movw bitH, #0
710
711 ; while (den < num && !(den & (1L << BITS_MINUS_1)))
712
713 .if 1
714 ;; see if we can short-circuit a bunch of shifts
715 movw ax, denH
716 cmpw ax, #0
717 bnz $shift_den_bit\which
718 movw ax, denL
719 cmpw ax, numH
720 bnh $shift_den_bit16\which
721 .endif
722
723 shift_den_bit\which:
724 movw ax, denH
725 mov1 cy,a.7
726 bc $enter_main_loop\which
727 cmpw ax, numH
728 movw ax, denL ; we re-use this below
729 sknz
730 cmpw ax, numL
731 bh $enter_main_loop\which
732
733 ;; den <<= 1
734 ; movw ax, denL ; already has it from the cmpw above
735 shlw ax, 1
736 movw denL, ax
737 ; movw ax, denH
738 rolwc denH, 1
739 ; movw denH, ax
740
741 ;; bit <<= 1
742 .if \need_result
743 movw ax, bitL
744 shlw ax, 1
745 movw bitL, ax
746 movw ax, bitH
747 rolwc ax, 1
748 movw bitH, ax
749 .else
750 ;; if we don't need to compute the quotent, we don't need an
751 ;; actual bit *mask*, we just need to keep track of which bit
752 inc bitB0
753 .endif
754
755 br $shift_den_bit\which
756
757 ;; while (bit)
758 main_loop\which:
759
760 ;; if (num >= den) (cmp den > num)
761 movw ax, numH
762 cmpw ax, denH
763 movw ax, numL
764 sknz
765 cmpw ax, denL
766 skz
767 bnh $next_loop\which
768
769 ;; num -= den
770 ; movw ax, numL ; already has it from the cmpw above
771 subw ax, denL
772 movw numL, ax
773 movw ax, numH
774 sknc
775 decw ax
776 subw ax, denH
777 movw numH, ax
778
779 .if \need_result
780 ;; res |= bit
781 mov a, quotB0
782 or a, bitB0
783 mov quotB0, a
784 mov a, quotB1
785 or a, bitB1
786 mov quotB1, a
787 mov a, quotB2
788 or a, bitB2
789 mov quotB2, a
790 mov a, quotB3
791 or a, bitB3
792 mov quotB3, a
793 .endif
794
795 next_loop\which:
796
797 ;; den >>= 1
798 movw ax, denH
799 shrw ax, 1
800 movw denH, ax
801 mov a, denB1
802 rorc a, 1
803 mov denB1, a
804 mov a, denB0
805 rorc a, 1
806 mov denB0, a
807
808 ;; bit >>= 1
809 .if \need_result
810 movw ax, bitH
811 shrw ax, 1
812 movw bitH, ax
813 mov a, bitB1
814 rorc a, 1
815 mov bitB1, a
816 mov a, bitB0
817 rorc a, 1
818 mov bitB0, a
819 .else
820 dec bitB0
821 .endif
822
823 enter_main_loop\which:
824 .if \need_result
825 movw ax, bitH
826 cmpw ax, #0
827 bnz $main_loop\which
828 .else
829 cmp bitB0, #15
830 bh $main_loop\which
831 .endif
832 ;; bit is HImode now; check others
833 movw ax, numH ; numerator
834 cmpw ax, #0
835 bnz $bit_high_set\which
836 movw ax, denH ; denominator
837 cmpw ax, #0
838 bz $switch_to_himode\which
839 bit_high_set\which:
840 .if \need_result
841 movw ax, bitL
842 cmpw ax, #0
843 .else
844 cmp0 bitB0
845 .endif
846 bnz $main_loop\which
847
848 switch_to_himode\which:
849 .if \need_result
850 movw ax, bitL
851 cmpw ax, #0
852 .else
853 cmp0 bitB0
854 .endif
855 bz $main_loop_done_himode\which
856
857 ;; From here on in, r22, r14, and r18 are all zero
858 ;; while (bit)
859 main_loop_himode\which:
860
861 ;; if (num >= den) (cmp den > num)
862 movw ax, denL
863 cmpw ax, numL
864 bh $next_loop_himode\which
865
866 ;; num -= den
867 movw ax, numL
868 subw ax, denL
869 movw numL, ax
870 movw ax, numH
871 sknc
872 decw ax
873 subw ax, denH
874 movw numH, ax
875
876 .if \need_result
877 ;; res |= bit
878 mov a, quotB0
879 or a, bitB0
880 mov quotB0, a
881 mov a, quotB1
882 or a, bitB1
883 mov quotB1, a
884 .endif
885
886 next_loop_himode\which:
887
888 ;; den >>= 1
889 movw ax, denL
890 shrw ax, 1
891 movw denL, ax
892
893 .if \need_result
894 ;; bit >>= 1
895 movw ax, bitL
896 shrw ax, 1
897 movw bitL, ax
898 .else
899 dec bitB0
900 .endif
901
902 .if \need_result
903 movw ax, bitL
904 cmpw ax, #0
905 .else
906 cmp0 bitB0
907 .endif
908 bnz $main_loop_himode\which
909
910 main_loop_done_himode\which:
911 #ifdef __RL78_G10__
912 pop ax
913 movw bitH, ax
914 pop ax
915 movw bitL, ax
916 pop ax
917 movw denL, ax
918 #else
919 sel rb2
920 pop hl ; bitH - stored in BC
921 pop de ; bitL
922 ; pop bc ; denH
923 pop ax ; denL
924 sel rb0
925 #endif
926
927 ret
928 END_FUNC __generic_sidivmod\which
929 .endm
930
931 ;----------------------------------------------------------------------
932
933 MAKE_GENERIC _d 1
934 MAKE_GENERIC _m 0
935
936 ;----------------------------------------------------------------------
937
938 START_FUNC ___udivsi3
939 ;; r8 = 4[sp] / 8[sp]
940 call $!__generic_sidiv
941 ret
942 END_FUNC ___udivsi3
943
944
945 START_FUNC ___umodsi3
946 ;; r8 = 4[sp] % 8[sp]
947 call $!__generic_simod
948 ret
949 END_FUNC ___umodsi3
950
951 ;----------------------------------------------------------------------
952
953 .macro NEG_AX
954 movw hl, ax
955 movw ax, #0
956 subw ax, [hl]
957 movw [hl], ax
958 movw ax, #0
959 sknc
960 decw ax
961 subw ax, [hl+2]
962 movw [hl+2], ax
963 .endm
964
965 ;----------------------------------------------------------------------
966
967 START_FUNC ___divsi3
968 ;; r8 = 4[sp] / 8[sp]
969 movw de, #0
970 mov a, [sp+7]
971 mov1 cy, a.7
972 bc $div_signed_num
973 mov a, [sp+11]
974 mov1 cy, a.7
975 bc $div_signed_den
976 call $!__generic_sidiv
977 ret
978
979 div_signed_num:
980 ;; neg [sp+4]
981 movw ax, sp
982 addw ax, #4
983 NEG_AX
984 mov d, #1
985 mov a, [sp+11]
986 mov1 cy, a.7
987 bnc $div_unsigned_den
988 div_signed_den:
989 ;; neg [sp+8]
990 movw ax, sp
991 addw ax, #8
992 NEG_AX
993 mov e, #1
994 div_unsigned_den:
995 call $!__generic_sidiv
996
997 mov a, d
998 cmp0 a
999 bz $div_skip_restore_num
1000 ;; We have to restore the numerator [sp+4]
1001 movw ax, sp
1002 addw ax, #4
1003 NEG_AX
1004 mov a, d
1005 div_skip_restore_num:
1006 xor a, e
1007 bz $div_no_neg
1008 movw ax, #r8
1009 NEG_AX
1010 div_no_neg:
1011 mov a, e
1012 cmp0 a
1013 bz $div_skip_restore_den
1014 ;; We have to restore the denominator [sp+8]
1015 movw ax, sp
1016 addw ax, #8
1017 NEG_AX
1018 div_skip_restore_den:
1019 ret
1020 END_FUNC ___divsi3
1021
1022
1023 START_FUNC ___modsi3
1024 ;; r8 = 4[sp] % 8[sp]
1025 movw de, #0
1026 mov a, [sp+7]
1027 mov1 cy, a.7
1028 bc $mod_signed_num
1029 mov a, [sp+11]
1030 mov1 cy, a.7
1031 bc $mod_signed_den
1032 call $!__generic_simod
1033 ret
1034
1035 mod_signed_num:
1036 ;; neg [sp+4]
1037 movw ax, sp
1038 addw ax, #4
1039 NEG_AX
1040 mov d, #1
1041 mov a, [sp+11]
1042 mov1 cy, a.7
1043 bnc $mod_unsigned_den
1044 mod_signed_den:
1045 ;; neg [sp+8]
1046 movw ax, sp
1047 addw ax, #8
1048 NEG_AX
1049 mov e, #1
1050 mod_unsigned_den:
1051 call $!__generic_simod
1052
1053 mov a, d
1054 cmp0 a
1055 bz $mod_no_neg
1056 movw ax, #r8
1057 NEG_AX
1058 ;; We have to restore [sp+4] as well.
1059 movw ax, sp
1060 addw ax, #4
1061 NEG_AX
1062 mod_no_neg:
1063 .if 1
1064 mov a, e
1065 cmp0 a
1066 bz $mod_skip_restore_den
1067 movw ax, sp
1068 addw ax, #8
1069 NEG_AX
1070 mod_skip_restore_den:
1071 .endif
1072 ret
1073 END_FUNC ___modsi3
1074
1075 ;----------------------------------------------------------------------
1076
1077 #else
1078
1079 #error "Unknown RL78 hardware multiply/divide support"
1080
1081 #endif