CPU: Add settings for execution mode

This commit is contained in:
Connor McLaughlin 2019-11-23 20:22:09 +10:00
parent b8de55b9b8
commit 889bd73ac8
8 changed files with 149 additions and 31 deletions

View File

@ -9,8 +9,6 @@ Log_SetChannel(CPU::CodeCache);
namespace CPU {
bool USE_CODE_CACHE = false;
bool USE_RECOMPILER = false;
constexpr bool USE_BLOCK_LINKING = true;
static constexpr size_t RECOMPILER_CODE_CACHE_SIZE = 32 * 1024 * 1024;
@ -20,11 +18,12 @@ CodeCache::CodeCache() = default;
CodeCache::~CodeCache() = default;
void CodeCache::Initialize(System* system, Core* core, Bus* bus)
void CodeCache::Initialize(System* system, Core* core, Bus* bus, bool use_recompiler)
{
m_system = system;
m_core = core;
m_bus = bus;
m_use_recompiler = use_recompiler;
m_code_buffer = std::make_unique<JitCodeBuffer>(RECOMPILER_CODE_CACHE_SIZE, RECOMPILER_FAR_CODE_CACHE_SIZE);
m_asm_functions = std::make_unique<Recompiler::ASMFunctions>();
@ -63,7 +62,7 @@ void CodeCache::Execute()
#endif
reexecute_block:
if (USE_RECOMPILER)
if (m_use_recompiler)
block->host_code(m_core);
else
InterpretCachedBlock(*block);
@ -118,7 +117,16 @@ void CodeCache::Execute()
}
}
void CodeCache::Reset()
void CodeCache::SetUseRecompiler(bool enable)
{
if (m_use_recompiler == enable)
return;
m_use_recompiler = enable;
Flush();
}
void CodeCache::Flush()
{
m_bus->ClearRAMCodePageFlags();
for (auto& it : m_ram_block_map)
@ -285,7 +293,7 @@ bool CodeCache::CompileBlock(CodeBlock* block)
return false;
}
if (USE_RECOMPILER)
if (m_use_recompiler)
{
// Ensure we're not going to run out of space while compiling this block.
if (m_code_buffer->GetFreeCodeSpace() <
@ -294,7 +302,7 @@ bool CodeCache::CompileBlock(CodeBlock* block)
(block->instructions.size() * Recompiler::MAX_FAR_HOST_BYTES_PER_INSTRUCTION))
{
Log_WarningPrintf("Out of code space, flushing all blocks.");
Reset();
Flush();
}
Recompiler::CodeGenerator codegen(m_core, m_code_buffer.get(), *m_asm_functions.get());

View File

@ -24,10 +24,15 @@ public:
CodeCache();
~CodeCache();
void Initialize(System* system, Core* core, Bus* bus);
void Reset();
void Initialize(System* system, Core* core, Bus* bus, bool use_recompiler);
void Execute();
/// Flushes the code cache, forcing all blocks to be recompiled.
void Flush();
/// Changes whether the recompiler is enabled.
void SetUseRecompiler(bool enable);
/// Invalidates all blocks which are in the range of the specified code page.
void InvalidateBlocksWithPageIndex(u32 page_index);
@ -69,10 +74,9 @@ private:
BlockMap m_blocks;
bool m_use_recompiler = false;
std::array<std::vector<CodeBlock*>, CPU_CODE_CACHE_PAGE_COUNT> m_ram_block_map;
};
extern bool USE_CODE_CACHE;
extern bool USE_RECOMPILER;
} // namespace CPU

View File

@ -14,6 +14,7 @@ Settings::Settings() = default;
void Settings::SetDefaults()
{
region = ConsoleRegion::Auto;
cpu_execution_mode = CPUExecutionMode::Interpreter;
audio_sync_enabled = true;
video_sync_enabled = true;
@ -50,6 +51,9 @@ void Settings::Load(const char* filename)
speed_limiter_enabled = ini.GetBoolValue("General", "SpeedLimiterEnabled", true);
start_paused = ini.GetBoolValue("General", "StartPaused", false);
cpu_execution_mode =
ParseCPUExecutionMode(ini.GetValue("CPU", "ExecutionMode", "Interpreter")).value_or(CPUExecutionMode::Interpreter);
gpu_renderer = ParseRendererName(ini.GetValue("GPU", "Renderer", "OpenGL")).value_or(GPURenderer::HardwareOpenGL);
gpu_resolution_scale = static_cast<u32>(ini.GetLongValue("GPU", "ResolutionScale", 1));
gpu_true_color = ini.GetBoolValue("GPU", "TrueColor", false);
@ -79,6 +83,8 @@ bool Settings::Save(const char* filename) const
ini.SetBoolValue("General", "SpeedLimiterEnabled", speed_limiter_enabled);
ini.SetBoolValue("General", "StartPaused", start_paused);
ini.SetValue("CPU", "ExecutionMode", GetCPUExecutionModeName(cpu_execution_mode));
ini.SetValue("GPU", "Renderer", GetRendererName(gpu_renderer));
ini.SetLongValue("GPU", "ResolutionScale", static_cast<long>(gpu_resolution_scale));
ini.SetBoolValue("GPU", "VSync", video_sync_enabled);
@ -138,6 +144,34 @@ const char* Settings::GetConsoleRegionDisplayName(ConsoleRegion region)
return s_console_region_display_names[static_cast<int>(region)];
}
static std::array<const char*, 3> s_cpu_execution_mode_names = {{"Interpreter", "CachedInterpreter", "Recompiler"}};
static std::array<const char*, 3> s_cpu_execution_mode_display_names = {
{"Intepreter (Slowest)", "Cached Interpreter (Faster)", "Recompiler (Fastest)"}};
std::optional<CPUExecutionMode> Settings::ParseCPUExecutionMode(const char* str)
{
u8 index = 0;
for (const char* name : s_cpu_execution_mode_names)
{
if (strcasecmp(name, str) == 0)
return static_cast<CPUExecutionMode>(index);
index++;
}
return std::nullopt;
}
const char* Settings::GetCPUExecutionModeName(CPUExecutionMode mode)
{
return s_cpu_execution_mode_names[static_cast<u8>(mode)];
}
const char* Settings::GetCPUExecutionModeDisplayName(CPUExecutionMode mode)
{
return s_cpu_execution_mode_display_names[static_cast<u8>(mode)];
}
static std::array<const char*, 3> s_gpu_renderer_names = {{"D3D11", "OpenGL", "Software"}};
static std::array<const char*, 3> s_gpu_renderer_display_names = {
{"Hardware (D3D11)", "Hardware (OpenGL)", "Software"}};

View File

@ -8,6 +8,8 @@ struct Settings
ConsoleRegion region = ConsoleRegion::Auto;
CPUExecutionMode cpu_execution_mode = CPUExecutionMode::Interpreter;
bool start_paused = false;
bool speed_limiter_enabled = true;
bool audio_sync_enabled = true;
@ -51,6 +53,10 @@ struct Settings
static const char* GetConsoleRegionName(ConsoleRegion region);
static const char* GetConsoleRegionDisplayName(ConsoleRegion region);
static std::optional<CPUExecutionMode> ParseCPUExecutionMode(const char* str);
static const char* GetCPUExecutionModeName(CPUExecutionMode mode);
static const char* GetCPUExecutionModeDisplayName(CPUExecutionMode mode);
static std::optional<GPURenderer> ParseRendererName(const char* str);
static const char* GetRendererName(GPURenderer renderer);
static const char* GetRendererDisplayName(GPURenderer renderer);

View File

@ -34,6 +34,7 @@ System::System(HostInterface* host_interface) : m_host_interface(host_interface)
m_spu = std::make_unique<SPU>();
m_mdec = std::make_unique<MDEC>();
m_region = host_interface->GetSettings().region;
m_cpu_execution_mode = host_interface->GetSettings().cpu_execution_mode;
}
System::~System() = default;
@ -171,7 +172,7 @@ bool System::Boot(const char* filename)
void System::InitializeComponents()
{
m_cpu->Initialize(m_bus.get());
m_cpu_code_cache->Initialize(this, m_cpu.get(), m_bus.get());
m_cpu_code_cache->Initialize(this, m_cpu.get(), m_bus.get(), m_cpu_execution_mode == CPUExecutionMode::Recompiler);
m_bus->Initialize(m_cpu.get(), m_cpu_code_cache.get(), m_dma.get(), m_interrupt_controller.get(), m_gpu.get(),
m_cdrom.get(), m_pad.get(), m_timers.get(), m_spu.get(), m_mdec.get());
@ -239,7 +240,7 @@ bool System::DoState(StateWrapper& sw)
return false;
if (sw.IsReading())
m_cpu_code_cache->Reset();
m_cpu_code_cache->Flush();
if (!sw.DoMarker("Bus") || !m_bus->DoState(sw))
return false;
@ -274,7 +275,7 @@ bool System::DoState(StateWrapper& sw)
void System::Reset()
{
m_cpu->Reset();
m_cpu_code_cache->Reset();
m_cpu_code_cache->Flush();
m_bus->Reset();
m_dma->Reset();
m_interrupt_controller->Reset();
@ -303,15 +304,24 @@ bool System::SaveState(ByteStream* state)
void System::RunFrame()
{
// Duplicated to avoid branch in the while loop, as the downcount can be quite low at times.
u32 current_frame_number = m_frame_number;
if (m_cpu_execution_mode == CPUExecutionMode::Interpreter)
{
while (current_frame_number == m_frame_number)
{
if (CPU::USE_CODE_CACHE)
m_cpu_code_cache->Execute();
else
m_cpu->Execute();
Synchronize();
}
}
else
{
while (current_frame_number == m_frame_number)
{
m_cpu_code_cache->Execute();
Synchronize();
}
}
}
bool System::LoadEXE(const char* filename, std::vector<u8>& bios_image)
@ -471,6 +481,13 @@ void System::UpdateMemoryCards()
}
}
void System::UpdateCPUExecutionMode()
{
m_cpu_execution_mode = GetSettings().cpu_execution_mode;
m_cpu_code_cache->Flush();
m_cpu_code_cache->SetUseRecompiler(m_cpu_execution_mode == CPUExecutionMode::Recompiler);
}
bool System::HasMedia() const
{
return m_cdrom->HasMedia();

View File

@ -83,6 +83,7 @@ public:
void SetController(u32 slot, std::shared_ptr<PadDevice> dev);
void UpdateMemoryCards();
void UpdateCPUExecutionMode();
bool HasMedia() const;
bool InsertMedia(const char* path);
@ -109,6 +110,7 @@ private:
std::unique_ptr<SPU> m_spu;
std::unique_ptr<MDEC> m_mdec;
ConsoleRegion m_region = ConsoleRegion::NTSC_U;
CPUExecutionMode m_cpu_execution_mode = CPUExecutionMode::Interpreter;
u32 m_frame_number = 1;
u32 m_internal_frame_number = 1;
u32 m_global_tick_counter = 0;

View File

@ -31,6 +31,14 @@ enum class ConsoleRegion
Count
};
enum class CPUExecutionMode : u8
{
Interpreter,
CachedInterpreter,
Recompiler,
Count
};
enum class GPURenderer : u8
{
HardwareD3D11,

View File

@ -803,6 +803,26 @@ void SDLHostInterface::DrawQuickSettingsMenu()
ImGui::Separator();
if (ImGui::BeginMenu("CPU Execution Mode"))
{
const CPUExecutionMode current = m_settings.cpu_execution_mode;
for (u32 i = 0; i < static_cast<u32>(CPUExecutionMode::Count); i++)
{
if (ImGui::MenuItem(Settings::GetCPUExecutionModeDisplayName(static_cast<CPUExecutionMode>(i)), nullptr,
i == static_cast<u32>(current)))
{
m_settings.cpu_execution_mode = static_cast<CPUExecutionMode>(i);
settings_changed = true;
if (m_system)
m_system->UpdateCPUExecutionMode();
}
}
ImGui::EndMenu();
}
ImGui::Separator();
if (ImGui::BeginMenu("Renderer"))
{
const GPURenderer current = m_settings.gpu_renderer;
@ -1012,6 +1032,13 @@ void SDLHostInterface::DrawSettingsWindow()
m_settings.region = static_cast<ConsoleRegion>(region);
settings_changed = true;
}
ImGui::Text("BIOS Path:");
ImGui::SameLine(indent);
settings_changed |= DrawFileChooser("##bios_path", &m_settings.bios_path);
settings_changed |= ImGui::Checkbox("Enable TTY Output", &m_settings.bios_patch_tty_enable);
settings_changed |= ImGui::Checkbox("Fast Boot", &m_settings.bios_patch_fast_boot);
}
ImGui::NewLine();
@ -1041,17 +1068,6 @@ void SDLHostInterface::DrawSettingsWindow()
}
}
ImGui::NewLine();
if (DrawSettingsSectionHeader("BIOS"))
{
ImGui::Text("ROM Path:");
ImGui::SameLine(indent);
settings_changed |= DrawFileChooser("##bios_path", &m_settings.bios_path);
settings_changed |= ImGui::Checkbox("Enable TTY Output", &m_settings.bios_patch_tty_enable);
settings_changed |= ImGui::Checkbox("Fast Boot", &m_settings.bios_patch_fast_boot);
}
ImGui::EndTabItem();
}
@ -1089,6 +1105,29 @@ void SDLHostInterface::DrawSettingsWindow()
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("CPU"))
{
ImGui::Text("Execution Mode:");
ImGui::SameLine(indent);
int execution_mode = static_cast<int>(m_settings.cpu_execution_mode);
if (ImGui::Combo(
"##execution_mode", &execution_mode,
[](void*, int index, const char** out_text) {
*out_text = Settings::GetCPUExecutionModeDisplayName(static_cast<CPUExecutionMode>(index));
return true;
},
nullptr, static_cast<int>(CPUExecutionMode::Count)))
{
m_settings.cpu_execution_mode = static_cast<CPUExecutionMode>(execution_mode);
settings_changed = true;
if (m_system)
m_system->UpdateCPUExecutionMode();
}
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("GPU"))
{
if (DrawSettingsSectionHeader("Basic"))