|  | /* QImode div/mod functions for the GCC support library for the Renesas RL78 processors. | 
|  | Copyright (C) 2012-2024 Free Software Foundation, Inc. | 
|  | Contributed by Red Hat. | 
|  |  | 
|  | This file is part of GCC. | 
|  |  | 
|  | GCC is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3, or (at your option) | 
|  | any later version. | 
|  |  | 
|  | GCC is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | Under Section 7 of GPL version 3, you are granted additional | 
|  | permissions described in the GCC Runtime Library Exception, version | 
|  | 3.1, as published by the Free Software Foundation. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License and | 
|  | a copy of the GCC Runtime Library Exception along with this program; | 
|  | see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see | 
|  | <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | #include "vregs.h" | 
|  |  | 
|  | .macro MAKE_GENERIC  which,need_result | 
|  |  | 
|  | .if \need_result | 
|  | quot = r8 | 
|  | num = r10 | 
|  | den = r12 | 
|  | bit = r14 | 
|  | .else | 
|  | num = r8 | 
|  | quot = r10 | 
|  | den = r12 | 
|  | bit = r14 | 
|  | .endif | 
|  |  | 
|  | #define bit	b | 
|  | #define den	c | 
|  | #define bitden	bc | 
|  |  | 
|  | START_FUNC __generic_qidivmod\which | 
|  |  | 
|  | num_lt_den\which: | 
|  | .if \need_result | 
|  | mov	r8, #0 | 
|  | .else | 
|  | mov	a, [hl+4] | 
|  | mov	r8, a | 
|  | .endif | 
|  | ret | 
|  |  | 
|  | num_eq_den\which: | 
|  | .if \need_result | 
|  | mov	r8, #1 | 
|  | .else | 
|  | mov	r8, #0 | 
|  | .endif | 
|  | ret | 
|  |  | 
|  | den_is_zero\which: | 
|  | mov	r8, #0x00 | 
|  | ret | 
|  |  | 
|  | ;; These routines leave DE alone - the signed functions use DE | 
|  | ;; to store sign information that must remain intact | 
|  |  | 
|  | .if \need_result | 
|  | .global __generic_qidiv | 
|  | __generic_qidiv: | 
|  |  | 
|  | .else | 
|  |  | 
|  | .global __generic_qimod | 
|  | __generic_qimod: | 
|  |  | 
|  | .endif | 
|  |  | 
|  | ;; (quot,rem) = 4[hl] /% 6[hl] | 
|  |  | 
|  | mov	a, [hl+4] ; num | 
|  | cmp	a, [hl+6] ; den | 
|  | bz	$num_eq_den\which | 
|  | bnh	$num_lt_den\which | 
|  |  | 
|  | ;; copy numerator | 
|  | ;	mov	a, [hl+4]	; already there from above | 
|  | mov	num, a | 
|  |  | 
|  | ;; copy denomonator | 
|  | mov	a, [hl+6] | 
|  | mov	den, a | 
|  |  | 
|  | cmp0	den | 
|  | bz	$den_is_zero\which | 
|  |  | 
|  | den_not_zero\which: | 
|  | .if \need_result | 
|  | ;; zero out quot | 
|  | mov	quot, #0 | 
|  | .endif | 
|  |  | 
|  | ;; initialize bit to 1 | 
|  | mov	bit, #1 | 
|  |  | 
|  | ; while (den < num && !(den & (1L << BITS_MINUS_1))) | 
|  |  | 
|  | shift_den_bit\which: | 
|  |  | 
|  | .macro	SDB_ONE\which | 
|  | mov	a, den | 
|  | mov1	cy,a.7 | 
|  | bc	$enter_main_loop\which | 
|  | cmp	a, num | 
|  | bh	$enter_main_loop\which | 
|  |  | 
|  | ;; den <<= 1 | 
|  | ;	mov	a, den		; already has it from the cmpw above | 
|  | shl	a, 1 | 
|  | mov	den, a | 
|  |  | 
|  | ;; bit <<= 1 | 
|  | shl	bit, 1 | 
|  | .endm | 
|  |  | 
|  | SDB_ONE\which | 
|  | SDB_ONE\which | 
|  |  | 
|  | br	$shift_den_bit\which | 
|  |  | 
|  | main_loop\which: | 
|  |  | 
|  | ;; if (num >= den) (cmp den > num) | 
|  | mov	a, den | 
|  | cmp	a, num | 
|  | bh	$next_loop\which | 
|  |  | 
|  | ;; num -= den | 
|  | mov	a, num | 
|  | sub	a, den | 
|  | mov	num, a | 
|  |  | 
|  | .if \need_result | 
|  | ;; res |= bit | 
|  | mov	a, quot | 
|  | or	a, bit | 
|  | mov	quot, a | 
|  | .endif | 
|  |  | 
|  | next_loop\which: | 
|  |  | 
|  | ;; den, bit >>= 1 | 
|  | movw	ax, bitden | 
|  | shrw	ax, 1 | 
|  | movw	bitden, ax | 
|  |  | 
|  | enter_main_loop\which: | 
|  | cmp0	bit | 
|  | bnz	$main_loop\which | 
|  |  | 
|  | main_loop_done\which: | 
|  | ret | 
|  | END_FUNC __generic_qidivmod\which | 
|  | .endm | 
|  |  | 
|  | ;---------------------------------------------------------------------- | 
|  |  | 
|  | MAKE_GENERIC _d 1 | 
|  | MAKE_GENERIC _m 0 | 
|  |  | 
|  | ;---------------------------------------------------------------------- | 
|  |  | 
|  | START_FUNC ___udivqi3 | 
|  | ;; r8 = 4[sp] / 6[sp] | 
|  | movw	hl, sp | 
|  | br	$!__generic_qidiv | 
|  | END_FUNC ___udivqi3 | 
|  |  | 
|  |  | 
|  | START_FUNC ___umodqi3 | 
|  | ;; r8 = 4[sp] % 6[sp] | 
|  | movw	hl, sp | 
|  | br	$!__generic_qimod | 
|  | END_FUNC ___umodqi3 | 
|  |  | 
|  | ;---------------------------------------------------------------------- | 
|  |  | 
|  | .macro NEG_AX | 
|  | movw	hl, ax | 
|  | mov	a, #0 | 
|  | sub	a, [hl] | 
|  | mov	[hl], a | 
|  | .endm | 
|  |  | 
|  | ;---------------------------------------------------------------------- | 
|  |  | 
|  | START_FUNC	___divqi3 | 
|  | ;; r8 = 4[sp] / 6[sp] | 
|  | movw	hl, sp | 
|  | movw	de, #0 | 
|  | mov	a, [sp+4] | 
|  | mov1	cy, a.7 | 
|  | bc	$div_signed_num | 
|  | mov	a, [sp+6] | 
|  | mov1	cy, a.7 | 
|  | bc	$div_signed_den | 
|  | br	$!__generic_qidiv | 
|  |  | 
|  | div_signed_num: | 
|  | ;; neg [sp+4] | 
|  | mov	a, #0 | 
|  | sub	a, [hl+4] | 
|  | mov	[hl+4], a | 
|  | mov	d, #1 | 
|  | mov	a, [sp+6] | 
|  | mov1	cy, a.6 | 
|  | bnc	$div_unsigned_den | 
|  | div_signed_den: | 
|  | ;; neg [sp+6] | 
|  | mov	a, #0 | 
|  | sub	a, [hl+6] | 
|  | mov	[hl+6], a | 
|  | mov	e, #1 | 
|  | div_unsigned_den: | 
|  | call	$!__generic_qidiv | 
|  |  | 
|  | mov	a, d | 
|  | cmp0	a | 
|  | bz	$div_skip_restore_num | 
|  | ;;  We have to restore the numerator [sp+4] | 
|  | movw	ax, sp | 
|  | addw	ax, #4 | 
|  | NEG_AX | 
|  | mov	a, d | 
|  | div_skip_restore_num: | 
|  | xor	a, e | 
|  | bz	$div_no_neg | 
|  | movw	ax, #r8 | 
|  | NEG_AX | 
|  | div_no_neg: | 
|  | mov	a, e | 
|  | cmp0	a | 
|  | bz	$div_skip_restore_den | 
|  | movw	ax, sp | 
|  | addw	ax, #6 | 
|  | NEG_AX | 
|  | div_skip_restore_den: | 
|  | ret | 
|  | END_FUNC ___divqi3 | 
|  |  | 
|  |  | 
|  | START_FUNC ___modqi3 | 
|  | ;; r8 = 4[sp] % 6[sp] | 
|  | movw	hl, sp | 
|  | movw	de, #0 | 
|  | mov	a, [hl+4] | 
|  | mov1	cy, a.7 | 
|  | bc	$mod_signed_num | 
|  | mov	a, [hl+6] | 
|  | mov1	cy, a.7 | 
|  | bc	$mod_signed_den | 
|  | br	$!__generic_qimod | 
|  |  | 
|  | mod_signed_num: | 
|  | ;; neg [sp+4] | 
|  | mov	a, #0 | 
|  | sub	a, [hl+4] | 
|  | mov	[hl+4], a | 
|  | mov	d, #1 | 
|  | mov	a, [hl+6] | 
|  | mov1	cy, a.7 | 
|  | bnc	$mod_unsigned_den | 
|  | mod_signed_den: | 
|  | ;; neg [sp+6] | 
|  | mov	a, #0 | 
|  | sub	a, [hl+6] | 
|  | mov	[hl+6], a | 
|  | mov	e, #1 | 
|  | mod_unsigned_den: | 
|  | call	$!__generic_qimod | 
|  |  | 
|  | mov	a, d | 
|  | cmp0	a | 
|  | bz	$mod_no_neg | 
|  | mov	a, #0 | 
|  | sub	a, r8 | 
|  | mov	r8, a | 
|  | ;;  Also restore numerator | 
|  | movw 	ax, sp | 
|  | addw	ax, #4 | 
|  | NEG_AX | 
|  | mod_no_neg: | 
|  | mov	a, e | 
|  | cmp0	a | 
|  | bz	$mod_skip_restore_den | 
|  | movw	ax, sp | 
|  | addw	ax, #6 | 
|  | NEG_AX | 
|  | mod_skip_restore_den: | 
|  | ret | 
|  | END_FUNC ___modqi3 |