Merge pull request #447 from lioncash/flag
A64: Implement CFINV, RMIF, AXFlag and XAFlag
This commit is contained in:
commit
bbd5330ad2
10 changed files with 154 additions and 5 deletions
|
@ -177,6 +177,8 @@ add_library(dynarmic
|
|||
frontend/A64/translate/impl/simd_vector_x_indexed_element.cpp
|
||||
frontend/A64/translate/impl/sys_dc.cpp
|
||||
frontend/A64/translate/impl/system.cpp
|
||||
frontend/A64/translate/impl/system_flag_format.cpp
|
||||
frontend/A64/translate/impl/system_flag_manipulation.cpp
|
||||
frontend/A64/translate/translate.cpp
|
||||
frontend/A64/translate/translate.h
|
||||
frontend/A64/types.cpp
|
||||
|
|
|
@ -368,6 +368,21 @@ void A64EmitX64::EmitA64GetCFlag(A64EmitContext& ctx, IR::Inst* inst) {
|
|||
ctx.reg_alloc.DefineValue(inst, result);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64GetNZCVRaw(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
const Xbyak::Reg32 nzcv_raw = ctx.reg_alloc.ScratchGpr().cvt32();
|
||||
|
||||
code.mov(nzcv_raw, dword[r15 + offsetof(A64JitState, CPSR_nzcv)]);
|
||||
ctx.reg_alloc.DefineValue(inst, nzcv_raw);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64SetNZCVRaw(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
const Xbyak::Reg32 nzcv_raw = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
|
||||
|
||||
code.and_(nzcv_raw, 0xF0000000);
|
||||
code.mov(dword[r15 + offsetof(A64JitState, CPSR_nzcv)], nzcv_raw);
|
||||
}
|
||||
|
||||
void A64EmitX64::EmitA64SetNZCV(A64EmitContext& ctx, IR::Inst* inst) {
|
||||
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
|
||||
Xbyak::Reg32 to_store = ctx.reg_alloc.UseScratchGpr(args[0]).cvt32();
|
||||
|
|
|
@ -81,14 +81,14 @@ INST(MSR_reg, "MSR (register)", "11010
|
|||
INST(MRS, "MRS", "110101010011poooNNNNMMMMooottttt")
|
||||
|
||||
// System - Flag manipulation instructions
|
||||
//INST(CFINV, "CFINV", "11010101000000000100000000011111") // ARMv8.4
|
||||
//INST(RMIF, "RMIF", "10111010000iiiiii00001nnnnn0IIII") // ARMv8.4
|
||||
INST(CFINV, "CFINV", "11010101000000000100000000011111") // ARMv8.4
|
||||
INST(RMIF, "RMIF", "10111010000iiiiii00001nnnnn0IIII") // ARMv8.4
|
||||
//INST(SETF8, "SETF8", "0011101000000000000010nnnnn01101") // ARMv8.4
|
||||
//INST(SETF16, "SETF16", "0011101000000000010010nnnnn01101") // ARMv8.4
|
||||
|
||||
// System - Flag format instructions
|
||||
//INST(XAFlag, "XAFlag", "11010101000000000100000000111111") // ARMv8.5
|
||||
//INST(AXFlag, "AXFlag", "11010101000000000100000001011111") // ARMv8.5
|
||||
INST(XAFlag, "XAFlag", "11010101000000000100000000111111") // ARMv8.5
|
||||
INST(AXFlag, "AXFlag", "11010101000000000100000001011111") // ARMv8.5
|
||||
|
||||
// SYS: Data Cache
|
||||
INST(DC_IVAC, "DC IVAC", "110101010000100001110110001ttttt")
|
||||
|
|
|
@ -29,6 +29,14 @@ IR::U1 IREmitter::GetCFlag() {
|
|||
return Inst<IR::U1>(Opcode::A64GetCFlag);
|
||||
}
|
||||
|
||||
IR::U32 IREmitter::GetNZCVRaw() {
|
||||
return Inst<IR::U32>(Opcode::A64GetNZCVRaw);
|
||||
}
|
||||
|
||||
void IREmitter::SetNZCVRaw(IR::U32 value) {
|
||||
Inst(Opcode::A64SetNZCVRaw, value);
|
||||
}
|
||||
|
||||
void IREmitter::SetNZCV(const IR::NZCV& nzcv) {
|
||||
Inst(Opcode::A64SetNZCV, nzcv);
|
||||
}
|
||||
|
|
|
@ -36,6 +36,8 @@ public:
|
|||
|
||||
void SetCheckBit(const IR::U1& value);
|
||||
IR::U1 GetCFlag();
|
||||
IR::U32 GetNZCVRaw();
|
||||
void SetNZCVRaw(IR::U32 value);
|
||||
void SetNZCV(const IR::NZCV& nzcv);
|
||||
void OrQC(const IR::U1& value);
|
||||
|
||||
|
|
47
src/frontend/A64/translate/impl/system_flag_format.cpp
Normal file
47
src/frontend/A64/translate/impl/system_flag_format.cpp
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2019 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 "frontend/A64/translate/impl/impl.h"
|
||||
|
||||
namespace Dynarmic::A64 {
|
||||
|
||||
bool TranslatorVisitor::AXFlag() {
|
||||
const IR::U32 nzcv = ir.GetNZCVRaw();
|
||||
|
||||
const IR::U32 z = ir.And(nzcv, ir.Imm32(0x40000000));
|
||||
const IR::U32 c = ir.And(nzcv, ir.Imm32(0x20000000));
|
||||
const IR::U32 v = ir.And(nzcv, ir.Imm32(0x10000000));
|
||||
|
||||
const IR::U32 new_z = ir.Or(ir.LogicalShiftLeft(v, ir.Imm8(2)), z);
|
||||
const IR::U32 new_c = ir.And(ir.And(c, ir.Not(ir.LogicalShiftLeft(v, ir.Imm8(1)))), ir.Imm32(0x20000000));
|
||||
|
||||
ir.SetNZCVRaw(ir.Or(new_z, new_c));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::XAFlag() {
|
||||
const IR::U32 nzcv = ir.GetNZCVRaw();
|
||||
|
||||
const IR::U32 z = ir.And(nzcv, ir.Imm32(0x40000000));
|
||||
const IR::U32 c = ir.And(nzcv, ir.Imm32(0x20000000));
|
||||
|
||||
const IR::U32 not_z = ir.And(ir.Not(z), ir.Imm32(0x40000000));
|
||||
const IR::U32 not_c = ir.And(ir.Not(c), ir.Imm32(0x20000000));
|
||||
|
||||
const IR::U32 new_n = ir.And(ir.LogicalShiftLeft(not_c, ir.Imm8(2)),
|
||||
ir.LogicalShiftLeft(not_z, ir.Imm8(1)));
|
||||
const IR::U32 new_z = ir.And(z, ir.LogicalShiftLeft(c, ir.Imm8(1)));
|
||||
const IR::U32 new_c = ir.Or(c, ir.LogicalShiftRight(z, ir.Imm8(1)));
|
||||
const IR::U32 new_v = ir.And(ir.LogicalShiftRight(not_c, ir.Imm8(1)),
|
||||
ir.LogicalShiftRight(z, ir.Imm8(2)));
|
||||
|
||||
const IR::U32 result = ir.Or(ir.Or(ir.Or(new_n, new_z), new_c), new_v);
|
||||
|
||||
ir.SetNZCVRaw(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::A64
|
63
src/frontend/A64/translate/impl/system_flag_manipulation.cpp
Normal file
63
src/frontend/A64/translate/impl/system_flag_manipulation.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2019 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 "frontend/A64/translate/impl/impl.h"
|
||||
|
||||
namespace Dynarmic::A64 {
|
||||
|
||||
bool TranslatorVisitor::CFINV() {
|
||||
const IR::U32 nzcv = ir.GetNZCVRaw();
|
||||
const IR::U32 result = ir.Eor(nzcv, ir.Imm32(0x20000000));
|
||||
|
||||
ir.SetNZCVRaw(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TranslatorVisitor::RMIF(Imm<6> lsb, Reg Rn, Imm<4> mask) {
|
||||
const u32 mask_value = mask.ZeroExtend();
|
||||
|
||||
// If no bits are to be moved into the NZCV bits, then we
|
||||
// just preserve the bits and do no extra work.
|
||||
if (mask_value == 0) {
|
||||
ir.SetNZCVRaw(ir.GetNZCVRaw());
|
||||
return true;
|
||||
}
|
||||
|
||||
const IR::U64 tmp_reg = ir.GetX(Rn);
|
||||
const IR::U64 rotated = ir.RotateRight(tmp_reg, ir.Imm8(lsb.ZeroExtend<u8>()));
|
||||
const IR::U32 shifted = ir.LeastSignificantWord(ir.LogicalShiftLeft(rotated, ir.Imm8(28)));
|
||||
|
||||
// On the other hand, if all mask bits are set, then we move all four
|
||||
// relevant bits in the source register to the NZCV bits.
|
||||
if (mask_value == 0b1111) {
|
||||
ir.SetNZCVRaw(shifted);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Determine which bits from the PSTATE will be preserved during the operation.
|
||||
u32 preservation_mask = 0;
|
||||
if ((mask_value & 0b1000) == 0) {
|
||||
preservation_mask |= 1U << 31;
|
||||
}
|
||||
if ((mask_value & 0b0100) == 0) {
|
||||
preservation_mask |= 1U << 30;
|
||||
}
|
||||
if ((mask_value & 0b0010) == 0) {
|
||||
preservation_mask |= 1U << 29;
|
||||
}
|
||||
if ((mask_value & 0b0001) == 0) {
|
||||
preservation_mask |= 1U << 28;
|
||||
}
|
||||
|
||||
const IR::U32 masked = ir.And(shifted, ir.Imm32(~preservation_mask));
|
||||
const IR::U32 nzcv = ir.And(ir.GetNZCVRaw(), ir.Imm32(preservation_mask));
|
||||
const IR::U32 result = ir.Or(nzcv, masked);
|
||||
|
||||
ir.SetNZCVRaw(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::A64
|
|
@ -124,6 +124,7 @@ bool Inst::ReadsFromCPSR() const {
|
|||
case Opcode::A32GetVFlag:
|
||||
case Opcode::A32GetGEFlags:
|
||||
case Opcode::A64GetCFlag:
|
||||
case Opcode::A64GetNZCVRaw:
|
||||
case Opcode::ConditionalSelect32:
|
||||
case Opcode::ConditionalSelect64:
|
||||
case Opcode::ConditionalSelectNZCV:
|
||||
|
@ -146,6 +147,7 @@ bool Inst::WritesToCPSR() const {
|
|||
case Opcode::A32OrQFlag:
|
||||
case Opcode::A32SetGEFlags:
|
||||
case Opcode::A32SetGEFlagsCompressed:
|
||||
case Opcode::A64SetNZCVRaw:
|
||||
case Opcode::A64SetNZCV:
|
||||
return true;
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ A32OPC(SetFpscrNZCV, Void, NZCV
|
|||
// A64 Context getters/setters
|
||||
A64OPC(SetCheckBit, Void, U1 )
|
||||
A64OPC(GetCFlag, U1, )
|
||||
A64OPC(GetNZCVRaw, U32, )
|
||||
A64OPC(SetNZCVRaw, Void, U32 )
|
||||
A64OPC(SetNZCV, Void, NZCV )
|
||||
A64OPC(GetW, U32, A64Reg )
|
||||
A64OPC(GetX, U64, A64Reg )
|
||||
|
|
|
@ -23,7 +23,7 @@ void A64GetSetElimination(IR::Block& block) {
|
|||
enum class TrackingType {
|
||||
W, X,
|
||||
S, D, Q,
|
||||
SP, NZCV,
|
||||
SP, NZCV, NZCVRaw,
|
||||
};
|
||||
struct RegisterInfo {
|
||||
IR::Value register_value;
|
||||
|
@ -100,6 +100,10 @@ void A64GetSetElimination(IR::Block& block) {
|
|||
do_get(sp_info, inst, TrackingType::SP);
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::A64GetNZCVRaw: {
|
||||
do_get(nzcv_info, inst, TrackingType::NZCVRaw);
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::A64SetW: {
|
||||
const size_t index = A64::RegNumber(inst->GetArg(0).GetA64RegRef());
|
||||
do_set(reg_info.at(index), inst->GetArg(1), inst, TrackingType::W);
|
||||
|
@ -133,6 +137,10 @@ void A64GetSetElimination(IR::Block& block) {
|
|||
do_set(nzcv_info, inst->GetArg(0), inst, TrackingType::NZCV);
|
||||
break;
|
||||
}
|
||||
case IR::Opcode::A64SetNZCVRaw: {
|
||||
do_set(nzcv_info, inst->GetArg(0), inst, TrackingType::NZCVRaw);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
if (inst->ReadsFromCPSR() || inst->WritesToCPSR()) {
|
||||
nzcv_info = {};
|
||||
|
|
Loading…
Reference in a new issue