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

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