diff --git a/src/backend/x64/a32_jitstate.cpp b/src/backend/x64/a32_jitstate.cpp index e835d4b3..75da3b09 100644 --- a/src/backend/x64/a32_jitstate.cpp +++ b/src/backend/x64/a32_jitstate.cpp @@ -165,10 +165,11 @@ u32 A32JitState::Fpscr() const { DEBUG_ASSERT((fpsr_nzcv & ~FPSCR_NZCV_MASK) == 0); const u32 fpcr_mode = static_cast(upper_location_descriptor) & FPSCR_MODE_MASK; + const u32 mxcsr = guest_MXCSR | asimd_MXCSR; u32 FPSCR = fpcr_mode | fpsr_nzcv; - FPSCR |= (guest_MXCSR & 0b0000000000001); // IOC = IE - FPSCR |= (guest_MXCSR & 0b0000000111100) >> 1; // IXC, UFC, OFC, DZC = PE, UE, OE, ZE + FPSCR |= (mxcsr & 0b0000000000001); // IOC = IE + FPSCR |= (mxcsr & 0b0000000111100) >> 1; // IXC, UFC, OFC, DZC = PE, UE, OE, ZE FPSCR |= fpsr_exc; return FPSCR; @@ -182,10 +183,9 @@ void A32JitState::SetFpscr(u32 FPSCR) { upper_location_descriptor |= FPSCR & FPSCR_MODE_MASK; fpsr_nzcv = FPSCR & FPSCR_NZCV_MASK; - guest_MXCSR = 0; - // Exception masks / enables - guest_MXCSR |= 0x00001f80; // mask all + guest_MXCSR = 0x00001f80; + asimd_MXCSR = 0x00001f80; // RMode const std::array MXCSR_RMode {0x0, 0x4000, 0x2000, 0x6000}; diff --git a/src/backend/x64/a32_jitstate.h b/src/backend/x64/a32_jitstate.h index fce05c03..55f8923e 100644 --- a/src/backend/x64/a32_jitstate.h +++ b/src/backend/x64/a32_jitstate.h @@ -48,6 +48,7 @@ struct A32JitState { // For internal use (See: BlockOfCode::RunCode) u32 guest_MXCSR = 0x00001f80; + u32 asimd_MXCSR = 0x00001f80; u32 save_host_MXCSR = 0; s64 cycles_to_run = 0; s64 cycles_remaining = 0; @@ -83,6 +84,7 @@ struct A32JitState { cpsr_jaifm = src.cpsr_jaifm; ExtReg = src.ExtReg; guest_MXCSR = src.guest_MXCSR; + asimd_MXCSR = src.asimd_MXCSR; fpsr_exc = src.fpsr_exc; fpsr_qc = src.fpsr_qc; fpsr_nzcv = src.fpsr_nzcv; diff --git a/src/backend/x64/a64_jitstate.cpp b/src/backend/x64/a64_jitstate.cpp index 62d222d3..be6bef6e 100644 --- a/src/backend/x64/a64_jitstate.cpp +++ b/src/backend/x64/a64_jitstate.cpp @@ -55,7 +55,9 @@ u32 A64JitState::GetFpcr() const { void A64JitState::SetFpcr(u32 value) { fpcr = value & FPCR_MASK; + asimd_MXCSR &= 0x0000003D; guest_MXCSR &= 0x0000003D; + asimd_MXCSR |= 0x00001f80; guest_MXCSR |= 0x00001f80; // Mask all exceptions // RMode @@ -93,9 +95,10 @@ void A64JitState::SetFpcr(u32 value) { */ u32 A64JitState::GetFpsr() const { + const u32 mxcsr = guest_MXCSR | asimd_MXCSR; u32 fpsr = 0; - fpsr |= (guest_MXCSR & 0b0000000000001); // IOC = IE - fpsr |= (guest_MXCSR & 0b0000000111100) >> 1; // IXC, UFC, OFC, DZC = PE, UE, OE, ZE + fpsr |= (mxcsr & 0b0000000000001); // IOC = IE + fpsr |= (mxcsr & 0b0000000111100) >> 1; // IXC, UFC, OFC, DZC = PE, UE, OE, ZE fpsr |= fpsr_exc; fpsr |= (fpsr_qc == 0 ? 0 : 1) << 27; return fpsr; @@ -103,6 +106,7 @@ u32 A64JitState::GetFpsr() const { void A64JitState::SetFpsr(u32 value) { guest_MXCSR &= ~0x0000003D; + asimd_MXCSR &= ~0x0000003D; fpsr_qc = (value >> 27) & 1; fpsr_exc = value & 0x9F; } diff --git a/src/backend/x64/a64_jitstate.h b/src/backend/x64/a64_jitstate.h index e9ee6969..d6c45185 100644 --- a/src/backend/x64/a64_jitstate.h +++ b/src/backend/x64/a64_jitstate.h @@ -51,6 +51,7 @@ struct A64JitState { // For internal use (See: BlockOfCode::RunCode) u32 guest_MXCSR = 0x00001f80; + u32 asimd_MXCSR = 0x00001f80; u32 save_host_MXCSR = 0; s64 cycles_to_run = 0; s64 cycles_remaining = 0; diff --git a/src/backend/x64/block_of_code.cpp b/src/backend/x64/block_of_code.cpp index b6c1b546..391bd916 100644 --- a/src/backend/x64/block_of_code.cpp +++ b/src/backend/x64/block_of_code.cpp @@ -247,6 +247,16 @@ void BlockOfCode::SwitchMxcsrOnExit() { ldmxcsr(dword[r15 + jsi.offsetof_save_host_MXCSR]); } +void BlockOfCode::EnterStandardASIMD() { + stmxcsr(dword[r15 + jsi.offsetof_guest_MXCSR]); + ldmxcsr(dword[r15 + jsi.offsetof_asimd_MXCSR]); +} + +void BlockOfCode::LeaveStandardASIMD() { + stmxcsr(dword[r15 + jsi.offsetof_asimd_MXCSR]); + ldmxcsr(dword[r15 + jsi.offsetof_guest_MXCSR]); +} + void BlockOfCode::UpdateTicks() { cb.AddTicks->EmitCall(*this, [this](RegList param) { mov(param[0], qword[r15 + jsi.offsetof_cycles_to_run]); diff --git a/src/backend/x64/block_of_code.h b/src/backend/x64/block_of_code.h index f55051fe..43c26cbd 100644 --- a/src/backend/x64/block_of_code.h +++ b/src/backend/x64/block_of_code.h @@ -59,6 +59,10 @@ public: void SwitchMxcsrOnEntry(); /// Code emitter: Makes saved host MXCSR the current MXCSR void SwitchMxcsrOnExit(); + /// Code emitter: Enter standard ASIMD MXCSR region + void EnterStandardASIMD(); + /// Code emitter: Leave standard ASIMD MXCSR region + void LeaveStandardASIMD(); /// Code emitter: Updates cycles remaining my calling cb.AddTicks and cb.GetTicksRemaining /// @note this clobbers ABI caller-save registers void UpdateTicks(); diff --git a/src/backend/x64/jitstate_info.h b/src/backend/x64/jitstate_info.h index 225ff890..e629a23c 100644 --- a/src/backend/x64/jitstate_info.h +++ b/src/backend/x64/jitstate_info.h @@ -16,6 +16,7 @@ struct JitStateInfo { , offsetof_cycles_to_run(offsetof(JitStateType, cycles_to_run)) , offsetof_save_host_MXCSR(offsetof(JitStateType, save_host_MXCSR)) , offsetof_guest_MXCSR(offsetof(JitStateType, guest_MXCSR)) + , offsetof_asimd_MXCSR(offsetof(JitStateType, asimd_MXCSR)) , offsetof_rsb_ptr(offsetof(JitStateType, rsb_ptr)) , rsb_ptr_mask(JitStateType::RSBPtrMask) , offsetof_rsb_location_descriptors(offsetof(JitStateType, rsb_location_descriptors)) @@ -29,6 +30,7 @@ struct JitStateInfo { const size_t offsetof_cycles_to_run; const size_t offsetof_save_host_MXCSR; const size_t offsetof_guest_MXCSR; + const size_t offsetof_asimd_MXCSR; const size_t offsetof_rsb_ptr; const size_t rsb_ptr_mask; const size_t offsetof_rsb_location_descriptors; diff --git a/src/common/fp/fpcr.h b/src/common/fp/fpcr.h index 1145bd57..6c34af7f 100644 --- a/src/common/fp/fpcr.h +++ b/src/common/fp/fpcr.h @@ -180,6 +180,14 @@ public: return value; } + /// Gets the StandardFPSCRValue (A32 ASIMD). + FPCR ASIMDStandardValue() const { + FPCR stdvalue; + stdvalue.AHP(AHP()); + stdvalue.FZ16(FZ16()); + return stdvalue; + } + private: // Bits 0-7, 13-14, and 27-31 are reserved. static constexpr u32 mask = 0x07FF9F00;