Implement VMRS and VMSR
This commit is contained in:
parent
814348371e
commit
dca3b2f079
9 changed files with 122 additions and 2 deletions
|
@ -327,6 +327,50 @@ void EmitX64::EmitCallSupervisor(IR::Block&, IR::Inst* inst) {
|
||||||
code->SwitchMxcsrOnEntry();
|
code->SwitchMxcsrOnEntry();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static u32 GetFpscrImpl(JitState* jit_state) {
|
||||||
|
return jit_state->Fpscr();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitGetFpscr(IR::Block&, IR::Inst* inst) {
|
||||||
|
reg_alloc.HostCall(inst);
|
||||||
|
code->mov(code->ABI_PARAM1, code->r15);
|
||||||
|
|
||||||
|
code->SwitchMxcsrOnExit();
|
||||||
|
code->CallFunction(reinterpret_cast<void*>(&GetFpscrImpl));
|
||||||
|
code->SwitchMxcsrOnEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetFpscrImpl(u32 value, JitState* jit_state) {
|
||||||
|
jit_state->SetFpscr(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitSetFpscr(IR::Block&, IR::Inst* inst) {
|
||||||
|
auto a = inst->GetArg(0);
|
||||||
|
|
||||||
|
reg_alloc.HostCall(nullptr, a);
|
||||||
|
code->mov(code->ABI_PARAM2, code->r15);
|
||||||
|
|
||||||
|
code->SwitchMxcsrOnExit();
|
||||||
|
code->CallFunction(reinterpret_cast<void*>(&SetFpscrImpl));
|
||||||
|
code->SwitchMxcsrOnEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitGetFpscrNZCV(IR::Block&, IR::Inst* inst) {
|
||||||
|
using namespace Xbyak::util;
|
||||||
|
|
||||||
|
Xbyak::Reg32 result = reg_alloc.DefGpr(inst).cvt32();
|
||||||
|
|
||||||
|
code->mov(result, dword[r15 + offsetof(JitState, guest_FPSCR_nzcv)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitX64::EmitSetFpscrNZCV(IR::Block&, IR::Inst* inst) {
|
||||||
|
using namespace Xbyak::util;
|
||||||
|
|
||||||
|
Xbyak::Reg32 value = reg_alloc.UseGpr(inst->GetArg(0)).cvt32();
|
||||||
|
|
||||||
|
code->mov(dword[r15 + offsetof(JitState, guest_FPSCR_nzcv)], value);
|
||||||
|
}
|
||||||
|
|
||||||
void EmitX64::EmitPushRSB(IR::Block&, IR::Inst* inst) {
|
void EmitX64::EmitPushRSB(IR::Block&, IR::Inst* inst) {
|
||||||
using namespace Xbyak::util;
|
using namespace Xbyak::util;
|
||||||
|
|
||||||
|
|
|
@ -96,6 +96,10 @@ boost::optional<const VFP2Matcher<V>&> DecodeVFP2(u32 instruction) {
|
||||||
// VCMP
|
// VCMP
|
||||||
// VCMPE
|
// VCMPE
|
||||||
|
|
||||||
|
// Floating-point system register access
|
||||||
|
INST(&V::vfp2_VMSR, "VMSR", "cccc111011100001tttt101000010000"),
|
||||||
|
INST(&V::vfp2_VMRS, "VMRS", "cccc111011110001tttt101000010000"),
|
||||||
|
|
||||||
// Extension register load-store instructions
|
// Extension register load-store instructions
|
||||||
INST(&V::vfp2_VPUSH, "VPUSH", "cccc11010D101101dddd101zvvvvvvvv"),
|
INST(&V::vfp2_VPUSH, "VPUSH", "cccc11010D101101dddd101zvvvvvvvv"),
|
||||||
INST(&V::vfp2_VPOP, "VPOP", "cccc11001D111101dddd101zvvvvvvvv"),
|
INST(&V::vfp2_VPOP, "VPOP", "cccc11001D111101dddd101zvvvvvvvv"),
|
||||||
|
|
|
@ -889,6 +889,17 @@ public:
|
||||||
return fmt::format("vcvt{}{}.s32.{} {}, {}", round_towards_zero ? "" : "r", CondToString(cond), sz ? "f64" : "f32", FPRegStr(false, Vd, D), FPRegStr(sz, Vm, M));
|
return fmt::format("vcvt{}{}.s32.{} {}, {}", round_towards_zero ? "" : "r", CondToString(cond), sz ? "f64" : "f32", FPRegStr(false, Vd, D), FPRegStr(sz, Vm, M));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string vfp2_VMSR(Cond cond, Reg t) {
|
||||||
|
return fmt::format("vmsr{} fpscr, {}", CondToString(cond), RegToString(t));
|
||||||
|
}
|
||||||
|
std::string vfp2_VMRS(Cond cond, Reg t) {
|
||||||
|
if (t == Reg::R15) {
|
||||||
|
return fmt::format("vmrs{} apsr_nzcv, fpscr", CondToString(cond));
|
||||||
|
} else {
|
||||||
|
return fmt::format("vmrs{} {}, fpscr", CondToString(cond), RegToString(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string vfp2_VPOP(Cond cond, bool D, size_t Vd, bool sz, Imm8 imm8) {
|
std::string vfp2_VPOP(Cond cond, bool D, size_t Vd, bool sz, Imm8 imm8) {
|
||||||
return fmt::format("vpop{} {}(+{})", CondToString(cond), FPRegStr(sz, Vd, D), imm8 >> (sz ? 1 : 0));
|
return fmt::format("vpop{} {}(+{})", CondToString(cond), FPRegStr(sz, Vd, D), imm8 >> (sz ? 1 : 0));
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,8 +134,23 @@ void IREmitter::OrQFlag(const Value& value) {
|
||||||
Inst(Opcode::OrQFlag, {value});
|
Inst(Opcode::OrQFlag, {value});
|
||||||
}
|
}
|
||||||
|
|
||||||
Value IREmitter::Pack2x32To1x64(const Value& lo, const Value& hi)
|
Value IREmitter::GetFpscr() {
|
||||||
{
|
return Inst(Opcode::GetFpscr, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void IREmitter::SetFpscr(const Value& new_fpscr) {
|
||||||
|
Inst(Opcode::SetFpscr, {new_fpscr});
|
||||||
|
}
|
||||||
|
|
||||||
|
Value IREmitter::GetFpscrNZCV() {
|
||||||
|
return Inst(Opcode::GetFpscrNZCV, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
void IREmitter::SetFpscrNZCV(const Value& new_fpscr_nzcv) {
|
||||||
|
Inst(Opcode::SetFpscrNZCV, {new_fpscr_nzcv});
|
||||||
|
}
|
||||||
|
|
||||||
|
Value IREmitter::Pack2x32To1x64(const Value& lo, const Value& hi) {
|
||||||
return Inst(Opcode::Pack2x32To1x64, {lo, hi});
|
return Inst(Opcode::Pack2x32To1x64, {lo, hi});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,11 @@ public:
|
||||||
void SetVFlag(const Value& value);
|
void SetVFlag(const Value& value);
|
||||||
void OrQFlag(const Value& value);
|
void OrQFlag(const Value& value);
|
||||||
|
|
||||||
|
Value GetFpscr();
|
||||||
|
void SetFpscr(const Value& new_fpscr);
|
||||||
|
Value GetFpscrNZCV();
|
||||||
|
void SetFpscrNZCV(const Value& new_fpscr_nzcv);
|
||||||
|
|
||||||
Value Pack2x32To1x64(const Value& lo, const Value& hi);
|
Value Pack2x32To1x64(const Value& lo, const Value& hi);
|
||||||
Value LeastSignificantWord(const Value& value);
|
Value LeastSignificantWord(const Value& value);
|
||||||
ResultAndCarry MostSignificantWord(const Value& value);
|
ResultAndCarry MostSignificantWord(const Value& value);
|
||||||
|
|
|
@ -148,6 +148,8 @@ bool Inst::WritesToCoreRegister() const {
|
||||||
|
|
||||||
bool Inst::ReadsFromFPSCR() const {
|
bool Inst::ReadsFromFPSCR() const {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
case Opcode::GetFpscr:
|
||||||
|
case Opcode::GetFpscrNZCV:
|
||||||
case Opcode::FPAbs32:
|
case Opcode::FPAbs32:
|
||||||
case Opcode::FPAbs64:
|
case Opcode::FPAbs64:
|
||||||
case Opcode::FPAdd32:
|
case Opcode::FPAdd32:
|
||||||
|
@ -171,6 +173,8 @@ bool Inst::ReadsFromFPSCR() const {
|
||||||
|
|
||||||
bool Inst::WritesToFPSCR() const {
|
bool Inst::WritesToFPSCR() const {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
case Opcode::SetFpscr:
|
||||||
|
case Opcode::SetFpscrNZCV:
|
||||||
case Opcode::FPAbs32:
|
case Opcode::FPAbs32:
|
||||||
case Opcode::FPAbs64:
|
case Opcode::FPAbs64:
|
||||||
case Opcode::FPAdd32:
|
case Opcode::FPAdd32:
|
||||||
|
|
|
@ -23,6 +23,10 @@ OPCODE(SetVFlag, T::Void, T::U1
|
||||||
OPCODE(OrQFlag, T::Void, T::U1 )
|
OPCODE(OrQFlag, T::Void, T::U1 )
|
||||||
OPCODE(BXWritePC, T::Void, T::U32 )
|
OPCODE(BXWritePC, T::Void, T::U32 )
|
||||||
OPCODE(CallSupervisor, T::Void, T::U32 )
|
OPCODE(CallSupervisor, T::Void, T::U32 )
|
||||||
|
OPCODE(GetFpscr, T::U32, )
|
||||||
|
OPCODE(SetFpscr, T::Void, T::U32, )
|
||||||
|
OPCODE(GetFpscrNZCV, T::U32, )
|
||||||
|
OPCODE(SetFpscrNZCV, T::Void, T::U32, )
|
||||||
|
|
||||||
// Hints
|
// Hints
|
||||||
OPCODE(PushRSB, T::Void, T::U64 )
|
OPCODE(PushRSB, T::Void, T::U64 )
|
||||||
|
|
|
@ -364,6 +364,10 @@ struct ArmTranslatorVisitor final {
|
||||||
bool vfp2_VCVT_to_u32(Cond cond, bool D, size_t Vd, bool sz, bool round_towards_zero, bool M, size_t Vm);
|
bool vfp2_VCVT_to_u32(Cond cond, bool D, size_t Vd, bool sz, bool round_towards_zero, bool M, size_t Vm);
|
||||||
bool vfp2_VCVT_to_s32(Cond cond, bool D, size_t Vd, bool sz, bool round_towards_zero, bool M, size_t Vm);
|
bool vfp2_VCVT_to_s32(Cond cond, bool D, size_t Vd, bool sz, bool round_towards_zero, bool M, size_t Vm);
|
||||||
|
|
||||||
|
// Floating-point system register access
|
||||||
|
bool vfp2_VMSR(Cond cond, Reg t);
|
||||||
|
bool vfp2_VMRS(Cond cond, Reg t);
|
||||||
|
|
||||||
// Floating-point load-store instructions
|
// Floating-point load-store instructions
|
||||||
bool vfp2_VLDR(Cond cond, bool U, bool D, Reg n, size_t Vd, bool sz, Imm8 imm8);
|
bool vfp2_VLDR(Cond cond, bool U, bool D, Reg n, size_t Vd, bool sz, Imm8 imm8);
|
||||||
bool vfp2_VSTR(Cond cond, bool U, bool D, Reg n, size_t Vd, bool sz, Imm8 imm8);
|
bool vfp2_VSTR(Cond cond, bool U, bool D, Reg n, size_t Vd, bool sz, Imm8 imm8);
|
||||||
|
|
|
@ -425,6 +425,35 @@ bool ArmTranslatorVisitor::vfp2_VCVT_to_s32(Cond cond, bool D, size_t Vd, bool s
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ArmTranslatorVisitor::vfp2_VMSR(Cond cond, Reg t) {
|
||||||
|
if (t == Reg::PC)
|
||||||
|
return UnpredictableInstruction();
|
||||||
|
|
||||||
|
// VMSR FPSCR, <Rt>
|
||||||
|
if (ConditionPassed(cond)) {
|
||||||
|
ir.PushRSB(ir.current_location.AdvancePC(4)); // TODO: Replace this with a local cache.
|
||||||
|
ir.SetFpscr(ir.GetRegister(t));
|
||||||
|
ir.BranchWritePC(ir.Imm32(ir.current_location.PC() + 4));
|
||||||
|
ir.SetTerm(IR::Term::PopRSBHint{});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ArmTranslatorVisitor::vfp2_VMRS(Cond cond, Reg t) {
|
||||||
|
// VMRS <Rt>, FPSCR
|
||||||
|
if (ConditionPassed(cond)) {
|
||||||
|
if (t == Reg::R15) {
|
||||||
|
// This encodes ASPR_nzcv access
|
||||||
|
auto nzcv = ir.GetFpscrNZCV();
|
||||||
|
auto old_cpsr = ir.And(ir.GetCpsr(), ir.Imm32(0x0FFFFFFF));
|
||||||
|
ir.SetCpsr(ir.Or(nzcv, old_cpsr));
|
||||||
|
} else {
|
||||||
|
ir.SetRegister(t, ir.GetFpscr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool ArmTranslatorVisitor::vfp2_VPOP(Cond cond, bool D, size_t Vd, bool sz, Imm8 imm8) {
|
bool ArmTranslatorVisitor::vfp2_VPOP(Cond cond, bool D, size_t Vd, bool sz, Imm8 imm8) {
|
||||||
const ExtReg d = ToExtReg(sz, Vd, D);
|
const ExtReg d = ToExtReg(sz, Vd, D);
|
||||||
|
|
Loading…
Reference in a new issue