Bit64u bx_get_realtime64_usec(void) { Bit64u new_bottom = ((Bit64u) GetTickCount()) & BX_CONST64(0x0FFFFFFFF); if(new_bottom < last_realtime64_bottom) { last_realtime64_top += BX_CONST64(0x0000000100000000); } last_realtime64_bottom = new_bottom; Bit64u interim_realtime64 = (last_realtime64_top & BX_CONST64(0xFFFFFFFF00000000)) | (new_bottom & BX_CONST64(0x00000000FFFFFFFF)); return interim_realtime64*(BX_CONST64(1000)); }
void BX_CPU_C::BSR_GqEq(bxInstruction_c *i) { /* for 64 bit operand size mode */ Bit64u op1_64, op2_64; /* op2_64 is a register or memory reference */ if (i->modC0()) { op2_64 = BX_READ_64BIT_REG(i->rm()); } else { /* pointer, segment address pair */ read_virtual_qword(i->seg(), RMAddr(i), &op2_64); } if (op2_64 == 0) { assert_ZF(); /* op1_64 undefined */ return; } op1_64 = 63; while ( (op2_64 & BX_CONST64(0x8000000000000000)) == 0 ) { op1_64--; op2_64 <<= 1; } SET_FLAGS_OSZAPC_RESULT_64(op1_64, BX_INSTR_BITSCAN64); /* now write result back to destination */ BX_WRITE_64BIT_REG(i->nnn(), op1_64); }
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::BEXTR_GqEqIdR(bxInstruction_c *i) { Bit16u control = (Bit16u) i->Id(); unsigned start = control & 0xff; unsigned len = control >> 8; Bit64u op1_64 = 0; if (start < 64 && len > 0) { op1_64 = BX_READ_64BIT_REG(i->rm()); op1_64 >>= start; if (len < 64) { Bit64u extract_mask = (BX_CONST64(1) << len) - 1; op1_64 &= extract_mask; } }
void BX_CPP_AttrRegparmN(1) BX_CPU_C::FBSTP_PACKED_BCD(bxInstruction_c *i) { #if BX_SUPPORT_FPU BX_CPU_THIS_PTR prepareFPU(i); /* * The packed BCD integer indefinite encoding (FFFFC000000000000000H) * is stored in response to a masked floating-point invalid-operation * exception. */ Bit16u save_reg_hi = 0xFFFF; Bit64u save_reg_lo = BX_CONST64(0xC000000000000000); clear_C1(); if (IS_TAG_EMPTY(0)) { BX_CPU_THIS_PTR FPU_exception(FPU_EX_Stack_Underflow); if (! (BX_CPU_THIS_PTR the_i387.is_IA_masked())) return; } else { float_status_t status = FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word()); floatx80 reg = BX_READ_FPU_REG(0); Bit64s save_val = floatx80_to_int64(reg, status); int sign = (reg.exp & 0x8000) != 0; if (sign) save_val = -save_val; if (save_val > BX_CONST64(999999999999999999)) { float_raise(status, float_flag_invalid); } if (! (status.float_exception_flags & float_flag_invalid)) { save_reg_hi = (sign) ? 0x8000 : 0; save_reg_lo = 0; for (int i=0; i<16; i++) { save_reg_lo += ((Bit64u)(save_val % 10)) << (4*i); save_val /= 10; } save_reg_hi += (Bit16u)(save_val % 10); save_val /= 10; save_reg_hi += (Bit16u)(save_val % 10) << 4; } /* check for fpu arithmetic exceptions */ if (BX_CPU_THIS_PTR FPU_exception(status.float_exception_flags)) return; } // write packed bcd to memory write_virtual_qword(i->seg(), RMAddr(i), save_reg_lo); write_virtual_word (i->seg(), RMAddr(i) + 8, save_reg_hi); BX_CPU_THIS_PTR the_i387.FPU_pop(); #else BX_INFO(("FBSTP_PACKED_BCD: required FPU, configure --enable-fpu")); #endif }
| | | | +---------------------------------------------------------------------------*/ #include "exception.h" #include "reg_constant.h" #include "fpu_emu.h" #include "fpu_system.h" #include "control_w.h" #include "poly.h" #define HIPOWER 11 static const u64 lterms[HIPOWER] = { BX_CONST64(0x0000000000000000), /* This term done separately as 12 bytes */ BX_CONST64(0xf5fdeffc162c7543), BX_CONST64(0x1c6b08d704a0bfa6), BX_CONST64(0x0276556df749cc21), BX_CONST64(0x002bb0ffcf14f6b8), BX_CONST64(0x0002861225ef751c), BX_CONST64(0x00001ffcbfcd5422), BX_CONST64(0x00000162c005d5f1), BX_CONST64(0x0000000da96ccb1b), BX_CONST64(0x0000000078d1b897), BX_CONST64(0x000000000422b029) }; static const Xsig hiterm = MK_XSIG(0xb17217f7, 0xd1cf79ab, 0xc8a39194); /* Four slices: 0.0 : 0.25 : 0.50 : 0.75 : 1.0,
void BX_CPU_C::long_mode_int(Bit8u vector, unsigned soft_int, bx_bool push_error, Bit16u error_code) { bx_descriptor_t gate_descriptor, cs_descriptor; bx_selector_t cs_selector; // interrupt vector must be within IDT table limits, // else #GP(vector*8 + 2 + EXT) if ((vector*16 + 15) > BX_CPU_THIS_PTR idtr.limit) { BX_ERROR(("interrupt(long mode): vector must be within IDT table limits, IDT.limit = 0x%x", BX_CPU_THIS_PTR idtr.limit)); exception(BX_GP_EXCEPTION, vector*8 + 2); } Bit64u desctmp1 = system_read_qword(BX_CPU_THIS_PTR idtr.base + vector*16); Bit64u desctmp2 = system_read_qword(BX_CPU_THIS_PTR idtr.base + vector*16 + 8); if (desctmp2 & BX_CONST64(0x00001F0000000000)) { BX_ERROR(("interrupt(long mode): IDT entry extended attributes DWORD4 TYPE != 0")); exception(BX_GP_EXCEPTION, vector*8 + 2); } Bit32u dword1 = GET32L(desctmp1); Bit32u dword2 = GET32H(desctmp1); Bit32u dword3 = GET32L(desctmp2); parse_descriptor(dword1, dword2, &gate_descriptor); if ((gate_descriptor.valid==0) || gate_descriptor.segment) { BX_ERROR(("interrupt(long mode): gate descriptor is not valid sys seg")); exception(BX_GP_EXCEPTION, vector*8 + 2); } // descriptor AR byte must indicate interrupt gate, trap gate, // or task gate, else #GP(vector*8 + 2 + EXT) if (gate_descriptor.type != BX_386_INTERRUPT_GATE && gate_descriptor.type != BX_386_TRAP_GATE) { BX_ERROR(("interrupt(long mode): unsupported gate type %u", (unsigned) gate_descriptor.type)); exception(BX_GP_EXCEPTION, vector*8 + 2); } // if software interrupt, then gate descripor DPL must be >= CPL, // else #GP(vector * 8 + 2 + EXT) if (soft_int && gate_descriptor.dpl < CPL) { BX_ERROR(("interrupt(long mode): soft_int && gate.dpl < CPL")); exception(BX_GP_EXCEPTION, vector*8 + 2); } // Gate must be present, else #NP(vector * 8 + 2 + EXT) if (! IS_PRESENT(gate_descriptor)) { BX_ERROR(("interrupt(long mode): gate.p == 0")); exception(BX_NP_EXCEPTION, vector*8 + 2); } Bit16u gate_dest_selector = gate_descriptor.u.gate.dest_selector; Bit64u gate_dest_offset = ((Bit64u)dword3 << 32) | gate_descriptor.u.gate.dest_offset; unsigned ist = gate_descriptor.u.gate.param_count & 0x7; // examine CS selector and descriptor given in gate descriptor // selector must be non-null else #GP(EXT) if ((gate_dest_selector & 0xfffc) == 0) { BX_ERROR(("int_trap_gate(long mode): selector null")); exception(BX_GP_EXCEPTION, 0); } parse_selector(gate_dest_selector, &cs_selector); // selector must be within its descriptor table limits // else #GP(selector+EXT) fetch_raw_descriptor(&cs_selector, &dword1, &dword2, BX_GP_EXCEPTION); parse_descriptor(dword1, dword2, &cs_descriptor); // descriptor AR byte must indicate code seg // and code segment descriptor DPL<=CPL, else #GP(selector+EXT) if (cs_descriptor.valid==0 || cs_descriptor.segment==0 || IS_DATA_SEGMENT(cs_descriptor.type) || cs_descriptor.dpl > CPL) { BX_ERROR(("interrupt(long mode): not accessible or not code segment")); exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc); } // check that it's a 64 bit segment if (! IS_LONG64_SEGMENT(cs_descriptor) || cs_descriptor.u.segment.d_b) { BX_ERROR(("interrupt(long mode): must be 64 bit segment")); exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc); } // segment must be present, else #NP(selector + EXT) if (! IS_PRESENT(cs_descriptor)) { BX_ERROR(("interrupt(long mode): segment not present")); exception(BX_NP_EXCEPTION, cs_selector.value & 0xfffc); } Bit64u RSP_for_cpl_x; Bit64u old_CS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_CS].selector.value; Bit64u old_RIP = RIP; Bit64u old_SS = BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS].selector.value; Bit64u old_RSP = RSP; // if code segment is non-conforming and DPL < CPL then // INTERRUPT TO INNER PRIVILEGE: if (IS_CODE_SEGMENT_NON_CONFORMING(cs_descriptor.type) && cs_descriptor.dpl < CPL) { BX_DEBUG(("interrupt(long mode): INTERRUPT TO INNER PRIVILEGE")); // check selector and descriptor for new stack in current TSS if (ist > 0) { BX_DEBUG(("interrupt(long mode): trap to IST, vector = %d", ist)); RSP_for_cpl_x = get_RSP_from_TSS(ist+3); } else { RSP_for_cpl_x = get_RSP_from_TSS(cs_descriptor.dpl); } // align stack RSP_for_cpl_x &= BX_CONST64(0xfffffffffffffff0); // push old stack long pointer onto new stack write_new_stack_qword_64(RSP_for_cpl_x - 8, cs_descriptor.dpl, old_SS); write_new_stack_qword_64(RSP_for_cpl_x - 16, cs_descriptor.dpl, old_RSP); write_new_stack_qword_64(RSP_for_cpl_x - 24, cs_descriptor.dpl, read_eflags()); // push long pointer to return address onto new stack write_new_stack_qword_64(RSP_for_cpl_x - 32, cs_descriptor.dpl, old_CS); write_new_stack_qword_64(RSP_for_cpl_x - 40, cs_descriptor.dpl, old_RIP); RSP_for_cpl_x -= 40; if (push_error) { RSP_for_cpl_x -= 8; write_new_stack_qword_64(RSP_for_cpl_x, cs_descriptor.dpl, error_code); } // load CS:RIP (guaranteed to be in 64 bit mode) branch_far64(&cs_selector, &cs_descriptor, gate_dest_offset, cs_descriptor.dpl); // set up null SS descriptor load_null_selector(&BX_CPU_THIS_PTR sregs[BX_SEG_REG_SS], cs_descriptor.dpl); } else if(IS_CODE_SEGMENT_CONFORMING(cs_descriptor.type) || cs_descriptor.dpl==CPL) { // if code segment is conforming OR code segment DPL = CPL then // INTERRUPT TO SAME PRIVILEGE LEVEL: BX_DEBUG(("interrupt(long mode): INTERRUPT TO SAME PRIVILEGE")); // check selector and descriptor for new stack in current TSS if (ist > 0) { BX_DEBUG(("interrupt(long mode): trap to IST, vector = %d", ist)); RSP_for_cpl_x = get_RSP_from_TSS(ist+3); } else { RSP_for_cpl_x = RSP; } // align stack RSP_for_cpl_x &= BX_CONST64(0xfffffffffffffff0); // push flags onto stack // push current CS selector onto stack // push return offset onto stack write_new_stack_qword_64(RSP_for_cpl_x - 8, cs_descriptor.dpl, old_SS); write_new_stack_qword_64(RSP_for_cpl_x - 16, cs_descriptor.dpl, old_RSP); write_new_stack_qword_64(RSP_for_cpl_x - 24, cs_descriptor.dpl, read_eflags()); // push long pointer to return address onto new stack write_new_stack_qword_64(RSP_for_cpl_x - 32, cs_descriptor.dpl, old_CS); write_new_stack_qword_64(RSP_for_cpl_x - 40, cs_descriptor.dpl, old_RIP); RSP_for_cpl_x -= 40; if (push_error) { RSP_for_cpl_x -= 8; write_new_stack_qword_64(RSP_for_cpl_x, cs_descriptor.dpl, error_code); } // set the RPL field of CS to CPL branch_far64(&cs_selector, &cs_descriptor, gate_dest_offset, CPL); } else { BX_ERROR(("interrupt(long mode): bad descriptor type %u (CS.DPL=%u CPL=%u)", (unsigned) cs_descriptor.type, (unsigned) cs_descriptor.dpl, (unsigned) CPL)); exception(BX_GP_EXCEPTION, cs_selector.value & 0xfffc); } RSP = RSP_for_cpl_x; // if interrupt gate then set IF to 0 if (!(gate_descriptor.type & 1)) // even is int-gate BX_CPU_THIS_PTR clear_IF(); BX_CPU_THIS_PTR clear_TF(); //BX_CPU_THIS_PTR clear_VM(); // VM is clear in long mode BX_CPU_THIS_PTR clear_RF(); BX_CPU_THIS_PTR clear_NT(); }
int ftan(floatx80 &a, float_status_t &status) { Bit64u aSig0, aSig1 = 0; Bit32s aExp, zExp, expDiff; int aSign, zSign; int q = 0; // handle unsupported extended double-precision floating encodings if (floatx80_is_unsupported(a)) { goto invalid; } aSig0 = extractFloatx80Frac(a); aExp = extractFloatx80Exp(a); aSign = extractFloatx80Sign(a); /* invalid argument */ if (aExp == 0x7FFF) { if ((Bit64u) (aSig0<<1)) { a = propagateFloatx80NaN(a, status); return 0; } invalid: float_raise(status, float_flag_invalid); a = floatx80_default_nan; return 0; } if (aExp == 0) { if (aSig0 == 0) return 0; float_raise(status, float_flag_denormal); /* handle pseudo denormals */ if (! (aSig0 & BX_CONST64(0x8000000000000000))) { float_raise(status, float_flag_inexact | float_flag_underflow); return 0; } normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0); } zSign = aSign; zExp = EXP_BIAS; expDiff = aExp - zExp; /* argument is out-of-range */ if (expDiff >= 63) return -1; float_raise(status, float_flag_inexact); if (expDiff < -1) { // doesn't require reduction if (expDiff <= -68) { a = packFloatx80(aSign, aExp, aSig0); return 0; } zExp = aExp; } else { q = reduce_trig_arg(expDiff, zSign, aSig0, aSig1); } /* **************************** */ /* argument reduction completed */ /* **************************** */ /* using float128 for approximation */ float128 r = normalizeRoundAndPackFloat128(0, zExp-0x10, aSig0, aSig1, status); float128 sin_r = poly_sin(r, status); float128 cos_r = poly_cos(r, status); if (q & 0x1) { r = float128_div(cos_r, sin_r, status); zSign = ! zSign; } else { r = float128_div(sin_r, cos_r, status); } a = float128_to_floatx80(r, status); if (zSign) floatx80_chs(a); return 0; }
the work is derivative, and (2) the source code includes prominent notice with these four paragraphs for those parts of this code that are retained. =============================================================================*/ /*============================================================================ * Written for Bochs (x86 achitecture simulator) by * Stanislav Shwartsman [sshwarts at sourceforge net] * ==========================================================================*/ #define FLOAT128 #include "softfloatx80.h" #include "softfloat-round-pack.h" #include "fpu_constant.h" static const floatx80 floatx80_one = packFloatx80(0, 0x3fff, BX_CONST64(0x8000000000000000)); /* reduce trigonometric function argument using 128-bit precision M_PI approximation */ static Bit64u argument_reduction_kernel(Bit64u aSig0, int Exp, Bit64u *zSig0, Bit64u *zSig1) { Bit64u term0, term1, term2; Bit64u aSig1 = 0; shortShift128Left(aSig1, aSig0, Exp, &aSig1, &aSig0); Bit64u q = estimateDiv128To64(aSig1, aSig0, FLOAT_PI_HI); mul128By64To192(FLOAT_PI_HI, FLOAT_PI_LO, q, &term0, &term1, &term2); sub128(aSig1, aSig0, term0, term1, zSig1, zSig0); while ((Bit64s)(*zSig1) < 0) { --q; add192(*zSig1, *zSig0, term2, 0, FLOAT_PI_HI, FLOAT_PI_LO, zSig1, zSig0, &term2);
int FPU_u_mul(const FPU_REG *a, const FPU_REG *b, FPU_REG *c, u16 cw, u_char sign, int expon) { u64 mu, ml, mi; u32 lh, ll, th, tl; #ifdef PARANOID if ( ! (a->sigh & 0x80000000) || ! (b->sigh & 0x80000000) ) { EXCEPTION(EX_INTERNAL|0x205); } #endif ml = a->sigl; ml *= b->sigl; ll = ml; lh = ml >> 32; mu = a->sigh; mu *= b->sigh; mi = a->sigh; mi *= b->sigl; tl = mi; th = mi >> 32; lh += tl; if ( tl > lh ) mu ++; mu += th; mi = a->sigl; mi *= b->sigh; tl = mi; th = mi >> 32; lh += tl; if ( tl > lh ) mu ++; mu += th; ml = lh; ml <<= 32; ml += ll; expon -= EXP_BIAS-1; if ( expon <= EXP_WAY_UNDER ) expon = EXP_WAY_UNDER; c->exp = expon; if ( ! (mu & BX_CONST64(0x8000000000000000)) ) { mu <<= 1; if ( ml & BX_CONST64(0x8000000000000000) ) mu |= 1; ml <<= 1; c->exp --; } ll = ml; lh = ml >> 32; if ( ll ) lh |= 1; c->sigl = mu; c->sigh = mu >> 32; return FPU_round(c, lh, 0, cw, sign); }
BX_INSF_TYPE BX_CPP_AttrRegparmN(1) BX_CPU_C::FBSTP_PACKED_BCD(bxInstruction_c *i) { BX_CPU_THIS_PTR prepareFPU(i); RMAddr(i) = BX_CPU_CALL_METHODR(i->ResolveModrm, (i)); FPU_update_last_instruction(i); Bit16u x87_sw = FPU_PARTIAL_STATUS; /* * The packed BCD integer indefinite encoding (FFFFC000000000000000H) * is stored in response to a masked floating-point invalid-operation * exception. */ Bit16u save_reg_hi = 0xFFFF; Bit64u save_reg_lo = BX_CONST64(0xC000000000000000); clear_C1(); if (IS_TAG_EMPTY(0)) { FPU_exception(FPU_EX_Stack_Underflow); if (! BX_CPU_THIS_PTR the_i387.is_IA_masked()) BX_NEXT_INSTR(i); } else { float_status_t status = FPU_pre_exception_handling(BX_CPU_THIS_PTR the_i387.get_control_word()); floatx80 reg = BX_READ_FPU_REG(0); Bit64s save_val = floatx80_to_int64(reg, status); int sign = (reg.exp & 0x8000) != 0; if (sign) save_val = -save_val; if (save_val > BX_CONST64(999999999999999999)) { status.float_exception_flags = float_flag_invalid; // throw away other flags } if (! (status.float_exception_flags & float_flag_invalid)) { save_reg_hi = (sign) ? 0x8000 : 0; save_reg_lo = 0; for (int i=0; i<16; i++) { save_reg_lo += ((Bit64u)(save_val % 10)) << (4*i); save_val /= 10; } save_reg_hi += (Bit16u)(save_val % 10); save_val /= 10; save_reg_hi += (Bit16u)(save_val % 10) << 4; } /* check for fpu arithmetic exceptions */ if (FPU_exception(status.float_exception_flags, 1)) BX_NEXT_INSTR(i); } // store to the memory might generate an exception, in this case origial FPU_SW must be kept swap_values16u(x87_sw, FPU_PARTIAL_STATUS); // write packed bcd to memory write_virtual_qword(i->seg(), RMAddr(i), save_reg_lo); write_virtual_word(i->seg(), (RMAddr(i) + 8) & i->asize_mask(), save_reg_hi); FPU_PARTIAL_STATUS = x87_sw; BX_CPU_THIS_PTR the_i387.FPU_pop(); BX_NEXT_INSTR(i); }
floatx80 fpatan(floatx80 a, floatx80 b, float_status_t &status) { // handle unsupported extended double-precision floating encodings if (floatx80_is_unsupported(a) || floatx80_is_unsupported(b)) { float_raise(status, float_flag_invalid); return floatx80_default_nan; } Bit64u aSig = extractFloatx80Frac(a); Bit32s aExp = extractFloatx80Exp(a); int aSign = extractFloatx80Sign(a); Bit64u bSig = extractFloatx80Frac(b); Bit32s bExp = extractFloatx80Exp(b); int bSign = extractFloatx80Sign(b); int zSign = aSign ^ bSign; if (bExp == 0x7FFF) { if ((Bit64u) (bSig<<1)) return propagateFloatx80NaN(a, b, status); if (aExp == 0x7FFF) { if ((Bit64u) (aSig<<1)) return propagateFloatx80NaN(a, b, status); if (aSign) { /* return 3PI/4 */ return roundAndPackFloatx80(80, bSign, FLOATX80_3PI4_EXP, FLOAT_3PI4_HI, FLOAT_3PI4_LO, status); } else { /* return PI/4 */ return roundAndPackFloatx80(80, bSign, FLOATX80_PI4_EXP, FLOAT_PI_HI, FLOAT_PI_LO, status); } } if (aSig && (aExp == 0)) float_raise(status, float_flag_denormal); /* return PI/2 */ return roundAndPackFloatx80(80, bSign, FLOATX80_PI2_EXP, FLOAT_PI_HI, FLOAT_PI_LO, status); } if (aExp == 0x7FFF) { if ((Bit64u) (aSig<<1)) return propagateFloatx80NaN(a, b, status); if (bSig && (bExp == 0)) float_raise(status, float_flag_denormal); return_PI_or_ZERO: if (aSign) { /* return PI */ return roundAndPackFloatx80(80, bSign, FLOATX80_PI_EXP, FLOAT_PI_HI, FLOAT_PI_LO, status); } else { /* return 0 */ return packFloatx80(bSign, 0, 0); } } if (bExp == 0) { if (bSig == 0) { if (aSig && (aExp == 0)) float_raise(status, float_flag_denormal); goto return_PI_or_ZERO; } float_raise(status, float_flag_denormal); normalizeFloatx80Subnormal(bSig, &bExp, &bSig); } if (aExp == 0) { if (aSig == 0) /* return PI/2 */ return roundAndPackFloatx80(80, bSign, FLOATX80_PI2_EXP, FLOAT_PI_HI, FLOAT_PI_LO, status); float_raise(status, float_flag_denormal); normalizeFloatx80Subnormal(aSig, &aExp, &aSig); } float_raise(status, float_flag_inexact); /* |a| = |b| ==> return PI/4 */ if (aSig == bSig && aExp == bExp) return roundAndPackFloatx80(80, bSign, FLOATX80_PI4_EXP, FLOAT_PI_HI, FLOAT_PI_LO, status); /* ******************************** */ /* using float128 for approximation */ /* ******************************** */ float128 a128 = normalizeRoundAndPackFloat128(0, aExp-0x10, aSig, 0, status); float128 b128 = normalizeRoundAndPackFloat128(0, bExp-0x10, bSig, 0, status); float128 x; int swap = 0, add_pi6 = 0, add_pi4 = 0; if (aExp > bExp || (aExp == bExp && aSig > bSig)) { x = float128_div(b128, a128, status); } else { x = float128_div(a128, b128, status); swap = 1; } Bit32s xExp = extractFloat128Exp(x); if (xExp <= EXP_BIAS-40) goto approximation_completed; if (x.hi >= BX_CONST64(0x3ffe800000000000)) // 3/4 < x < 1 { /* arctan(x) = arctan((x-1)/(x+1)) + pi/4 */ float128 t1 = float128_sub(x, float128_one, status); float128 t2 = float128_add(x, float128_one, status); x = float128_div(t1, t2, status); add_pi4 = 1; } else { /* argument correction */ if (xExp >= 0x3FFD) // 1/4 < x < 3/4 { /* arctan(x) = arctan((x*sqrt(3)-1)/(x+sqrt(3))) + pi/6 */ float128 t1 = float128_mul(x, float128_sqrt3, status); float128 t2 = float128_add(x, float128_sqrt3, status); x = float128_sub(t1, float128_one, status); x = float128_div(x, t2, status); add_pi6 = 1; } } x = poly_atan(x, status); if (add_pi6) x = float128_add(x, float128_pi6, status); if (add_pi4) x = float128_add(x, float128_pi4, status); approximation_completed: if (swap) x = float128_sub(float128_pi2, x, status); floatx80 result = float128_to_floatx80(x, status); if (zSign) floatx80_chs(result); int rSign = extractFloatx80Sign(result); if (!bSign && rSign) return floatx80_add(result, floatx80_pi, status); if (bSign && !rSign) return floatx80_sub(result, floatx80_pi, status); return result; }
/*============================================================================ * Written for Bochs (x86 achitecture simulator) by * Stanislav Shwartsman [sshwarts at sourceforge net] * ==========================================================================*/ #define FLOAT128 #include "softfloatx80.h" #include "softfloat-round-pack.h" #include "fpu_constant.h" #define FPATAN_ARR_SIZE 11 static const float128 float128_one = packFloat128(BX_CONST64(0x3fff000000000000), BX_CONST64(0x0000000000000000)); static const float128 float128_sqrt3 = packFloat128(BX_CONST64(0x3fffbb67ae8584ca), BX_CONST64(0xa73b25742d7078b8)); static const floatx80 floatx80_pi = packFloatx80(0, 0x4000, BX_CONST64(0xc90fdaa22168c235)); static const float128 float128_pi2 = packFloat128(BX_CONST64(0x3fff921fb54442d1), BX_CONST64(0x8469898CC5170416)); static const float128 float128_pi4 = packFloat128(BX_CONST64(0x3ffe921fb54442d1), BX_CONST64(0x8469898CC5170416)); static const float128 float128_pi6 = packFloat128(BX_CONST64(0x3ffe0c152382d736), BX_CONST64(0x58465BB32E0F580F)); static float128 atan_arr[FPATAN_ARR_SIZE] = { PACK_FLOAT_128(0x3fff000000000000, 0x0000000000000000), /* 1 */
if ( exponent(dest) <= EXP_UNDER ) EXCEPTION(EX_Underflow); return 0; } #undef HIPOWER #define HIPOWER 10 static const u64 logterms[HIPOWER] = { BX_CONST64(0x2a8eca5705fc2ef0), BX_CONST64(0xf6384ee1d01febce), BX_CONST64(0x093bb62877cdf642), BX_CONST64(0x006985d8a9ec439b), BX_CONST64(0x0005212c4f55a9c8), BX_CONST64(0x00004326a16927f0), BX_CONST64(0x0000038d1d80a0e7), BX_CONST64(0x0000003141cc80c6), BX_CONST64(0x00000002b1668c9f), BX_CONST64(0x000000002c7a46aa) }; static const u32 leadterm = 0xb8000000; /*--- log2_kernel() ---------------------------------------------------------+
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // ///////////////////////////////////////////////////////////////////////// #define NEED_CPU_REG_SHORTCUTS 1 #include "bochs.h" #include "cpu/cpu.h" #define LOG_THIS BX_CPU_THIS_PTR #if BX_SUPPORT_FPU #include "softfloatx80.h" const floatx80 Const_QNaN = packFloatx80(0, floatx80_default_nan_exp, floatx80_default_nan_fraction); const floatx80 Const_Z = packFloatx80(0, 0x0000, 0); const floatx80 Const_1 = packFloatx80(0, 0x3fff, BX_CONST64(0x8000000000000000)); const floatx80 Const_L2T = packFloatx80(0, 0x4000, BX_CONST64(0xd49a784bcd1b8afe)); const floatx80 Const_L2E = packFloatx80(0, 0x3fff, BX_CONST64(0xb8aa3b295c17f0bc)); const floatx80 Const_PI = packFloatx80(0, 0x4000, BX_CONST64(0xc90fdaa22168c235)); const floatx80 Const_LG2 = packFloatx80(0, 0x3ffd, BX_CONST64(0x9a209a84fbcff799)); const floatx80 Const_LN2 = packFloatx80(0, 0x3ffe, BX_CONST64(0xb17217f7d1cf79ac)); const floatx80 Const_INF = packFloatx80(0, 0x7fff, BX_CONST64(0x8000000000000000)); /* A fast way to find out whether x is one of RC_DOWN or RC_CHOP (and not one of RC_RND or RC_UP). */ #define DOWN_OR_CHOP() (FPU_CONTROL_WORD & FPU_CW_RC & FPU_RC_DOWN) BX_CPP_INLINE floatx80 FPU_round_const(const floatx80 &a, int adj) { floatx80 result = a;
static floatx80 do_fprem(floatx80 a, floatx80 b, Bit64u &q, int rounding_mode, float_status_t &status) { Bit32s aExp, bExp, zExp, expDiff; Bit64u aSig0, aSig1, bSig; int aSign; q = 0; // handle unsupported extended double-precision floating encodings if (floatx80_is_unsupported(a) || floatx80_is_unsupported(b)) { float_raise(status, float_flag_invalid); return floatx80_default_nan; } aSig0 = extractFloatx80Frac(a); aExp = extractFloatx80Exp(a); aSign = extractFloatx80Sign(a); bSig = extractFloatx80Frac(b); bExp = extractFloatx80Exp(b); if (aExp == 0x7FFF) { if ((Bit64u) (aSig0<<1) || ((bExp == 0x7FFF) && (Bit64u) (bSig<<1))) { return propagateFloatx80NaN(a, b, status); } goto invalid; } if (bExp == 0x7FFF) { if ((Bit64u) (bSig<<1)) return propagateFloatx80NaN(a, b, status); return a; } if (bExp == 0) { if (bSig == 0) { invalid: float_raise(status, float_flag_invalid); return floatx80_default_nan; } float_raise(status, float_flag_denormal); normalizeFloatx80Subnormal(bSig, &bExp, &bSig); } if (aExp == 0) { if ((Bit64u) (aSig0<<1) == 0) return a; float_raise(status, float_flag_denormal); normalizeFloatx80Subnormal(aSig0, &aExp, &aSig0); } expDiff = aExp - bExp; aSig1 = 0; if (expDiff >= 64) { int n = (expDiff & 0x1f) | 0x20; remainder_kernel(aSig0, bSig, n, &aSig0, &aSig1); zExp = aExp - n; q = (Bit64u) -1; } else { zExp = bExp; if (expDiff < 0) { if (expDiff < -1) return (a.fraction & BX_CONST64(0x8000000000000000)) ? packFloatx80(aSign, aExp, aSig0) : a; shift128Right(aSig0, 0, 1, &aSig0, &aSig1); expDiff = 0; } if (expDiff > 0) { q = remainder_kernel(aSig0, bSig, expDiff, &aSig0, &aSig1); } else { if (bSig <= aSig0) { aSig0 -= bSig; q = 1; } } if (rounding_mode == float_round_nearest_even) { Bit64u term0, term1; shift128Right(bSig, 0, 1, &term0, &term1); if (! lt128(aSig0, aSig1, term0, term1)) { int lt = lt128(term0, term1, aSig0, aSig1); int eq = eq128(aSig0, aSig1, term0, term1); if ((eq && (q & 1)) || lt) { aSign = !aSign; ++q; } if (lt) sub128(bSig, 0, aSig0, aSig1, &aSig0, &aSig1); } } } return normalizeRoundAndPackFloatx80(80, aSign, zExp, aSig0, aSig1, status); }