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