diff --git a/src/backend/A64/a32_emit_a64.cpp b/src/backend/A64/a32_emit_a64.cpp index a5a429d6..d1b86191 100644 --- a/src/backend/A64/a32_emit_a64.cpp +++ b/src/backend/A64/a32_emit_a64.cpp @@ -424,7 +424,7 @@ void A32EmitA64::EmitA32SetCpsr(A32EmitContext& ctx, IR::Inst* inst) { code.QuickCallFunction(&SetCpsrImpl); } -void A32EmitA64::EmitA32SetCpsrNZCV(A32EmitContext& ctx, IR::Inst* inst) { +void A32EmitA64::EmitA32SetCpsrNZCVRaw(A32EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); ARM64Reg a = DecodeReg(ctx.reg_alloc.UseScratchGpr(args[0])); @@ -432,6 +432,10 @@ void A32EmitA64::EmitA32SetCpsrNZCV(A32EmitContext& ctx, IR::Inst* inst) { code.STR(INDEX_UNSIGNED, a, X28, offsetof(A32JitState, CPSR_nzcv)); } +void A32EmitA64::EmitA32SetCpsrNZCV(A32EmitContext& ctx, IR::Inst* inst) { + EmitA32SetCpsrNZCVRaw(ctx, inst); +} + void A32EmitA64::EmitA32SetCpsrNZCVQ(A32EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); ARM64Reg host_fpsr = ctx.reg_alloc.ScratchGpr(); diff --git a/src/backend/A64/opcodes.inc b/src/backend/A64/opcodes.inc index cfb262df..8c1c72ca 100644 --- a/src/backend/A64/opcodes.inc +++ b/src/backend/A64/opcodes.inc @@ -14,7 +14,8 @@ A32OPC(SetExtendedRegister32, Void, A32E A32OPC(SetExtendedRegister64, Void, A32ExtReg, U64 ) A32OPC(GetCpsr, U32, ) A32OPC(SetCpsr, Void, U32 ) -A32OPC(SetCpsrNZCV, Void, U32 ) +A32OPC(SetCpsrNZCVRaw, Void, U32 ) +A32OPC(SetCpsrNZCV, Void, NZCV ) A32OPC(SetCpsrNZCVQ, Void, U32 ) A32OPC(GetNFlag, U1, ) A32OPC(SetNFlag, Void, U1 ) diff --git a/src/backend/x64/a32_emit_x64.cpp b/src/backend/x64/a32_emit_x64.cpp index 6548fd00..0b4a318d 100644 --- a/src/backend/x64/a32_emit_x64.cpp +++ b/src/backend/x64/a32_emit_x64.cpp @@ -427,7 +427,7 @@ void A32EmitX64::EmitA32SetCpsr(A32EmitContext& ctx, IR::Inst* inst) { } } -void A32EmitX64::EmitA32SetCpsrNZCV(A32EmitContext& ctx, IR::Inst* inst) { +void A32EmitX64::EmitA32SetCpsrNZCVRaw(A32EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (args[0].IsImmediate()) { const u32 imm = args[0].GetImmediateU32(); @@ -441,6 +441,17 @@ void A32EmitX64::EmitA32SetCpsrNZCV(A32EmitContext& ctx, IR::Inst* inst) { } } +void A32EmitX64::EmitA32SetCpsrNZCV(A32EmitContext& ctx, IR::Inst* inst) { + auto args = ctx.reg_alloc.GetArgumentInfo(inst); + const Xbyak::Reg32 to_store = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32(); + code.and_(to_store, 0b11000001'00000001); + code.imul(to_store, to_store, 0b00010000'00100001); + code.shl(to_store, 16); + code.and_(to_store, 0xF0000000); + code.mov(dword[r15 + offsetof(A32JitState, cpsr_nzcv)], to_store); +} + + void A32EmitX64::EmitA32SetCpsrNZCVQ(A32EmitContext& ctx, IR::Inst* inst) { auto args = ctx.reg_alloc.GetArgumentInfo(inst); if (args[0].IsImmediate()) { diff --git a/src/frontend/A32/ir_emitter.cpp b/src/frontend/A32/ir_emitter.cpp index 8e3f5241..41037720 100644 --- a/src/frontend/A32/ir_emitter.cpp +++ b/src/frontend/A32/ir_emitter.cpp @@ -100,6 +100,10 @@ void IREmitter::SetCpsr(const IR::U32& value) { } void IREmitter::SetCpsrNZCV(const IR::U32& value) { + Inst(Opcode::A32SetCpsrNZCVRaw, value); +} + +void IREmitter::SetCpsrNZCV(const IR::NZCV& value) { Inst(Opcode::A32SetCpsrNZCV, value); } diff --git a/src/frontend/A32/ir_emitter.h b/src/frontend/A32/ir_emitter.h index 4c89c009..6eef8278 100644 --- a/src/frontend/A32/ir_emitter.h +++ b/src/frontend/A32/ir_emitter.h @@ -48,6 +48,7 @@ public: IR::U32 GetCpsr(); void SetCpsr(const IR::U32& value); void SetCpsrNZCV(const IR::U32& value); + void SetCpsrNZCV(const IR::NZCV& value); void SetCpsrNZCVQ(const IR::U32& value); void SetCheckBit(const IR::U1& value); IR::U1 GetCFlag(); diff --git a/src/frontend/ir/microinstruction.cpp b/src/frontend/ir/microinstruction.cpp index e6a9c4ff..64b8fe5c 100644 --- a/src/frontend/ir/microinstruction.cpp +++ b/src/frontend/ir/microinstruction.cpp @@ -153,6 +153,7 @@ bool Inst::ReadsFromCPSR() const { bool Inst::WritesToCPSR() const { switch (op) { case Opcode::A32SetCpsr: + case Opcode::A32SetCpsrNZCVRaw: case Opcode::A32SetCpsrNZCV: case Opcode::A32SetCpsrNZCVQ: case Opcode::A32SetNFlag: diff --git a/src/frontend/ir/opcodes.inc b/src/frontend/ir/opcodes.inc index a2a90a49..2ed8084a 100644 --- a/src/frontend/ir/opcodes.inc +++ b/src/frontend/ir/opcodes.inc @@ -14,7 +14,8 @@ A32OPC(SetExtendedRegister32, Void, A32E A32OPC(SetExtendedRegister64, Void, A32ExtReg, U64 ) A32OPC(GetCpsr, U32, ) A32OPC(SetCpsr, Void, U32 ) -A32OPC(SetCpsrNZCV, Void, U32 ) +A32OPC(SetCpsrNZCVRaw, Void, U32 ) +A32OPC(SetCpsrNZCV, Void, NZCV ) A32OPC(SetCpsrNZCVQ, Void, U32 ) A32OPC(GetNFlag, U1, ) A32OPC(SetNFlag, Void, U1 )