backend/x64: Implement separate MSXCSR for ASIMDStandardValue

This commit is contained in:
MerryMage 2020-06-20 00:00:36 +01:00
parent d3664b03fe
commit 1b3a70a83c
8 changed files with 38 additions and 7 deletions

View file

@ -165,10 +165,11 @@ u32 A32JitState::Fpscr() const {
DEBUG_ASSERT((fpsr_nzcv & ~FPSCR_NZCV_MASK) == 0); DEBUG_ASSERT((fpsr_nzcv & ~FPSCR_NZCV_MASK) == 0);
const u32 fpcr_mode = static_cast<u32>(upper_location_descriptor) & FPSCR_MODE_MASK; const u32 fpcr_mode = static_cast<u32>(upper_location_descriptor) & FPSCR_MODE_MASK;
const u32 mxcsr = guest_MXCSR | asimd_MXCSR;
u32 FPSCR = fpcr_mode | fpsr_nzcv; u32 FPSCR = fpcr_mode | fpsr_nzcv;
FPSCR |= (guest_MXCSR & 0b0000000000001); // IOC = IE FPSCR |= (mxcsr & 0b0000000000001); // IOC = IE
FPSCR |= (guest_MXCSR & 0b0000000111100) >> 1; // IXC, UFC, OFC, DZC = PE, UE, OE, ZE FPSCR |= (mxcsr & 0b0000000111100) >> 1; // IXC, UFC, OFC, DZC = PE, UE, OE, ZE
FPSCR |= fpsr_exc; FPSCR |= fpsr_exc;
return FPSCR; return FPSCR;
@ -182,10 +183,9 @@ void A32JitState::SetFpscr(u32 FPSCR) {
upper_location_descriptor |= FPSCR & FPSCR_MODE_MASK; upper_location_descriptor |= FPSCR & FPSCR_MODE_MASK;
fpsr_nzcv = FPSCR & FPSCR_NZCV_MASK; fpsr_nzcv = FPSCR & FPSCR_NZCV_MASK;
guest_MXCSR = 0;
// Exception masks / enables guest_MXCSR = 0x00001f80;
guest_MXCSR |= 0x00001f80; // mask all asimd_MXCSR = 0x00001f80;
// RMode // RMode
const std::array<u32, 4> MXCSR_RMode {0x0, 0x4000, 0x2000, 0x6000}; const std::array<u32, 4> MXCSR_RMode {0x0, 0x4000, 0x2000, 0x6000};

View file

@ -48,6 +48,7 @@ struct A32JitState {
// For internal use (See: BlockOfCode::RunCode) // For internal use (See: BlockOfCode::RunCode)
u32 guest_MXCSR = 0x00001f80; u32 guest_MXCSR = 0x00001f80;
u32 asimd_MXCSR = 0x00001f80;
u32 save_host_MXCSR = 0; u32 save_host_MXCSR = 0;
s64 cycles_to_run = 0; s64 cycles_to_run = 0;
s64 cycles_remaining = 0; s64 cycles_remaining = 0;
@ -83,6 +84,7 @@ struct A32JitState {
cpsr_jaifm = src.cpsr_jaifm; cpsr_jaifm = src.cpsr_jaifm;
ExtReg = src.ExtReg; ExtReg = src.ExtReg;
guest_MXCSR = src.guest_MXCSR; guest_MXCSR = src.guest_MXCSR;
asimd_MXCSR = src.asimd_MXCSR;
fpsr_exc = src.fpsr_exc; fpsr_exc = src.fpsr_exc;
fpsr_qc = src.fpsr_qc; fpsr_qc = src.fpsr_qc;
fpsr_nzcv = src.fpsr_nzcv; fpsr_nzcv = src.fpsr_nzcv;

View file

@ -55,7 +55,9 @@ u32 A64JitState::GetFpcr() const {
void A64JitState::SetFpcr(u32 value) { void A64JitState::SetFpcr(u32 value) {
fpcr = value & FPCR_MASK; fpcr = value & FPCR_MASK;
asimd_MXCSR &= 0x0000003D;
guest_MXCSR &= 0x0000003D; guest_MXCSR &= 0x0000003D;
asimd_MXCSR |= 0x00001f80;
guest_MXCSR |= 0x00001f80; // Mask all exceptions guest_MXCSR |= 0x00001f80; // Mask all exceptions
// RMode // RMode
@ -93,9 +95,10 @@ void A64JitState::SetFpcr(u32 value) {
*/ */
u32 A64JitState::GetFpsr() const { u32 A64JitState::GetFpsr() const {
const u32 mxcsr = guest_MXCSR | asimd_MXCSR;
u32 fpsr = 0; u32 fpsr = 0;
fpsr |= (guest_MXCSR & 0b0000000000001); // IOC = IE fpsr |= (mxcsr & 0b0000000000001); // IOC = IE
fpsr |= (guest_MXCSR & 0b0000000111100) >> 1; // IXC, UFC, OFC, DZC = PE, UE, OE, ZE fpsr |= (mxcsr & 0b0000000111100) >> 1; // IXC, UFC, OFC, DZC = PE, UE, OE, ZE
fpsr |= fpsr_exc; fpsr |= fpsr_exc;
fpsr |= (fpsr_qc == 0 ? 0 : 1) << 27; fpsr |= (fpsr_qc == 0 ? 0 : 1) << 27;
return fpsr; return fpsr;
@ -103,6 +106,7 @@ u32 A64JitState::GetFpsr() const {
void A64JitState::SetFpsr(u32 value) { void A64JitState::SetFpsr(u32 value) {
guest_MXCSR &= ~0x0000003D; guest_MXCSR &= ~0x0000003D;
asimd_MXCSR &= ~0x0000003D;
fpsr_qc = (value >> 27) & 1; fpsr_qc = (value >> 27) & 1;
fpsr_exc = value & 0x9F; fpsr_exc = value & 0x9F;
} }

View file

@ -51,6 +51,7 @@ struct A64JitState {
// For internal use (See: BlockOfCode::RunCode) // For internal use (See: BlockOfCode::RunCode)
u32 guest_MXCSR = 0x00001f80; u32 guest_MXCSR = 0x00001f80;
u32 asimd_MXCSR = 0x00001f80;
u32 save_host_MXCSR = 0; u32 save_host_MXCSR = 0;
s64 cycles_to_run = 0; s64 cycles_to_run = 0;
s64 cycles_remaining = 0; s64 cycles_remaining = 0;

View file

@ -247,6 +247,16 @@ void BlockOfCode::SwitchMxcsrOnExit() {
ldmxcsr(dword[r15 + jsi.offsetof_save_host_MXCSR]); 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() { void BlockOfCode::UpdateTicks() {
cb.AddTicks->EmitCall(*this, [this](RegList param) { cb.AddTicks->EmitCall(*this, [this](RegList param) {
mov(param[0], qword[r15 + jsi.offsetof_cycles_to_run]); mov(param[0], qword[r15 + jsi.offsetof_cycles_to_run]);

View file

@ -59,6 +59,10 @@ public:
void SwitchMxcsrOnEntry(); void SwitchMxcsrOnEntry();
/// Code emitter: Makes saved host MXCSR the current MXCSR /// Code emitter: Makes saved host MXCSR the current MXCSR
void SwitchMxcsrOnExit(); 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 /// Code emitter: Updates cycles remaining my calling cb.AddTicks and cb.GetTicksRemaining
/// @note this clobbers ABI caller-save registers /// @note this clobbers ABI caller-save registers
void UpdateTicks(); void UpdateTicks();

View file

@ -16,6 +16,7 @@ struct JitStateInfo {
, offsetof_cycles_to_run(offsetof(JitStateType, cycles_to_run)) , offsetof_cycles_to_run(offsetof(JitStateType, cycles_to_run))
, offsetof_save_host_MXCSR(offsetof(JitStateType, save_host_MXCSR)) , offsetof_save_host_MXCSR(offsetof(JitStateType, save_host_MXCSR))
, offsetof_guest_MXCSR(offsetof(JitStateType, guest_MXCSR)) , offsetof_guest_MXCSR(offsetof(JitStateType, guest_MXCSR))
, offsetof_asimd_MXCSR(offsetof(JitStateType, asimd_MXCSR))
, offsetof_rsb_ptr(offsetof(JitStateType, rsb_ptr)) , offsetof_rsb_ptr(offsetof(JitStateType, rsb_ptr))
, rsb_ptr_mask(JitStateType::RSBPtrMask) , rsb_ptr_mask(JitStateType::RSBPtrMask)
, offsetof_rsb_location_descriptors(offsetof(JitStateType, rsb_location_descriptors)) , 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_cycles_to_run;
const size_t offsetof_save_host_MXCSR; const size_t offsetof_save_host_MXCSR;
const size_t offsetof_guest_MXCSR; const size_t offsetof_guest_MXCSR;
const size_t offsetof_asimd_MXCSR;
const size_t offsetof_rsb_ptr; const size_t offsetof_rsb_ptr;
const size_t rsb_ptr_mask; const size_t rsb_ptr_mask;
const size_t offsetof_rsb_location_descriptors; const size_t offsetof_rsb_location_descriptors;

View file

@ -180,6 +180,14 @@ public:
return value; return value;
} }
/// Gets the StandardFPSCRValue (A32 ASIMD).
FPCR ASIMDStandardValue() const {
FPCR stdvalue;
stdvalue.AHP(AHP());
stdvalue.FZ16(FZ16());
return stdvalue;
}
private: private:
// Bits 0-7, 13-14, and 27-31 are reserved. // Bits 0-7, 13-14, and 27-31 are reserved.
static constexpr u32 mask = 0x07FF9F00; static constexpr u32 mask = 0x07FF9F00;