Kernel/armv7 - Moved to asssembly 32-bit divide
authorJohn Hodge <[email protected]>
Thu, 20 Oct 2011 23:37:54 +0000 (07:37 +0800)
committerJohn Hodge <[email protected]>
Thu, 20 Oct 2011 23:37:54 +0000 (07:37 +0800)
Kernel/arch/armv7/lib.S
Kernel/arch/armv7/lib.c

index d37c4a1..e2f0613 100644 (file)
@@ -42,3 +42,43 @@ __memcpy_align4:
 
 3:     pop {r4}
        mov pc, lr
+
+@
+@ Division
+@
+.globl __divmod32_asm
+__divmod32_asm:
+       push {r4}
+       mov r4, #0      @ Return value
+       mov r3, #1      @ add value
+
+       @ Scan up for first larger multiple of 2
+1:     cmp r0, r1      @ N < D
+       bmi 2f          @ ^^
+       lsl r1, r1, #1  @ D <<= 1
+       lsls r3, r3, #1 @ add <<= 1
+       beq .err        @ result is zero
+       b 1b
+       
+       @ Go back down
+2:     lsrs r3, r3, #1 @ add >>= 1
+       beq 3f          @ Done (value is zero)
+       lsr r1, r1, #1  @ D >>= 1
+       cmp r0, r1      @ N < D
+       bmi 2b
+       sub r0, r1      @ N -= D
+       add r4, r3      @ ret += add
+       b 2b
+3:
+       tst r2, r2      @ Remainder (if wanted)
+       strne r0,[r2]
+       mov r0, r4      @ Return value
+       pop {r4}
+       mov pc, lr
+.err:
+       mov r0, #0
+       tst r2, r2
+       strne r0, [r2]
+       pop {r4}
+       mov pc, lr
+
index c0feab6..a1fbfb7 100644 (file)
@@ -8,6 +8,7 @@
 // === IMPORTS ===
 extern void    __memcpy_align4(void *_dest, const void *_src, size_t _length);
 extern void    __memcpy_byte(void *_dest, const void *_src, size_t _length);
+extern Uint32  __divmod32_asm(Uint32 Num, Uint32 Den, Uint32 *Rem);
 
 // === PROTOTYPES ===
 Uint64 __divmod64(Uint64 Num, Uint64 Den, Uint64 *Rem);
@@ -41,7 +42,7 @@ void *memcpy(void *_dest, const void *_src, size_t _length)
        // Force alignment
        while( (tVAddr)dst8 & 3 ) *dst8 ++ = *src8++, _length --;
 
-       __memcpy_align32(dst8, src8, _length);
+       __memcpy_align4(dst8, src8, _length);
        
        return _dest;
 }
@@ -136,6 +137,10 @@ Uint64 DivMod64U(Uint64 Num, Uint64 Den, Uint64 *Rem)
 {
        Uint64  ret;
        if(Den == 0)    return 0;       // TODO: #div0
+       if(Num < Den) {
+               if(Rem) *Rem = Num;
+               return 0;
+       }
        if(Num == 0) {
                if(Rem) *Rem = 0;
                return 0;
@@ -160,6 +165,11 @@ Uint64 DivMod64U(Uint64 Num, Uint64 Den, Uint64 *Rem)
                if(Rem) *Rem = Num & 0xFFF;
                return Num >> 12;
        }
+       
+       if( !(Den >> 32) && !(Num >> 32) ) {
+               if(Rem) *Rem = 0;       // Clear high bits
+               return __divmod32_asm(Num, Den, (Uint32*)Rem);
+       }
 
        ret = __divmod64(Num, Den, Rem);
        return ret;
@@ -181,13 +191,13 @@ Uint64 __umoddi3(Uint64 Num, Uint64 Den)
 
 Uint32 __udivsi3(Uint32 Num, Uint32 Den)
 {
-       return __divmod32(Num, Den, NULL);
+       return __divmod32_asm(Num, Den, NULL);
 }
 
 Uint32 __umodsi3(Uint32 Num, Uint32 Den)
 {
        Uint32  rem;
-       __divmod32(Num, Den, &rem);
+       __divmod32_asm(Num, Den, &rem);
        return rem;
 }
 

UCC git Repository :: git.ucc.asn.au