1da957e11SThomas Gleixner .file "reg_round.S" 2da957e11SThomas Gleixner/*---------------------------------------------------------------------------+ 3da957e11SThomas Gleixner | reg_round.S | 4da957e11SThomas Gleixner | | 5da957e11SThomas Gleixner | Rounding/truncation/etc for FPU basic arithmetic functions. | 6da957e11SThomas Gleixner | | 7da957e11SThomas Gleixner | Copyright (C) 1993,1995,1997 | 8da957e11SThomas Gleixner | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | 9da957e11SThomas Gleixner | Australia. E-mail billm@suburbia.net | 10da957e11SThomas Gleixner | | 11da957e11SThomas Gleixner | This code has four possible entry points. | 12da957e11SThomas Gleixner | The following must be entered by a jmp instruction: | 13da957e11SThomas Gleixner | fpu_reg_round, fpu_reg_round_sqrt, and fpu_Arith_exit. | 14da957e11SThomas Gleixner | | 15da957e11SThomas Gleixner | The FPU_round entry point is intended to be used by C code. | 16da957e11SThomas Gleixner | From C, call as: | 17da957e11SThomas Gleixner | int FPU_round(FPU_REG *arg, unsigned int extent, unsigned int control_w) | 18da957e11SThomas Gleixner | | 19da957e11SThomas Gleixner | Return value is the tag of the answer, or-ed with FPU_Exception if | 20da957e11SThomas Gleixner | one was raised, or -1 on internal error. | 21da957e11SThomas Gleixner | | 22da957e11SThomas Gleixner | For correct "up" and "down" rounding, the argument must have the correct | 23da957e11SThomas Gleixner | sign. | 24da957e11SThomas Gleixner | | 25da957e11SThomas Gleixner +---------------------------------------------------------------------------*/ 26da957e11SThomas Gleixner 27da957e11SThomas Gleixner/*---------------------------------------------------------------------------+ 28da957e11SThomas Gleixner | Four entry points. | 29da957e11SThomas Gleixner | | 30da957e11SThomas Gleixner | Needed by both the fpu_reg_round and fpu_reg_round_sqrt entry points: | 31da957e11SThomas Gleixner | %eax:%ebx 64 bit significand | 32da957e11SThomas Gleixner | %edx 32 bit extension of the significand | 33da957e11SThomas Gleixner | %edi pointer to an FPU_REG for the result to be stored | 34da957e11SThomas Gleixner | stack calling function must have set up a C stack frame and | 35da957e11SThomas Gleixner | pushed %esi, %edi, and %ebx | 36da957e11SThomas Gleixner | | 37da957e11SThomas Gleixner | Needed just for the fpu_reg_round_sqrt entry point: | 38da957e11SThomas Gleixner | %cx A control word in the same format as the FPU control word. | 39da957e11SThomas Gleixner | Otherwise, PARAM4 must give such a value. | 40da957e11SThomas Gleixner | | 41da957e11SThomas Gleixner | | 42da957e11SThomas Gleixner | The significand and its extension are assumed to be exact in the | 43da957e11SThomas Gleixner | following sense: | 44da957e11SThomas Gleixner | If the significand by itself is the exact result then the significand | 45da957e11SThomas Gleixner | extension (%edx) must contain 0, otherwise the significand extension | 46da957e11SThomas Gleixner | must be non-zero. | 47da957e11SThomas Gleixner | If the significand extension is non-zero then the significand is | 48da957e11SThomas Gleixner | smaller than the magnitude of the correct exact result by an amount | 49da957e11SThomas Gleixner | greater than zero and less than one ls bit of the significand. | 50da957e11SThomas Gleixner | The significand extension is only required to have three possible | 51da957e11SThomas Gleixner | non-zero values: | 52da957e11SThomas Gleixner | less than 0x80000000 <=> the significand is less than 1/2 an ls | 53da957e11SThomas Gleixner | bit smaller than the magnitude of the | 54da957e11SThomas Gleixner | true exact result. | 55da957e11SThomas Gleixner | exactly 0x80000000 <=> the significand is exactly 1/2 an ls bit | 56da957e11SThomas Gleixner | smaller than the magnitude of the true | 57da957e11SThomas Gleixner | exact result. | 58da957e11SThomas Gleixner | greater than 0x80000000 <=> the significand is more than 1/2 an ls | 59da957e11SThomas Gleixner | bit smaller than the magnitude of the | 60da957e11SThomas Gleixner | true exact result. | 61da957e11SThomas Gleixner | | 62da957e11SThomas Gleixner +---------------------------------------------------------------------------*/ 63da957e11SThomas Gleixner 64da957e11SThomas Gleixner/*---------------------------------------------------------------------------+ 65da957e11SThomas Gleixner | The code in this module has become quite complex, but it should handle | 66da957e11SThomas Gleixner | all of the FPU flags which are set at this stage of the basic arithmetic | 67da957e11SThomas Gleixner | computations. | 68da957e11SThomas Gleixner | There are a few rare cases where the results are not set identically to | 69da957e11SThomas Gleixner | a real FPU. These require a bit more thought because at this stage the | 70da957e11SThomas Gleixner | results of the code here appear to be more consistent... | 71da957e11SThomas Gleixner | This may be changed in a future version. | 72da957e11SThomas Gleixner +---------------------------------------------------------------------------*/ 73da957e11SThomas Gleixner 74da957e11SThomas Gleixner 75da957e11SThomas Gleixner#include "fpu_emu.h" 76da957e11SThomas Gleixner#include "exception.h" 77da957e11SThomas Gleixner#include "control_w.h" 78da957e11SThomas Gleixner 79da957e11SThomas Gleixner/* Flags for FPU_bits_lost */ 80da957e11SThomas Gleixner#define LOST_DOWN $1 81da957e11SThomas Gleixner#define LOST_UP $2 82da957e11SThomas Gleixner 83da957e11SThomas Gleixner/* Flags for FPU_denormal */ 84da957e11SThomas Gleixner#define DENORMAL $1 85da957e11SThomas Gleixner#define UNMASKED_UNDERFLOW $2 86da957e11SThomas Gleixner 87da957e11SThomas Gleixner 88da957e11SThomas Gleixner#ifndef NON_REENTRANT_FPU 89da957e11SThomas Gleixner/* Make the code re-entrant by putting 90da957e11SThomas Gleixner local storage on the stack: */ 91da957e11SThomas Gleixner#define FPU_bits_lost (%esp) 92da957e11SThomas Gleixner#define FPU_denormal 1(%esp) 93da957e11SThomas Gleixner 94da957e11SThomas Gleixner#else 95da957e11SThomas Gleixner/* Not re-entrant, so we can gain speed by putting 96da957e11SThomas Gleixner local storage in a static area: */ 97da957e11SThomas Gleixner.data 98da957e11SThomas Gleixner .align 4,0 99da957e11SThomas GleixnerFPU_bits_lost: 100da957e11SThomas Gleixner .byte 0 101da957e11SThomas GleixnerFPU_denormal: 102da957e11SThomas Gleixner .byte 0 103da957e11SThomas Gleixner#endif /* NON_REENTRANT_FPU */ 104da957e11SThomas Gleixner 105da957e11SThomas Gleixner 106da957e11SThomas Gleixner.text 107da957e11SThomas Gleixner.globl fpu_reg_round 108da957e11SThomas Gleixner.globl fpu_Arith_exit 109da957e11SThomas Gleixner 110da957e11SThomas Gleixner/* Entry point when called from C */ 111da957e11SThomas GleixnerENTRY(FPU_round) 112da957e11SThomas Gleixner pushl %ebp 113da957e11SThomas Gleixner movl %esp,%ebp 114da957e11SThomas Gleixner pushl %esi 115da957e11SThomas Gleixner pushl %edi 116da957e11SThomas Gleixner pushl %ebx 117da957e11SThomas Gleixner 118da957e11SThomas Gleixner movl PARAM1,%edi 119da957e11SThomas Gleixner movl SIGH(%edi),%eax 120da957e11SThomas Gleixner movl SIGL(%edi),%ebx 121da957e11SThomas Gleixner movl PARAM2,%edx 122da957e11SThomas Gleixner 123da957e11SThomas Gleixnerfpu_reg_round: /* Normal entry point */ 124da957e11SThomas Gleixner movl PARAM4,%ecx 125da957e11SThomas Gleixner 126da957e11SThomas Gleixner#ifndef NON_REENTRANT_FPU 127da957e11SThomas Gleixner pushl %ebx /* adjust the stack pointer */ 128da957e11SThomas Gleixner#endif /* NON_REENTRANT_FPU */ 129da957e11SThomas Gleixner 130da957e11SThomas Gleixner#ifdef PARANOID 131da957e11SThomas Gleixner/* Cannot use this here yet */ 132da957e11SThomas Gleixner/* orl %eax,%eax */ 133da957e11SThomas Gleixner/* jns L_entry_bugged */ 134da957e11SThomas Gleixner#endif /* PARANOID */ 135da957e11SThomas Gleixner 136da957e11SThomas Gleixner cmpw EXP_UNDER,EXP(%edi) 137da957e11SThomas Gleixner jle L_Make_denorm /* The number is a de-normal */ 138da957e11SThomas Gleixner 139da957e11SThomas Gleixner movb $0,FPU_denormal /* 0 -> not a de-normal */ 140da957e11SThomas Gleixner 141da957e11SThomas GleixnerDenorm_done: 142da957e11SThomas Gleixner movb $0,FPU_bits_lost /* No bits yet lost in rounding */ 143da957e11SThomas Gleixner 144da957e11SThomas Gleixner movl %ecx,%esi 145da957e11SThomas Gleixner andl CW_PC,%ecx 146da957e11SThomas Gleixner cmpl PR_64_BITS,%ecx 147da957e11SThomas Gleixner je LRound_To_64 148da957e11SThomas Gleixner 149da957e11SThomas Gleixner cmpl PR_53_BITS,%ecx 150da957e11SThomas Gleixner je LRound_To_53 151da957e11SThomas Gleixner 152da957e11SThomas Gleixner cmpl PR_24_BITS,%ecx 153da957e11SThomas Gleixner je LRound_To_24 154da957e11SThomas Gleixner 155da957e11SThomas Gleixner#ifdef PECULIAR_486 156da957e11SThomas Gleixner/* With the precision control bits set to 01 "(reserved)", a real 80486 157da957e11SThomas Gleixner behaves as if the precision control bits were set to 11 "64 bits" */ 158da957e11SThomas Gleixner cmpl PR_RESERVED_BITS,%ecx 159da957e11SThomas Gleixner je LRound_To_64 160da957e11SThomas Gleixner#ifdef PARANOID 161da957e11SThomas Gleixner jmp L_bugged_denorm_486 162da957e11SThomas Gleixner#endif /* PARANOID */ 163da957e11SThomas Gleixner#else 164da957e11SThomas Gleixner#ifdef PARANOID 165da957e11SThomas Gleixner jmp L_bugged_denorm /* There is no bug, just a bad control word */ 166da957e11SThomas Gleixner#endif /* PARANOID */ 167da957e11SThomas Gleixner#endif /* PECULIAR_486 */ 168da957e11SThomas Gleixner 169da957e11SThomas Gleixner 170da957e11SThomas Gleixner/* Round etc to 24 bit precision */ 171da957e11SThomas GleixnerLRound_To_24: 172da957e11SThomas Gleixner movl %esi,%ecx 173da957e11SThomas Gleixner andl CW_RC,%ecx 174da957e11SThomas Gleixner cmpl RC_RND,%ecx 175da957e11SThomas Gleixner je LRound_nearest_24 176da957e11SThomas Gleixner 177da957e11SThomas Gleixner cmpl RC_CHOP,%ecx 178da957e11SThomas Gleixner je LCheck_truncate_24 179da957e11SThomas Gleixner 180da957e11SThomas Gleixner cmpl RC_UP,%ecx /* Towards +infinity */ 181da957e11SThomas Gleixner je LUp_24 182da957e11SThomas Gleixner 183da957e11SThomas Gleixner cmpl RC_DOWN,%ecx /* Towards -infinity */ 184da957e11SThomas Gleixner je LDown_24 185da957e11SThomas Gleixner 186da957e11SThomas Gleixner#ifdef PARANOID 187da957e11SThomas Gleixner jmp L_bugged_round24 188da957e11SThomas Gleixner#endif /* PARANOID */ 189da957e11SThomas Gleixner 190da957e11SThomas GleixnerLUp_24: 191da957e11SThomas Gleixner cmpb SIGN_POS,PARAM5 192da957e11SThomas Gleixner jne LCheck_truncate_24 /* If negative then up==truncate */ 193da957e11SThomas Gleixner 194da957e11SThomas Gleixner jmp LCheck_24_round_up 195da957e11SThomas Gleixner 196da957e11SThomas GleixnerLDown_24: 197da957e11SThomas Gleixner cmpb SIGN_POS,PARAM5 198da957e11SThomas Gleixner je LCheck_truncate_24 /* If positive then down==truncate */ 199da957e11SThomas Gleixner 200da957e11SThomas GleixnerLCheck_24_round_up: 201da957e11SThomas Gleixner movl %eax,%ecx 202da957e11SThomas Gleixner andl $0x000000ff,%ecx 203da957e11SThomas Gleixner orl %ebx,%ecx 204da957e11SThomas Gleixner orl %edx,%ecx 205da957e11SThomas Gleixner jnz LDo_24_round_up 206da957e11SThomas Gleixner jmp L_Re_normalise 207da957e11SThomas Gleixner 208da957e11SThomas GleixnerLRound_nearest_24: 209da957e11SThomas Gleixner /* Do rounding of the 24th bit if needed (nearest or even) */ 210da957e11SThomas Gleixner movl %eax,%ecx 211da957e11SThomas Gleixner andl $0x000000ff,%ecx 212da957e11SThomas Gleixner cmpl $0x00000080,%ecx 213da957e11SThomas Gleixner jc LCheck_truncate_24 /* less than half, no increment needed */ 214da957e11SThomas Gleixner 215da957e11SThomas Gleixner jne LGreater_Half_24 /* greater than half, increment needed */ 216da957e11SThomas Gleixner 217da957e11SThomas Gleixner /* Possibly half, we need to check the ls bits */ 218da957e11SThomas Gleixner orl %ebx,%ebx 219da957e11SThomas Gleixner jnz LGreater_Half_24 /* greater than half, increment needed */ 220da957e11SThomas Gleixner 221da957e11SThomas Gleixner orl %edx,%edx 222da957e11SThomas Gleixner jnz LGreater_Half_24 /* greater than half, increment needed */ 223da957e11SThomas Gleixner 224da957e11SThomas Gleixner /* Exactly half, increment only if 24th bit is 1 (round to even) */ 225da957e11SThomas Gleixner testl $0x00000100,%eax 226da957e11SThomas Gleixner jz LDo_truncate_24 227da957e11SThomas Gleixner 228da957e11SThomas GleixnerLGreater_Half_24: /* Rounding: increment at the 24th bit */ 229da957e11SThomas GleixnerLDo_24_round_up: 230da957e11SThomas Gleixner andl $0xffffff00,%eax /* Truncate to 24 bits */ 231da957e11SThomas Gleixner xorl %ebx,%ebx 232da957e11SThomas Gleixner movb LOST_UP,FPU_bits_lost 233da957e11SThomas Gleixner addl $0x00000100,%eax 234da957e11SThomas Gleixner jmp LCheck_Round_Overflow 235da957e11SThomas Gleixner 236da957e11SThomas GleixnerLCheck_truncate_24: 237da957e11SThomas Gleixner movl %eax,%ecx 238da957e11SThomas Gleixner andl $0x000000ff,%ecx 239da957e11SThomas Gleixner orl %ebx,%ecx 240da957e11SThomas Gleixner orl %edx,%ecx 241da957e11SThomas Gleixner jz L_Re_normalise /* No truncation needed */ 242da957e11SThomas Gleixner 243da957e11SThomas GleixnerLDo_truncate_24: 244da957e11SThomas Gleixner andl $0xffffff00,%eax /* Truncate to 24 bits */ 245da957e11SThomas Gleixner xorl %ebx,%ebx 246da957e11SThomas Gleixner movb LOST_DOWN,FPU_bits_lost 247da957e11SThomas Gleixner jmp L_Re_normalise 248da957e11SThomas Gleixner 249da957e11SThomas Gleixner 250da957e11SThomas Gleixner/* Round etc to 53 bit precision */ 251da957e11SThomas GleixnerLRound_To_53: 252da957e11SThomas Gleixner movl %esi,%ecx 253da957e11SThomas Gleixner andl CW_RC,%ecx 254da957e11SThomas Gleixner cmpl RC_RND,%ecx 255da957e11SThomas Gleixner je LRound_nearest_53 256da957e11SThomas Gleixner 257da957e11SThomas Gleixner cmpl RC_CHOP,%ecx 258da957e11SThomas Gleixner je LCheck_truncate_53 259da957e11SThomas Gleixner 260da957e11SThomas Gleixner cmpl RC_UP,%ecx /* Towards +infinity */ 261da957e11SThomas Gleixner je LUp_53 262da957e11SThomas Gleixner 263da957e11SThomas Gleixner cmpl RC_DOWN,%ecx /* Towards -infinity */ 264da957e11SThomas Gleixner je LDown_53 265da957e11SThomas Gleixner 266da957e11SThomas Gleixner#ifdef PARANOID 267da957e11SThomas Gleixner jmp L_bugged_round53 268da957e11SThomas Gleixner#endif /* PARANOID */ 269da957e11SThomas Gleixner 270da957e11SThomas GleixnerLUp_53: 271da957e11SThomas Gleixner cmpb SIGN_POS,PARAM5 272da957e11SThomas Gleixner jne LCheck_truncate_53 /* If negative then up==truncate */ 273da957e11SThomas Gleixner 274da957e11SThomas Gleixner jmp LCheck_53_round_up 275da957e11SThomas Gleixner 276da957e11SThomas GleixnerLDown_53: 277da957e11SThomas Gleixner cmpb SIGN_POS,PARAM5 278da957e11SThomas Gleixner je LCheck_truncate_53 /* If positive then down==truncate */ 279da957e11SThomas Gleixner 280da957e11SThomas GleixnerLCheck_53_round_up: 281da957e11SThomas Gleixner movl %ebx,%ecx 282da957e11SThomas Gleixner andl $0x000007ff,%ecx 283da957e11SThomas Gleixner orl %edx,%ecx 284da957e11SThomas Gleixner jnz LDo_53_round_up 285da957e11SThomas Gleixner jmp L_Re_normalise 286da957e11SThomas Gleixner 287da957e11SThomas GleixnerLRound_nearest_53: 288da957e11SThomas Gleixner /* Do rounding of the 53rd bit if needed (nearest or even) */ 289da957e11SThomas Gleixner movl %ebx,%ecx 290da957e11SThomas Gleixner andl $0x000007ff,%ecx 291da957e11SThomas Gleixner cmpl $0x00000400,%ecx 292da957e11SThomas Gleixner jc LCheck_truncate_53 /* less than half, no increment needed */ 293da957e11SThomas Gleixner 294da957e11SThomas Gleixner jnz LGreater_Half_53 /* greater than half, increment needed */ 295da957e11SThomas Gleixner 296da957e11SThomas Gleixner /* Possibly half, we need to check the ls bits */ 297da957e11SThomas Gleixner orl %edx,%edx 298da957e11SThomas Gleixner jnz LGreater_Half_53 /* greater than half, increment needed */ 299da957e11SThomas Gleixner 300da957e11SThomas Gleixner /* Exactly half, increment only if 53rd bit is 1 (round to even) */ 301da957e11SThomas Gleixner testl $0x00000800,%ebx 302da957e11SThomas Gleixner jz LTruncate_53 303da957e11SThomas Gleixner 304da957e11SThomas GleixnerLGreater_Half_53: /* Rounding: increment at the 53rd bit */ 305da957e11SThomas GleixnerLDo_53_round_up: 306da957e11SThomas Gleixner movb LOST_UP,FPU_bits_lost 307da957e11SThomas Gleixner andl $0xfffff800,%ebx /* Truncate to 53 bits */ 308da957e11SThomas Gleixner addl $0x00000800,%ebx 309da957e11SThomas Gleixner adcl $0,%eax 310da957e11SThomas Gleixner jmp LCheck_Round_Overflow 311da957e11SThomas Gleixner 312da957e11SThomas GleixnerLCheck_truncate_53: 313da957e11SThomas Gleixner movl %ebx,%ecx 314da957e11SThomas Gleixner andl $0x000007ff,%ecx 315da957e11SThomas Gleixner orl %edx,%ecx 316da957e11SThomas Gleixner jz L_Re_normalise 317da957e11SThomas Gleixner 318da957e11SThomas GleixnerLTruncate_53: 319da957e11SThomas Gleixner movb LOST_DOWN,FPU_bits_lost 320da957e11SThomas Gleixner andl $0xfffff800,%ebx /* Truncate to 53 bits */ 321da957e11SThomas Gleixner jmp L_Re_normalise 322da957e11SThomas Gleixner 323da957e11SThomas Gleixner 324da957e11SThomas Gleixner/* Round etc to 64 bit precision */ 325da957e11SThomas GleixnerLRound_To_64: 326da957e11SThomas Gleixner movl %esi,%ecx 327da957e11SThomas Gleixner andl CW_RC,%ecx 328da957e11SThomas Gleixner cmpl RC_RND,%ecx 329da957e11SThomas Gleixner je LRound_nearest_64 330da957e11SThomas Gleixner 331da957e11SThomas Gleixner cmpl RC_CHOP,%ecx 332da957e11SThomas Gleixner je LCheck_truncate_64 333da957e11SThomas Gleixner 334da957e11SThomas Gleixner cmpl RC_UP,%ecx /* Towards +infinity */ 335da957e11SThomas Gleixner je LUp_64 336da957e11SThomas Gleixner 337da957e11SThomas Gleixner cmpl RC_DOWN,%ecx /* Towards -infinity */ 338da957e11SThomas Gleixner je LDown_64 339da957e11SThomas Gleixner 340da957e11SThomas Gleixner#ifdef PARANOID 341da957e11SThomas Gleixner jmp L_bugged_round64 342da957e11SThomas Gleixner#endif /* PARANOID */ 343da957e11SThomas Gleixner 344da957e11SThomas GleixnerLUp_64: 345da957e11SThomas Gleixner cmpb SIGN_POS,PARAM5 346da957e11SThomas Gleixner jne LCheck_truncate_64 /* If negative then up==truncate */ 347da957e11SThomas Gleixner 348da957e11SThomas Gleixner orl %edx,%edx 349da957e11SThomas Gleixner jnz LDo_64_round_up 350da957e11SThomas Gleixner jmp L_Re_normalise 351da957e11SThomas Gleixner 352da957e11SThomas GleixnerLDown_64: 353da957e11SThomas Gleixner cmpb SIGN_POS,PARAM5 354da957e11SThomas Gleixner je LCheck_truncate_64 /* If positive then down==truncate */ 355da957e11SThomas Gleixner 356da957e11SThomas Gleixner orl %edx,%edx 357da957e11SThomas Gleixner jnz LDo_64_round_up 358da957e11SThomas Gleixner jmp L_Re_normalise 359da957e11SThomas Gleixner 360da957e11SThomas GleixnerLRound_nearest_64: 361da957e11SThomas Gleixner cmpl $0x80000000,%edx 362da957e11SThomas Gleixner jc LCheck_truncate_64 363da957e11SThomas Gleixner 364da957e11SThomas Gleixner jne LDo_64_round_up 365da957e11SThomas Gleixner 366da957e11SThomas Gleixner /* Now test for round-to-even */ 367da957e11SThomas Gleixner testb $1,%bl 368da957e11SThomas Gleixner jz LCheck_truncate_64 369da957e11SThomas Gleixner 370da957e11SThomas GleixnerLDo_64_round_up: 371da957e11SThomas Gleixner movb LOST_UP,FPU_bits_lost 372da957e11SThomas Gleixner addl $1,%ebx 373da957e11SThomas Gleixner adcl $0,%eax 374da957e11SThomas Gleixner 375da957e11SThomas GleixnerLCheck_Round_Overflow: 376da957e11SThomas Gleixner jnc L_Re_normalise 377da957e11SThomas Gleixner 378da957e11SThomas Gleixner /* Overflow, adjust the result (significand to 1.0) */ 379da957e11SThomas Gleixner rcrl $1,%eax 380da957e11SThomas Gleixner rcrl $1,%ebx 381da957e11SThomas Gleixner incw EXP(%edi) 382da957e11SThomas Gleixner jmp L_Re_normalise 383da957e11SThomas Gleixner 384da957e11SThomas GleixnerLCheck_truncate_64: 385da957e11SThomas Gleixner orl %edx,%edx 386da957e11SThomas Gleixner jz L_Re_normalise 387da957e11SThomas Gleixner 388da957e11SThomas GleixnerLTruncate_64: 389da957e11SThomas Gleixner movb LOST_DOWN,FPU_bits_lost 390da957e11SThomas Gleixner 391da957e11SThomas GleixnerL_Re_normalise: 392da957e11SThomas Gleixner testb $0xff,FPU_denormal 393da957e11SThomas Gleixner jnz Normalise_result 394da957e11SThomas Gleixner 395da957e11SThomas GleixnerL_Normalised: 396da957e11SThomas Gleixner movl TAG_Valid,%edx 397da957e11SThomas Gleixner 398da957e11SThomas GleixnerL_deNormalised: 399da957e11SThomas Gleixner cmpb LOST_UP,FPU_bits_lost 400da957e11SThomas Gleixner je L_precision_lost_up 401da957e11SThomas Gleixner 402da957e11SThomas Gleixner cmpb LOST_DOWN,FPU_bits_lost 403da957e11SThomas Gleixner je L_precision_lost_down 404da957e11SThomas Gleixner 405da957e11SThomas GleixnerL_no_precision_loss: 406da957e11SThomas Gleixner /* store the result */ 407da957e11SThomas Gleixner 408da957e11SThomas GleixnerL_Store_significand: 409da957e11SThomas Gleixner movl %eax,SIGH(%edi) 410da957e11SThomas Gleixner movl %ebx,SIGL(%edi) 411da957e11SThomas Gleixner 412da957e11SThomas Gleixner cmpw EXP_OVER,EXP(%edi) 413da957e11SThomas Gleixner jge L_overflow 414da957e11SThomas Gleixner 415da957e11SThomas Gleixner movl %edx,%eax 416da957e11SThomas Gleixner 417da957e11SThomas Gleixner /* Convert the exponent to 80x87 form. */ 418da957e11SThomas Gleixner addw EXTENDED_Ebias,EXP(%edi) 419da957e11SThomas Gleixner andw $0x7fff,EXP(%edi) 420da957e11SThomas Gleixner 421da957e11SThomas Gleixnerfpu_reg_round_signed_special_exit: 422da957e11SThomas Gleixner 423da957e11SThomas Gleixner cmpb SIGN_POS,PARAM5 424da957e11SThomas Gleixner je fpu_reg_round_special_exit 425da957e11SThomas Gleixner 426da957e11SThomas Gleixner orw $0x8000,EXP(%edi) /* Negative sign for the result. */ 427da957e11SThomas Gleixner 428da957e11SThomas Gleixnerfpu_reg_round_special_exit: 429da957e11SThomas Gleixner 430da957e11SThomas Gleixner#ifndef NON_REENTRANT_FPU 431da957e11SThomas Gleixner popl %ebx /* adjust the stack pointer */ 432da957e11SThomas Gleixner#endif /* NON_REENTRANT_FPU */ 433da957e11SThomas Gleixner 434da957e11SThomas Gleixnerfpu_Arith_exit: 435da957e11SThomas Gleixner popl %ebx 436da957e11SThomas Gleixner popl %edi 437da957e11SThomas Gleixner popl %esi 438da957e11SThomas Gleixner leave 439da957e11SThomas Gleixner ret 440da957e11SThomas Gleixner 441da957e11SThomas Gleixner 442da957e11SThomas Gleixner/* 443da957e11SThomas Gleixner * Set the FPU status flags to represent precision loss due to 444da957e11SThomas Gleixner * round-up. 445da957e11SThomas Gleixner */ 446da957e11SThomas GleixnerL_precision_lost_up: 447da957e11SThomas Gleixner push %edx 448da957e11SThomas Gleixner push %eax 449da957e11SThomas Gleixner call set_precision_flag_up 450da957e11SThomas Gleixner popl %eax 451da957e11SThomas Gleixner popl %edx 452da957e11SThomas Gleixner jmp L_no_precision_loss 453da957e11SThomas Gleixner 454da957e11SThomas Gleixner/* 455da957e11SThomas Gleixner * Set the FPU status flags to represent precision loss due to 456da957e11SThomas Gleixner * truncation. 457da957e11SThomas Gleixner */ 458da957e11SThomas GleixnerL_precision_lost_down: 459da957e11SThomas Gleixner push %edx 460da957e11SThomas Gleixner push %eax 461da957e11SThomas Gleixner call set_precision_flag_down 462da957e11SThomas Gleixner popl %eax 463da957e11SThomas Gleixner popl %edx 464da957e11SThomas Gleixner jmp L_no_precision_loss 465da957e11SThomas Gleixner 466da957e11SThomas Gleixner 467da957e11SThomas Gleixner/* 468da957e11SThomas Gleixner * The number is a denormal (which might get rounded up to a normal) 469da957e11SThomas Gleixner * Shift the number right the required number of bits, which will 470da957e11SThomas Gleixner * have to be undone later... 471da957e11SThomas Gleixner */ 472da957e11SThomas GleixnerL_Make_denorm: 473da957e11SThomas Gleixner /* The action to be taken depends upon whether the underflow 474da957e11SThomas Gleixner exception is masked */ 475da957e11SThomas Gleixner testb CW_Underflow,%cl /* Underflow mask. */ 476da957e11SThomas Gleixner jz Unmasked_underflow /* Do not make a denormal. */ 477da957e11SThomas Gleixner 478da957e11SThomas Gleixner movb DENORMAL,FPU_denormal 479da957e11SThomas Gleixner 480da957e11SThomas Gleixner pushl %ecx /* Save */ 481da957e11SThomas Gleixner movw EXP_UNDER+1,%cx 482da957e11SThomas Gleixner subw EXP(%edi),%cx 483da957e11SThomas Gleixner 484da957e11SThomas Gleixner cmpw $64,%cx /* shrd only works for 0..31 bits */ 485da957e11SThomas Gleixner jnc Denorm_shift_more_than_63 486da957e11SThomas Gleixner 487da957e11SThomas Gleixner cmpw $32,%cx /* shrd only works for 0..31 bits */ 488da957e11SThomas Gleixner jnc Denorm_shift_more_than_32 489da957e11SThomas Gleixner 490da957e11SThomas Gleixner/* 491da957e11SThomas Gleixner * We got here without jumps by assuming that the most common requirement 492da957e11SThomas Gleixner * is for a small de-normalising shift. 493da957e11SThomas Gleixner * Shift by [1..31] bits 494da957e11SThomas Gleixner */ 495da957e11SThomas Gleixner addw %cx,EXP(%edi) 496da957e11SThomas Gleixner orl %edx,%edx /* extension */ 497da957e11SThomas Gleixner setne %ch /* Save whether %edx is non-zero */ 498da957e11SThomas Gleixner xorl %edx,%edx 499da957e11SThomas Gleixner shrd %cl,%ebx,%edx 500da957e11SThomas Gleixner shrd %cl,%eax,%ebx 501da957e11SThomas Gleixner shr %cl,%eax 502da957e11SThomas Gleixner orb %ch,%dl 503da957e11SThomas Gleixner popl %ecx 504da957e11SThomas Gleixner jmp Denorm_done 505da957e11SThomas Gleixner 506da957e11SThomas Gleixner/* Shift by [32..63] bits */ 507da957e11SThomas GleixnerDenorm_shift_more_than_32: 508da957e11SThomas Gleixner addw %cx,EXP(%edi) 509da957e11SThomas Gleixner subb $32,%cl 510da957e11SThomas Gleixner orl %edx,%edx 511da957e11SThomas Gleixner setne %ch 512da957e11SThomas Gleixner orb %ch,%bl 513da957e11SThomas Gleixner xorl %edx,%edx 514da957e11SThomas Gleixner shrd %cl,%ebx,%edx 515da957e11SThomas Gleixner shrd %cl,%eax,%ebx 516da957e11SThomas Gleixner shr %cl,%eax 517da957e11SThomas Gleixner orl %edx,%edx /* test these 32 bits */ 518da957e11SThomas Gleixner setne %cl 519da957e11SThomas Gleixner orb %ch,%bl 520da957e11SThomas Gleixner orb %cl,%bl 521da957e11SThomas Gleixner movl %ebx,%edx 522da957e11SThomas Gleixner movl %eax,%ebx 523da957e11SThomas Gleixner xorl %eax,%eax 524da957e11SThomas Gleixner popl %ecx 525da957e11SThomas Gleixner jmp Denorm_done 526da957e11SThomas Gleixner 527da957e11SThomas Gleixner/* Shift by [64..) bits */ 528da957e11SThomas GleixnerDenorm_shift_more_than_63: 529da957e11SThomas Gleixner cmpw $64,%cx 530da957e11SThomas Gleixner jne Denorm_shift_more_than_64 531da957e11SThomas Gleixner 532da957e11SThomas Gleixner/* Exactly 64 bit shift */ 533da957e11SThomas Gleixner addw %cx,EXP(%edi) 534da957e11SThomas Gleixner xorl %ecx,%ecx 535da957e11SThomas Gleixner orl %edx,%edx 536da957e11SThomas Gleixner setne %cl 537da957e11SThomas Gleixner orl %ebx,%ebx 538da957e11SThomas Gleixner setne %ch 539da957e11SThomas Gleixner orb %ch,%cl 540da957e11SThomas Gleixner orb %cl,%al 541da957e11SThomas Gleixner movl %eax,%edx 542da957e11SThomas Gleixner xorl %eax,%eax 543da957e11SThomas Gleixner xorl %ebx,%ebx 544da957e11SThomas Gleixner popl %ecx 545da957e11SThomas Gleixner jmp Denorm_done 546da957e11SThomas Gleixner 547da957e11SThomas GleixnerDenorm_shift_more_than_64: 548da957e11SThomas Gleixner movw EXP_UNDER+1,EXP(%edi) 549da957e11SThomas Gleixner/* This is easy, %eax must be non-zero, so.. */ 550da957e11SThomas Gleixner movl $1,%edx 551da957e11SThomas Gleixner xorl %eax,%eax 552da957e11SThomas Gleixner xorl %ebx,%ebx 553da957e11SThomas Gleixner popl %ecx 554da957e11SThomas Gleixner jmp Denorm_done 555da957e11SThomas Gleixner 556da957e11SThomas Gleixner 557da957e11SThomas GleixnerUnmasked_underflow: 558da957e11SThomas Gleixner movb UNMASKED_UNDERFLOW,FPU_denormal 559da957e11SThomas Gleixner jmp Denorm_done 560da957e11SThomas Gleixner 561da957e11SThomas Gleixner 562da957e11SThomas Gleixner/* Undo the de-normalisation. */ 563da957e11SThomas GleixnerNormalise_result: 564da957e11SThomas Gleixner cmpb UNMASKED_UNDERFLOW,FPU_denormal 565da957e11SThomas Gleixner je Signal_underflow 566da957e11SThomas Gleixner 567da957e11SThomas Gleixner/* The number must be a denormal if we got here. */ 568da957e11SThomas Gleixner#ifdef PARANOID 569da957e11SThomas Gleixner /* But check it... just in case. */ 570da957e11SThomas Gleixner cmpw EXP_UNDER+1,EXP(%edi) 571da957e11SThomas Gleixner jne L_norm_bugged 572da957e11SThomas Gleixner#endif /* PARANOID */ 573da957e11SThomas Gleixner 574da957e11SThomas Gleixner#ifdef PECULIAR_486 575da957e11SThomas Gleixner /* 576da957e11SThomas Gleixner * This implements a special feature of 80486 behaviour. 577da957e11SThomas Gleixner * Underflow will be signalled even if the number is 578da957e11SThomas Gleixner * not a denormal after rounding. 579da957e11SThomas Gleixner * This difference occurs only for masked underflow, and not 580da957e11SThomas Gleixner * in the unmasked case. 581da957e11SThomas Gleixner * Actual 80486 behaviour differs from this in some circumstances. 582da957e11SThomas Gleixner */ 583da957e11SThomas Gleixner orl %eax,%eax /* ms bits */ 584da957e11SThomas Gleixner js LPseudoDenormal /* Will be masked underflow */ 585da957e11SThomas Gleixner#else 586da957e11SThomas Gleixner orl %eax,%eax /* ms bits */ 587da957e11SThomas Gleixner js L_Normalised /* No longer a denormal */ 588da957e11SThomas Gleixner#endif /* PECULIAR_486 */ 589da957e11SThomas Gleixner 590da957e11SThomas Gleixner jnz LDenormal_adj_exponent 591da957e11SThomas Gleixner 592da957e11SThomas Gleixner orl %ebx,%ebx 593da957e11SThomas Gleixner jz L_underflow_to_zero /* The contents are zero */ 594da957e11SThomas Gleixner 595da957e11SThomas GleixnerLDenormal_adj_exponent: 596da957e11SThomas Gleixner decw EXP(%edi) 597da957e11SThomas Gleixner 598da957e11SThomas GleixnerLPseudoDenormal: 599da957e11SThomas Gleixner testb $0xff,FPU_bits_lost /* bits lost == underflow */ 600da957e11SThomas Gleixner movl TAG_Special,%edx 601da957e11SThomas Gleixner jz L_deNormalised 602da957e11SThomas Gleixner 603da957e11SThomas Gleixner /* There must be a masked underflow */ 604da957e11SThomas Gleixner push %eax 605da957e11SThomas Gleixner pushl EX_Underflow 606da957e11SThomas Gleixner call EXCEPTION 607da957e11SThomas Gleixner popl %eax 608da957e11SThomas Gleixner popl %eax 609da957e11SThomas Gleixner movl TAG_Special,%edx 610da957e11SThomas Gleixner jmp L_deNormalised 611da957e11SThomas Gleixner 612da957e11SThomas Gleixner 613da957e11SThomas Gleixner/* 614da957e11SThomas Gleixner * The operations resulted in a number too small to represent. 615da957e11SThomas Gleixner * Masked response. 616da957e11SThomas Gleixner */ 617da957e11SThomas GleixnerL_underflow_to_zero: 618da957e11SThomas Gleixner push %eax 619da957e11SThomas Gleixner call set_precision_flag_down 620da957e11SThomas Gleixner popl %eax 621da957e11SThomas Gleixner 622da957e11SThomas Gleixner push %eax 623da957e11SThomas Gleixner pushl EX_Underflow 624da957e11SThomas Gleixner call EXCEPTION 625da957e11SThomas Gleixner popl %eax 626da957e11SThomas Gleixner popl %eax 627da957e11SThomas Gleixner 628da957e11SThomas Gleixner/* Reduce the exponent to EXP_UNDER */ 629da957e11SThomas Gleixner movw EXP_UNDER,EXP(%edi) 630da957e11SThomas Gleixner movl TAG_Zero,%edx 631da957e11SThomas Gleixner jmp L_Store_significand 632da957e11SThomas Gleixner 633da957e11SThomas Gleixner 634da957e11SThomas Gleixner/* The operations resulted in a number too large to represent. */ 635da957e11SThomas GleixnerL_overflow: 636da957e11SThomas Gleixner addw EXTENDED_Ebias,EXP(%edi) /* Set for unmasked response. */ 637da957e11SThomas Gleixner push %edi 638da957e11SThomas Gleixner call arith_overflow 639da957e11SThomas Gleixner pop %edi 640da957e11SThomas Gleixner jmp fpu_reg_round_signed_special_exit 641da957e11SThomas Gleixner 642da957e11SThomas Gleixner 643da957e11SThomas GleixnerSignal_underflow: 644da957e11SThomas Gleixner /* The number may have been changed to a non-denormal */ 645da957e11SThomas Gleixner /* by the rounding operations. */ 646da957e11SThomas Gleixner cmpw EXP_UNDER,EXP(%edi) 647da957e11SThomas Gleixner jle Do_unmasked_underflow 648da957e11SThomas Gleixner 649da957e11SThomas Gleixner jmp L_Normalised 650da957e11SThomas Gleixner 651da957e11SThomas GleixnerDo_unmasked_underflow: 652da957e11SThomas Gleixner /* Increase the exponent by the magic number */ 653da957e11SThomas Gleixner addw $(3*(1<<13)),EXP(%edi) 654da957e11SThomas Gleixner push %eax 655da957e11SThomas Gleixner pushl EX_Underflow 656da957e11SThomas Gleixner call EXCEPTION 657da957e11SThomas Gleixner popl %eax 658da957e11SThomas Gleixner popl %eax 659da957e11SThomas Gleixner jmp L_Normalised 660da957e11SThomas Gleixner 661da957e11SThomas Gleixner 662da957e11SThomas Gleixner#ifdef PARANOID 663da957e11SThomas Gleixner#ifdef PECULIAR_486 664da957e11SThomas GleixnerL_bugged_denorm_486: 665da957e11SThomas Gleixner pushl EX_INTERNAL|0x236 666da957e11SThomas Gleixner call EXCEPTION 667da957e11SThomas Gleixner popl %ebx 668da957e11SThomas Gleixner jmp L_exception_exit 669da957e11SThomas Gleixner#else 670da957e11SThomas GleixnerL_bugged_denorm: 671da957e11SThomas Gleixner pushl EX_INTERNAL|0x230 672da957e11SThomas Gleixner call EXCEPTION 673da957e11SThomas Gleixner popl %ebx 674da957e11SThomas Gleixner jmp L_exception_exit 675da957e11SThomas Gleixner#endif /* PECULIAR_486 */ 676da957e11SThomas Gleixner 677da957e11SThomas GleixnerL_bugged_round24: 678da957e11SThomas Gleixner pushl EX_INTERNAL|0x231 679da957e11SThomas Gleixner call EXCEPTION 680da957e11SThomas Gleixner popl %ebx 681da957e11SThomas Gleixner jmp L_exception_exit 682da957e11SThomas Gleixner 683da957e11SThomas GleixnerL_bugged_round53: 684da957e11SThomas Gleixner pushl EX_INTERNAL|0x232 685da957e11SThomas Gleixner call EXCEPTION 686da957e11SThomas Gleixner popl %ebx 687da957e11SThomas Gleixner jmp L_exception_exit 688da957e11SThomas Gleixner 689da957e11SThomas GleixnerL_bugged_round64: 690da957e11SThomas Gleixner pushl EX_INTERNAL|0x233 691da957e11SThomas Gleixner call EXCEPTION 692da957e11SThomas Gleixner popl %ebx 693da957e11SThomas Gleixner jmp L_exception_exit 694da957e11SThomas Gleixner 695da957e11SThomas GleixnerL_norm_bugged: 696da957e11SThomas Gleixner pushl EX_INTERNAL|0x234 697da957e11SThomas Gleixner call EXCEPTION 698da957e11SThomas Gleixner popl %ebx 699da957e11SThomas Gleixner jmp L_exception_exit 700da957e11SThomas Gleixner 701da957e11SThomas GleixnerL_entry_bugged: 702da957e11SThomas Gleixner pushl EX_INTERNAL|0x235 703da957e11SThomas Gleixner call EXCEPTION 704da957e11SThomas Gleixner popl %ebx 705da957e11SThomas GleixnerL_exception_exit: 706da957e11SThomas Gleixner mov $-1,%eax 707da957e11SThomas Gleixner jmp fpu_reg_round_special_exit 708da957e11SThomas Gleixner#endif /* PARANOID */ 709*bd6be579SJiri Slaby 710*bd6be579SJiri SlabyENDPROC(FPU_round) 711