summaryrefslogtreecommitdiff
path: root/Source
diff options
context:
space:
mode:
authorspycrab <spycrab@users.noreply.github.com>2018-04-09 15:31:20 +0200
committerspycrab <spycrab@users.noreply.github.com>2018-05-11 18:10:35 +0200
commit1dfcffcce27651055dfebf0a399ff05cda68f8e9 (patch)
tree0e319a864ab719869aad2dec562a076592b61b06 /Source
parentdabfecfd7432728d93c622de2f4c9e4dd8ccd814 (diff)
Qt/Debugger: Implement "JIT" widget
Diffstat (limited to 'Source')
-rw-r--r--Source/Core/DolphinQt2/CMakeLists.txt1
-rw-r--r--Source/Core/DolphinQt2/Debugger/CodeViewWidget.cpp2
-rw-r--r--Source/Core/DolphinQt2/Debugger/CodeWidget.cpp3
-rw-r--r--Source/Core/DolphinQt2/Debugger/CodeWidget.h3
-rw-r--r--Source/Core/DolphinQt2/Debugger/JITWidget.cpp205
-rw-r--r--Source/Core/DolphinQt2/Debugger/JITWidget.h44
-rw-r--r--Source/Core/DolphinQt2/DolphinQt2.vcxproj3
-rw-r--r--Source/Core/DolphinQt2/MainWindow.cpp5
-rw-r--r--Source/Core/DolphinQt2/MainWindow.h2
-rw-r--r--Source/Core/DolphinQt2/MenuBar.cpp166
-rw-r--r--Source/Core/DolphinQt2/MenuBar.h25
-rw-r--r--Source/Core/DolphinQt2/Settings.cpp14
-rw-r--r--Source/Core/DolphinQt2/Settings.h3
13 files changed, 475 insertions, 1 deletions
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 <QDockWidget>
#include <QString>
+#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 <QPushButton>
+#include <QSplitter>
+#include <QTableWidget>
+#include <QTextBrowser>
+#include <QVBoxLayout>
+
+#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("<i>%1</i>").arg(tr("(ppc)")));
+ m_host_asm_widget->setHtml(QStringLiteral("<i>%1</i>").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("<pre>%1</pre>").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("<pre>%1</pre>").arg(QString::fromStdString(ppc_disasm.str())));
+ }
+ else
+ {
+ m_host_asm_widget->setHtml(
+ QStringLiteral("<pre>%1</pre>")
+ .arg(QString::fromStdString(StringFromFormat("(non-code address: %08x)", m_address))));
+ m_ppc_asm_widget->setHtml(QStringLiteral("<i>---</i>"));
+ }
+}
+
+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 <QDockWidget>
+#include <memory>
+
+#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<HostDisassembler> 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 @@
<QtMoc Include="Debugger\BreakpointWidget.h" />
<QtMoc Include="Debugger\CodeWidget.h" />
<QtMoc Include="Debugger\CodeViewWidget.h" />
+ <QtMoc Include="Debugger\JITWidget.h" />
<QtMoc Include="Debugger\MemoryWidget.h" />
<QtMoc Include="Debugger\MemoryViewWidget.h" />
<QtMoc Include="Debugger\NewBreakpointDialog.h" />
@@ -176,6 +177,7 @@
<ClCompile Include="$(QtMocOutPrefix)InfoWidget.cpp" />
<ClCompile Include="$(QtMocOutPrefix)InterfacePane.cpp" />
<ClCompile Include="$(QtMocOutPrefix)IOWindow.cpp" />
+ <ClCompile Include="$(QtMocOutPrefix)JITWidget.cpp" />
<ClCompile Include="$(QtMocOutPrefix)GridProxyModel.cpp" />
<ClCompile Include="$(QtMocOutPrefix)ListProxyModel.cpp" />
<ClCompile Include="$(QtMocOutPrefix)LogConfigWidget.cpp" />
@@ -257,6 +259,7 @@
<ClCompile Include="Config\SettingsWindow.cpp" />
<ClCompile Include="Debugger\CodeViewWidget.cpp" />
<ClCompile Include="Debugger\CodeWidget.cpp" />
+ <ClCompile Include="Debugger\JITWidget.cpp" />
<ClCompile Include="Debugger\MemoryWidget.cpp" />
<ClCompile Include="Debugger\MemoryViewWidget.cpp" />
<ClCompile Include="FIFOPlayerWindow.cpp" />
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<const UICommon::GameFile> 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);