1*4882a593Smuzhiyun/* SPDX-License-Identifier: GPL-2.0 */ 2*4882a593Smuzhiyun .file "reg_u_div.S" 3*4882a593Smuzhiyun/*---------------------------------------------------------------------------+ 4*4882a593Smuzhiyun | reg_u_div.S | 5*4882a593Smuzhiyun | | 6*4882a593Smuzhiyun | Divide one FPU_REG by another and put the result in a destination FPU_REG.| 7*4882a593Smuzhiyun | | 8*4882a593Smuzhiyun | Copyright (C) 1992,1993,1995,1997 | 9*4882a593Smuzhiyun | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, Australia | 10*4882a593Smuzhiyun | E-mail billm@suburbia.net | 11*4882a593Smuzhiyun | | 12*4882a593Smuzhiyun | | 13*4882a593Smuzhiyun +---------------------------------------------------------------------------*/ 14*4882a593Smuzhiyun 15*4882a593Smuzhiyun/*---------------------------------------------------------------------------+ 16*4882a593Smuzhiyun | Call from C as: | 17*4882a593Smuzhiyun | int FPU_u_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest, | 18*4882a593Smuzhiyun | unsigned int control_word, char *sign) | 19*4882a593Smuzhiyun | | 20*4882a593Smuzhiyun | Does not compute the destination exponent, but does adjust it. | 21*4882a593Smuzhiyun | | 22*4882a593Smuzhiyun | Return value is the tag of the answer, or-ed with FPU_Exception if | 23*4882a593Smuzhiyun | one was raised, or -1 on internal error. | 24*4882a593Smuzhiyun +---------------------------------------------------------------------------*/ 25*4882a593Smuzhiyun 26*4882a593Smuzhiyun#include "exception.h" 27*4882a593Smuzhiyun#include "fpu_emu.h" 28*4882a593Smuzhiyun#include "control_w.h" 29*4882a593Smuzhiyun 30*4882a593Smuzhiyun 31*4882a593Smuzhiyun/* #define dSIGL(x) (x) */ 32*4882a593Smuzhiyun/* #define dSIGH(x) 4(x) */ 33*4882a593Smuzhiyun 34*4882a593Smuzhiyun 35*4882a593Smuzhiyun#ifndef NON_REENTRANT_FPU 36*4882a593Smuzhiyun/* 37*4882a593Smuzhiyun Local storage on the stack: 38*4882a593Smuzhiyun Result: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0 39*4882a593Smuzhiyun Overflow flag: ovfl_flag 40*4882a593Smuzhiyun */ 41*4882a593Smuzhiyun#define FPU_accum_3 -4(%ebp) 42*4882a593Smuzhiyun#define FPU_accum_2 -8(%ebp) 43*4882a593Smuzhiyun#define FPU_accum_1 -12(%ebp) 44*4882a593Smuzhiyun#define FPU_accum_0 -16(%ebp) 45*4882a593Smuzhiyun#define FPU_result_1 -20(%ebp) 46*4882a593Smuzhiyun#define FPU_result_2 -24(%ebp) 47*4882a593Smuzhiyun#define FPU_ovfl_flag -28(%ebp) 48*4882a593Smuzhiyun 49*4882a593Smuzhiyun#else 50*4882a593Smuzhiyun.data 51*4882a593Smuzhiyun/* 52*4882a593Smuzhiyun Local storage in a static area: 53*4882a593Smuzhiyun Result: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0 54*4882a593Smuzhiyun Overflow flag: ovfl_flag 55*4882a593Smuzhiyun */ 56*4882a593Smuzhiyun .align 4,0 57*4882a593SmuzhiyunFPU_accum_3: 58*4882a593Smuzhiyun .long 0 59*4882a593SmuzhiyunFPU_accum_2: 60*4882a593Smuzhiyun .long 0 61*4882a593SmuzhiyunFPU_accum_1: 62*4882a593Smuzhiyun .long 0 63*4882a593SmuzhiyunFPU_accum_0: 64*4882a593Smuzhiyun .long 0 65*4882a593SmuzhiyunFPU_result_1: 66*4882a593Smuzhiyun .long 0 67*4882a593SmuzhiyunFPU_result_2: 68*4882a593Smuzhiyun .long 0 69*4882a593SmuzhiyunFPU_ovfl_flag: 70*4882a593Smuzhiyun .byte 0 71*4882a593Smuzhiyun#endif /* NON_REENTRANT_FPU */ 72*4882a593Smuzhiyun 73*4882a593Smuzhiyun#define REGA PARAM1 74*4882a593Smuzhiyun#define REGB PARAM2 75*4882a593Smuzhiyun#define DEST PARAM3 76*4882a593Smuzhiyun 77*4882a593Smuzhiyun.text 78*4882a593SmuzhiyunSYM_FUNC_START(FPU_u_div) 79*4882a593Smuzhiyun pushl %ebp 80*4882a593Smuzhiyun movl %esp,%ebp 81*4882a593Smuzhiyun#ifndef NON_REENTRANT_FPU 82*4882a593Smuzhiyun subl $28,%esp 83*4882a593Smuzhiyun#endif /* NON_REENTRANT_FPU */ 84*4882a593Smuzhiyun 85*4882a593Smuzhiyun pushl %esi 86*4882a593Smuzhiyun pushl %edi 87*4882a593Smuzhiyun pushl %ebx 88*4882a593Smuzhiyun 89*4882a593Smuzhiyun movl REGA,%esi 90*4882a593Smuzhiyun movl REGB,%ebx 91*4882a593Smuzhiyun movl DEST,%edi 92*4882a593Smuzhiyun 93*4882a593Smuzhiyun movswl EXP(%esi),%edx 94*4882a593Smuzhiyun movswl EXP(%ebx),%eax 95*4882a593Smuzhiyun subl %eax,%edx 96*4882a593Smuzhiyun addl EXP_BIAS,%edx 97*4882a593Smuzhiyun 98*4882a593Smuzhiyun /* A denormal and a large number can cause an exponent underflow */ 99*4882a593Smuzhiyun cmpl EXP_WAY_UNDER,%edx 100*4882a593Smuzhiyun jg xExp_not_underflow 101*4882a593Smuzhiyun 102*4882a593Smuzhiyun /* Set to a really low value allow correct handling */ 103*4882a593Smuzhiyun movl EXP_WAY_UNDER,%edx 104*4882a593Smuzhiyun 105*4882a593SmuzhiyunxExp_not_underflow: 106*4882a593Smuzhiyun 107*4882a593Smuzhiyun movw %dx,EXP(%edi) 108*4882a593Smuzhiyun 109*4882a593Smuzhiyun#ifdef PARANOID 110*4882a593Smuzhiyun/* testl $0x80000000, SIGH(%esi) // Dividend */ 111*4882a593Smuzhiyun/* je L_bugged */ 112*4882a593Smuzhiyun testl $0x80000000, SIGH(%ebx) /* Divisor */ 113*4882a593Smuzhiyun je L_bugged 114*4882a593Smuzhiyun#endif /* PARANOID */ 115*4882a593Smuzhiyun 116*4882a593Smuzhiyun/* Check if the divisor can be treated as having just 32 bits */ 117*4882a593Smuzhiyun cmpl $0,SIGL(%ebx) 118*4882a593Smuzhiyun jnz L_Full_Division /* Can't do a quick divide */ 119*4882a593Smuzhiyun 120*4882a593Smuzhiyun/* We should be able to zip through the division here */ 121*4882a593Smuzhiyun movl SIGH(%ebx),%ecx /* The divisor */ 122*4882a593Smuzhiyun movl SIGH(%esi),%edx /* Dividend */ 123*4882a593Smuzhiyun movl SIGL(%esi),%eax /* Dividend */ 124*4882a593Smuzhiyun 125*4882a593Smuzhiyun cmpl %ecx,%edx 126*4882a593Smuzhiyun setaeb FPU_ovfl_flag /* Keep a record */ 127*4882a593Smuzhiyun jb L_no_adjust 128*4882a593Smuzhiyun 129*4882a593Smuzhiyun subl %ecx,%edx /* Prevent the overflow */ 130*4882a593Smuzhiyun 131*4882a593SmuzhiyunL_no_adjust: 132*4882a593Smuzhiyun /* Divide the 64 bit number by the 32 bit denominator */ 133*4882a593Smuzhiyun divl %ecx 134*4882a593Smuzhiyun movl %eax,FPU_result_2 135*4882a593Smuzhiyun 136*4882a593Smuzhiyun /* Work on the remainder of the first division */ 137*4882a593Smuzhiyun xorl %eax,%eax 138*4882a593Smuzhiyun divl %ecx 139*4882a593Smuzhiyun movl %eax,FPU_result_1 140*4882a593Smuzhiyun 141*4882a593Smuzhiyun /* Work on the remainder of the 64 bit division */ 142*4882a593Smuzhiyun xorl %eax,%eax 143*4882a593Smuzhiyun divl %ecx 144*4882a593Smuzhiyun 145*4882a593Smuzhiyun testb $255,FPU_ovfl_flag /* was the num > denom ? */ 146*4882a593Smuzhiyun je L_no_overflow 147*4882a593Smuzhiyun 148*4882a593Smuzhiyun /* Do the shifting here */ 149*4882a593Smuzhiyun /* increase the exponent */ 150*4882a593Smuzhiyun incw EXP(%edi) 151*4882a593Smuzhiyun 152*4882a593Smuzhiyun /* shift the mantissa right one bit */ 153*4882a593Smuzhiyun stc /* To set the ms bit */ 154*4882a593Smuzhiyun rcrl FPU_result_2 155*4882a593Smuzhiyun rcrl FPU_result_1 156*4882a593Smuzhiyun rcrl %eax 157*4882a593Smuzhiyun 158*4882a593SmuzhiyunL_no_overflow: 159*4882a593Smuzhiyun jmp LRound_precision /* Do the rounding as required */ 160*4882a593Smuzhiyun 161*4882a593Smuzhiyun 162*4882a593Smuzhiyun/*---------------------------------------------------------------------------+ 163*4882a593Smuzhiyun | Divide: Return arg1/arg2 to arg3. | 164*4882a593Smuzhiyun | | 165*4882a593Smuzhiyun | This routine does not use the exponents of arg1 and arg2, but does | 166*4882a593Smuzhiyun | adjust the exponent of arg3. | 167*4882a593Smuzhiyun | | 168*4882a593Smuzhiyun | The maximum returned value is (ignoring exponents) | 169*4882a593Smuzhiyun | .ffffffff ffffffff | 170*4882a593Smuzhiyun | ------------------ = 1.ffffffff fffffffe | 171*4882a593Smuzhiyun | .80000000 00000000 | 172*4882a593Smuzhiyun | and the minimum is | 173*4882a593Smuzhiyun | .80000000 00000000 | 174*4882a593Smuzhiyun | ------------------ = .80000000 00000001 (rounded) | 175*4882a593Smuzhiyun | .ffffffff ffffffff | 176*4882a593Smuzhiyun | | 177*4882a593Smuzhiyun +---------------------------------------------------------------------------*/ 178*4882a593Smuzhiyun 179*4882a593Smuzhiyun 180*4882a593SmuzhiyunL_Full_Division: 181*4882a593Smuzhiyun /* Save extended dividend in local register */ 182*4882a593Smuzhiyun movl SIGL(%esi),%eax 183*4882a593Smuzhiyun movl %eax,FPU_accum_2 184*4882a593Smuzhiyun movl SIGH(%esi),%eax 185*4882a593Smuzhiyun movl %eax,FPU_accum_3 186*4882a593Smuzhiyun xorl %eax,%eax 187*4882a593Smuzhiyun movl %eax,FPU_accum_1 /* zero the extension */ 188*4882a593Smuzhiyun movl %eax,FPU_accum_0 /* zero the extension */ 189*4882a593Smuzhiyun 190*4882a593Smuzhiyun movl SIGL(%esi),%eax /* Get the current num */ 191*4882a593Smuzhiyun movl SIGH(%esi),%edx 192*4882a593Smuzhiyun 193*4882a593Smuzhiyun/*----------------------------------------------------------------------*/ 194*4882a593Smuzhiyun/* Initialization done. 195*4882a593Smuzhiyun Do the first 32 bits. */ 196*4882a593Smuzhiyun 197*4882a593Smuzhiyun movb $0,FPU_ovfl_flag 198*4882a593Smuzhiyun cmpl SIGH(%ebx),%edx /* Test for imminent overflow */ 199*4882a593Smuzhiyun jb LLess_than_1 200*4882a593Smuzhiyun ja LGreater_than_1 201*4882a593Smuzhiyun 202*4882a593Smuzhiyun cmpl SIGL(%ebx),%eax 203*4882a593Smuzhiyun jb LLess_than_1 204*4882a593Smuzhiyun 205*4882a593SmuzhiyunLGreater_than_1: 206*4882a593Smuzhiyun/* The dividend is greater or equal, would cause overflow */ 207*4882a593Smuzhiyun setaeb FPU_ovfl_flag /* Keep a record */ 208*4882a593Smuzhiyun 209*4882a593Smuzhiyun subl SIGL(%ebx),%eax 210*4882a593Smuzhiyun sbbl SIGH(%ebx),%edx /* Prevent the overflow */ 211*4882a593Smuzhiyun movl %eax,FPU_accum_2 212*4882a593Smuzhiyun movl %edx,FPU_accum_3 213*4882a593Smuzhiyun 214*4882a593SmuzhiyunLLess_than_1: 215*4882a593Smuzhiyun/* At this point, we have a dividend < divisor, with a record of 216*4882a593Smuzhiyun adjustment in FPU_ovfl_flag */ 217*4882a593Smuzhiyun 218*4882a593Smuzhiyun /* We will divide by a number which is too large */ 219*4882a593Smuzhiyun movl SIGH(%ebx),%ecx 220*4882a593Smuzhiyun addl $1,%ecx 221*4882a593Smuzhiyun jnc LFirst_div_not_1 222*4882a593Smuzhiyun 223*4882a593Smuzhiyun /* here we need to divide by 100000000h, 224*4882a593Smuzhiyun i.e., no division at all.. */ 225*4882a593Smuzhiyun mov %edx,%eax 226*4882a593Smuzhiyun jmp LFirst_div_done 227*4882a593Smuzhiyun 228*4882a593SmuzhiyunLFirst_div_not_1: 229*4882a593Smuzhiyun divl %ecx /* Divide the numerator by the augmented 230*4882a593Smuzhiyun denom ms dw */ 231*4882a593Smuzhiyun 232*4882a593SmuzhiyunLFirst_div_done: 233*4882a593Smuzhiyun movl %eax,FPU_result_2 /* Put the result in the answer */ 234*4882a593Smuzhiyun 235*4882a593Smuzhiyun mull SIGH(%ebx) /* mul by the ms dw of the denom */ 236*4882a593Smuzhiyun 237*4882a593Smuzhiyun subl %eax,FPU_accum_2 /* Subtract from the num local reg */ 238*4882a593Smuzhiyun sbbl %edx,FPU_accum_3 239*4882a593Smuzhiyun 240*4882a593Smuzhiyun movl FPU_result_2,%eax /* Get the result back */ 241*4882a593Smuzhiyun mull SIGL(%ebx) /* now mul the ls dw of the denom */ 242*4882a593Smuzhiyun 243*4882a593Smuzhiyun subl %eax,FPU_accum_1 /* Subtract from the num local reg */ 244*4882a593Smuzhiyun sbbl %edx,FPU_accum_2 245*4882a593Smuzhiyun sbbl $0,FPU_accum_3 246*4882a593Smuzhiyun je LDo_2nd_32_bits /* Must check for non-zero result here */ 247*4882a593Smuzhiyun 248*4882a593Smuzhiyun#ifdef PARANOID 249*4882a593Smuzhiyun jb L_bugged_1 250*4882a593Smuzhiyun#endif /* PARANOID */ 251*4882a593Smuzhiyun 252*4882a593Smuzhiyun /* need to subtract another once of the denom */ 253*4882a593Smuzhiyun incl FPU_result_2 /* Correct the answer */ 254*4882a593Smuzhiyun 255*4882a593Smuzhiyun movl SIGL(%ebx),%eax 256*4882a593Smuzhiyun movl SIGH(%ebx),%edx 257*4882a593Smuzhiyun subl %eax,FPU_accum_1 /* Subtract from the num local reg */ 258*4882a593Smuzhiyun sbbl %edx,FPU_accum_2 259*4882a593Smuzhiyun 260*4882a593Smuzhiyun#ifdef PARANOID 261*4882a593Smuzhiyun sbbl $0,FPU_accum_3 262*4882a593Smuzhiyun jne L_bugged_1 /* Must check for non-zero result here */ 263*4882a593Smuzhiyun#endif /* PARANOID */ 264*4882a593Smuzhiyun 265*4882a593Smuzhiyun/*----------------------------------------------------------------------*/ 266*4882a593Smuzhiyun/* Half of the main problem is done, there is just a reduced numerator 267*4882a593Smuzhiyun to handle now. 268*4882a593Smuzhiyun Work with the second 32 bits, FPU_accum_0 not used from now on */ 269*4882a593SmuzhiyunLDo_2nd_32_bits: 270*4882a593Smuzhiyun movl FPU_accum_2,%edx /* get the reduced num */ 271*4882a593Smuzhiyun movl FPU_accum_1,%eax 272*4882a593Smuzhiyun 273*4882a593Smuzhiyun /* need to check for possible subsequent overflow */ 274*4882a593Smuzhiyun cmpl SIGH(%ebx),%edx 275*4882a593Smuzhiyun jb LDo_2nd_div 276*4882a593Smuzhiyun ja LPrevent_2nd_overflow 277*4882a593Smuzhiyun 278*4882a593Smuzhiyun cmpl SIGL(%ebx),%eax 279*4882a593Smuzhiyun jb LDo_2nd_div 280*4882a593Smuzhiyun 281*4882a593SmuzhiyunLPrevent_2nd_overflow: 282*4882a593Smuzhiyun/* The numerator is greater or equal, would cause overflow */ 283*4882a593Smuzhiyun /* prevent overflow */ 284*4882a593Smuzhiyun subl SIGL(%ebx),%eax 285*4882a593Smuzhiyun sbbl SIGH(%ebx),%edx 286*4882a593Smuzhiyun movl %edx,FPU_accum_2 287*4882a593Smuzhiyun movl %eax,FPU_accum_1 288*4882a593Smuzhiyun 289*4882a593Smuzhiyun incl FPU_result_2 /* Reflect the subtraction in the answer */ 290*4882a593Smuzhiyun 291*4882a593Smuzhiyun#ifdef PARANOID 292*4882a593Smuzhiyun je L_bugged_2 /* Can't bump the result to 1.0 */ 293*4882a593Smuzhiyun#endif /* PARANOID */ 294*4882a593Smuzhiyun 295*4882a593SmuzhiyunLDo_2nd_div: 296*4882a593Smuzhiyun cmpl $0,%ecx /* augmented denom msw */ 297*4882a593Smuzhiyun jnz LSecond_div_not_1 298*4882a593Smuzhiyun 299*4882a593Smuzhiyun /* %ecx == 0, we are dividing by 1.0 */ 300*4882a593Smuzhiyun mov %edx,%eax 301*4882a593Smuzhiyun jmp LSecond_div_done 302*4882a593Smuzhiyun 303*4882a593SmuzhiyunLSecond_div_not_1: 304*4882a593Smuzhiyun divl %ecx /* Divide the numerator by the denom ms dw */ 305*4882a593Smuzhiyun 306*4882a593SmuzhiyunLSecond_div_done: 307*4882a593Smuzhiyun movl %eax,FPU_result_1 /* Put the result in the answer */ 308*4882a593Smuzhiyun 309*4882a593Smuzhiyun mull SIGH(%ebx) /* mul by the ms dw of the denom */ 310*4882a593Smuzhiyun 311*4882a593Smuzhiyun subl %eax,FPU_accum_1 /* Subtract from the num local reg */ 312*4882a593Smuzhiyun sbbl %edx,FPU_accum_2 313*4882a593Smuzhiyun 314*4882a593Smuzhiyun#ifdef PARANOID 315*4882a593Smuzhiyun jc L_bugged_2 316*4882a593Smuzhiyun#endif /* PARANOID */ 317*4882a593Smuzhiyun 318*4882a593Smuzhiyun movl FPU_result_1,%eax /* Get the result back */ 319*4882a593Smuzhiyun mull SIGL(%ebx) /* now mul the ls dw of the denom */ 320*4882a593Smuzhiyun 321*4882a593Smuzhiyun subl %eax,FPU_accum_0 /* Subtract from the num local reg */ 322*4882a593Smuzhiyun sbbl %edx,FPU_accum_1 /* Subtract from the num local reg */ 323*4882a593Smuzhiyun sbbl $0,FPU_accum_2 324*4882a593Smuzhiyun 325*4882a593Smuzhiyun#ifdef PARANOID 326*4882a593Smuzhiyun jc L_bugged_2 327*4882a593Smuzhiyun#endif /* PARANOID */ 328*4882a593Smuzhiyun 329*4882a593Smuzhiyun jz LDo_3rd_32_bits 330*4882a593Smuzhiyun 331*4882a593Smuzhiyun#ifdef PARANOID 332*4882a593Smuzhiyun cmpl $1,FPU_accum_2 333*4882a593Smuzhiyun jne L_bugged_2 334*4882a593Smuzhiyun#endif /* PARANOID */ 335*4882a593Smuzhiyun 336*4882a593Smuzhiyun /* need to subtract another once of the denom */ 337*4882a593Smuzhiyun movl SIGL(%ebx),%eax 338*4882a593Smuzhiyun movl SIGH(%ebx),%edx 339*4882a593Smuzhiyun subl %eax,FPU_accum_0 /* Subtract from the num local reg */ 340*4882a593Smuzhiyun sbbl %edx,FPU_accum_1 341*4882a593Smuzhiyun sbbl $0,FPU_accum_2 342*4882a593Smuzhiyun 343*4882a593Smuzhiyun#ifdef PARANOID 344*4882a593Smuzhiyun jc L_bugged_2 345*4882a593Smuzhiyun jne L_bugged_2 346*4882a593Smuzhiyun#endif /* PARANOID */ 347*4882a593Smuzhiyun 348*4882a593Smuzhiyun addl $1,FPU_result_1 /* Correct the answer */ 349*4882a593Smuzhiyun adcl $0,FPU_result_2 350*4882a593Smuzhiyun 351*4882a593Smuzhiyun#ifdef PARANOID 352*4882a593Smuzhiyun jc L_bugged_2 /* Must check for non-zero result here */ 353*4882a593Smuzhiyun#endif /* PARANOID */ 354*4882a593Smuzhiyun 355*4882a593Smuzhiyun/*----------------------------------------------------------------------*/ 356*4882a593Smuzhiyun/* The division is essentially finished here, we just need to perform 357*4882a593Smuzhiyun tidying operations. 358*4882a593Smuzhiyun Deal with the 3rd 32 bits */ 359*4882a593SmuzhiyunLDo_3rd_32_bits: 360*4882a593Smuzhiyun movl FPU_accum_1,%edx /* get the reduced num */ 361*4882a593Smuzhiyun movl FPU_accum_0,%eax 362*4882a593Smuzhiyun 363*4882a593Smuzhiyun /* need to check for possible subsequent overflow */ 364*4882a593Smuzhiyun cmpl SIGH(%ebx),%edx /* denom */ 365*4882a593Smuzhiyun jb LRound_prep 366*4882a593Smuzhiyun ja LPrevent_3rd_overflow 367*4882a593Smuzhiyun 368*4882a593Smuzhiyun cmpl SIGL(%ebx),%eax /* denom */ 369*4882a593Smuzhiyun jb LRound_prep 370*4882a593Smuzhiyun 371*4882a593SmuzhiyunLPrevent_3rd_overflow: 372*4882a593Smuzhiyun /* prevent overflow */ 373*4882a593Smuzhiyun subl SIGL(%ebx),%eax 374*4882a593Smuzhiyun sbbl SIGH(%ebx),%edx 375*4882a593Smuzhiyun movl %edx,FPU_accum_1 376*4882a593Smuzhiyun movl %eax,FPU_accum_0 377*4882a593Smuzhiyun 378*4882a593Smuzhiyun addl $1,FPU_result_1 /* Reflect the subtraction in the answer */ 379*4882a593Smuzhiyun adcl $0,FPU_result_2 380*4882a593Smuzhiyun jne LRound_prep 381*4882a593Smuzhiyun jnc LRound_prep 382*4882a593Smuzhiyun 383*4882a593Smuzhiyun /* This is a tricky spot, there is an overflow of the answer */ 384*4882a593Smuzhiyun movb $255,FPU_ovfl_flag /* Overflow -> 1.000 */ 385*4882a593Smuzhiyun 386*4882a593SmuzhiyunLRound_prep: 387*4882a593Smuzhiyun/* 388*4882a593Smuzhiyun * Prepare for rounding. 389*4882a593Smuzhiyun * To test for rounding, we just need to compare 2*accum with the 390*4882a593Smuzhiyun * denom. 391*4882a593Smuzhiyun */ 392*4882a593Smuzhiyun movl FPU_accum_0,%ecx 393*4882a593Smuzhiyun movl FPU_accum_1,%edx 394*4882a593Smuzhiyun movl %ecx,%eax 395*4882a593Smuzhiyun orl %edx,%eax 396*4882a593Smuzhiyun jz LRound_ovfl /* The accumulator contains zero. */ 397*4882a593Smuzhiyun 398*4882a593Smuzhiyun /* Multiply by 2 */ 399*4882a593Smuzhiyun clc 400*4882a593Smuzhiyun rcll $1,%ecx 401*4882a593Smuzhiyun rcll $1,%edx 402*4882a593Smuzhiyun jc LRound_large /* No need to compare, denom smaller */ 403*4882a593Smuzhiyun 404*4882a593Smuzhiyun subl SIGL(%ebx),%ecx 405*4882a593Smuzhiyun sbbl SIGH(%ebx),%edx 406*4882a593Smuzhiyun jnc LRound_not_small 407*4882a593Smuzhiyun 408*4882a593Smuzhiyun movl $0x70000000,%eax /* Denom was larger */ 409*4882a593Smuzhiyun jmp LRound_ovfl 410*4882a593Smuzhiyun 411*4882a593SmuzhiyunLRound_not_small: 412*4882a593Smuzhiyun jnz LRound_large 413*4882a593Smuzhiyun 414*4882a593Smuzhiyun movl $0x80000000,%eax /* Remainder was exactly 1/2 denom */ 415*4882a593Smuzhiyun jmp LRound_ovfl 416*4882a593Smuzhiyun 417*4882a593SmuzhiyunLRound_large: 418*4882a593Smuzhiyun movl $0xff000000,%eax /* Denom was smaller */ 419*4882a593Smuzhiyun 420*4882a593SmuzhiyunLRound_ovfl: 421*4882a593Smuzhiyun/* We are now ready to deal with rounding, but first we must get 422*4882a593Smuzhiyun the bits properly aligned */ 423*4882a593Smuzhiyun testb $255,FPU_ovfl_flag /* was the num > denom ? */ 424*4882a593Smuzhiyun je LRound_precision 425*4882a593Smuzhiyun 426*4882a593Smuzhiyun incw EXP(%edi) 427*4882a593Smuzhiyun 428*4882a593Smuzhiyun /* shift the mantissa right one bit */ 429*4882a593Smuzhiyun stc /* Will set the ms bit */ 430*4882a593Smuzhiyun rcrl FPU_result_2 431*4882a593Smuzhiyun rcrl FPU_result_1 432*4882a593Smuzhiyun rcrl %eax 433*4882a593Smuzhiyun 434*4882a593Smuzhiyun/* Round the result as required */ 435*4882a593SmuzhiyunLRound_precision: 436*4882a593Smuzhiyun decw EXP(%edi) /* binary point between 1st & 2nd bits */ 437*4882a593Smuzhiyun 438*4882a593Smuzhiyun movl %eax,%edx 439*4882a593Smuzhiyun movl FPU_result_1,%ebx 440*4882a593Smuzhiyun movl FPU_result_2,%eax 441*4882a593Smuzhiyun jmp fpu_reg_round 442*4882a593Smuzhiyun 443*4882a593Smuzhiyun 444*4882a593Smuzhiyun#ifdef PARANOID 445*4882a593Smuzhiyun/* The logic is wrong if we got here */ 446*4882a593SmuzhiyunL_bugged: 447*4882a593Smuzhiyun pushl EX_INTERNAL|0x202 448*4882a593Smuzhiyun call EXCEPTION 449*4882a593Smuzhiyun pop %ebx 450*4882a593Smuzhiyun jmp L_exit 451*4882a593Smuzhiyun 452*4882a593SmuzhiyunL_bugged_1: 453*4882a593Smuzhiyun pushl EX_INTERNAL|0x203 454*4882a593Smuzhiyun call EXCEPTION 455*4882a593Smuzhiyun pop %ebx 456*4882a593Smuzhiyun jmp L_exit 457*4882a593Smuzhiyun 458*4882a593SmuzhiyunL_bugged_2: 459*4882a593Smuzhiyun pushl EX_INTERNAL|0x204 460*4882a593Smuzhiyun call EXCEPTION 461*4882a593Smuzhiyun pop %ebx 462*4882a593Smuzhiyun jmp L_exit 463*4882a593Smuzhiyun 464*4882a593SmuzhiyunL_exit: 465*4882a593Smuzhiyun movl $-1,%eax 466*4882a593Smuzhiyun popl %ebx 467*4882a593Smuzhiyun popl %edi 468*4882a593Smuzhiyun popl %esi 469*4882a593Smuzhiyun 470*4882a593Smuzhiyun leave 471*4882a593Smuzhiyun RET 472*4882a593Smuzhiyun#endif /* PARANOID */ 473*4882a593Smuzhiyun 474*4882a593SmuzhiyunSYM_FUNC_END(FPU_u_div) 475