root/kernel/FPU-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                                                   |
   8  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
   9  |                       Australia.  E-mail apm233m@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 .text
  21         .align 2
  22 
  23 .globl  _reg_div
  24 _reg_div:
  25         pushl   %ebp
  26         movl    %esp,%ebp
  27 
  28         pushl   %esi
  29         pushl   %edi
  30         pushl   %ebx
  31 
  32         movl    PARAM1,%esi
  33         movl    PARAM2,%ebx
  34         movl    PARAM3,%edi
  35 
  36         movb    TAG(%esi),%al
  37         orb     TAG(%ebx),%al
  38 
  39         jne     L_div_special           // Not (both numbers TW_Valid)
  40 
  41 #ifdef DENORM_OPERAND
  42 // Check for denormals
  43         cmpl    EXP_UNDER,EXP(%esi)
  44         jg      xL_arg1_not_denormal
  45 
  46         call    _denormal_operand
  47         orl     %eax,%eax
  48         jnz     FPU_Arith_exit
  49 
  50 xL_arg1_not_denormal:
  51         cmpl    EXP_UNDER,EXP(%ebx)
  52         jg      xL_arg2_not_denormal
  53 
  54         call    _denormal_operand
  55         orl     %eax,%eax
  56         jnz     FPU_Arith_exit
  57 
  58 xL_arg2_not_denormal:
  59 #endif DENORM_OPERAND
  60 
  61 // Both arguments are TW_Valid
  62         movb    TW_Valid,TAG(%edi)
  63 
  64         movb    SIGN(%esi),%cl
  65         cmpb    %cl,SIGN(%ebx)
  66         setne   (%edi)        // Set the sign, requires SIGN_NEG=1, SIGN_POS=0
  67 
  68         movl    EXP(%esi),%edx
  69         movl    EXP(%ebx),%eax
  70         subl    %eax,%edx
  71         addl    EXP_BIAS,%edx
  72         movl    %edx,EXP(%edi)
  73 
  74         jmp     _divide_kernel
  75 
  76 
  77 /*-----------------------------------------------------------------------*/
  78 L_div_special:
  79         cmpb    TW_NaN,TAG(%esi)        // A NaN with anything to give NaN
  80         je      L_arg1_NaN
  81 
  82         cmpb    TW_NaN,TAG(%ebx)        // A NaN with anything to give NaN
  83         jne     L_no_NaN_arg
  84 
  85 // Operations on NaNs
  86 L_arg1_NaN:
  87 L_arg2_NaN:
  88         pushl   %edi                    // Destination
  89 //      pushl   %ebx
  90         pushl   %esi
  91         pushl   %ebx                    // Ordering is important here
  92         call    _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    _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    _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    _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    _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    _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         leal    -12(%ebp),%esp
 215 
 216         popl    %ebx
 217         popl    %edi
 218         popl    %esi
 219         leave
 220         ret
 221 
 222 
 223 L_return_zero:
 224         xorl    %eax,%eax
 225         movl    %eax,SIGH(%edi)
 226         movl    %eax,SIGL(%edi)
 227         movl    EXP_UNDER,EXP(%edi)
 228         movb    TW_Zero,TAG(%edi)
 229         jmp     LDiv_set_result_sign
 230 
 231 #ifdef PARANOID
 232 L_unknown_tags:
 233         push    EX_INTERNAL | 0x208
 234         call    EXCEPTION
 235 
 236         // Generate a NaN for unknown tags
 237         movl    _CONST_QNaN,%eax
 238         movl    %eax,(%edi)
 239         movl    _CONST_QNaN+4,%eax
 240         movl    %eax,SIGL(%edi)
 241         movl    _CONST_QNaN+8,%eax
 242         movl    %eax,SIGH(%edi)
 243         jmp     LDiv_exit               // %eax is nz
 244 #endif PARANOID

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