Commit a6784306 authored by Richard Levitte's avatar Richard Levitte
Browse files

Redo the VAX assembler version of bn_div_words().

PR: 366
parent e9b553da
Loading
Loading
Loading
Loading
+62 −101
Original line number Diff line number Diff line
@@ -172,145 +172,106 @@ n=12 ;(AP) n by value (input)
; }
;
; Using EDIV would be very easy, if it didn't do signed calculations.
; Therefore, som extra things have to happen around it.  The way to
; handle that is to shift all operands right one step (basically dividing
; them by 2) and handle the different cases depending on what the lowest
; bit of each operand was.
; It doesn't accept a signed dividend, but accepts a signed divisor.
; So, shifting down the dividend right one bit makes it positive, and
; just makes us lose the lowest bit, which can be used afterwards as
; an addition to the remainder.  All that needs to be done at the end
; is a little bit of fiddling; shifting both quotient and remainder
; one step to the left, and deal with the situation when the remainder
; ends up being larger than the divisor.
;
; To start with, let's define the following:
; We end up doing something like this:
;
; a' = l & 1
; a2 = <h,l> >> 1	# UNSIGNED shift!
; b' = d & 1
; b2 = d >> 1		# UNSIGNED shift!
; l'    = l & 1
; [h,l] = [h,l] >> 1
; [q,r] = floor([h,l] / d)
; if (q < 0) q = -q	# Because EDIV thought d was negative
;
; Now, use EDIV to calculate a quotient and a remainder:
; Now, we need to adjust back by multiplying quotient and remainder with 2,
; and add the bit that dropped out when dividing by 2:
;
; q'' = a2/b2
; r'' = a2 - q''*b2
; r'    = r & 0x80000000
; q     = q << 1
; r     = (r << 1) + a'
;
; If b' is 0, the quotient is already correct, we just need to adjust the
; remainder:
; And now, the final adjustment if the remainder happens to get larger than
; the divisor:
;
; if (b' == 0)
; if (r')
;   {
;     r = 2*r'' + a'
;     q = q''
;     r = r - d
;     q = q + 1
;   }
;
; If b' is 1, we need to do other adjustements.  The first thought is the
; following (note that r' will not always have the right value, but an
; adjustement follows further down):
;
; if (b' == 1)
;   {
;     q' = q''
;     r' = a - q'*b
;
; However, one can note the folowing relationship:
;
;                         r'' = a2 - q''*b2
;                  =>   2*r'' = 2*a2 - 2*q''*b2
;                             = { a = 2*a2 + a', b = 2*b2 + b' = 2*b2 + 1,
;                                 q' = q'' }
;                             = a - a' - q'*(b - 1)
;                             = a - q'*b - a' + q'
;                             = r' - a' + q'
;                  =>     r'  = 2*r'' - q' + a'
;
; This enables us to use r'' instead of discarding and calculating another
; modulo:
;
; if (b' == 1)
;   {
;     q' = q''
;     r' = (r'' << 1) - q' + a'
;
; Now, all we have to do is adjust r', because it might be < 0:
;
;     while (r' < 0)
; while (r > d)
;   {
;         r' = r' + b
;         q' = q' - 1
;       }
;     r = r - d
;     q = q + 1
;   }
;
; return q'
; return q

h=4 ;(AP)	h	by value (input)
l=8 ;(AP)	l	by value (input)
d=12 ;(AP)	d	by value (input)

;aprim=r5
;a2=r6
;a20=r6
;a21=r7
;bprim=r8
;b2=r9
;qprim=r10	; initially used as q''
;rprim=r11	; initially used as r''
;lprim=r5
;rprim=r6


	.psect	code,nowrt

.entry	bn_div_words,^m<r2,r3,r4,r5,r6,r7,r8,r9,r10,r11>
.entry	bn_div_words,^m<r2,r3,r4,r5,r6>
	movl	l(ap),r2
	movl	h(ap),r3
	movl	d(ap),r4

	movl	#0,r5
	movl	#0,r8
	movl	#0,r0
;	movl	#0,r1
	movl	#0,r6

	rotl	#-1,r2,r6	; a20 = l >> 1 (almost)
	rotl	#-1,r3,r7	; a21 = h >> 1 (almost)
	rotl	#-1,r4,r9	; b2 = d >> 1 (almost)
	rotl	#-1,r2,r2	; l = l >> 1 (almost)
	rotl	#-1,r3,r3	; h = h >> 1 (almost)

	tstl	r6
	tstl	r2
	bgeq	1$
	xorl2	#^X80000000,r6	; fixup a20 so highest bit is 0
	incl	r5		; a' = 1
	xorl2	#^X80000000,r2	; fixup l so highest bit is 0
	incl	r5		; l' = 1
1$:
	tstl	r7
	tstl	r3
	bgeq	2$
	xorl2	#^X80000000,r6	; fixup a20 so highest bit is 1,
				; since that's what was lowest in a21
	xorl2	#^X80000000,r7	; fixup a21 so highest bit is 1
	xorl2	#^X80000000,r2	; fixup l so highest bit is 1,
				; since that's what was lowest in h
	xorl2	#^X80000000,r3	; fixup h so highest bit is 0
2$:
	tstl	r9
	tstl	r4
	beql	666$		; Uh-oh, the divisor is 0...
	bgtr	3$
	xorl2	#^X80000000,r9	; fixup b2 so highest bit is 0
	incl	r8		; b' = 1

	ediv	r4,r2,r2,r3	; Do the actual division

	tstl	r2
	bgeq	3$
	mnegl	r2,r2		; if q < 0, negate it
3$:
	tstl	r9
	bneq	4$		; if b2 is 0, we know that b' is 1
	tstl	r3
	bneq	666$		; if higher half isn't 0, we overflow
	movl	r2,r10		; otherwise, we have our result
	brb	42$		; This is a success, really.
	bgeq	4$
	incl	r6		; since the high bit in r is set, set rprim
4$:
	ediv	r9,r6,r10,r11
	ashl	#1,r2,r2
	ashl	#1,r3,r3
	addl	r5,r3

	tstl	r8
	bneq	5$		; If b' != 0, go to the other part
;	addl3	r11,r11,r1
;	addl2	r5,r1
	brb	42$
	tstl	r6
	beql	5$
	subl	r4,r3
	incl	r2
5$:
	ashl	#1,r11,r11
	subl2	r10,r11
	addl2	r5,r11
	bgeq	7$
6$:
	decl	r10
	addl2	r4,r11
	blss	6$
7$:
;	movl	r11,r1
	cmpl	r3,r4
	blequ	42$
	subl	r4,r3
	incl	r2
	brb	5$	
42$:
	movl	r10,r0
;	movl	r3,r1
	movl	r2,r0
666$:
	ret