⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wm_sqrt.s

📁 freebsd v4.4内核源码
💻 S
字号:
	.file	"wm_sqrt.S"/* *  wm_sqrt.S * * Fixed point arithmetic square root evaluation. * * Call from C as: *   void wm_sqrt(FPU_REG *n, unsigned int control_word) * * * Copyright (C) 1992,1993,1994 *                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163, *                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au * All rights reserved. * * This copyright notice covers the redistribution and use of the * FPU emulator developed by W. Metzenthen. It covers only its use * in the 386BSD, FreeBSD and NetBSD operating systems. Any other * use is not permitted under this copyright. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must include information specifying *    that source code for the emulator is freely available and include *    either: *      a) an offer to provide the source code for a nominal distribution *         fee, or *      b) list at least two alternative methods whereby the source *         can be obtained, e.g. a publically accessible bulletin board *         and an anonymous ftp site from which the software can be *         downloaded. * 3. All advertising materials specifically mentioning features or use of *    this emulator must acknowledge that it was developed by W. Metzenthen. * 4. The name of W. Metzenthen may not be used to endorse or promote *    products derived from this software without specific prior written *    permission. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * * The purpose of this copyright, based upon the Berkeley copyright, is to * ensure that the covered software remains freely available to everyone. * * The software (with necessary differences) is also available, but under * the terms of the GNU copyleft, for the Linux operating system and for * the djgpp ms-dos extender. * * W. Metzenthen   June 1994. * * * $FreeBSD: src/sys/gnu/i386/fpemul/wm_sqrt.s,v 1.4.2.1 1999/09/05 08:10:00 peter Exp $ * *//*---------------------------------------------------------------------------+ |  wm_sqrt(FPU_REG *n, unsigned int control_word)                           | |    returns the square root of n in n.                                     | |                                                                           | |  Use Newton's method to compute the square root of a number, which must   | |  be in the range  [1.0 .. 4.0),  to 64 bits accuracy.                     | |  Does not check the sign or tag of the argument.                          | |  Sets the exponent, but not the sign or tag of the result.                | |                                                                           | |  The guess is kept in %esi:%edi                                           | +---------------------------------------------------------------------------*/#include <gnu/i386/fpemul/exception.h>#include <gnu/i386/fpemul/fpu_asm.h>.data/*	Local storage: */	.align 4,0accum_3:	.long	0		/* ms word */accum_2:	.long	0accum_1:	.long	0accum_0:	.long	0/* The de-normalised argument://                  sq_2                  sq_1              sq_0//        b b b b b b b ... b b b   b b b .... b b b   b 0 0 0 ... 0//           ^ binary point here */fsqrt_arg_2:	.long	0		/* ms word */fsqrt_arg_1:	.long	0fsqrt_arg_0:	.long	0		/* ls word, at most the ms bit is set */.text	.align 2,144.globl _wm_sqrt_wm_sqrt:	pushl	%ebp	movl	%esp,%ebp	pushl	%esi	pushl	%edi	pushl	%ebx	movl	PARAM1,%esi	movl	SIGH(%esi),%eax	movl	SIGL(%esi),%ecx	xorl	%edx,%edx/* We use a rough linear estimate for the first guess.. */	cmpl	EXP_BIAS,EXP(%esi)	jnz	sqrt_arg_ge_2	shrl	$1,%eax			/* arg is in the range  [1.0 .. 2.0) */	rcrl	$1,%ecx	rcrl	$1,%edxsqrt_arg_ge_2:/* From here on, n is never accessed directly again until it is// replaced by the answer. */	movl	%eax,fsqrt_arg_2		/* ms word of n */	movl	%ecx,fsqrt_arg_1	movl	%edx,fsqrt_arg_0/* Make a linear first estimate */	shrl	$1,%eax	addl	$0x40000000,%eax	movl	$0xaaaaaaaa,%ecx	mull	%ecx	shll	%edx			/* max result was 7fff... */	testl	$0x80000000,%edx	/* but min was 3fff... */	jnz	sqrt_prelim_no_adjust	movl	$0x80000000,%edx	/* round up */sqrt_prelim_no_adjust:	movl	%edx,%esi	/* Our first guess *//* We have now computed (approx)   (2 + x) / 3, which forms the basis   for a few iterations of Newton's method */	movl	fsqrt_arg_2,%ecx	/* ms word *//* From our initial estimate, three iterations are enough to get us// to 30 bits or so. This will then allow two iterations at better// precision to complete the process.// Compute  (g + n/g)/2  at each iteration (g is the guess). */	shrl	%ecx		/* Doing this first will prevent a divide */				/* overflow later. */	movl	%ecx,%edx	/* msw of the arg / 2 */	divl	%esi		/* current estimate */	shrl	%esi		/* divide by 2 */	addl	%eax,%esi	/* the new estimate */	movl	%ecx,%edx	divl	%esi	shrl	%esi	addl	%eax,%esi	movl	%ecx,%edx	divl	%esi	shrl	%esi	addl	%eax,%esi/* Now that an estimate accurate to about 30 bits has been obtained (in %esi),// we improve it to 60 bits or so.// The strategy from now on is to compute new estimates from//      guess := guess + (n - guess^2) / (2 * guess) *//* First, find the square of the guess */	movl	%esi,%eax	mull	%esi/* guess^2 now in %edx:%eax */	movl	fsqrt_arg_1,%ecx	subl	%ecx,%eax	movl	fsqrt_arg_2,%ecx	/* ms word of normalized n */	sbbl	%ecx,%edx	jnc	sqrt_stage_2_positive/* subtraction gives a negative result// negate the result before division */	notl	%edx	notl	%eax	addl	$1,%eax	adcl	$0,%edx	divl	%esi	movl	%eax,%ecx	movl	%edx,%eax	divl	%esi	jmp	sqrt_stage_2_finishsqrt_stage_2_positive:	divl	%esi	movl	%eax,%ecx	movl	%edx,%eax	divl	%esi	notl	%ecx	notl	%eax	addl	$1,%eax	adcl	$0,%ecxsqrt_stage_2_finish:	sarl	$1,%ecx		/* divide by 2 */	rcrl	$1,%eax	/* Form the new estimate in %esi:%edi */	movl	%eax,%edi	addl	%ecx,%esi	jnz	sqrt_stage_2_done	/* result should be [1..2) */#ifdef PARANOID/* It should be possible to get here only if the arg is ffff....ffff*/	cmp	$0xffffffff,fsqrt_arg_1	jnz	sqrt_stage_2_error#endif PARANOID/* The best rounded result.*/	xorl	%eax,%eax	decl	%eax	movl	%eax,%edi	movl	%eax,%esi	movl	$0x7fffffff,%eax	jmp	sqrt_round_result#ifdef PARANOIDsqrt_stage_2_error:	pushl	EX_INTERNAL|0x213	call	EXCEPTION#endif PARANOIDsqrt_stage_2_done:/* Now the square root has been computed to better than 60 bits *//* Find the square of the guess*/	movl	%edi,%eax		/* ls word of guess*/	mull	%edi	movl	%edx,accum_1	movl	%esi,%eax	mull	%esi	movl	%edx,accum_3	movl	%eax,accum_2	movl	%edi,%eax	mull	%esi	addl	%eax,accum_1	adcl	%edx,accum_2	adcl	$0,accum_3/*	movl	%esi,%eax*//*	mull	%edi*/	addl	%eax,accum_1	adcl	%edx,accum_2	adcl	$0,accum_3/* guess^2 now in accum_3:accum_2:accum_1*/	movl	fsqrt_arg_0,%eax		/* get normalized n*/	subl	%eax,accum_1	movl	fsqrt_arg_1,%eax	sbbl	%eax,accum_2	movl	fsqrt_arg_2,%eax		/* ms word of normalized n*/	sbbl	%eax,accum_3	jnc	sqrt_stage_3_positive/* subtraction gives a negative result*//* negate the result before division */	notl	accum_1	notl	accum_2	notl	accum_3	addl	$1,accum_1	adcl	$0,accum_2#ifdef PARANOID	adcl	$0,accum_3	/* This must be zero */	jz	sqrt_stage_3_no_errorsqrt_stage_3_error:	pushl	EX_INTERNAL|0x207	call	EXCEPTIONsqrt_stage_3_no_error:#endif PARANOID	movl	accum_2,%edx	movl	accum_1,%eax	divl	%esi	movl	%eax,%ecx	movl	%edx,%eax	divl	%esi	sarl	$1,%ecx		/ divide by 2*/	rcrl	$1,%eax	/* prepare to round the result*/	addl	%ecx,%edi	adcl	$0,%esi	jmp	sqrt_stage_3_finishedsqrt_stage_3_positive:	movl	accum_2,%edx	movl	accum_1,%eax	divl	%esi	movl	%eax,%ecx	movl	%edx,%eax	divl	%esi	sarl	$1,%ecx		/* divide by 2*/	rcrl	$1,%eax	/* prepare to round the result*/	notl	%eax		/* Negate the correction term*/	notl	%ecx	addl	$1,%eax	adcl	$0,%ecx		/* carry here ==> correction == 0*/	adcl	$0xffffffff,%esi	addl	%ecx,%edi	adcl	$0,%esisqrt_stage_3_finished:/* The result in %esi:%edi:%esi should be good to about 90 bits here,// and the rounding information here does not have sufficient accuracy// in a few rare cases. */	cmpl	$0xffffffe0,%eax	ja	sqrt_near_exact_x	cmpl	$0x00000020,%eax	jb	sqrt_near_exact	cmpl	$0x7fffffe0,%eax	jb	sqrt_round_result	cmpl	$0x80000020,%eax	jb	sqrt_get_more_precisionsqrt_round_result:/* Set up for rounding operations*/	movl	%eax,%edx	movl	%esi,%eax	movl	%edi,%ebx	movl	PARAM1,%edi	movl	EXP_BIAS,EXP(%edi)	/* Result is in  [1.0 .. 2.0)*/	movl	PARAM2,%ecx	jmp	FPU_round_sqrtsqrt_near_exact_x:/* First, the estimate must be rounded up.*/	addl	$1,%edi	adcl	$0,%esisqrt_near_exact:/* This is an easy case because x^1/2 is monotonic.// We need just find the square of our estimate, compare it// with the argument, and deduce whether our estimate is// above, below, or exact. We use the fact that the estimate// is known to be accurate to about 90 bits. */	movl	%edi,%eax		/* ls word of guess*/	mull	%edi	movl	%edx,%ebx		/* 2nd ls word of square*/	movl	%eax,%ecx		/* ls word of square*/	movl	%edi,%eax	mull	%esi	addl	%eax,%ebx	addl	%eax,%ebx#ifdef PARANOID	cmp	$0xffffffb0,%ebx	jb	sqrt_near_exact_ok	cmp	$0x00000050,%ebx	ja	sqrt_near_exact_ok	pushl	EX_INTERNAL|0x214	call	EXCEPTIONsqrt_near_exact_ok:#endif PARANOID	or	%ebx,%ebx	js	sqrt_near_exact_small	jnz	sqrt_near_exact_large	or	%ebx,%edx	jnz	sqrt_near_exact_large/* Our estimate is exactly the right answer*/	xorl	%eax,%eax	jmp	sqrt_round_resultsqrt_near_exact_small:/* Our estimate is too small*/	movl	$0x000000ff,%eax	jmp	sqrt_round_result	sqrt_near_exact_large:/* Our estimate is too large, we need to decrement it*/	subl	$1,%edi	sbbl	$0,%esi	movl	$0xffffff00,%eax	jmp	sqrt_round_resultsqrt_get_more_precision:/* This case is almost the same as the above, except we start*//* with an extra bit of precision in the estimate.*/	stc			/* The extra bit.*/	rcll	$1,%edi		/* Shift the estimate left one bit*/	rcll	$1,%esi	movl	%edi,%eax		/* ls word of guess*/	mull	%edi	movl	%edx,%ebx		/* 2nd ls word of square*/	movl	%eax,%ecx		/* ls word of square*/	movl	%edi,%eax	mull	%esi	addl	%eax,%ebx	addl	%eax,%ebx/* Put our estimate back to its original value*/	stc			/* The ms bit.*/	rcrl	$1,%esi		/* Shift the estimate left one bit*/	rcrl	$1,%edi#ifdef PARANOID	cmp	$0xffffff60,%ebx	jb	sqrt_more_prec_ok	cmp	$0x000000a0,%ebx	ja	sqrt_more_prec_ok	pushl	EX_INTERNAL|0x215	call	EXCEPTIONsqrt_more_prec_ok:#endif PARANOID	or	%ebx,%ebx	js	sqrt_more_prec_small	jnz	sqrt_more_prec_large	or	%ebx,%ecx	jnz	sqrt_more_prec_large/* Our estimate is exactly the right answer*/	movl	$0x80000000,%eax	jmp	sqrt_round_resultsqrt_more_prec_small:/* Our estimate is too small*/	movl	$0x800000ff,%eax	jmp	sqrt_round_result	sqrt_more_prec_large:/* Our estimate is too large*/	movl	$0x7fffff00,%eax	jmp	sqrt_round_result

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -