 	.Title	QUADMATH	- A package of routines to manipulate quadwords
 
 ;++
 ;
 ; Written by Kevin Carosso, @ Hughes S&CG PWB/ENG.
 ;
 ; This is a simple package of four routines to do quadword mathematics.
 ;
 ; Note:
 ;	All arguments are addresses of quadwords.
 ;
 ;--
 
 ;------------------------------------------------------------------------------
 ;
 ; ADDQ	- Integer addition.
 ;
 ; Call:
 ;	ret = ADDQ (Sum, Operand1, Operand2)
 ; i.e.:
 ;	Sum = Operand1 + Operand2
 ;
 ;-
 
 	.Entry	ADDQ, ^M<r2, r3>
 
 	movq	@12(ap), r0		; Get the two addends.
 	movq	@8(ap), r2
 	addl	r0, r2			; Add low order longwords
 	adwc	r1, r3			; then high order.
 	movq	r2, @4(ap)		; Store result
 	movl	#SS$_NORMAL, r0		; and return success.
 	ret
 
 ;------------------------------------------------------------------------------
 ;
 ; SUBQ	- Integer subtraction.
 ;
 ; Call:
 ;	ret = SUBQ (Difference, Operand1, Operand2)
 ; i.e.:
 ;	Difference = Operand1 - Operand2
 ;
 ;-
 
 	.Entry	SUBQ, ^M<r2, r3>
 
 	movq	@12(ap), r0		; Get the two operands.
 	movq	@8(ap), r2
 	subl2	r0, r2			; Subtract low order longwords
 	sbwc	r1, r3			; then high order.
 	movq	r2, @4(ap)		; Store result
 	movl	#SS$_NORMAL, r0		; and return success.
 	ret
 
 ;------------------------------------------------------------------------------
 ;
 ; MULQ	- Integer multiplication.
 ;
 ; Call:
 ;	ret = MULQ (Product, Operand1, Operand2)
 ; i.e.:
 ;	Product = Operand1 * Operand2
 ;
 ;-
 
 	.Entry	MULQ, ^M<r2, r3, r4, r5, r6, r7>
 
 	movq	@8(ap), r0		; Get the operands
 	movq	@12(ap), r2
 	emul	r0, r2, #0, r4		; Multiply low order half
 	mull3	r1, r2, r6		; hi-order = A[high] * B[low]
 	mull3	r0, r3, r7		;          + A[low] * B[high]
 	addl2	r7, r6
 	tstl	r0			; If A[low] < 0 then compensate for
 	bgeq	10$
 	addl2	r2, r6			; unsigned bias of 2^32.
 10$:	tstl	r2			; Same for B
 	bgeq	20$
 	addl2	r0, r6
 20$:	addl2	r6, r5			; Combine with high of A[low] * B[high]
 	movq	r4, @4(ap)		; Store result
 	movl	#SS$_NORMAL, r0
 	ret
 
 ;------------------------------------------------------------------------------
 ;
 ; DIVQ	- Integer division.
 ;
 ; Call:
 ;	ret = DIVQ (Quotient, Remainder, Dividend, Divisor)
 ; i.e.:
 ;	(Quotient, Remainder) = Dividend/Divisor
 ;
 ;-
 
 	.Entry	DIVQ, ^M<r2,r3,r4,r5,r6,r7,r8,r9,r10>
 
 	movq	@16(ap), r0		; Get divisor.
 	movq	@12(ap), r2		; Get dividend.
 	movq	r2, r4			; Quotient := Dividend
 	clrq	r6			; Remainder := 0
 	clrl	r8			; Use this for a "carry" flag.
 	movl	#65, r10		; Loop counter.
 
 10$:	ashq	#1, r6, r6		; Shift remainder left by 1
 	bisl2	r8, r6			; and shift in from dividend "carry".
 	clrl	r8			; Clear the "carry" flag.
 	cmpl	r1, r7			; See if divisor > current remainder
 	 bneq	20$
 	cmpl	r0, r6
 20$:	bgtru	30$			; and if so skip on ("carry" is clear).
 	subl2	r0, r6			; Subtract divisor from remainder.
 	sbwc	r1, r7
 	incl	r8			; Set "carry".
 
 30$:	clrl	r9			; Now check whether or not we will
 	tstl	r5			; need a "carry" after the shift.
 	 bgeq	40$
 	incl	r9			; Set it if so.
 40$:	ashq	#1, r4, r4		; Shift quotient left by one
 	bisl2	r8, r4			; and shift in a new bit.
 	movl	r9, r8			; Set "carry" for this operation.
 	decl	r10			; Decrement counter
 	 bneq	10$			; and loop back.
 
 	movq	r4, @4(ap)		; Save the quotient
 	movq	r6, @8(ap)		; and the remainder.
 	movl	#SS$_NORMAL, r0		; Return success...
 	ret
 
 	.End
