EmbeddedRelated.com
Forums
Memfault Beyond the Launch

64-bit integer division problem in CrossWorks(r) for ARM

Started by John Doe March 10, 2005
Hi!
CrossWorks(c) for ARM has problem with 64-bit integer division when
one or both operands have value exceeds 32-bit capacity. This is
code below to work around.

Does somebody knows this is CrossWorks ARM library problem only
or also GCC ARM library has it ???

Regards,
John Doe

<pre>

/* C-wrapper */
long long y_64div(long long a,long long b)
{
y_div64();
return b;
}
/* GCC ASM code - derived from ARM(c) macros */
.text
.code 32
.align 4
.global y_div64

y_div64:
STMFD SP!,{R0,R1,R2,R3,R6-R11,R12,LR}
ANDS R9, R3, #1<<31 // get sign of d
BPL L_00
RSBS R2, R2, #0 // ensure d +ve
RSC R3, R3, #0
L_00:
EORS R9, R9, R1, ASR#32 // b31=result b30=sign of n
BCC L_01
RSBS R0, R0, #0 // ensure n +ve
RSC R1, R1, #0
L_01:
BL y_divu64
MOVS R9, R9, LSL#1 // get out sign bits
BCC L_02
RSBS R2, R2, #0
RSC R3, R3, #0
L_02:
MOVS R9, R9, LSL#1
BCC L_03
L_03:
MOV R4, R2
MOV R5, R3
LDMFD SP!,{R0,R1,R2,R3,R6-R11,R12,LR}
BX LR
//-----------------------------------
y_divu64:
STMDB SP!, {R4,R5,R6,R7,R8}
MOV R4,#0 /* zero the quotient */
MOV R5,#0
MOV R7,R1 /* set the remainder to the current value */
MOV R6,R0
ORRS R8, R2, R3
BEQ LU_08 /* divide by 0 */
MOVS R8,#0 /* count number of shifts */
/* first loop gets $d as large as possible */
LU_00:
ADDS R2, R2, R2
ADCS R3, R3, R3 /* double d */
BCS LU_01 /* overflowed */
CMP R3, R7
CMPEQ R2, R6
ADDLS R8, R8, #1 /* done an extra shift */
BLS LU_00
ADDS R8, R8, #0 /* clear carry */
LU_01: /* carry the overflow here */
MOVS R3, R3, RRX /* colour */
MOV R2, R2, RRX /* shift back down again */
LU_02:
SUBS R0, R6, R2
SBCS R1, R7, R3 /* n = r - d and C set if r>=d */
MOVCS R7, R1
MOVCS R6, R0 /* r=r-d if this goes */
ADCS R4, R4, R4
ADC R5, R5, R5 /* shift next bit into the answer */
MOVS R3, R3, LSR#1
MOV R2, R2, RRX /* shift down d */
SUBS R8, R8, #1
BGE LU_02 /* do next loop (t+1) loops */
LU_08:
MOV R2, R4
MOV R3, R5
MOV R0, R6
MOV R1, R7
LDMIA SP!, {R4,R5,R6,R7,R8}
BX LR
</pre ---------------------------------


An Engineer's Guide to the LPC2100 Series


Hi,

Which version of CrossWorks for ARM are you using? You can use "Help |
About CrossStudio" to determine the version and build number.

I can't reproduce the problem, so can you provide some source code
that demonstrates the problem you are seeing?

Regards,

Jon Elliott
Rowley Associates Ltd

--- In , John Doe <ytremil@y...> wrote:
> Hi!
> CrossWorks(c) for ARM has problem with 64-bit integer division when
> one or both operands have value exceeds 32-bit capacity. This is
> code below to work around.
>
> Does somebody knows this is CrossWorks ARM library problem only
> or also GCC ARM library has it ???
>
> Regards,
> John Doe
>
> <pre>
>
> /* C-wrapper */
> long long y_64div(long long a,long long b)
> {
> y_div64();
> return b;
> }
> /* GCC ASM code - derived from ARM(c) macros */
> .text
> .code 32
> .align 4
> .global y_div64
>
> y_div64:
> STMFD SP!,{R0,R1,R2,R3,R6-R11,R12,LR}
> ANDS R9, R3, #1<<31 // get sign of d
> BPL L_00
> RSBS R2, R2, #0 // ensure d +ve
> RSC R3, R3, #0
> L_00:
> EORS R9, R9, R1, ASR#32 // b31=result
b30=sign of n
> BCC L_01
> RSBS R0, R0, #0 // ensure n +ve
> RSC R1, R1, #0
> L_01:
> BL y_divu64
> MOVS R9, R9, LSL#1 // get out sign bits
> BCC L_02
> RSBS R2, R2, #0
> RSC R3, R3, #0
> L_02:
> MOVS R9, R9, LSL#1
> BCC L_03
> L_03:
> MOV R4, R2
> MOV R5, R3
> LDMFD SP!,{R0,R1,R2,R3,R6-R11,R12,LR}
> BX LR
>
//-----------------------------------
> y_divu64:
> STMDB SP!, {R4,R5,R6,R7,R8}
> MOV R4,#0 /* zero the quotient */
> MOV R5,#0
> MOV R7,R1 /* set the remainder to the
current value */
> MOV R6,R0
> ORRS R8, R2, R3
> BEQ LU_08 /* divide by 0 */
> MOVS R8,#0 /* count number of shifts */
> /* first loop gets $d as large as possible */
> LU_00:
> ADDS R2, R2, R2
> ADCS R3, R3, R3 /* double d */
> BCS LU_01 /* overflowed */
> CMP R3, R7
> CMPEQ R2, R6
> ADDLS R8, R8, #1 /* done an extra shift */
> BLS LU_00
> ADDS R8, R8, #0 /* clear carry */
> LU_01: /* carry the overflow here */
> MOVS R3, R3, RRX /* colour */
> MOV R2, R2, RRX /* shift back down again */
> LU_02:
> SUBS R0, R6, R2
> SBCS R1, R7, R3 /* n = r - d and C set if r>=d */
> MOVCS R7, R1
> MOVCS R6, R0 /* r=r-d if this goes */
> ADCS R4, R4, R4
> ADC R5, R5, R5 /* shift next bit into the
answer */
> MOVS R3, R3, LSR#1
> MOV R2, R2, RRX /* shift down d */
> SUBS R8, R8, #1
> BGE LU_02 /* do next loop (t+1) loops */
> LU_08:
> MOV R2, R4
> MOV R3, R5
> MOV R0, R6
> MOV R1, R7
> LDMIA SP!, {R4,R5,R6,R7,R8}
> BX LR
> </pre > ---------------------------------
>




--- In , "moruisg" <je@r...> wrote:
>
> Hi,
>
> Which version of CrossWorks for ARM are you using? You can
use "Help |
> About CrossStudio" to determine the version and build number.
>
> I can't reproduce the problem, so can you provide some source code
> that demonstrates the problem you are seeing?
>
> Regards,
>
> Jon Elliott
> Rowley Associates Ltd
>

Hi,

This is a simple example:

long long a = 1767040273612800LL;
long long b = 2365440384LL;
long long c;

int main(void)
{
c = a/b;
return 0;
}

After division, "c" has value 747009,but correct result - 747023.

Another few numbers:

1767020750438400 / 2365439945 = 747015,
but CrossWorks give 747008;

1767001050316800 / 2365438870 = 747007,
but CrossWorks give 746528 (!)

My CrossStudio(r) current version - 1.3 Build 5
(with ver. 1.2 - the same problem)

In LPC2106,S3C44B0X,ARM Simulator - the same problem. Regards,

Yuri Tiomkin,
http://www.tnkernel.com




Memfault Beyond the Launch