nest-open-source / nest-learning-thermostat / 5.0 / x-loader / refs/heads/master / . / x-loader / lib / _modsi3.S

.macro ARM_MOD_BODY dividend, divisor, order, spare | |

#if __LINUX_ARM_ARCH__ >= 5 | |

clz \order, \divisor | |

clz \spare, \dividend | |

sub \order, \order, \spare | |

mov \divisor, \divisor, lsl \order | |

#else | |

mov \order, #0 | |

@ 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 | |

addlo \order, \order, #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 | |

addlo \order, \order, #1 | |

blo 1b | |

#endif | |

@ Perform all needed substractions to keep only the reminder. | |

@ Do comparisons in batch of 4 first. | |

subs \order, \order, #3 @ yes, 3 is intended here | |

blt 2f | |

1: cmp \dividend, \divisor | |

subhs \dividend, \dividend, \divisor | |

cmp \dividend, \divisor, lsr #1 | |

subhs \dividend, \dividend, \divisor, lsr #1 | |

cmp \dividend, \divisor, lsr #2 | |

subhs \dividend, \dividend, \divisor, lsr #2 | |

cmp \dividend, \divisor, lsr #3 | |

subhs \dividend, \dividend, \divisor, lsr #3 | |

cmp \dividend, #1 | |

mov \divisor, \divisor, lsr #4 | |

subges \order, \order, #4 | |

bge 1b | |

tst \order, #3 | |

teqne \dividend, #0 | |

beq 5f | |

@ Either 1, 2 or 3 comparison/substractions are left. | |

2: cmn \order, #2 | |

blt 4f | |

beq 3f | |

cmp \dividend, \divisor | |

subhs \dividend, \dividend, \divisor | |

mov \divisor, \divisor, lsr #1 | |

3: cmp \dividend, \divisor | |

subhs \dividend, \dividend, \divisor | |

mov \divisor, \divisor, lsr #1 | |

4: cmp \dividend, \divisor | |

subhs \dividend, \dividend, \divisor | |

5: | |

.endm | |

.align 5 | |

.globl __modsi3 | |

__modsi3: | |

cmp r1, #0 | |

beq Ldiv0 | |

rsbmi r1, r1, #0 @ loops below use unsigned. | |

movs ip, r0 @ preserve sign of dividend | |

rsbmi r0, r0, #0 @ if negative make positive | |

subs r2, r1, #1 @ compare divisor with 1 | |

cmpne r0, r1 @ compare dividend with divisor | |

moveq r0, #0 | |

tsthi r1, r2 @ see if divisor is power of 2 | |

andeq r0, r0, r2 | |

bls 10f | |

ARM_MOD_BODY r0, r1, r2, r3 | |

10: cmp ip, #0 | |

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 |