From 1dfcffcce27651055dfebf0a399ff05cda68f8e9 Mon Sep 17 00:00:00 2001 From: spycrab Date: Mon, 9 Apr 2018 15:31:20 +0200 Subject: [PATCH] Qt/Debugger: Implement "JIT" widget --- Source/Core/DolphinQt2/CMakeLists.txt | 1 + .../DolphinQt2/Debugger/CodeViewWidget.cpp | 2 +- .../Core/DolphinQt2/Debugger/CodeWidget.cpp | 3 + Source/Core/DolphinQt2/Debugger/CodeWidget.h | 3 + Source/Core/DolphinQt2/Debugger/JITWidget.cpp | 205 ++++++++++++++++++ Source/Core/DolphinQt2/Debugger/JITWidget.h | 44 ++++ Source/Core/DolphinQt2/DolphinQt2.vcxproj | 3 + Source/Core/DolphinQt2/MainWindow.cpp | 5 + Source/Core/DolphinQt2/MainWindow.h | 2 + Source/Core/DolphinQt2/MenuBar.cpp | 166 ++++++++++++++ Source/Core/DolphinQt2/MenuBar.h | 25 +++ Source/Core/DolphinQt2/Settings.cpp | 14 ++ Source/Core/DolphinQt2/Settings.h | 3 + 13 files changed, 475 insertions(+), 1 deletion(-) create mode 100644 Source/Core/DolphinQt2/Debugger/JITWidget.cpp create mode 100644 Source/Core/DolphinQt2/Debugger/JITWidget.h diff --git a/Source/Core/DolphinQt2/CMakeLists.txt b/Source/Core/DolphinQt2/CMakeLists.txt index a59660babc..93cab3f5bc 100644 --- a/Source/Core/DolphinQt2/CMakeLists.txt +++ b/Source/Core/DolphinQt2/CMakeLists.txt @@ -72,6 +72,7 @@ add_executable(dolphin-emu-qt2 Debugger/BreakpointWidget.cpp Debugger/CodeViewWidget.cpp Debugger/CodeWidget.cpp + Debugger/JITWidget.cpp Debugger/MemoryViewWidget.cpp Debugger/MemoryWidget.cpp Debugger/NewBreakpointDialog.cpp diff --git a/Source/Core/DolphinQt2/Debugger/CodeViewWidget.cpp b/Source/Core/DolphinQt2/Debugger/CodeViewWidget.cpp index b04766f814..2deb4c6745 100644 --- a/Source/Core/DolphinQt2/Debugger/CodeViewWidget.cpp +++ b/Source/Core/DolphinQt2/Debugger/CodeViewWidget.cpp @@ -250,7 +250,7 @@ void CodeViewWidget::OnContextMenu() AddAction(menu, tr("Run &To Here"), this, &CodeViewWidget::OnRunToHere); auto* function_action = AddAction(menu, tr("&Add function"), this, &CodeViewWidget::OnAddFunction); - auto* ppc_action = AddAction(menu, tr("PPC vs x86"), this, &CodeViewWidget::OnPPCComparison); + auto* ppc_action = AddAction(menu, tr("PPC vs Host"), this, &CodeViewWidget::OnPPCComparison); auto* insert_blr_action = AddAction(menu, tr("&Insert blr"), this, &CodeViewWidget::OnInsertBLR); auto* insert_nop_action = AddAction(menu, tr("Insert &nop"), this, &CodeViewWidget::OnInsertNOP); auto* replace_action = diff --git a/Source/Core/DolphinQt2/Debugger/CodeWidget.cpp b/Source/Core/DolphinQt2/Debugger/CodeWidget.cpp index 19dff6448b..d1aa487591 100644 --- a/Source/Core/DolphinQt2/Debugger/CodeWidget.cpp +++ b/Source/Core/DolphinQt2/Debugger/CodeWidget.cpp @@ -152,6 +152,9 @@ void CodeWidget::ConnectWidgets() connect(m_code_view, &CodeViewWidget::SymbolsChanged, this, &CodeWidget::UpdateSymbols); connect(m_code_view, &CodeViewWidget::BreakpointsChanged, this, [this] { emit BreakpointsChanged(); }); + + connect(m_code_view, &CodeViewWidget::RequestPPCComparison, this, + &CodeWidget::RequestPPCComparison); } void CodeWidget::OnSearchAddress() diff --git a/Source/Core/DolphinQt2/Debugger/CodeWidget.h b/Source/Core/DolphinQt2/Debugger/CodeWidget.h index 6739c5fa7a..b9c1a9b962 100644 --- a/Source/Core/DolphinQt2/Debugger/CodeWidget.h +++ b/Source/Core/DolphinQt2/Debugger/CodeWidget.h @@ -7,6 +7,8 @@ #include #include +#include "Common/CommonTypes.h" + class CodeViewWidget; class QCloseEvent; class QLineEdit; @@ -35,6 +37,7 @@ public: void Update(); signals: void BreakpointsChanged(); + void RequestPPCComparison(u32 addr); private: void CreateWidgets(); diff --git a/Source/Core/DolphinQt2/Debugger/JITWidget.cpp b/Source/Core/DolphinQt2/Debugger/JITWidget.cpp new file mode 100644 index 0000000000..b0b4a772a5 --- /dev/null +++ b/Source/Core/DolphinQt2/Debugger/JITWidget.cpp @@ -0,0 +1,205 @@ +// Copyright 2018 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "DolphinQt2/Debugger/JITWidget.h" + +#include +#include +#include +#include +#include + +#include "Common/GekkoDisassembler.h" +#include "Common/StringUtil.h" +#include "Core/PowerPC/PPCAnalyst.h" +#include "UICommon/Disassembler.h" + +#include "DolphinQt2/Settings.h" + +JITWidget::JITWidget(QWidget* parent) : QDockWidget(parent) +{ + setWindowTitle(tr("JIT Blocks")); + setAllowedAreas(Qt::AllDockWidgetAreas); + + auto& settings = Settings::GetQSettings(); + + CreateWidgets(); + + restoreGeometry(settings.value(QStringLiteral("jitwidget/geometry")).toByteArray()); + setFloating(settings.value(QStringLiteral("jitwidget/floating")).toBool()); + + m_table_splitter->restoreState( + settings.value(QStringLiteral("jitwidget/tablesplitter")).toByteArray()); + m_asm_splitter->restoreState( + settings.value(QStringLiteral("jitwidget/asmsplitter")).toByteArray()); + + connect(&Settings::Instance(), &Settings::JITVisibilityChanged, + [this](bool visible) { setHidden(!visible); }); + + connect(&Settings::Instance(), &Settings::DebugModeToggled, + [this](bool enabled) { setHidden(!enabled || !Settings::Instance().IsJITVisible()); }); + + connect(&Settings::Instance(), &Settings::EmulationStateChanged, this, &JITWidget::Update); + + setHidden(!Settings::Instance().IsJITVisible() || !Settings::Instance().IsDebugModeEnabled()); + + ConnectWidgets(); + +#if defined(_M_X86) + m_disassembler = GetNewDisassembler("x86"); +#elif defined(_M_ARM_64) + m_disassembler = GetNewDisassembler("aarch64"); +#else + m_disassembler = GetNewDisassembler("UNK"); +#endif + + Update(); +} + +JITWidget::~JITWidget() +{ + auto& settings = Settings::GetQSettings(); + + settings.setValue(QStringLiteral("jitwidget/geometry"), saveGeometry()); + settings.setValue(QStringLiteral("jitwidget/floating"), isFloating()); + settings.setValue(QStringLiteral("jitwidget/tablesplitter"), m_table_splitter->saveState()); + settings.setValue(QStringLiteral("jitwidget/asmsplitter"), m_asm_splitter->saveState()); +} + +void JITWidget::CreateWidgets() +{ + m_table_widget = new QTableWidget; + + m_table_widget->setColumnCount(7); + m_table_widget->setHorizontalHeaderLabels( + {tr("Address"), tr("PPC Size"), tr("Host Size"), + // i18n: The symbolic name of a code block + tr("Symbol"), + // i18n: These are the kinds of flags that a CPU uses (e.g. carry), + // not the kinds of flags that represent e.g. countries + tr("Flags"), + // i18n: The number of times a code block has been executed + tr("NumExec"), + // i18n: Performance cost, not monetary cost + tr("Cost")}); + + m_ppc_asm_widget = new QTextBrowser; + m_host_asm_widget = new QTextBrowser; + + m_table_splitter = new QSplitter(Qt::Vertical); + m_asm_splitter = new QSplitter(Qt::Horizontal); + + m_refresh_button = new QPushButton(tr("Refresh")); + + m_table_splitter->addWidget(m_table_widget); + m_table_splitter->addWidget(m_asm_splitter); + + m_asm_splitter->addWidget(m_ppc_asm_widget); + m_asm_splitter->addWidget(m_host_asm_widget); + + QWidget* widget = new QWidget; + auto* layout = new QVBoxLayout; + widget->setLayout(layout); + + layout->addWidget(m_table_splitter); + layout->addWidget(m_refresh_button); + + setWidget(widget); +} + +void JITWidget::ConnectWidgets() +{ + connect(m_refresh_button, &QPushButton::pressed, this, &JITWidget::Update); +} + +void JITWidget::Compare(u32 address) +{ + m_address = address; + Update(); +} + +void JITWidget::Update() +{ + if (!m_address) + { + m_ppc_asm_widget->setHtml(QStringLiteral("%1").arg(tr("(ppc)"))); + m_host_asm_widget->setHtml(QStringLiteral("%1").arg(tr("(host)"))); + return; + } + + // TODO: Actually do something with the table (Wx doesn't) + + // Get host side code disassembly + u32 host_instructions_count = 0; + u32 host_code_size = 0; + std::string host_instructions_disasm; + host_instructions_disasm = + DisassembleBlock(m_disassembler.get(), &m_address, &host_instructions_count, &host_code_size); + + m_host_asm_widget->setHtml( + QStringLiteral("
%1
").arg(QString::fromStdString(host_instructions_disasm))); + + // == Fill in ppc box + u32 ppc_addr = m_address; + PPCAnalyst::CodeBuffer code_buffer(32000); + PPCAnalyst::BlockStats st; + PPCAnalyst::BlockRegStats gpa; + PPCAnalyst::BlockRegStats fpa; + PPCAnalyst::CodeBlock code_block; + PPCAnalyst::PPCAnalyzer analyzer; + analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_CONDITIONAL_CONTINUE); + analyzer.SetOption(PPCAnalyst::PPCAnalyzer::OPTION_BRANCH_FOLLOW); + + code_block.m_stats = &st; + code_block.m_gpa = &gpa; + code_block.m_fpa = &fpa; + + if (analyzer.Analyze(ppc_addr, &code_block, &code_buffer, 32000) != 0xFFFFFFFF) + { + std::ostringstream ppc_disasm; + for (u32 i = 0; i < code_block.m_num_instructions; i++) + { + const PPCAnalyst::CodeOp& op = code_buffer.codebuffer[i]; + std::string opcode = GekkoDisassembler::Disassemble(op.inst.hex, op.address); + ppc_disasm << std::setfill('0') << std::setw(8) << std::hex << op.address; + ppc_disasm << " " << opcode << std::endl; + } + + // Add stats to the end of the ppc box since it's generally the shortest. + ppc_disasm << std::dec << std::endl; + + // Add some generic analysis + if (st.isFirstBlockOfFunction) + ppc_disasm << "(first block of function)" << std::endl; + if (st.isLastBlockOfFunction) + ppc_disasm << "(last block of function)" << std::endl; + + ppc_disasm << st.numCycles << " estimated cycles" << std::endl; + + ppc_disasm << "Num instr: PPC: " << code_block.m_num_instructions + << " Host: " << host_instructions_count << " (blowup: " + << 100 * host_instructions_count / code_block.m_num_instructions - 100 << "%)" + << std::endl; + + ppc_disasm << "Num bytes: PPC: " << code_block.m_num_instructions * 4 + << " Host: " << host_code_size + << " (blowup: " << 100 * host_code_size / (4 * code_block.m_num_instructions) - 100 + << "%)" << std::endl; + + m_ppc_asm_widget->setHtml( + QStringLiteral("
%1
").arg(QString::fromStdString(ppc_disasm.str()))); + } + else + { + m_host_asm_widget->setHtml( + QStringLiteral("
%1
") + .arg(QString::fromStdString(StringFromFormat("(non-code address: %08x)", m_address)))); + m_ppc_asm_widget->setHtml(QStringLiteral("---")); + } +} + +void JITWidget::closeEvent(QCloseEvent*) +{ + Settings::Instance().SetJITVisible(false); +} diff --git a/Source/Core/DolphinQt2/Debugger/JITWidget.h b/Source/Core/DolphinQt2/Debugger/JITWidget.h new file mode 100644 index 0000000000..4549d39261 --- /dev/null +++ b/Source/Core/DolphinQt2/Debugger/JITWidget.h @@ -0,0 +1,44 @@ +// Copyright 2018 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "Common/CommonTypes.h" + +class QCloseEvent; +class QSplitter; +class QTextBrowser; +class QTableWidget; +class QPushButton; +class HostDisassembler; + +class JITWidget : public QDockWidget +{ + Q_OBJECT +public: + explicit JITWidget(QWidget* parent = nullptr); + ~JITWidget(); + + void Compare(u32 address); + +private: + void Update(); + void CreateWidgets(); + void ConnectWidgets(); + + void closeEvent(QCloseEvent*) override; + + QTableWidget* m_table_widget; + QTextBrowser* m_ppc_asm_widget; + QTextBrowser* m_host_asm_widget; + QSplitter* m_table_splitter; + QSplitter* m_asm_splitter; + QPushButton* m_refresh_button; + + std::unique_ptr m_disassembler; + u32 m_address = 0; +}; diff --git a/Source/Core/DolphinQt2/DolphinQt2.vcxproj b/Source/Core/DolphinQt2/DolphinQt2.vcxproj index 1d925a3950..ed0255c4d3 100644 --- a/Source/Core/DolphinQt2/DolphinQt2.vcxproj +++ b/Source/Core/DolphinQt2/DolphinQt2.vcxproj @@ -98,6 +98,7 @@ + @@ -176,6 +177,7 @@ + @@ -257,6 +259,7 @@ + diff --git a/Source/Core/DolphinQt2/MainWindow.cpp b/Source/Core/DolphinQt2/MainWindow.cpp index 49cf3a3af9..38170ee6cf 100644 --- a/Source/Core/DolphinQt2/MainWindow.cpp +++ b/Source/Core/DolphinQt2/MainWindow.cpp @@ -55,6 +55,7 @@ #include "DolphinQt2/Config/SettingsWindow.h" #include "DolphinQt2/Debugger/BreakpointWidget.h" #include "DolphinQt2/Debugger/CodeWidget.h" +#include "DolphinQt2/Debugger/JITWidget.h" #include "DolphinQt2/Debugger/MemoryWidget.h" #include "DolphinQt2/Debugger/RegisterWidget.h" #include "DolphinQt2/Debugger/WatchWidget.h" @@ -202,6 +203,7 @@ void MainWindow::CreateComponents() m_hotkey_window = new MappingWindow(this, MappingWindow::Type::MAPPING_HOTKEYS, 0); + m_jit_widget = new JITWidget(this); m_log_widget = new LogWidget(this); m_log_config_widget = new LogConfigWidget(this); m_fifo_window = new FIFOPlayerWindow(this); @@ -222,6 +224,7 @@ void MainWindow::CreateComponents() connect(m_code_widget, &CodeWidget::BreakpointsChanged, m_breakpoint_widget, &BreakpointWidget::Update); + connect(m_code_widget, &CodeWidget::RequestPPCComparison, m_jit_widget, &JITWidget::Compare); connect(m_memory_widget, &MemoryWidget::BreakpointsChanged, m_breakpoint_widget, &BreakpointWidget::Update); @@ -430,6 +433,7 @@ void MainWindow::ConnectStack() addDockWidget(Qt::RightDockWidgetArea, m_watch_widget); addDockWidget(Qt::RightDockWidgetArea, m_breakpoint_widget); addDockWidget(Qt::RightDockWidgetArea, m_memory_widget); + addDockWidget(Qt::RightDockWidgetArea, m_jit_widget); tabifyDockWidget(m_log_widget, m_log_config_widget); tabifyDockWidget(m_log_widget, m_code_widget); @@ -437,6 +441,7 @@ void MainWindow::ConnectStack() tabifyDockWidget(m_log_widget, m_watch_widget); tabifyDockWidget(m_log_widget, m_breakpoint_widget); tabifyDockWidget(m_log_widget, m_memory_widget); + tabifyDockWidget(m_log_widget, m_jit_widget); } QString MainWindow::PromptFileName() diff --git a/Source/Core/DolphinQt2/MainWindow.h b/Source/Core/DolphinQt2/MainWindow.h index c654dfb538..160c39ddf0 100644 --- a/Source/Core/DolphinQt2/MainWindow.h +++ b/Source/Core/DolphinQt2/MainWindow.h @@ -30,6 +30,7 @@ class FIFOPlayerWindow; class GCTASInputWindow; class GraphicsWindow; class HotkeyScheduler; +class JITWidget; class LogConfigWidget; class LogWidget; class MappingWindow; @@ -184,6 +185,7 @@ private: BreakpointWidget* m_breakpoint_widget; CodeWidget* m_code_widget; + JITWidget* m_jit_widget; LogWidget* m_log_widget; LogConfigWidget* m_log_config_widget; MemoryWidget* m_memory_widget; diff --git a/Source/Core/DolphinQt2/MenuBar.cpp b/Source/Core/DolphinQt2/MenuBar.cpp index b02fd70ad2..ec05e55e56 100644 --- a/Source/Core/DolphinQt2/MenuBar.cpp +++ b/Source/Core/DolphinQt2/MenuBar.cpp @@ -33,8 +33,10 @@ #include "Core/IOS/IOS.h" #include "Core/IOS/USB/Bluetooth/BTEmu.h" #include "Core/Movie.h" +#include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/PPCSymbolDB.h" +#include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/SignatureDB/SignatureDB.h" #include "Core/State.h" #include "Core/TitleDatabase.h" @@ -57,6 +59,7 @@ MenuBar::MenuBar(QWidget* parent) : QMenuBar(parent) AddOptionsMenu(); AddToolsMenu(); AddViewMenu(); + AddJITMenu(); AddSymbolsMenu(); AddHelpMenu(); @@ -102,6 +105,22 @@ void MenuBar::OnEmulationStateChanged(Core::State state) // Tools m_show_cheat_manager->setEnabled(Settings::Instance().GetCheatsEnabled()); + // JIT + m_jit_interpreter_core->setEnabled(running); + m_jit_block_linking->setEnabled(!running); + m_jit_disable_cache->setEnabled(!running); + m_jit_clear_cache->setEnabled(running); + m_jit_log_coverage->setEnabled(!running); + m_jit_search_instruction->setEnabled(running); + + for (QAction* action : + {m_jit_off, m_jit_loadstore_off, m_jit_loadstore_lbzx_off, m_jit_loadstore_lxz_off, + m_jit_loadstore_lwz_off, m_jit_loadstore_floating_off, m_jit_loadstore_paired_off, + m_jit_floatingpoint_off, m_jit_integer_off, m_jit_paired_off, m_jit_systemregisters_off}) + { + action->setEnabled(running); + } + // Symbols m_symbols->setEnabled(running); @@ -124,11 +143,18 @@ void MenuBar::OnDebugModeToggled(bool enabled) m_show_watch->setVisible(enabled); m_show_breakpoints->setVisible(enabled); m_show_memory->setVisible(enabled); + m_show_jit->setVisible(enabled); if (enabled) + { + addMenu(m_jit); addMenu(m_symbols); + } else + { + removeAction(m_jit->menuAction()); removeAction(m_symbols->menuAction()); + } } void MenuBar::AddDVDBackupMenu(QMenu* file_menu) @@ -410,6 +436,12 @@ void MenuBar::AddViewMenu() connect(&Settings::Instance(), &Settings::MemoryVisibilityChanged, m_show_memory, &QAction::setChecked); + m_show_jit = view_menu->addAction(tr("&JIT")); + m_show_jit->setCheckable(true); + m_show_jit->setChecked(Settings::Instance().IsJITVisible()); + connect(m_show_jit, &QAction::toggled, &Settings::Instance(), &Settings::SetJITVisible); + connect(&Settings::Instance(), &Settings::JITVisibilityChanged, m_show_jit, &QAction::setChecked); + view_menu->addSeparator(); AddGameListTypeSection(view_menu); @@ -654,6 +686,106 @@ void MenuBar::AddMovieMenu() [](bool value) { SConfig::GetInstance().m_DumpAudio = value; }); } +void MenuBar::AddJITMenu() +{ + m_jit = addMenu(tr("JIT")); + + m_jit_interpreter_core = m_jit->addAction(tr("Interpreter Core")); + m_jit_interpreter_core->setCheckable(true); + m_jit_interpreter_core->setChecked(SConfig::GetInstance().iCPUCore == PowerPC::CORE_INTERPRETER); + + m_jit->addSeparator(); + + m_jit_block_linking = m_jit->addAction(tr("JIT Block Linking Off")); + m_jit_block_linking->setCheckable(true); + m_jit_block_linking->setChecked(SConfig::GetInstance().bJITNoBlockLinking); + connect(m_jit_block_linking, &QAction::toggled, + [](bool enabled) { SConfig::GetInstance().bJITNoBlockLinking = enabled; }); + + m_jit_disable_cache = m_jit->addAction(tr("Disable JIT Cache")); + m_jit_disable_cache->setCheckable(true); + m_jit_disable_cache->setChecked(SConfig::GetInstance().bJITNoBlockCache); + connect(m_jit_disable_cache, &QAction::toggled, + [](bool enabled) { SConfig::GetInstance().bJITNoBlockCache = enabled; }); + + m_jit_clear_cache = AddAction(m_jit, tr("Clear Cache"), this, &MenuBar::ClearCache); + + m_jit->addSeparator(); + + m_jit_log_coverage = + AddAction(m_jit, tr("Log JIT Instruction Coverage"), this, &MenuBar::LogInstructions); + m_jit_search_instruction = + AddAction(m_jit, tr("Search for an Instruction"), this, &MenuBar::SearchInstruction); + + m_jit->addSeparator(); + + m_jit_off = m_jit->addAction(tr("JIT Off (JIT Core)")); + m_jit_off->setCheckable(true); + m_jit_off->setChecked(SConfig::GetInstance().bJITOff); + connect(m_jit_off, &QAction::toggled, + [](bool enabled) { SConfig::GetInstance().bJITOff = enabled; }); + + m_jit_loadstore_off = m_jit->addAction(tr("JIT LoadStore Off")); + m_jit_loadstore_off->setCheckable(true); + m_jit_loadstore_off->setChecked(SConfig::GetInstance().bJITLoadStoreOff); + connect(m_jit_loadstore_off, &QAction::toggled, + [](bool enabled) { SConfig::GetInstance().bJITLoadStoreOff = enabled; }); + + m_jit_loadstore_lbzx_off = m_jit->addAction(tr("JIT LoadStore lbzx Off")); + m_jit_loadstore_lbzx_off->setCheckable(true); + m_jit_loadstore_lbzx_off->setChecked(SConfig::GetInstance().bJITLoadStorelbzxOff); + connect(m_jit_loadstore_lbzx_off, &QAction::toggled, + [](bool enabled) { SConfig::GetInstance().bJITLoadStorelbzxOff = enabled; }); + + m_jit_loadstore_lxz_off = m_jit->addAction(tr("JIT LoadStore lXz Off")); + m_jit_loadstore_lxz_off->setCheckable(true); + m_jit_loadstore_lxz_off->setChecked(SConfig::GetInstance().bJITLoadStorelXzOff); + connect(m_jit_loadstore_lxz_off, &QAction::toggled, + [](bool enabled) { SConfig::GetInstance().bJITLoadStorelXzOff = enabled; }); + + m_jit_loadstore_lwz_off = m_jit->addAction(tr("JIT LoadStore lwz Off")); + m_jit_loadstore_lwz_off->setCheckable(true); + m_jit_loadstore_lwz_off->setChecked(SConfig::GetInstance().bJITLoadStorelwzOff); + connect(m_jit_loadstore_lwz_off, &QAction::toggled, + [](bool enabled) { SConfig::GetInstance().bJITLoadStorelwzOff = enabled; }); + + m_jit_loadstore_floating_off = m_jit->addAction(tr("JIT LoadStore Floating Off")); + m_jit_loadstore_floating_off->setCheckable(true); + m_jit_loadstore_floating_off->setChecked(SConfig::GetInstance().bJITLoadStoreFloatingOff); + connect(m_jit_loadstore_floating_off, &QAction::toggled, + [](bool enabled) { SConfig::GetInstance().bJITLoadStoreFloatingOff = enabled; }); + + m_jit_loadstore_paired_off = m_jit->addAction(tr("JIT LoadStore Paired Off")); + m_jit_loadstore_paired_off->setCheckable(true); + m_jit_loadstore_paired_off->setChecked(SConfig::GetInstance().bJITLoadStorePairedOff); + connect(m_jit_loadstore_paired_off, &QAction::toggled, + [](bool enabled) { SConfig::GetInstance().bJITLoadStorePairedOff = enabled; }); + + m_jit_floatingpoint_off = m_jit->addAction(tr("JIT FloatingPoint Off")); + m_jit_floatingpoint_off->setCheckable(true); + m_jit_floatingpoint_off->setChecked(SConfig::GetInstance().bJITFloatingPointOff); + connect(m_jit_floatingpoint_off, &QAction::toggled, + [](bool enabled) { SConfig::GetInstance().bJITFloatingPointOff = enabled; }); + + m_jit_integer_off = m_jit->addAction(tr("JIT Integer Off")); + m_jit_integer_off->setCheckable(true); + m_jit_integer_off->setChecked(SConfig::GetInstance().bJITIntegerOff); + connect(m_jit_integer_off, &QAction::toggled, + [](bool enabled) { SConfig::GetInstance().bJITIntegerOff = enabled; }); + + m_jit_paired_off = m_jit->addAction(tr("JIT Paired Off")); + m_jit_paired_off->setCheckable(true); + m_jit_paired_off->setChecked(SConfig::GetInstance().bJITPairedOff); + connect(m_jit_paired_off, &QAction::toggled, + [](bool enabled) { SConfig::GetInstance().bJITPairedOff = enabled; }); + + m_jit_systemregisters_off = m_jit->addAction(tr("JIT SystemRegisters Off")); + m_jit_systemregisters_off->setCheckable(true); + m_jit_systemregisters_off->setChecked(SConfig::GetInstance().bJITSystemRegistersOff); + connect(m_jit_systemregisters_off, &QAction::toggled, + [](bool enabled) { SConfig::GetInstance().bJITSystemRegistersOff = enabled; }); +} + void MenuBar::AddSymbolsMenu() { m_symbols = addMenu(tr("Symbols")); @@ -1041,3 +1173,37 @@ void MenuBar::PatchHLEFunctions() { HLE::PatchFunctions(); } + +void MenuBar::ClearCache() +{ + Core::RunAsCPUThread(JitInterface::ClearCache); +} + +void MenuBar::LogInstructions() +{ + PPCTables::LogCompiledInstructions(); +} + +void MenuBar::SearchInstruction() +{ + bool good; + QString op = QInputDialog::getText(this, tr("Search instruction"), tr("Instruction:"), + QLineEdit::Normal, QStringLiteral(""), &good); + + if (!good) + return; + + bool found = false; + for (u32 addr = 0x80000000; addr < 0x81800000; addr += 4) + { + auto ins_name = + QString::fromStdString(PPCTables::GetInstructionName(PowerPC::HostRead_U32(addr))); + if (op == ins_name) + { + NOTICE_LOG(POWERPC, "Found %s at %08x", op.toStdString().c_str(), addr); + found = true; + } + } + if (!found) + NOTICE_LOG(POWERPC, "Opcode %s not found", op.toStdString().c_str()); +} diff --git a/Source/Core/DolphinQt2/MenuBar.h b/Source/Core/DolphinQt2/MenuBar.h index cb2678dca6..fb2f2b9d4b 100644 --- a/Source/Core/DolphinQt2/MenuBar.h +++ b/Source/Core/DolphinQt2/MenuBar.h @@ -123,6 +123,7 @@ private: void AddToolsMenu(); void AddHelpMenu(); void AddMovieMenu(); + void AddJITMenu(); void AddSymbolsMenu(); void InstallWAD(); @@ -144,6 +145,9 @@ private: void SaveCode(); void CreateSignatureFile(); void PatchHLEFunctions(); + void ClearCache(); + void LogInstructions(); + void SearchInstruction(); void OnSelectionChanged(std::shared_ptr game_file); void OnRecordingStatusChanged(bool recording); @@ -204,7 +208,28 @@ private: QAction* m_show_watch; QAction* m_show_breakpoints; QAction* m_show_memory; + QAction* m_show_jit; + + // JIT + QMenu* m_jit; // Symbols QMenu* m_symbols; + QAction* m_jit_interpreter_core; + QAction* m_jit_block_linking; + QAction* m_jit_disable_cache; + QAction* m_jit_clear_cache; + QAction* m_jit_log_coverage; + QAction* m_jit_search_instruction; + QAction* m_jit_off; + QAction* m_jit_loadstore_off; + QAction* m_jit_loadstore_lbzx_off; + QAction* m_jit_loadstore_lxz_off; + QAction* m_jit_loadstore_lwz_off; + QAction* m_jit_loadstore_floating_off; + QAction* m_jit_loadstore_paired_off; + QAction* m_jit_floatingpoint_off; + QAction* m_jit_integer_off; + QAction* m_jit_paired_off; + QAction* m_jit_systemregisters_off; }; diff --git a/Source/Core/DolphinQt2/Settings.cpp b/Source/Core/DolphinQt2/Settings.cpp index 8a523605de..764aa62801 100644 --- a/Source/Core/DolphinQt2/Settings.cpp +++ b/Source/Core/DolphinQt2/Settings.cpp @@ -319,6 +319,20 @@ bool Settings::IsMemoryVisible() const return QSettings().value(QStringLiteral("debugger/showmemory")).toBool(); } +void Settings::SetJITVisible(bool enabled) +{ + if (IsJITVisible() == enabled) + return; + QSettings().setValue(QStringLiteral("debugger/showjit"), enabled); + + emit JITVisibilityChanged(enabled); +} + +bool Settings::IsJITVisible() const +{ + return QSettings().value(QStringLiteral("debugger/showjit")).toBool(); +} + void Settings::SetDebugFont(QFont font) { if (GetDebugFont() != font) diff --git a/Source/Core/DolphinQt2/Settings.h b/Source/Core/DolphinQt2/Settings.h index dcde3434d6..335de1d005 100644 --- a/Source/Core/DolphinQt2/Settings.h +++ b/Source/Core/DolphinQt2/Settings.h @@ -103,6 +103,8 @@ public: bool IsCodeVisible() const; void SetMemoryVisible(bool enabled); bool IsMemoryVisible() const; + void SetJITVisible(bool enabled); + bool IsJITVisible() const; QFont GetDebugFont() const; void SetDebugFont(QFont font); @@ -136,6 +138,7 @@ signals: void BreakpointsVisibilityChanged(bool visible); void CodeVisibilityChanged(bool visible); void MemoryVisibilityChanged(bool visible); + void JITVisibilityChanged(bool visible); void DebugModeToggled(bool enabled); void DebugFontChanged(QFont font); void AutoUpdateTrackChanged(const QString& mode);