.asciz "@(#)bigmath.s 35.5 6/7/82" .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: jsb _qnewdot #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 # # WARNING: this code is duplicated in C in divbig.c # 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. 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 jsb _qnewdot #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 0xf00 movl 4(ap),r11 # &u[j] into r11 movl 8(ap),r10 # &v[1] into r10 cmpl (r10),(r11) # v[1] == u[j] ?? beql L102 # calculate qhat and rhat simultaneously, # qhat in r0 # rhat in r1 emul (r11),$0x40000000,4(r11),r4 # u[j]b+u[j+1] into r4,r5 ediv (r10),r4,r0,r1 # qhat = ((u[j]b+u[j+1])/v[1]) into r0 # (u[j]b+u[j+1] -qhat*v[1]) into r1 # called rhat L101: # check if v[2]*qhat > rhat*b+u[j+2] emul r0,4(r10),$0,r2 # qhat*v[2] into r3,r2 emul r1,$0x40000000,8(r11),r8 #rhat*b + u[j+2] into r9,r8 # give up if r3,r2 <= r9,r8, otherwise iterate subl2 r8,r2 # perform r3,r2 - r9,r8 sbwc r9,r3 bleq L103 # give up if negative or equal decl r0 # otherwise, qhat = qhat - 1 addl2 (r10),r1 # since dec'ed qhat, inc rhat by v[1] jbr L101 L102: # get here if v[1]==u[j] # set qhat to b-1 # rhat is easily calculated since if we substitute b-1 for qhat in # the formula, then it simplifies to (u[j+1] + v[1]) # addl3 4(r11),(r10),r1 # rhat = u[j+1] + v[1] movl $0x3fffffff,r0 # qhat = b-1 jbr L101 L103: ret .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 _dsrsh _dsrsh: .word .R7 movl 8(ap),r11 # bot movl 16(ap),r5 # mask movl 12(ap),r4 # shift count clrl r0 L201: emul r0,$0x40000000,(r11),r1 bicl3 r5,r1,r0 ashq r4,r1,r1 movl r1,(r11) acbl 4(ap),$4,r11,L201 ret .set .R7,0x800 .align 1 .globl _dsadd1 _dsadd1: .word .R8 movl 4(ap),r11 movl $1,r0 L501: emul $1,(r11),r0,r1 extzv $0,$30,r1,(r11) extv $30,$32,r1,r0 acbl 8(ap),$-4,r11,L501 movl r1,4(r11) ret .set .R8,0x800 # # myfrexp (value, exp, hi, lo) # double value; # int *exp, *hi, *lo; # # myfrexp returns three values, exp, hi, lo, # Such that value = 2**exp*tmp, where tmp = (hi*2**-23+lo*2**-53) # is uniquely determined subect to .5< abs(tmp) <= 1.0 # # # Entry point # .text .globl _myfrexp _myfrexp: .word 0x0000 # We use r2, but do not save it clrl *12(ap) # Make for easy exit later clrl *16(ap) # clrl *20(ap) # movd 4(ap),r0 # Fetch "value" bneq L301 # if zero return zero exponent + mantissa ret L301: extzv $7,$8,r0,r2 # r2 := biased exponent movab -129(r2),*12(ap)# subtract bias, store exp insv $154,$7,$8,r0 # lie about exponent to get out # high 24 bits easily with emodd. # This instruction does the following: # # Extend the long floating value in r0 with 0, and # multiply it by 1.0. Store the integer part of the result # in hi, and the fractional part of the result in r0-r1. # emodd r0,$0,$0f1.0,*16(ap),r0 # How did you like # THAT, sports fans? [jfr's comment] tstd r0 # if zero, exit; bneq L401 ret L401: insv $158,$7,$8,r0 # lie about exponent to get out # next 30 bits easily with emodd. # (2^29 takes 30 bits). emodd r0,$0,$0f1.0,*20(ap),r0 # Get last bits out likewise! ret # (r0 should be zero by now!)