149 lines
		
	
	
	
		
			3.6 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
		
		
			
		
	
	
			149 lines
		
	
	
	
		
			3.6 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
|   | 	.file	"reg_u_mul.S" | ||
|  | /*---------------------------------------------------------------------------+ | ||
|  |  |  reg_u_mul.S                                                              | | ||
|  |  |                                                                           | | ||
|  |  | Core multiplication routine                                               | | ||
|  |  |                                                                           | | ||
|  |  | Copyright (C) 1992,1993,1995,1997                                         | | ||
|  |  |                  W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | | ||
|  |  |                  E-mail   billm@suburbia.net                              |
 | ||
|  |  |                                                                           | | ||
|  |  |                                                                           | | ||
|  |  +---------------------------------------------------------------------------*/ | ||
|  | 
 | ||
|  | /*---------------------------------------------------------------------------+ | ||
|  |  |   Basic multiplication routine.                                           | | ||
|  |  |   Does not check the resulting exponent for overflow/underflow            | | ||
|  |  |                                                                           | | ||
|  |  |   FPU_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw);         |
 | ||
|  |  |                                                                           | | ||
|  |  |   Internal working is at approx 128 bits.                                 | | ||
|  |  |   Result is rounded to nearest 53 or 64 bits, using "nearest or even".    | | ||
|  |  +---------------------------------------------------------------------------*/ | ||
|  | 
 | ||
|  | #include "exception.h" | ||
|  | #include "fpu_emu.h" | ||
|  | #include "control_w.h" | ||
|  | 
 | ||
|  | 
 | ||
|  | 
 | ||
|  | #ifndef NON_REENTRANT_FPU | ||
|  | /*  Local storage on the stack: */ | ||
|  | #define FPU_accum_0	-4(%ebp)	/* ms word */ | ||
|  | #define FPU_accum_1	-8(%ebp) | ||
|  | 
 | ||
|  | #else | ||
|  | /*  Local storage in a static area: */ | ||
|  | .data | ||
|  | 	.align 4,0 | ||
|  | FPU_accum_0: | ||
|  | 	.long	0
 | ||
|  | FPU_accum_1: | ||
|  | 	.long	0
 | ||
|  | #endif /* NON_REENTRANT_FPU */ | ||
|  | 
 | ||
|  | 
 | ||
|  | .text | ||
|  | ENTRY(FPU_u_mul) | ||
|  | 	pushl	%ebp | ||
|  | 	movl	%esp,%ebp | ||
|  | #ifndef NON_REENTRANT_FPU | ||
|  | 	subl	$8,%esp | ||
|  | #endif /* NON_REENTRANT_FPU */  | ||
|  | 
 | ||
|  | 	pushl	%esi | ||
|  | 	pushl	%edi | ||
|  | 	pushl	%ebx | ||
|  | 
 | ||
|  | 	movl	PARAM1,%esi | ||
|  | 	movl	PARAM2,%edi | ||
|  | 
 | ||
|  | #ifdef PARANOID | ||
|  | 	testl	$0x80000000,SIGH(%esi) | ||
|  | 	jz	L_bugged | ||
|  | 	testl	$0x80000000,SIGH(%edi) | ||
|  | 	jz	L_bugged | ||
|  | #endif /* PARANOID */ | ||
|  | 
 | ||
|  | 	xorl	%ecx,%ecx | ||
|  | 	xorl	%ebx,%ebx | ||
|  | 
 | ||
|  | 	movl	SIGL(%esi),%eax | ||
|  | 	mull	SIGL(%edi) | ||
|  | 	movl	%eax,FPU_accum_0 | ||
|  | 	movl	%edx,FPU_accum_1 | ||
|  | 
 | ||
|  | 	movl	SIGL(%esi),%eax | ||
|  | 	mull	SIGH(%edi) | ||
|  | 	addl	%eax,FPU_accum_1 | ||
|  | 	adcl	%edx,%ebx | ||
|  | /*	adcl	$0,%ecx		// overflow here is not possible */ | ||
|  | 
 | ||
|  | 	movl	SIGH(%esi),%eax | ||
|  | 	mull	SIGL(%edi) | ||
|  | 	addl	%eax,FPU_accum_1 | ||
|  | 	adcl	%edx,%ebx | ||
|  | 	adcl	$0,%ecx | ||
|  | 
 | ||
|  | 	movl	SIGH(%esi),%eax | ||
|  | 	mull	SIGH(%edi) | ||
|  | 	addl	%eax,%ebx | ||
|  | 	adcl	%edx,%ecx | ||
|  | 
 | ||
|  | 	/* Get the sum of the exponents. */ | ||
|  | 	movl	PARAM6,%eax | ||
|  | 	subl	EXP_BIAS-1,%eax | ||
|  | 
 | ||
|  | 	/* Two denormals can cause an exponent underflow */ | ||
|  | 	cmpl	EXP_WAY_UNDER,%eax | ||
|  | 	jg	Exp_not_underflow | ||
|  | 
 | ||
|  | 	/* Set to a really low value allow correct handling */ | ||
|  | 	movl	EXP_WAY_UNDER,%eax | ||
|  | 
 | ||
|  | Exp_not_underflow: | ||
|  | 
 | ||
|  | /*  Have now finished with the sources */ | ||
|  | 	movl	PARAM3,%edi	/* Point to the destination */ | ||
|  | 	movw	%ax,EXP(%edi) | ||
|  | 
 | ||
|  | /*  Now make sure that the result is normalized */ | ||
|  | 	testl	$0x80000000,%ecx | ||
|  | 	jnz	LResult_Normalised | ||
|  | 
 | ||
|  | 	/* Normalize by shifting left one bit */ | ||
|  | 	shll	$1,FPU_accum_0 | ||
|  | 	rcll	$1,FPU_accum_1 | ||
|  | 	rcll	$1,%ebx | ||
|  | 	rcll	$1,%ecx | ||
|  | 	decw	EXP(%edi) | ||
|  | 
 | ||
|  | LResult_Normalised: | ||
|  | 	movl	FPU_accum_0,%eax | ||
|  | 	movl	FPU_accum_1,%edx | ||
|  | 	orl	%eax,%eax | ||
|  | 	jz	L_extent_zero | ||
|  | 
 | ||
|  | 	orl	$1,%edx | ||
|  | 
 | ||
|  | L_extent_zero: | ||
|  | 	movl	%ecx,%eax | ||
|  | 	jmp	fpu_reg_round | ||
|  | 
 | ||
|  | 
 | ||
|  | #ifdef PARANOID | ||
|  | L_bugged: | ||
|  | 	pushl	EX_INTERNAL|0x205 | ||
|  | 	call	EXCEPTION | ||
|  | 	pop	%ebx | ||
|  | 	jmp	L_exit | ||
|  | 
 | ||
|  | L_exit: | ||
|  | 	popl	%ebx | ||
|  | 	popl	%edi | ||
|  | 	popl	%esi | ||
|  | 	leave | ||
|  | 	ret | ||
|  | #endif /* PARANOID */  | ||
|  | 
 |