1 // Copyright 2015 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #include "DolphinQt/MenuBar.h"
6 
7 #include <cinttypes>
8 
9 #include <QAction>
10 #include <QDesktopServices>
11 #include <QFileDialog>
12 #include <QFontDialog>
13 #include <QInputDialog>
14 #include <QMap>
15 #include <QUrl>
16 
17 #include "Common/CommonPaths.h"
18 #include "Common/FileUtil.h"
19 #include "Common/StringUtil.h"
20 
21 #include "Common/CDUtils.h"
22 #include "Core/Boot/Boot.h"
23 #include "Core/CommonTitles.h"
24 #include "Core/ConfigManager.h"
25 #include "Core/Core.h"
26 #include "Core/Debugger/RSO.h"
27 #include "Core/HLE/HLE.h"
28 #include "Core/HW/AddressSpace.h"
29 #include "Core/HW/Memmap.h"
30 #include "Core/HW/WiiSave.h"
31 #include "Core/HW/Wiimote.h"
32 #include "Core/IOS/ES/ES.h"
33 #include "Core/IOS/IOS.h"
34 #include "Core/IOS/USB/Bluetooth/BTEmu.h"
35 #include "Core/Movie.h"
36 #include "Core/NetPlayProto.h"
37 #include "Core/PowerPC/JitInterface.h"
38 #include "Core/PowerPC/MMU.h"
39 #include "Core/PowerPC/PPCAnalyst.h"
40 #include "Core/PowerPC/PPCSymbolDB.h"
41 #include "Core/PowerPC/PowerPC.h"
42 #include "Core/PowerPC/SignatureDB/SignatureDB.h"
43 #include "Core/State.h"
44 #include "Core/TitleDatabase.h"
45 #include "Core/WiiUtils.h"
46 
47 #include "DiscIO/Enums.h"
48 #include "DiscIO/NANDImporter.h"
49 #include "DiscIO/WiiSaveBanner.h"
50 
51 #include "DolphinQt/AboutDialog.h"
52 #include "DolphinQt/Host.h"
53 #include "DolphinQt/QtUtils/ModalMessageBox.h"
54 #include "DolphinQt/Settings.h"
55 #include "DolphinQt/Updater.h"
56 
57 #include "UICommon/AutoUpdate.h"
58 #include "UICommon/GameFile.h"
59 
60 QPointer<MenuBar> MenuBar::s_menu_bar;
61 
GetSignatureSelector() const62 QString MenuBar::GetSignatureSelector() const
63 {
64   return QStringLiteral("%1 (*.dsy);; %2 (*.csv);; %3 (*.mega)")
65       .arg(tr("Dolphin Signature File"), tr("Dolphin Signature CSV File"),
66            tr("WiiTools Signature MEGA File"));
67 }
68 
MenuBar(QWidget * parent)69 MenuBar::MenuBar(QWidget* parent) : QMenuBar(parent)
70 {
71   s_menu_bar = this;
72 
73   AddFileMenu();
74   AddEmulationMenu();
75   AddMovieMenu();
76   AddOptionsMenu();
77   AddToolsMenu();
78   AddViewMenu();
79   AddJITMenu();
80   AddSymbolsMenu();
81   AddHelpMenu();
82 
83   connect(&Settings::Instance(), &Settings::EmulationStateChanged, this,
84           [=](Core::State state) { OnEmulationStateChanged(state); });
85   connect(Host::GetInstance(), &Host::UpdateDisasmDialog, this,
86           [this] { OnEmulationStateChanged(Core::GetState()); });
87 
88   OnEmulationStateChanged(Core::GetState());
89   connect(&Settings::Instance(), &Settings::DebugModeToggled, this, &MenuBar::OnDebugModeToggled);
90 
91   connect(this, &MenuBar::SelectionChanged, this, &MenuBar::OnSelectionChanged);
92   connect(this, &MenuBar::RecordingStatusChanged, this, &MenuBar::OnRecordingStatusChanged);
93   connect(this, &MenuBar::ReadOnlyModeChanged, this, &MenuBar::OnReadOnlyModeChanged);
94 }
95 
OnEmulationStateChanged(Core::State state)96 void MenuBar::OnEmulationStateChanged(Core::State state)
97 {
98   bool running = state != Core::State::Uninitialized;
99   bool playing = running && state != Core::State::Paused;
100 
101   // File
102   m_eject_disc->setEnabled(running);
103   m_change_disc->setEnabled(running);
104 
105   // Emulation
106   m_play_action->setEnabled(!playing);
107   m_play_action->setVisible(!playing);
108   m_pause_action->setEnabled(playing);
109   m_pause_action->setVisible(playing);
110   m_stop_action->setEnabled(running);
111   m_stop_action->setVisible(running);
112   m_reset_action->setEnabled(running);
113   m_fullscreen_action->setEnabled(running);
114   m_frame_advance_action->setEnabled(running);
115   m_screenshot_action->setEnabled(running);
116   m_state_load_menu->setEnabled(running);
117   m_state_save_menu->setEnabled(running);
118 
119   // Movie
120   m_recording_read_only->setEnabled(running);
121   if (!running)
122   {
123     m_recording_stop->setEnabled(false);
124     m_recording_export->setEnabled(false);
125   }
126   m_recording_play->setEnabled(m_game_selected && !running);
127   m_recording_start->setEnabled((m_game_selected || running) && !Movie::IsPlayingInput());
128 
129   // Options
130   m_controllers_action->setEnabled(NetPlay::IsNetPlayRunning() ? !running : true);
131 
132   // Tools
133   m_show_cheat_manager->setEnabled(Settings::Instance().GetCheatsEnabled() && running);
134 
135   // JIT
136   m_jit_interpreter_core->setEnabled(running);
137   m_jit_block_linking->setEnabled(!running);
138   m_jit_disable_cache->setEnabled(!running);
139   m_jit_disable_fastmem->setEnabled(!running);
140   m_jit_clear_cache->setEnabled(running);
141   m_jit_log_coverage->setEnabled(!running);
142   m_jit_search_instruction->setEnabled(running);
143 
144   for (QAction* action :
145        {m_jit_off, m_jit_loadstore_off, m_jit_loadstore_lbzx_off, m_jit_loadstore_lxz_off,
146         m_jit_loadstore_lwz_off, m_jit_loadstore_floating_off, m_jit_loadstore_paired_off,
147         m_jit_floatingpoint_off, m_jit_integer_off, m_jit_paired_off, m_jit_systemregisters_off,
148         m_jit_branch_off, m_jit_register_cache_off})
149   {
150     action->setEnabled(running && !playing);
151   }
152 
153   // Symbols
154   m_symbols->setEnabled(running);
155 
156   UpdateStateSlotMenu();
157   UpdateToolsMenu(running);
158 
159   OnDebugModeToggled(Settings::Instance().IsDebugModeEnabled());
160 }
161 
OnDebugModeToggled(bool enabled)162 void MenuBar::OnDebugModeToggled(bool enabled)
163 {
164   // Options
165   m_boot_to_pause->setVisible(enabled);
166   m_automatic_start->setVisible(enabled);
167   m_change_font->setVisible(enabled);
168 
169   // View
170   m_show_code->setVisible(enabled);
171   m_show_registers->setVisible(enabled);
172   m_show_threads->setVisible(enabled);
173   m_show_watch->setVisible(enabled);
174   m_show_breakpoints->setVisible(enabled);
175   m_show_memory->setVisible(enabled);
176   m_show_network->setVisible(enabled);
177   m_show_jit->setVisible(enabled);
178 
179   if (enabled)
180   {
181     addMenu(m_jit);
182     addMenu(m_symbols);
183   }
184   else
185   {
186     removeAction(m_jit->menuAction());
187     removeAction(m_symbols->menuAction());
188   }
189 }
190 
AddDVDBackupMenu(QMenu * file_menu)191 void MenuBar::AddDVDBackupMenu(QMenu* file_menu)
192 {
193   m_backup_menu = file_menu->addMenu(tr("&Boot from DVD Backup"));
194 
195   const std::vector<std::string> drives = Common::GetCDDevices();
196   // Windows Limitation of 24 character drives
197   for (size_t i = 0; i < drives.size() && i < 24; i++)
198   {
199     auto drive = QString::fromStdString(drives[i]);
200     m_backup_menu->addAction(drive, this, [this, drive] { emit BootDVDBackup(drive); });
201   }
202 }
203 
AddFileMenu()204 void MenuBar::AddFileMenu()
205 {
206   QMenu* file_menu = addMenu(tr("&File"));
207   m_open_action = file_menu->addAction(tr("&Open..."), this, &MenuBar::Open, QKeySequence::Open);
208 
209   file_menu->addSeparator();
210 
211   m_change_disc = file_menu->addAction(tr("Change &Disc..."), this, &MenuBar::ChangeDisc);
212   m_eject_disc = file_menu->addAction(tr("&Eject Disc"), this, &MenuBar::EjectDisc);
213 
214   AddDVDBackupMenu(file_menu);
215 
216   file_menu->addSeparator();
217 
218   m_exit_action = file_menu->addAction(tr("E&xit"), this, &MenuBar::Exit);
219   m_exit_action->setShortcuts({QKeySequence::Quit, QKeySequence(Qt::ALT + Qt::Key_F4)});
220 }
221 
AddToolsMenu()222 void MenuBar::AddToolsMenu()
223 {
224   QMenu* tools_menu = addMenu(tr("&Tools"));
225 
226   tools_menu->addAction(tr("&Resource Pack Manager"), this,
227                         [this] { emit ShowResourcePackManager(); });
228 
229   m_show_cheat_manager =
230       tools_menu->addAction(tr("&Cheats Manager"), this, [this] { emit ShowCheatsManager(); });
231 
232   connect(&Settings::Instance(), &Settings::EnableCheatsChanged, this, [this](bool enabled) {
233     m_show_cheat_manager->setEnabled(Core::GetState() != Core::State::Uninitialized && enabled);
234   });
235 
236   tools_menu->addAction(tr("FIFO Player"), this, &MenuBar::ShowFIFOPlayer);
237 
238   tools_menu->addSeparator();
239 
240   tools_menu->addAction(tr("Start &NetPlay..."), this, &MenuBar::StartNetPlay);
241   tools_menu->addAction(tr("Browse &NetPlay Sessions...."), this, &MenuBar::BrowseNetPlay);
242 
243   tools_menu->addSeparator();
244 
245   QMenu* gc_ipl = tools_menu->addMenu(tr("Load GameCube Main Menu"));
246 
247   m_ntscj_ipl = gc_ipl->addAction(tr("NTSC-J"), this,
248                                   [this] { emit BootGameCubeIPL(DiscIO::Region::NTSC_J); });
249   m_ntscu_ipl = gc_ipl->addAction(tr("NTSC-U"), this,
250                                   [this] { emit BootGameCubeIPL(DiscIO::Region::NTSC_U); });
251   m_pal_ipl =
252       gc_ipl->addAction(tr("PAL"), this, [this] { emit BootGameCubeIPL(DiscIO::Region::PAL); });
253 
254   tools_menu->addAction(tr("Memory Card Manager"), this, [this] { emit ShowMemcardManager(); });
255 
256   tools_menu->addSeparator();
257 
258   // Label will be set by a NANDRefresh later
259   m_boot_sysmenu = tools_menu->addAction(QString{}, this, [this] { emit BootWiiSystemMenu(); });
260   m_wad_install_action = tools_menu->addAction(tr("Install WAD..."), this, &MenuBar::InstallWAD);
261   m_manage_nand_menu = tools_menu->addMenu(tr("Manage NAND"));
262   m_import_backup = m_manage_nand_menu->addAction(tr("Import BootMii NAND Backup..."), this,
263                                                   [this] { emit ImportNANDBackup(); });
264   m_check_nand = m_manage_nand_menu->addAction(tr("Check NAND..."), this, &MenuBar::CheckNAND);
265   m_extract_certificates = m_manage_nand_menu->addAction(tr("Extract Certificates from NAND"), this,
266                                                          &MenuBar::NANDExtractCertificates);
267 
268   m_boot_sysmenu->setEnabled(false);
269 
270   connect(&Settings::Instance(), &Settings::NANDRefresh, this, [this] { UpdateToolsMenu(false); });
271 
272   m_perform_online_update_menu = tools_menu->addMenu(tr("Perform Online System Update"));
273   m_perform_online_update_for_current_region = m_perform_online_update_menu->addAction(
274       tr("Current Region"), this, [this] { emit PerformOnlineUpdate(""); });
275   m_perform_online_update_menu->addSeparator();
276   m_perform_online_update_menu->addAction(tr("Europe"), this,
277                                           [this] { emit PerformOnlineUpdate("EUR"); });
278   m_perform_online_update_menu->addAction(tr("Japan"), this,
279                                           [this] { emit PerformOnlineUpdate("JPN"); });
280   m_perform_online_update_menu->addAction(tr("Korea"), this,
281                                           [this] { emit PerformOnlineUpdate("KOR"); });
282   m_perform_online_update_menu->addAction(tr("United States"), this,
283                                           [this] { emit PerformOnlineUpdate("USA"); });
284 
285   tools_menu->addSeparator();
286 
287   tools_menu->addAction(tr("Import Wii Save..."), this, &MenuBar::ImportWiiSave);
288   tools_menu->addAction(tr("Export All Wii Saves"), this, &MenuBar::ExportWiiSaves);
289 
290   QMenu* menu = new QMenu(tr("Connect Wii Remotes"), tools_menu);
291 
292   tools_menu->addSeparator();
293   tools_menu->addMenu(menu);
294 
295   for (int i = 0; i < 4; i++)
296   {
297     m_wii_remotes[i] = menu->addAction(tr("Connect Wii Remote %1").arg(i + 1), this,
298                                        [this, i] { emit ConnectWiiRemote(i); });
299     m_wii_remotes[i]->setCheckable(true);
300   }
301 
302   menu->addSeparator();
303 
304   m_wii_remotes[4] =
305       menu->addAction(tr("Connect Balance Board"), this, [this] { emit ConnectWiiRemote(4); });
306   m_wii_remotes[4]->setCheckable(true);
307 }
308 
AddEmulationMenu()309 void MenuBar::AddEmulationMenu()
310 {
311   QMenu* emu_menu = addMenu(tr("&Emulation"));
312   m_play_action = emu_menu->addAction(tr("&Play"), this, &MenuBar::Play);
313   m_pause_action = emu_menu->addAction(tr("&Pause"), this, &MenuBar::Pause);
314   m_stop_action = emu_menu->addAction(tr("&Stop"), this, &MenuBar::Stop);
315   m_reset_action = emu_menu->addAction(tr("&Reset"), this, &MenuBar::Reset);
316   m_fullscreen_action = emu_menu->addAction(tr("Toggle &Fullscreen"), this, &MenuBar::Fullscreen);
317   m_frame_advance_action = emu_menu->addAction(tr("&Frame Advance"), this, &MenuBar::FrameAdvance);
318 
319   m_screenshot_action = emu_menu->addAction(tr("Take Screenshot"), this, &MenuBar::Screenshot);
320 
321   emu_menu->addSeparator();
322 
323   AddStateLoadMenu(emu_menu);
324   AddStateSaveMenu(emu_menu);
325   AddStateSlotMenu(emu_menu);
326   UpdateStateSlotMenu();
327 
328   for (QMenu* menu : {m_state_load_menu, m_state_save_menu, m_state_slot_menu})
329     connect(menu, &QMenu::aboutToShow, this, &MenuBar::UpdateStateSlotMenu);
330 }
331 
AddStateLoadMenu(QMenu * emu_menu)332 void MenuBar::AddStateLoadMenu(QMenu* emu_menu)
333 {
334   m_state_load_menu = emu_menu->addMenu(tr("&Load State"));
335   m_state_load_menu->addAction(tr("Load State from File"), this, &MenuBar::StateLoad);
336   m_state_load_menu->addAction(tr("Load State from Selected Slot"), this, &MenuBar::StateLoadSlot);
337   m_state_load_slots_menu = m_state_load_menu->addMenu(tr("Load State from Slot"));
338   m_state_load_menu->addAction(tr("Undo Load State"), this, &MenuBar::StateLoadUndo);
339 
340   for (int i = 1; i <= 10; i++)
341   {
342     QAction* action = m_state_load_slots_menu->addAction(QString{});
343 
344     connect(action, &QAction::triggered, this, [=]() { emit StateLoadSlotAt(i); });
345   }
346 }
347 
AddStateSaveMenu(QMenu * emu_menu)348 void MenuBar::AddStateSaveMenu(QMenu* emu_menu)
349 {
350   m_state_save_menu = emu_menu->addMenu(tr("Sa&ve State"));
351   m_state_save_menu->addAction(tr("Save State to File"), this, &MenuBar::StateSave);
352   m_state_save_menu->addAction(tr("Save State to Selected Slot"), this, &MenuBar::StateSaveSlot);
353   m_state_save_menu->addAction(tr("Save State to Oldest Slot"), this, &MenuBar::StateSaveOldest);
354   m_state_save_slots_menu = m_state_save_menu->addMenu(tr("Save State to Slot"));
355   m_state_save_menu->addAction(tr("Undo Save State"), this, &MenuBar::StateSaveUndo);
356 
357   for (int i = 1; i <= 10; i++)
358   {
359     QAction* action = m_state_save_slots_menu->addAction(QString{});
360 
361     connect(action, &QAction::triggered, this, [=]() { emit StateSaveSlotAt(i); });
362   }
363 }
364 
AddStateSlotMenu(QMenu * emu_menu)365 void MenuBar::AddStateSlotMenu(QMenu* emu_menu)
366 {
367   m_state_slot_menu = emu_menu->addMenu(tr("Select State Slot"));
368   m_state_slots = new QActionGroup(this);
369 
370   for (int i = 1; i <= 10; i++)
371   {
372     QAction* action = m_state_slot_menu->addAction(QString{});
373     action->setCheckable(true);
374     action->setActionGroup(m_state_slots);
375     if (Settings::Instance().GetStateSlot() == i)
376       action->setChecked(true);
377 
378     connect(action, &QAction::triggered, this, [=]() { emit SetStateSlot(i); });
379   }
380 }
381 
UpdateStateSlotMenu()382 void MenuBar::UpdateStateSlotMenu()
383 {
384   QList<QAction*> actions_slot = m_state_slots->actions();
385   QList<QAction*> actions_load = m_state_load_slots_menu->actions();
386   QList<QAction*> actions_save = m_state_save_slots_menu->actions();
387   for (int i = 0; i < actions_slot.length(); i++)
388   {
389     int slot = i + 1;
390     QString info = QString::fromStdString(State::GetInfoStringOfSlot(slot));
391     actions_load.at(i)->setText(tr("Load from Slot %1 - %2").arg(slot).arg(info));
392     actions_save.at(i)->setText(tr("Save to Slot %1 - %2").arg(slot).arg(info));
393     actions_slot.at(i)->setText(tr("Select Slot %1 - %2").arg(slot).arg(info));
394   }
395 }
396 
AddViewMenu()397 void MenuBar::AddViewMenu()
398 {
399   QMenu* view_menu = addMenu(tr("&View"));
400   QAction* show_log = view_menu->addAction(tr("Show &Log"));
401   show_log->setCheckable(true);
402   show_log->setChecked(Settings::Instance().IsLogVisible());
403 
404   connect(show_log, &QAction::toggled, &Settings::Instance(), &Settings::SetLogVisible);
405 
406   QAction* show_log_config = view_menu->addAction(tr("Show Log &Configuration"));
407   show_log_config->setCheckable(true);
408   show_log_config->setChecked(Settings::Instance().IsLogConfigVisible());
409 
410   connect(show_log_config, &QAction::toggled, &Settings::Instance(),
411           &Settings::SetLogConfigVisible);
412 
413   QAction* show_toolbar = view_menu->addAction(tr("Show &Toolbar"));
414   show_toolbar->setCheckable(true);
415   show_toolbar->setChecked(Settings::Instance().IsToolBarVisible());
416 
417   connect(show_toolbar, &QAction::toggled, &Settings::Instance(), &Settings::SetToolBarVisible);
418 
419   connect(&Settings::Instance(), &Settings::LogVisibilityChanged, show_log, &QAction::setChecked);
420   connect(&Settings::Instance(), &Settings::LogConfigVisibilityChanged, show_log_config,
421           &QAction::setChecked);
422   connect(&Settings::Instance(), &Settings::ToolBarVisibilityChanged, show_toolbar,
423           &QAction::setChecked);
424 
425   QAction* lock_widgets = view_menu->addAction(tr("&Lock Widgets In Place"));
426   lock_widgets->setCheckable(true);
427   lock_widgets->setChecked(Settings::Instance().AreWidgetsLocked());
428 
429   connect(lock_widgets, &QAction::toggled, &Settings::Instance(), &Settings::SetWidgetsLocked);
430 
431   view_menu->addSeparator();
432 
433   m_show_code = view_menu->addAction(tr("&Code"));
434   m_show_code->setCheckable(true);
435   m_show_code->setChecked(Settings::Instance().IsCodeVisible());
436 
437   connect(m_show_code, &QAction::toggled, &Settings::Instance(), &Settings::SetCodeVisible);
438   connect(&Settings::Instance(), &Settings::CodeVisibilityChanged, m_show_code,
439           &QAction::setChecked);
440 
441   m_show_registers = view_menu->addAction(tr("&Registers"));
442   m_show_registers->setCheckable(true);
443   m_show_registers->setChecked(Settings::Instance().IsRegistersVisible());
444 
445   connect(m_show_registers, &QAction::toggled, &Settings::Instance(),
446           &Settings::SetRegistersVisible);
447   connect(&Settings::Instance(), &Settings::RegistersVisibilityChanged, m_show_registers,
448           &QAction::setChecked);
449 
450   m_show_threads = view_menu->addAction(tr("&Threads"));
451   m_show_threads->setCheckable(true);
452   m_show_threads->setChecked(Settings::Instance().IsThreadsVisible());
453 
454   connect(m_show_threads, &QAction::toggled, &Settings::Instance(), &Settings::SetThreadsVisible);
455   connect(&Settings::Instance(), &Settings::ThreadsVisibilityChanged, m_show_threads,
456           &QAction::setChecked);
457 
458   // i18n: This kind of "watch" is used for watching emulated memory.
459   // It's not related to timekeeping devices.
460   m_show_watch = view_menu->addAction(tr("&Watch"));
461   m_show_watch->setCheckable(true);
462   m_show_watch->setChecked(Settings::Instance().IsWatchVisible());
463 
464   connect(m_show_watch, &QAction::toggled, &Settings::Instance(), &Settings::SetWatchVisible);
465   connect(&Settings::Instance(), &Settings::WatchVisibilityChanged, m_show_watch,
466           &QAction::setChecked);
467 
468   m_show_breakpoints = view_menu->addAction(tr("&Breakpoints"));
469   m_show_breakpoints->setCheckable(true);
470   m_show_breakpoints->setChecked(Settings::Instance().IsBreakpointsVisible());
471 
472   connect(m_show_breakpoints, &QAction::toggled, &Settings::Instance(),
473           &Settings::SetBreakpointsVisible);
474   connect(&Settings::Instance(), &Settings::BreakpointsVisibilityChanged, m_show_breakpoints,
475           &QAction::setChecked);
476 
477   m_show_memory = view_menu->addAction(tr("&Memory"));
478   m_show_memory->setCheckable(true);
479   m_show_memory->setChecked(Settings::Instance().IsMemoryVisible());
480 
481   connect(m_show_memory, &QAction::toggled, &Settings::Instance(), &Settings::SetMemoryVisible);
482   connect(&Settings::Instance(), &Settings::MemoryVisibilityChanged, m_show_memory,
483           &QAction::setChecked);
484 
485   m_show_network = view_menu->addAction(tr("&Network"));
486   m_show_network->setCheckable(true);
487   m_show_network->setChecked(Settings::Instance().IsNetworkVisible());
488 
489   connect(m_show_network, &QAction::toggled, &Settings::Instance(), &Settings::SetNetworkVisible);
490   connect(&Settings::Instance(), &Settings::NetworkVisibilityChanged, m_show_network,
491           &QAction::setChecked);
492 
493   m_show_jit = view_menu->addAction(tr("&JIT"));
494   m_show_jit->setCheckable(true);
495   m_show_jit->setChecked(Settings::Instance().IsJITVisible());
496   connect(m_show_jit, &QAction::toggled, &Settings::Instance(), &Settings::SetJITVisible);
497   connect(&Settings::Instance(), &Settings::JITVisibilityChanged, m_show_jit, &QAction::setChecked);
498 
499   view_menu->addSeparator();
500 
501   AddGameListTypeSection(view_menu);
502   view_menu->addSeparator();
503   AddListColumnsMenu(view_menu);
504   view_menu->addSeparator();
505   AddShowPlatformsMenu(view_menu);
506   AddShowRegionsMenu(view_menu);
507 
508   view_menu->addSeparator();
509   view_menu->addAction(tr("Purge Game List Cache"), this, &MenuBar::PurgeGameListCache);
510   view_menu->addSeparator();
511   view_menu->addAction(tr("Search"), this, &MenuBar::ShowSearch, QKeySequence::Find);
512 }
513 
AddOptionsMenu()514 void MenuBar::AddOptionsMenu()
515 {
516   QMenu* options_menu = addMenu(tr("&Options"));
517   options_menu->addAction(tr("Co&nfiguration"), this, &MenuBar::Configure,
518                           QKeySequence::Preferences);
519   options_menu->addSeparator();
520   options_menu->addAction(tr("&Graphics Settings"), this, &MenuBar::ConfigureGraphics);
521   options_menu->addAction(tr("&Audio Settings"), this, &MenuBar::ConfigureAudio);
522   m_controllers_action =
523       options_menu->addAction(tr("&Controller Settings"), this, &MenuBar::ConfigureControllers);
524   options_menu->addAction(tr("&Hotkey Settings"), this, &MenuBar::ConfigureHotkeys);
525 
526   options_menu->addSeparator();
527 
528   // Debugging mode only
529   m_boot_to_pause = options_menu->addAction(tr("Boot to Pause"));
530   m_boot_to_pause->setCheckable(true);
531   m_boot_to_pause->setChecked(SConfig::GetInstance().bBootToPause);
532 
533   connect(m_boot_to_pause, &QAction::toggled, this,
534           [](bool enable) { SConfig::GetInstance().bBootToPause = enable; });
535 
536   m_automatic_start = options_menu->addAction(tr("&Automatic Start"));
537   m_automatic_start->setCheckable(true);
538   m_automatic_start->setChecked(SConfig::GetInstance().bAutomaticStart);
539 
540   connect(m_automatic_start, &QAction::toggled, this,
541           [](bool enable) { SConfig::GetInstance().bAutomaticStart = enable; });
542 
543   m_change_font = options_menu->addAction(tr("&Font..."), this, &MenuBar::ChangeDebugFont);
544 }
545 
InstallUpdateManually()546 void MenuBar::InstallUpdateManually()
547 {
548   auto& track = SConfig::GetInstance().m_auto_update_track;
549   auto previous_value = track;
550 
551   track = "dev";
552 
553   auto* updater = new Updater(this->parentWidget());
554 
555   if (!updater->CheckForUpdate())
556   {
557     ModalMessageBox::information(
558         this, tr("Update"),
559         tr("You are running the latest version available on this update track."));
560   }
561 
562   track = previous_value;
563 }
564 
AddHelpMenu()565 void MenuBar::AddHelpMenu()
566 {
567   QMenu* help_menu = addMenu(tr("&Help"));
568 
569   QAction* website = help_menu->addAction(tr("&Website"));
570   connect(website, &QAction::triggered, this,
571           []() { QDesktopServices::openUrl(QUrl(QStringLiteral("https://dolphin-emu.org/"))); });
572   QAction* documentation = help_menu->addAction(tr("Online &Documentation"));
573   connect(documentation, &QAction::triggered, this, []() {
574     QDesktopServices::openUrl(QUrl(QStringLiteral("https://dolphin-emu.org/docs/guides")));
575   });
576   QAction* github = help_menu->addAction(tr("&GitHub Repository"));
577   connect(github, &QAction::triggered, this, []() {
578     QDesktopServices::openUrl(QUrl(QStringLiteral("https://github.com/dolphin-emu/dolphin")));
579   });
580   QAction* bugtracker = help_menu->addAction(tr("&Bug Tracker"));
581   connect(bugtracker, &QAction::triggered, this, []() {
582     QDesktopServices::openUrl(
583         QUrl(QStringLiteral("https://bugs.dolphin-emu.org/projects/emulator")));
584   });
585 
586   if (AutoUpdateChecker::SystemSupportsAutoUpdates())
587   {
588     help_menu->addSeparator();
589 
590     help_menu->addAction(tr("&Check for Updates..."), this, &MenuBar::InstallUpdateManually);
591   }
592 
593 #ifndef __APPLE__
594   help_menu->addSeparator();
595 #endif
596 
597   help_menu->addAction(tr("&About"), this, &MenuBar::ShowAboutDialog);
598 }
599 
AddGameListTypeSection(QMenu * view_menu)600 void MenuBar::AddGameListTypeSection(QMenu* view_menu)
601 {
602   QAction* list_view = view_menu->addAction(tr("List View"));
603   list_view->setCheckable(true);
604 
605   QAction* grid_view = view_menu->addAction(tr("Grid View"));
606   grid_view->setCheckable(true);
607 
608   QActionGroup* list_group = new QActionGroup(this);
609   list_group->addAction(list_view);
610   list_group->addAction(grid_view);
611 
612   bool prefer_list = Settings::Instance().GetPreferredView();
613   list_view->setChecked(prefer_list);
614   grid_view->setChecked(!prefer_list);
615 
616   connect(list_view, &QAction::triggered, this, &MenuBar::ShowList);
617   connect(grid_view, &QAction::triggered, this, &MenuBar::ShowGrid);
618 }
619 
AddListColumnsMenu(QMenu * view_menu)620 void MenuBar::AddListColumnsMenu(QMenu* view_menu)
621 {
622   static const QMap<QString, bool*> columns{
623       {tr("Platform"), &SConfig::GetInstance().m_showSystemColumn},
624       {tr("Banner"), &SConfig::GetInstance().m_showBannerColumn},
625       {tr("Title"), &SConfig::GetInstance().m_showTitleColumn},
626       {tr("Description"), &SConfig::GetInstance().m_showDescriptionColumn},
627       {tr("Maker"), &SConfig::GetInstance().m_showMakerColumn},
628       {tr("File Name"), &SConfig::GetInstance().m_showFileNameColumn},
629       {tr("File Path"), &SConfig::GetInstance().m_showFilePathColumn},
630       {tr("Game ID"), &SConfig::GetInstance().m_showIDColumn},
631       {tr("Region"), &SConfig::GetInstance().m_showRegionColumn},
632       {tr("File Size"), &SConfig::GetInstance().m_showSizeColumn},
633       {tr("File Format"), &SConfig::GetInstance().m_showFileFormatColumn},
634       {tr("Block Size"), &SConfig::GetInstance().m_showBlockSizeColumn},
635       {tr("Compression"), &SConfig::GetInstance().m_showCompressionColumn},
636       {tr("Tags"), &SConfig::GetInstance().m_showTagsColumn}};
637 
638   QActionGroup* column_group = new QActionGroup(this);
639   m_cols_menu = view_menu->addMenu(tr("List Columns"));
640   column_group->setExclusive(false);
641 
642   for (const auto& key : columns.keys())
643   {
644     bool* config = columns[key];
645     QAction* action = column_group->addAction(m_cols_menu->addAction(key));
646     action->setCheckable(true);
647     action->setChecked(*config);
648     connect(action, &QAction::toggled, [this, config, key](bool value) {
649       *config = value;
650       emit ColumnVisibilityToggled(key, value);
651     });
652   }
653 }
654 
AddShowPlatformsMenu(QMenu * view_menu)655 void MenuBar::AddShowPlatformsMenu(QMenu* view_menu)
656 {
657   static const QMap<QString, bool*> platform_map{
658       {tr("Show Wii"), &SConfig::GetInstance().m_ListWii},
659       {tr("Show GameCube"), &SConfig::GetInstance().m_ListGC},
660       {tr("Show WAD"), &SConfig::GetInstance().m_ListWad},
661       {tr("Show ELF/DOL"), &SConfig::GetInstance().m_ListElfDol}};
662 
663   QActionGroup* platform_group = new QActionGroup(this);
664   QMenu* plat_menu = view_menu->addMenu(tr("Show Platforms"));
665   platform_group->setExclusive(false);
666 
667   for (const auto& key : platform_map.keys())
668   {
669     bool* config = platform_map[key];
670     QAction* action = platform_group->addAction(plat_menu->addAction(key));
671     action->setCheckable(true);
672     action->setChecked(*config);
673     connect(action, &QAction::toggled, [this, config, key](bool value) {
674       *config = value;
675       emit GameListPlatformVisibilityToggled(key, value);
676     });
677   }
678 }
679 
AddShowRegionsMenu(QMenu * view_menu)680 void MenuBar::AddShowRegionsMenu(QMenu* view_menu)
681 {
682   static const QMap<QString, bool*> region_map{
683       {tr("Show JAP"), &SConfig::GetInstance().m_ListJap},
684       {tr("Show PAL"), &SConfig::GetInstance().m_ListPal},
685       {tr("Show USA"), &SConfig::GetInstance().m_ListUsa},
686       {tr("Show Australia"), &SConfig::GetInstance().m_ListAustralia},
687       {tr("Show France"), &SConfig::GetInstance().m_ListFrance},
688       {tr("Show Germany"), &SConfig::GetInstance().m_ListGermany},
689       {tr("Show Italy"), &SConfig::GetInstance().m_ListItaly},
690       {tr("Show Korea"), &SConfig::GetInstance().m_ListKorea},
691       {tr("Show Netherlands"), &SConfig::GetInstance().m_ListNetherlands},
692       {tr("Show Russia"), &SConfig::GetInstance().m_ListRussia},
693       {tr("Show Spain"), &SConfig::GetInstance().m_ListSpain},
694       {tr("Show Taiwan"), &SConfig::GetInstance().m_ListTaiwan},
695       {tr("Show World"), &SConfig::GetInstance().m_ListWorld},
696       {tr("Show Unknown"), &SConfig::GetInstance().m_ListUnknown}};
697 
698   QActionGroup* region_group = new QActionGroup(this);
699   QMenu* region_menu = view_menu->addMenu(tr("Show Regions"));
700   region_group->setExclusive(false);
701 
702   for (const auto& key : region_map.keys())
703   {
704     bool* config = region_map[key];
705     QAction* action = region_group->addAction(region_menu->addAction(key));
706     action->setCheckable(true);
707     action->setChecked(*config);
708     connect(action, &QAction::toggled, [this, config, key](bool value) {
709       *config = value;
710       emit GameListRegionVisibilityToggled(key, value);
711     });
712   }
713 }
714 
AddMovieMenu()715 void MenuBar::AddMovieMenu()
716 {
717   auto* movie_menu = addMenu(tr("&Movie"));
718   m_recording_start =
719       movie_menu->addAction(tr("Start Re&cording Input"), this, [this] { emit StartRecording(); });
720   m_recording_play =
721       movie_menu->addAction(tr("P&lay Input Recording..."), this, [this] { emit PlayRecording(); });
722   m_recording_stop = movie_menu->addAction(tr("Stop Playing/Recording Input"), this,
723                                            [this] { emit StopRecording(); });
724   m_recording_export =
725       movie_menu->addAction(tr("Export Recording..."), this, [this] { emit ExportRecording(); });
726 
727   m_recording_start->setEnabled(false);
728   m_recording_play->setEnabled(false);
729   m_recording_stop->setEnabled(false);
730   m_recording_export->setEnabled(false);
731 
732   m_recording_read_only = movie_menu->addAction(tr("&Read-Only Mode"));
733   m_recording_read_only->setCheckable(true);
734   m_recording_read_only->setChecked(Movie::IsReadOnly());
735   connect(m_recording_read_only, &QAction::toggled, [](bool value) { Movie::SetReadOnly(value); });
736 
737   movie_menu->addAction(tr("TAS Input"), this, [this] { emit ShowTASInput(); });
738 
739   movie_menu->addSeparator();
740 
741   auto* pause_at_end = movie_menu->addAction(tr("Pause at End of Movie"));
742   pause_at_end->setCheckable(true);
743   pause_at_end->setChecked(SConfig::GetInstance().m_PauseMovie);
744   connect(pause_at_end, &QAction::toggled,
745           [](bool value) { SConfig::GetInstance().m_PauseMovie = value; });
746 
747   auto* lag_counter = movie_menu->addAction(tr("Show Lag Counter"));
748   lag_counter->setCheckable(true);
749   lag_counter->setChecked(SConfig::GetInstance().m_ShowLag);
750   connect(lag_counter, &QAction::toggled,
751           [](bool value) { SConfig::GetInstance().m_ShowLag = value; });
752 
753   auto* frame_counter = movie_menu->addAction(tr("Show Frame Counter"));
754   frame_counter->setCheckable(true);
755   frame_counter->setChecked(SConfig::GetInstance().m_ShowFrameCount);
756   connect(frame_counter, &QAction::toggled,
757           [](bool value) { SConfig::GetInstance().m_ShowFrameCount = value; });
758 
759   auto* input_display = movie_menu->addAction(tr("Show Input Display"));
760   input_display->setCheckable(true);
761   input_display->setChecked(SConfig::GetInstance().m_ShowInputDisplay);
762   connect(input_display, &QAction::toggled,
763           [](bool value) { SConfig::GetInstance().m_ShowInputDisplay = value; });
764 
765   auto* system_clock = movie_menu->addAction(tr("Show System Clock"));
766   system_clock->setCheckable(true);
767   system_clock->setChecked(SConfig::GetInstance().m_ShowRTC);
768   connect(system_clock, &QAction::toggled,
769           [](bool value) { SConfig::GetInstance().m_ShowRTC = value; });
770 
771   movie_menu->addSeparator();
772 
773   auto* dump_frames = movie_menu->addAction(tr("Dump Frames"));
774   dump_frames->setCheckable(true);
775   dump_frames->setChecked(SConfig::GetInstance().m_DumpFrames);
776   connect(dump_frames, &QAction::toggled,
777           [](bool value) { SConfig::GetInstance().m_DumpFrames = value; });
778 
779   auto* dump_audio = movie_menu->addAction(tr("Dump Audio"));
780   dump_audio->setCheckable(true);
781   dump_audio->setChecked(SConfig::GetInstance().m_DumpAudio);
782   connect(dump_audio, &QAction::toggled,
783           [](bool value) { SConfig::GetInstance().m_DumpAudio = value; });
784 }
785 
AddJITMenu()786 void MenuBar::AddJITMenu()
787 {
788   m_jit = addMenu(tr("JIT"));
789 
790   m_jit_interpreter_core = m_jit->addAction(tr("Interpreter Core"));
791   m_jit_interpreter_core->setCheckable(true);
792   m_jit_interpreter_core->setChecked(SConfig::GetInstance().cpu_core ==
793                                      PowerPC::CPUCore::Interpreter);
794 
795   connect(m_jit_interpreter_core, &QAction::toggled, [](bool enabled) {
796     PowerPC::SetMode(enabled ? PowerPC::CoreMode::Interpreter : PowerPC::CoreMode::JIT);
797   });
798 
799   m_jit->addSeparator();
800 
801   m_jit_block_linking = m_jit->addAction(tr("JIT Block Linking Off"));
802   m_jit_block_linking->setCheckable(true);
803   m_jit_block_linking->setChecked(SConfig::GetInstance().bJITNoBlockLinking);
804   connect(m_jit_block_linking, &QAction::toggled, [this](bool enabled) {
805     SConfig::GetInstance().bJITNoBlockLinking = enabled;
806     ClearCache();
807   });
808 
809   m_jit_disable_cache = m_jit->addAction(tr("Disable JIT Cache"));
810   m_jit_disable_cache->setCheckable(true);
811   m_jit_disable_cache->setChecked(SConfig::GetInstance().bJITNoBlockCache);
812   connect(m_jit_disable_cache, &QAction::toggled, [this](bool enabled) {
813     SConfig::GetInstance().bJITNoBlockCache = enabled;
814     ClearCache();
815   });
816 
817   m_jit_disable_fastmem = m_jit->addAction(tr("Disable Fastmem"));
818   m_jit_disable_fastmem->setCheckable(true);
819   m_jit_disable_fastmem->setChecked(!SConfig::GetInstance().bFastmem);
820   connect(m_jit_disable_fastmem, &QAction::toggled, [this](bool enabled) {
821     SConfig::GetInstance().bFastmem = !enabled;
822     ClearCache();
823   });
824 
825   m_jit_clear_cache = m_jit->addAction(tr("Clear Cache"), this, &MenuBar::ClearCache);
826 
827   m_jit->addSeparator();
828 
829   m_jit_log_coverage =
830       m_jit->addAction(tr("Log JIT Instruction Coverage"), this, &MenuBar::LogInstructions);
831   m_jit_search_instruction =
832       m_jit->addAction(tr("Search for an Instruction"), this, &MenuBar::SearchInstruction);
833 
834   m_jit->addSeparator();
835 
836   m_jit_off = m_jit->addAction(tr("JIT Off (JIT Core)"));
837   m_jit_off->setCheckable(true);
838   m_jit_off->setChecked(SConfig::GetInstance().bJITOff);
839   connect(m_jit_off, &QAction::toggled, [this](bool enabled) {
840     SConfig::GetInstance().bJITOff = enabled;
841     ClearCache();
842   });
843 
844   m_jit_loadstore_off = m_jit->addAction(tr("JIT LoadStore Off"));
845   m_jit_loadstore_off->setCheckable(true);
846   m_jit_loadstore_off->setChecked(SConfig::GetInstance().bJITLoadStoreOff);
847   connect(m_jit_loadstore_off, &QAction::toggled, [this](bool enabled) {
848     SConfig::GetInstance().bJITLoadStoreOff = enabled;
849     ClearCache();
850   });
851 
852   m_jit_loadstore_lbzx_off = m_jit->addAction(tr("JIT LoadStore lbzx Off"));
853   m_jit_loadstore_lbzx_off->setCheckable(true);
854   m_jit_loadstore_lbzx_off->setChecked(SConfig::GetInstance().bJITLoadStorelbzxOff);
855   connect(m_jit_loadstore_lbzx_off, &QAction::toggled, [this](bool enabled) {
856     SConfig::GetInstance().bJITLoadStorelbzxOff = enabled;
857     ClearCache();
858   });
859 
860   m_jit_loadstore_lxz_off = m_jit->addAction(tr("JIT LoadStore lXz Off"));
861   m_jit_loadstore_lxz_off->setCheckable(true);
862   m_jit_loadstore_lxz_off->setChecked(SConfig::GetInstance().bJITLoadStorelXzOff);
863   connect(m_jit_loadstore_lxz_off, &QAction::toggled, [this](bool enabled) {
864     SConfig::GetInstance().bJITLoadStorelXzOff = enabled;
865     ClearCache();
866   });
867 
868   m_jit_loadstore_lwz_off = m_jit->addAction(tr("JIT LoadStore lwz Off"));
869   m_jit_loadstore_lwz_off->setCheckable(true);
870   m_jit_loadstore_lwz_off->setChecked(SConfig::GetInstance().bJITLoadStorelwzOff);
871   connect(m_jit_loadstore_lwz_off, &QAction::toggled, [this](bool enabled) {
872     SConfig::GetInstance().bJITLoadStorelwzOff = enabled;
873     ClearCache();
874   });
875 
876   m_jit_loadstore_floating_off = m_jit->addAction(tr("JIT LoadStore Floating Off"));
877   m_jit_loadstore_floating_off->setCheckable(true);
878   m_jit_loadstore_floating_off->setChecked(SConfig::GetInstance().bJITLoadStoreFloatingOff);
879   connect(m_jit_loadstore_floating_off, &QAction::toggled, [this](bool enabled) {
880     SConfig::GetInstance().bJITLoadStoreFloatingOff = enabled;
881     ClearCache();
882   });
883 
884   m_jit_loadstore_paired_off = m_jit->addAction(tr("JIT LoadStore Paired Off"));
885   m_jit_loadstore_paired_off->setCheckable(true);
886   m_jit_loadstore_paired_off->setChecked(SConfig::GetInstance().bJITLoadStorePairedOff);
887   connect(m_jit_loadstore_paired_off, &QAction::toggled, [this](bool enabled) {
888     SConfig::GetInstance().bJITLoadStorePairedOff = enabled;
889     ClearCache();
890   });
891 
892   m_jit_floatingpoint_off = m_jit->addAction(tr("JIT FloatingPoint Off"));
893   m_jit_floatingpoint_off->setCheckable(true);
894   m_jit_floatingpoint_off->setChecked(SConfig::GetInstance().bJITFloatingPointOff);
895   connect(m_jit_floatingpoint_off, &QAction::toggled, [this](bool enabled) {
896     SConfig::GetInstance().bJITFloatingPointOff = enabled;
897     ClearCache();
898   });
899 
900   m_jit_integer_off = m_jit->addAction(tr("JIT Integer Off"));
901   m_jit_integer_off->setCheckable(true);
902   m_jit_integer_off->setChecked(SConfig::GetInstance().bJITIntegerOff);
903   connect(m_jit_integer_off, &QAction::toggled, [this](bool enabled) {
904     SConfig::GetInstance().bJITIntegerOff = enabled;
905     ClearCache();
906   });
907 
908   m_jit_paired_off = m_jit->addAction(tr("JIT Paired Off"));
909   m_jit_paired_off->setCheckable(true);
910   m_jit_paired_off->setChecked(SConfig::GetInstance().bJITPairedOff);
911   connect(m_jit_paired_off, &QAction::toggled, [this](bool enabled) {
912     SConfig::GetInstance().bJITPairedOff = enabled;
913     ClearCache();
914   });
915 
916   m_jit_systemregisters_off = m_jit->addAction(tr("JIT SystemRegisters Off"));
917   m_jit_systemregisters_off->setCheckable(true);
918   m_jit_systemregisters_off->setChecked(SConfig::GetInstance().bJITSystemRegistersOff);
919   connect(m_jit_systemregisters_off, &QAction::toggled, [this](bool enabled) {
920     SConfig::GetInstance().bJITSystemRegistersOff = enabled;
921     ClearCache();
922   });
923 
924   m_jit_branch_off = m_jit->addAction(tr("JIT Branch Off"));
925   m_jit_branch_off->setCheckable(true);
926   m_jit_branch_off->setChecked(SConfig::GetInstance().bJITBranchOff);
927   connect(m_jit_branch_off, &QAction::toggled, [this](bool enabled) {
928     SConfig::GetInstance().bJITBranchOff = enabled;
929     ClearCache();
930   });
931 
932   m_jit_register_cache_off = m_jit->addAction(tr("JIT Register Cache Off"));
933   m_jit_register_cache_off->setCheckable(true);
934   m_jit_register_cache_off->setChecked(SConfig::GetInstance().bJITRegisterCacheOff);
935   connect(m_jit_register_cache_off, &QAction::toggled, [this](bool enabled) {
936     SConfig::GetInstance().bJITRegisterCacheOff = enabled;
937     ClearCache();
938   });
939 }
940 
AddSymbolsMenu()941 void MenuBar::AddSymbolsMenu()
942 {
943   m_symbols = addMenu(tr("Symbols"));
944 
945   m_symbols->addAction(tr("&Clear Symbols"), this, &MenuBar::ClearSymbols);
946 
947   auto* generate = m_symbols->addMenu(tr("&Generate Symbols From"));
948   generate->addAction(tr("Address"), this, &MenuBar::GenerateSymbolsFromAddress);
949   generate->addAction(tr("Signature Database"), this, &MenuBar::GenerateSymbolsFromSignatureDB);
950   generate->addAction(tr("RSO Modules"), this, &MenuBar::GenerateSymbolsFromRSO);
951   m_symbols->addSeparator();
952 
953   m_symbols->addAction(tr("&Load Symbol Map"), this, &MenuBar::LoadSymbolMap);
954   m_symbols->addAction(tr("&Save Symbol Map"), this, &MenuBar::SaveSymbolMap);
955   m_symbols->addSeparator();
956 
957   m_symbols->addAction(tr("Load &Other Map File..."), this, &MenuBar::LoadOtherSymbolMap);
958   m_symbols->addAction(tr("Load &Bad Map File..."), this, &MenuBar::LoadBadSymbolMap);
959   m_symbols->addAction(tr("Save Symbol Map &As..."), this, &MenuBar::SaveSymbolMapAs);
960   m_symbols->addSeparator();
961 
962   m_symbols->addAction(tr("Sa&ve Code"), this, &MenuBar::SaveCode);
963   m_symbols->addSeparator();
964 
965   m_symbols->addAction(tr("C&reate Signature File..."), this, &MenuBar::CreateSignatureFile);
966   m_symbols->addAction(tr("Append to &Existing Signature File..."), this,
967                        &MenuBar::AppendSignatureFile);
968   m_symbols->addAction(tr("Combine &Two Signature Files..."), this,
969                        &MenuBar::CombineSignatureFiles);
970   m_symbols->addAction(tr("Appl&y Signature File..."), this, &MenuBar::ApplySignatureFile);
971   m_symbols->addSeparator();
972 
973   m_symbols->addAction(tr("&Patch HLE Functions"), this, &MenuBar::PatchHLEFunctions);
974 }
975 
UpdateToolsMenu(bool emulation_started)976 void MenuBar::UpdateToolsMenu(bool emulation_started)
977 {
978   m_boot_sysmenu->setEnabled(!emulation_started);
979   m_perform_online_update_menu->setEnabled(!emulation_started);
980   m_ntscj_ipl->setEnabled(!emulation_started &&
981                           File::Exists(SConfig::GetInstance().GetBootROMPath(JAP_DIR)));
982   m_ntscu_ipl->setEnabled(!emulation_started &&
983                           File::Exists(SConfig::GetInstance().GetBootROMPath(USA_DIR)));
984   m_pal_ipl->setEnabled(!emulation_started &&
985                         File::Exists(SConfig::GetInstance().GetBootROMPath(EUR_DIR)));
986   m_import_backup->setEnabled(!emulation_started);
987   m_check_nand->setEnabled(!emulation_started);
988 
989   if (!emulation_started)
990   {
991     IOS::HLE::Kernel ios;
992     const auto tmd = ios.GetES()->FindInstalledTMD(Titles::SYSTEM_MENU);
993 
994     const QString sysmenu_version =
995         tmd.IsValid() ?
996             QString::fromStdString(DiscIO::GetSysMenuVersionString(tmd.GetTitleVersion())) :
997             QString{};
998     m_boot_sysmenu->setText(tr("Load Wii System Menu %1").arg(sysmenu_version));
999 
1000     m_boot_sysmenu->setEnabled(tmd.IsValid());
1001 
1002     for (QAction* action : m_perform_online_update_menu->actions())
1003       action->setEnabled(!tmd.IsValid());
1004     m_perform_online_update_for_current_region->setEnabled(tmd.IsValid());
1005   }
1006 
1007   const auto ios = IOS::HLE::GetIOS();
1008   const auto bt = ios ? std::static_pointer_cast<IOS::HLE::Device::BluetoothEmu>(
1009                             ios->GetDeviceByName("/dev/usb/oh1/57e/305")) :
1010                         nullptr;
1011   const bool enable_wiimotes =
1012       emulation_started && bt && !SConfig::GetInstance().m_bt_passthrough_enabled;
1013 
1014   for (std::size_t i = 0; i < m_wii_remotes.size(); i++)
1015   {
1016     QAction* const wii_remote = m_wii_remotes[i];
1017 
1018     wii_remote->setEnabled(enable_wiimotes);
1019     if (enable_wiimotes)
1020       wii_remote->setChecked(bt->AccessWiimoteByIndex(i)->IsConnected());
1021   }
1022 }
1023 
InstallWAD()1024 void MenuBar::InstallWAD()
1025 {
1026   QString wad_file = QFileDialog::getOpenFileName(this, tr("Select a title to install to NAND"),
1027                                                   QString(), tr("WAD files (*.wad)"));
1028 
1029   if (wad_file.isEmpty())
1030     return;
1031 
1032   if (WiiUtils::InstallWAD(wad_file.toStdString()))
1033   {
1034     Settings::Instance().NANDRefresh();
1035     ModalMessageBox::information(this, tr("Success"),
1036                                  tr("Successfully installed this title to the NAND."));
1037   }
1038   else
1039   {
1040     ModalMessageBox::critical(this, tr("Failure"), tr("Failed to install this title to the NAND."));
1041   }
1042 }
1043 
ImportWiiSave()1044 void MenuBar::ImportWiiSave()
1045 {
1046   QString file = QFileDialog::getOpenFileName(this, tr("Select the save file"), QDir::currentPath(),
1047                                               tr("Wii save files (*.bin);;"
1048                                                  "All Files (*)"));
1049 
1050   if (file.isEmpty())
1051     return;
1052 
1053   bool cancelled = false;
1054   auto can_overwrite = [&] {
1055     bool yes = ModalMessageBox::question(
1056                    this, tr("Save Import"),
1057                    tr("Save data for this title already exists in the NAND. Consider backing up "
1058                       "the current data before overwriting.\nOverwrite now?")) == QMessageBox::Yes;
1059     cancelled = !yes;
1060     return yes;
1061   };
1062   if (WiiSave::Import(file.toStdString(), can_overwrite))
1063     ModalMessageBox::information(this, tr("Save Import"), tr("Successfully imported save files."));
1064   else if (!cancelled)
1065     ModalMessageBox::critical(this, tr("Save Import"), tr("Failed to import save files."));
1066 }
1067 
ExportWiiSaves()1068 void MenuBar::ExportWiiSaves()
1069 {
1070   const QString export_dir = QFileDialog::getExistingDirectory(
1071       this, tr("Select Export Directory"), QString::fromStdString(File::GetUserPath(D_USER_IDX)),
1072       QFileDialog::ShowDirsOnly);
1073   if (export_dir.isEmpty())
1074     return;
1075 
1076   const size_t count = WiiSave::ExportAll(export_dir.toStdString());
1077   ModalMessageBox::information(this, tr("Save Export"),
1078                                tr("Exported %n save(s)", "", static_cast<int>(count)));
1079 }
1080 
CheckNAND()1081 void MenuBar::CheckNAND()
1082 {
1083   IOS::HLE::Kernel ios;
1084   WiiUtils::NANDCheckResult result = WiiUtils::CheckNAND(ios);
1085   if (!result.bad)
1086   {
1087     ModalMessageBox::information(this, tr("NAND Check"), tr("No issues have been detected."));
1088     return;
1089   }
1090 
1091   QString message = tr("The emulated NAND is damaged. System titles such as the Wii Menu and "
1092                        "the Wii Shop Channel may not work correctly.\n\n"
1093                        "Do you want to try to repair the NAND?");
1094   if (!result.titles_to_remove.empty())
1095   {
1096     std::string title_listings;
1097     Core::TitleDatabase title_db;
1098     const DiscIO::Language language = SConfig::GetInstance().GetCurrentLanguage(true);
1099     for (const u64 title_id : result.titles_to_remove)
1100     {
1101       title_listings += StringFromFormat("%016" PRIx64, title_id);
1102 
1103       const std::string database_name = title_db.GetChannelName(title_id, language);
1104       if (!database_name.empty())
1105       {
1106         title_listings += " - " + database_name;
1107       }
1108       else
1109       {
1110         DiscIO::WiiSaveBanner banner(title_id);
1111         if (banner.IsValid())
1112         {
1113           title_listings += " - " + banner.GetName();
1114           const std::string description = banner.GetDescription();
1115           if (!StripSpaces(description).empty())
1116             title_listings += " - " + description;
1117         }
1118       }
1119 
1120       title_listings += "\n";
1121     }
1122 
1123     message += tr("\n\nWARNING: Fixing this NAND requires the deletion of titles that have "
1124                   "incomplete data on the NAND, including all associated save data. "
1125                   "By continuing, the following title(s) will be removed:\n\n"
1126                   "%1"
1127                   "\nLaunching these titles may also fix the issues.")
1128                    .arg(QString::fromStdString(title_listings));
1129   }
1130 
1131   if (ModalMessageBox::question(this, tr("NAND Check"), message) != QMessageBox::Yes)
1132     return;
1133 
1134   if (WiiUtils::RepairNAND(ios))
1135   {
1136     ModalMessageBox::information(this, tr("NAND Check"), tr("The NAND has been repaired."));
1137     return;
1138   }
1139 
1140   ModalMessageBox::critical(this, tr("NAND Check"),
1141                             tr("The NAND could not be repaired. It is recommended to back up "
1142                                "your current data and start over with a fresh NAND."));
1143 }
1144 
NANDExtractCertificates()1145 void MenuBar::NANDExtractCertificates()
1146 {
1147   if (DiscIO::NANDImporter().ExtractCertificates(File::GetUserPath(D_WIIROOT_IDX)))
1148   {
1149     ModalMessageBox::information(this, tr("Success"),
1150                                  tr("Successfully extracted certificates from NAND"));
1151   }
1152   else
1153   {
1154     ModalMessageBox::critical(this, tr("Error"), tr("Failed to extract certificates from NAND"));
1155   }
1156 }
1157 
OnSelectionChanged(std::shared_ptr<const UICommon::GameFile> game_file)1158 void MenuBar::OnSelectionChanged(std::shared_ptr<const UICommon::GameFile> game_file)
1159 {
1160   m_game_selected = !!game_file;
1161 
1162   m_recording_play->setEnabled(m_game_selected && !Core::IsRunning());
1163   m_recording_start->setEnabled((m_game_selected || Core::IsRunning()) && !Movie::IsPlayingInput());
1164 }
1165 
OnRecordingStatusChanged(bool recording)1166 void MenuBar::OnRecordingStatusChanged(bool recording)
1167 {
1168   m_recording_start->setEnabled(!recording && (m_game_selected || Core::IsRunning()));
1169   m_recording_stop->setEnabled(recording);
1170   m_recording_export->setEnabled(recording);
1171 }
1172 
OnReadOnlyModeChanged(bool read_only)1173 void MenuBar::OnReadOnlyModeChanged(bool read_only)
1174 {
1175   m_recording_read_only->setChecked(read_only);
1176 }
1177 
ChangeDebugFont()1178 void MenuBar::ChangeDebugFont()
1179 {
1180   bool okay;
1181   QFont font = QFontDialog::getFont(&okay, Settings::Instance().GetDebugFont(), this,
1182                                     tr("Pick a debug font"));
1183 
1184   if (okay)
1185     Settings::Instance().SetDebugFont(font);
1186 }
1187 
ClearSymbols()1188 void MenuBar::ClearSymbols()
1189 {
1190   auto result = ModalMessageBox::warning(this, tr("Confirmation"),
1191                                          tr("Do you want to clear the list of symbol names?"),
1192                                          QMessageBox::Yes | QMessageBox::Cancel);
1193 
1194   if (result == QMessageBox::Cancel)
1195     return;
1196 
1197   g_symbolDB.Clear();
1198   emit NotifySymbolsUpdated();
1199 }
1200 
GenerateSymbolsFromAddress()1201 void MenuBar::GenerateSymbolsFromAddress()
1202 {
1203   PPCAnalyst::FindFunctions(Memory::MEM1_BASE_ADDR,
1204                             Memory::MEM1_BASE_ADDR + Memory::GetRamSizeReal(), &g_symbolDB);
1205   emit NotifySymbolsUpdated();
1206 }
1207 
GenerateSymbolsFromSignatureDB()1208 void MenuBar::GenerateSymbolsFromSignatureDB()
1209 {
1210   PPCAnalyst::FindFunctions(Memory::MEM1_BASE_ADDR,
1211                             Memory::MEM1_BASE_ADDR + Memory::GetRamSizeReal(), &g_symbolDB);
1212   SignatureDB db(SignatureDB::HandlerType::DSY);
1213   if (db.Load(File::GetSysDirectory() + TOTALDB))
1214   {
1215     db.Apply(&g_symbolDB);
1216     ModalMessageBox::information(
1217         this, tr("Information"),
1218         tr("Generated symbol names from '%1'").arg(QString::fromStdString(TOTALDB)));
1219     db.List();
1220   }
1221   else
1222   {
1223     ModalMessageBox::critical(
1224         this, tr("Error"),
1225         tr("'%1' not found, no symbol names generated").arg(QString::fromStdString(TOTALDB)));
1226   }
1227 
1228   emit NotifySymbolsUpdated();
1229 }
1230 
GenerateSymbolsFromRSO()1231 void MenuBar::GenerateSymbolsFromRSO()
1232 {
1233   // i18n: RSO refers to a proprietary format for shared objects (like DLL files).
1234   const int ret =
1235       ModalMessageBox::question(this, tr("RSO auto-detection"), tr("Auto-detect RSO modules?"));
1236   if (ret == QMessageBox::Yes)
1237     return GenerateSymbolsFromRSOAuto();
1238 
1239   QString text = QInputDialog::getText(this, tr("Input"), tr("Enter the RSO module address:"));
1240   bool good;
1241   uint address = text.toUInt(&good, 16);
1242 
1243   if (!good)
1244   {
1245     ModalMessageBox::warning(this, tr("Error"), tr("Invalid RSO module address: %1").arg(text));
1246     return;
1247   }
1248 
1249   RSOChainView rso_chain;
1250   if (rso_chain.Load(static_cast<u32>(address)))
1251   {
1252     rso_chain.Apply(&g_symbolDB);
1253     emit NotifySymbolsUpdated();
1254   }
1255   else
1256   {
1257     ModalMessageBox::warning(this, tr("Error"), tr("Failed to load RSO module at %1").arg(text));
1258   }
1259 }
1260 
GenerateSymbolsFromRSOAuto()1261 void MenuBar::GenerateSymbolsFromRSOAuto()
1262 {
1263   constexpr std::array<std::string_view, 2> search_for = {".elf", ".plf"};
1264   const AddressSpace::Accessors* accessors =
1265       AddressSpace::GetAccessors(AddressSpace::Type::Effective);
1266   std::vector<std::pair<u32, std::string>> matches;
1267 
1268   // Find filepath to elf/plf commonly used by RSO modules
1269   for (const auto& str : search_for)
1270   {
1271     u32 next = 0;
1272     while (true)
1273     {
1274       auto found_addr =
1275           accessors->Search(next, reinterpret_cast<const u8*>(str.data()), str.size() + 1, true);
1276 
1277       if (!found_addr.has_value())
1278         break;
1279       next = *found_addr + 1;
1280 
1281       // Get the beginning of the string
1282       found_addr = accessors->Search(*found_addr, reinterpret_cast<const u8*>(""), 1, false);
1283       if (!found_addr.has_value())
1284         continue;
1285 
1286       // Get the string reference
1287       const u32 ref_addr = *found_addr + 1;
1288       const std::array<u8, 4> ref = {static_cast<u8>(ref_addr >> 24),
1289                                      static_cast<u8>(ref_addr >> 16),
1290                                      static_cast<u8>(ref_addr >> 8), static_cast<u8>(ref_addr)};
1291       found_addr = accessors->Search(ref_addr, ref.data(), ref.size(), false);
1292       if (!found_addr.has_value() || *found_addr < 16)
1293         continue;
1294 
1295       // Go to the beginning of the RSO header
1296       matches.emplace_back(*found_addr - 16, PowerPC::HostGetString(ref_addr, 128));
1297     }
1298   }
1299 
1300   QStringList items;
1301   for (const auto& match : matches)
1302   {
1303     const QString item = QLatin1String("%1 %2");
1304 
1305     items << item.arg(QString::number(match.first, 16), QString::fromStdString(match.second));
1306   }
1307 
1308   if (items.empty())
1309   {
1310     ModalMessageBox::warning(this, tr("Error"), tr("Unable to auto-detect RSO module"));
1311     return;
1312   }
1313 
1314   bool ok;
1315   const QString item = QInputDialog::getItem(
1316       this, tr("Input"), tr("Select the RSO module address:"), items, 0, false, &ok);
1317 
1318   if (!ok)
1319     return;
1320 
1321   RSOChainView rso_chain;
1322   const u32 address = item.mid(0, item.indexOf(QLatin1Char(' '))).toUInt(nullptr, 16);
1323   if (rso_chain.Load(address))
1324   {
1325     rso_chain.Apply(&g_symbolDB);
1326     emit NotifySymbolsUpdated();
1327   }
1328   else
1329   {
1330     ModalMessageBox::warning(this, tr("Error"), tr("Failed to load RSO module at %1").arg(address));
1331   }
1332 }
1333 
LoadSymbolMap()1334 void MenuBar::LoadSymbolMap()
1335 {
1336   std::string existing_map_file, writable_map_file;
1337   bool map_exists = CBoot::FindMapFile(&existing_map_file, &writable_map_file);
1338 
1339   if (!map_exists)
1340   {
1341     g_symbolDB.Clear();
1342     PPCAnalyst::FindFunctions(Memory::MEM1_BASE_ADDR + 0x1300000,
1343                               Memory::MEM1_BASE_ADDR + Memory::GetRamSizeReal(), &g_symbolDB);
1344     SignatureDB db(SignatureDB::HandlerType::DSY);
1345     if (db.Load(File::GetSysDirectory() + TOTALDB))
1346       db.Apply(&g_symbolDB);
1347 
1348     ModalMessageBox::warning(this, tr("Warning"),
1349                              tr("'%1' not found, scanning for common functions instead")
1350                                  .arg(QString::fromStdString(writable_map_file)));
1351   }
1352   else
1353   {
1354     const QString existing_map_file_path = QString::fromStdString(existing_map_file);
1355 
1356     if (!TryLoadMapFile(existing_map_file_path))
1357       return;
1358 
1359     ModalMessageBox::information(this, tr("Information"),
1360                                  tr("Loaded symbols from '%1'").arg(existing_map_file_path));
1361   }
1362 
1363   HLE::PatchFunctions();
1364   emit NotifySymbolsUpdated();
1365 }
1366 
SaveSymbolMap()1367 void MenuBar::SaveSymbolMap()
1368 {
1369   std::string existing_map_file, writable_map_file;
1370   CBoot::FindMapFile(&existing_map_file, &writable_map_file);
1371 
1372   TrySaveSymbolMap(QString::fromStdString(writable_map_file));
1373 }
1374 
LoadOtherSymbolMap()1375 void MenuBar::LoadOtherSymbolMap()
1376 {
1377   const QString file = QFileDialog::getOpenFileName(
1378       this, tr("Load map file"), QString::fromStdString(File::GetUserPath(D_MAPS_IDX)),
1379       tr("Dolphin Map File (*.map)"));
1380 
1381   if (file.isEmpty())
1382     return;
1383 
1384   if (!TryLoadMapFile(file))
1385     return;
1386 
1387   HLE::PatchFunctions();
1388   emit NotifySymbolsUpdated();
1389 }
1390 
LoadBadSymbolMap()1391 void MenuBar::LoadBadSymbolMap()
1392 {
1393   const QString file = QFileDialog::getOpenFileName(
1394       this, tr("Load map file"), QString::fromStdString(File::GetUserPath(D_MAPS_IDX)),
1395       tr("Dolphin Map File (*.map)"));
1396 
1397   if (file.isEmpty())
1398     return;
1399 
1400   if (!TryLoadMapFile(file, true))
1401     return;
1402 
1403   HLE::PatchFunctions();
1404   emit NotifySymbolsUpdated();
1405 }
1406 
SaveSymbolMapAs()1407 void MenuBar::SaveSymbolMapAs()
1408 {
1409   const std::string& title_id_str = SConfig::GetInstance().m_debugger_game_id;
1410   const QString file = QFileDialog::getSaveFileName(
1411       this, tr("Save map file"),
1412       QString::fromStdString(File::GetUserPath(D_MAPS_IDX) + "/" + title_id_str + ".map"),
1413       tr("Dolphin Map File (*.map)"));
1414 
1415   if (file.isEmpty())
1416     return;
1417 
1418   TrySaveSymbolMap(file);
1419 }
1420 
SaveCode()1421 void MenuBar::SaveCode()
1422 {
1423   std::string existing_map_file, writable_map_file;
1424   CBoot::FindMapFile(&existing_map_file, &writable_map_file);
1425 
1426   const std::string path =
1427       writable_map_file.substr(0, writable_map_file.find_last_of('.')) + "_code.map";
1428 
1429   if (!g_symbolDB.SaveCodeMap(path))
1430   {
1431     ModalMessageBox::warning(
1432         this, tr("Error"),
1433         tr("Failed to save code map to path '%1'").arg(QString::fromStdString(path)));
1434   }
1435 }
1436 
TryLoadMapFile(const QString & path,const bool bad)1437 bool MenuBar::TryLoadMapFile(const QString& path, const bool bad)
1438 {
1439   if (!g_symbolDB.LoadMap(path.toStdString(), bad))
1440   {
1441     ModalMessageBox::warning(this, tr("Error"), tr("Failed to load map file '%1'").arg(path));
1442     return false;
1443   }
1444 
1445   return true;
1446 }
1447 
TrySaveSymbolMap(const QString & path)1448 void MenuBar::TrySaveSymbolMap(const QString& path)
1449 {
1450   if (g_symbolDB.SaveSymbolMap(path.toStdString()))
1451     return;
1452 
1453   ModalMessageBox::warning(this, tr("Error"),
1454                            tr("Failed to save symbol map to path '%1'").arg(path));
1455 }
1456 
CreateSignatureFile()1457 void MenuBar::CreateSignatureFile()
1458 {
1459   const QString text = QInputDialog::getText(
1460       this, tr("Input"), tr("Only export symbols with prefix:\n(Blank for all symbols)"));
1461 
1462   const QString file = QFileDialog::getSaveFileName(this, tr("Save signature file"),
1463                                                     QDir::homePath(), GetSignatureSelector());
1464   if (file.isEmpty())
1465     return;
1466 
1467   const std::string prefix = text.toStdString();
1468   const std::string save_path = file.toStdString();
1469   SignatureDB db(save_path);
1470   db.Populate(&g_symbolDB, prefix);
1471 
1472   if (!db.Save(save_path))
1473   {
1474     ModalMessageBox::warning(this, tr("Error"), tr("Failed to save signature file '%1'").arg(file));
1475     return;
1476   }
1477 
1478   db.List();
1479 }
1480 
AppendSignatureFile()1481 void MenuBar::AppendSignatureFile()
1482 {
1483   const QString text = QInputDialog::getText(
1484       this, tr("Input"), tr("Only append symbols with prefix:\n(Blank for all symbols)"));
1485 
1486   const QString file = QFileDialog::getSaveFileName(this, tr("Append signature to"),
1487                                                     QDir::homePath(), GetSignatureSelector());
1488   if (file.isEmpty())
1489     return;
1490 
1491   const std::string prefix = text.toStdString();
1492   const std::string signature_path = file.toStdString();
1493   SignatureDB db(signature_path);
1494   db.Populate(&g_symbolDB, prefix);
1495   db.List();
1496   db.Load(signature_path);
1497   if (!db.Save(signature_path))
1498   {
1499     ModalMessageBox::warning(this, tr("Error"),
1500                              tr("Failed to append to signature file '%1'").arg(file));
1501     return;
1502   }
1503 
1504   db.List();
1505 }
1506 
ApplySignatureFile()1507 void MenuBar::ApplySignatureFile()
1508 {
1509   const QString file = QFileDialog::getOpenFileName(this, tr("Apply signature file"),
1510                                                     QDir::homePath(), GetSignatureSelector());
1511 
1512   if (file.isEmpty())
1513     return;
1514 
1515   const std::string load_path = file.toStdString();
1516   SignatureDB db(load_path);
1517   db.Load(load_path);
1518   db.Apply(&g_symbolDB);
1519   db.List();
1520   HLE::PatchFunctions();
1521   emit NotifySymbolsUpdated();
1522 }
1523 
CombineSignatureFiles()1524 void MenuBar::CombineSignatureFiles()
1525 {
1526   const QString priorityFile = QFileDialog::getOpenFileName(
1527       this, tr("Choose priority input file"), QDir::homePath(), GetSignatureSelector());
1528   if (priorityFile.isEmpty())
1529     return;
1530 
1531   const QString secondaryFile = QFileDialog::getOpenFileName(
1532       this, tr("Choose secondary input file"), QDir::homePath(), GetSignatureSelector());
1533   if (secondaryFile.isEmpty())
1534     return;
1535 
1536   const QString saveFile = QFileDialog::getSaveFileName(this, tr("Save combined output file as"),
1537                                                         QDir::homePath(), GetSignatureSelector());
1538   if (saveFile.isEmpty())
1539     return;
1540 
1541   const std::string load_pathPriorityFile = priorityFile.toStdString();
1542   const std::string load_pathSecondaryFile = secondaryFile.toStdString();
1543   const std::string save_path = saveFile.toStdString();
1544   SignatureDB db(load_pathPriorityFile);
1545   db.Load(load_pathPriorityFile);
1546   db.Load(load_pathSecondaryFile);
1547   if (!db.Save(save_path))
1548   {
1549     ModalMessageBox::warning(this, tr("Error"),
1550                              tr("Failed to save to signature file '%1'").arg(saveFile));
1551     return;
1552   }
1553 
1554   db.List();
1555 }
1556 
PatchHLEFunctions()1557 void MenuBar::PatchHLEFunctions()
1558 {
1559   HLE::PatchFunctions();
1560 }
1561 
ClearCache()1562 void MenuBar::ClearCache()
1563 {
1564   Core::RunAsCPUThread(JitInterface::ClearCache);
1565 }
1566 
LogInstructions()1567 void MenuBar::LogInstructions()
1568 {
1569   PPCTables::LogCompiledInstructions();
1570 }
1571 
SearchInstruction()1572 void MenuBar::SearchInstruction()
1573 {
1574   bool good;
1575   const QString op = QInputDialog::getText(this, tr("Search instruction"), tr("Instruction:"),
1576                                            QLineEdit::Normal, QString{}, &good);
1577 
1578   if (!good)
1579     return;
1580 
1581   bool found = false;
1582   for (u32 addr = Memory::MEM1_BASE_ADDR; addr < Memory::MEM1_BASE_ADDR + Memory::GetRamSizeReal();
1583        addr += 4)
1584   {
1585     auto ins_name =
1586         QString::fromStdString(PPCTables::GetInstructionName(PowerPC::HostRead_U32(addr)));
1587     if (op == ins_name)
1588     {
1589       NOTICE_LOG(POWERPC, "Found %s at %08x", op.toStdString().c_str(), addr);
1590       found = true;
1591     }
1592   }
1593   if (!found)
1594     NOTICE_LOG(POWERPC, "Opcode %s not found", op.toStdString().c_str());
1595 }
1596