/*1* Copyright 2004-2009 Analog Devices Inc.2*3* Licensed under the ADI BSD license or the GPL-2 (or later)4*5* 16 / 32 bit signed division.6* Special cases :7* 1) If(numerator == 0)8* return 09* 2) If(denominator ==0)10* return positive max = 0x7fffffff11* 3) If(numerator == denominator)12* return 113* 4) If(denominator ==1)14* return numerator15* 5) If(denominator == -1)16* return -numerator17*18* Operand : R0 - Numerator (i)19* R1 - Denominator (i)20* R0 - Quotient (o)21* Registers Used : R2-R7,P0-P222*23*/2425.global ___divsi3;26.type ___divsi3, STT_FUNC;2728#ifdef CONFIG_ARITHMETIC_OPS_L129.section .l1.text30#else31.text32#endif3334.align 2;35___divsi3 :363738R3 = R0 ^ R1;39R0 = ABS R0;4041CC = V;4243r3 = rot r3 by -1;44r1 = abs r1; /* now both positive, r3.30 means "negate result",45** r3.31 means overflow, add one to result46*/47cc = r0 < r1;48if cc jump .Lret_zero;49r2 = r1 >> 15;50cc = r2;51if cc jump .Lidents;52r2 = r1 << 16;53cc = r2 <= r0;54if cc jump .Lidents;5556DIVS(R0, R1);57DIVQ(R0, R1);58DIVQ(R0, R1);59DIVQ(R0, R1);60DIVQ(R0, R1);61DIVQ(R0, R1);62DIVQ(R0, R1);63DIVQ(R0, R1);64DIVQ(R0, R1);65DIVQ(R0, R1);66DIVQ(R0, R1);67DIVQ(R0, R1);68DIVQ(R0, R1);69DIVQ(R0, R1);70DIVQ(R0, R1);71DIVQ(R0, R1);72DIVQ(R0, R1);7374R0 = R0.L (Z);75r1 = r3 >> 31; /* add overflow issue back in */76r0 = r0 + r1;77r1 = -r0;78cc = bittst(r3, 30);79if cc r0 = r1;80RTS;8182/* Can't use the primitives. Test common identities.83** If the identity is true, return the value in R2.84*/8586.Lidents:87CC = R1 == 0; /* check for divide by zero */88IF CC JUMP .Lident_return;8990CC = R0 == 0; /* check for division of zero */91IF CC JUMP .Lzero_return;9293CC = R0 == R1; /* check for identical operands */94IF CC JUMP .Lident_return;9596CC = R1 == 1; /* check for divide by 1 */97IF CC JUMP .Lident_return;9899R2.L = ONES R1;100R2 = R2.L (Z);101CC = R2 == 1;102IF CC JUMP .Lpower_of_two;103104/* Identities haven't helped either.105** Perform the full division process.106*/107108P1 = 31; /* Set loop counter */109110[--SP] = (R7:5); /* Push registers R5-R7 */111R2 = -R1;112[--SP] = R2;113R2 = R0 << 1; /* R2 lsw of dividend */114R6 = R0 ^ R1; /* Get sign */115R5 = R6 >> 31; /* Shift sign to LSB */116117R0 = 0 ; /* Clear msw partial remainder */118R2 = R2 | R5; /* Shift quotient bit */119R6 = R0 ^ R1; /* Get new quotient bit */120121LSETUP(.Llst,.Llend) LC0 = P1; /* Setup loop */122.Llst: R7 = R2 >> 31; /* record copy of carry from R2 */123R2 = R2 << 1; /* Shift 64 bit dividend up by 1 bit */124R0 = R0 << 1 || R5 = [SP];125R0 = R0 | R7; /* and add carry */126CC = R6 < 0; /* Check quotient(AQ) */127/* we might be subtracting divisor (AQ==0) */128IF CC R5 = R1; /* or we might be adding divisor (AQ==1)*/129R0 = R0 + R5; /* do add or subtract, as indicated by AQ */130R6 = R0 ^ R1; /* Generate next quotient bit */131R5 = R6 >> 31;132/* Assume AQ==1, shift in zero */133BITTGL(R5,0); /* tweak AQ to be what we want to shift in */134.Llend: R2 = R2 + R5; /* and then set shifted-in value to135** tweaked AQ.136*/137r1 = r3 >> 31;138r2 = r2 + r1;139cc = bittst(r3,30);140r0 = -r2;141if !cc r0 = r2;142SP += 4;143(R7:5)= [SP++]; /* Pop registers R6-R7 */144RTS;145146.Lident_return:147CC = R1 == 0; /* check for divide by zero => 0x7fffffff */148R2 = -1 (X);149R2 >>= 1;150IF CC JUMP .Ltrue_ident_return;151152CC = R0 == R1; /* check for identical operands => 1 */153R2 = 1 (Z);154IF CC JUMP .Ltrue_ident_return;155156R2 = R0; /* assume divide by 1 => numerator */157/*FALLTHRU*/158159.Ltrue_ident_return:160R0 = R2; /* Return an identity value */161R2 = -R2;162CC = bittst(R3,30);163IF CC R0 = R2;164.Lzero_return:165RTS; /* ...including zero */166167.Lpower_of_two:168/* Y has a single bit set, which means it's a power of two.169** That means we can perform the division just by shifting170** X to the right the appropriate number of bits171*/172173/* signbits returns the number of sign bits, minus one.174** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need175** to shift right n-signbits spaces. It also means 0x80000000176** is a special case, because that *also* gives a signbits of 0177*/178179R2 = R0 >> 31;180CC = R1 < 0;181IF CC JUMP .Ltrue_ident_return;182183R1.l = SIGNBITS R1;184R1 = R1.L (Z);185R1 += -30;186R0 = LSHIFT R0 by R1.L;187r1 = r3 >> 31;188r0 = r0 + r1;189R2 = -R0; // negate result if necessary190CC = bittst(R3,30);191IF CC R0 = R2;192RTS;193194.Lret_zero:195R0 = 0;196RTS;197198.size ___divsi3, .-___divsi3199200201