#
 !	C68 8 byte floating point add/subtract routines.
 !-----------------------------------------------------------------------------
 ! ported to 68000 by Kai-Uwe Bloem, 12/89
 !	#1	original author: Peter S. Housel 9/21/88,01/17/89,03/19/89,5/24/89
 !	#2	replaced shifts by swap if possible for speed increase	-kub-, 01/90
 !	#3	Redid register usage, and then added wrapper routine
 !		to provide C68 IEEE compatibility			Dave & Keith Walker 02/92
 !	#4	Changed exit code to put pointer to result in D0   Dave Walker	12/92
 !	#5	Changed entry point names for use with C68 v4.3
 !		Changed exit code to C68 v4.3 compatibility
 !		Removed ACK entry points.								-djw-	09/93
 !	#6	Added support for hardware FPU support under QDOS		-djw-	12/95
 !-----------------------------------------------------------------------------

	.define .Xdfadd
	.define .Xdfsub
	.define .Xasdfadd
	.define .Xasdfsub

SAVEREG = 6*4		! Size of saved registers on stack

	.sect .text
!----------------------------------------
!	sp	Return address
!	sp+4	address of result
!	sp+8	address of v
!	sp+12	address of u
!----------------------------------------

.Xdfadd:
	move.l	#0,d1				! set for add
	bra 1f
.Xdfsub:
	move.l	#1,d1				! sign bit
	ror.l	#1,d1				! set for subtract
1:
#ifdef HW_FPU
	jsr 	__FPcheck
	bne 	2f
	move.l	8(sp),a1			! get address for numerator
!	FMOVE.D (a1),FP7			! move to FP register
	dc.l	0xf2115780
	move.l	12(sp),a1			! get address of denominator
	tst.l	d1					! is it a 'add'
	bne 	3f					! ... NO, jump to subtract
!	FADD.D	(a1),FP7			! ... YES do add
	dc.l	0xf21157a2
	bra 	4f
!	FSUB.D	(a1),FP7
3:	dc.l	0xf21157a8
4:	move.l	4(sp),a0			! get address for result
!	FMOVE.D FP7,(a0)			! store result
	dc.l	0xf2107780
	jsr 	__FPrelease
	bra 	addexit
#endif /* HW_FPU */

2:	movem.l d2-d7,-(sp) 		! save registers
	move.l	SAVEREG+12(sp),a1	! address of v
	movem.l (a1),d4-d5		!  ... load v
	move.l	SAVEREG+8(sp),a1	! address of u
	movem.l (a1),d6-d7		!  ... load u
	move.l	SAVEREG+4(sp),a1	! result address
	bsr 	dfaddsub		! go to do operation
	movem.l (sp)+,d2-d7 	! restore saved registers
addexit:
	move.l	(sp)+,a1		! get return address
	lea 	12(sp),sp		! remove 3 parameters from stack
	jmp 	(a1)			! ... and return


!----------------------------------------
!	sp	Return address
!	sp+4	address of result/v
!	sp+8	address of u
!----------------------------------------

.Xasdfadd:
	move.l	#0,d1				! set for add
	bra 1f

.Xasdfsub:
	move.l	#1,d1				! sign bit
	ror.l	#1,d1				! set for subtract

1:
#ifdef HW_FPU
	jsr 	__FPcheck
	bne 	2f
	move.l	4(sp),a0			! get address for result/ numerator
	move.l	8(sp),a1			! get address for denominator
!	FMOVE.D (a0),FP7
	dc.l	0xf2105780
	tst.l	d1					! is it an 'add'
	bne 	3f					! ... NO, jump
!	FADD.D	(a1),FP7
	dc.l	0xf21157a2
	bra 	4f
!	FSUB.D	(a1),FP7
3:	dc.l	0xf21157a8
!	FMOVE.D FP7,(a0)			! store result
4:	dc.l	0xf2107780
	jsr 	__FPrelease
	bra 	asexit
#endif /* HW_FPU */

2:	movem.l d2-d7,-(sp) 		! save registers
	move.l	SAVEREG+8(sp),a1	! address of u
	movem.l (a1),d4-d5			!  ... load u
	move.l	SAVEREG+4(sp),a1	! address of v / result address
	movem.l (a1),d6-d7			! ... load v
	bsr dfaddsub				! go to do operation
	movem.l (sp)+,d2-d7 		! restore saved registers
asexit:
	move.l	(sp)+,a1			! get return address
	move.l	(sp),d0 			! address of v returned as result
	add.l	#8,sp				! remove 2 parameters from stack
	jmp (a1)					! ... and return


 !-------------------------------------------------------------------------
 ! This is the routine that actually carries out the operation.
 !
 ! Register usage:
 !
 !		Entry				Exit
 !
 !	d0	add/subtract mask		undefined
 !	d1	?				undefined
 !	d2	?				undefined
 !	d3	?				undefined
 !	d4-d5	v				undefined
 !	d6-d7	u				undefined
 !
 !	A1	Address for result		preserved
 !
 !-----------------------------------------------------------------------------

dfaddsub:
	eor.l	d1,d4		! reverse sign of v if needed (frees d1 for use)
	move.l	d6,d0		! d0 = u.exp
	swap	d0
	move.l	d6,d2		! d2.h = u.sign
	move.w	d0,d2
	lsr.w	#4,d0
	and.w	#0x07ff,d0	! kill sign bit

	move.l	d4,d1		! d1 = v.exp
	swap	d1
	eor.w	d1,d2		! d2.l = u.sign ^ v.sign
	lsr.w	#4,d1
	and.w	#0x07ff,d1	! kill sign bit

	and.l	#0x0fffff,d6	! remove exponent from u.mantissa
	tst.w	d0		! check for zero exponent - no leading "1"
	beq 0f
	or.l	#0x100000,d6	! restore implied leading "1"
	bra 1f
0:	add.w	#1,d0		! "normalize" exponent
1:
	and.l	#0x0fffff,d4	! remove exponent from v.mantissa
	tst.w	d1		! check for zero exponent - no leading "1"
	beq 0f
	or.l	#0x100000,d4	! restore implied leading "1"
	bra 1f
0:	add.w	#1,d1		! "normalize" exponent
1:
	clr.w	d3		! (put initial zero rounding bits in d3)
	neg.w	d1		! d1 = u.exp - v.exp
	add.w	d0,d1
	beq 5f		! exponents are equal - no shifting neccessary
	bgt 1f		! not equal but no exchange neccessary
	exg d4,d6		! exchange u and v
	exg d5,d7
	sub.w	d1,d0		! d0 = u.exp - (u.exp - v.exp) = v.exp
	neg.w	d1
	tst.w	d2		! d2.h = u.sign ^ (u.sign ^ v.sign) = v.sign
	bpl 1f
	bchg	#31,d2
1:
	cmp.w	#53,d1		! is u so much bigger that v is not
	bge 7f		! significant ?

	move.w	#10-1,d3	! shift u left up to 10 bits to minimize loss
2:
	add.l	d7,d7
	addx.l	d6,d6
	sub.w	#1,d0		! decrement exponent
	sub.w	#1,d1		! done shifting altogether ?
	dbeq	d3,2b		! loop if still can shift u.mant more
	clr.w	d3
3:
	cmp.w	#16,d1		! see if fast rotate possible
	blt 4f
	or.b	d5,d3		! set rounding bits
	or.b	d2,d3
	sne d2		! "sticky byte"
	move.w	d5,d3
	lsr.w	#8,d3
	move.w	d4,d5		! rotate by swapping register halfs
	swap	d5
	clr.w	d4
	swap	d4
	sub.w	#16,d1
	bra 3b
0:
	lsr.l	#1,d4		! shift v.mant right the rest of the way
	roxr.l	#1,d5		! to line it up with u.mant
	or.b	d3,d2		! set "sticky byte" if necessary
	roxr.w	#1,d3		! shift into rounding bits
4:	dbra	d1,0b		! loop
	and.b	#1,d2		! see if "sticky bit" should be set
	or.b	d2,d3
5:
	tst.w	d2		! are the signs equal ?
	bpl 6f		! yes, no negate necessary

	neg.b	d3		! negate rounding bits and v.mant
	neg.l	d5
	negx.l	d4
6:
	add.l	d5,d7		! u.mant = u.mant + v.mant
	addx.l	d4,d6
	bcs 7f		! need not negate
	tst.w	d2		! opposite signs ?
	bpl 7f		! do not need to negate result

	neg.b	d3		! negate rounding bits and u.mant
	neg.l	d7
	negx.l	d6
	not.l	d2		! switch sign
7:
	movem.l d6-d7,(a1)	! move result on stack
	move.b	d3,d1		! put rounding bits in d1 for .norm8
	swap	d2		! put sign into d2
	jmp .Xnorm8 	! exit via normalising routine
