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