1 .file "reg_u_div.S" 2/* 3 * reg_u_div.S 4 * 5 * Core division routines 6 * 7 * 8 * Copyright (C) 1992, 1993 W. Metzenthen, 22 Parker St, Ormond, 9 * Vic 3163, Australia. 10 * E-mail apm233m@vaxc.cc.monash.edu.au 11 * All rights reserved. 12 * 13 * This copyright notice covers the redistribution and use of the 14 * FPU emulator developed by W. Metzenthen. It covers only its use 15 * in the 386BSD operating system. Any other use is not permitted 16 * under this copyright. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions 20 * are met: 21 * 1. Redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer. 23 * 2. Redistributions in binary form must include information specifying 24 * that source code for the emulator is freely available and include 25 * either: 26 * a) an offer to provide the source code for a nominal distribution 27 * fee, or 28 * b) list at least two alternative methods whereby the source 29 * can be obtained, e.g. a publically accessible bulletin board 30 * and an anonymous ftp site from which the software can be 31 * downloaded. 32 * 3. All advertising materials specifically mentioning features or use of 33 * this emulator must acknowledge that it was developed by W. Metzenthen. 34 * 4. The name of W. Metzenthen may not be used to endorse or promote 35 * products derived from this software without specific prior written 36 * permission. 37 * 38 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 39 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 40 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 41 * W. METZENTHEN BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 42 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 43 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 44 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 45 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 46 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 47 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 * 49 */ 50 51/*---------------------------------------------------------------------------+ 52 | Kernel for the division routines. | 53 | | 54 | void reg_u_div(FPU_REG *a, FPU_REG *a, | 55 | FPU_REG *dest, unsigned int control_word) | 56 | | 57 | Does not compute the destination exponent, but does adjust it. | 58 +---------------------------------------------------------------------------*/ 59 60#include "exception.h" 61#include "fpu_asm.h" 62#include "control_w.h" 63 64 65 # // #define dSIGL(x) (x) 66 # // #define dSIGH(x) 4(x) 67 68 69.data 70/* 71 Local storage: 72 Result: accum_3:accum_2:accum_1:accum_0 73 Overflow flag: ovfl_flag 74 */ 75 .align 2,0 76accum_3: 77 .long 0 78accum_2: 79 .long 0 80accum_1: 81 .long 0 82accum_0: 83 .long 0 84result_1: 85 .long 0 86result_2: 87 .long 0 88ovfl_flag: 89 .byte 0 90 91 92.text 93 .align 2,144 94 95.globl _reg_u_div 96 97.globl _divide_kernel 98 99_reg_u_div: 100 pushl %ebp 101 movl %esp,%ebp 102 103 pushl %esi 104 pushl %edi 105 pushl %ebx 106 107 movl PARAM1,%esi /* pointer to num */ 108 movl PARAM2,%ebx /* pointer to denom */ 109 movl PARAM3,%edi /* pointer to answer */ 110 111#ifdef DENORM_OPERAND 112 movl EXP(%esi),%eax 113 cmpl EXP_UNDER,%eax 114 jg xOp1_not_denorm 115 116 call _denormal_operand 117 orl %eax,%eax 118 jnz FPU_Arith_exit 119 120xOp1_not_denorm: 121 movl EXP(%ebx),%eax 122 cmpl EXP_UNDER,%eax 123 jg xOp2_not_denorm 124 125 call _denormal_operand 126 orl %eax,%eax 127 jnz FPU_Arith_exit 128 129xOp2_not_denorm: 130#endif DENORM_OPERAND 131 132_divide_kernel: 133#ifdef PARANOID 134 # // testl $0x80000000, SIGH(%esi) // Dividend 135 # // je L_bugged 136 testl $0x80000000, SIGH(%ebx) # // Divisor 137 je L_bugged 138#endif PARANOID 139 140/* Check if the divisor can be treated as having just 32 bits */ 141 cmpl $0,SIGL(%ebx) 142 jnz L_Full_Division /* Can't do a quick divide */ 143 144/* We should be able to zip through the division here */ 145 movl SIGH(%ebx),%ecx /* The divisor */ 146 movl SIGH(%esi),%edx /* Dividend */ 147 movl SIGL(%esi),%eax /* Dividend */ 148 149 cmpl %ecx,%edx 150 setaeb ovfl_flag /* Keep a record */ 151 jb L_no_adjust 152 153 subl %ecx,%edx /* Prevent the overflow */ 154 155L_no_adjust: 156 /* Divide the 64 bit number by the 32 bit denominator */ 157 divl %ecx 158 movl %eax,result_2 159 160 /* Work on the remainder of the first division */ 161 xorl %eax,%eax 162 divl %ecx 163 movl %eax,result_1 164 165 /* Work on the remainder of the 64 bit division */ 166 xorl %eax,%eax 167 divl %ecx 168 169 testb $255,ovfl_flag /* was the num > denom ? */ 170 je L_no_overflow 171 172 /* Do the shifting here */ 173 /* increase the exponent */ 174 incl EXP(%edi) 175 176 /* shift the mantissa right one bit */ 177 stc /* To set the ms bit */ 178 rcrl result_2 179 rcrl result_1 180 rcrl %eax 181 182L_no_overflow: 183 jmp LRound_precision # // Do the rounding as required 184 185 186/*---------------------------------------------------------------------------+ 187 | Divide: Return arg1/arg2 to arg3. | 188 | | 189 | This routine does not use the exponents of arg1 and arg2, but does | 190 | adjust the exponent of arg3. | 191 | | 192 | The maximum returned value is (ignoring exponents) | 193 | .ffffffff ffffffff | 194 | ------------------ = 1.ffffffff fffffffe | 195 | .80000000 00000000 | 196 | and the minimum is | 197 | .80000000 00000000 | 198 | ------------------ = .80000000 00000001 (rounded) | 199 | .ffffffff ffffffff | 200 | | 201 +---------------------------------------------------------------------------*/ 202 203 204L_Full_Division: 205 # // Save extended dividend in local register 206 movl SIGL(%esi),%eax 207 movl %eax,accum_2 208 movl SIGH(%esi),%eax 209 movl %eax,accum_3 210 xorl %eax,%eax 211 movl %eax,accum_1 /* zero the extension */ 212 movl %eax,accum_0 /* zero the extension */ 213 214 movl SIGL(%esi),%eax /* Get the current num */ 215 movl SIGH(%esi),%edx 216 217/*----------------------------------------------------------------------*/ 218/* Initialization done */ 219/* Do the first 32 bits */ 220 221 movb $0,ovfl_flag 222 cmpl SIGH(%ebx),%edx /* Test for imminent overflow */ 223 jb LLess_than_1 224 ja LGreater_than_1 225 226 cmpl SIGL(%ebx),%eax 227 jb LLess_than_1 228 229LGreater_than_1: 230/* The dividend is greater or equal, would cause overflow */ 231 setaeb ovfl_flag /* Keep a record */ 232 233 subl SIGL(%ebx),%eax 234 sbbl SIGH(%ebx),%edx /* Prevent the overflow */ 235 movl %eax,accum_2 236 movl %edx,accum_3 237 238LLess_than_1: 239/* At this point, we have a dividend < divisor, with a record of 240 adjustment in ovfl_flag */ 241 242 /* We will divide by a number which is too large */ 243 movl SIGH(%ebx),%ecx 244 addl $1,%ecx 245 jnc LFirst_div_not_1 246 247 /* here we need to divide by 100000000h, 248 i.e., no division at all.. */ 249 mov %edx,%eax 250 jmp LFirst_div_done 251 252LFirst_div_not_1: 253 divl %ecx /* Divide the numerator by the augmented 254 denom ms dw */ 255 256LFirst_div_done: 257 movl %eax,result_2 /* Put the result in the answer */ 258 259 mull SIGH(%ebx) /* mul by the ms dw of the denom */ 260 261 subl %eax,accum_2 /* Subtract from the num local reg */ 262 sbbl %edx,accum_3 263 264 movl result_2,%eax /* Get the result back */ 265 mull SIGL(%ebx) /* now mul the ls dw of the denom */ 266 267 subl %eax,accum_1 /* Subtract from the num local reg */ 268 sbbl %edx,accum_2 269 sbbl $0,accum_3 270 je LDo_2nd_32_bits /* Must check for non-zero result here */ 271 272#ifdef PARANOID 273 jb L_bugged_1 274#endif PARANOID 275 276 /* need to subtract another once of the denom */ 277 incl result_2 /* Correct the answer */ 278 279 movl SIGL(%ebx),%eax 280 movl SIGH(%ebx),%edx 281 subl %eax,accum_1 /* Subtract from the num local reg */ 282 sbbl %edx,accum_2 283 284#ifdef PARANOID 285 sbbl $0,accum_3 286 jne L_bugged_1 /* Must check for non-zero result here */ 287#endif PARANOID 288 289/*----------------------------------------------------------------------*/ 290/* Half of the main problem is done, there is just a reduced numerator 291 to handle now */ 292/* Work with the second 32 bits, accum_0 not used from now on */ 293LDo_2nd_32_bits: 294 movl accum_2,%edx /* get the reduced num */ 295 movl accum_1,%eax 296 297 /* need to check for possible subsequent overflow */ 298 cmpl SIGH(%ebx),%edx 299 jb LDo_2nd_div 300 ja LPrevent_2nd_overflow 301 302 cmpl SIGL(%ebx),%eax 303 jb LDo_2nd_div 304 305LPrevent_2nd_overflow: 306/* The numerator is greater or equal, would cause overflow */ 307 /* prevent overflow */ 308 subl SIGL(%ebx),%eax 309 sbbl SIGH(%ebx),%edx 310 movl %edx,accum_2 311 movl %eax,accum_1 312 313 incl result_2 /* Reflect the subtraction in the answer */ 314 315#ifdef PARANOID 316 je L_bugged_2 /* Can't bump the result to 1.0 */ 317#endif PARANOID 318 319LDo_2nd_div: 320 cmpl $0,%ecx # // augmented denom msw 321 jnz LSecond_div_not_1 322 323 /* %ecx == 0, we are dividing by 1.0 */ 324 mov %edx,%eax 325 jmp LSecond_div_done 326 327LSecond_div_not_1: 328 divl %ecx /* Divide the numerator by the denom ms dw */ 329 330LSecond_div_done: 331 movl %eax,result_1 /* Put the result in the answer */ 332 333 mull SIGH(%ebx) /* mul by the ms dw of the denom */ 334 335 subl %eax,accum_1 /* Subtract from the num local reg */ 336 sbbl %edx,accum_2 337 338#ifdef PARANOID 339 jc L_bugged_2 340#endif PARANOID 341 342 movl result_1,%eax /* Get the result back */ 343 mull SIGL(%ebx) /* now mul the ls dw of the denom */ 344 345 subl %eax,accum_0 /* Subtract from the num local reg */ 346 sbbl %edx,accum_1 /* Subtract from the num local reg */ 347 sbbl $0,accum_2 348 349#ifdef PARANOID 350 jc L_bugged_2 351#endif PARANOID 352 353 jz LDo_3rd_32_bits 354 355#ifdef PARANOID 356 cmpl $1,accum_2 357 jne L_bugged_2 358#endif PARANOID 359 360 /* need to subtract another once of the denom */ 361 movl SIGL(%ebx),%eax 362 movl SIGH(%ebx),%edx 363 subl %eax,accum_0 /* Subtract from the num local reg */ 364 sbbl %edx,accum_1 365 sbbl $0,accum_2 366 367#ifdef PARANOID 368 jc L_bugged_2 369 jne L_bugged_2 370#endif PARANOID 371 372 addl $1,result_1 /* Correct the answer */ 373 adcl $0,result_2 374 375#ifdef PARANOID 376 jc L_bugged_2 /* Must check for non-zero result here */ 377#endif PARANOID 378 379/*----------------------------------------------------------------------*/ 380/* The division is essentially finished here, we just need to perform 381 tidying operations. */ 382/* deal with the 3rd 32 bits */ 383LDo_3rd_32_bits: 384 movl accum_1,%edx /* get the reduced num */ 385 movl accum_0,%eax 386 387 /* need to check for possible subsequent overflow */ 388 cmpl SIGH(%ebx),%edx # // denom 389 jb LRound_prep 390 ja LPrevent_3rd_overflow 391 392 cmpl SIGL(%ebx),%eax # // denom 393 jb LRound_prep 394 395LPrevent_3rd_overflow: 396 /* prevent overflow */ 397 subl SIGL(%ebx),%eax 398 sbbl SIGH(%ebx),%edx 399 movl %edx,accum_1 400 movl %eax,accum_0 401 402 addl $1,result_1 /* Reflect the subtraction in the answer */ 403 adcl $0,result_2 404 jne LRound_prep 405 jnc LRound_prep 406 407 /* This is a tricky spot, there is an overflow of the answer */ 408 movb $255,ovfl_flag /* Overflow -> 1.000 */ 409 410LRound_prep: 411 # // Prepare for rounding. 412 # // To test for rounding, we just need to compare 2*accum with the 413 # // denom. 414 movl accum_0,%ecx 415 movl accum_1,%edx 416 movl %ecx,%eax 417 orl %edx,%eax 418 jz LRound_ovfl # // The accumulator contains zero. 419 420 # // Multiply by 2 421 clc 422 rcll $1,%ecx 423 rcll $1,%edx 424 jc LRound_large # // No need to compare, denom smaller 425 426 subl SIGL(%ebx),%ecx 427 sbbl SIGH(%ebx),%edx 428 jnc LRound_not_small 429 430 movl $0x70000000,%eax # // Denom was larger 431 jmp LRound_ovfl 432 433LRound_not_small: 434 jnz LRound_large 435 436 movl $0x80000000,%eax # // Remainder was exactly 1/2 denom 437 jmp LRound_ovfl 438 439LRound_large: 440 movl $0xff000000,%eax # // Denom was smaller 441 442LRound_ovfl: 443/* We are now ready to deal with rounding, but first we must get 444 the bits properly aligned */ 445 testb $255,ovfl_flag /* was the num > denom ? */ 446 je LRound_precision 447 448 incl EXP(%edi) 449 450 /* shift the mantissa right one bit */ 451 stc # // Will set the ms bit 452 rcrl result_2 453 rcrl result_1 454 rcrl %eax 455 456 # // Round the result as required 457LRound_precision: 458 decl EXP(%edi) /* binary point between 1st & 2nd bits */ 459 460 movl %eax,%edx 461 movl result_1,%ebx 462 movl result_2,%eax 463 jmp FPU_round 464 465 466#ifdef PARANOID 467/* The logic is wrong if we got here */ 468L_bugged: 469 pushl EX_INTERNAL|0x202 470 call EXCEPTION 471 pop %ebx 472 jmp L_exit 473 474L_bugged_1: 475 pushl EX_INTERNAL|0x203 476 call EXCEPTION 477 pop %ebx 478 jmp L_exit 479 480L_bugged_2: 481 pushl EX_INTERNAL|0x204 482 call EXCEPTION 483 pop %ebx 484 jmp L_exit 485 486L_exit: 487 popl %ebx 488 popl %edi 489 popl %esi 490 491 leave 492 ret 493#endif PARANOID 494