root/kernel/FPU-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                                                   |
   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_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_asm.h"
  30 #include "control_w.h"
  31 
  32 .text
  33         .align 2,144
  34 .globl _reg_u_sub
  35 _reg_u_sub:
  36         pushl   %ebp
  37         movl    %esp,%ebp
  38         pushl   %esi
  39         pushl   %edi
  40         pushl   %ebx
  41 
  42         movl    PARAM1,%esi     /* source 1 */
  43         movl    PARAM2,%edi     /* source 2 */
  44 
  45 #ifdef DENORM_OPERAND
  46         cmpl    EXP_UNDER,EXP(%esi)
  47         jg      xOp1_not_denorm
  48 
  49         call    _denormal_operand
  50         orl     %eax,%eax
  51         jnz     FPU_Arith_exit
  52 
  53 xOp1_not_denorm:
  54         cmpl    EXP_UNDER,EXP(%edi)
  55         jg      xOp2_not_denorm
  56 
  57         call    _denormal_operand
  58         orl     %eax,%eax
  59         jnz     FPU_Arith_exit
  60 
  61 xOp2_not_denorm:
  62 #endif DENORM_OPERAND
  63 
  64 //      xorl    %ecx,%ecx
  65         movl    EXP(%esi),%ecx
  66         subl    EXP(%edi),%ecx  /* exp1 - exp2 */
  67 
  68 #ifdef PARANOID
  69         /* source 2 is always smaller than source 1 */
  70 //      jc      L_bugged
  71         js      L_bugged_1
  72 
  73         testl   $0x80000000,SIGH(%edi)  /* The args are assumed to be be normalized */
  74         je      L_bugged_2
  75 
  76         testl   $0x80000000,SIGH(%esi)
  77         je      L_bugged_2
  78 #endif PARANOID
  79 
  80 /*--------------------------------------+
  81  |      Form a register holding the     |
  82  |      smaller number                  |
  83  +--------------------------------------*/
  84         movl    SIGH(%edi),%eax // register ms word
  85         movl    SIGL(%edi),%ebx // register ls word
  86 
  87         movl    PARAM3,%edi     /* destination */
  88         movl    EXP(%esi),%edx
  89         movl    %edx,EXP(%edi)  /* Copy exponent to destination */
  90         movb    SIGN(%esi),%dl
  91         movb    %dl,SIGN(%edi)  /* Copy the sign from the first arg */
  92 
  93         xorl    %edx,%edx       // register extension
  94 
  95 /*--------------------------------------+
  96  |      Shift the temporary register    |
  97  |      right the required number of    |
  98  |      places.                         |
  99  +--------------------------------------*/
 100 L_shift_r:
 101         cmpl    $32,%ecx                /* shrd only works for 0..31 bits */
 102         jnc     L_more_than_31
 103 
 104 /* less than 32 bits */
 105         shrd    %cl,%ebx,%edx
 106         shrd    %cl,%eax,%ebx
 107         shr     %cl,%eax
 108         jmp     L_shift_done
 109 
 110 L_more_than_31:
 111         cmpl    $64,%ecx
 112         jnc     L_more_than_63
 113 
 114         subb    $32,%cl
 115         jz      L_exactly_32
 116 
 117         shrd    %cl,%eax,%edx
 118         shr     %cl,%eax
 119         orl     %ebx,%ebx
 120         jz      L_more_31_no_low        // none of the lowest bits is set
 121 
 122         orl     $1,%edx                 // record the fact in the extension
 123 
 124 L_more_31_no_low:
 125         movl    %eax,%ebx
 126         xorl    %eax,%eax
 127         jmp     L_shift_done
 128 
 129 L_exactly_32:
 130         movl    %ebx,%edx
 131         movl    %eax,%ebx
 132         xorl    %eax,%eax
 133         jmp     L_shift_done
 134 
 135 L_more_than_63:
 136         cmpw    $65,%cx
 137         jnc     L_more_than_64
 138 
 139         // Shift right by 64 bits
 140         movl    %eax,%edx
 141         orl     %ebx,%ebx
 142         jz      L_more_63_no_low
 143 
 144         orl     $1,%edx
 145         jmp     L_more_63_no_low
 146 
 147 L_more_than_64:
 148         jne     L_more_than_65
 149 
 150         // Shift right by 65 bits
 151         // Carry is clear if we get here
 152         movl    %eax,%edx
 153         rcrl    %edx
 154         jnc     L_shift_65_nc
 155 
 156         orl     $1,%edx
 157         jmp     L_more_63_no_low
 158 
 159 L_shift_65_nc:
 160         orl     %ebx,%ebx
 161         jz      L_more_63_no_low
 162 
 163         orl     $1,%edx
 164         jmp     L_more_63_no_low
 165 
 166 L_more_than_65:
 167         movl    $1,%edx         // The shifted nr always at least one '1'
 168 
 169 L_more_63_no_low:
 170         xorl    %ebx,%ebx
 171         xorl    %eax,%eax
 172 
 173 L_shift_done:
 174 L_subtr:
 175 /*------------------------------+
 176  |      Do the subtraction      |
 177  +------------------------------*/
 178         xorl    %ecx,%ecx
 179         subl    %edx,%ecx
 180         movl    %ecx,%edx
 181         movl    SIGL(%esi),%ecx
 182         sbbl    %ebx,%ecx
 183         movl    %ecx,%ebx
 184         movl    SIGH(%esi),%ecx
 185         sbbl    %eax,%ecx
 186         movl    %ecx,%eax
 187 
 188 #ifdef PARANOID
 189         /* We can never get a borrow */
 190         jc      L_bugged
 191 #endif PARANOID
 192 
 193 /*--------------------------------------+
 194  |      Normalize the result            |
 195  +--------------------------------------*/
 196         testl   $0x80000000,%eax
 197         jnz     L_round         /* no shifting needed */
 198 
 199         orl     %eax,%eax
 200         jnz     L_shift_1       /* shift left 1 - 31 bits */
 201 
 202         orl     %ebx,%ebx
 203         jnz     L_shift_32      /* shift left 32 - 63 bits */
 204 
 205 //       A rare case, the only one which is non-zero if we got here
 206 //         is:           1000000 .... 0000
 207 //                      -0111111 .... 1111 1
 208 //                       -------------------- 
 209 //                       0000000 .... 0000 1 
 210 
 211         cmpl    $0x80000000,%edx
 212         jnz     L_must_be_zero
 213 
 214         /* Shift left 64 bits */
 215         subl    $64,EXP(%edi)
 216         movl    %edx,%eax
 217         jmp     L_store
 218 
 219 L_must_be_zero:
 220 #ifdef PARANOID
 221         orl     %edx,%edx
 222         jnz     L_bugged_3
 223 #endif PARANOID
 224 
 225         /* The result is zero */
 226         movb    TW_Zero,TAG(%edi)
 227         movl    $0,EXP(%edi)            /* exponent */
 228         movl    $0,SIGL(%edi)
 229         movl    $0,SIGH(%edi)
 230         jmp     L_exit          // Does not underflow
 231 
 232 L_shift_32:
 233         movl    %ebx,%eax
 234         movl    %edx,%ebx
 235         movl    $0,%edx
 236         subl    $32,EXP(%edi)   /* Can get underflow here */
 237 
 238 /* We need to shift left by 1 - 31 bits */
 239 L_shift_1:
 240         bsrl    %eax,%ecx       /* get the required shift in %ecx */
 241         subl    $31,%ecx
 242         negl    %ecx
 243         shld    %cl,%ebx,%eax
 244         shld    %cl,%edx,%ebx
 245         shl     %cl,%edx
 246         subl    %ecx,EXP(%edi)  /* Can get underflow here */
 247 
 248 L_round:
 249         jmp     FPU_round       // Round the result
 250 
 251 
 252 #ifdef PARANOID
 253 L_bugged_1:
 254         pushl   EX_INTERNAL|0x206
 255         call    EXCEPTION
 256         pop     %ebx
 257         jmp     L_exit
 258 
 259 L_bugged_2:
 260         pushl   EX_INTERNAL|0x209
 261         call    EXCEPTION
 262         pop     %ebx
 263         jmp     L_exit
 264 
 265 L_bugged_3:
 266         pushl   EX_INTERNAL|0x210
 267         call    EXCEPTION
 268         pop     %ebx
 269         jmp     L_exit
 270 
 271 L_bugged_4:
 272         pushl   EX_INTERNAL|0x211
 273         call    EXCEPTION
 274         pop     %ebx
 275         jmp     L_exit
 276 
 277 L_bugged:
 278         pushl   EX_INTERNAL|0x212
 279         call    EXCEPTION
 280         pop     %ebx
 281         jmp     L_exit
 282 #endif PARANOID
 283 
 284 
 285 L_store:
 286 /*------------------------------+
 287  |      Store the result        |
 288  +------------------------------*/
 289         movl    %eax,SIGH(%edi)
 290         movl    %ebx,SIGL(%edi)
 291 
 292         movb    TW_Valid,TAG(%edi)              /* Set the tags to TW_Valid */
 293 
 294         cmpl    EXP_UNDER,EXP(%edi)
 295         jle     L_underflow
 296 
 297 L_exit:
 298         popl    %ebx
 299         popl    %edi
 300         popl    %esi
 301         leave
 302         ret
 303 
 304 
 305 L_underflow:
 306         push    %edi
 307         call    _arith_underflow
 308         pop     %ebx
 309         jmp     L_exit
 310 

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