Merge branch 'master' into feature/savestates-2

This commit is contained in:
Hamish Milne 2020-03-07 21:23:08 +00:00
commit da3ab3d56e
80 changed files with 7297 additions and 2608 deletions

View file

@ -5,6 +5,7 @@
#include <fstream>
#include <memory>
#include <stdexcept>
#include <utility>
#include <boost/serialization/array.hpp>
#include "audio_core/dsp_interface.h"
@ -65,7 +66,8 @@ System::~System() = default;
System::ResultStatus System::RunLoop(bool tight_loop) {
status = ResultStatus::Success;
if (!cpu_core) {
if (std::any_of(cpu_cores.begin(), cpu_cores.end(),
[](std::shared_ptr<ARM_Interface> ptr) { return ptr == nullptr; })) {
return ResultStatus::ErrorNotInitialized;
}
@ -83,22 +85,73 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
}
}
// If we don't have a currently active thread then don't execute instructions,
// instead advance to the next event and try to yield to the next thread
if (kernel->GetThreadManager().GetCurrentThread() == nullptr) {
LOG_TRACE(Core_ARM11, "Idling");
timing->Idle();
timing->Advance();
PrepareReschedule();
} else {
timing->Advance();
if (tight_loop) {
cpu_core->Run();
} else {
cpu_core->Step();
// All cores should have executed the same amount of ticks. If this is not the case an event was
// scheduled with a cycles_into_future smaller then the current downcount.
// So we have to get those cores to the same global time first
u64 global_ticks = timing->GetGlobalTicks();
s64 max_delay = 0;
std::shared_ptr<ARM_Interface> current_core_to_execute = nullptr;
for (auto& cpu_core : cpu_cores) {
if (cpu_core->GetTimer()->GetTicks() < global_ticks) {
s64 delay = global_ticks - cpu_core->GetTimer()->GetTicks();
cpu_core->GetTimer()->Advance(delay);
if (max_delay < delay) {
max_delay = delay;
current_core_to_execute = cpu_core;
}
}
}
if (max_delay > 0) {
LOG_TRACE(Core_ARM11, "Core {} running (delayed) for {} ticks",
current_core_to_execute->GetID(),
current_core_to_execute->GetTimer()->GetDowncount());
running_core = current_core_to_execute.get();
kernel->SetRunningCPU(current_core_to_execute);
if (kernel->GetCurrentThreadManager().GetCurrentThread() == nullptr) {
LOG_TRACE(Core_ARM11, "Core {} idling", current_core_to_execute->GetID());
current_core_to_execute->GetTimer()->Idle();
PrepareReschedule();
} else {
if (tight_loop) {
current_core_to_execute->Run();
} else {
current_core_to_execute->Step();
}
}
} else {
// Now all cores are at the same global time. So we will run them one after the other
// with a max slice that is the minimum of all max slices of all cores
// TODO: Make special check for idle since we can easily revert the time of idle cores
s64 max_slice = Timing::MAX_SLICE_LENGTH;
for (const auto& cpu_core : cpu_cores) {
max_slice = std::min(max_slice, cpu_core->GetTimer()->GetMaxSliceLength());
}
for (auto& cpu_core : cpu_cores) {
cpu_core->GetTimer()->Advance(max_slice);
}
for (auto& cpu_core : cpu_cores) {
LOG_TRACE(Core_ARM11, "Core {} running for {} ticks", cpu_core->GetID(),
cpu_core->GetTimer()->GetDowncount());
running_core = cpu_core.get();
kernel->SetRunningCPU(cpu_core);
// If we don't have a currently active thread then don't execute instructions,
// instead advance to the next event and try to yield to the next thread
if (kernel->GetCurrentThreadManager().GetCurrentThread() == nullptr) {
LOG_TRACE(Core_ARM11, "Core {} idling", cpu_core->GetID());
cpu_core->GetTimer()->Idle();
PrepareReschedule();
} else {
if (tight_loop) {
cpu_core->Run();
} else {
cpu_core->Step();
}
}
}
timing->AddToGlobalTicks(max_slice);
}
if (GDBStub::IsServerEnabled()) {
GDBStub::SetCpuStepFlag(false);
}
@ -183,7 +236,9 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
}
ASSERT(system_mode.first);
ResultStatus init_result{Init(emu_window, *system_mode.first)};
auto n3ds_mode = app_loader->LoadKernelN3dsMode();
ASSERT(n3ds_mode.first);
ResultStatus init_result{Init(emu_window, *system_mode.first, *n3ds_mode.first)};
if (init_result != ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<u32>(init_result));
@ -235,7 +290,7 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
}
void System::PrepareReschedule() {
cpu_core->PrepareReschedule();
running_core->PrepareReschedule();
reschedule_pending = true;
}
@ -249,31 +304,50 @@ void System::Reschedule() {
}
reschedule_pending = false;
kernel->GetThreadManager().Reschedule();
for (const auto& core : cpu_cores) {
LOG_TRACE(Core_ARM11, "Reschedule core {}", core->GetID());
kernel->GetThreadManager(core->GetID()).Reschedule();
}
}
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mode) {
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mode, u8 n3ds_mode) {
LOG_DEBUG(HW_Memory, "initialized OK");
std::size_t num_cores = 2;
if (Settings::values.is_new_3ds) {
num_cores = 4;
}
memory = std::make_unique<Memory::MemorySystem>();
timing = std::make_unique<Timing>();
timing = std::make_unique<Timing>(num_cores);
kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing,
[this] { PrepareReschedule(); }, system_mode);
kernel = std::make_unique<Kernel::KernelSystem>(
*memory, *timing, [this] { PrepareReschedule(); }, system_mode, num_cores, n3ds_mode);
if (Settings::values.use_cpu_jit) {
#ifdef ARCHITECTURE_x86_64
cpu_core = std::make_shared<ARM_Dynarmic>(this, *memory, USER32MODE);
for (std::size_t i = 0; i < num_cores; ++i) {
cpu_cores.push_back(
std::make_shared<ARM_Dynarmic>(this, *memory, USER32MODE, i, timing->GetTimer(i)));
}
#else
cpu_core = std::make_shared<ARM_DynCom>(this, *memory, USER32MODE);
for (std::size_t i = 0; i < num_cores; ++i) {
cpu_cores.push_back(
std::make_shared<ARM_DynCom>(this, *memory, USER32MODE, i, timing->GetTimer(i)));
}
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#endif
} else {
cpu_core = std::make_shared<ARM_DynCom>(this, *memory, USER32MODE);
for (std::size_t i = 0; i < num_cores; ++i) {
cpu_cores.push_back(
std::make_shared<ARM_DynCom>(this, *memory, USER32MODE, i, timing->GetTimer(i)));
}
}
running_core = cpu_cores[0].get();
kernel->SetCPU(cpu_core);
kernel->SetCPUs(cpu_cores);
kernel->SetRunningCPU(cpu_cores[0]);
if (Settings::values.enable_dsp_lle) {
dsp_core = std::make_unique<AudioCore::DspLle>(*memory,
@ -296,7 +370,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
HW::Init(*memory);
Service::Init(*this);
GDBStub::Init();
GDBStub::DeferStart();
VideoCore::ResultStatus result = VideoCore::Init(emu_window, *memory);
if (result != VideoCore::ResultStatus::Success) {
@ -318,6 +392,8 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
LOG_DEBUG(Core, "Initialized OK");
initalized = true;
return ResultStatus::Success;
}
@ -421,9 +497,10 @@ void System::Shutdown() {
perf_stats.reset();
rpc_server.reset();
cheat_engine.reset();
archive_manager.reset();
service_manager.reset();
dsp_core.reset();
cpu_core.reset();
cpu_cores.clear();
kernel.reset();
timing.reset();
app_loader.reset();
@ -452,11 +529,18 @@ void System::Reset() {
template <class Archive>
void System::serialize(Archive& ar, const unsigned int file_version) {
u32 num_cores;
ar& num_cores;
if (num_cores != this->GetNumCores()) {
throw std::runtime_error("Wrong N3DS mode");
}
// flush on save, don't flush on load
bool should_flush = !Archive::is_loading::value;
Memory::RasterizerClearAll(should_flush);
ar&* timing.get();
ar&* cpu_core.get();
for (int i = 0; i < num_cores; i++) {
ar&* cpu_cores[i].get();
}
ar&* service_manager.get();
ar& GPU::g_regs;
ar& LCD::g_regs;