/* This file is part of the dynarmic project. * Copyright (c) 2016 MerryMage * This software may be used and distributed according to the terms of the GNU * General Public License version 2 or any later version. */ #include "backend_x64/a64_jitstate.h" #include "common/bit_util.h" #include "frontend/A64/location_descriptor.h" namespace Dynarmic::BackendX64 { u64 A64JitState::GetUniqueHash() const { u64 fpcr_u64 = static_cast(fpcr & A64::LocationDescriptor::FPCR_MASK) << 37; u64 pc_u64 = pc & A64::LocationDescriptor::PC_MASK; return pc_u64 | fpcr_u64; } /** * Comparing MXCSR and FPCR * ======================== * * SSE MSCSR exception masks * ------------------------- * PM bit 12 Precision Mask * UM bit 11 Underflow Mask * OM bit 10 Overflow Mask * ZM bit 9 Divide By Zero Mask * DM bit 8 Denormal Mask * IM bit 7 Invalid Operation Mask * * A64 FPCR exception trap enables * ------------------------------- * IDE bit 15 Input Denormal exception trap enable * IXE bit 12 Inexact exception trap enable * UFE bit 11 Underflow exception trap enable * OFE bit 10 Overflow exception trap enable * DZE bit 9 Division by Zero exception trap enable * IOE bit 8 Invalid Operation exception trap enable * * SSE MXCSR mode bits * ------------------- * FZ bit 15 Flush To Zero * DAZ bit 6 Denormals Are Zero * RN bits 13-14 Round to {0 = Nearest, 1 = Negative, 2 = Positive, 3 = Zero} * * A64 FPCR mode bits * ------------------ * AHP bit 26 Alternative half-precision * DN bit 25 Default NaN * FZ bit 24 Flush to Zero * RMode bits 22-23 Round to {0 = Nearest, 1 = Positive, 2 = Negative, 3 = Zero} * FZ16 bit 19 Flush to Zero for half-precision */ constexpr u32 FPCR_MASK = 0x07C89F00; u32 A64JitState::GetFpcr() const { return fpcr; } void A64JitState::SetFpcr(u32 value) { fpcr = value & FPCR_MASK; guest_MXCSR &= 0x0000003D; guest_MXCSR |= 0x00001f80; // Mask all exceptions // RMode const std::array MXCSR_RMode {0x0, 0x4000, 0x2000, 0x6000}; guest_MXCSR |= MXCSR_RMode[(value >> 22) & 0x3]; if (Common::Bit<24>(value)) { guest_MXCSR |= (1 << 15); // SSE Flush to Zero guest_MXCSR |= (1 << 6); // SSE Denormals are Zero } } /** * Comparing MXCSR and FPSR * ======================== * * SSE MXCSR exception flags * ------------------------- * PE bit 5 Precision Flag * UE bit 4 Underflow Flag * OE bit 3 Overflow Flag * ZE bit 2 Divide By Zero Flag * DE bit 1 Denormal Flag // Appears to only be set when MXCSR.DAZ = 0 * IE bit 0 Invalid Operation Flag * * A64 FPSR cumulative exception bits * ---------------------------------- * QC bit 27 Cumulative saturation bit * IDC bit 7 Input Denormal cumulative exception bit // Only ever set when FPCR.FTZ = 1 * IXC bit 4 Inexact cumulative exception bit * UFC bit 3 Underflow cumulative exception bit * OFC bit 2 Overflow cumulative exception bit * DZC bit 1 Division by Zero cumulative exception bit * IOC bit 0 Invalid Operation cumulative exception bit */ u32 A64JitState::GetFpsr() const { u32 fpsr = 0; fpsr |= (guest_MXCSR & 0b0000000000001); // IOC = IE fpsr |= (guest_MXCSR & 0b0000000111100) >> 1; // IXC, UFC, OFC, DZC = PE, UE, OE, ZE fpsr |= FPSCR_IDC; fpsr |= FPSCR_UFC; return fpsr; } void A64JitState::SetFpsr(u32 value) { guest_MXCSR &= ~0x0000003D; guest_MXCSR |= ( value ) & 0b0000000000001; // IE = IOC guest_MXCSR |= ( value << 1) & 0b0000000111100; // PE, UE, OE, ZE = IXC, UFC, OFC, DZC FPSCR_IDC = value & (1 << 7); FPSCR_UFC = value & (1 << 3); } } // namespace Dynarmic::BackendX64