BSD 4 release
[unix-history] / usr / src / cmd / lisp / bigmath.s
.asciz "@(#)bigmath.s 34.1 10/3/80"
.globl _dmlad
#
# routine for destructive multiplication and addition to a bignum by
# two fixnums.
#
# from C, the invocation is dmlad(sdot,mul,add);
# where sdot is the address of the first special cell of the bignum
# mul is the multiplier, add is the fixnum to be added (The latter
# being passed by value, as is the usual case.
#
#
# Register assignments:
#
# r11 = current sdot
# r10 = carry
# r9 = previous sdot, for relinking.
#
_dmlad: .word 0x0e00
movl 4(ap),r11 #initialize cell pointer
movl 12(ap),r10 #initialize carry
loop: emul 8(ap),(r11),r10,r0 #r0 gets cell->car times mul + carry
# ediv $0x40000000,r0,r10,(r11)#cell->car gets prod % 2**30
# #carry gets quotient
extzv $0,$30,r0,(r11)
extv $30,$32,r0,r10
movl r11,r9 #save last cell for fixup at end.
movl 4(r11),r11 #move to next cell
bneq loop #done indicated by 0 for next sdot
tstl r10 #if carry zero no need to allocate
beql done #new bigit
mcoml r10,r3 #test to see if neg 1.
bneq alloc #if not must allocate new cell.
tstl (r9) #make sure product isn't -2**30
beql alloc
movl r0,(r9) #save old lower half of product.
brb done
alloc: calls $0,_newsdot #otherwise allocate new bigit
movl r10,(r0) #store carry
movl r0,4(r9) #save new link cell
done: movl 4(ap),r0
ret
.globl _dodiv
#
# routine to destructively divide array representation of a bignum by
# 1000000000
#
# invocation:
# remainder = dodiv(top,bottom)
# int *top, *bottom;
# where *bottom is the address of the biggning of the array, *top is
# the top of the array.
#
# register assignments:
# r0 = carry
# r1 & r2 = 64bit temporary
# r3 = pointer
#
_dodiv: .word 0
clrl r0 #no carry to begin.
movl 8(ap),r3 #get pointer to array.
loop2: emul $0x40000000,r0,(r3),r1
ediv $1000000000,r1,(r3),r0
acbl 4(ap),$4,r3,loop2
ret
.globl _dsneg
#
# dsneg(top, bot);
# int *top, *bot;
#
# routine to destructively negate a bignum stored in array format
# lower order stuff at higher addresses. It is assume that the
# result will be positive.
#
_dsneg: .word 0
movl 4(ap),r1 #load up address.
clrl r2 #set carry
loop3: mnegl (r1),r0 #negate and take carry into account.
addl2 r2,r0
extzv $0,$30,r0,(r1)
extv $30,$2,r0,r2
acbl 8(ap),$-4,r1,loop3
#decrease r1, and branch back if appropriate.
ret
# bignum add routine
# basic data representation is each bigit is a positive number
# less than 2^30, except for the leading bigit, which is in
# the range -2^30 < x < 2^30.
.globl _adbig
.globl Bexport
.globl backfr
#
# Initialization section
#
_adbig: .word 0x0fc0 #save registers 6-11
movl 4(ap),r1 #arg1 = addr of 1st bignum
movl 8(ap),r2 #arg2 = addr of 2nd bignum
clrl r5 #r5 = carry
movl $0xC0000000,r4 #r4 = clear constant.
movl sp,r10 #save start address of bignum on stack.
#note well that this is 4 above the actual
#low order word.
#
# first loop is to waltz through both bignums adding
# bigits, pushing them onto stack.
#
loop4: addl3 (r1),(r2),r0 #add bigits
addl2 r5,r0 #add carry
bicl3 r4,r0,-(sp) #save sum, no overflow possible
extv $30,$2,r0,r5 #sign extend two high order bits
#to be next carry.
movl 4(r1),r1 #get cdr
bleq out1 #negative indicates end of list.
movl 4(r2),r2 #get cdr of second bignum
bgtr loop4 #if neither list at end, do it again
#
# second loop propagates carries through higher order words.
# It assumes remaining list in r1.
#
loop5: addl3 (r1),r5,r0 #add bigits and carry
bicl3 r4,r0,-(sp) #save sum, no overflow possible
extv $30,$2,r0,r5 #sign extend two high order bits
#to be next carry.
movl 4(r1),r1 #get cdr
out2: bgtr loop5 #negative indicates end of list.
out2a: pushl r5
#
# suppress unnecessary leading zeroes and -1's
#
iexport:movl sp,r11 #more set up for output routine
ckloop:
Bexport:tstl (r11) #look at leading bigit
bgtr copyit #if positive, can allocate storage etc.
blss negchk #if neg, still a chance we can get by
cmpl r11,r10 #check to see that
bgeq copyit #we don't pop everything off of stack
tstl (r11)+ #incr r11
brb ckloop #examine next
negchk:
mcoml (r11),r3 #r3 is junk register
bneq copyit #short test for -1
tstl 4(r11) #examine next bigit
beql copyit #if zero must must leave as is.
cmpl r11,r10 #check to see that
bgeq copyit #we don't pop everything off of stack
tstl (r11)+ #incr r11
bisl2 r4,(r11) #set high order two bits
brb negchk #try to supress more leading -1's
#
# The following code is an error exit from the first loop
# and is out of place to avoid a jump around a jump.
#
out1: movl 4(r2),r1 #get next addr of list to continue.
brb out2 #if second list simult. exhausted, do
#right thing.
#
# loop6 is a faster version of loop5 when carries are no
# longer necessary.
#
loop6a: pushl (r1) #get datum
loop6: movl 4(r1),r1 #get cdr
bgtr loop6a #if not at end get next cell
brb out2a
#
# create linked list representation of bignum
#
copyit: subl3 r11,r10,r2 #see if we can get away with allocating an int
bneq on1 #test for having popped everything
subl3 $4,r10,r11 #if so, fix up pointer to bottom
brb intout #and allocate int.
on1: cmpl r2,$4 #if = 4, then can do
beql intout
calls $0,_newsdot #get new cell for new bignum
backfr: movl r0,(r6)+ #push address of cell on
#arg stack to save from garbage collection.
#There is guaranteed to be slop for a least one
#push without checking.
movl r0,r8 #r8 = result of adbig
loop7: movl -(r10),(r0) #save bigit
movl r0,r9 #r9 = old cell, to link
cmpl r10,r11 #have we copy'ed all the bigits?
bleq Edone
calls $0,_newsdot #get new cell for new bignum
movl r0,4(r9) #link new cell to old
brb loop7
Edone:
clrl 4(r9) #indicate end of list with 0
movl -(r6),r0 #give resultant address.
ret
#
# export integer
#
intout: pushl (r11)
calls $1,_inewint
ret
.globl _mulbig
#
# bignum multiplication routine
#
# Initialization section
#
_mulbig:.word 0x0fc0 #save regs 6-11
movl 4(ap),r1 #get address of first bignum
movl sp,r11 #save top of 1st bignum
mloop1: pushl (r1) #get bigit
movl 4(r1),r1 #get cdr
bgtr mloop1 #repeat if not done
movl sp,r10 #save bottom of 1st bignum, top of 2nd bignum
movl 8(ap),r1 #get address of 2nd bignum
mloop2: pushl (r1) #get bigit
movl 4(r1),r1 #get cdr
bgtr mloop2 #repeat if not done
movl sp,r9 #save bottom of 2nd bignum
subl3 r9,r11,r6 #r6 contains sum of lengths of bignums
subl2 r6,sp
movl sp,r8 #save bottom of product bignum
#
# Actual multiplication
#
m1: movc5 $0,(r8),$0,r6,(r8)#zap out stack space
movl r9,r7 #r7 = &w[j +n] (+4 for a.d.) through calculation
subl3 $4,r10,r4 #r4 = &v[j]
m3: movl r7,r5 #r7 = &w[j+n]
subl3 $4,r11,r3 #r3 = &u[i]
clrl r2 #clear carry.
m4: addl2 -(r5),r2 #add w[i + j] to carry (no ofl poss)
emul (r3),(r4),r2,r0 #r0 = u[i] * v[j] + sext(carry)
extzv $0,$30,r0,(r5) #get new bigit
extv $30,$32,r0,r2 #get new carry
m5: acbl r10,$-4,r3,m4 #r3 =- 4; if(r3 >= r10) goto m4; r10 = &[u1];
movl r2,-(r5) #save w[j] = carry
m6: subl2 $4,r7 #add just &w[j+n] (+4 for autodec)
acbl r9,$-4,r4,m3 #r4 =- 4; if(r4>=r9) goto m5; r9 = &v[1]
movl r9,r10 #set up for output routine
movl $0xC0000000,r4 #r4 = clear constant.
movq 20(fp),r6 #restor _np and _lbot !
brw iexport #do it!
#
# The remainder of this file are routines used in bignum division.
# Interested parties should consult Knuth, Vol 2, and divbig.c.
# These files are here only due to an optimizer bug.
#
.align 1
.globl _calqhat
_calqhat:
.word .R1
movl 4(ap),r11
movl 8(ap),r10
movl $0x3fffffff,r0
cmpl (r10),(r11)
beql on3
emul (r11),$0x40000000,4(r11),r1
ediv (r10),r1,r0,r5
on3:
emul r0,4(r10),$0,r1
emul r5,$0x40000000,8(r11),r3
subl2 r3,r1
sbwc r4,r2
bleq out4
decl r0
out4:
ret
.set .R1,0xc00
.align 1
.globl _mlsb
_mlsb:
.word .R2
movl 4(ap),r11
movl 8(ap),r10
movl 12(ap),r9
movl 16(ap),r8
clrl r0
loop8: addl2 (r11),r0
emul r8,-(r9),r0,r2
extzv $0,$30,r2,(r11)
extv $30,$32,r2,r0
acbl r10,$-4,r11,loop8
ret
.set .R2,0xf00
.align 1
.globl _adback
_adback:
.word .R3
movl 4(ap),r11
movl 8(ap),r10
movl 12(ap),r9
clrl r0
loop9: addl2 -(r9),r0
addl2 (r11),r0
extzv $0,$30,r0,(r11)
extv $30,$2,r0,r0
acbl r10,$-4,r11,loop9
ret
.set .R3,0xe00
.align 1
.globl _dsdiv
_dsdiv:
.word .R4
movl 8(ap),r11
clrl r0
loopa: emul r0,$0x40000000,(r11),r1
ediv 12(ap),r1,(r11),r0
acbl 4(ap),$4,r11,loopa
ret
.set .R4,0x800
.align 1
.globl _dsmult
_dsmult:
.word .R5
movl 4(ap),r11
clrl r0
loopb: emul 12(ap),(r11),r0,r1
extzv $0,$30,r1,(r11)
extv $30,$32,r1,r0
acbl 8(ap),$-4,r11,loopb
movl r1,4(r11)
ret
.set .R5,0x800
.align 1
.globl _export
_export:
.word .R6
movl 8(ap),r11
movl 4(ap),r10
movl $0xC0000000,r4
jmp Bexport
ret
.set .R6,0xfc0