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    W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
   8  |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
   9  |                                                                           |
  10  | Call from C as:                                                           |
  11  |   void reg_u_sub(reg *arg1, reg *arg2, reg *answ)                         |
  12  |                                                                           |
  13  +---------------------------------------------------------------------------*/
  14 
  15 /*
  16  |    Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ).
  17  |    Takes two valid reg f.p. numbers (TW_Valid), which are
  18  |    treated as unsigned numbers,
  19  |    and returns their difference as a TW_Valid or TW_Zero f.p.
  20  |    number.
  21  |    The first number (arg1) must be the larger.
  22  |    The returned number is normalized.
  23  |    Basic checks are performed if PARANOID is defined.
  24  */
  25 
  26 #include "exception.h"
  27 #include "fpu_asm.h"
  28 
  29 
  30 .text
  31         .align 2,144
  32 .globl _reg_u_sub
  33 _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 //      xorl    %ecx,%ecx
  44         movl    EXP(%esi),%ecx
  45         subl    EXP(%edi),%ecx  /* exp1 - exp2 */
  46 
  47 #ifdef PARANOID
  48         /* source 2 is always smaller than source 1 */
  49 //      jc      L_bugged
  50         js      L_bugged_1
  51 
  52         testl   $0x80000000,SIGH(%edi)  /* The args are assumed to be be normalized */
  53         je      L_bugged_2
  54 
  55         testl   $0x80000000,SIGH(%esi)
  56         je      L_bugged_2
  57 #endif PARANOID
  58 
  59 /*--------------------------------------+
  60  |      Form a register holding the     |
  61  |      smaller number                  |
  62  +--------------------------------------*/
  63         movl    SIGH(%edi),%eax // register ms word
  64         movl    SIGL(%edi),%ebx // register ls word
  65 
  66         movl    PARAM3,%edi     /* destination */
  67         movl    EXP(%esi),%edx
  68         movl    %edx,EXP(%edi)  /* Copy exponent to destination */
  69 
  70         xorl    %edx,%edx       // register extension
  71 
  72 /*--------------------------------------+
  73  |      Shift the temporary register    |
  74  |      right the required number of    |
  75  |      places.                         |
  76  +--------------------------------------*/
  77 L_shift_r:
  78         cmpl    $32,%ecx                /* shrd only works for 0..31 bits */
  79         jnc     L_more_than_31
  80 
  81 /* less than 32 bits */
  82         shrd    %cl,%ebx,%edx
  83         shrd    %cl,%eax,%ebx
  84         shr     %cl,%eax
  85         jmp     L_shift_done
  86 
  87 L_more_than_31:
  88         cmpl    $64,%ecx
  89         jnc     L_more_than_63
  90 
  91         subb    $32,%cl
  92         shrd    %cl,%eax,%edx
  93         movl    %eax,%ebx
  94         shr     %cl,%ebx
  95         xorl    %eax,%eax
  96         jmp     L_shift_done
  97 
  98 L_more_than_63:
  99         cmpl    $66,%ecx
 100         jnc     L_more_than_65
 101 
 102         subb    $64,%cl
 103         movl    %eax,%edx
 104         shr     %cl,%edx
 105         xorl    %ebx,%ebx
 106         xorl    %eax,%eax
 107         jmp     L_shift_done
 108 
 109 L_more_than_65:
 110         /* just copy the larger reg to dest */
 111         movw    SIGN(%esi),%ax
 112         movw    %ax,SIGN(%edi)
 113         movl    EXP(%esi),%eax
 114         movl    %eax,EXP(%edi)
 115         movl    SIGL(%esi),%eax
 116         movl    %eax,SIGL(%edi)
 117         movl    SIGH(%esi),%eax
 118         movl    %eax,SIGH(%edi)
 119         jmp     L_exit          // Does not underflow
 120 
 121 L_shift_done:
 122 L_subtr:
 123 /*------------------------------+
 124  |      Do the subtraction      |
 125  +------------------------------*/
 126         xorl    %ecx,%ecx
 127         subl    %edx,%ecx
 128         movl    %ecx,%edx
 129         movl    SIGL(%esi),%ecx
 130         sbbl    %ebx,%ecx
 131         movl    %ecx,%ebx
 132         movl    SIGH(%esi),%ecx
 133         sbbl    %eax,%ecx
 134         movl    %ecx,%eax
 135 
 136 #ifdef PARANOID
 137         /* We can never get a borrow */
 138         jc      L_bugged
 139 #endif PARANOID
 140 
 141 /*--------------------------------------+
 142  |      Normalize the result            |
 143  +--------------------------------------*/
 144         testl   $0x80000000,%eax
 145         jnz     L_round         /* no shifting needed */
 146 
 147         orl     %eax,%eax
 148         jnz     L_shift_1       /* shift left 1 - 31 bits */
 149 
 150         orl     %ebx,%ebx
 151         jnz     L_shift_32      /* shift left 32 - 63 bits */
 152 
 153 //       A rare case, the only one which is non-zero if we got here
 154 //         is:           1000000 .... 0000
 155 //                      -0111111 .... 1111 1
 156 //                       -------------------- 
 157 //                       0000000 .... 0000 1 
 158 
 159         cmpl    $0x80000000,%edx
 160         jnz     L_must_be_zero
 161 
 162         /* Shift left 64 bits */
 163         subl    $64,EXP(%edi)
 164         movl    %edx,%eax
 165         jmp     L_store
 166 
 167 L_must_be_zero:
 168 #ifdef PARANOID
 169         orl     %edx,%edx
 170         jnz     L_bugged_3
 171 #endif PARANOID
 172 
 173         /* The result is zero */
 174         movb    TW_Zero,TAG(%edi)
 175         movl    $0,EXP(%edi)            /* exponent */
 176         movl    $0,SIGL(%edi)
 177         movl    $0,SIGH(%edi)
 178         jmp     L_exit          // Does not underflow
 179 
 180 L_shift_32:
 181         movl    %ebx,%eax
 182         movl    %edx,%ebx
 183         movl    $0,%edx
 184         subl    $32,EXP(%edi)   /* Can get underflow here */
 185 
 186 /* We need to shift left by 1 - 31 bits */
 187 L_shift_1:
 188         bsrl    %eax,%ecx       /* get the required shift in %ecx */
 189         subl    $31,%ecx
 190         negl    %ecx
 191         shld    %cl,%ebx,%eax
 192         shld    %cl,%edx,%ebx
 193         shl     %cl,%edx
 194         subl    %ecx,EXP(%edi)  /* Can get underflow here */
 195 
 196 L_round:
 197 /*------------------------------+
 198  |      Round the result        |
 199  +------------------------------*/
 200         cmpl    $0x80000000,%edx
 201         jc      L_store
 202 
 203         jne     L_round_up
 204 
 205         testb   $1,%dl
 206         jz      L_store
 207 
 208 L_round_up:
 209         addl    $1,%ebx
 210         adcl    $0,%eax
 211         jnc     L_store
 212 
 213         /* We just rounded up to (1) 00 00 */
 214         /* This *is* possible, if the subtraction is of the
 215            form (1. + x) - (x + y) where x is small and y is
 216            very small. */
 217         incl    EXP(%edi)
 218         movl    $0x80000000,%eax
 219 
 220 L_store:
 221 /*------------------------------+
 222  |      Store the result        |
 223  +------------------------------*/
 224         movl    %eax,SIGH(%edi)
 225         movl    %ebx,SIGL(%edi)
 226 
 227         movb    TW_Valid,TAG(%edi)              /* Set the tags to TW_Valid */
 228 
 229         cmpl    EXP_UNDER,EXP(%edi)
 230         jle     L_underflow
 231 
 232 L_exit:
 233         popl    %ebx
 234         popl    %edi
 235         popl    %esi
 236         leave
 237         ret
 238 
 239 
 240 L_underflow:
 241         push    %edi
 242         call    _arith_underflow
 243         pop     %ebx
 244         jmp     L_exit
 245 
 246 
 247 #ifdef PARANOID
 248 L_bugged_1:
 249         pushl   EX_INTERNAL|0x206
 250         call    EXCEPTION
 251         pop     %ebx
 252         jmp     L_exit
 253 
 254 L_bugged_2:
 255         pushl   EX_INTERNAL|0x209
 256         call    EXCEPTION
 257         pop     %ebx
 258         jmp     L_exit
 259 
 260 L_bugged_3:
 261         pushl   EX_INTERNAL|0x210
 262         call    EXCEPTION
 263         pop     %ebx
 264         jmp     L_exit
 265 
 266 L_bugged_4:
 267         pushl   EX_INTERNAL|0x211
 268         call    EXCEPTION
 269         pop     %ebx
 270         jmp     L_exit
 271 
 272 L_bugged:
 273         pushl   EX_INTERNAL|0x212
 274         call    EXCEPTION
 275         pop     %ebx
 276         jmp     L_exit
 277 #endif PARANOID

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