 | add exponent to floating point number
 | C Interface
 | double ldexp(double value, unsigned int exp);
 | returns value * 2**exp
 | (int is 16 bits if -mshort, 32 bits if !-mshort)
 |-----------------------------------------------------------------------------
 | 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	added support for denormalized numbers			-kub-, 01/90
 |  #3  ported to gcc  ++jrb  04/90
 |  #4  handle exponent overflow when ints are 32 bits		-kub-, 04/90
 |-----------------------------------------------------------------------------

	.text; .even
	.globl _ldexp
	.globl __infinitydf
_ldexp:
	lea	sp@(4),a1
	moveml	d2-d7,sp@-	| save d2-d7

	movew	a1@,d0		| extract value.exp
	movew	d0,d2		| extract value.sign
	lsrw	#4,d0
	andw	#0x7ff,d0	| kill sign bit

	andw	#0x0f,a1@	| remove exponent from value.mantissa
	tstw	d0		| check for zero exponent - no leading 1
	beq	0f
	orw	#0x10,a1@	| restore implied leading 1
	bra	1f
0:	addw	#1,d0
1:
#ifdef __MSHORT__
	addw	a1@(8),d0	| add in exponent
	extl	d0
#else
	extl	d0
	addl	a1@(8),d0	| add in exponent
#endif
	cmpl	#-53,d0		| hmm. works only if 1 in implied position...
	ble	retz		| range error - underflow
	cmpl	#2047,d0
	bge	rangerr		| range error - overflow

	clrw	d1		| zero rounding bits
	moveml	a1@,d4-d5	| value into d4,d5
	jmp	norm_df		| norm_df will pop d2-d7 and rts


	.globl	_errno		| from <errno.h>
ERANGE	=	34

retz:
#ifdef __MSHORT__
	movew	#ERANGE,_errno	| set errno
#else
	movel	#ERANGE,_errno	| set errno
#endif
	moveq	#0,d0		| zero return value
	moveq	#0,d1
	jra	L0

rangerr:
#ifdef __MSHORT__
	movew	#ERANGE,_errno	| set errno
#else
	movel	#ERANGE,_errno	| set errno
#endif
	moveml	__infinitydf,d0-d1 | return HUGE_VAL (same as in <math.h>)
	andw	#0x8000,d2	| get sign bit of argument
	swap	d2
	clrw	d2
	orl	d2,d0
L0:
	moveml	sp@+,d2-d7	| pop saved reggies
	rts
