| 1 | .file "reg_u_sub.S" |
| 2 | /* |
| 3 | * reg_u_sub.S |
| 4 | * |
| 5 | * Core floating point subtraction routine. |
| 6 | * |
| 7 | * Call from C as: |
| 8 | * void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, |
| 9 | * int control_w) |
| 10 | * |
| 11 | * |
| 12 | * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, |
| 13 | * Vic 3163, Australia. |
| 14 | * E-mail apm233m@vaxc.cc.monash.edu.au |
| 15 | * All rights reserved. |
| 16 | * |
| 17 | * This copyright notice covers the redistribution and use of the |
| 18 | * FPU emulator developed by W. Metzenthen. It covers only its use |
| 19 | * in the 386BSD operating system. Any other use is not permitted |
| 20 | * under this copyright. |
| 21 | * |
| 22 | * Redistribution and use in source and binary forms, with or without |
| 23 | * modification, are permitted provided that the following conditions |
| 24 | * are met: |
| 25 | * 1. Redistributions of source code must retain the above copyright |
| 26 | * notice, this list of conditions and the following disclaimer. |
| 27 | * 2. Redistributions in binary form must include information specifying |
| 28 | * that source code for the emulator is freely available and include |
| 29 | * either: |
| 30 | * a) an offer to provide the source code for a nominal distribution |
| 31 | * fee, or |
| 32 | * b) list at least two alternative methods whereby the source |
| 33 | * can be obtained, e.g. a publically accessible bulletin board |
| 34 | * and an anonymous ftp site from which the software can be |
| 35 | * downloaded. |
| 36 | * 3. All advertising materials specifically mentioning features or use of |
| 37 | * this emulator must acknowledge that it was developed by W. Metzenthen. |
| 38 | * 4. The name of W. Metzenthen may not be used to endorse or promote |
| 39 | * products derived from this software without specific prior written |
| 40 | * permission. |
| 41 | * |
| 42 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, |
| 43 | * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY |
| 44 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL |
| 45 | * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| 46 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| 47 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| 48 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| 49 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| 50 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 51 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 52 | * |
| 53 | */ |
| 54 | |
| 55 | /* |
| 56 | | Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ). |
| 57 | | Takes two valid reg f.p. numbers (TW_Valid), which are |
| 58 | | treated as unsigned numbers, |
| 59 | | and returns their difference as a TW_Valid or TW_Zero f.p. |
| 60 | | number. |
| 61 | | The first number (arg1) must be the larger. |
| 62 | | The returned number is normalized. |
| 63 | | Basic checks are performed if PARANOID is defined. |
| 64 | */ |
| 65 | |
| 66 | #include "exception.h" |
| 67 | #include "fpu_asm.h" |
| 68 | #include "control_w.h" |
| 69 | |
| 70 | .text |
| 71 | .align 2,144 |
| 72 | .globl _reg_u_sub |
| 73 | _reg_u_sub: |
| 74 | pushl %ebp |
| 75 | movl %esp,%ebp |
| 76 | pushl %esi |
| 77 | pushl %edi |
| 78 | pushl %ebx |
| 79 | |
| 80 | movl PARAM1,%esi /* source 1 */ |
| 81 | movl PARAM2,%edi /* source 2 */ |
| 82 | |
| 83 | #ifdef DENORM_OPERAND |
| 84 | cmpl EXP_UNDER,EXP(%esi) |
| 85 | jg xOp1_not_denorm |
| 86 | |
| 87 | call _denormal_operand |
| 88 | orl %eax,%eax |
| 89 | jnz FPU_Arith_exit |
| 90 | |
| 91 | xOp1_not_denorm: |
| 92 | cmpl EXP_UNDER,EXP(%edi) |
| 93 | jg xOp2_not_denorm |
| 94 | |
| 95 | call _denormal_operand |
| 96 | orl %eax,%eax |
| 97 | jnz FPU_Arith_exit |
| 98 | |
| 99 | xOp2_not_denorm: |
| 100 | #endif DENORM_OPERAND |
| 101 | |
| 102 | /* xorl %ecx,%ecx */ |
| 103 | movl EXP(%esi),%ecx |
| 104 | subl EXP(%edi),%ecx /* exp1 - exp2 */ |
| 105 | |
| 106 | #ifdef PARANOID |
| 107 | /* source 2 is always smaller than source 1 */ |
| 108 | /* jc L_bugged */ |
| 109 | js L_bugged_1 |
| 110 | |
| 111 | testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */ |
| 112 | je L_bugged_2 |
| 113 | |
| 114 | testl $0x80000000,SIGH(%esi) |
| 115 | je L_bugged_2 |
| 116 | #endif PARANOID |
| 117 | |
| 118 | /*--------------------------------------+ |
| 119 | | Form a register holding the | |
| 120 | | smaller number | |
| 121 | +--------------------------------------*/ |
| 122 | movl SIGH(%edi),%eax /* register ms word */ |
| 123 | movl SIGL(%edi),%ebx /* register ls word */ |
| 124 | |
| 125 | movl PARAM3,%edi /* destination */ |
| 126 | movl EXP(%esi),%edx |
| 127 | movl %edx,EXP(%edi) /* Copy exponent to destination */ |
| 128 | movb SIGN(%esi),%dl |
| 129 | movb %dl,SIGN(%edi) /* Copy the sign from the first arg */ |
| 130 | |
| 131 | xorl %edx,%edx /* register extension */ |
| 132 | |
| 133 | /*--------------------------------------+ |
| 134 | | Shift the temporary register | |
| 135 | | right the required number of | |
| 136 | | places. | |
| 137 | +--------------------------------------*/ |
| 138 | L_shift_r: |
| 139 | cmpl $32,%ecx /* shrd only works for 0..31 bits */ |
| 140 | jnc L_more_than_31 |
| 141 | |
| 142 | /* less than 32 bits */ |
| 143 | shrd %cl,%ebx,%edx |
| 144 | shrd %cl,%eax,%ebx |
| 145 | shr %cl,%eax |
| 146 | jmp L_shift_done |
| 147 | |
| 148 | L_more_than_31: |
| 149 | cmpl $64,%ecx |
| 150 | jnc L_more_than_63 |
| 151 | |
| 152 | subb $32,%cl |
| 153 | jz L_exactly_32 |
| 154 | |
| 155 | shrd %cl,%eax,%edx |
| 156 | shr %cl,%eax |
| 157 | orl %ebx,%ebx |
| 158 | jz L_more_31_no_low /* none of the lowest bits is set */ |
| 159 | |
| 160 | orl $1,%edx /* record the fact in the extension */ |
| 161 | |
| 162 | L_more_31_no_low: |
| 163 | movl %eax,%ebx |
| 164 | xorl %eax,%eax |
| 165 | jmp L_shift_done |
| 166 | |
| 167 | L_exactly_32: |
| 168 | movl %ebx,%edx |
| 169 | movl %eax,%ebx |
| 170 | xorl %eax,%eax |
| 171 | jmp L_shift_done |
| 172 | |
| 173 | L_more_than_63: |
| 174 | cmpw $65,%cx |
| 175 | jnc L_more_than_64 |
| 176 | |
| 177 | /* Shift right by 64 bits */ |
| 178 | movl %eax,%edx |
| 179 | orl %ebx,%ebx |
| 180 | jz L_more_63_no_low |
| 181 | |
| 182 | orl $1,%edx |
| 183 | jmp L_more_63_no_low |
| 184 | |
| 185 | L_more_than_64: |
| 186 | jne L_more_than_65 |
| 187 | |
| 188 | /* Shift right by 65 bits */ |
| 189 | /* Carry is clear if we get here */ |
| 190 | movl %eax,%edx |
| 191 | rcrl %edx |
| 192 | jnc L_shift_65_nc |
| 193 | |
| 194 | orl $1,%edx |
| 195 | jmp L_more_63_no_low |
| 196 | |
| 197 | L_shift_65_nc: |
| 198 | orl %ebx,%ebx |
| 199 | jz L_more_63_no_low |
| 200 | |
| 201 | orl $1,%edx |
| 202 | jmp L_more_63_no_low |
| 203 | |
| 204 | L_more_than_65: |
| 205 | movl $1,%edx /* The shifted nr always at least one '1' */ |
| 206 | |
| 207 | L_more_63_no_low: |
| 208 | xorl %ebx,%ebx |
| 209 | xorl %eax,%eax |
| 210 | |
| 211 | L_shift_done: |
| 212 | L_subtr: |
| 213 | /*------------------------------+ |
| 214 | | Do the subtraction | |
| 215 | +------------------------------*/ |
| 216 | xorl %ecx,%ecx |
| 217 | subl %edx,%ecx |
| 218 | movl %ecx,%edx |
| 219 | movl SIGL(%esi),%ecx |
| 220 | sbbl %ebx,%ecx |
| 221 | movl %ecx,%ebx |
| 222 | movl SIGH(%esi),%ecx |
| 223 | sbbl %eax,%ecx |
| 224 | movl %ecx,%eax |
| 225 | |
| 226 | #ifdef PARANOID |
| 227 | /* We can never get a borrow */ |
| 228 | jc L_bugged |
| 229 | #endif PARANOID |
| 230 | |
| 231 | /*--------------------------------------+ |
| 232 | | Normalize the result | |
| 233 | +--------------------------------------*/ |
| 234 | testl $0x80000000,%eax |
| 235 | jnz L_round /* no shifting needed */ |
| 236 | |
| 237 | orl %eax,%eax |
| 238 | jnz L_shift_1 /* shift left 1 - 31 bits */ |
| 239 | |
| 240 | orl %ebx,%ebx |
| 241 | jnz L_shift_32 /* shift left 32 - 63 bits */ |
| 242 | |
| 243 | /* A rare case, the only one which is non-zero if we got here |
| 244 | // is: 1000000 .... 0000 |
| 245 | // -0111111 .... 1111 1 |
| 246 | // -------------------- |
| 247 | // 0000000 .... 0000 1 */ |
| 248 | |
| 249 | cmpl $0x80000000,%edx |
| 250 | jnz L_must_be_zero |
| 251 | |
| 252 | /* Shift left 64 bits */ |
| 253 | subl $64,EXP(%edi) |
| 254 | movl %edx,%eax |
| 255 | jmp L_store |
| 256 | |
| 257 | L_must_be_zero: |
| 258 | #ifdef PARANOID |
| 259 | orl %edx,%edx |
| 260 | jnz L_bugged_3 |
| 261 | #endif PARANOID |
| 262 | |
| 263 | /* The result is zero */ |
| 264 | movb TW_Zero,TAG(%edi) |
| 265 | movl $0,EXP(%edi) /* exponent */ |
| 266 | movl $0,SIGL(%edi) |
| 267 | movl $0,SIGH(%edi) |
| 268 | jmp L_exit /* Does not underflow */ |
| 269 | |
| 270 | L_shift_32: |
| 271 | movl %ebx,%eax |
| 272 | movl %edx,%ebx |
| 273 | movl $0,%edx |
| 274 | subl $32,EXP(%edi) /* Can get underflow here */ |
| 275 | |
| 276 | /* We need to shift left by 1 - 31 bits */ |
| 277 | L_shift_1: |
| 278 | bsrl %eax,%ecx /* get the required shift in %ecx */ |
| 279 | subl $31,%ecx |
| 280 | negl %ecx |
| 281 | shld %cl,%ebx,%eax |
| 282 | shld %cl,%edx,%ebx |
| 283 | shl %cl,%edx |
| 284 | subl %ecx,EXP(%edi) /* Can get underflow here */ |
| 285 | |
| 286 | L_round: |
| 287 | jmp FPU_round /* Round the result */ |
| 288 | |
| 289 | |
| 290 | #ifdef PARANOID |
| 291 | L_bugged_1: |
| 292 | pushl EX_INTERNAL|0x206 |
| 293 | call EXCEPTION |
| 294 | pop %ebx |
| 295 | jmp L_exit |
| 296 | |
| 297 | L_bugged_2: |
| 298 | pushl EX_INTERNAL|0x209 |
| 299 | call EXCEPTION |
| 300 | pop %ebx |
| 301 | jmp L_exit |
| 302 | |
| 303 | L_bugged_3: |
| 304 | pushl EX_INTERNAL|0x210 |
| 305 | call EXCEPTION |
| 306 | pop %ebx |
| 307 | jmp L_exit |
| 308 | |
| 309 | L_bugged_4: |
| 310 | pushl EX_INTERNAL|0x211 |
| 311 | call EXCEPTION |
| 312 | pop %ebx |
| 313 | jmp L_exit |
| 314 | |
| 315 | L_bugged: |
| 316 | pushl EX_INTERNAL|0x212 |
| 317 | call EXCEPTION |
| 318 | pop %ebx |
| 319 | jmp L_exit |
| 320 | #endif PARANOID |
| 321 | |
| 322 | |
| 323 | L_store: |
| 324 | /*------------------------------+ |
| 325 | | Store the result | |
| 326 | +------------------------------*/ |
| 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 | cmpl EXP_UNDER,EXP(%edi) |
| 333 | jle L_underflow |
| 334 | |
| 335 | L_exit: |
| 336 | popl %ebx |
| 337 | popl %edi |
| 338 | popl %esi |
| 339 | leave |
| 340 | ret |
| 341 | |
| 342 | |
| 343 | L_underflow: |
| 344 | push %edi |
| 345 | call _arith_underflow |
| 346 | pop %ebx |
| 347 | jmp L_exit |
| 348 | |