1 /* HImode div/mod functions for the GCC support library for the Renesas RL78 processors.
2 Copyright (C) 2012-2024 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
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public 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/>. */
28 #if defined __RL78_MUL_G14__
33 ;; Test for a negative denumerator.
39 ;; Test for a negative numerator.
44 ;; Neither are negative - we can use the unsigned divide instruction.
55 ;; Negate the denumerator (which is in DE)
60 ;; Test for a negative numerator.
63 ;; If it is not negative then we perform the division and then negate the result.
64 bnc $__div_then_convert
66 ;; Otherwise we negate the numerator and then go with an unsigned division.
73 ;; Negate the numerator (which is in AX)
74 ;; We know that the denumerator is positive.
85 ;; Negate result and transfer into r8
94 ;----------------------------------------------------------------------
99 ;; Test for a negative denumerator.
105 ;; Test for a negative numerator.
110 ;; Neither are negative - we can use the unsigned divide instruction.
122 ;; Negate the denumerator (which is in DE)
127 ;; Test for a negative numerator.
130 ;; If it is not negative then we perform the modulo operation without conversion.
131 bnc $__mod_no_convert
133 ;; Otherwise we negate the numerator and then go with an unsigned modulo operation.
137 br $__mod_then_convert
140 ;; Negate the numerator (which is in AX)
141 ;; We know that the denumerator is positive.
152 ;; Negate result and transfer into r8
160 ;----------------------------------------------------------------------
162 #elif defined __RL78_MUL_G13__
164 ;; The G13 S2 core does not have a 16 bit divide peripheral.
165 ;; So instead we perform a 32-bit divide and twiddle the inputs
168 ;; Hardware registers. Note - these values match the silicon, not the documentation.
177 .macro _Negate src, dest
185 ;----------------------------------------------------------------------
188 ;; r8 = 4[sp] / 6[sp] (signed division)
190 mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
191 mov !MDUC, a ; This preps the peripheral for division without interrupt generation
193 clrw ax ; Clear the top 16-bits of the divisor and dividend
197 ;; Load and test for a negative denumerator.
203 ;; Load and test for a negative numerator.
209 ;; Neither are negative - we can use the unsigned divide hardware.
211 mov a, #0xC1 ; Set the DIVST bit in MDUC
212 mov !MDUC, a ; This starts the division op
214 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
217 movw ax, MDAL ; Read the result
222 ;; Negate the denumerator (which is in MDBL)
225 ;; Load and test for a negative numerator.
229 ;; If it is not negative then we perform the division and then negate the result.
230 bnc $__div_then_convert
232 ;; Otherwise we negate the numerator and then go with a straightforward unsigned division.
234 br $!__div_no_convert
237 ;; Negate the numerator (which is in MDAL)
238 ;; We know that the denumerator is positive.
242 mov a, #0xC1 ; Set the DIVST bit in MDUC
243 mov !MDUC, a ; This starts the division op
245 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
248 ;; Negate result and transfer into r8
254 ;----------------------------------------------------------------------
257 ;; r8 = 4[sp] % 6[sp] (signed modulus)
259 mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
260 mov !MDUC, a ; This preps the peripheral for division without interrupt generation
262 clrw ax ; Clear the top 16-bits of the divisor and dividend
266 ;; Load and test for a negative denumerator.
272 ;; Load and test for a negative numerator.
278 ;; Neither are negative - we can use the unsigned divide hardware
280 mov a, #0xC1 ; Set the DIVST bit in MDUC
281 mov !MDUC, a ; This starts the division op
283 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
286 movw ax, !MDCL ; Read the remainder
291 ;; Negate the denumerator (which is in MDBL)
294 ;; Load and test for a negative numerator.
298 ;; If it is not negative then we perform the modulo operation without conversion.
299 bnc $__mod_no_convert
301 ;; Otherwise we negate the numerator and then go with a modulo followed by negation.
303 br $!__mod_then_convert
306 ;; Negate the numerator (which is in MDAL)
307 ;; We know that the denumerator is positive.
311 mov a, #0xC1 ; Set the DIVST bit in MDUC
312 mov !MDUC, a ; This starts the division op
314 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
322 ;----------------------------------------------------------------------
324 START_FUNC ___udivhi3
325 ;; r8 = 4[sp] / 6[sp] (unsigned division)
327 mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
328 mov !MDUC, a ; This preps the peripheral for division without interrupt generation
330 movw ax, [sp+4] ; Load the divisor
332 movw ax, [sp+6] ; Load the dividend
338 mov a, #0xC1 ; Set the DIVST bit in MDUC
339 mov !MDUC, a ; This starts the division op
341 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
344 movw ax, !MDAL ; Read the remainder
350 ;----------------------------------------------------------------------
352 START_FUNC ___umodhi3
353 ;; r8 = 4[sp] % 6[sp] (unsigned modulus)
355 mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1
356 mov !MDUC, a ; This preps the peripheral for division without interrupt generation
358 movw ax, [sp+4] ; Load the divisor
360 movw ax, [sp+6] ; Load the dividend
366 mov a, #0xC1 ; Set the DIVST bit in MDUC
367 mov !MDUC, a ; This starts the division op
369 1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear
372 movw ax, !MDCL ; Read the remainder
378 ;----------------------------------------------------------------------
380 #elif defined __RL78_MUL_NONE__
382 .macro MAKE_GENERIC which,need_result
412 START_FUNC __generic_hidivmod\which
423 ;; These routines leave DE alone - the signed functions use DE
424 ;; to store sign information that must remain intact
427 .global __generic_hidiv
432 .global __generic_himod
437 ;; (quot,rem) = 8[sp] /% 10[sp]
440 movw ax, [hl+10] ; denH
441 cmpw ax, [hl+8] ; numH
444 ;; (quot,rem) = 16[sp] /% 20[sp]
456 bnz $den_not_zero\which
470 ;; initialize bit to 1
473 ; while (den < num && !(den & (1L << BITS_MINUS_1)))
478 bc $enter_main_loop\which
480 bh $enter_main_loop\which
483 ; movw ax, den ; already has it from the cmpw above
497 ;; if we don't need to compute the quotent, we don't need an
498 ;; actual bit *mask*, we just need to keep track of which bit
502 br $shift_den_bit\which
506 ;; if (num >= den) (cmp den > num)
542 enter_main_loop\which:
551 main_loop_done\which:
553 END_FUNC __generic_hidivmod\which
555 ;----------------------------------------------------------------------
560 ;----------------------------------------------------------------------
562 START_FUNC ___udivhi3
563 ;; r8 = 4[sp] / 6[sp]
564 call $!__generic_hidiv
569 START_FUNC ___umodhi3
570 ;; r8 = 4[sp] % 6[sp]
571 call $!__generic_himod
575 ;----------------------------------------------------------------------
584 ;----------------------------------------------------------------------
587 ;; r8 = 4[sp] / 6[sp]
595 call $!__generic_hidiv
606 bnc $div_unsigned_den
614 call $!__generic_hidiv
618 bz $div_skip_restore_num
619 ;; We have to restore the numerator [sp+4]
624 div_skip_restore_num:
632 bz $div_skip_restore_den
636 div_skip_restore_den:
642 ;; r8 = 4[sp] % 6[sp]
650 call $!__generic_himod
661 bnc $mod_unsigned_den
668 call $!__generic_himod
675 ;; Also restore numerator
682 bz $mod_skip_restore_den
686 mod_skip_restore_den:
690 ;----------------------------------------------------------------------
694 #error "Unknown RL78 hardware multiply/divide support"