Merge pull request #8148 from merryhime/interrupts
dynarmic: Better interrupts
This commit is contained in:
commit
50192eb4ad
7 changed files with 43 additions and 46 deletions
2
externals/dynarmic
vendored
2
externals/dynarmic
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit af2d50288fc537201014c4230bb55ab9018a7438
|
Subproject commit 644172477eaf0d822178cb7e96c62b75caa96573
|
|
@ -171,6 +171,9 @@ public:
|
||||||
/// Prepare core for thread reschedule (if needed to correctly handle state)
|
/// Prepare core for thread reschedule (if needed to correctly handle state)
|
||||||
virtual void PrepareReschedule() = 0;
|
virtual void PrepareReschedule() = 0;
|
||||||
|
|
||||||
|
/// Signal an interrupt and ask the core to halt as soon as possible.
|
||||||
|
virtual void SignalInterrupt() = 0;
|
||||||
|
|
||||||
struct BacktraceEntry {
|
struct BacktraceEntry {
|
||||||
std::string module;
|
std::string module;
|
||||||
u64 address;
|
u64 address;
|
||||||
|
|
|
@ -25,6 +25,9 @@ namespace Core {
|
||||||
|
|
||||||
using namespace Common::Literals;
|
using namespace Common::Literals;
|
||||||
|
|
||||||
|
constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2;
|
||||||
|
constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3;
|
||||||
|
|
||||||
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
|
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
|
||||||
public:
|
public:
|
||||||
explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_)
|
explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_)
|
||||||
|
@ -84,15 +87,13 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallSVC(u32 swi) override {
|
void CallSVC(u32 swi) override {
|
||||||
parent.svc_called = true;
|
|
||||||
parent.svc_swi = swi;
|
parent.svc_swi = swi;
|
||||||
parent.jit->HaltExecution();
|
parent.jit->HaltExecution(svc_call);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddTicks(u64 ticks) override {
|
void AddTicks(u64 ticks) override {
|
||||||
if (parent.uses_wall_clock) {
|
ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
|
// Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
|
||||||
// rough approximation of the amount of executed ticks in the system, it may be thrown off
|
// rough approximation of the amount of executed ticks in the system, it may be thrown off
|
||||||
// if not all cores are doing a similar amount of work. Instead of doing this, we should
|
// if not all cores are doing a similar amount of work. Instead of doing this, we should
|
||||||
|
@ -108,12 +109,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetTicksRemaining() override {
|
u64 GetTicksRemaining() override {
|
||||||
if (parent.uses_wall_clock) {
|
ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
|
||||||
if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) {
|
|
||||||
return minimum_run_cycles;
|
|
||||||
}
|
|
||||||
return 0U;
|
|
||||||
}
|
|
||||||
return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
|
return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,6 +145,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
|
||||||
|
|
||||||
// Timing
|
// Timing
|
||||||
config.wall_clock_cntpct = uses_wall_clock;
|
config.wall_clock_cntpct = uses_wall_clock;
|
||||||
|
config.enable_cycle_counting = !uses_wall_clock;
|
||||||
|
|
||||||
// Code cache size
|
// Code cache size
|
||||||
config.code_cache_size = 512_MiB;
|
config.code_cache_size = 512_MiB;
|
||||||
|
@ -230,13 +228,11 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
|
||||||
|
|
||||||
void ARM_Dynarmic_32::Run() {
|
void ARM_Dynarmic_32::Run() {
|
||||||
while (true) {
|
while (true) {
|
||||||
jit->Run();
|
const auto hr = jit->Run();
|
||||||
if (!svc_called) {
|
if (Has(hr, svc_call)) {
|
||||||
break;
|
Kernel::Svc::Call(system, svc_swi);
|
||||||
}
|
}
|
||||||
svc_called = false;
|
if (Has(hr, break_loop)) {
|
||||||
Kernel::Svc::Call(system, svc_swi);
|
|
||||||
if (shutdown) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -322,8 +318,11 @@ void ARM_Dynarmic_32::LoadContext(const ThreadContext32& ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic_32::PrepareReschedule() {
|
void ARM_Dynarmic_32::PrepareReschedule() {
|
||||||
jit->HaltExecution();
|
jit->HaltExecution(break_loop);
|
||||||
shutdown = true;
|
}
|
||||||
|
|
||||||
|
void ARM_Dynarmic_32::SignalInterrupt() {
|
||||||
|
jit->HaltExecution(break_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic_32::ClearInstructionCache() {
|
void ARM_Dynarmic_32::ClearInstructionCache() {
|
||||||
|
|
|
@ -57,6 +57,7 @@ public:
|
||||||
void LoadContext(const ThreadContext64& ctx) override {}
|
void LoadContext(const ThreadContext64& ctx) override {}
|
||||||
|
|
||||||
void PrepareReschedule() override;
|
void PrepareReschedule() override;
|
||||||
|
void SignalInterrupt() override;
|
||||||
void ClearExclusiveState() override;
|
void ClearExclusiveState() override;
|
||||||
|
|
||||||
void ClearInstructionCache() override;
|
void ClearInstructionCache() override;
|
||||||
|
@ -83,9 +84,6 @@ private:
|
||||||
|
|
||||||
// SVC callback
|
// SVC callback
|
||||||
u32 svc_swi{};
|
u32 svc_swi{};
|
||||||
bool svc_called{};
|
|
||||||
|
|
||||||
bool shutdown{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|
|
@ -26,6 +26,9 @@ namespace Core {
|
||||||
using Vector = Dynarmic::A64::Vector;
|
using Vector = Dynarmic::A64::Vector;
|
||||||
using namespace Common::Literals;
|
using namespace Common::Literals;
|
||||||
|
|
||||||
|
constexpr Dynarmic::HaltReason break_loop = Dynarmic::HaltReason::UserDefined2;
|
||||||
|
constexpr Dynarmic::HaltReason svc_call = Dynarmic::HaltReason::UserDefined3;
|
||||||
|
|
||||||
class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
|
class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
|
||||||
public:
|
public:
|
||||||
explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_)
|
explicit DynarmicCallbacks64(ARM_Dynarmic_64& parent_)
|
||||||
|
@ -106,7 +109,7 @@ public:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
parent.jit->HaltExecution();
|
parent.jit->HaltExecution(Dynarmic::HaltReason::CacheInvalidation);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
|
void ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) override {
|
||||||
|
@ -126,15 +129,12 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallSVC(u32 swi) override {
|
void CallSVC(u32 swi) override {
|
||||||
parent.svc_called = true;
|
|
||||||
parent.svc_swi = swi;
|
parent.svc_swi = swi;
|
||||||
parent.jit->HaltExecution();
|
parent.jit->HaltExecution(svc_call);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddTicks(u64 ticks) override {
|
void AddTicks(u64 ticks) override {
|
||||||
if (parent.uses_wall_clock) {
|
ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
|
// Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
|
||||||
// rough approximation of the amount of executed ticks in the system, it may be thrown off
|
// rough approximation of the amount of executed ticks in the system, it may be thrown off
|
||||||
|
@ -149,12 +149,8 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetTicksRemaining() override {
|
u64 GetTicksRemaining() override {
|
||||||
if (parent.uses_wall_clock) {
|
ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
|
||||||
if (!parent.interrupt_handlers[parent.core_index].IsInterrupted()) {
|
|
||||||
return minimum_run_cycles;
|
|
||||||
}
|
|
||||||
return 0U;
|
|
||||||
}
|
|
||||||
return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
|
return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,6 +206,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
|
||||||
|
|
||||||
// Timing
|
// Timing
|
||||||
config.wall_clock_cntpct = uses_wall_clock;
|
config.wall_clock_cntpct = uses_wall_clock;
|
||||||
|
config.enable_cycle_counting = !uses_wall_clock;
|
||||||
|
|
||||||
// Code cache size
|
// Code cache size
|
||||||
config.code_cache_size = 512_MiB;
|
config.code_cache_size = 512_MiB;
|
||||||
|
@ -292,13 +289,11 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
|
||||||
|
|
||||||
void ARM_Dynarmic_64::Run() {
|
void ARM_Dynarmic_64::Run() {
|
||||||
while (true) {
|
while (true) {
|
||||||
jit->Run();
|
const auto hr = jit->Run();
|
||||||
if (!svc_called) {
|
if (Has(hr, svc_call)) {
|
||||||
break;
|
Kernel::Svc::Call(system, svc_swi);
|
||||||
}
|
}
|
||||||
svc_called = false;
|
if (Has(hr, break_loop)) {
|
||||||
Kernel::Svc::Call(system, svc_swi);
|
|
||||||
if (shutdown) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -389,8 +384,11 @@ void ARM_Dynarmic_64::LoadContext(const ThreadContext64& ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic_64::PrepareReschedule() {
|
void ARM_Dynarmic_64::PrepareReschedule() {
|
||||||
jit->HaltExecution();
|
jit->HaltExecution(break_loop);
|
||||||
shutdown = true;
|
}
|
||||||
|
|
||||||
|
void ARM_Dynarmic_64::SignalInterrupt() {
|
||||||
|
jit->HaltExecution(break_loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic_64::ClearInstructionCache() {
|
void ARM_Dynarmic_64::ClearInstructionCache() {
|
||||||
|
|
|
@ -51,6 +51,7 @@ public:
|
||||||
void LoadContext(const ThreadContext64& ctx) override;
|
void LoadContext(const ThreadContext64& ctx) override;
|
||||||
|
|
||||||
void PrepareReschedule() override;
|
void PrepareReschedule() override;
|
||||||
|
void SignalInterrupt() override;
|
||||||
void ClearExclusiveState() override;
|
void ClearExclusiveState() override;
|
||||||
|
|
||||||
void ClearInstructionCache() override;
|
void ClearInstructionCache() override;
|
||||||
|
@ -77,9 +78,6 @@ private:
|
||||||
|
|
||||||
// SVC callback
|
// SVC callback
|
||||||
u32 svc_swi{};
|
u32 svc_swi{};
|
||||||
bool svc_called{};
|
|
||||||
|
|
||||||
bool shutdown{};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
|
|
@ -58,6 +58,7 @@ bool PhysicalCore::IsInterrupted() const {
|
||||||
void PhysicalCore::Interrupt() {
|
void PhysicalCore::Interrupt() {
|
||||||
guard->lock();
|
guard->lock();
|
||||||
interrupts[core_index].SetInterrupt(true);
|
interrupts[core_index].SetInterrupt(true);
|
||||||
|
arm_interface->SignalInterrupt();
|
||||||
guard->unlock();
|
guard->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue