diff options
author | Nick Clifton <nickc@redhat.com> | 2015-04-16 07:57:56 +0000 |
---|---|---|
committer | Nick Clifton <nickc@gcc.gnu.org> | 2015-04-16 07:57:56 +0000 |
commit | 72ed1126861875a4fae0d75f994e35f1b79509bd (patch) | |
tree | 6058a55ad9abb695d0a8f4a9b314ab329d819ebc /libgcc | |
parent | 8a474dc5d7d152653e90e960eff1852d1c7ff914 (diff) | |
download | gcc-72ed1126861875a4fae0d75f994e35f1b79509bd.zip gcc-72ed1126861875a4fae0d75f994e35f1b79509bd.tar.gz gcc-72ed1126861875a4fae0d75f994e35f1b79509bd.tar.bz2 |
rl78-opts.h (enum rl78_mul_types): Add MUL_G14 and MUL_UNINIT.
* config/rl78/rl78-opts.h (enum rl78_mul_types): Add MUL_G14 and
MUL_UNINIT.
(enum rl78_cpu_type): New.
* config/rl78/rl78-virt.md (attr valloc): Add divhi and divsi.
(umulhi3_shift_virt): Remove m constraint from operand 1.
(umulqihi3_virt): Likewise.
* config/rl78/rl78.c (rl78_option_override): Add code to process
-mcpu and -mmul options.
(rl78_alloc_physical_registers): Add code to handle divhi and
divsi valloc attributes.
(set_origin): Likewise.
* config/rl78/rl78.h (RL78_MUL_G14): Define.
(TARGET_G10, TARGET_G13, TARGET_G14): Define.
(TARGET_CPU_CPP_BUILTINS): Define __RL78_MUL_xxx__ and
__RL78_Gxx__.
(ASM_SPEC): Pass -mcpu on to assembler.
* config/rl78/rl78.md (mulqi3): Add a clobber of AX.
(mulqi3_rl78): Likewise.
(mulhi3_g13): Likewise.
(mulhi3): Generate the G13 or G14 versions of the insn directly.
(mulsi3): Likewise.
(mulhi3_g14): Add clobbers of AX and BC.
(mulsi3_g14): Likewise.
(mulsi3_g13): Likewise.
(udivmodhi4, udivmodhi4_g14, udivmodsi4): New patterns.
(udivmodsi4_g14, udivmodsi4_g13): New patterns.
* config/rl78/rl78.opt (mmul): Initialise value to
RL78_MUL_UNINIT.
(mcpu): New option.
(m13, m14, mrl78): New option aliases.
* config/rl78/t-rl78 (MULTILIB_OPTIONS): Add mg13 and mg14.
(MULTILIB_DIRNAMES): Add g13 and g14.
* doc/invoke.texi: Document -mcpu and -mmul options.
* config/rl78/divmodhi.S: Add G14 and G13 versions of the __divhi3
and __modhi3 functions.
* config/rl78/divmodso.S: Add G14 and G13 versions of the
__divsi3, __udivsi3, __modsi3 and __umodsi3 functions.
From-SVN: r222142
Diffstat (limited to 'libgcc')
-rw-r--r-- | libgcc/ChangeLog | 7 | ||||
-rw-r--r-- | libgcc/config/rl78/divmodhi.S | 362 | ||||
-rw-r--r-- | libgcc/config/rl78/divmodsi.S | 541 |
3 files changed, 910 insertions, 0 deletions
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 611223a..a21afe86 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,10 @@ +2015-04-16 Nick Clifton <nickc@redhat.com> + + * config/rl78/divmodhi.S: Add G14 and G13 versions of the __divhi3 + and __modhi3 functions. + * config/rl78/divmodso.S: Add G14 and G13 versions of the + __divsi3, __udivsi3, __modsi3 and __umodsi3 functions. + 2015-04-15 Chen Gang <gang.chen.5i5j@gmail.com> * gthr-single.h (__GTHREAD_MUTEX_INIT_FUNCTION): Use empty diff --git a/libgcc/config/rl78/divmodhi.S b/libgcc/config/rl78/divmodhi.S index 4e5f3a2..adf91e2 100644 --- a/libgcc/config/rl78/divmodhi.S +++ b/libgcc/config/rl78/divmodhi.S @@ -25,6 +25,360 @@ #include "vregs.h" +#if defined __RL78_MUL_G14__ + +START_FUNC ___divhi3 + ;; r8 = 4[sp] / 6[sp] + + ;; Test for a negative denumerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw de, ax + bc $__div_neg_den + + ;; Test for a negative numerator. + movw ax, [sp+4] + mov1 cy, a.7 + bc $__div_neg_num + + ;; Neither are negative - we can use the unsigned divide instruction. +__div_no_convert: + push psw + di + divhu + pop psw + + movw r8, ax + ret + +__div_neg_den: + ;; Negate the denumerator (which is in DE) + clrw ax + subw ax, de + movw de, ax + + ;; Test for a negative numerator. + movw ax, [sp+4] + mov1 cy, a.7 + ;; If it is not negative then we perform the division and then negate the result. + bnc $__div_then_convert + + ;; Otherwise we negate the numerator and then go with an unsigned division. + movw bc, ax + clrw ax + subw ax, bc + br $__div_no_convert + +__div_neg_num: + ;; Negate the numerator (which is in AX) + ;; We know that the denumerator is positive. + movw bc, ax + clrw ax + subw ax, bc + +__div_then_convert: + push psw + di + divhu + pop psw + + ;; Negate result and transfer into r8 + movw bc, ax + clrw ax + subw ax, bc + movw r8, ax + ret + +END_FUNC ___divhi3 + +;---------------------------------------------------------------------- + +START_FUNC ___modhi3 + ;; r8 = 4[sp] % 6[sp] + + ;; Test for a negative denumerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw de, ax + bc $__mod_neg_den + + ;; Test for a negative numerator. + movw ax, [sp+4] + mov1 cy, a.7 + bc $__mod_neg_num + + ;; Neither are negative - we can use the unsigned divide instruction. +__mod_no_convert: + push psw + di + divhu + pop psw + + movw ax, de + movw r8, ax + ret + +__mod_neg_den: + ;; Negate the denumerator (which is in DE) + clrw ax + subw ax, de + movw de, ax + + ;; Test for a negative numerator. + movw ax, [sp+4] + mov1 cy, a.7 + ;; If it is not negative then we perform the modulo operation without conversion. + bnc $__mod_no_convert + + ;; Otherwise we negate the numerator and then go with an unsigned modulo operation. + movw bc, ax + clrw ax + subw ax, bc + br $__mod_then_convert + +__mod_neg_num: + ;; Negate the numerator (which is in AX) + ;; We know that the denumerator is positive. + movw bc, ax + clrw ax + subw ax, bc + +__mod_then_convert: + push psw + di + divhu + pop psw + + ;; Negate result and transfer into r8 + clrw ax + subw ax, de + movw r8, ax + ret + +END_FUNC ___modhi3 + +;---------------------------------------------------------------------- + +#elif defined __RL78_MUL_G13__ + + ;; The G13 S2 core does not have a 16 bit divide peripheral. + ;; So instead we perform a 32-bit divide and twiddle the inputs + ;; as necessary. + + ;; Hardware registers. Note - these values match the silicon, not the documentation. + MDAL = 0xffff0 + MDAH = 0xffff2 + MDBL = 0xffff6 + MDBH = 0xffff4 + MDCL = 0xf00e0 + MDCH = 0xf00e2 + MDUC = 0xf00e8 + +.macro _Negate src, dest + movw ax, !\src + movw bc, ax + clrw ax + subw ax, bc + movw \dest, ax +.endm + +;---------------------------------------------------------------------- + +START_FUNC ___divhi3 + ;; r8 = 4[sp] / 6[sp] (signed division) + + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 + mov !MDUC, a ; This preps the peripheral for division without interrupt generation + + clrw ax ; Clear the top 16-bits of the divisor and dividend + movw MDBH, ax + movw MDAH, ax + + ;; Load and test for a negative denumerator. + movw ax, [sp+6] + movw MDBL, ax + mov1 cy, a.7 + bc $__div_neg_den + + ;; Load and test for a negative numerator. + movw ax, [sp+4] + mov1 cy, a.7 + movw MDAL, ax + bc $__div_neg_num + + ;; Neither are negative - we can use the unsigned divide hardware. +__div_no_convert: + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, MDAL ; Read the result + movw r8, ax + ret + +__div_neg_den: + ;; Negate the denumerator (which is in MDBL) + _Negate MDBL MDBL + + ;; Load and test for a negative numerator. + movw ax, [sp+4] + mov1 cy, a.7 + movw MDAL, ax + ;; If it is not negative then we perform the division and then negate the result. + bnc $__div_then_convert + + ;; Otherwise we negate the numerator and then go with a straightforward unsigned division. + _Negate MDAL MDAL + br $!__div_no_convert + +__div_neg_num: + ;; Negate the numerator (which is in MDAL) + ;; We know that the denumerator is positive. + _Negate MDAL MDAL + +__div_then_convert: + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + ;; Negate result and transfer into r8 + _Negate MDAL r8 + ret + +END_FUNC ___divhi3 + +;---------------------------------------------------------------------- + +START_FUNC ___modhi3 + ;; r8 = 4[sp] % 6[sp] (signed modulus) + + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 + mov !MDUC, a ; This preps the peripheral for division without interrupt generation + + clrw ax ; Clear the top 16-bits of the divisor and dividend + movw MDBH, ax + movw MDAH, ax + + ;; Load and test for a negative denumerator. + movw ax, [sp+6] + movw MDBL, ax + mov1 cy, a.7 + bc $__mod_neg_den + + ;; Load and test for a negative numerator. + movw ax, [sp+4] + mov1 cy, a.7 + movw MDAL, ax + bc $__mod_neg_num + + ;; Neither are negative - we can use the unsigned divide hardware +__mod_no_convert: + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, !MDCL ; Read the remainder + movw r8, ax + ret + +__mod_neg_den: + ;; Negate the denumerator (which is in MDBL) + _Negate MDBL MDBL + + ;; Load and test for a negative numerator. + movw ax, [sp+4] + mov1 cy, a.7 + movw MDAL, ax + ;; If it is not negative then we perform the modulo operation without conversion. + bnc $__mod_no_convert + + ;; Otherwise we negate the numerator and then go with a modulo followed by negation. + _Negate MDAL MDAL + br $!__mod_then_convert + +__mod_neg_num: + ;; Negate the numerator (which is in MDAL) + ;; We know that the denumerator is positive. + _Negate MDAL MDAL + +__mod_then_convert: + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + _Negate MDCL r8 + ret + +END_FUNC ___modhi3 + +;---------------------------------------------------------------------- + +START_FUNC ___udivhi3 + ;; r8 = 4[sp] / 6[sp] (unsigned division) + + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 + mov !MDUC, a ; This preps the peripheral for division without interrupt generation + + movw ax, [sp+4] ; Load the divisor + movw MDAL, ax + movw ax, [sp+6] ; Load the dividend + movw MDBL, ax + clrw ax + movw MDAH, ax + movw MDBH, ax + + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, !MDAL ; Read the remainder + movw r8, ax + ret + +END_FUNC ___udivhi3 + +;---------------------------------------------------------------------- + +START_FUNC ___umodhi3 + ;; r8 = 4[sp] % 6[sp] (unsigned modulus) + + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 + mov !MDUC, a ; This preps the peripheral for division without interrupt generation + + movw ax, [sp+4] ; Load the divisor + movw MDAL, ax + movw ax, [sp+6] ; Load the dividend + movw MDBL, ax + clrw ax + movw MDAH, ax + movw MDBH, ax + + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, !MDCL ; Read the remainder + movw r8, ax + ret + +END_FUNC ___umodhi3 + +;---------------------------------------------------------------------- + +#elif defined __RL78_MUL_NONE__ + .macro MAKE_GENERIC which,need_result .if \need_result @@ -328,3 +682,11 @@ mod_no_neg: mod_skip_restore_den: ret END_FUNC ___modhi3 + +;---------------------------------------------------------------------- + +#else + +#error "Unknown RL78 hardware multiply/divide support" + +#endif diff --git a/libgcc/config/rl78/divmodsi.S b/libgcc/config/rl78/divmodsi.S index 7acaa86..987a9e3 100644 --- a/libgcc/config/rl78/divmodsi.S +++ b/libgcc/config/rl78/divmodsi.S @@ -25,6 +25,537 @@ #include "vregs.h" +#if defined __RL78_MUL_G14__ + +START_FUNC ___divsi3 + ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp] + + ;; Load and test for a negative denumerator. + movw ax, [sp+8] + movw de, ax + movw ax, [sp+10] + mov1 cy, a.7 + movw hl, ax + bc $__div_neg_den + + ;; Load and test for a negative numerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw bc, ax + movw ax, [sp+4] + bc $__div_neg_num + + ;; Neither are negative - we can use the unsigned divide instruction. +__div_no_convert: + push psw + di + divwu + pop psw + + movw r8, ax + movw ax, bc + movw r10, ax + ret + +__div_neg_den: + ;; Negate the denumerator (which is in HLDE) + clrw ax + subw ax, de + movw de, ax + clrw ax + sknc + decw ax + subw ax, hl + movw hl, ax + + ;; Load and test for a negative numerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw bc, ax + movw ax, [sp+4] + ;; If it is not negative then we perform the division and then negate the result. + bnc $__div_then_convert + + ;; Otherwise we negate the numerator and then go with a straightforward unsigned division. + ;; The negation is complicated because AX, BC, DE and HL are already in use. + ;; ax: numL bc: numH r8: r10: + xchw ax, bc + ;; ax: numH bc: numL r8: r10: + movw r8, ax + ;; ax: bc: numL r8: numH r10: + clrw ax + ;; ax: 0 bc: numL r8: numH r10: + subw ax, bc + ;; ax: -numL bc: r8: numH r10: + movw r10, ax + ;; ax: bc: r8: numH r10: -numL + movw ax, r8 + ;; ax: numH bc: r8: r10: -numL + movw bc, ax + ;; ax: bc: numH r8: r10: -numL + clrw ax + ;; ax: 0 bc: numH r8: r10: -numL + sknc + decw ax + ;; ax: -1 bc: numH r8: r10: -numL + subw ax, bc + ;; ax: -numH bc: r8: r10: -numL + movw bc, ax + ;; ax: bc: -numH r8: r10: -numL + movw ax, r10 + ;; ax: -numL bc: -numH r8: r10: + br $!__div_no_convert + +__div_neg_num: + ;; Negate the numerator (which is in BCAX) + ;; We know that the denumerator is positive. + ;; Note - we temporarily overwrite DE. We know that we can safely load it again off the stack again. + movw de, ax + clrw ax + subw ax, de + movw de, ax + clrw ax + sknc + decw ax + subw ax, bc + movw bc, ax + + movw ax, [sp+8] + xchw ax, de + +__div_then_convert: + push psw + di + divwu + pop psw + + ;; Negate result (in BCAX) and transfer into r8,r10 + movw de, ax + clrw ax + subw ax, de + movw r8, ax + clrw ax + sknc + decw ax + subw ax, bc + movw r10, ax + ret + +END_FUNC ___divsi3 + +;---------------------------------------------------------------------- + +START_FUNC ___udivsi3 + ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp] + ;; Used when compiling with -Os specified. + + movw ax, [sp+10] + movw hl, ax + movw ax, [sp+8] + movw de, ax + movw ax, [sp+6] + movw bc, ax + movw ax, [sp+4] + push psw ; Save the current interrupt status + di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E + divwu ; bcax = bcax / hlde + pop psw ; Restore saved interrupt status + movw r8, ax + movw ax, bc + movw r10, ax + ret + +END_FUNC ___udivsi3 + +;---------------------------------------------------------------------- + +START_FUNC ___modsi3 + ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp] + + ;; Load and test for a negative denumerator. + movw ax, [sp+8] + movw de, ax + movw ax, [sp+10] + mov1 cy, a.7 + movw hl, ax + bc $__mod_neg_den + + ;; Load and test for a negative numerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw bc, ax + movw ax, [sp+4] + bc $__mod_neg_num + + ;; Neither are negative - we can use the unsigned divide instruction. +__mod_no_convert: + push psw + di + divwu + pop psw + + movw ax, de + movw r8, ax + movw ax, hl + movw r10, ax + ret + +__mod_neg_den: + ;; Negate the denumerator (which is in HLDE) + clrw ax + subw ax, de + movw de, ax + clrw ax + sknc + decw ax + subw ax, hl + movw hl, ax + + ;; Load and test for a negative numerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw bc, ax + movw ax, [sp+4] + ;; If it is not negative then we perform the modulo operation without conversion + bnc $__mod_no_convert + + ;; Otherwise we negate the numerator and then go with a modulo followed by negation. + ;; The negation is complicated because AX, BC, DE and HL are already in use. + xchw ax, bc + movw r8, ax + clrw ax + subw ax, bc + movw r10, ax + movw ax, r8 + movw bc, ax + clrw ax + sknc + decw ax + subw ax, bc + movw bc, ax + movw ax, r10 + br $!__mod_then_convert + +__mod_neg_num: + ;; Negate the numerator (which is in BCAX) + ;; We know that the denumerator is positive. + ;; Note - we temporarily overwrite DE. We know that we can safely load it again off the stack again. + movw de, ax + clrw ax + subw ax, de + movw de, ax + clrw ax + sknc + decw ax + subw ax, bc + movw bc, ax + + movw ax, [sp+8] + xchw ax, de + +__mod_then_convert: + push psw + di + divwu + pop psw + + ;; Negate result (in HLDE) and transfer into r8,r10 + clrw ax + subw ax, de + movw r8, ax + clrw ax + sknc + decw ax + subw ax, hl + movw r10, ax + ret + +END_FUNC ___modsi3 + +;---------------------------------------------------------------------- + +START_FUNC ___umodsi3 + ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp] + ;; Used when compiling with -Os specified. + + movw ax, [sp+10] + movw hl, ax + movw ax, [sp+8] + movw de, ax + movw ax, [sp+6] + movw bc, ax + movw ax, [sp+4] + push psw ; Save the current interrupt status + di ; Disable interrupts. See Renesas Technical update TN-RL*-A025B/E + divwu ; hlde = bcax %% hlde + pop psw ; Restore saved interrupt status + movw ax, de + movw r8, ax + movw ax, hl + movw r10, ax + ret + +END_FUNC ___umodsi3 + +;---------------------------------------------------------------------- + +#elif defined __RL78_MUL_G13__ + +;---------------------------------------------------------------------- + + ;; Hardware registers. Note - these values match the silicon, not the documentation. + MDAL = 0xffff0 + MDAH = 0xffff2 + MDBL = 0xffff6 + MDBH = 0xffff4 + MDCL = 0xf00e0 + MDCH = 0xf00e2 + MDUC = 0xf00e8 + +.macro _Negate low, high + movw ax, \low + movw bc, ax + clrw ax + subw ax, bc + movw \low, ax + movw ax, \high + movw bc, ax + clrw ax + sknc + decw ax + subw ax, bc + movw \high, ax +.endm + +;---------------------------------------------------------------------- + +START_FUNC ___divsi3 + ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp] + + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 + mov !MDUC, a ; This preps the peripheral for division without interrupt generation + + ;; Load and test for a negative denumerator. + movw ax, [sp+8] + movw MDBL, ax + movw ax, [sp+10] + mov1 cy, a.7 + movw MDBH, ax + bc $__div_neg_den + + ;; Load and test for a negative numerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw MDAH, ax + movw ax, [sp+4] + movw MDAL, ax + bc $__div_neg_num + + ;; Neither are negative - we can use the unsigned divide hardware. +__div_no_convert: + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, MDAL ; Read the result + movw r8, ax + movw ax, MDAH + movw r10, ax + ret + +__div_neg_den: + ;; Negate the denumerator (which is in MDBL/MDBH) + _Negate MDBL MDBH + + ;; Load and test for a negative numerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw MDAH, ax + movw ax, [sp+4] + movw MDAL, ax + ;; If it is not negative then we perform the division and then negate the result. + bnc $__div_then_convert + + ;; Otherwise we negate the numerator and then go with a straightforward unsigned division. + _Negate MDAL MDAH + br $!__div_no_convert + +__div_neg_num: + ;; Negate the numerator (which is in MDAL/MDAH) + ;; We know that the denumerator is positive. + _Negate MDAL MDAH + +__div_then_convert: + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + ;; Negate result and transfer into r8,r10 + _Negate MDAL MDAH ; FIXME: This could be coded more efficiently. + movw r10, ax + movw ax, MDAL + movw r8, ax + + ret + +END_FUNC ___divsi3 + +;---------------------------------------------------------------------- + +START_FUNC ___modsi3 + ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp] + + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 + mov !MDUC, a ; This preps the peripheral for division without interrupt generation + + ;; Load and test for a negative denumerator. + movw ax, [sp+8] + movw MDBL, ax + movw ax, [sp+10] + mov1 cy, a.7 + movw MDBH, ax + bc $__mod_neg_den + + ;; Load and test for a negative numerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw MDAH, ax + movw ax, [sp+4] + movw MDAL, ax + bc $__mod_neg_num + + ;; Neither are negative - we can use the unsigned divide hardware +__mod_no_convert: + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, !MDCL ; Read the remainder + movw r8, ax + movw ax, !MDCH + movw r10, ax + ret + +__mod_neg_den: + ;; Negate the denumerator (which is in MDBL/MDBH) + _Negate MDBL MDBH + + ;; Load and test for a negative numerator. + movw ax, [sp+6] + mov1 cy, a.7 + movw MDAH, ax + movw ax, [sp+4] + movw MDAL, ax + ;; If it is not negative then we perform the modulo operation without conversion + bnc $__mod_no_convert + + ;; Otherwise we negate the numerator and then go with a modulo followed by negation. + _Negate MDAL MDAH + br $!__mod_then_convert + +__mod_neg_num: + ;; Negate the numerator (which is in MDAL/MDAH) + ;; We know that the denumerator is positive. + _Negate MDAL MDAH + +__mod_then_convert: + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, !MDCL + movw bc, ax + clrw ax + subw ax, bc + movw r8, ax + movw ax, !MDCH + movw bc, ax + clrw ax + sknc + decw ax + subw ax, bc + movw r10, ax + ret + +END_FUNC ___modsi3 + +;---------------------------------------------------------------------- + +START_FUNC ___udivsi3 + ;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp] + ;; Used when compilng with -Os specified. + + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 + mov !MDUC, a ; This preps the peripheral for division without interrupt generation + + movw ax, [sp+4] ; Load the divisor + movw MDAL, ax + movw ax, [sp+6] + movw MDAH, ax + movw ax, [sp+8] ; Load the dividend + movw MDBL, ax + movw ax, [sp+10] + movw MDBH, ax + + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, !MDAL ; Read the result + movw r8, ax + movw ax, !MDAH + movw r10, ax + ret + +END_FUNC ___udivsi3 + +;---------------------------------------------------------------------- + +START_FUNC ___umodsi3 + ;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp] + ;; Used when compilng with -Os specified. + ;; Note - hardware address match the silicon, not the documentation + + mov a, #0xC0 ; Set DIVMODE=1 and MACMODE=1 + mov !MDUC, a ; This preps the peripheral for division without interrupt generation + + movw ax, [sp+4] ; Load the divisor + movw MDAL, ax + movw ax, [sp+6] + movw MDAH, ax + movw ax, [sp+8] ; Load the dividend + movw MDBL, ax + movw ax, [sp+10] + movw MDBH, ax + + mov a, #0xC1 ; Set the DIVST bit in MDUC + mov !MDUC, a ; This starts the division op + +1: mov a, !MDUC ; Wait 16 clocks or until DIVST is clear + bt a.0, $1b + + movw ax, !MDCL ; Read the remainder + movw r8, ax + movw ax, !MDCH + movw r10, ax + ret + +END_FUNC ___umodsi3 + +;---------------------------------------------------------------------- + +#elif defined __RL78_MUL_NONE__ + .macro MAKE_GENERIC which,need_result .if \need_result @@ -67,6 +598,8 @@ bitB2 = bit+2 bitB3 = bit+3 +;---------------------------------------------------------------------- + START_FUNC __generic_sidivmod\which num_lt_den\which: @@ -533,3 +1066,11 @@ mod_skip_restore_den: .endif ret END_FUNC ___modsi3 + +;---------------------------------------------------------------------- + +#else + +#error "Unknown RL78 hardware multiply/divide support" + +#endif |