Home | History | Annotate | Line # | Download | only in rl78
divmodsi.S revision 1.1.1.7
      1 /* SImode div/mod functions for the GCC support library for the Renesas RL78 processors.
      2    Copyright (C) 2012-2022 Free Software Foundation, Inc.
      3    Contributed by Red Hat.
      4 
      5    This file is part of GCC.
      6 
      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.
     11 
     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.
     16 
     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.
     20 
     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/>.  */
     25 
     26 #include "vregs.h"
     27 
     28 #if defined __RL78_MUL_G14__
     29 
     30 START_FUNC ___divsi3
     31 	;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
     32 
     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
     40 
     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
     47 
     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
     59 
     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
     78 
     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
    108 
    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
    122 
    123 	movw	ax, [sp+8]
    124 	xchw	ax, de
    125 
    126 __div_then_convert:
    127 	push	psw
    128 	di
    129 	divwu
    130 	pop	psw
    131 
    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
    143 
    144 END_FUNC ___divsi3
    145 
    146 ;----------------------------------------------------------------------
    147 
    148 START_FUNC ___udivsi3
    149 	;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
    150 	;; Used when compiling with -Os specified.
    151 
    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
    167 
    168 END_FUNC ___udivsi3
    169 
    170 ;----------------------------------------------------------------------
    171 
    172 START_FUNC ___modsi3
    173 	;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
    174 
    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
    182 
    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
    189 
    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
    196 
    197 	movw	ax, de
    198 	movw	r8, ax
    199 	movw	ax, hl
    200 	movw	r10, ax
    201 	ret
    202 
    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
    221 
    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
    238 
    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
    252 
    253 	movw	ax, [sp+8]
    254 	xchw	ax, de
    255 
    256 __mod_then_convert:
    257 	push	psw
    258 	di
    259 	divwu
    260 	pop	psw
    261 
    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
    272 
    273 END_FUNC ___modsi3
    274 
    275 ;----------------------------------------------------------------------
    276 
    277 START_FUNC ___umodsi3
    278 	;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
    279 	;; Used when compiling with -Os specified.
    280 
    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
    297 
    298 END_FUNC   ___umodsi3
    299 
    300 ;----------------------------------------------------------------------
    301 
    302 #elif defined __RL78_MUL_G13__
    303 
    304 ;----------------------------------------------------------------------
    305 
    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
    314 
    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 ;----------------------------------------------------------------------
    331 
    332 START_FUNC ___divsi3
    333 	;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
    334 
    335 	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1
    336 	mov	!MDUC, a	; This preps the peripheral for division without interrupt generation
    337 
    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
    345 
    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
    353 
    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
    358 
    359 1:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
    360 	bt	a.0, $1b
    361 
    362   	movw	ax, MDAL	; Read the result
    363 	movw	r8, ax
    364 	movw	ax, MDAH
    365 	movw	r10, ax
    366 	ret
    367 
    368 __div_neg_den:
    369 	;; Negate the denumerator (which is in MDBL/MDBH)
    370 	_Negate MDBL MDBH
    371 
    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
    380 
    381 	;; Otherwise we negate the numerator and then go with a straightforward unsigned division.
    382 	_Negate MDAL MDAH
    383 	br	$!__div_no_convert
    384 
    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
    393 
    394 1:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
    395 	bt	a.0, $1b
    396 
    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
    402 
    403 	ret
    404 
    405 END_FUNC ___divsi3
    406 
    407 ;----------------------------------------------------------------------
    408 
    409 START_FUNC ___modsi3
    410 	;; r8,r10 = 4[sp],6[sp] % 8[sp],10[sp]
    411 
    412 	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1
    413 	mov	!MDUC, a	; This preps the peripheral for division without interrupt generation
    414 
    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
    422 
    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
    430 
    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
    435 
    436 1:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
    437 	bt	a.0, $1b
    438 
    439   	movw	ax, !MDCL	; Read the remainder
    440 	movw	r8, ax
    441 	movw	ax, !MDCH
    442 	movw	r10, ax
    443 	ret
    444 
    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
    457 
    458 	;; Otherwise we negate the numerator and then go with a modulo followed by negation.
    459 	_Negate MDAL MDAH
    460 	br	$!__mod_then_convert
    461 
    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
    470 
    471 1:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
    472 	bt	a.0, $1b
    473 
    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
    487 
    488 END_FUNC ___modsi3
    489 
    490 ;----------------------------------------------------------------------
    491 
    492 START_FUNC ___udivsi3
    493 	;; r8,r10 = 4[sp],6[sp] / 8[sp],10[sp]
    494 	;; Used when compilng with -Os specified.
    495 
    496 	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1
    497 	mov	!MDUC, a	; This preps the peripheral for division without interrupt generation
    498 
    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
    510 
    511 1:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
    512 	bt	a.0, $1b
    513 
    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
    521 
    522 ;----------------------------------------------------------------------
    523 
    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
    528 
    529 	mov	a, #0xC0	; Set DIVMODE=1 and MACMODE=1
    530 	mov	!MDUC, a	; This preps the peripheral for division without interrupt generation
    531 
    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
    543 
    544 1:	mov	a, !MDUC	; Wait 16 clocks or until DIVST is clear
    545 	bt	a.0, $1b
    546 
    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
    554 
    555 ;----------------------------------------------------------------------
    556 
    557 #elif defined __RL78_MUL_NONE__
    558 
    559 .macro MAKE_GENERIC  which,need_result
    560 
    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
    572 
    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
    600 
    601 ;----------------------------------------------------------------------
    602 
    603 START_FUNC __generic_sidivmod\which
    604 
    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
    616 
    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
    631 
    632 	;; These routines leave DE alone - the signed functions use DE
    633 	;; to store sign information that must remain intact
    634 
    635 	.if \need_result
    636 	.global __generic_sidiv
    637 __generic_sidiv:
    638 
    639 	.else
    640 
    641 	.global __generic_simod
    642 __generic_simod:
    643 
    644 	.endif
    645 
    646 	;; (quot,rem) = 8[sp] /% 12[sp]
    647 
    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
    655 
    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
    671 
    672 	;; (quot,rem) = 16[sp] /% 20[sp]
    673 
    674 	;; copy numerator
    675 	movw	ax, [hl+8]
    676 	movw	numL, ax
    677 	movw	ax, [hl+10]
    678 	movw	numH, ax
    679 
    680 	;; copy denomonator
    681 	movw	ax, [hl+12]
    682 	movw	denL, ax
    683 	movw	ax, [hl+14]
    684 	movw	denH, ax
    685 
    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
    699 
    700 den_not_zero\which:
    701 	.if \need_result
    702 	;; zero out quot
    703 	movw	quotL, #0
    704 	movw	quotH, #0
    705 	.endif
    706 
    707 	;; initialize bit to 1
    708 	movw	bitL, #1
    709 	movw	bitH, #0
    710 
    711 ; while (den < num && !(den & (1L << BITS_MINUS_1)))
    712 
    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
    722 
    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
    732 
    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
    740 
    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
    754 
    755 	br	$shift_den_bit\which
    756 
    757 	;; while (bit)
    758 main_loop\which:
    759 
    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
    768 
    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
    778 
    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
    794 
    795 next_loop\which:
    796 
    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
    807 
    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
    822 
    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
    847 
    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
    856 
    857 	;; From here on in, r22, r14, and r18 are all zero
    858 	;; while (bit)
    859 main_loop_himode\which:
    860 
    861 	;; if (num >= den) (cmp den > num)
    862 	movw	ax, denL
    863 	cmpw	ax, numL
    864 	bh	$next_loop_himode\which
    865 
    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
    875 
    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
    885 
    886 next_loop_himode\which:
    887 
    888 	;; den >>= 1
    889 	movw	ax, denL
    890 	shrw	ax, 1
    891 	movw	denL, ax
    892 
    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
    901 
    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
    909 
    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
    926 
    927 	ret
    928 END_FUNC __generic_sidivmod\which
    929 .endm
    930 
    931 ;----------------------------------------------------------------------
    932 
    933 	MAKE_GENERIC _d 1
    934 	MAKE_GENERIC _m 0
    935 
    936 ;----------------------------------------------------------------------
    937 
    938 START_FUNC ___udivsi3
    939 	;; r8 = 4[sp] / 8[sp]
    940 	call	$!__generic_sidiv
    941 	ret
    942 END_FUNC ___udivsi3
    943 
    944 
    945 START_FUNC ___umodsi3
    946 	;; r8 = 4[sp] % 8[sp]
    947 	call	$!__generic_simod
    948 	ret
    949 END_FUNC ___umodsi3
    950 
    951 ;----------------------------------------------------------------------
    952 
    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
    964 
    965 ;----------------------------------------------------------------------
    966 
    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
    978 
    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
    996 
    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 
   1022 
   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
   1034 
   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
   1052 
   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
   1074 
   1075 ;----------------------------------------------------------------------
   1076 
   1077 #else
   1078 
   1079 #error "Unknown RL78 hardware multiply/divide support"
   1080 
   1081 #endif
   1082