system: Implement MRS CNTFRQ_EL0
This commit is contained in:
parent
f91a9f18cd
commit
d1d6f4feb5
7 changed files with 50 additions and 26 deletions
|
@ -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.
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 )
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue