Daily bump.
[official-gcc.git] / libgcc / config / rl78 / divmodsi.S
blob987a9e31126a79729aefdefb584e95b8e29fb2f8
1 /* SImode div/mod functions for the GCC support library for the Renesas RL78 processors.
2    Copyright (C) 2012-2015 Free Software Foundation, Inc.
3    Contributed by Red Hat.
5    This file is part of GCC.
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.
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.
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.
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/>.  */
26 #include "vregs.h"
28 #if defined __RL78_MUL_G14__
30 START_FUNC ___divsi3
31         ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
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
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
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
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
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
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
123         movw    ax, [sp+8]
124         xchw    ax, de
125         
126 __div_then_convert:
127         push    psw
128         di
129         divwu
130         pop     psw
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
144 END_FUNC ___divsi3
146 ;----------------------------------------------------------------------
148 START_FUNC ___udivsi3
149         ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
150         ;; Used when compiling with -Os specified.
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
168 END_FUNC ___udivsi3
170 ;----------------------------------------------------------------------
171         
172 START_FUNC ___modsi3
173         ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
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
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
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
197         movw    ax, de
198         movw    r8, ax
199         movw    ax, hl
200         movw    r10, ax
201         ret
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
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
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
253         movw    ax, [sp+8]
254         xchw    ax, de
255         
256 __mod_then_convert:
257         push    psw
258         di
259         divwu
260         pop     psw
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
273 END_FUNC ___modsi3
275 ;----------------------------------------------------------------------
277 START_FUNC ___umodsi3
278         ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
279         ;; Used when compiling with -Os specified.
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
298 END_FUNC   ___umodsi3
300 ;----------------------------------------------------------------------
302 #elif defined __RL78_MUL_G13__
304 ;----------------------------------------------------------------------
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
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 ;----------------------------------------------------------------------
332 START_FUNC ___divsi3
333         ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
335         mov     a, #0xC0        ; Set DIVMODE=1 and MACMODE=1
336         mov     !MDUC, a        ; This preps the peripheral for division without interrupt generation
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
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
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
359 1:      mov     a, !MDUC        ; Wait 16 clocks or until DIVST is clear
360         bt      a.0, $1b
362         movw    ax, MDAL        ; Read the result
363         movw    r8, ax
364         movw    ax, MDAH
365         movw    r10, ax 
366         ret
368 __div_neg_den:
369         ;; Negate the denumerator (which is in MDBL/MDBH)
370         _Negate MDBL MDBH
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
381         ;; Otherwise we negate the numerator and then go with a straightforward unsigned division.
382         _Negate MDAL MDAH
383         br      $!__div_no_convert
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
394 1:      mov     a, !MDUC        ; Wait 16 clocks or until DIVST is clear
395         bt      a.0, $1b
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
403         ret
405 END_FUNC ___divsi3
407 ;----------------------------------------------------------------------
409 START_FUNC ___modsi3
410         ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
412         mov     a, #0xC0        ; Set DIVMODE=1 and MACMODE=1
413         mov     !MDUC, a        ; This preps the peripheral for division without interrupt generation
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
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
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
436 1:      mov     a, !MDUC        ; Wait 16 clocks or until DIVST is clear
437         bt      a.0, $1b
439         movw    ax, !MDCL       ; Read the remainder
440         movw    r8, ax
441         movw    ax, !MDCH
442         movw    r10, ax 
443         ret
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
458         ;; Otherwise we negate the numerator and then go with a modulo followed by negation.
459         _Negate MDAL MDAH
460         br      $!__mod_then_convert
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
471 1:      mov     a, !MDUC        ; Wait 16 clocks or until DIVST is clear
472         bt      a.0, $1b
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
488 END_FUNC ___modsi3
490 ;----------------------------------------------------------------------
492 START_FUNC ___udivsi3
493         ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
494         ;; Used when compilng with -Os specified.
496         mov     a, #0xC0        ; Set DIVMODE=1 and MACMODE=1
497         mov     !MDUC, a        ; This preps the peripheral for division without interrupt generation
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
511 1:      mov     a, !MDUC        ; Wait 16 clocks or until DIVST is clear
512         bt      a.0, $1b
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
522 ;----------------------------------------------------------------------
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
529         mov     a, #0xC0        ; Set DIVMODE=1 and MACMODE=1
530         mov     !MDUC, a        ; This preps the peripheral for division without interrupt generation
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
544 1:      mov     a, !MDUC        ; Wait 16 clocks or until DIVST is clear
545         bt      a.0, $1b
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
555 ;----------------------------------------------------------------------
557 #elif defined __RL78_MUL_NONE__
559 .macro MAKE_GENERIC  which,need_result
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
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
601 ;----------------------------------------------------------------------
603 START_FUNC __generic_sidivmod\which
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
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
632         ;; These routines leave DE alone - the signed functions use DE
633         ;; to store sign information that must remain intact
635         .if \need_result
636         .global __generic_sidiv
637 __generic_sidiv:
639         .else
641         .global __generic_simod
642 __generic_simod:
644         .endif
646         ;; (quot,rem) = 8[sp] /% 12[sp]
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
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
672         ;; (quot,rem) = 16[sp] /% 20[sp]
674         ;; copy numerator
675         movw    ax, [hl+8]
676         movw    numL, ax
677         movw    ax, [hl+10]
678         movw    numH, ax
680         ;; copy denomonator
681         movw    ax, [hl+12]
682         movw    denL, ax
683         movw    ax, [hl+14]
684         movw    denH, ax
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         movw    numL, #0
692         movw    numH, #0
693         ret
695 den_not_zero\which:
696         .if \need_result
697         ;; zero out quot
698         movw    quotL, #0
699         movw    quotH, #0
700         .endif
702         ;; initialize bit to 1
703         movw    bitL, #1
704         movw    bitH, #0
706 ; while (den < num && !(den & (1L << BITS_MINUS_1)))
708         .if 1
709         ;; see if we can short-circuit a bunch of shifts
710         movw    ax, denH
711         cmpw    ax, #0
712         bnz     $shift_den_bit\which
713         movw    ax, denL
714         cmpw    ax, numH
715         bnh     $shift_den_bit16\which
716         .endif
718 shift_den_bit\which:    
719         movw    ax, denH
720         mov1    cy,a.7
721         bc      $enter_main_loop\which
722         cmpw    ax, numH
723         movw    ax, denL        ; we re-use this below
724         sknz
725         cmpw    ax, numL
726         bh      $enter_main_loop\which
728         ;; den <<= 1
729 ;       movw    ax, denL        ; already has it from the cmpw above
730         shlw    ax, 1
731         movw    denL, ax
732 ;       movw    ax, denH
733         rolwc   denH, 1
734 ;       movw    denH, ax
736         ;; bit <<= 1
737         .if \need_result
738         movw    ax, bitL
739         shlw    ax, 1
740         movw    bitL, ax
741         movw    ax, bitH
742         rolwc   ax, 1
743         movw    bitH, ax
744         .else
745         ;; if we don't need to compute the quotent, we don't need an
746         ;; actual bit *mask*, we just need to keep track of which bit
747         inc     bitB0
748         .endif
750         br      $shift_den_bit\which
752         ;; while (bit)
753 main_loop\which:
755         ;; if (num >= den) (cmp den > num)
756         movw    ax, numH
757         cmpw    ax, denH
758         movw    ax, numL
759         sknz
760         cmpw    ax, denL
761         skz
762         bnh     $next_loop\which
764         ;; num -= den
765 ;       movw    ax, numL        ; already has it from the cmpw above
766         subw    ax, denL
767         movw    numL, ax
768         movw    ax, numH
769         sknc
770         decw    ax
771         subw    ax, denH
772         movw    numH, ax
774         .if \need_result
775         ;; res |= bit
776         mov     a, quotB0
777         or      a, bitB0
778         mov     quotB0, a
779         mov     a, quotB1
780         or      a, bitB1
781         mov     quotB1, a
782         mov     a, quotB2
783         or      a, bitB2
784         mov     quotB2, a
785         mov     a, quotB3
786         or      a, bitB3
787         mov     quotB3, a
788         .endif
790 next_loop\which:        
792         ;; den >>= 1
793         movw    ax, denH
794         shrw    ax, 1
795         movw    denH, ax
796         mov     a, denB1
797         rorc    a, 1
798         mov     denB1, a
799         mov     a, denB0
800         rorc    a, 1
801         mov     denB0, a
803         ;; bit >>= 1
804         .if \need_result
805         movw    ax, bitH
806         shrw    ax, 1
807         movw    bitH, ax
808         mov     a, bitB1
809         rorc    a, 1
810         mov     bitB1, a
811         mov     a, bitB0
812         rorc    a, 1
813         mov     bitB0, a
814         .else
815         dec     bitB0
816         .endif
818 enter_main_loop\which:
819         .if \need_result
820         movw    ax, bitH
821         cmpw    ax, #0
822         bnz     $main_loop\which
823         .else
824         cmp     bitB0, #15
825         bh      $main_loop\which
826         .endif
827         ;; bit is HImode now; check others
828         movw    ax, numH        ; numerator
829         cmpw    ax, #0
830         bnz     $bit_high_set\which
831         movw    ax, denH        ; denominator
832         cmpw    ax, #0
833         bz      $switch_to_himode\which
834 bit_high_set\which:     
835         .if \need_result
836         movw    ax, bitL
837         cmpw    ax, #0
838         .else
839         cmp0    bitB0
840         .endif
841         bnz     $main_loop\which
843 switch_to_himode\which:
844         .if \need_result
845         movw    ax, bitL
846         cmpw    ax, #0
847         .else
848         cmp0    bitB0
849         .endif
850         bz      $main_loop_done_himode\which
852         ;; From here on in, r22, r14, and r18 are all zero
853         ;; while (bit)
854 main_loop_himode\which:
856         ;; if (num >= den) (cmp den > num)
857         movw    ax, denL
858         cmpw    ax, numL
859         bh      $next_loop_himode\which
861         ;; num -= den
862         movw    ax, numL
863         subw    ax, denL
864         movw    numL, ax
865         movw    ax, numH
866         sknc
867         decw    ax
868         subw    ax, denH
869         movw    numH, ax
871         .if \need_result
872         ;; res |= bit
873         mov     a, quotB0
874         or      a, bitB0
875         mov     quotB0, a
876         mov     a, quotB1
877         or      a, bitB1
878         mov     quotB1, a
879         .endif
881 next_loop_himode\which: 
883         ;; den >>= 1
884         movw    ax, denL
885         shrw    ax, 1
886         movw    denL, ax
888         .if \need_result
889         ;; bit >>= 1
890         movw    ax, bitL
891         shrw    ax, 1
892         movw    bitL, ax
893         .else
894         dec     bitB0
895         .endif
897         .if \need_result
898         movw    ax, bitL
899         cmpw    ax, #0
900         .else
901         cmp0    bitB0
902         .endif
903         bnz     $main_loop_himode\which
905 main_loop_done_himode\which:    
906 #ifdef __RL78_G10__
907         pop     ax
908         movw    bitH, ax
909         pop     ax
910         movw    bitL, ax
911         pop     ax
912         movw    denL, ax
913 #else
914         sel     rb2
915         pop     hl              ; bitH - stored in BC
916         pop     de              ; bitL
917 ;       pop     bc              ; denH
918         pop     ax              ; denL
919         sel     rb0
920 #endif
922         ret
923 END_FUNC __generic_sidivmod\which
924 .endm
926 ;----------------------------------------------------------------------
928         MAKE_GENERIC _d 1
929         MAKE_GENERIC _m 0
931 ;----------------------------------------------------------------------
933 START_FUNC ___udivsi3
934         ;; r8 = 4[sp] / 8[sp]
935         call    $!__generic_sidiv
936         ret
937 END_FUNC ___udivsi3
938         
940 START_FUNC ___umodsi3
941         ;; r8 = 4[sp] % 8[sp]
942         call    $!__generic_simod
943         ret
944 END_FUNC ___umodsi3
946 ;----------------------------------------------------------------------
948 .macro NEG_AX
949         movw    hl, ax
950         movw    ax, #0
951         subw    ax, [hl]
952         movw    [hl], ax
953         movw    ax, #0
954         sknc
955         decw    ax
956         subw    ax, [hl+2]
957         movw    [hl+2], ax
958 .endm
960 ;----------------------------------------------------------------------
962 START_FUNC ___divsi3
963         ;; r8 = 4[sp] / 8[sp]
964         movw    de, #0
965         mov     a, [sp+7]
966         mov1    cy, a.7
967         bc      $div_signed_num
968         mov     a, [sp+11]
969         mov1    cy, a.7
970         bc      $div_signed_den
971         call    $!__generic_sidiv
972         ret
974 div_signed_num:
975         ;; neg [sp+4]
976         movw    ax, sp
977         addw    ax, #4
978         NEG_AX
979         mov     d, #1
980         mov     a, [sp+11]
981         mov1    cy, a.7
982         bnc     $div_unsigned_den
983 div_signed_den: 
984         ;; neg [sp+8]
985         movw    ax, sp
986         addw    ax, #8
987         NEG_AX
988         mov     e, #1
989 div_unsigned_den:       
990         call    $!__generic_sidiv
992         mov     a, d
993         cmp0    a
994         bz      $div_skip_restore_num
995         ;;  We have to restore the numerator [sp+4]
996         movw    ax, sp
997         addw    ax, #4
998         NEG_AX
999         mov     a, d
1000 div_skip_restore_num:   
1001         xor     a, e
1002         bz      $div_no_neg
1003         movw    ax, #r8
1004         NEG_AX
1005 div_no_neg:
1006         mov     a, e
1007         cmp0    a
1008         bz      $div_skip_restore_den
1009         ;;  We have to restore the denominator [sp+8]
1010         movw    ax, sp
1011         addw    ax, #8
1012         NEG_AX
1013 div_skip_restore_den:
1014         ret
1015 END_FUNC ___divsi3
1016         
1018 START_FUNC ___modsi3
1019         ;; r8 = 4[sp] % 8[sp]
1020         movw    de, #0
1021         mov     a, [sp+7]
1022         mov1    cy, a.7
1023         bc      $mod_signed_num
1024         mov     a, [sp+11]
1025         mov1    cy, a.7
1026         bc      $mod_signed_den
1027         call    $!__generic_simod
1028         ret
1030 mod_signed_num:
1031         ;; neg [sp+4]
1032         movw    ax, sp
1033         addw    ax, #4
1034         NEG_AX
1035         mov     d, #1
1036         mov     a, [sp+11]
1037         mov1    cy, a.7
1038         bnc     $mod_unsigned_den
1039 mod_signed_den: 
1040         ;; neg [sp+8]
1041         movw    ax, sp
1042         addw    ax, #8
1043         NEG_AX
1044         mov     e, #1
1045 mod_unsigned_den:       
1046         call    $!__generic_simod
1048         mov     a, d
1049         cmp0    a
1050         bz      $mod_no_neg
1051         movw    ax, #r8
1052         NEG_AX
1053         ;;  We have to restore [sp+4] as well.
1054         movw    ax, sp
1055         addw    ax, #4
1056         NEG_AX
1057 mod_no_neg:
1058  .if 1
1059         mov     a, e
1060         cmp0    a
1061         bz      $mod_skip_restore_den
1062         movw    ax, sp
1063         addw    ax, #8
1064         NEG_AX
1065 mod_skip_restore_den:   
1066  .endif 
1067         ret
1068 END_FUNC ___modsi3
1070 ;----------------------------------------------------------------------
1072 #else
1074 #error "Unknown RL78 hardware multiply/divide support"
1076 #endif