CWG 616, 1213 - value category of subobject references.
[official-gcc.git] / libgcc / config / rl78 / divmodsi.S
blob9e5a8d659f109d96a69b86cce78980d17dc48c01
1 /* SImode div/mod functions for the GCC support library for the Renesas RL78 processors.
2    Copyright (C) 2012-2018 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         .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
700 den_not_zero\which:
701         .if \need_result
702         ;; zero out quot
703         movw    quotL, #0
704         movw    quotH, #0
705         .endif
707         ;; initialize bit to 1
708         movw    bitL, #1
709         movw    bitH, #0
711 ; while (den < num && !(den & (1L << BITS_MINUS_1)))
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
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
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
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
755         br      $shift_den_bit\which
757         ;; while (bit)
758 main_loop\which:
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
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
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
795 next_loop\which:        
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
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
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
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
857         ;; From here on in, r22, r14, and r18 are all zero
858         ;; while (bit)
859 main_loop_himode\which:
861         ;; if (num >= den) (cmp den > num)
862         movw    ax, denL
863         cmpw    ax, numL
864         bh      $next_loop_himode\which
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
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
886 next_loop_himode\which: 
888         ;; den >>= 1
889         movw    ax, denL
890         shrw    ax, 1
891         movw    denL, ax
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
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
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
927         ret
928 END_FUNC __generic_sidivmod\which
929 .endm
931 ;----------------------------------------------------------------------
933         MAKE_GENERIC _d 1
934         MAKE_GENERIC _m 0
936 ;----------------------------------------------------------------------
938 START_FUNC ___udivsi3
939         ;; r8 = 4[sp] / 8[sp]
940         call    $!__generic_sidiv
941         ret
942 END_FUNC ___udivsi3
943         
945 START_FUNC ___umodsi3
946         ;; r8 = 4[sp] % 8[sp]
947         call    $!__generic_simod
948         ret
949 END_FUNC ___umodsi3
951 ;----------------------------------------------------------------------
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
965 ;----------------------------------------------------------------------
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
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
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         
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
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
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
1075 ;----------------------------------------------------------------------
1077 #else
1079 #error "Unknown RL78 hardware multiply/divide support"
1081 #endif