OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [i386/] [math-emu/] [reg_div.S] - Rev 1765

Compare with Previous | Blame | View Log

        .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,1995                                         |
 |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
 |                       Australia.  E-mail billm@jacobi.maths.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_emu.h"


.text
ENTRY(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    SYMBOL_NAME(denormal_operand)
        orl     %eax,%eax
        jnz     fpu_Arith_exit

xL_arg1_not_denormal:
        cmpl    EXP_UNDER,EXP(%ebx)
        jg      xL_arg2_not_denormal

        call    SYMBOL_NAME(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     SYMBOL_NAME(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    SYMBOL_NAME(real_2op_NaN)
        jmp     LDiv_exit

/* Invalid operations */
L_zero_zero:
L_inf_inf:
        pushl   %edi                    /* Destination */
        call    SYMBOL_NAME(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    SYMBOL_NAME(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    SYMBOL_NAME(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    SYMBOL_NAME(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    SYMBOL_NAME(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    SYMBOL_NAME(CONST_QNaN),%eax
        movl    %eax,(%edi)
        movl    SYMBOL_NAME(CONST_QNaN)+4,%eax
        movl    %eax,SIGL(%edi)
        movl    SYMBOL_NAME(CONST_QNaN)+8,%eax
        movl    %eax,SIGH(%edi)
        jmp     LDiv_exit               /* %eax is nz */
#endif PARANOID

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.