162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later WITH GCC-exception-2.0 */
262306a36Sopenharmony_ci#include <linux/linkage.h>
362306a36Sopenharmony_ci#include <asm/asmmacro.h>
462306a36Sopenharmony_ci#include <asm/core.h>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ciENTRY(__modsi3)
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci	abi_entry_default
962306a36Sopenharmony_ci#if XCHAL_HAVE_DIV32
1062306a36Sopenharmony_ci	rems	a2, a2, a3
1162306a36Sopenharmony_ci#else
1262306a36Sopenharmony_ci	mov	a7, a2		/* save original (signed) dividend */
1362306a36Sopenharmony_ci	do_abs	a2, a2, a4	/* udividend = abs (dividend) */
1462306a36Sopenharmony_ci	do_abs	a3, a3, a4	/* udivisor = abs (divisor) */
1562306a36Sopenharmony_ci	bltui	a3, 2, .Lle_one	/* check if udivisor <= 1 */
1662306a36Sopenharmony_ci	do_nsau	a5, a2, a6, a8	/* udividend_shift = nsau (udividend) */
1762306a36Sopenharmony_ci	do_nsau	a4, a3, a6, a8	/* udivisor_shift = nsau (udivisor) */
1862306a36Sopenharmony_ci	bgeu	a5, a4, .Lspecial
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci	sub	a4, a4, a5	/* count = udivisor_shift - udividend_shift */
2162306a36Sopenharmony_ci	ssl	a4
2262306a36Sopenharmony_ci	sll	a3, a3		/* udivisor <<= count */
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	/* test-subtract-and-shift loop */
2562306a36Sopenharmony_ci#if XCHAL_HAVE_LOOPS
2662306a36Sopenharmony_ci	loopnez	a4, .Lloopend
2762306a36Sopenharmony_ci#endif /* XCHAL_HAVE_LOOPS */
2862306a36Sopenharmony_ci.Lloop:
2962306a36Sopenharmony_ci	bltu	a2, a3, .Lzerobit
3062306a36Sopenharmony_ci	sub	a2, a2, a3
3162306a36Sopenharmony_ci.Lzerobit:
3262306a36Sopenharmony_ci	srli	a3, a3, 1
3362306a36Sopenharmony_ci#if !XCHAL_HAVE_LOOPS
3462306a36Sopenharmony_ci	addi	a4, a4, -1
3562306a36Sopenharmony_ci	bnez	a4, .Lloop
3662306a36Sopenharmony_ci#endif /* !XCHAL_HAVE_LOOPS */
3762306a36Sopenharmony_ci.Lloopend:
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci.Lspecial:
4062306a36Sopenharmony_ci	bltu	a2, a3, .Lreturn
4162306a36Sopenharmony_ci	sub	a2, a2, a3	/* subtract again if udividend >= udivisor */
4262306a36Sopenharmony_ci.Lreturn:
4362306a36Sopenharmony_ci	bgez	a7, .Lpositive
4462306a36Sopenharmony_ci	neg	a2, a2		/* if (dividend < 0), return -udividend */
4562306a36Sopenharmony_ci.Lpositive:
4662306a36Sopenharmony_ci	abi_ret_default
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci.Lle_one:
4962306a36Sopenharmony_ci	bnez	a3, .Lreturn0
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	/* Divide by zero: Use an illegal instruction to force an exception.
5262306a36Sopenharmony_ci	   The subsequent "DIV0" string can be recognized by the exception
5362306a36Sopenharmony_ci	   handler to identify the real cause of the exception.  */
5462306a36Sopenharmony_ci	ill
5562306a36Sopenharmony_ci	.ascii	"DIV0"
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci.Lreturn0:
5862306a36Sopenharmony_ci	movi	a2, 0
5962306a36Sopenharmony_ci#endif /* XCHAL_HAVE_DIV32 */
6062306a36Sopenharmony_ci	abi_ret_default
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ciENDPROC(__modsi3)
6362306a36Sopenharmony_ciEXPORT_SYMBOL(__modsi3)
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci#if !XCHAL_HAVE_NSA
6662306a36Sopenharmony_ci	.section .rodata
6762306a36Sopenharmony_ci	.align	4
6862306a36Sopenharmony_ci	.global	__nsau_data
6962306a36Sopenharmony_ci	.type	__nsau_data, @object
7062306a36Sopenharmony_ci__nsau_data:
7162306a36Sopenharmony_ci	.byte	8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4
7262306a36Sopenharmony_ci	.byte	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
7362306a36Sopenharmony_ci	.byte	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
7462306a36Sopenharmony_ci	.byte	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2
7562306a36Sopenharmony_ci	.byte	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
7662306a36Sopenharmony_ci	.byte	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
7762306a36Sopenharmony_ci	.byte	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
7862306a36Sopenharmony_ci	.byte	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
7962306a36Sopenharmony_ci	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
8062306a36Sopenharmony_ci	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
8162306a36Sopenharmony_ci	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
8262306a36Sopenharmony_ci	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
8362306a36Sopenharmony_ci	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
8462306a36Sopenharmony_ci	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
8562306a36Sopenharmony_ci	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
8662306a36Sopenharmony_ci	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
8762306a36Sopenharmony_ci	.size	__nsau_data, . - __nsau_data
8862306a36Sopenharmony_ci#endif /* !XCHAL_HAVE_NSA */
89