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