mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-29 16:10:58 +00:00
141 lines
3 KiB
ArmAsm
141 lines
3 KiB
ArmAsm
|
|
||
|
.macro ARM_DIV_BODY dividend, divisor, result, curbit
|
||
|
|
||
|
#if __LINUX_ARM_ARCH__ >= 5
|
||
|
|
||
|
clz \curbit, \divisor
|
||
|
clz \result, \dividend
|
||
|
sub \result, \curbit, \result
|
||
|
mov \curbit, #1
|
||
|
mov \divisor, \divisor, lsl \result
|
||
|
mov \curbit, \curbit, lsl \result
|
||
|
mov \result, #0
|
||
|
|
||
|
#else
|
||
|
|
||
|
@ Initially shift the divisor left 3 bits if possible,
|
||
|
@ set curbit accordingly. This allows for curbit to be located
|
||
|
@ at the left end of each 4 bit nibbles in the division loop
|
||
|
@ to save one loop in most cases.
|
||
|
tst \divisor, #0xe0000000
|
||
|
moveq \divisor, \divisor, lsl #3
|
||
|
moveq \curbit, #8
|
||
|
movne \curbit, #1
|
||
|
|
||
|
@ Unless the divisor is very big, shift it up in multiples of
|
||
|
@ four bits, since this is the amount of unwinding in the main
|
||
|
@ division loop. Continue shifting until the divisor is
|
||
|
@ larger than the dividend.
|
||
|
1: cmp \divisor, #0x10000000
|
||
|
cmplo \divisor, \dividend
|
||
|
movlo \divisor, \divisor, lsl #4
|
||
|
movlo \curbit, \curbit, lsl #4
|
||
|
blo 1b
|
||
|
|
||
|
@ For very big divisors, we must shift it a bit at a time, or
|
||
|
@ we will be in danger of overflowing.
|
||
|
1: cmp \divisor, #0x80000000
|
||
|
cmplo \divisor, \dividend
|
||
|
movlo \divisor, \divisor, lsl #1
|
||
|
movlo \curbit, \curbit, lsl #1
|
||
|
blo 1b
|
||
|
|
||
|
mov \result, #0
|
||
|
|
||
|
#endif
|
||
|
|
||
|
@ Division loop
|
||
|
1: cmp \dividend, \divisor
|
||
|
subhs \dividend, \dividend, \divisor
|
||
|
orrhs \result, \result, \curbit
|
||
|
cmp \dividend, \divisor, lsr #1
|
||
|
subhs \dividend, \dividend, \divisor, lsr #1
|
||
|
orrhs \result, \result, \curbit, lsr #1
|
||
|
cmp \dividend, \divisor, lsr #2
|
||
|
subhs \dividend, \dividend, \divisor, lsr #2
|
||
|
orrhs \result, \result, \curbit, lsr #2
|
||
|
cmp \dividend, \divisor, lsr #3
|
||
|
subhs \dividend, \dividend, \divisor, lsr #3
|
||
|
orrhs \result, \result, \curbit, lsr #3
|
||
|
cmp \dividend, #0 @ Early termination?
|
||
|
movnes \curbit, \curbit, lsr #4 @ No, any more bits to do?
|
||
|
movne \divisor, \divisor, lsr #4
|
||
|
bne 1b
|
||
|
|
||
|
.endm
|
||
|
|
||
|
.macro ARM_DIV2_ORDER divisor, order
|
||
|
|
||
|
#if __LINUX_ARM_ARCH__ >= 5
|
||
|
|
||
|
clz \order, \divisor
|
||
|
rsb \order, \order, #31
|
||
|
|
||
|
#else
|
||
|
|
||
|
cmp \divisor, #(1 << 16)
|
||
|
movhs \divisor, \divisor, lsr #16
|
||
|
movhs \order, #16
|
||
|
movlo \order, #0
|
||
|
|
||
|
cmp \divisor, #(1 << 8)
|
||
|
movhs \divisor, \divisor, lsr #8
|
||
|
addhs \order, \order, #8
|
||
|
|
||
|
cmp \divisor, #(1 << 4)
|
||
|
movhs \divisor, \divisor, lsr #4
|
||
|
addhs \order, \order, #4
|
||
|
|
||
|
cmp \divisor, #(1 << 2)
|
||
|
addhi \order, \order, #3
|
||
|
addls \order, \order, \divisor, lsr #1
|
||
|
|
||
|
#endif
|
||
|
|
||
|
.endm
|
||
|
|
||
|
.align 5
|
||
|
.globl __divsi3
|
||
|
__divsi3:
|
||
|
cmp r1, #0
|
||
|
eor ip, r0, r1 @ save the sign of the result.
|
||
|
beq Ldiv0
|
||
|
rsbmi r1, r1, #0 @ loops below use unsigned.
|
||
|
subs r2, r1, #1 @ division by 1 or -1 ?
|
||
|
beq 10f
|
||
|
movs r3, r0
|
||
|
rsbmi r3, r0, #0 @ positive dividend value
|
||
|
cmp r3, r1
|
||
|
bls 11f
|
||
|
tst r1, r2 @ divisor is power of 2 ?
|
||
|
beq 12f
|
||
|
|
||
|
ARM_DIV_BODY r3, r1, r0, r2
|
||
|
|
||
|
cmp ip, #0
|
||
|
rsbmi r0, r0, #0
|
||
|
mov pc, lr
|
||
|
|
||
|
10: teq ip, r0 @ same sign ?
|
||
|
rsbmi r0, r0, #0
|
||
|
mov pc, lr
|
||
|
|
||
|
11: movlo r0, #0
|
||
|
moveq r0, ip, asr #31
|
||
|
orreq r0, r0, #1
|
||
|
mov pc, lr
|
||
|
|
||
|
12: ARM_DIV2_ORDER r1, r2
|
||
|
|
||
|
cmp ip, #0
|
||
|
mov r0, r3, lsr r2
|
||
|
rsbmi r0, r0, #0
|
||
|
mov pc, lr
|
||
|
|
||
|
Ldiv0:
|
||
|
|
||
|
str lr, [sp, #-4]!
|
||
|
bl __div0
|
||
|
mov r0, #0 @ About as wrong as it could be.
|
||
|
ldr pc, [sp], #4
|