Implement VMRS and VMSR

This commit is contained in:
MerryMage 2016-08-26 22:47:54 +01:00
parent 814348371e
commit dca3b2f079
9 changed files with 122 additions and 2 deletions

View file

@ -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;

View file

@ -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"),

View file

@ -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));
} }

View file

@ -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});
} }

View file

@ -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);

View file

@ -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:

View file

@ -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 )

View file

@ -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);

View file

@ -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);