summaryrefslogtreecommitdiffstats
path: root/arch/i386/math-emu/reg_div.S
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
committer <ralf@linux-mips.org>1995-11-14 08:00:00 +0000
commite7c2a72e2680827d6a733931273a93461c0d8d1b (patch)
treec9abeda78ef7504062bb2e816bcf3e3c9d680112 /arch/i386/math-emu/reg_div.S
parentec6044459060a8c9ce7f64405c465d141898548c (diff)
Import of Linux/MIPS 1.3.0
Diffstat (limited to 'arch/i386/math-emu/reg_div.S')
-rw-r--r--arch/i386/math-emu/reg_div.S251
1 files changed, 251 insertions, 0 deletions
diff --git a/arch/i386/math-emu/reg_div.S b/arch/i386/math-emu/reg_div.S
new file mode 100644
index 000000000..2fbc5f7c4
--- /dev/null
+++ b/arch/i386/math-emu/reg_div.S
@@ -0,0 +1,251 @@
+ .file "reg_div.S"
+/*---------------------------------------------------------------------------+
+ | reg_div.S |
+ | |
+ | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
+ | |
+ | Copyright (C) 1992,1993,1994 |
+ | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, |
+ | Australia. E-mail billm@vaxc.cc.monash.edu.au |
+ | |
+ | Call from C as: |
+ | void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest, |
+ | unsigned int control_word) |
+ | |
+ +---------------------------------------------------------------------------*/
+
+#include "exception.h"
+#include "fpu_asm.h"
+
+
+.text
+ .align 2
+
+.globl _reg_div
+_reg_div:
+ pushl %ebp
+ movl %esp,%ebp
+#ifndef NON_REENTRANT_FPU
+ subl $28,%esp /* Needed by divide_kernel */
+#endif NON_REENTRANT_FPU
+
+ pushl %esi
+ pushl %edi
+ pushl %ebx
+
+ movl PARAM1,%esi
+ movl PARAM2,%ebx
+ movl PARAM3,%edi
+
+ movb TAG(%esi),%al
+ orb TAG(%ebx),%al
+
+ jne L_div_special /* Not (both numbers TW_Valid) */
+
+#ifdef DENORM_OPERAND
+/* Check for denormals */
+ cmpl EXP_UNDER,EXP(%esi)
+ jg xL_arg1_not_denormal
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz fpu_Arith_exit
+
+xL_arg1_not_denormal:
+ cmpl EXP_UNDER,EXP(%ebx)
+ jg xL_arg2_not_denormal
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz fpu_Arith_exit
+
+xL_arg2_not_denormal:
+#endif DENORM_OPERAND
+
+/* Both arguments are TW_Valid */
+ movb TW_Valid,TAG(%edi)
+
+ movb SIGN(%esi),%cl
+ cmpb %cl,SIGN(%ebx)
+ setne (%edi) /* Set the sign, requires SIGN_NEG=1, SIGN_POS=0 */
+
+ movl EXP(%esi),%edx
+ movl EXP(%ebx),%eax
+ subl %eax,%edx
+ addl EXP_BIAS,%edx
+ movl %edx,EXP(%edi)
+
+ jmp _divide_kernel
+
+
+/*-----------------------------------------------------------------------*/
+L_div_special:
+ cmpb TW_NaN,TAG(%esi) /* A NaN with anything to give NaN */
+ je L_arg1_NaN
+
+ cmpb TW_NaN,TAG(%ebx) /* A NaN with anything to give NaN */
+ jne L_no_NaN_arg
+
+/* Operations on NaNs */
+L_arg1_NaN:
+L_arg2_NaN:
+ pushl %edi /* Destination */
+ pushl %esi
+ pushl %ebx /* Ordering is important here */
+ call _real_2op_NaN
+ jmp LDiv_exit
+
+/* Invalid operations */
+L_zero_zero:
+L_inf_inf:
+ pushl %edi /* Destination */
+ call _arith_invalid /* 0/0 or Infinity/Infinity */
+ jmp LDiv_exit
+
+L_no_NaN_arg:
+ cmpb TW_Infinity,TAG(%esi)
+ jne L_arg1_not_inf
+
+ cmpb TW_Infinity,TAG(%ebx)
+ je L_inf_inf /* invalid operation */
+
+ cmpb TW_Valid,TAG(%ebx)
+ je L_inf_valid
+
+#ifdef PARANOID
+ /* arg2 must be zero or valid */
+ cmpb TW_Zero,TAG(%ebx)
+ ja L_unknown_tags
+#endif PARANOID
+
+ /* Note that p16-9 says that infinity/0 returns infinity */
+ jmp L_copy_arg1 /* Answer is Inf */
+
+L_inf_valid:
+#ifdef DENORM_OPERAND
+ cmpl EXP_UNDER,EXP(%ebx)
+ jg L_copy_arg1 /* Answer is Inf */
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz fpu_Arith_exit
+#endif DENORM_OPERAND
+
+ jmp L_copy_arg1 /* Answer is Inf */
+
+L_arg1_not_inf:
+ cmpb TW_Zero,TAG(%ebx) /* Priority to div-by-zero error */
+ jne L_arg2_not_zero
+
+ cmpb TW_Zero,TAG(%esi)
+ je L_zero_zero /* invalid operation */
+
+#ifdef PARANOID
+ /* arg1 must be valid */
+ cmpb TW_Valid,TAG(%esi)
+ ja L_unknown_tags
+#endif PARANOID
+
+/* Division by zero error */
+ pushl %edi /* destination */
+ movb SIGN(%esi),%al
+ xorb SIGN(%ebx),%al
+ pushl %eax /* lower 8 bits have the sign */
+ call _divide_by_zero
+ jmp LDiv_exit
+
+L_arg2_not_zero:
+ cmpb TW_Infinity,TAG(%ebx)
+ jne L_arg2_not_inf
+
+#ifdef DENORM_OPERAND
+ cmpb TW_Valid,TAG(%esi)
+ jne L_return_zero
+
+ cmpl EXP_UNDER,EXP(%esi)
+ jg L_return_zero /* Answer is zero */
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz fpu_Arith_exit
+#endif DENORM_OPERAND
+
+ jmp L_return_zero /* Answer is zero */
+
+L_arg2_not_inf:
+
+#ifdef PARANOID
+ cmpb TW_Zero,TAG(%esi)
+ jne L_unknown_tags
+#endif PARANOID
+
+ /* arg1 is zero, arg2 is not Infinity or a NaN */
+
+#ifdef DENORM_OPERAND
+ cmpl EXP_UNDER,EXP(%ebx)
+ jg L_copy_arg1 /* Answer is zero */
+
+ call _denormal_operand
+ orl %eax,%eax
+ jnz fpu_Arith_exit
+#endif DENORM_OPERAND
+
+L_copy_arg1:
+ movb TAG(%esi),%ax
+ movb %ax,TAG(%edi)
+ movl EXP(%esi),%eax
+ movl %eax,EXP(%edi)
+ movl SIGL(%esi),%eax
+ movl %eax,SIGL(%edi)
+ movl SIGH(%esi),%eax
+ movl %eax,SIGH(%edi)
+
+LDiv_set_result_sign:
+ movb SIGN(%esi),%cl
+ cmpb %cl,SIGN(%ebx)
+ jne LDiv_negative_result
+
+ movb SIGN_POS,SIGN(%edi)
+ xorl %eax,%eax /* Valid result */
+ jmp LDiv_exit
+
+LDiv_negative_result:
+ movb SIGN_NEG,SIGN(%edi)
+ xorl %eax,%eax /* Valid result */
+
+LDiv_exit:
+#ifndef NON_REENTRANT_FPU
+ leal -40(%ebp),%esp
+#else
+ leal -12(%ebp),%esp
+#endif NON_REENTRANT_FPU
+
+ popl %ebx
+ popl %edi
+ popl %esi
+ leave
+ ret
+
+
+L_return_zero:
+ xorl %eax,%eax
+ movl %eax,SIGH(%edi)
+ movl %eax,SIGL(%edi)
+ movl EXP_UNDER,EXP(%edi)
+ movb TW_Zero,TAG(%edi)
+ jmp LDiv_set_result_sign
+
+#ifdef PARANOID
+L_unknown_tags:
+ pushl EX_INTERNAL | 0x208
+ call EXCEPTION
+
+ /* Generate a NaN for unknown tags */
+ movl _CONST_QNaN,%eax
+ movl %eax,(%edi)
+ movl _CONST_QNaN+4,%eax
+ movl %eax,SIGL(%edi)
+ movl _CONST_QNaN+8,%eax
+ movl %eax,SIGH(%edi)
+ jmp LDiv_exit /* %eax is nz */
+#endif PARANOID