Home | History | Annotate | Line # | Download | only in rl78
      1       1.1  mrg /* HImode div/mod functions for the GCC support library for the Renesas RL78 processors.
      2  1.1.1.10  mrg    Copyright (C) 2012-2024 Free Software Foundation, Inc.
      3       1.1  mrg    Contributed by Red Hat.
      4       1.1  mrg 
      5       1.1  mrg    This file is part of GCC.
      6       1.1  mrg 
      7       1.1  mrg    GCC is free software; you can redistribute it and/or modify
      8       1.1  mrg    it under the terms of the GNU General Public License as published by
      9       1.1  mrg    the Free Software Foundation; either version 3, or (at your option)
     10       1.1  mrg    any later version.
     11       1.1  mrg 
     12       1.1  mrg    GCC is distributed in the hope that it will be useful,
     13       1.1  mrg    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14       1.1  mrg    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15       1.1  mrg    GNU General Public License for more details.
     16       1.1  mrg 
     17       1.1  mrg    Under Section 7 of GPL version 3, you are granted additional
     18       1.1  mrg    permissions described in the GCC Runtime Library Exception, version
     19       1.1  mrg    3.1, as published by the Free Software Foundation.
     20       1.1  mrg 
     21       1.1  mrg    You should have received a copy of the GNU General Public License and
     22       1.1  mrg    a copy of the GCC Runtime Library Exception along with this program;
     23       1.1  mrg    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     24       1.1  mrg    <http://www.gnu.org/licenses/>.  */
     25       1.1  mrg 
     26       1.1  mrg #include "vregs.h"
     27       1.1  mrg 
     28   1.1.1.2  mrg #if defined __RL78_MUL_G14__
     29   1.1.1.2  mrg 
     30   1.1.1.2  mrg START_FUNC ___divhi3
     31   1.1.1.2  mrg 	;; r8 = 4[sp] / 6[sp]
     32   1.1.1.2  mrg 
     33   1.1.1.2  mrg 	;; Test for a negative denumerator.
     34   1.1.1.2  mrg 	movw	ax, [sp+6]
     35   1.1.1.2  mrg 	mov1	cy, a.7
     36   1.1.1.2  mrg 	movw	de, ax
     37   1.1.1.2  mrg 	bc	$__div_neg_den
     38   1.1.1.2  mrg 
     39   1.1.1.2  mrg 	;; Test for a negative numerator.
     40   1.1.1.2  mrg 	movw	ax, [sp+4]
     41   1.1.1.2  mrg 	mov1	cy, a.7
     42   1.1.1.2  mrg 	bc	$__div_neg_num
     43   1.1.1.2  mrg 
     44   1.1.1.2  mrg 	;; Neither are negative - we can use the unsigned divide instruction.
     45   1.1.1.2  mrg __div_no_convert:
     46   1.1.1.2  mrg 	push	psw
     47   1.1.1.2  mrg 	di
     48   1.1.1.2  mrg 	divhu
     49   1.1.1.2  mrg 	pop	psw
     50   1.1.1.2  mrg 
     51   1.1.1.2  mrg 	movw	r8, ax
     52   1.1.1.2  mrg 	ret
     53   1.1.1.2  mrg 
     54   1.1.1.2  mrg __div_neg_den:
     55   1.1.1.2  mrg 	;; Negate the denumerator (which is in DE)
     56   1.1.1.2  mrg 	clrw	ax
     57   1.1.1.2  mrg 	subw	ax, de
     58   1.1.1.2  mrg 	movw	de, ax
     59   1.1.1.2  mrg 
     60   1.1.1.2  mrg 	;; Test for a negative numerator.
     61   1.1.1.2  mrg 	movw	ax, [sp+4]
     62   1.1.1.2  mrg 	mov1	cy, a.7
     63   1.1.1.2  mrg 	;; If it is not negative then we perform the division and then negate the result.
     64   1.1.1.2  mrg 	bnc	$__div_then_convert
     65   1.1.1.2  mrg 
     66   1.1.1.2  mrg 	;; Otherwise we negate the numerator and then go with an unsigned division.
     67   1.1.1.2  mrg 	movw	bc, ax
     68   1.1.1.2  mrg 	clrw	ax
     69   1.1.1.2  mrg 	subw	ax, bc
     70   1.1.1.2  mrg 	br	$__div_no_convert
     71   1.1.1.2  mrg 
     72   1.1.1.2  mrg __div_neg_num:
     73   1.1.1.2  mrg 	;; Negate the numerator (which is in AX)
     74   1.1.1.2  mrg 	;; We know that the denumerator is positive.
     75   1.1.1.2  mrg 	movw	bc, ax
     76   1.1.1.2  mrg 	clrw	ax
     77   1.1.1.2  mrg 	subw	ax, bc
     78   1.1.1.2  mrg 
     79   1.1.1.2  mrg __div_then_convert:
     80   1.1.1.2  mrg 	push	psw
     81   1.1.1.2  mrg 	di
     82   1.1.1.2  mrg 	divhu
     83   1.1.1.2  mrg 	pop	psw
     84   1.1.1.2  mrg 
     85   1.1.1.2  mrg 	;; Negate result and transfer into r8
     86   1.1.1.2  mrg 	movw	bc, ax
     87   1.1.1.2  mrg 	clrw	ax
     88   1.1.1.2  mrg 	subw	ax, bc
     89   1.1.1.2  mrg 	movw	r8, ax
     90   1.1.1.2  mrg 	ret
     91   1.1.1.2  mrg 
     92   1.1.1.2  mrg END_FUNC ___divhi3
     93   1.1.1.2  mrg 
     94   1.1.1.2  mrg ;----------------------------------------------------------------------
     95   1.1.1.2  mrg 
     96   1.1.1.2  mrg START_FUNC ___modhi3
     97   1.1.1.2  mrg 	;; r8 = 4[sp] % 6[sp]
     98   1.1.1.2  mrg 
     99   1.1.1.2  mrg 	;; Test for a negative denumerator.
    100   1.1.1.2  mrg 	movw	ax, [sp+6]
    101   1.1.1.2  mrg 	mov1	cy, a.7
    102   1.1.1.2  mrg 	movw	de, ax
    103   1.1.1.2  mrg 	bc	$__mod_neg_den
    104   1.1.1.2  mrg 
    105   1.1.1.2  mrg 	;; Test for a negative numerator.
    106   1.1.1.2  mrg 	movw	ax, [sp+4]
    107   1.1.1.2  mrg 	mov1	cy, a.7
    108   1.1.1.2  mrg 	bc	$__mod_neg_num
    109   1.1.1.2  mrg 
    110   1.1.1.2  mrg 	;; Neither are negative - we can use the unsigned divide instruction.
    111   1.1.1.2  mrg __mod_no_convert:
    112   1.1.1.2  mrg 	push	psw
    113   1.1.1.2  mrg 	di
    114   1.1.1.2  mrg 	divhu
    115   1.1.1.2  mrg 	pop	psw
    116   1.1.1.2  mrg 
    117   1.1.1.2  mrg 	movw	ax, de
    118   1.1.1.2  mrg 	movw	r8, ax
    119   1.1.1.2  mrg 	ret
    120   1.1.1.2  mrg 
    121   1.1.1.2  mrg __mod_neg_den:
    122   1.1.1.2  mrg 	;; Negate the denumerator (which is in DE)
    123   1.1.1.2  mrg 	clrw	ax
    124   1.1.1.2  mrg 	subw	ax, de
    125   1.1.1.2  mrg 	movw	de, ax
    126   1.1.1.2  mrg 
    127   1.1.1.2  mrg 	;; Test for a negative numerator.
    128   1.1.1.2  mrg 	movw	ax, [sp+4]
    129   1.1.1.2  mrg 	mov1	cy, a.7
    130   1.1.1.2  mrg 	;; If it is not negative then we perform the modulo operation without conversion.
    131   1.1.1.2  mrg 	bnc	$__mod_no_convert
    132   1.1.1.2  mrg 
    133   1.1.1.2  mrg 	;; Otherwise we negate the numerator and then go with an unsigned modulo operation.
    134   1.1.1.2  mrg 	movw	bc, ax
    135   1.1.1.2  mrg 	clrw	ax
    136   1.1.1.2  mrg 	subw	ax, bc
    137   1.1.1.2  mrg 	br	$__mod_then_convert
    138   1.1.1.2  mrg 
    139   1.1.1.2  mrg __mod_neg_num:
    140   1.1.1.2  mrg 	;; Negate the numerator (which is in AX)
    141   1.1.1.2  mrg 	;; We know that the denumerator is positive.
    142   1.1.1.2  mrg 	movw	bc, ax
    143   1.1.1.2  mrg 	clrw	ax
    144   1.1.1.2  mrg 	subw	ax, bc
    145   1.1.1.2  mrg 
    146   1.1.1.2  mrg __mod_then_convert:
    147   1.1.1.2  mrg 	push	psw
    148   1.1.1.2  mrg 	di
    149   1.1.1.2  mrg 	divhu
    150   1.1.1.2  mrg 	pop	psw
    151   1.1.1.2  mrg 
    152   1.1.1.2  mrg 	;; Negate result and transfer into r8
    153   1.1.1.2  mrg 	clrw	  ax
    154   1.1.1.2  mrg 	subw	  ax, de
    155   1.1.1.2  mrg 	movw	  r8, ax
    156   1.1.1.2  mrg 	ret
    157   1.1.1.2  mrg 
    158   1.1.1.2  mrg END_FUNC ___modhi3
    159   1.1.1.2  mrg 
    160   1.1.1.2  mrg ;----------------------------------------------------------------------
    161   1.1.1.2  mrg 
    162   1.1.1.2  mrg #elif defined __RL78_MUL_G13__
    163   1.1.1.2  mrg 
    164   1.1.1.2  mrg 	;; The G13 S2 core does not have a 16 bit divide peripheral.
    165   1.1.1.2  mrg 	;; So instead we perform a 32-bit divide and twiddle the inputs
    166   1.1.1.2  mrg 	;; as necessary.
    167   1.1.1.2  mrg 
    168   1.1.1.2  mrg 	;; Hardware registers.  Note - these values match the silicon, not the documentation.
    169   1.1.1.2  mrg 	MDAL = 0xffff0
    170   1.1.1.2  mrg 	MDAH = 0xffff2
    171   1.1.1.2  mrg 	MDBL = 0xffff6
    172   1.1.1.2  mrg 	MDBH = 0xffff4
    173   1.1.1.2  mrg 	MDCL = 0xf00e0
    174   1.1.1.2  mrg 	MDCH = 0xf00e2
    175   1.1.1.2  mrg 	MDUC = 0xf00e8
    176   1.1.1.2  mrg 
    177   1.1.1.2  mrg .macro _Negate src, dest
    178   1.1.1.2  mrg 	movw	ax, !\src
    179   1.1.1.2  mrg 	movw	bc, ax
    180   1.1.1.2  mrg 	clrw	ax
    181   1.1.1.2  mrg 	subw	ax, bc
    182   1.1.1.2  mrg 	movw	\dest, ax
    183   1.1.1.2  mrg .endm
    184   1.1.1.2  mrg 
    185   1.1.1.2  mrg ;----------------------------------------------------------------------
    186   1.1.1.2  mrg 
    187   1.1.1.2  mrg START_FUNC ___divhi3
    188   1.1.1.2  mrg 	;; r8 = 4[sp] / 6[sp] (signed division)
    189   1.1.1.2  mrg 
    190   1.1.1.2  mrg 	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1
    191   1.1.1.2  mrg 	mov	!MDUC, a	; This preps the peripheral for division without interrupt generation
    192   1.1.1.2  mrg 
    193   1.1.1.2  mrg 	clrw	ax     		; Clear the top 16-bits of the divisor and dividend
    194   1.1.1.2  mrg 	movw	MDBH, ax
    195   1.1.1.2  mrg 	movw	MDAH, ax
    196   1.1.1.2  mrg 
    197   1.1.1.2  mrg 	;; Load and test for a negative denumerator.
    198   1.1.1.2  mrg 	movw	ax, [sp+6]
    199   1.1.1.2  mrg 	movw	MDBL, ax
    200   1.1.1.2  mrg 	mov1	cy, a.7
    201   1.1.1.2  mrg 	bc	$__div_neg_den
    202   1.1.1.2  mrg 
    203   1.1.1.2  mrg 	;; Load and test for a negative numerator.
    204   1.1.1.2  mrg 	movw	ax, [sp+4]
    205   1.1.1.2  mrg 	mov1	cy, a.7
    206   1.1.1.2  mrg 	movw	MDAL, ax
    207   1.1.1.2  mrg 	bc	$__div_neg_num
    208   1.1.1.2  mrg 
    209   1.1.1.2  mrg 	;; Neither are negative - we can use the unsigned divide hardware.
    210   1.1.1.2  mrg __div_no_convert:
    211   1.1.1.2  mrg 	mov	a, #0xC1	; Set the DIVST bit in MDUC
    212   1.1.1.2  mrg 	mov	!MDUC, a	; This starts the division op
    213   1.1.1.2  mrg 
    214   1.1.1.2  mrg 1:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
    215   1.1.1.2  mrg 	bt	a.0, $1b
    216   1.1.1.2  mrg 
    217   1.1.1.2  mrg   	movw	ax, MDAL	; Read the result
    218   1.1.1.2  mrg 	movw	r8, ax
    219   1.1.1.2  mrg 	ret
    220   1.1.1.2  mrg 
    221   1.1.1.2  mrg __div_neg_den:
    222   1.1.1.2  mrg 	;; Negate the denumerator (which is in MDBL)
    223   1.1.1.2  mrg 	_Negate MDBL MDBL
    224   1.1.1.2  mrg 
    225   1.1.1.2  mrg 	;; Load and test for a negative numerator.
    226   1.1.1.2  mrg 	movw	ax, [sp+4]
    227   1.1.1.2  mrg 	mov1	cy, a.7
    228   1.1.1.2  mrg 	movw	MDAL, ax
    229   1.1.1.2  mrg 	;; If it is not negative then we perform the division and then negate the result.
    230   1.1.1.2  mrg 	bnc	$__div_then_convert
    231   1.1.1.2  mrg 
    232   1.1.1.2  mrg 	;; Otherwise we negate the numerator and then go with a straightforward unsigned division.
    233   1.1.1.2  mrg 	_Negate MDAL MDAL
    234   1.1.1.2  mrg 	br	$!__div_no_convert
    235   1.1.1.2  mrg 
    236   1.1.1.2  mrg __div_neg_num:
    237   1.1.1.2  mrg 	;; Negate the numerator (which is in MDAL)
    238   1.1.1.2  mrg 	;; We know that the denumerator is positive.
    239   1.1.1.2  mrg 	_Negate MDAL MDAL
    240   1.1.1.2  mrg 
    241   1.1.1.2  mrg __div_then_convert:
    242   1.1.1.2  mrg 	mov	a, #0xC1	; Set the DIVST bit in MDUC
    243   1.1.1.2  mrg 	mov	!MDUC, a	; This starts the division op
    244   1.1.1.2  mrg 
    245   1.1.1.2  mrg 1:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
    246   1.1.1.2  mrg 	bt	a.0, $1b
    247   1.1.1.2  mrg 
    248   1.1.1.2  mrg 	;; Negate result and transfer into r8
    249   1.1.1.2  mrg 	_Negate MDAL r8
    250   1.1.1.2  mrg 	ret
    251   1.1.1.2  mrg 
    252   1.1.1.2  mrg END_FUNC ___divhi3
    253   1.1.1.2  mrg 
    254   1.1.1.2  mrg ;----------------------------------------------------------------------
    255   1.1.1.2  mrg 
    256   1.1.1.2  mrg START_FUNC ___modhi3
    257   1.1.1.2  mrg 	;; r8 = 4[sp] % 6[sp] (signed modulus)
    258   1.1.1.2  mrg 
    259   1.1.1.2  mrg 	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1
    260   1.1.1.2  mrg 	mov	!MDUC, a	; This preps the peripheral for division without interrupt generation
    261   1.1.1.2  mrg 
    262   1.1.1.2  mrg 	clrw	ax     		; Clear the top 16-bits of the divisor and dividend
    263   1.1.1.2  mrg 	movw	MDBH, ax
    264   1.1.1.2  mrg 	movw	MDAH, ax
    265   1.1.1.2  mrg 
    266   1.1.1.2  mrg 	;; Load and test for a negative denumerator.
    267   1.1.1.2  mrg 	movw	ax, [sp+6]
    268   1.1.1.2  mrg 	movw	MDBL, ax
    269   1.1.1.2  mrg 	mov1	cy, a.7
    270   1.1.1.2  mrg 	bc	$__mod_neg_den
    271   1.1.1.2  mrg 
    272   1.1.1.2  mrg 	;; Load and test for a negative numerator.
    273   1.1.1.2  mrg 	movw	ax, [sp+4]
    274   1.1.1.2  mrg 	mov1	cy, a.7
    275   1.1.1.2  mrg 	movw	MDAL, ax
    276   1.1.1.2  mrg 	bc	$__mod_neg_num
    277   1.1.1.2  mrg 
    278   1.1.1.2  mrg 	;; Neither are negative - we can use the unsigned divide hardware
    279   1.1.1.2  mrg __mod_no_convert:
    280   1.1.1.2  mrg 	mov	a, #0xC1	; Set the DIVST bit in MDUC
    281   1.1.1.2  mrg 	mov	!MDUC, a	; This starts the division op
    282   1.1.1.2  mrg 
    283   1.1.1.2  mrg 1:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
    284   1.1.1.2  mrg 	bt	a.0, $1b
    285   1.1.1.2  mrg 
    286   1.1.1.2  mrg   	movw	ax, !MDCL	; Read the remainder
    287   1.1.1.2  mrg 	movw	r8, ax
    288   1.1.1.2  mrg 	ret
    289   1.1.1.2  mrg 
    290   1.1.1.2  mrg __mod_neg_den:
    291   1.1.1.2  mrg 	;; Negate the denumerator (which is in MDBL)
    292   1.1.1.2  mrg 	_Negate MDBL MDBL
    293   1.1.1.2  mrg 
    294   1.1.1.2  mrg 	;; Load and test for a negative numerator.
    295   1.1.1.2  mrg 	movw	ax, [sp+4]
    296   1.1.1.2  mrg 	mov1	cy, a.7
    297   1.1.1.2  mrg 	movw	MDAL, ax
    298   1.1.1.2  mrg 	;; If it is not negative then we perform the modulo operation without conversion.
    299   1.1.1.2  mrg 	bnc	$__mod_no_convert
    300   1.1.1.2  mrg 
    301   1.1.1.2  mrg 	;; Otherwise we negate the numerator and then go with a modulo followed by negation.
    302   1.1.1.2  mrg 	_Negate MDAL MDAL
    303   1.1.1.2  mrg 	br	$!__mod_then_convert
    304   1.1.1.2  mrg 
    305   1.1.1.2  mrg __mod_neg_num:
    306   1.1.1.2  mrg 	;; Negate the numerator (which is in MDAL)
    307   1.1.1.2  mrg 	;; We know that the denumerator is positive.
    308   1.1.1.2  mrg 	_Negate MDAL MDAL
    309   1.1.1.2  mrg 
    310   1.1.1.2  mrg __mod_then_convert:
    311   1.1.1.2  mrg 	mov	a, #0xC1	; Set the DIVST bit in MDUC
    312   1.1.1.2  mrg 	mov	!MDUC, a	; This starts the division op
    313   1.1.1.2  mrg 
    314   1.1.1.2  mrg 1:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
    315   1.1.1.2  mrg 	bt	a.0, $1b
    316   1.1.1.2  mrg 
    317   1.1.1.2  mrg 	_Negate	MDCL r8
    318   1.1.1.2  mrg 	ret
    319   1.1.1.2  mrg 
    320   1.1.1.2  mrg END_FUNC ___modhi3
    321   1.1.1.2  mrg 
    322   1.1.1.2  mrg ;----------------------------------------------------------------------
    323   1.1.1.2  mrg 
    324   1.1.1.2  mrg START_FUNC ___udivhi3
    325   1.1.1.2  mrg 	;; r8 = 4[sp] / 6[sp] (unsigned division)
    326   1.1.1.2  mrg 
    327   1.1.1.2  mrg 	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1
    328   1.1.1.2  mrg 	mov	!MDUC, a	; This preps the peripheral for division without interrupt generation
    329   1.1.1.2  mrg 
    330   1.1.1.2  mrg 	movw	ax, [sp+4]	; Load the divisor
    331   1.1.1.2  mrg 	movw	MDAL, ax
    332   1.1.1.2  mrg 	movw	ax, [sp+6]	; Load the dividend
    333   1.1.1.2  mrg 	movw	MDBL, ax
    334   1.1.1.2  mrg 	clrw	ax
    335   1.1.1.2  mrg 	movw	MDAH, ax
    336   1.1.1.2  mrg 	movw	MDBH, ax
    337   1.1.1.2  mrg 
    338   1.1.1.2  mrg 	mov	a, #0xC1	; Set the DIVST bit in MDUC
    339   1.1.1.2  mrg 	mov	!MDUC, a	; This starts the division op
    340   1.1.1.2  mrg 
    341   1.1.1.2  mrg 1:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
    342   1.1.1.2  mrg 	bt	a.0, $1b
    343   1.1.1.2  mrg 
    344   1.1.1.2  mrg   	movw	ax, !MDAL	; Read the remainder
    345   1.1.1.2  mrg 	movw	r8, ax
    346   1.1.1.2  mrg 	ret
    347   1.1.1.2  mrg 
    348   1.1.1.2  mrg END_FUNC   ___udivhi3
    349   1.1.1.2  mrg 
    350   1.1.1.2  mrg ;----------------------------------------------------------------------
    351   1.1.1.2  mrg 
    352   1.1.1.2  mrg START_FUNC ___umodhi3
    353   1.1.1.2  mrg 	;; r8 = 4[sp] % 6[sp] (unsigned modulus)
    354   1.1.1.2  mrg 
    355   1.1.1.2  mrg 	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1
    356   1.1.1.2  mrg 	mov	!MDUC, a	; This preps the peripheral for division without interrupt generation
    357   1.1.1.2  mrg 
    358   1.1.1.2  mrg 	movw	ax, [sp+4]	; Load the divisor
    359   1.1.1.2  mrg 	movw	MDAL, ax
    360   1.1.1.2  mrg 	movw	ax, [sp+6]	; Load the dividend
    361   1.1.1.2  mrg 	movw	MDBL, ax
    362   1.1.1.2  mrg 	clrw	ax
    363   1.1.1.2  mrg 	movw	MDAH, ax
    364   1.1.1.2  mrg 	movw	MDBH, ax
    365   1.1.1.2  mrg 
    366   1.1.1.2  mrg 	mov	a, #0xC1	; Set the DIVST bit in MDUC
    367   1.1.1.2  mrg 	mov	!MDUC, a	; This starts the division op
    368   1.1.1.2  mrg 
    369   1.1.1.2  mrg 1:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
    370   1.1.1.2  mrg 	bt	a.0, $1b
    371   1.1.1.2  mrg 
    372   1.1.1.2  mrg   	movw	ax, !MDCL	; Read the remainder
    373   1.1.1.2  mrg 	movw	r8, ax
    374   1.1.1.2  mrg 	ret
    375   1.1.1.2  mrg 
    376   1.1.1.2  mrg END_FUNC   ___umodhi3
    377   1.1.1.2  mrg 
    378   1.1.1.2  mrg ;----------------------------------------------------------------------
    379   1.1.1.2  mrg 
    380   1.1.1.2  mrg #elif defined __RL78_MUL_NONE__
    381   1.1.1.2  mrg 
    382       1.1  mrg .macro MAKE_GENERIC  which,need_result
    383       1.1  mrg 
    384       1.1  mrg 	.if \need_result
    385       1.1  mrg 	quot = r8
    386       1.1  mrg 	num = r10
    387       1.1  mrg 	den = r12
    388       1.1  mrg 	bit = r14
    389       1.1  mrg 	.else
    390       1.1  mrg 	num = r8
    391       1.1  mrg 	quot = r10
    392       1.1  mrg 	den = r12
    393       1.1  mrg 	bit = r14
    394       1.1  mrg 	.endif
    395       1.1  mrg 
    396       1.1  mrg 	quotB0 = quot
    397       1.1  mrg 	quotB1 = quot+1
    398       1.1  mrg 
    399       1.1  mrg 	numB0 = num
    400       1.1  mrg 	numB1 = num+1
    401       1.1  mrg 
    402       1.1  mrg 	denB0 = den
    403       1.1  mrg 	denB1 = den+1
    404       1.1  mrg 
    405       1.1  mrg 	bitB0 = bit
    406       1.1  mrg 	bitB1 = bit+1
    407       1.1  mrg 
    408       1.1  mrg #define bit	bc
    409       1.1  mrg #define bitB0	c
    410       1.1  mrg #define bitB1	b
    411       1.1  mrg 
    412       1.1  mrg 	START_FUNC __generic_hidivmod\which
    413       1.1  mrg 
    414       1.1  mrg num_lt_den\which:
    415       1.1  mrg 	.if \need_result
    416       1.1  mrg 	movw	r8, #0
    417       1.1  mrg 	.else
    418       1.1  mrg 	movw	ax, [sp+8]
    419       1.1  mrg 	movw	r8, ax
    420       1.1  mrg 	.endif
    421       1.1  mrg 	ret
    422       1.1  mrg 
    423       1.1  mrg 	;; These routines leave DE alone - the signed functions use DE
    424       1.1  mrg 	;; to store sign information that must remain intact
    425       1.1  mrg 
    426       1.1  mrg 	.if \need_result
    427       1.1  mrg 	.global __generic_hidiv
    428       1.1  mrg __generic_hidiv:
    429       1.1  mrg 
    430       1.1  mrg 	.else
    431       1.1  mrg 
    432       1.1  mrg 	.global __generic_himod
    433       1.1  mrg __generic_himod:
    434       1.1  mrg 
    435       1.1  mrg 	.endif
    436       1.1  mrg 
    437       1.1  mrg 	;; (quot,rem) = 8[sp] /% 10[sp]
    438       1.1  mrg 
    439       1.1  mrg 	movw	hl, sp
    440       1.1  mrg 	movw	ax, [hl+10] ; denH
    441       1.1  mrg 	cmpw	ax, [hl+8] ; numH
    442       1.1  mrg 	bh	$num_lt_den\which
    443       1.1  mrg 
    444       1.1  mrg 	;; (quot,rem) = 16[sp] /% 20[sp]
    445       1.1  mrg 
    446       1.1  mrg 	;; copy numerator
    447       1.1  mrg 	movw	ax, [hl+8]
    448       1.1  mrg 	movw	num, ax
    449       1.1  mrg 
    450       1.1  mrg 	;; copy denomonator
    451       1.1  mrg 	movw	ax, [hl+10]
    452       1.1  mrg 	movw	den, ax
    453       1.1  mrg 
    454       1.1  mrg 	movw	ax, den
    455       1.1  mrg 	cmpw	ax, #0
    456       1.1  mrg 	bnz	$den_not_zero\which
    457   1.1.1.2  mrg 	.if \need_result
    458   1.1.1.2  mrg 	movw    quot, #0
    459   1.1.1.2  mrg 	.else
    460       1.1  mrg 	movw	num, #0
    461   1.1.1.2  mrg 	.endif
    462       1.1  mrg 	ret
    463       1.1  mrg 
    464       1.1  mrg den_not_zero\which:
    465       1.1  mrg 	.if \need_result
    466       1.1  mrg 	;; zero out quot
    467       1.1  mrg 	movw	quot, #0
    468       1.1  mrg 	.endif
    469       1.1  mrg 
    470       1.1  mrg 	;; initialize bit to 1
    471       1.1  mrg 	movw	bit, #1
    472       1.1  mrg 
    473       1.1  mrg ; while (den < num && !(den & (1L << BITS_MINUS_1)))
    474       1.1  mrg 
    475       1.1  mrg shift_den_bit\which:
    476       1.1  mrg 	movw	ax, den
    477       1.1  mrg 	mov1	cy,a.7
    478       1.1  mrg 	bc	$enter_main_loop\which
    479       1.1  mrg 	cmpw	ax, num
    480       1.1  mrg 	bh	$enter_main_loop\which
    481       1.1  mrg 
    482       1.1  mrg 	;; den <<= 1
    483       1.1  mrg ;	movw	ax, den		; already has it from the cmpw above
    484       1.1  mrg 	shlw	ax, 1
    485       1.1  mrg 	movw	den, ax
    486       1.1  mrg 
    487       1.1  mrg 	;; bit <<= 1
    488       1.1  mrg 	.if \need_result
    489       1.1  mrg #ifdef bit
    490       1.1  mrg 	shlw	bit, 1
    491       1.1  mrg #else
    492       1.1  mrg 	movw	ax, bit
    493       1.1  mrg 	shlw	ax, 1
    494       1.1  mrg 	movw	bit, ax
    495       1.1  mrg #endif
    496       1.1  mrg 	.else
    497       1.1  mrg 	;; if we don't need to compute the quotent, we don't need an
    498       1.1  mrg 	;; actual bit *mask*, we just need to keep track of which bit
    499       1.1  mrg 	inc	bitB0
    500       1.1  mrg 	.endif
    501       1.1  mrg 
    502       1.1  mrg 	br	$shift_den_bit\which
    503       1.1  mrg 
    504       1.1  mrg main_loop\which:
    505       1.1  mrg 
    506       1.1  mrg 	;; if (num >= den) (cmp den > num)
    507       1.1  mrg 	movw	ax, den
    508       1.1  mrg 	cmpw	ax, num
    509       1.1  mrg 	bh	$next_loop\which
    510       1.1  mrg 
    511       1.1  mrg 	;; num -= den
    512       1.1  mrg 	movw	ax, num
    513       1.1  mrg 	subw	ax, den
    514       1.1  mrg 	movw	num, ax
    515       1.1  mrg 
    516       1.1  mrg 	.if \need_result
    517       1.1  mrg 	;; res |= bit
    518       1.1  mrg 	mov	a, quotB0
    519       1.1  mrg 	or	a, bitB0
    520       1.1  mrg 	mov	quotB0, a
    521       1.1  mrg 	mov	a, quotB1
    522       1.1  mrg 	or	a, bitB1
    523       1.1  mrg 	mov	quotB1, a
    524       1.1  mrg 	.endif
    525       1.1  mrg 
    526       1.1  mrg next_loop\which:
    527       1.1  mrg 
    528       1.1  mrg 	;; den >>= 1
    529       1.1  mrg 	movw	ax, den
    530       1.1  mrg 	shrw	ax, 1
    531       1.1  mrg 	movw	den, ax
    532       1.1  mrg 
    533       1.1  mrg 	.if \need_result
    534       1.1  mrg 	;; bit >>= 1
    535       1.1  mrg 	movw	ax, bit
    536       1.1  mrg 	shrw	ax, 1
    537       1.1  mrg 	movw	bit, ax
    538       1.1  mrg 	.else
    539       1.1  mrg 	dec	bitB0
    540       1.1  mrg 	.endif
    541       1.1  mrg 
    542       1.1  mrg enter_main_loop\which:
    543       1.1  mrg 	.if \need_result
    544       1.1  mrg 	movw	ax, bit
    545       1.1  mrg 	cmpw	ax, #0
    546       1.1  mrg 	.else
    547       1.1  mrg 	cmp0	bitB0
    548       1.1  mrg 	.endif
    549       1.1  mrg 	bnz	$main_loop\which
    550       1.1  mrg 
    551       1.1  mrg main_loop_done\which:
    552       1.1  mrg 	ret
    553       1.1  mrg 	END_FUNC __generic_hidivmod\which
    554       1.1  mrg .endm
    555       1.1  mrg ;----------------------------------------------------------------------
    556       1.1  mrg 
    557       1.1  mrg 	MAKE_GENERIC _d 1
    558       1.1  mrg 	MAKE_GENERIC _m 0
    559       1.1  mrg 
    560       1.1  mrg ;----------------------------------------------------------------------
    561       1.1  mrg 
    562       1.1  mrg START_FUNC ___udivhi3
    563       1.1  mrg 	;; r8 = 4[sp] / 6[sp]
    564       1.1  mrg 	call	$!__generic_hidiv
    565       1.1  mrg 	ret
    566       1.1  mrg END_FUNC ___udivhi3
    567       1.1  mrg 
    568       1.1  mrg 
    569       1.1  mrg START_FUNC ___umodhi3
    570       1.1  mrg 	;; r8 = 4[sp] % 6[sp]
    571       1.1  mrg 	call	$!__generic_himod
    572       1.1  mrg 	ret
    573       1.1  mrg END_FUNC ___umodhi3
    574       1.1  mrg 
    575       1.1  mrg ;----------------------------------------------------------------------
    576       1.1  mrg 
    577       1.1  mrg .macro NEG_AX
    578       1.1  mrg 	movw	hl, ax
    579       1.1  mrg 	movw	ax, #0
    580       1.1  mrg 	subw	ax, [hl]
    581       1.1  mrg 	movw	[hl], ax
    582       1.1  mrg .endm
    583       1.1  mrg 
    584       1.1  mrg ;----------------------------------------------------------------------
    585       1.1  mrg 
    586       1.1  mrg START_FUNC ___divhi3
    587       1.1  mrg 	;; r8 = 4[sp] / 6[sp]
    588       1.1  mrg 	movw	de, #0
    589       1.1  mrg 	mov	a, [sp+5]
    590       1.1  mrg 	mov1	cy, a.7
    591       1.1  mrg 	bc	$div_signed_num
    592       1.1  mrg 	mov	a, [sp+7]
    593       1.1  mrg 	mov1	cy, a.7
    594       1.1  mrg 	bc	$div_signed_den
    595       1.1  mrg 	call	$!__generic_hidiv
    596       1.1  mrg 	ret
    597       1.1  mrg 
    598       1.1  mrg div_signed_num:
    599       1.1  mrg 	;; neg [sp+4]
    600       1.1  mrg 	movw	ax, sp
    601       1.1  mrg 	addw	ax, #4
    602       1.1  mrg 	NEG_AX
    603       1.1  mrg 	mov	d, #1
    604       1.1  mrg 	mov	a, [sp+7]
    605       1.1  mrg 	mov1	cy, a.7
    606       1.1  mrg 	bnc	$div_unsigned_den
    607       1.1  mrg div_signed_den:
    608       1.1  mrg 	;; neg [sp+6]
    609       1.1  mrg 	movw	ax, sp
    610       1.1  mrg 	addw	ax, #6
    611       1.1  mrg 	NEG_AX
    612       1.1  mrg 	mov	e, #1
    613       1.1  mrg div_unsigned_den:
    614       1.1  mrg 	call	$!__generic_hidiv
    615       1.1  mrg 
    616       1.1  mrg 	mov	a, d
    617       1.1  mrg 	cmp0	a
    618       1.1  mrg 	bz	$div_skip_restore_num
    619       1.1  mrg 	;;  We have to restore the numerator [sp+4]
    620       1.1  mrg 	movw	ax, sp
    621       1.1  mrg 	addw	ax, #4
    622       1.1  mrg 	NEG_AX
    623       1.1  mrg 	mov	a, d
    624       1.1  mrg div_skip_restore_num:
    625       1.1  mrg 	xor	a, e
    626       1.1  mrg 	bz	$div_no_neg
    627       1.1  mrg 	movw	ax, #r8
    628       1.1  mrg 	NEG_AX
    629       1.1  mrg div_no_neg:
    630       1.1  mrg 	mov	a, e
    631       1.1  mrg 	cmp0	a
    632       1.1  mrg 	bz	$div_skip_restore_den
    633       1.1  mrg 	movw	ax, sp
    634       1.1  mrg 	addw	ax, #6
    635       1.1  mrg 	NEG_AX
    636       1.1  mrg div_skip_restore_den:
    637       1.1  mrg 	ret
    638       1.1  mrg END_FUNC ___divhi3
    639       1.1  mrg 
    640       1.1  mrg 
    641       1.1  mrg START_FUNC ___modhi3
    642       1.1  mrg 	;; r8 = 4[sp] % 6[sp]
    643       1.1  mrg 	movw	de, #0
    644       1.1  mrg 	mov	a, [sp+5]
    645       1.1  mrg 	mov1	cy, a.7
    646       1.1  mrg 	bc	$mod_signed_num
    647       1.1  mrg 	mov	a, [sp+7]
    648       1.1  mrg 	mov1	cy, a.7
    649       1.1  mrg 	bc	$mod_signed_den
    650       1.1  mrg 	call	$!__generic_himod
    651       1.1  mrg 	ret
    652       1.1  mrg 
    653       1.1  mrg mod_signed_num:
    654       1.1  mrg 	;; neg [sp+4]
    655       1.1  mrg 	movw	ax, sp
    656       1.1  mrg 	addw	ax, #4
    657       1.1  mrg 	NEG_AX
    658       1.1  mrg 	mov	d, #1
    659       1.1  mrg 	mov	a, [sp+7]
    660       1.1  mrg 	mov1	cy, a.7
    661       1.1  mrg 	bnc	$mod_unsigned_den
    662       1.1  mrg mod_signed_den:
    663       1.1  mrg 	;; neg [sp+6]
    664       1.1  mrg 	movw	ax, sp
    665       1.1  mrg 	addw	ax, #6
    666       1.1  mrg 	NEG_AX
    667       1.1  mrg mod_unsigned_den:
    668       1.1  mrg 	call	$!__generic_himod
    669       1.1  mrg 
    670       1.1  mrg 	mov	a, d
    671       1.1  mrg 	cmp0	a
    672       1.1  mrg 	bz	$mod_no_neg
    673       1.1  mrg 	movw	ax, #r8
    674       1.1  mrg 	NEG_AX
    675       1.1  mrg 	;;  Also restore numerator
    676       1.1  mrg 	movw 	ax, sp
    677       1.1  mrg 	addw	ax, #4
    678       1.1  mrg 	NEG_AX
    679       1.1  mrg mod_no_neg:
    680       1.1  mrg 	mov	a, e
    681       1.1  mrg 	cmp0	a
    682       1.1  mrg 	bz	$mod_skip_restore_den
    683       1.1  mrg 	movw	ax, sp
    684       1.1  mrg 	addw	ax, #6
    685       1.1  mrg 	NEG_AX
    686       1.1  mrg mod_skip_restore_den:
    687       1.1  mrg 	ret
    688       1.1  mrg END_FUNC ___modhi3
    689   1.1.1.2  mrg 
    690   1.1.1.2  mrg ;----------------------------------------------------------------------
    691   1.1.1.2  mrg 
    692   1.1.1.2  mrg #else
    693   1.1.1.2  mrg 
    694   1.1.1.2  mrg #error "Unknown RL78 hardware multiply/divide support"
    695   1.1.1.2  mrg 
    696   1.1.1.2  mrg #endif
    697