xref: /openbmc/linux/arch/xtensa/lib/udivsi3.S (revision 338d9150)
1dbf4ed89SMax Filippov/* SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 */
2dbf4ed89SMax Filippov#include <linux/linkage.h>
3dbf4ed89SMax Filippov#include <asm/asmmacro.h>
4dbf4ed89SMax Filippov#include <asm/core.h>
5dbf4ed89SMax Filippov
6dbf4ed89SMax FilippovENTRY(__udivsi3)
7dbf4ed89SMax Filippov
8dbf4ed89SMax Filippov	abi_entry_default
9dbf4ed89SMax Filippov#if XCHAL_HAVE_DIV32
10dbf4ed89SMax Filippov	quou	a2, a2, a3
11dbf4ed89SMax Filippov#else
12dbf4ed89SMax Filippov	bltui	a3, 2, .Lle_one	/* check if the divisor <= 1 */
13dbf4ed89SMax Filippov
14dbf4ed89SMax Filippov	mov	a6, a2		/* keep dividend in a6 */
15dbf4ed89SMax Filippov	do_nsau	a5, a6, a2, a7	/* dividend_shift = nsau (dividend) */
16dbf4ed89SMax Filippov	do_nsau	a4, a3, a2, a7	/* divisor_shift = nsau (divisor) */
17dbf4ed89SMax Filippov	bgeu	a5, a4, .Lspecial
18dbf4ed89SMax Filippov
19dbf4ed89SMax Filippov	sub	a4, a4, a5	/* count = divisor_shift - dividend_shift */
20dbf4ed89SMax Filippov	ssl	a4
21dbf4ed89SMax Filippov	sll	a3, a3		/* divisor <<= count */
22dbf4ed89SMax Filippov	movi	a2, 0		/* quotient = 0 */
23dbf4ed89SMax Filippov
24dbf4ed89SMax Filippov	/* test-subtract-and-shift loop; one quotient bit on each iteration */
25dbf4ed89SMax Filippov#if XCHAL_HAVE_LOOPS
26dbf4ed89SMax Filippov	loopnez	a4, .Lloopend
27dbf4ed89SMax Filippov#endif /* XCHAL_HAVE_LOOPS */
28dbf4ed89SMax Filippov.Lloop:
29dbf4ed89SMax Filippov	bltu	a6, a3, .Lzerobit
30dbf4ed89SMax Filippov	sub	a6, a6, a3
31dbf4ed89SMax Filippov	addi	a2, a2, 1
32dbf4ed89SMax Filippov.Lzerobit:
33dbf4ed89SMax Filippov	slli	a2, a2, 1
34dbf4ed89SMax Filippov	srli	a3, a3, 1
35dbf4ed89SMax Filippov#if !XCHAL_HAVE_LOOPS
36dbf4ed89SMax Filippov	addi	a4, a4, -1
37dbf4ed89SMax Filippov	bnez	a4, .Lloop
38dbf4ed89SMax Filippov#endif /* !XCHAL_HAVE_LOOPS */
39dbf4ed89SMax Filippov.Lloopend:
40dbf4ed89SMax Filippov
41dbf4ed89SMax Filippov	bltu	a6, a3, .Lreturn
42dbf4ed89SMax Filippov	addi	a2, a2, 1	/* increment quotient if dividend >= divisor */
43dbf4ed89SMax Filippov.Lreturn:
44dbf4ed89SMax Filippov	abi_ret_default
45dbf4ed89SMax Filippov
46dbf4ed89SMax Filippov.Lle_one:
47dbf4ed89SMax Filippov	beqz	a3, .Lerror	/* if divisor == 1, return the dividend */
48dbf4ed89SMax Filippov	abi_ret_default
49dbf4ed89SMax Filippov
50dbf4ed89SMax Filippov.Lspecial:
51dbf4ed89SMax Filippov	/* return dividend >= divisor */
52dbf4ed89SMax Filippov	bltu	a6, a3, .Lreturn0
53dbf4ed89SMax Filippov	movi	a2, 1
54dbf4ed89SMax Filippov	abi_ret_default
55dbf4ed89SMax Filippov
56dbf4ed89SMax Filippov.Lerror:
57dbf4ed89SMax Filippov	/* Divide by zero: Use an illegal instruction to force an exception.
58dbf4ed89SMax Filippov	   The subsequent "DIV0" string can be recognized by the exception
59dbf4ed89SMax Filippov	   handler to identify the real cause of the exception.  */
60dbf4ed89SMax Filippov	ill
61dbf4ed89SMax Filippov	.ascii	"DIV0"
62dbf4ed89SMax Filippov
63dbf4ed89SMax Filippov.Lreturn0:
64dbf4ed89SMax Filippov	movi	a2, 0
65dbf4ed89SMax Filippov#endif /* XCHAL_HAVE_DIV32 */
66dbf4ed89SMax Filippov	abi_ret_default
67dbf4ed89SMax Filippov
68dbf4ed89SMax FilippovENDPROC(__udivsi3)
69*338d9150SMax FilippovEXPORT_SYMBOL(__udivsi3)
70