A64: Implement system register CNTPCT_EL0
This commit is contained in:
parent
1e15283d00
commit
9e4e4e9c1d
8 changed files with 29 additions and 2 deletions
|
@ -92,6 +92,8 @@ struct UserCallbacks {
|
||||||
virtual void AddTicks(std::uint64_t ticks) = 0;
|
virtual void AddTicks(std::uint64_t ticks) = 0;
|
||||||
// How many more ticks am I allowed to execute?
|
// How many more ticks am I allowed to execute?
|
||||||
virtual std::uint64_t GetTicksRemaining() = 0;
|
virtual std::uint64_t GetTicksRemaining() = 0;
|
||||||
|
// Get value in the emulated counter-timer physical count register.
|
||||||
|
virtual std::uint64_t GetCNTPCT() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct UserConfig {
|
struct UserConfig {
|
||||||
|
|
|
@ -472,6 +472,11 @@ void A64EmitX64::EmitA64DataMemoryBarrier(A64EmitContext&, IR::Inst*) {
|
||||||
code.lfence();
|
code.lfence();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void A64EmitX64::EmitA64GetCNTPCT(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
ctx.reg_alloc.HostCall(inst);
|
||||||
|
DEVIRT(conf.callbacks, &A64::UserCallbacks::GetCNTPCT).EmitCall(code);
|
||||||
|
}
|
||||||
|
|
||||||
void A64EmitX64::EmitA64GetCTR(A64EmitContext& ctx, IR::Inst* inst) {
|
void A64EmitX64::EmitA64GetCTR(A64EmitContext& ctx, IR::Inst* inst) {
|
||||||
Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32();
|
Xbyak::Reg32 result = ctx.reg_alloc.ScratchGpr().cvt32();
|
||||||
code.mov(result, conf.ctr_el0);
|
code.mov(result, conf.ctr_el0);
|
||||||
|
|
|
@ -53,6 +53,10 @@ void IREmitter::DataMemoryBarrier() {
|
||||||
Inst(Opcode::A64DataMemoryBarrier);
|
Inst(Opcode::A64DataMemoryBarrier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IR::U64 IREmitter::GetCNTPCT() {
|
||||||
|
return Inst<IR::U64>(Opcode::A64GetCNTPCT);
|
||||||
|
}
|
||||||
|
|
||||||
IR::U32 IREmitter::GetCTR() {
|
IR::U32 IREmitter::GetCTR() {
|
||||||
return Inst<IR::U32>(Opcode::A64GetCTR);
|
return Inst<IR::U32>(Opcode::A64GetCTR);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ 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::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 GetTPIDRRO();
|
IR::U64 GetTPIDRRO();
|
||||||
|
|
|
@ -63,6 +63,9 @@ bool TranslatorVisitor::MRS(Imm<1> o0, Imm<3> op1, Imm<4> CRn, Imm<4> CRm, Imm<3
|
||||||
case 0b11'011'0000'0000'001: // CTR_EL0
|
case 0b11'011'0000'0000'001: // CTR_EL0
|
||||||
X(32, Rt, ir.GetCTR());
|
X(32, Rt, ir.GetCTR());
|
||||||
return true;
|
return true;
|
||||||
|
case 0b11'011'1110'0000'001: // CNTPCT_EL0
|
||||||
|
X(64, Rt, ir.GetCNTPCT());
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return InterpretThisInstruction();
|
return InterpretThisInstruction();
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,7 @@ A64OPC(ExceptionRaised, T::Void, T::U64, 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(GetCNTPCT, T::U64, )
|
||||||
A64OPC(GetCTR, T::U32, )
|
A64OPC(GetCTR, T::U32, )
|
||||||
A64OPC(GetDCZID, T::U32, )
|
A64OPC(GetDCZID, T::U32, )
|
||||||
A64OPC(GetTPIDRRO, T::U64, )
|
A64OPC(GetTPIDRRO, T::U64, )
|
||||||
|
|
|
@ -45,9 +45,17 @@ static bool ShouldTestInst(u32 instruction, u64 pc, bool is_last_inst) {
|
||||||
return false;
|
return false;
|
||||||
if (auto terminal = block.GetTerminal(); boost::get<IR::Term::Interpret>(&terminal))
|
if (auto terminal = block.GetTerminal(); boost::get<IR::Term::Interpret>(&terminal))
|
||||||
return false;
|
return false;
|
||||||
for (const auto& ir_inst : block)
|
for (const auto& ir_inst : block) {
|
||||||
if (ir_inst.GetOpcode() == IR::Opcode::A64ExceptionRaised || ir_inst.GetOpcode() == IR::Opcode::A64CallSupervisor || ir_inst.GetOpcode() == IR::Opcode::A64DataCacheOperationRaised)
|
switch (ir_inst.GetOpcode()) {
|
||||||
|
case IR::Opcode::A64ExceptionRaised:
|
||||||
|
case IR::Opcode::A64CallSupervisor:
|
||||||
|
case IR::Opcode::A64DataCacheOperationRaised:
|
||||||
|
case IR::Opcode::A64GetCNTPCT:
|
||||||
return false;
|
return false;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,4 +92,7 @@ public:
|
||||||
std::uint64_t GetTicksRemaining() override {
|
std::uint64_t GetTicksRemaining() override {
|
||||||
return ticks_left;
|
return ticks_left;
|
||||||
}
|
}
|
||||||
|
std::uint64_t GetCNTPCT() override {
|
||||||
|
ASSERT_MSG(false, "GetCNTPCT()");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue