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         call    _real_2op_NaN
  92         jmp     LDiv_exit
  93 
  94 // Invalid operations
  95 L_zero_zero:
  96 L_inf_inf:
  97         pushl   %edi                    // Destination
  98         call    _arith_invalid          // 0/0 or Infinity/Infinity
  99         jmp     LDiv_exit
 100 
 101 L_no_NaN_arg:
 102         cmpb    TW_Infinity,TAG(%esi)
 103         jne     L_arg1_not_inf
 104 
 105         cmpb    TW_Infinity,TAG(%ebx)
 106         je      L_inf_inf               // invalid operation
 107 
 108         cmpb    TW_Valid,TAG(%ebx)
 109         je      L_inf_valid
 110 
 111 #ifdef PARANOID
 112         // arg2 must be zero or valid
 113         cmpb    TW_Zero,TAG(%ebx)
 114         ja      L_unknown_tags
 115 #endif PARANOID
 116 
 117         // Note that p16-9 says that infinity/0 returns infinity
 118         jmp     L_copy_arg1             // Answer is Inf
 119 
 120 L_inf_valid:
 121 #ifdef DENORM_OPERAND
 122         cmpl    EXP_UNDER,EXP(%ebx)
 123         jg      L_copy_arg1             // Answer is Inf
 124 
 125         call    _denormal_operand
 126         orl     %eax,%eax
 127         jnz     FPU_Arith_exit
 128 #endif DENORM_OPERAND
 129 
 130         jmp     L_copy_arg1             // Answer is Inf
 131 
 132 L_arg1_not_inf:
 133         cmpb    TW_Zero,TAG(%ebx)       // Priority to div-by-zero error
 134         jne     L_arg2_not_zero
 135 
 136         cmpb    TW_Zero,TAG(%esi)
 137         je      L_zero_zero             // invalid operation
 138 
 139 #ifdef PARANOID
 140         // arg1 must be valid
 141         cmpb    TW_Valid,TAG(%esi)
 142         ja      L_unknown_tags
 143 #endif PARANOID
 144 
 145 // Division by zero error
 146         pushl   %edi                    // destination
 147         movb    SIGN(%esi),%al
 148         xorb    SIGN(%ebx),%al
 149         pushl   %eax                    // lower 8 bits have the sign
 150         call    _divide_by_zero
 151         jmp     LDiv_exit
 152 
 153 L_arg2_not_zero:
 154         cmpb    TW_Infinity,TAG(%ebx)
 155         jne     L_arg2_not_inf
 156 
 157 #ifdef DENORM_OPERAND
 158         cmpb    TW_Valid,TAG(%esi)
 159         jne     L_return_zero
 160 
 161         cmpl    EXP_UNDER,EXP(%esi)
 162         jg      L_return_zero           // Answer is zero
 163 
 164         call    _denormal_operand
 165         orl     %eax,%eax
 166         jnz     FPU_Arith_exit
 167 #endif DENORM_OPERAND
 168 
 169         jmp     L_return_zero           // Answer is zero
 170 
 171 L_arg2_not_inf:
 172 
 173 #ifdef PARANOID
 174         cmpb    TW_Zero,TAG(%esi)
 175         jne     L_unknown_tags
 176 #endif PARANOID
 177 
 178         // arg1 is zero, arg2 is not Infinity or a NaN
 179 
 180 #ifdef DENORM_OPERAND
 181         cmpl    EXP_UNDER,EXP(%ebx)
 182         jg      L_copy_arg1             // Answer is zero
 183 
 184         call    _denormal_operand
 185         orl     %eax,%eax
 186         jnz     FPU_Arith_exit
 187 #endif DENORM_OPERAND
 188 
 189 L_copy_arg1:
 190         movb    TAG(%esi),%ax
 191         movb    %ax,TAG(%edi)
 192         movl    EXP(%esi),%eax
 193         movl    %eax,EXP(%edi)
 194         movl    SIGL(%esi),%eax
 195         movl    %eax,SIGL(%edi)
 196         movl    SIGH(%esi),%eax
 197         movl    %eax,SIGH(%edi)
 198 
 199         movb    SIGN(%esi),%cl
 200         cmpb    %cl,SIGN(%ebx)
 201         jne     LDiv_negative_result
 202 
 203         movb    SIGN_POS,SIGN(%edi)
 204         jmp     LDiv_exit
 205 
 206 LDiv_set_result_sign:
 207         movb    SIGN(%esi),%cl
 208         cmpb    %cl,SIGN(%edi)
 209         jne     LDiv_negative_result
 210 
 211         movb    SIGN_POS,SIGN(%ebx)
 212         jmp     LDiv_exit
 213 
 214 LDiv_negative_result:
 215         movb    SIGN_NEG,SIGN(%edi)
 216 
 217 LDiv_exit:
 218         leal    -12(%ebp),%esp
 219 
 220         popl    %ebx
 221         popl    %edi
 222         popl    %esi
 223         leave
 224         ret
 225 
 226 
 227 L_return_zero:
 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
 244 #endif PARANOID

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