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

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

/* [<][>][^][v][top][bottom][index][help] */