A64: PSTATE access and tests

This commit is contained in:
MerryMage 2018-01-07 14:46:35 +00:00
parent 23f3afe0b3
commit e8bcf72ee5
6 changed files with 86 additions and 2 deletions

View file

@ -83,6 +83,11 @@ public:
/// Modify FPCR. /// Modify FPCR.
void SetFpcr(std::uint32_t value); void SetFpcr(std::uint32_t value);
/// View PSTATE
std::uint32_t GetPstate() const;
/// Modify PSTATE
void SetPstate(std::uint32_t value);
/** /**
* Returns true if Jit::Run was called but hasn't returned yet. * Returns true if Jit::Run was called but hasn't returned yet.
* i.e.: We're in a callback. * i.e.: We're in a callback.

View file

@ -128,7 +128,8 @@ void A64EmitX64::EmitA64SetNZCV(A64EmitContext& ctx, IR::Inst* inst) {
Xbyak::Reg32 to_store = ctx.reg_alloc.UseGpr(args[0]).cvt32(); Xbyak::Reg32 to_store = ctx.reg_alloc.UseGpr(args[0]).cvt32();
code->and_(to_store, 0b11000001'00000001); code->and_(to_store, 0b11000001'00000001);
code->imul(to_store, to_store, 0b00010000'00100001); code->imul(to_store, to_store, 0b00010000'00100001);
code->and_(to_store, 0xFF000000); code->shl(to_store, 16);
code->and_(to_store, 0xF0000000);
code->mov(dword[r15 + offsetof(A64JitState, CPSR_nzcv)], to_store); code->mov(dword[r15 + offsetof(A64JitState, CPSR_nzcv)], to_store);
} }

View file

@ -125,6 +125,14 @@ public:
jit_state.SetFpcr(value); jit_state.SetFpcr(value);
} }
u32 GetPstate() const {
return jit_state.GetPstate();
}
void SetPstate(u32 value) {
jit_state.SetPstate(value);
}
bool IsExecuting() const { bool IsExecuting() const {
return is_executing; return is_executing;
} }
@ -257,6 +265,14 @@ void Jit::SetFpcr(u32 value) {
impl->SetFpcr(value); impl->SetFpcr(value);
} }
u32 Jit::GetPstate() const {
return impl->GetPstate();
}
void Jit::SetPstate(u32 value) {
impl->SetPstate(value);
}
bool Jit::IsExecuting() const { bool Jit::IsExecuting() const {
return impl->IsExecuting(); return impl->IsExecuting();
} }

View file

@ -33,6 +33,12 @@ struct A64JitState {
u32 CPSR_nzcv = 0; u32 CPSR_nzcv = 0;
u32 FPSCR_nzcv = 0; u32 FPSCR_nzcv = 0;
u32 GetPstate() const {
return CPSR_nzcv;
}
void SetPstate(u32 new_pstate) {
CPSR_nzcv = new_pstate & 0xF0000000;
}
alignas(16) std::array<u64, 64> vec{}; // Extension registers. alignas(16) std::array<u64, 64> vec{}; // Extension registers.

View file

@ -124,6 +124,7 @@ bool Inst::WritesToCPSR() const {
case Opcode::A32OrQFlag: case Opcode::A32OrQFlag:
case Opcode::A32SetGEFlags: case Opcode::A32SetGEFlags:
case Opcode::A32SetGEFlagsCompressed: case Opcode::A32SetGEFlagsCompressed:
case Opcode::A64SetNZCV:
return true; return true;
default: default:
@ -387,7 +388,7 @@ void Inst::Use(const Value& value) {
break; break;
case Opcode::GetNZCVFromOp: case Opcode::GetNZCVFromOp:
ASSERT_MSG(!value.GetInst()->nzcv_inst, "Only one of each type of pseudo-op allowed"); ASSERT_MSG(!value.GetInst()->nzcv_inst, "Only one of each type of pseudo-op allowed");
ASSERT_MSG(MayGetNZCVFromOp(), "This instruction doesn't support the GetNZCVFromOp pseduo-op"); ASSERT_MSG(value.GetInst()->MayGetNZCVFromOp(), "This value doesn't support the GetNZCVFromOp pseduo-op");
value.GetInst()->nzcv_inst = this; value.GetInst()->nzcv_inst = this;
break; break;
default: default:

View file

@ -113,3 +113,58 @@ TEST_CASE("A64: Bitmasks", "[a64]") {
REQUIRE(jit.GetRegister(2) == 1); REQUIRE(jit.GetRegister(2) == 1);
REQUIRE(jit.GetPC() == 12); REQUIRE(jit.GetPC() == 12);
} }
TEST_CASE("A64: ANDS NZCV", "[a64]") {
TestEnv env;
Dynarmic::A64::Jit jit{Dynarmic::A64::UserConfig{&env}};
env.code_mem[0] = 0x6a020020; // ANDS W0, W1, W2
env.code_mem[1] = 0x14000000; // B .
SECTION("N=1, Z=0") {
jit.SetRegister(0, 0);
jit.SetRegister(1, 0xFFFFFFFF);
jit.SetRegister(2, 0xFFFFFFFF);
jit.SetPC(0);
env.ticks_left = 2;
jit.Run();
REQUIRE(jit.GetRegister(0) == 0xFFFFFFFF);
REQUIRE(jit.GetRegister(1) == 0xFFFFFFFF);
REQUIRE(jit.GetRegister(2) == 0xFFFFFFFF);
REQUIRE(jit.GetPC() == 4);
REQUIRE((jit.GetPstate() & 0xF0000000) == 0x80000000);
}
SECTION("N=0, Z=1") {
jit.SetRegister(0, 0);
jit.SetRegister(1, 0xFFFFFFFF);
jit.SetRegister(2, 0x00000000);
jit.SetPC(0);
env.ticks_left = 2;
jit.Run();
REQUIRE(jit.GetRegister(0) == 0x00000000);
REQUIRE(jit.GetRegister(1) == 0xFFFFFFFF);
REQUIRE(jit.GetRegister(2) == 0x00000000);
REQUIRE(jit.GetPC() == 4);
REQUIRE((jit.GetPstate() & 0xF0000000) == 0x40000000);
}
SECTION("N=0, Z=0") {
jit.SetRegister(0, 0);
jit.SetRegister(1, 0x12345678);
jit.SetRegister(2, 0x7324a993);
jit.SetPC(0);
env.ticks_left = 2;
jit.Run();
REQUIRE(jit.GetRegister(0) == 0x12240010);
REQUIRE(jit.GetRegister(1) == 0x12345678);
REQUIRE(jit.GetRegister(2) == 0x7324a993);
REQUIRE(jit.GetPC() == 4);
REQUIRE((jit.GetPstate() & 0xF0000000) == 0x00000000);
}
}