system: Implement MRS CNTFRQ_EL0

This commit is contained in:
MerryMage 2018-08-16 09:58:34 +01:00
parent f91a9f18cd
commit d1d6f4feb5
7 changed files with 50 additions and 26 deletions

View file

@ -120,6 +120,10 @@ struct UserConfig {
/// Executing DC ZVA in this mode will result in zeros being written to memory. /// Executing DC ZVA in this mode will result in zeros being written to memory.
bool hook_data_cache_operations = false; bool hook_data_cache_operations = false;
/// Counter-timer frequency register. The value of the register is not interpreted by
/// dynarmic.
std::uint32_t cntfrq_el0 = 600000000;
/// CTR_EL0<27:24> is log2 of the cache writeback granule in words. /// CTR_EL0<27:24> is log2 of the cache writeback granule in words.
/// CTR_EL0<23:20> is log2 of the exclusives reservation granule in words. /// CTR_EL0<23:20> is log2 of the exclusives reservation granule in words.
/// CTR_EL0<19:16> is log2 of the smallest data/unifed cacheline in words. /// CTR_EL0<19:16> is log2 of the smallest data/unifed cacheline in words.

View file

@ -538,6 +538,12 @@ void A64EmitX64::EmitA64DataMemoryBarrier(A64EmitContext&, IR::Inst*) {
code.lfence(); code.lfence();
} }
void A64EmitX64::EmitA64GetCNTFRQ(A64EmitContext& ctx, IR::Inst* inst) {
Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32();
code.mov(result, conf.cntfrq_el0);
ctx.reg_alloc.DefineValue(inst, result);
}
void A64EmitX64::EmitA64GetCNTPCT(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64GetCNTPCT(A64EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.HostCall(inst); ctx.reg_alloc.HostCall(inst);
code.UpdateTicks(); code.UpdateTicks();
@ -567,16 +573,6 @@ void A64EmitX64::EmitA64GetTPIDR(A64EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.DefineValue(inst, result); ctx.reg_alloc.DefineValue(inst, result);
} }
void A64EmitX64::EmitA64SetTPIDR(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
Xbyak::Reg64 value = ctx.reg_alloc.UseGpr(args[0]);
Xbyak::Reg64 addr = ctx.reg_alloc.ScratchGpr();
if (conf.tpidr_el0) {
code.mov(addr, u64(conf.tpidr_el0));
code.mov(qword[addr], value);
}
}
void A64EmitX64::EmitA64GetTPIDRRO(A64EmitContext& ctx, IR::Inst* inst) { void A64EmitX64::EmitA64GetTPIDRRO(A64EmitContext& ctx, IR::Inst* inst) {
Xbyak::Reg64 result = ctx.reg_alloc.ScratchGpr(); Xbyak::Reg64 result = ctx.reg_alloc.ScratchGpr();
if (conf.tpidrro_el0) { if (conf.tpidrro_el0) {
@ -588,6 +584,16 @@ void A64EmitX64::EmitA64GetTPIDRRO(A64EmitContext& ctx, IR::Inst* inst) {
ctx.reg_alloc.DefineValue(inst, result); ctx.reg_alloc.DefineValue(inst, result);
} }
void A64EmitX64::EmitA64SetTPIDR(A64EmitContext& ctx, IR::Inst* inst) {
auto args = ctx.reg_alloc.GetArgumentInfo(inst);
Xbyak::Reg64 value = ctx.reg_alloc.UseGpr(args[0]);
Xbyak::Reg64 addr = ctx.reg_alloc.ScratchGpr();
if (conf.tpidr_el0) {
code.mov(addr, u64(conf.tpidr_el0));
code.mov(qword[addr], value);
}
}
void A64EmitX64::EmitA64ClearExclusive(A64EmitContext&, IR::Inst*) { void A64EmitX64::EmitA64ClearExclusive(A64EmitContext&, IR::Inst*) {
code.mov(code.byte[r15 + offsetof(A64JitState, exclusive_state)], u8(0)); code.mov(code.byte[r15 + offsetof(A64JitState, exclusive_state)], u8(0));
} }

View file

@ -57,6 +57,10 @@ void IREmitter::DataMemoryBarrier() {
Inst(Opcode::A64DataMemoryBarrier); Inst(Opcode::A64DataMemoryBarrier);
} }
IR::U32 IREmitter::GetCNTFRQ() {
return Inst<IR::U32>(Opcode::A64GetCNTFRQ);
}
IR::U64 IREmitter::GetCNTPCT() { IR::U64 IREmitter::GetCNTPCT() {
return Inst<IR::U64>(Opcode::A64GetCNTPCT); return Inst<IR::U64>(Opcode::A64GetCNTPCT);
} }

View file

@ -45,12 +45,13 @@ public:
void DataCacheOperationRaised(DataCacheOperation op, const IR::U64& value); void DataCacheOperationRaised(DataCacheOperation op, const IR::U64& value);
void DataSynchronizationBarrier(); void DataSynchronizationBarrier();
void DataMemoryBarrier(); void DataMemoryBarrier();
IR::U32 GetCNTFRQ();
IR::U64 GetCNTPCT(); // TODO: Ensure sub-basic-block cycle counts are updated before this. IR::U64 GetCNTPCT(); // TODO: Ensure sub-basic-block cycle counts are updated before this.
IR::U32 GetCTR(); IR::U32 GetCTR();
IR::U32 GetDCZID(); IR::U32 GetDCZID();
IR::U64 GetTPIDR(); IR::U64 GetTPIDR();
void SetTPIDR(const IR::U64& value);
IR::U64 GetTPIDRRO(); IR::U64 GetTPIDRRO();
void SetTPIDR(const IR::U64& value);
void ClearExclusive(); void ClearExclusive();
void SetExclusive(const IR::U64& vaddr, size_t byte_size); void SetExclusive(const IR::U64& vaddr, size_t byte_size);

View file

@ -10,6 +10,8 @@ namespace Dynarmic::A64 {
// Register encodings used by MRS and MSR. // Register encodings used by MRS and MSR.
enum class SystemRegisterEncoding : u32 { enum class SystemRegisterEncoding : u32 {
// Counter-timer Frequency register
CNTFRQ_EL0 = 0b11'011'1110'0000'000,
// Counter-timer Physical Count register // Counter-timer Physical Count register
CNTPCT_EL0 = 0b11'011'1110'0000'001, CNTPCT_EL0 = 0b11'011'1110'0000'001,
// Cache Type Register // Cache Type Register
@ -72,9 +74,6 @@ bool TranslatorVisitor::DMB(Imm<4> /*CRm*/) {
bool TranslatorVisitor::MSR_reg(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) { bool TranslatorVisitor::MSR_reg(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) {
const auto sys_reg = concatenate(Imm<1>{1}, o0, op1, CRn, CRm, op2).ZeroExtend<SystemRegisterEncoding>(); const auto sys_reg = concatenate(Imm<1>{1}, o0, op1, CRn, CRm, op2).ZeroExtend<SystemRegisterEncoding>();
switch (sys_reg) { switch (sys_reg) {
case SystemRegisterEncoding::TPIDR_EL0:
ir.SetTPIDR(X(64, Rt));
return true;
case SystemRegisterEncoding::FPCR: case SystemRegisterEncoding::FPCR:
ir.SetFPCR(X(32, Rt)); ir.SetFPCR(X(32, Rt));
ir.SetPC(ir.Imm64(ir.current_location->PC() + 4)); ir.SetPC(ir.Imm64(ir.current_location->PC() + 4));
@ -83,6 +82,9 @@ bool TranslatorVisitor::MSR_reg(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, I
case SystemRegisterEncoding::FPSR: case SystemRegisterEncoding::FPSR:
ir.SetFPSR(X(32, Rt)); ir.SetFPSR(X(32, Rt));
return true; return true;
case SystemRegisterEncoding::TPIDR_EL0:
ir.SetTPIDR(X(64, Rt));
return true;
default: default:
break; break;
} }
@ -92,17 +94,8 @@ bool TranslatorVisitor::MSR_reg(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, I
bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) { bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3> op2, Reg Rt) {
const auto sys_reg = concatenate(Imm<1>{1}, o0, op1, CRn, CRm, op2).ZeroExtend<SystemRegisterEncoding>(); const auto sys_reg = concatenate(Imm<1>{1}, o0, op1, CRn, CRm, op2).ZeroExtend<SystemRegisterEncoding>();
switch (sys_reg) { switch (sys_reg) {
case SystemRegisterEncoding::TPIDR_EL0: case SystemRegisterEncoding::CNTFRQ_EL0:
X(64, Rt, ir.GetTPIDR()); X(32, Rt, ir.GetCNTFRQ());
return true;
case SystemRegisterEncoding::TPIDRRO_EL0:
X(64, Rt, ir.GetTPIDRRO());
return true;
case SystemRegisterEncoding::DCZID_EL0:
X(32, Rt, ir.GetDCZID());
return true;
case SystemRegisterEncoding::CTR_EL0:
X(32, Rt, ir.GetCTR());
return true; return true;
case SystemRegisterEncoding::CNTPCT_EL0: case SystemRegisterEncoding::CNTPCT_EL0:
// HACK: Ensure that this is the first instruction in the block it's emitted in, so the cycle count is most up-to-date. // HACK: Ensure that this is the first instruction in the block it's emitted in, so the cycle count is most up-to-date.
@ -113,12 +106,25 @@ bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3
} }
X(64, Rt, ir.GetCNTPCT()); X(64, Rt, ir.GetCNTPCT());
return true; return true;
case SystemRegisterEncoding::CTR_EL0:
X(32, Rt, ir.GetCTR());
return true;
case SystemRegisterEncoding::DCZID_EL0:
X(32, Rt, ir.GetDCZID());
return true;
case SystemRegisterEncoding::FPCR: case SystemRegisterEncoding::FPCR:
X(32, Rt, ir.GetFPCR()); X(32, Rt, ir.GetFPCR());
return true; return true;
case SystemRegisterEncoding::FPSR: case SystemRegisterEncoding::FPSR:
X(32, Rt, ir.GetFPSR()); X(32, Rt, ir.GetFPSR());
return true; return true;
case SystemRegisterEncoding::TPIDR_EL0:
X(64, Rt, ir.GetTPIDR());
return true;
case SystemRegisterEncoding::TPIDRRO_EL0:
X(64, Rt, ir.GetTPIDRRO());
return true;
} }
return InterpretThisInstruction(); return InterpretThisInstruction();
} }

View file

@ -66,12 +66,13 @@ A64OPC(ExceptionRaised, T::Void, T::U64,
A64OPC(DataCacheOperationRaised, T::Void, T::U64, T::U64 ) A64OPC(DataCacheOperationRaised, T::Void, T::U64, T::U64 )
A64OPC(DataSynchronizationBarrier, T::Void, ) A64OPC(DataSynchronizationBarrier, T::Void, )
A64OPC(DataMemoryBarrier, T::Void, ) A64OPC(DataMemoryBarrier, T::Void, )
A64OPC(GetCNTFRQ, T::U32, )
A64OPC(GetCNTPCT, T::U64, ) A64OPC(GetCNTPCT, T::U64, )
A64OPC(GetCTR, T::U32, ) A64OPC(GetCTR, T::U32, )
A64OPC(GetDCZID, T::U32, ) A64OPC(GetDCZID, T::U32, )
A64OPC(GetTPIDR, T::U64, ) A64OPC(GetTPIDR, T::U64, )
A64OPC(SetTPIDR, T::Void, T::U64 )
A64OPC(GetTPIDRRO, T::U64, ) A64OPC(GetTPIDRRO, T::U64, )
A64OPC(SetTPIDR, T::Void, T::U64 )
// Hints // Hints
OPCODE(PushRSB, T::Void, T::U64 ) OPCODE(PushRSB, T::Void, T::U64 )

View file

@ -78,6 +78,8 @@ static u32 GenRandomInst(u64 pc, bool is_last_inst) {
"STXR", "STLXR", "STXP", "STLXP", "LDXR", "LDAXR", "LDXP", "LDAXP", "STXR", "STLXR", "STXP", "STLXP", "LDXR", "LDAXR", "LDXP", "LDAXP",
// QEMU's implementation of FDIV is incorrect // QEMU's implementation of FDIV is incorrect
"FDIV_1", "FDIV_2", "FDIV_1", "FDIV_2",
// Behaviour differs from QEMU
"MSR_reg", "MSR_imm", "MRS",
}; };
for (const auto& [fn, bitstring] : list) { for (const auto& [fn, bitstring] : list) {