aboutsummaryrefslogtreecommitdiff
path: root/libgcc
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2015-04-16 07:57:56 +0000
committerNick Clifton <nickc@gcc.gnu.org>2015-04-16 07:57:56 +0000
commit72ed1126861875a4fae0d75f994e35f1b79509bd (patch)
tree6058a55ad9abb695d0a8f4a9b314ab329d819ebc /libgcc
parent8a474dc5d7d152653e90e960eff1852d1c7ff914 (diff)
downloadgcc-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/ChangeLog7
-rw-r--r--libgcc/config/rl78/divmodhi.S362
-rw-r--r--libgcc/config/rl78/divmodsi.S541
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