diff options
author | Rob Barnes <robbarnes@google.com> | 2022-07-27 18:57:07 +0000 |
---|---|---|
committer | Martin L Roth <gaumless@gmail.com> | 2022-08-13 17:20:32 +0000 |
commit | f6bb293f1c2ed33f09159a5e0b094e81576ef7f3 (patch) | |
tree | 5df9a923571495be99201347970e1b62dc861fa1 /src/arch/arm/libgcc/ldivmod.S | |
parent | b11f9f7e162759cf5ae0f033e125e9158520030d (diff) |
arm/libgcc: Support signed 64-bit division
Add support for signed 64-bit division. The implementation mostly
relies on __aeabi_uldivmod, which is already implemented.
ldivmod.S was adapted from CrOS EC version of ldivmod.S:
https://chromium.googlesource.com/chromiumos/platform/ec/+/main/third_party/libaeabi-cortexm0/core/cortex-m0/ldivmod.S
The CrOS EC version was adapted from:
https://github.com/bobbl/libaeabi-cortexm0/blob/master/ldivmod.S
BUG=b:240316722
BRANCH=None
TEST=Signed division works in PSP verstage (runs on ARM)
Change-Id: I53785c732b0fa35a4809bc054f1482c5461ada7b
Signed-off-by: Rob Barnes <robbarnes@google.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/66207
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
Reviewed-by: Tim Van Patten <timvp@google.com>
Diffstat (limited to 'src/arch/arm/libgcc/ldivmod.S')
-rw-r--r-- | src/arch/arm/libgcc/ldivmod.S | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/src/arch/arm/libgcc/ldivmod.S b/src/arch/arm/libgcc/ldivmod.S new file mode 100644 index 0000000000..39b89434cd --- /dev/null +++ b/src/arch/arm/libgcc/ldivmod.S @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: ISC OR GPL-2.0-only */ + +/* + * ldivmod.S: signed 64 bit division (quotient and remainder) + * + * Taken from CrOS EC: third_party/libaeabi-cortexm0/core/cortex-m0/ldivmod.S + */ + +#include <arch/asm.h> + + +@ {long long quotient, long long remainder} +@ __aeabi_ldivmod(long long numerator, long long denominator) +@ +@ Divide r1:r0 by r3:r2 and return the quotient in r1:r0 and the remainder in +@ r3:r2 (all signed) +@ + +ENTRY(__aeabi_ldivmod) + + cmp r1, #0 + bge L_num_pos + + push {r4, lr} + movs r4, #0 @ num = -num + rsbs r0, r0, #0 + sbcs r4, r1 + mov r1, r4 + + cmp r3, #0 + bge L_neg_both + + movs r4, #0 @ den = -den + rsbs r2, r2, #0 + sbcs r4, r3 + mov r3, r4 + bl __aeabi_uldivmod + movs r4, #0 @ rem = -rem + rsbs r2, r2, #0 + sbcs r4, r3 + mov r3, r4 + pop {r4, pc} + +L_neg_both: + bl __aeabi_uldivmod + movs r4, #0 @ quot = -quot + rsbs r0, r0, #0 + sbcs r4, r1 + mov r1, r4 + movs r4, #0 @ rem = -rem + rsbs r2, r2, #0 + sbcs r4, r3 + mov r3, r4 + pop {r4, pc} + +L_num_pos: + cmp r3, #0 + blt L_den_neg + push {r4, lr} + bl __aeabi_uldivmod @ offset too big for b / bge + pop {r4, pc} + +L_den_neg: + push {r4, lr} + movs r4, #0 @ den = -den + rsbs r2, r2, #0 + sbcs r4, r3 + mov r3, r4 + bl __aeabi_uldivmod + movs r4, #0 @ quot = -quot + rsbs r0, r0, #0 + sbcs r4, r1 + mov r1, r4 + pop {r4, pc} |