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

/* [previous][next][first][last][top][bottom][index][help] */
   1         .file   "reg_u_sub.S"
   2 /*---------------------------------------------------------------------------+
   3  |  reg_u_sub.S                                                              |
   4  |                                                                           |
   5  | Core floating point subtraction routine.                                  |
   6  |                                                                           |
   7  | Copyright (C) 1992,1993,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_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ,             |
  13  |                                                int control_w)             |
  14  |                                                                           |
  15  +---------------------------------------------------------------------------*/
  16 
  17 /*
  18  |    Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ).
  19  |    Takes two valid reg f.p. numbers (TW_Valid), which are
  20  |    treated as unsigned numbers,
  21  |    and returns their difference as a TW_Valid or TW_Zero f.p.
  22  |    number.
  23  |    The first number (arg1) must be the larger.
  24  |    The returned number is normalized.
  25  |    Basic checks are performed if PARANOID is defined.
  26  */
  27 
  28 #include "exception.h"
  29 #include "fpu_emu.h"
  30 #include "control_w.h"
  31 
  32 .text
  33 ENTRY(reg_u_sub)
  34         pushl   %ebp
  35         movl    %esp,%ebp
  36         pushl   %esi
  37         pushl   %edi
  38         pushl   %ebx
  39 
  40         movl    PARAM1,%esi     /* source 1 */
  41         movl    PARAM2,%edi     /* source 2 */
  42 
  43 #ifdef DENORM_OPERAND
  44         cmpl    EXP_UNDER,EXP(%esi)
  45         jg      xOp1_not_denorm
  46 
  47         call    SYMBOL_NAME(denormal_operand)
  48         orl     %eax,%eax
  49         jnz     fpu_Arith_exit
  50 
  51 xOp1_not_denorm:
  52         cmpl    EXP_UNDER,EXP(%edi)
  53         jg      xOp2_not_denorm
  54 
  55         call    SYMBOL_NAME(denormal_operand)
  56         orl     %eax,%eax
  57         jnz     fpu_Arith_exit
  58 
  59 xOp2_not_denorm:
  60 #endif DENORM_OPERAND
  61 
  62         movl    EXP(%esi),%ecx
  63         subl    EXP(%edi),%ecx  /* exp1 - exp2 */
  64 
  65 #ifdef PARANOID
  66         /* source 2 is always smaller than source 1 */
  67         js      L_bugged_1
  68 
  69         testl   $0x80000000,SIGH(%edi)  /* The args are assumed to be be normalized */
  70         je      L_bugged_2
  71 
  72         testl   $0x80000000,SIGH(%esi)
  73         je      L_bugged_2
  74 #endif PARANOID
  75 
  76 /*--------------------------------------+
  77  |      Form a register holding the     |
  78  |      smaller number                  |
  79  +--------------------------------------*/
  80         movl    SIGH(%edi),%eax /* register ms word */
  81         movl    SIGL(%edi),%ebx /* register ls word */
  82 
  83         movl    PARAM3,%edi     /* destination */
  84         movl    EXP(%esi),%edx
  85         movl    %edx,EXP(%edi)  /* Copy exponent to destination */
  86 /*      movb    SIGN(%esi),%dl
  87         movb    %dl,SIGN(%edi) */       /* Copy the sign from the first arg */
  88 
  89         xorl    %edx,%edx       /* register extension */
  90 
  91 /*--------------------------------------+
  92  |      Shift the temporary register    |
  93  |      right the required number of    |
  94  |      places.                         |
  95  +--------------------------------------*/
  96 L_shift_r:
  97         cmpl    $32,%ecx                /* shrd only works for 0..31 bits */
  98         jnc     L_more_than_31
  99 
 100 /* less than 32 bits */
 101         shrd    %cl,%ebx,%edx
 102         shrd    %cl,%eax,%ebx
 103         shr     %cl,%eax
 104         jmp     L_shift_done
 105 
 106 L_more_than_31:
 107         cmpl    $64,%ecx
 108         jnc     L_more_than_63
 109 
 110         subb    $32,%cl
 111         jz      L_exactly_32
 112 
 113         shrd    %cl,%eax,%edx
 114         shr     %cl,%eax
 115         orl     %ebx,%ebx
 116         jz      L_more_31_no_low        /* none of the lowest bits is set */
 117 
 118         orl     $1,%edx                 /* record the fact in the extension */
 119 
 120 L_more_31_no_low:
 121         movl    %eax,%ebx
 122         xorl    %eax,%eax
 123         jmp     L_shift_done
 124 
 125 L_exactly_32:
 126         movl    %ebx,%edx
 127         movl    %eax,%ebx
 128         xorl    %eax,%eax
 129         jmp     L_shift_done
 130 
 131 L_more_than_63:
 132         cmpw    $65,%cx
 133         jnc     L_more_than_64
 134 
 135         /* Shift right by 64 bits */
 136         movl    %eax,%edx
 137         orl     %ebx,%ebx
 138         jz      L_more_63_no_low
 139 
 140         orl     $1,%edx
 141         jmp     L_more_63_no_low
 142 
 143 L_more_than_64:
 144         jne     L_more_than_65
 145 
 146         /* Shift right by 65 bits */
 147         /* Carry is clear if we get here */
 148         movl    %eax,%edx
 149         rcrl    %edx
 150         jnc     L_shift_65_nc
 151 
 152         orl     $1,%edx
 153         jmp     L_more_63_no_low
 154 
 155 L_shift_65_nc:
 156         orl     %ebx,%ebx
 157         jz      L_more_63_no_low
 158 
 159         orl     $1,%edx
 160         jmp     L_more_63_no_low
 161 
 162 L_more_than_65:
 163         movl    $1,%edx         /* The shifted nr always at least one '1' */
 164 
 165 L_more_63_no_low:
 166         xorl    %ebx,%ebx
 167         xorl    %eax,%eax
 168 
 169 L_shift_done:
 170 L_subtr:
 171 /*------------------------------+
 172  |      Do the subtraction      |
 173  +------------------------------*/
 174         xorl    %ecx,%ecx
 175         subl    %edx,%ecx
 176         movl    %ecx,%edx
 177         movl    SIGL(%esi),%ecx
 178         sbbl    %ebx,%ecx
 179         movl    %ecx,%ebx
 180         movl    SIGH(%esi),%ecx
 181         sbbl    %eax,%ecx
 182         movl    %ecx,%eax
 183 
 184 #ifdef PARANOID
 185         /* We can never get a borrow */
 186         jc      L_bugged
 187 #endif PARANOID
 188 
 189 /*--------------------------------------+
 190  |      Normalize the result            |
 191  +--------------------------------------*/
 192         testl   $0x80000000,%eax
 193         jnz     L_round         /* no shifting needed */
 194 
 195         orl     %eax,%eax
 196         jnz     L_shift_1       /* shift left 1 - 31 bits */
 197 
 198         orl     %ebx,%ebx
 199         jnz     L_shift_32      /* shift left 32 - 63 bits */
 200 
 201 /*
 202  *       A rare case, the only one which is non-zero if we got here
 203  *         is:           1000000 .... 0000
 204  *                      -0111111 .... 1111 1
 205  *                       -------------------- 
 206  *                       0000000 .... 0000 1 
 207  */
 208 
 209         cmpl    $0x80000000,%edx
 210         jnz     L_must_be_zero
 211 
 212         /* Shift left 64 bits */
 213         subl    $64,EXP(%edi)
 214         xchg    %edx,%eax
 215         jmp     fpu_reg_round
 216 
 217 L_must_be_zero:
 218 #ifdef PARANOID
 219         orl     %edx,%edx
 220         jnz     L_bugged_3
 221 #endif PARANOID
 222 
 223         /* The result is zero */
 224         movb    TW_Zero,TAG(%edi)
 225         movl    $0,EXP(%edi)            /* exponent */
 226         movl    $0,SIGL(%edi)
 227         movl    $0,SIGH(%edi)
 228         jmp     L_exit          /* %eax contains zero */
 229 
 230 L_shift_32:
 231         movl    %ebx,%eax
 232         movl    %edx,%ebx
 233         movl    $0,%edx
 234         subl    $32,EXP(%edi)   /* Can get underflow here */
 235 
 236 /* We need to shift left by 1 - 31 bits */
 237 L_shift_1:
 238         bsrl    %eax,%ecx       /* get the required shift in %ecx */
 239         subl    $31,%ecx
 240         negl    %ecx
 241         shld    %cl,%ebx,%eax
 242         shld    %cl,%edx,%ebx
 243         shl     %cl,%edx
 244         subl    %ecx,EXP(%edi)  /* Can get underflow here */
 245 
 246 L_round:
 247         jmp     fpu_reg_round   /* Round the result */
 248 
 249 
 250 #ifdef PARANOID
 251 L_bugged_1:
 252         pushl   EX_INTERNAL|0x206
 253         call    EXCEPTION
 254         pop     %ebx
 255         jmp     L_error_exit
 256 
 257 L_bugged_2:
 258         pushl   EX_INTERNAL|0x209
 259         call    EXCEPTION
 260         pop     %ebx
 261         jmp     L_error_exit
 262 
 263 L_bugged_3:
 264         pushl   EX_INTERNAL|0x210
 265         call    EXCEPTION
 266         pop     %ebx
 267         jmp     L_error_exit
 268 
 269 L_bugged_4:
 270         pushl   EX_INTERNAL|0x211
 271         call    EXCEPTION
 272         pop     %ebx
 273         jmp     L_error_exit
 274 
 275 L_bugged:
 276         pushl   EX_INTERNAL|0x212
 277         call    EXCEPTION
 278         pop     %ebx
 279         jmp     L_error_exit
 280 #endif PARANOID
 281 
 282 
 283 L_error_exit:
 284         movl    $1,%eax
 285 L_exit:
 286         popl    %ebx
 287         popl    %edi
 288         popl    %esi
 289         leave
 290         ret

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