xref: /linux/arch/xtensa/lib/modsi3.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(__modsi3)
7dbf4ed89SMax Filippov
8dbf4ed89SMax Filippov	abi_entry_default
9dbf4ed89SMax Filippov#if XCHAL_HAVE_DIV32
10dbf4ed89SMax Filippov	rems	a2, a2, a3
11dbf4ed89SMax Filippov#else
12dbf4ed89SMax Filippov	mov	a7, a2		/* save original (signed) dividend */
13dbf4ed89SMax Filippov	do_abs	a2, a2, a4	/* udividend = abs (dividend) */
14dbf4ed89SMax Filippov	do_abs	a3, a3, a4	/* udivisor = abs (divisor) */
15dbf4ed89SMax Filippov	bltui	a3, 2, .Lle_one	/* check if udivisor <= 1 */
16dbf4ed89SMax Filippov	do_nsau	a5, a2, a6, a8	/* udividend_shift = nsau (udividend) */
17dbf4ed89SMax Filippov	do_nsau	a4, a3, a6, a8	/* udivisor_shift = nsau (udivisor) */
18dbf4ed89SMax Filippov	bgeu	a5, a4, .Lspecial
19dbf4ed89SMax Filippov
20dbf4ed89SMax Filippov	sub	a4, a4, a5	/* count = udivisor_shift - udividend_shift */
21dbf4ed89SMax Filippov	ssl	a4
22dbf4ed89SMax Filippov	sll	a3, a3		/* udivisor <<= count */
23dbf4ed89SMax Filippov
24dbf4ed89SMax Filippov	/* test-subtract-and-shift loop */
25dbf4ed89SMax Filippov#if XCHAL_HAVE_LOOPS
26dbf4ed89SMax Filippov	loopnez	a4, .Lloopend
27dbf4ed89SMax Filippov#endif /* XCHAL_HAVE_LOOPS */
28dbf4ed89SMax Filippov.Lloop:
29dbf4ed89SMax Filippov	bltu	a2, a3, .Lzerobit
30dbf4ed89SMax Filippov	sub	a2, a2, a3
31dbf4ed89SMax Filippov.Lzerobit:
32dbf4ed89SMax Filippov	srli	a3, a3, 1
33dbf4ed89SMax Filippov#if !XCHAL_HAVE_LOOPS
34dbf4ed89SMax Filippov	addi	a4, a4, -1
35dbf4ed89SMax Filippov	bnez	a4, .Lloop
36dbf4ed89SMax Filippov#endif /* !XCHAL_HAVE_LOOPS */
37dbf4ed89SMax Filippov.Lloopend:
38dbf4ed89SMax Filippov
39dbf4ed89SMax Filippov.Lspecial:
40dbf4ed89SMax Filippov	bltu	a2, a3, .Lreturn
41dbf4ed89SMax Filippov	sub	a2, a2, a3	/* subtract again if udividend >= udivisor */
42dbf4ed89SMax Filippov.Lreturn:
43dbf4ed89SMax Filippov	bgez	a7, .Lpositive
44dbf4ed89SMax Filippov	neg	a2, a2		/* if (dividend < 0), return -udividend */
45dbf4ed89SMax Filippov.Lpositive:
46dbf4ed89SMax Filippov	abi_ret_default
47dbf4ed89SMax Filippov
48dbf4ed89SMax Filippov.Lle_one:
49dbf4ed89SMax Filippov	bnez	a3, .Lreturn0
50dbf4ed89SMax Filippov
51dbf4ed89SMax Filippov	/* Divide by zero: Use an illegal instruction to force an exception.
52dbf4ed89SMax Filippov	   The subsequent "DIV0" string can be recognized by the exception
53dbf4ed89SMax Filippov	   handler to identify the real cause of the exception.  */
54dbf4ed89SMax Filippov	ill
55dbf4ed89SMax Filippov	.ascii	"DIV0"
56dbf4ed89SMax Filippov
57dbf4ed89SMax Filippov.Lreturn0:
58dbf4ed89SMax Filippov	movi	a2, 0
59dbf4ed89SMax Filippov#endif /* XCHAL_HAVE_DIV32 */
60dbf4ed89SMax Filippov	abi_ret_default
61dbf4ed89SMax Filippov
62dbf4ed89SMax FilippovENDPROC(__modsi3)
63*338d9150SMax FilippovEXPORT_SYMBOL(__modsi3)
64dbf4ed89SMax Filippov
65dbf4ed89SMax Filippov#if !XCHAL_HAVE_NSA
66dbf4ed89SMax Filippov	.section .rodata
67dbf4ed89SMax Filippov	.align	4
68dbf4ed89SMax Filippov	.global	__nsau_data
69dbf4ed89SMax Filippov	.type	__nsau_data, @object
70dbf4ed89SMax Filippov__nsau_data:
71dbf4ed89SMax Filippov	.byte	8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4
72dbf4ed89SMax Filippov	.byte	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
73dbf4ed89SMax Filippov	.byte	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
74dbf4ed89SMax Filippov	.byte	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
75dbf4ed89SMax Filippov	.byte	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
76dbf4ed89SMax Filippov	.byte	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
77dbf4ed89SMax Filippov	.byte	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
78dbf4ed89SMax Filippov	.byte	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
79dbf4ed89SMax Filippov	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
80dbf4ed89SMax Filippov	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
81dbf4ed89SMax Filippov	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
82dbf4ed89SMax Filippov	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
83dbf4ed89SMax Filippov	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
84dbf4ed89SMax Filippov	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
85dbf4ed89SMax Filippov	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
86dbf4ed89SMax Filippov	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
87dbf4ed89SMax Filippov	.size	__nsau_data, . - __nsau_data
88dbf4ed89SMax Filippov#endif /* !XCHAL_HAVE_NSA */
89