root/arch/i386/math-emu/reg_div.S

/* [previous][next][first][last][top][bottom][index][help] */
   1         .file   "reg_div.S"
   2 /*---------------------------------------------------------------------------+
   3  |  reg_div.S                                                                |
   4  |                                                                           |
   5  | Divide one FPU_REG by another and put the result in a destination FPU_REG.|
   6  |                                                                           |
   7  | Copyright (C) 1992,1993,1994                                              |
   8  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
   9  |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  10  |                                                                           |
  11  | Call from C as:                                                           |
  12  |   void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest,                     |
  13  |                                    unsigned int control_word)             |
  14  |                                                                           |
  15  +---------------------------------------------------------------------------*/
  16 
  17 #include "exception.h"
  18 #include "fpu_asm.h"
  19 
  20 
  21 .text
  22         .align 2
  23 
  24 .globl  _reg_div
  25 _reg_div:
  26         pushl   %ebp
  27         movl    %esp,%ebp
  28 #ifndef NON_REENTRANT_FPU
  29         subl    $28,%esp        /* Needed by divide_kernel */
  30 #endif NON_REENTRANT_FPU
  31 
  32         pushl   %esi
  33         pushl   %edi
  34         pushl   %ebx
  35 
  36         movl    PARAM1,%esi
  37         movl    PARAM2,%ebx
  38         movl    PARAM3,%edi
  39 
  40         movb    TAG(%esi),%al
  41         orb     TAG(%ebx),%al
  42 
  43         jne     L_div_special           /* Not (both numbers TW_Valid) */
  44 
  45 #ifdef DENORM_OPERAND
  46 /* Check for denormals */
  47         cmpl    EXP_UNDER,EXP(%esi)
  48         jg      xL_arg1_not_denormal
  49 
  50         call    _denormal_operand
  51         orl     %eax,%eax
  52         jnz     fpu_Arith_exit
  53 
  54 xL_arg1_not_denormal:
  55         cmpl    EXP_UNDER,EXP(%ebx)
  56         jg      xL_arg2_not_denormal
  57 
  58         call    _denormal_operand
  59         orl     %eax,%eax
  60         jnz     fpu_Arith_exit
  61 
  62 xL_arg2_not_denormal:
  63 #endif DENORM_OPERAND
  64 
  65 /* Both arguments are TW_Valid */
  66         movb    TW_Valid,TAG(%edi)
  67 
  68         movb    SIGN(%esi),%cl
  69         cmpb    %cl,SIGN(%ebx)
  70         setne   (%edi)        /* Set the sign, requires SIGN_NEG=1, SIGN_POS=0 */
  71 
  72         movl    EXP(%esi),%edx
  73         movl    EXP(%ebx),%eax
  74         subl    %eax,%edx
  75         addl    EXP_BIAS,%edx
  76         movl    %edx,EXP(%edi)
  77 
  78         jmp     _divide_kernel
  79 
  80 
  81 /*-----------------------------------------------------------------------*/
  82 L_div_special:
  83         cmpb    TW_NaN,TAG(%esi)        /* A NaN with anything to give NaN */
  84         je      L_arg1_NaN
  85 
  86         cmpb    TW_NaN,TAG(%ebx)        /* A NaN with anything to give NaN */
  87         jne     L_no_NaN_arg
  88 
  89 /* Operations on NaNs */
  90 L_arg1_NaN:
  91 L_arg2_NaN:
  92         pushl   %edi                    /* Destination */
  93         pushl   %esi
  94         pushl   %ebx                    /* Ordering is important here */
  95         call    _real_2op_NaN
  96         jmp     LDiv_exit
  97 
  98 /* Invalid operations */
  99 L_zero_zero:
 100 L_inf_inf:
 101         pushl   %edi                    /* Destination */
 102         call    _arith_invalid          /* 0/0 or Infinity/Infinity */
 103         jmp     LDiv_exit
 104 
 105 L_no_NaN_arg:
 106         cmpb    TW_Infinity,TAG(%esi)
 107         jne     L_arg1_not_inf
 108 
 109         cmpb    TW_Infinity,TAG(%ebx)
 110         je      L_inf_inf               /* invalid operation */
 111 
 112         cmpb    TW_Valid,TAG(%ebx)
 113         je      L_inf_valid
 114 
 115 #ifdef PARANOID
 116         /* arg2 must be zero or valid */
 117         cmpb    TW_Zero,TAG(%ebx)
 118         ja      L_unknown_tags
 119 #endif PARANOID
 120 
 121         /* Note that p16-9 says that infinity/0 returns infinity */
 122         jmp     L_copy_arg1             /* Answer is Inf */
 123 
 124 L_inf_valid:
 125 #ifdef DENORM_OPERAND
 126         cmpl    EXP_UNDER,EXP(%ebx)
 127         jg      L_copy_arg1             /* Answer is Inf */
 128 
 129         call    _denormal_operand
 130         orl     %eax,%eax
 131         jnz     fpu_Arith_exit
 132 #endif DENORM_OPERAND
 133 
 134         jmp     L_copy_arg1             /* Answer is Inf */
 135 
 136 L_arg1_not_inf:
 137         cmpb    TW_Zero,TAG(%ebx)       /* Priority to div-by-zero error */
 138         jne     L_arg2_not_zero
 139 
 140         cmpb    TW_Zero,TAG(%esi)
 141         je      L_zero_zero             /* invalid operation */
 142 
 143 #ifdef PARANOID
 144         /* arg1 must be valid */
 145         cmpb    TW_Valid,TAG(%esi)
 146         ja      L_unknown_tags
 147 #endif PARANOID
 148 
 149 /* Division by zero error */
 150         pushl   %edi                    /* destination */
 151         movb    SIGN(%esi),%al
 152         xorb    SIGN(%ebx),%al
 153         pushl   %eax                    /* lower 8 bits have the sign */
 154         call    _divide_by_zero
 155         jmp     LDiv_exit
 156 
 157 L_arg2_not_zero:
 158         cmpb    TW_Infinity,TAG(%ebx)
 159         jne     L_arg2_not_inf
 160 
 161 #ifdef DENORM_OPERAND
 162         cmpb    TW_Valid,TAG(%esi)
 163         jne     L_return_zero
 164 
 165         cmpl    EXP_UNDER,EXP(%esi)
 166         jg      L_return_zero           /* Answer is zero */
 167 
 168         call    _denormal_operand
 169         orl     %eax,%eax
 170         jnz     fpu_Arith_exit
 171 #endif DENORM_OPERAND
 172 
 173         jmp     L_return_zero           /* Answer is zero */
 174 
 175 L_arg2_not_inf:
 176 
 177 #ifdef PARANOID
 178         cmpb    TW_Zero,TAG(%esi)
 179         jne     L_unknown_tags
 180 #endif PARANOID
 181 
 182         /* arg1 is zero, arg2 is not Infinity or a NaN */
 183 
 184 #ifdef DENORM_OPERAND
 185         cmpl    EXP_UNDER,EXP(%ebx)
 186         jg      L_copy_arg1             /* Answer is zero */
 187 
 188         call    _denormal_operand
 189         orl     %eax,%eax
 190         jnz     fpu_Arith_exit
 191 #endif DENORM_OPERAND
 192 
 193 L_copy_arg1:
 194         movb    TAG(%esi),%ax
 195         movb    %ax,TAG(%edi)
 196         movl    EXP(%esi),%eax
 197         movl    %eax,EXP(%edi)
 198         movl    SIGL(%esi),%eax
 199         movl    %eax,SIGL(%edi)
 200         movl    SIGH(%esi),%eax
 201         movl    %eax,SIGH(%edi)
 202 
 203 LDiv_set_result_sign:
 204         movb    SIGN(%esi),%cl
 205         cmpb    %cl,SIGN(%ebx)
 206         jne     LDiv_negative_result
 207 
 208         movb    SIGN_POS,SIGN(%edi)
 209         xorl    %eax,%eax               /* Valid result */
 210         jmp     LDiv_exit
 211 
 212 LDiv_negative_result:
 213         movb    SIGN_NEG,SIGN(%edi)
 214         xorl    %eax,%eax               /* Valid result */
 215 
 216 LDiv_exit:
 217 #ifndef NON_REENTRANT_FPU
 218         leal    -40(%ebp),%esp
 219 #else
 220         leal    -12(%ebp),%esp
 221 #endif NON_REENTRANT_FPU
 222 
 223         popl    %ebx
 224         popl    %edi
 225         popl    %esi
 226         leave
 227         ret
 228 
 229 
 230 L_return_zero:
 231         xorl    %eax,%eax
 232         movl    %eax,SIGH(%edi)
 233         movl    %eax,SIGL(%edi)
 234         movl    EXP_UNDER,EXP(%edi)
 235         movb    TW_Zero,TAG(%edi)
 236         jmp     LDiv_set_result_sign
 237 
 238 #ifdef PARANOID
 239 L_unknown_tags:
 240         pushl   EX_INTERNAL | 0x208
 241         call    EXCEPTION
 242 
 243         /* Generate a NaN for unknown tags */
 244         movl    _CONST_QNaN,%eax
 245         movl    %eax,(%edi)
 246         movl    _CONST_QNaN+4,%eax
 247         movl    %eax,SIGL(%edi)
 248         movl    _CONST_QNaN+8,%eax
 249         movl    %eax,SIGH(%edi)
 250         jmp     LDiv_exit               /* %eax is nz */
 251 #endif PARANOID

/* [previous][next][first][last][top][bottom][index][help] */