root/kernel/FPU-emu/reg_round.S

/* [previous][next][first][last][top][bottom][index][help] */
   1         .file "reg_round.S"
   2 /*---------------------------------------------------------------------------+
   3  |  reg_round.S                                                              |
   4  |                                                                           |
   5  | Rounding/truncation/etc for FPU basic arithmetic functions.               |
   6  |                                                                           |
   7  | Copyright (C) 1993                                                        |
   8  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
   9  |                       Australia.  E-mail apm233m@vaxc.cc.monash.edu.au    |
  10  |                                                                           |
  11  | Not callable from C.                                                      |
  12  | Must be entered by a jmp intruction.                                      |
  13  |                                                                           |
  14  +---------------------------------------------------------------------------*/
  15 
  16 /*---------------------------------------------------------------------------+
  17  | Two entry points.                                                         |
  18  |                                                                           |
  19  | Needed by both entry points:                                              |
  20  |  %eax:%ebx  64 bit significand                                            |
  21  |  %edx       32 bit extension of the significand                           |
  22  |  %edi       pointer to an FPU_REG for the result to be stored             |
  23  |  stack      calling function must have set up a C stack frame and         |
  24  |             pushed %esi, %edi, and %ebx                                   |
  25  |                                                                           |
  26  | Needed just for the FPU_round_sqrt entry point:                           |
  27  |  %cx  A control word in the same format as the FPU control word.          |
  28  | Otherwise, PARAM4 must give such a value.                                 |
  29  |                                                                           |
  30  |                                                                           |
  31  | The significand and its extension are assumed to be exact in the          |
  32  | following sense:                                                          |
  33  |   If the significand by itself is the exact result then the significand   |
  34  |   extension (%edx) must contain 0, otherwise the significand extension    |
  35  |   must be non-zero.                                                       |
  36  |   If the significand extension is non-zero then the significand is        |
  37  |   smaller than the magnitude of the correct exact result by an amount     |
  38  |   greater than zero and less than one ls bit of the significand.          |
  39  |   The significand extension is only required to have three possible       |
  40  |   non-zero values:                                                        |
  41  |       less than 0x80000000  <=> the significand is less than 1/2 an ls    |
  42  |                                 bit smaller than the magnitude of the     |
  43  |                                 true exact result.                        |
  44  |         exactly 0x80000000  <=> the significand is exactly 1/2 an ls bit  |
  45  |                                 smaller than the magnitude of the true    |
  46  |                                 exact result.                             |
  47  |    greater than 0x80000000  <=> the significand is more than 1/2 an ls    |
  48  |                                 bit smaller than the magnitude of the     |
  49  |                                 true exact result.                        |
  50  |                                                                           |
  51  +---------------------------------------------------------------------------*/
  52 
  53 #include "fpu_asm.h"
  54 #include "fpu_emu.h"
  55 #include "exception.h"
  56 #include "control_w.h"
  57 
  58 
  59 .text
  60         .align 2,144
  61 .globl FPU_round
  62 .globl FPU_round_sqrt
  63 
  64 FPU_round:
  65         /* Round the result */
  66         movl    PARAM4,%ecx
  67 
  68 FPU_round_sqrt:         // entry point from wm_sqrt.S
  69         movl    %ecx,%esi
  70         andl    CW_PC,%ecx
  71         cmpl    PR_64_BITS,%ecx
  72         je      LRound_To_64
  73 
  74         cmpl    PR_53_BITS,%ecx
  75         je      LRound_To_53
  76 
  77         cmpl    PR_24_BITS,%ecx
  78         je      LRound_To_24
  79 
  80 #ifdef PARANOID
  81         jmp     L_bugged        // There is no bug, just a bad control word
  82 #endif PARANOID
  83 
  84 
  85 LRound_To_24:
  86         movl    %esi,%ecx
  87         andl    CW_RC,%ecx
  88         cmpl    RC_RND,%ecx
  89         je      LRound_nearest_24
  90 
  91         cmpl    RC_CHOP,%ecx
  92         je      LTruncate_24
  93 
  94         cmpl    RC_UP,%ecx              // Towards +infinity
  95         je      LUp_24
  96 
  97         cmpl    RC_DOWN,%ecx            // Towards -infinity
  98         je      LDown_24
  99 
 100 #ifdef PARANOID
 101         jmp     L_bugged
 102 #endif PARANOID
 103 
 104 LUp_24:
 105         cmpb    SIGN_POS,SIGN(%edi)
 106         je      LUp_24_pos
 107 
 108         movl    %eax,%ecx
 109         andl    $0x000000ff,%ecx
 110         orl     %ebx,%ecx
 111         orl     %edx,%ecx
 112         jnz     LTruncate_24
 113         jmp     L_store
 114 
 115 LUp_24_pos:
 116         movl    %eax,%ecx
 117         andl    $0x000000ff,%ecx
 118         orl     %ebx,%ecx
 119         orl     %edx,%ecx
 120         jnz     LDo_24_round_up
 121         jmp     L_store
 122 
 123 LDown_24:
 124         cmpb    SIGN_POS,SIGN(%edi)
 125         je      LDown_24_pos
 126 
 127         movl    %eax,%ecx
 128         andl    $0x000000ff,%ecx
 129         orl     %ebx,%ecx
 130         orl     %edx,%ecx
 131         jnz     LDo_24_round_up
 132         jmp     L_store
 133 
 134 LDown_24_pos:
 135         movl    %eax,%ecx
 136         andl    $0x000000ff,%ecx
 137         orl     %ebx,%ecx
 138         orl     %edx,%ecx
 139         jnz     LTruncate_24
 140         jmp     L_store
 141 
 142 LRound_nearest_24:
 143         // Do rounding of the 24th bit if needed (nearest or even)
 144         movl    %eax,%ecx
 145         andl    $0x000000ff,%ecx
 146         cmpl    $0x00000080,%ecx
 147         jc      LTruncate_24            // less than half, no increment needed
 148 
 149         jne     LGreater_Half_24        // greater than half, increment needed
 150 
 151         // Possibly half, we need to check the ls bits
 152         orl     %ebx,%ebx
 153         jne     LGreater_Half_24        // greater than half, increment needed
 154 
 155         orl     %edx,%edx
 156         jne     LGreater_Half_24        // greater than half, increment needed
 157 
 158         // Exactly half, increment only if 24th bit is 1 (round to even)
 159         testl   $0x00000100,%eax
 160         jz      LTruncate_24
 161 
 162 LGreater_Half_24:                       // Rounding: increment at the 24th bit
 163 LDo_24_round_up:
 164         andl    $0xffffff00,%eax        // Truncate to 24 bits
 165         xorl    %ebx,%ebx
 166         addl    $0x00000100,%eax
 167         jmp     LCheck_Round_Overflow
 168 
 169 LTruncate_24:
 170         andl    $0xffffff00,%eax        // Truncate to 24 bits
 171         xorl    %ebx,%ebx
 172         jmp     L_store
 173 
 174 
 175 LRound_To_53:
 176         movl    %esi,%ecx
 177         andl    CW_RC,%ecx
 178         cmpl    RC_RND,%ecx
 179         je      LRound_nearest_53
 180 
 181         cmpl    RC_CHOP,%ecx
 182         je      LTruncate_53
 183 
 184         cmpl    RC_UP,%ecx              // Towards +infinity
 185         je      LUp_53
 186 
 187         cmpl    RC_DOWN,%ecx            // Towards -infinity
 188         je      LDown_53
 189 
 190 #ifdef PARANOID
 191         jmp     L_bugged
 192 #endif PARANOID
 193 
 194 LUp_53:
 195         cmpb    SIGN_POS,SIGN(%edi)
 196         je      LUp_53_pos
 197 
 198         movl    %ebx,%ecx
 199         andl    $0x000007ff,%ecx
 200         orl     %edx,%ecx
 201         jnz     LTruncate_53
 202         jmp     L_store
 203 
 204 LUp_53_pos:
 205         movl    %ebx,%ecx
 206         andl    $0x000007ff,%ecx
 207         orl     %edx,%ecx
 208         jnz     LDo_53_round_up
 209         jmp     L_store
 210 
 211 LDown_53:
 212         cmpb    SIGN_POS,SIGN(%edi)
 213         je      LDown_53_pos
 214 
 215         movl    %ebx,%ecx
 216         andl    $0x000007ff,%ecx
 217         orl     %edx,%ecx
 218         jnz     LDo_53_round_up
 219         jmp     L_store
 220 
 221 LDown_53_pos:
 222         movl    %ebx,%ecx
 223         andl    $0x000007ff,%ecx
 224         orl     %edx,%ecx
 225         jnz     LTruncate_53
 226         jmp     L_store
 227 
 228 LRound_nearest_53:
 229         // Do rounding of the 53rd bit if needed (nearest or even)
 230         movl    %ebx,%ecx
 231         andl    $0x000007ff,%ecx
 232         cmpl    $0x00000400,%ecx
 233         jc      LTruncate_53            // less than half, no increment needed
 234 
 235         jne     LGreater_Half_53        // greater than half, increment needed
 236 
 237         // Possibly half, we need to check the ls bits
 238         orl     %edx,%edx
 239         jne     LGreater_Half_53        // greater than half, increment needed
 240 
 241         // Exactly half, increment only if 53rd bit is 1 (round to even)
 242         testl   $0x00000800,%ebx
 243         jz      LTruncate_53
 244 
 245 LGreater_Half_53:                       // Rounding: increment at the 53rd bit
 246 LDo_53_round_up:
 247         andl    $0xfffff800,%ebx        // Truncate to 53 bits
 248         addl    $0x00000800,%ebx
 249         adcl    $0,%eax
 250         jmp     LCheck_Round_Overflow
 251 
 252 LTruncate_53:
 253         andl    $0xfffff800,%ebx        // Truncate to 53 bits
 254         jmp     L_store
 255 
 256 
 257 LRound_To_64:
 258         movl    %esi,%ecx
 259         andl    CW_RC,%ecx
 260         cmpl    RC_RND,%ecx
 261         je      LRound_nearest_64
 262 
 263         cmpl    RC_CHOP,%ecx
 264         je      LTruncate_64
 265 
 266         cmpl    RC_UP,%ecx              // Towards +infinity
 267         je      LUp_64
 268 
 269         cmpl    RC_DOWN,%ecx            // Towards -infinity
 270         je      LDown_64
 271 
 272 #ifdef PARANOID
 273         jmp     L_bugged
 274 #endif PARANOID
 275 
 276 LUp_64:
 277         cmpb    SIGN_POS,SIGN(%edi)
 278         je      LUp_64_pos
 279 
 280         orl     %edx,%edx
 281         jnz     LTruncate_64
 282         jmp     L_store
 283 
 284 LUp_64_pos:
 285         orl     %edx,%edx
 286         jnz     LDo_64_round_up
 287         jmp     L_store
 288 
 289 LDown_64:
 290         cmpb    SIGN_POS,SIGN(%edi)
 291         je      LDown_64_pos
 292 
 293         orl     %edx,%edx
 294         jnz     LDo_64_round_up
 295         jmp     L_store
 296 
 297 LDown_64_pos:
 298         orl     %edx,%edx
 299         jnz     LTruncate_64
 300         jmp     L_store
 301 
 302 LRound_nearest_64:
 303         cmpl    $0x80000000,%edx
 304         jc      LTruncate_64
 305 
 306         jne     LDo_64_round_up
 307 
 308         /* Now test for round-to-even */
 309         testb   $1,%ebx
 310         jz      LTruncate_64
 311 
 312 LDo_64_round_up:
 313         addl    $1,%ebx
 314         adcl    $0,%eax
 315 
 316 LCheck_Round_Overflow:
 317         jnc     L_store         /* Rounding done, no overflow */
 318 
 319         /* Overflow, adjust the result (to 1.0) */
 320         rcrl    $1,%eax
 321         rcrl    $1,%ebx
 322         incl    EXP(%edi)
 323 
 324 LTruncate_64:
 325 L_store:
 326         /* store the result */
 327         movl    %eax,SIGH(%edi)
 328         movl    %ebx,SIGL(%edi)
 329 
 330         movb    TW_Valid,TAG(%edi)              /* Set the tags to TW_Valid */
 331 
 332         // The number may have overflowed
 333         cmpl    EXP_OVER,EXP(%edi)
 334         jge     L_overflow
 335 
 336         cmpl    EXP_UNDER,EXP(%edi)
 337         jle     L_underflow
 338 
 339 L_exit:
 340         popl    %ebx
 341         popl    %edi
 342         popl    %esi
 343         leave
 344         ret
 345 
 346 
 347 /* The operations resulted in a number too large to represent */
 348 L_overflow:
 349         push    %edi
 350         call    _arith_overflow
 351         pop     %edi
 352         jmp     L_exit
 353 
 354 /* The operations resulted in a number too small to represent */
 355 L_underflow:
 356         pushl   %edi
 357         call    _arith_underflow
 358         popl    %edi
 359         jmp     L_exit
 360 
 361 
 362 #ifdef PARANOID
 363 /* If we ever get here then we have problems! */
 364 L_bugged:
 365         pushl   EX_INTERNAL|0x201
 366         call    EXCEPTION
 367         pop     %ebx
 368         jmp     L_exit
 369 #endif PARANOID

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