ocaml/otherlibs/num/bignum/s/i960KerN.s

929 lines
15 KiB
ArmAsm

/*
** (c) Copyright 1989 Digital Equipment Corporation
**
** Last modified_on Mon Apr 9 20:18:11 GMT+2:00 1990 by shand
** modified_on Tue Apr 3 19:48:27 GMT+2:00 1990 by sills@notok.enet.dec.com
**
** KerN for 80960KA
**
** Author: Glenn Sills
** Date: 1.1
** Version: 1
**
*/
/*
** BnnSetToZero(nn, nl)
** BigNum nn;
** int nl;
**
** Set all of the digits specified by nn length nl to zero
**
** nn -> g0
** nl -> g1
*/
.file "kern.s"
.text
.align 2
.globl _BnnSetToZero
.leafproc _BnnSetToZero
_BnnSetToZero:
mov g14,g7 /* Preserve the return address */
ldconst 0,g14 /* Must always load g14 with 0 for*/
/* branch and link procs */
cmpobe 0,g1,.bstzxt /* if (!nl) return */
subo 1,g1,g1
shlo 2,g1,g1 /* Do some pointer arithmetic */
addc g0,g1,g1 /* nl = nn + nl*byte_per_digit */
/* (I happen to know that */
/* bytes_per_digit is 4 on 960 */
.bstzlp: /* Do { */
ldconst 0,g3
st g3,(g0) /* *nn = 0 */
addc 4,g0,g0 /* } while (++nn <= nl) */
cmpoble g0,g1,.bstzlp
.bstzxt:
bx (g7) /* Return voidly */
/*
** void BnnAssign(mm, nn, nl)
** Bignum mm, nn;
** int nl;
**
** Copies nn to mm. We copy from back to front to defend against
** over lapping bignums.
**
** mm -> g0
** nn -> g1
** nl -> g2
*/
.globl _BnnAssign
.leafproc _BnnAssign
_BnnAssign:
mov g14,g7 /* Mandatory saving of g14 */
cmpo 0,g2
mov 0,g14
be .baexit
subo 1,g2,g2 /* Prepare for some pointer */
cmpo g0,g1
shlo 2,g2,g2 /* Arithmetic */
be .baexit /* if (mm == nn) exit */
/* if (mm >> nn) */
bg .balast1 /* then */
/* Copy from last to first */
addo g2,g1,g2
.ba1last:
ld (g1),g3
addo 4,g1,g1 /* *mm++ == *nn++ */
st g3,(g0)
addo 4,g0,g0
cmpo g1,g2
ble .ba1last /* while (nl > 0) */
bx (g7)
.balast1:
mov g1,g4
addo g2,g0,g0
addo g2,g1,g1 /* nn += nl */
.baloop:
ld (g1),g3
subo 4,g1,g1 /* *mm-- == *nn-- */
st g3,(g0)
subo 4,g0,g0
cmpo g1,g4
bge .baloop
.baexit:
bx (g7) /* Return voidly */
/*
** void BnnSetDigit(nn,d)
** BigNum nn;
** int d;
**
** Sets a single digit of N to the passed value
**
** g0 -> nn
** g1 -> d
**
*/
.globl _BnnSetDigit
.leafproc _BnnSetDigit
.align 2
_BnnSetDigit:
mov g14,g7 /* Mandatory saving of g14 */
ldconst 0,g14
st g1,(g0) /* *nn = d */
bx (g7) /* Return ustedes */
/*
** BigNumDigit BnnGetDigit (nn)
** BigNum nn;
**
** Returns digit pointed to by nn
**
** g0 -> nn
*/
.globl _BnnGetDigit
.leafproc _BnnGetDigit
.align 2
_BnnGetDigit:
mov g14,g7
ldconst 0,g14
ld (g0),g0
bx (g7)
/*
** BigNumLength BnnNumDigits(nn, nl)
** Bignum nn;
** int nl;
**
** Returns the total number of digits in nn not counting leading
** zeros.
**
** g0 -> nn
** g1 -> nl
**
*/
.globl _BnnNumDigits
.leafproc _BnnNumDigits
_BnnNumDigits:
mov g14,g7
ldconst 0,g14
.bndnot0:
subo 1,g1,g2
shlo 2,g2,g2
addo g0,g2,g0
.bndloop:
cmpobe 0,g1,.bndret1 /* while (nl && *nn == 0) */
ld (g0),g3
cmpobne 0,g3,.bndrett /* --nl; */
subo 4,g0,g0
subo 1,g1,g1
b .bndloop
.bndret1:
ldconst 1,g0 /* If nl == 0 return 1 */
bx (g7)
.bndrett:
mov g1,g0
bx (g7)
/*
** BigNumDigit BnnNumLeadingZeroBitsInDigit(d)
** BigNumDigit d;
**
** How many leading zero bits are there in the digit? HUH???
**
** g0 -> d;
**
*/
.globl _BnnNumLeadingZeroBitsInDigit
.leafproc _BnnNumLeadingZeroBitsInDigit
_BnnNumLeadingZeroBitsInDigit:
mov g14,g7
ldconst 0,g14
scanbit g0, g1
bo .bzidnz
ldconst 32,g0
bx (g7)
.bzidnz:
subo g1,31,g0
bx (g7)
/*
** Boolean BnnDoesDigitFitInWord(d)
** BigNumDigit d;
**
** Returns true if the digit d can fit in BNN_WORD_SIZE bits.
** On the 80960, it always can.
**
** g0 -> d
*/
.globl _BnnDoesDigitFitInWord
.leafproc _BnnDoesDigitFitInWord
_BnnDoesDigitFitInWord:
mov g14,g7
ldconst 0,g14
ldconst 1,g0
bx (g7)
/*
** Boolean BnnIsDigitZero (d)
** BigNumDigit d;
**
** Returns TRUE iff digit = 0. We can do this!
**
**
** g0 -> d
**
*/
.globl _BnnIsDigitZero
.leafproc _BnnIsDigitZero
_BnnIsDigitZero:
mov g14,g7
ldconst 0,g14
cmpobne 0,g0, .bidz1
ldconst 1,g0
bx (g7)
.bidz1:
ldconst 0,g0
bx (g7)
/*
** Boolean BnnIsDigitNormalized (d)
** BigNumDigit d
**
** Returns TRUE iff Base/2 <= digit < Base
** i.e., if digit's leading bit is 1
**
** g0 -> d
*/
.globl _BnnIsDigitNormalized
.leafproc _BnnIsDigitNormalized
_BnnIsDigitNormalized:
mov g14,g7
ldconst 0,g14
scanbit g0,g0
cmpobe 31,g0,.bidnt
ldconst 0,g0
bx (g7)
.bidnt:
ldconst 1,g0
bx (g7)
/*
** Boolean BnnIsDigitOdd (d)
** BigNumDigit d;
**
** Returns TRUE iff digit is odd
**
** g0 -> d
*/
.globl _BnnIsDigitOdd
.leafproc _BnnIsDigitOdd
_BnnIsDigitOdd:
mov g14,g7
ldconst 0, g14
and 1, g0, g0
bx (g7)
/*
** BigNumCmp BnnCompareDigits (d1, d2)
** BigNumDigit d1, d2
**
** Compares digits and returns
**
** BNN_GREATER d1 > d2
** BNN_EQUAL d1 == d2
** BNN_LESS d1 < d2
**
** g0 -> d1
** g1 -> d2
*/
.globl _BnnCompareDigits
.leafproc _BnnCompareDigits
_BnnCompareDigits:
mov g14,g7
ldconst 0,g14
cmpobe g0,g1,.bcdequal
bg .bcdgreater
ldconst -1,g0 /* BNN_LESS */
bx (g7)
.bcdequal:
ldconst 0,g0 /* BNN_EQUAL */
bx (g7)
.bcdgreater:
ldconst 1,g0 /*BNN_GREATER */
bx (g7)
/*
** BnnComplement(nn, nl)
** BigNum nn
** int nl
**
** Complement nn and store result in nn
**
** g0 -> nn
** g1 -> nl
**
*/
.globl _BnnComplement
.leafproc _BnnComplement
_BnnComplement:
mov g14,g7
ldconst 0,g14
cmpobe 0,g1,.bcexit
subo 1,g1,g1
shlo 2,g1,g1
addo g1,g0,g1
ldconst 0xffffffff,g3
.bcloop:
ld (g0),g2
xor g3,g2,g2
st g2, (g0)
addo 4,g0,g0
cmpoble g0,g1,.bcloop
.bcexit:
bx (g7)
/*
** BnnAndDigits(n,d)
** BigNum nn
** BigNumDigit d
**
** And the digit d with the first digit in n
**
** g0 -> nn
** g1 -> d
**
*/
.globl _BnnAndDigits
.leafproc _BnnAndDigits
_BnnAndDigits:
mov g14,g7
ldconst 0,g14
ld (g0),g2
and g1,g2,g2
st g2,(g0)
bx (g7)
/*
** BnnOrDigits(n,d)
** BigNum nn
** BigNumDigit d
**
** Returns the logical computation nn[0] |= d;
**
** g0 -> nn
** g1 -> d
**
*/
.globl _BnnOrDigits
.leafproc _BnnOrDigits
_BnnOrDigits:
mov g14,g7
ldconst 0,g14
ld (g0),g2
or g1,g2,g2
st g2,(g0)
bx (g7)
/*
** void BnnXorDigits (n, d)
** BigNum n
** BigNumDigit d
**
** Returns the logical computation n[0] XOR d in n[0]
**
** g0 -> n
** g1 -> d
**
*/
.globl _BnnXorDigits
.leafproc _BnnXorDigits
_BnnXorDigits:
mov g14,g7
ldconst 0,g14
ld (g0),g2
xor g1,g2,g2
st g2,(g0)
bx (g7)
/*
** BigNumDigit BnnShiftLeft (mm, ml, nbits)
** BigNum mm
** int ml
** int nbits
**
** Shifts M left by "nbits", filling with 0s.
** Returns the leftmost "nbits" of M in a digit.
** Assumes 0 <= nbits < BNN_DIGIT_SIZE.
**
** g0 -> mm
** g1 -> ml
** g2 -> nbits
*/
.globl _BnnShiftLeft
.leafproc _BnnShiftLeft
_BnnShiftLeft:
mov g14,g7
ldconst 0,g14
cmpo 0,g1
be .bslexit0
subo 1,g1,g1
shlo 2,g1,g1
addo g1,g0,g1 /* nl += nn i.e. get the final address */
mov g0,g3 /* Save beginning of mm */
ldconst 0,g0 /* pre-load result with 0 */
cmpo 0,g2
be .bslexit
ldconst 32,g6 /* BNN_DIGIT_SIZE */
subo g2,g6,g6
.blsloop:
ld (g3),g4 /* Access *mm */
shlo g2,g4,g5 /* *mm == (*mm << nbits) */
or g5,g0,g5 /* or in remaining bits from last op */
st g5,(g3) /* save the stuff */
shro g6,g4,g0 /* Save the left over high bits */
/* for the next time through the loop */
addo 4,g3,g3 /* Increment to next address */
cmpi g3,g1
ble .blsloop
.bslexit:
bx (g7) /* Note that g0 holds bits that where */
/* Shifted out at the end */
.bslexit0:
mov 0,g0
bx (g7)
/*
** BigNumDigit BnnShiftRight (mm, ml, nbits)
** BigNum mm;
** int ml;
** int nbits;
**
** Shifts M right by "nbits", filling with 0s.
** Returns the rightmost "nbits" of M in a digit.
** Assumes 0 <= nbits < BNN_DIGIT_SIZE.
**
** g0 -> mm
** g1 -> ml
** g2 -> nbits
**
** Returns result in g0
**
*/
.globl _BnnShiftRight
.leafproc _BnnShiftRight
_BnnShiftRight:
mov g14,g7
ldconst 0,g14
mov g0,g3 /*Save mm in g3 and preload result */
ldconst 0,g0
cmpobe 0,g1,.bsrexit /* If this is a zero length Bignum or */
cmpobe 0,g2,.bsrexit /* there are no bits to shift, exit */
subo 1,g1,g1 /* Prepare for pointer arithmetic */
shlo 2,g1,g1
addo g3,g1,g1 /*Point to the last element in the array*/
ldconst 32,g8 /* BNN_DIGIT_SIZE */
subo g2,g8,g6
.bsrloop:
ld (g1),g4 /* *mm = (*mm >> nbits)| leftover bits */
/* from the last time through the loop */
shro g2,g4,g5
or g0,g5,g5
st g5,(g1)
shlo g6,g4,g0
subo 4,g1,g1
cmpobge g1,g3,.bsrloop
.bsrexit:
bx (g7) /* Bits shifted out are still in g0! */
/*
** BigNumCarry BnnAddCarry (nn, nl, carryin)
** BigNum nn;
** int nl;
** BigNumCarry carryin;
**
** Performs the sum N + CarryIn => N. Returns the CarryOut.
**
** g0 -> nn
** g1 -> nl
** g2 -> carryin
**
** Result is in g0
**
*/
.globl _BnnAddCarry
.leafproc _BnnAddCarry
_BnnAddCarry:
mov g14,g7
ldconst 0,g14
cmpobe 0,g2,.bacexit0 /* If carry == 0 return 0 */
cmpobe 0,g1,.bacexit1 /* If nl == 0 return 1 */
.bacloop:
subo 1,g1,g1 /* --nl */
ld (g0),g3 /* g3= *nn */
addo 1,g3,g3 /* ++g3 */
st g3,(g0) /* *nn = g3 */
addo 4,g0,g0 /* ++nn */
cmpobne 0,g3,.bacexit0 /* if (g3) then return 0 */
cmpibl 0,g1,.bacloop /* If (nl) continue loop */
.bacexit1:
ldconst 1,g0
bx (g7)
.bacexit0:
ldconst 0,g0
bx (g7)
/*
** BigNumCarry BnnSubtractBorrow (nn, nl, carryin)
** BigNum nn;
** int nl;
** BigNumCarry carryin;
**
** Performs the difference N + CarryIn - 1 => N. Returns the CarryOut.
**
** g0 -> nn
** g1 -> nl
** g2 -> carryin
*/
.globl _BnnSubtractBorrow
.leafproc _BnnSubtractBorrow
_BnnSubtractBorrow:
mov g14,g7
ldconst 0,g14
cmpibe 1,g2,.bsbexit1 /* If Carry return 1 */
cmpobe 0,g1,.bsbexit0 /* If (!nl) return 0 */
.bsbloop:
subi 1,g1,g1 /* --nl */
ld (g0),g3 /* g3 = *nn */
mov g3,g5 /* g5 = *nn */
subo 1,g3,g3 /* --g3 */
st g3,(g0) /* *nn = g3 */
addo 4,g0,g0
cmpobne 0,g5,.bsbexit1
cmpibl 0,g1,.bsbloop
.bsbexit0:
ldconst 0,g0
bx (g7)
.bsbexit1:
ldconst 1,g0
bx (g7)
/*
** BigNumCarry BnnSubtract (mm, ml, nn, nl, carryin)
** BigNum mm, nn;
** int ml;
** int nl;
** BigNumCarry carryin;
**
** Performs the difference M - N + CarryIn - 1 => M.
** Returns the CarryOut.
** Assumes Size(M) >= Size(N).
**
** g0 -> mm
** g1 -> ml
** g2 -> nn
** g3 -> nl
** g4 -> carryin
**
*/
.globl _BnnSubtract
_BnnSubtract:
subo g3,g1,g1
cmpibe 0,g3,.bslpe /* While (--nl >= 0) */
ldconst -1,r5
.bsloop:
subi 1,g3,g3
ld (g0),g5 /* g5 = *mm */
ld (g2),g6 /* g6 = *nn */
xor r5,g6,g6 /* g6 = (*nn) ^ -1 */
addo g4,g5,g4 /* c += *mm */
cmpobge g4,g5,.bsgt /* if (c < *mm) { */
mov g6,g5 /* *mm = invn */
ldconst 1,g4 /* c = 1 */
b .cleanup /* } */
.bsgt:
addo g4,g6,g4 /* else { c += g6 */
mov g4,g5 /* *mm = c */
cmpobl g4,g6, .bsset1 /* if (c < g6) then c=1 */
ldconst 0,g4 /* else c = 0 */
b .cleanup /* } */
.bsset1:
ldconst 1,g4
.cleanup:
st g5,(g0)
addo 4,g0,g0
addo 4,g2,g2
cmpibl 0,g3,.bsloop /* While (--nl >= 0) */
.bslpe:
mov g4,g2
lda .bsexit,g14
bal _BnnSubtractBorrow
.bsexit:
ret
/*
** BigNumCarry BnnMultiplyDigit (pp, pl, mm, ml, d)
** BigNum pp, mm;
** int pl, ml;
** BigNumDigit d;
**
** Performs the product:
** Q = P + M * d
** BB = BBase(P)
** Q mod BB => P
** Q div BB => CarryOut
** Returns the CarryOut.
** Assumes Size(P) >= Size(M) + 1.
**
**
** g0 -> pp
** g1 -> pl
** g2 -> mm
** g3 -> ml
** g4 -> d
*/
.globl _BnnMultiplyDigit
_BnnMultiplyDigit:
cmpo 0,g4
be .bmdexit0 /* if the multiplier is 0 */
cmpo 1,g4
be .bmdbnnadd
subo g3,g1,g1 /* pl -= ml */
mov 0,g6 /* Carry = 0 */
cmpo 0,g3
mov 0,g7
be .bmdbye /* While (m--) */
.bmdlp1:
ld (g2),r3 /* r3 = *mm */
subo 1,g3,g3
ld (g0),r4 /* r4 = *p */
/* r5 = *(p++) */
emul g4,r3,r6 /* r6-r7 = *mm x d */
cmpo 1,0 /* Clear the carry bit */
addc r4,r6,r6
addc 0,r7,r7
addc r6,g6,g6
addc r7,g7,g7
st g6,(g0) /* *p = C */
mov g7,g6 /* c >> = BN_DIGIT_SIZE */
addo 4,g0,g0
mov 0,g7
addo 4,g2,g2
cmpo 0,g3
bl .bmdlp1 /* While (m--) */
cmpobl 0,g1, .bmdlp2
mov g6,g0
ret
.bmdlp2:
ld (g0),r4
cmpo 1,0
addc g6,r4,g6
addc 0,g7,g7
st g6,(g0)
mov g7,g6
subo 1,g1,g1
mov 0,g7
addo 4,g0,g0
cmpobl 0,g1,.bmdlp2
mov g6,g0
ret
.bmdbye:
mov 0,g0
ret
.bmdexit0:
mov 0,g0 /* its a sure bet the result */
ret
.bmdbnnadd:
mov 0,g4 /* Just add the 2 bignums */
call _BnnAdd /* of adding the 2 */
ret
/*
** BigNumDigit BnnDivideDigit (qq, nn, nl, d)
** BigNum qq, nn;
** int nl;
** BigNumDigit d;
**
** Performs the quotient: N div d => Q
** Returns R = N mod d
** Assumes leading digit of N < d, and d > 0.
**
** g0 -> qq
** g1 -> nn
** g2 -> nl
** g3 -> d
*/
.globl _BnnDivideDigit
.leafproc _BnnDivideDigit
_BnnDivideDigit:
mov g14,g7 /* Do standard leafproc stuff */
ldconst 0,g14
cmpo 0,g2
be .bddret0 /* Is this a Null length BIGNUM? */
cmpo 0,g3
be .bddret0 /* Is the divisor zero? */
.bddndz:
subo 1,g2,g2
shlo 2,g2,g5
addo g1,g5,g1 /* nn += nl */
subo 4,g5,g5 /* --nl */
addo g0,g5,g0 /* qq += nl */
ld (g1),g9 /* Preset remainder */
subo 4,g1,g1 /* --nn */
cmpo 0,g2
be .bddexit
.bddloop:
subo 1,g2,g2 /* --nl */
ld (g1),g8 /* LSB of quad is next digit */
ediv g3,g8,g8 /* remainder =quad%d, */
st g9,(g0) /* *qq = quad/d */
subo 4,g0,g0 /* --qq */
subo 4,g1,g1 /* --nn */
cmpo 0,g2
mov g8,g9
bne .bddloop /* } */
.bddexit:
mov g9,g0 /* Return (remainder) */
bx (g7)
.bddret0:
mov 0,g0
bx (g7)
/*
** BigNumCarry BnnAdd (mm, ml, nn, nl, carryin)
** BigNum mm, nn;
** int ml;
** int nl;
** BigNumCarry carryin;
**
** Performs the sum M + N + CarryIn => M.
** Returns the CarryOut. Assumes Size(M) >= Size(N).
**
** g0 -> mm
** g1 -> ml
** g2 -> nn
** g3 -> nl
** g4 -> caryin;
**
** Result is in g0 and M (of course!)
*/
.text
.align 2
.globl _BnnAdd
_BnnAdd:
subo g3,g1,g1 /* ml -= nl */
shlo 1,g4,g4
cmpobe 0,g3,.bafni /* if (!nl) */
.balp:
modac 02,g4,g4
ld (g0),g5 /* g5 = *mm */
ld (g2),g6 /* g6 = *nn */
addc g6,g5,g7 /* g7 = *m + *n */
modac 00,00,g4 /* Save the carry bit */
st g7,(g0) /* *m = g7 */
addo 4,g0,g0 /* ++m */
addo 4,g2,g2 /* ++n */
subi 1,g3,g3 /* --nl */
cmpobl 0,g3,.balp
.bafni:
shro 1,g4,g4
and 01,g4,g2
lda .bazit,g14
bal _BnnAddCarry
.bazit:
ret