diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1995-11-14 08:00:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1995-11-14 08:00:00 +0000 |
commit | e7c2a72e2680827d6a733931273a93461c0d8d1b (patch) | |
tree | c9abeda78ef7504062bb2e816bcf3e3c9d680112 /arch/i386/math-emu/reg_div.S | |
parent | ec6044459060a8c9ce7f64405c465d141898548c (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.S | 251 |
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 |