| /* |
| * File: arch/blackfin/lib/divsi3.S |
| * Based on: |
| * Author: |
| * |
| * Created: |
| * Description: 16 / 32 bit signed division. |
| * Special cases : |
| * 1) If(numerator == 0) |
| * return 0 |
| * 2) If(denominator ==0) |
| * return positive max = 0x7fffffff |
| * 3) If(numerator == denominator) |
| * return 1 |
| * 4) If(denominator ==1) |
| * return numerator |
| * 5) If(denominator == -1) |
| * return -numerator |
| * |
| * Operand : R0 - Numerator (i) |
| * R1 - Denominator (i) |
| * R0 - Quotient (o) |
| * Registers Used : R2-R7,P0-P2 |
| * |
| * Modified: |
| * Copyright 2004-2006 Analog Devices Inc. |
| * |
| * Bugs: Enter bugs at http://blackfin.uclinux.org/ |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, see the file COPYING, or write |
| * to the Free Software Foundation, Inc., |
| * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| .global ___divsi3; |
| |
| #ifdef CONFIG_ARITHMETIC_OPS_L1 |
| .section .l1.text |
| #else |
| .text |
| #endif |
| |
| .align 2; |
| ___divsi3 : |
| |
| |
| R3 = R0 ^ R1; |
| R0 = ABS R0; |
| |
| CC = V; |
| |
| r3 = rot r3 by -1; |
| r1 = abs r1; /* now both positive, r3.30 means "negate result", |
| ** r3.31 means overflow, add one to result |
| */ |
| cc = r0 < r1; |
| if cc jump .Lret_zero; |
| r2 = r1 >> 15; |
| cc = r2; |
| if cc jump .Lidents; |
| r2 = r1 << 16; |
| cc = r2 <= r0; |
| if cc jump .Lidents; |
| |
| DIVS(R0, R1); |
| DIVQ(R0, R1); |
| DIVQ(R0, R1); |
| DIVQ(R0, R1); |
| DIVQ(R0, R1); |
| DIVQ(R0, R1); |
| DIVQ(R0, R1); |
| DIVQ(R0, R1); |
| DIVQ(R0, R1); |
| DIVQ(R0, R1); |
| DIVQ(R0, R1); |
| DIVQ(R0, R1); |
| DIVQ(R0, R1); |
| DIVQ(R0, R1); |
| DIVQ(R0, R1); |
| DIVQ(R0, R1); |
| DIVQ(R0, R1); |
| |
| R0 = R0.L (Z); |
| r1 = r3 >> 31; /* add overflow issue back in */ |
| r0 = r0 + r1; |
| r1 = -r0; |
| cc = bittst(r3, 30); |
| if cc r0 = r1; |
| RTS; |
| |
| /* Can't use the primitives. Test common identities. |
| ** If the identity is true, return the value in R2. |
| */ |
| |
| .Lidents: |
| CC = R1 == 0; /* check for divide by zero */ |
| IF CC JUMP .Lident_return; |
| |
| CC = R0 == 0; /* check for division of zero */ |
| IF CC JUMP .Lzero_return; |
| |
| CC = R0 == R1; /* check for identical operands */ |
| IF CC JUMP .Lident_return; |
| |
| CC = R1 == 1; /* check for divide by 1 */ |
| IF CC JUMP .Lident_return; |
| |
| R2.L = ONES R1; |
| R2 = R2.L (Z); |
| CC = R2 == 1; |
| IF CC JUMP .Lpower_of_two; |
| |
| /* Identities haven't helped either. |
| ** Perform the full division process. |
| */ |
| |
| P1 = 31; /* Set loop counter */ |
| |
| [--SP] = (R7:5); /* Push registers R5-R7 */ |
| R2 = -R1; |
| [--SP] = R2; |
| R2 = R0 << 1; /* R2 lsw of dividend */ |
| R6 = R0 ^ R1; /* Get sign */ |
| R5 = R6 >> 31; /* Shift sign to LSB */ |
| |
| R0 = 0 ; /* Clear msw partial remainder */ |
| R2 = R2 | R5; /* Shift quotient bit */ |
| R6 = R0 ^ R1; /* Get new quotient bit */ |
| |
| LSETUP(.Llst,.Llend) LC0 = P1; /* Setup loop */ |
| .Llst: R7 = R2 >> 31; /* record copy of carry from R2 */ |
| R2 = R2 << 1; /* Shift 64 bit dividend up by 1 bit */ |
| R0 = R0 << 1 || R5 = [SP]; |
| R0 = R0 | R7; /* and add carry */ |
| CC = R6 < 0; /* Check quotient(AQ) */ |
| /* we might be subtracting divisor (AQ==0) */ |
| IF CC R5 = R1; /* or we might be adding divisor (AQ==1)*/ |
| R0 = R0 + R5; /* do add or subtract, as indicated by AQ */ |
| R6 = R0 ^ R1; /* Generate next quotient bit */ |
| R5 = R6 >> 31; |
| /* Assume AQ==1, shift in zero */ |
| BITTGL(R5,0); /* tweak AQ to be what we want to shift in */ |
| .Llend: R2 = R2 + R5; /* and then set shifted-in value to |
| ** tweaked AQ. |
| */ |
| r1 = r3 >> 31; |
| r2 = r2 + r1; |
| cc = bittst(r3,30); |
| r0 = -r2; |
| if !cc r0 = r2; |
| SP += 4; |
| (R7:5)= [SP++]; /* Pop registers R6-R7 */ |
| RTS; |
| |
| .Lident_return: |
| CC = R1 == 0; /* check for divide by zero => 0x7fffffff */ |
| R2 = -1 (X); |
| R2 >>= 1; |
| IF CC JUMP .Ltrue_ident_return; |
| |
| CC = R0 == R1; /* check for identical operands => 1 */ |
| R2 = 1 (Z); |
| IF CC JUMP .Ltrue_ident_return; |
| |
| R2 = R0; /* assume divide by 1 => numerator */ |
| /*FALLTHRU*/ |
| |
| .Ltrue_ident_return: |
| R0 = R2; /* Return an identity value */ |
| R2 = -R2; |
| CC = bittst(R3,30); |
| IF CC R0 = R2; |
| .Lzero_return: |
| RTS; /* ...including zero */ |
| |
| .Lpower_of_two: |
| /* Y has a single bit set, which means it's a power of two. |
| ** That means we can perform the division just by shifting |
| ** X to the right the appropriate number of bits |
| */ |
| |
| /* signbits returns the number of sign bits, minus one. |
| ** 1=>30, 2=>29, ..., 0x40000000=>0. Which means we need |
| ** to shift right n-signbits spaces. It also means 0x80000000 |
| ** is a special case, because that *also* gives a signbits of 0 |
| */ |
| |
| R2 = R0 >> 31; |
| CC = R1 < 0; |
| IF CC JUMP .Ltrue_ident_return; |
| |
| R1.l = SIGNBITS R1; |
| R1 = R1.L (Z); |
| R1 += -30; |
| R0 = LSHIFT R0 by R1.L; |
| r1 = r3 >> 31; |
| r0 = r0 + r1; |
| R2 = -R0; // negate result if necessary |
| CC = bittst(R3,30); |
| IF CC R0 = R2; |
| RTS; |
| |
| .Lret_zero: |
| R0 = 0; |
| RTS; |