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

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