diff options
38 files changed, 284 insertions, 2518 deletions
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 3e6106f0a..4e837668e 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -11,8 +11,6 @@ set(SRCS configuration/configure_graphics.cpp configuration/configure_input.cpp configuration/configure_system.cpp - debugger/callstack.cpp - debugger/disassembler.cpp debugger/graphics/graphics.cpp debugger/graphics/graphics_breakpoint_observer.cpp debugger/graphics/graphics_breakpoints.cpp @@ -43,8 +41,6 @@ set(HEADERS configuration/configure_graphics.h configuration/configure_input.h configuration/configure_system.h - debugger/callstack.h - debugger/disassembler.h debugger/graphics/graphics.h debugger/graphics/graphics_breakpoint_observer.h debugger/graphics/graphics_breakpoints.h @@ -74,8 +70,6 @@ set(UIS configuration/configure_graphics.ui configuration/configure_input.ui configuration/configure_system.ui - debugger/callstack.ui - debugger/disassembler.ui debugger/registers.ui hotkeys.ui main.ui diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp deleted file mode 100644 index 08d2e7a22..000000000 --- a/src/citra_qt/debugger/callstack.cpp +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <QStandardItemModel> -#include "citra_qt/debugger/callstack.h" -#include "common/common_types.h" -#include "common/symbols.h" -#include "core/arm/arm_interface.h" -#include "core/arm/disassembler/arm_disasm.h" -#include "core/core.h" -#include "core/memory.h" - -CallstackWidget::CallstackWidget(QWidget* parent) : QDockWidget(parent) { - ui.setupUi(this); - - callstack_model = new QStandardItemModel(this); - callstack_model->setColumnCount(4); - callstack_model->setHeaderData(0, Qt::Horizontal, "Stack Pointer"); - callstack_model->setHeaderData(2, Qt::Horizontal, "Return Address"); - callstack_model->setHeaderData(1, Qt::Horizontal, "Call Address"); - callstack_model->setHeaderData(3, Qt::Horizontal, "Function"); - ui.treeView->setModel(callstack_model); -} - -void CallstackWidget::OnDebugModeEntered() { - // Stack pointer - const u32 sp = Core::CPU().GetReg(13); - - Clear(); - - int counter = 0; - for (u32 addr = 0x10000000; addr >= sp; addr -= 4) { - if (!Memory::IsValidVirtualAddress(addr)) - break; - - const u32 ret_addr = Memory::Read32(addr); - const u32 call_addr = ret_addr - 4; // get call address??? - - if (!Memory::IsValidVirtualAddress(call_addr)) - break; - - /* TODO (mattvail) clean me, move to debugger interface */ - u32 insn = Memory::Read32(call_addr); - if (ARM_Disasm::Decode(insn) == OP_BL) { - std::string name; - // ripped from disasm - u32 i_offset = insn & 0xffffff; - // Sign-extend the 24-bit offset - if ((i_offset >> 23) & 1) - i_offset |= 0xff000000; - - // Pre-compute the left-shift and the prefetch offset - i_offset <<= 2; - i_offset += 8; - const u32 func_addr = call_addr + i_offset; - - callstack_model->setItem( - counter, 0, new QStandardItem(QString("0x%1").arg(addr, 8, 16, QLatin1Char('0')))); - callstack_model->setItem(counter, 1, new QStandardItem(QString("0x%1").arg( - ret_addr, 8, 16, QLatin1Char('0')))); - callstack_model->setItem(counter, 2, new QStandardItem(QString("0x%1").arg( - call_addr, 8, 16, QLatin1Char('0')))); - - name = Symbols::HasSymbol(func_addr) ? Symbols::GetSymbol(func_addr).name : "unknown"; - callstack_model->setItem( - counter, 3, new QStandardItem( - QString("%1_%2") - .arg(QString::fromStdString(name)) - .arg(QString("0x%1").arg(func_addr, 8, 16, QLatin1Char('0'))))); - - counter++; - } - } -} - -void CallstackWidget::OnDebugModeLeft() {} - -void CallstackWidget::Clear() { - for (int row = 0; row < callstack_model->rowCount(); row++) { - for (int column = 0; column < callstack_model->columnCount(); column++) { - callstack_model->setItem(row, column, new QStandardItem()); - } - } -} diff --git a/src/citra_qt/debugger/callstack.h b/src/citra_qt/debugger/callstack.h deleted file mode 100644 index f04ab9c7e..000000000 --- a/src/citra_qt/debugger/callstack.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <QDockWidget> -#include "ui_callstack.h" - -class QStandardItemModel; - -class CallstackWidget : public QDockWidget { - Q_OBJECT - -public: - explicit CallstackWidget(QWidget* parent = nullptr); - -public slots: - void OnDebugModeEntered(); - void OnDebugModeLeft(); - -private: - Ui::CallStack ui; - QStandardItemModel* callstack_model; - - /// Clears the callstack widget while keeping the column widths the same - void Clear(); -}; diff --git a/src/citra_qt/debugger/callstack.ui b/src/citra_qt/debugger/callstack.ui deleted file mode 100644 index 248ea3dd7..000000000 --- a/src/citra_qt/debugger/callstack.ui +++ /dev/null @@ -1,39 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>CallStack</class> - <widget class="QDockWidget" name="CallStack"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>400</width> - <height>300</height> - </rect> - </property> - <property name="windowTitle"> - <string>Call Stack</string> - </property> - <widget class="QWidget" name="dockWidgetContents"> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QTreeView" name="treeView"> - <property name="editTriggers"> - <set>QAbstractItemView::NoEditTriggers</set> - </property> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - <property name="rootIsDecorated"> - <bool>false</bool> - </property> - <property name="itemsExpandable"> - <bool>false</bool> - </property> - </widget> - </item> - </layout> - </widget> - </widget> - <resources/> - <connections/> -</ui> diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp deleted file mode 100644 index e9c8ad858..000000000 --- a/src/citra_qt/debugger/disassembler.cpp +++ /dev/null @@ -1,272 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <QShortcut> -#include "citra_qt/bootmanager.h" -#include "citra_qt/debugger/disassembler.h" -#include "citra_qt/hotkeys.h" -#include "citra_qt/util/util.h" -#include "common/break_points.h" -#include "common/symbols.h" -#include "core/arm/arm_interface.h" -#include "core/arm/disassembler/arm_disasm.h" -#include "core/core.h" -#include "core/memory.h" - -DisassemblerModel::DisassemblerModel(QObject* parent) - : QAbstractListModel(parent), base_address(0), code_size(0), program_counter(0), - selection(QModelIndex()) {} - -int DisassemblerModel::columnCount(const QModelIndex& parent) const { - return 3; -} - -int DisassemblerModel::rowCount(const QModelIndex& parent) const { - return code_size; -} - -QVariant DisassemblerModel::data(const QModelIndex& index, int role) const { - switch (role) { - case Qt::DisplayRole: { - u32 address = base_address + index.row() * 4; - u32 instr = Memory::Read32(address); - std::string disassembly = ARM_Disasm::Disassemble(address, instr); - - if (index.column() == 0) { - return QString("0x%1").arg((uint)(address), 8, 16, QLatin1Char('0')); - } else if (index.column() == 1) { - return QString::fromStdString(disassembly); - } else if (index.column() == 2) { - if (Symbols::HasSymbol(address)) { - TSymbol symbol = Symbols::GetSymbol(address); - return QString("%1 - Size:%2") - .arg(QString::fromStdString(symbol.name)) - .arg(symbol.size / 4); // divide by 4 to get instruction count - } else if (ARM_Disasm::Decode(instr) == OP_BL) { - u32 offset = instr & 0xFFFFFF; - - // Sign-extend the 24-bit offset - if ((offset >> 23) & 1) - offset |= 0xFF000000; - - // Pre-compute the left-shift and the prefetch offset - offset <<= 2; - offset += 8; - - TSymbol symbol = Symbols::GetSymbol(address + offset); - return QString(" --> %1").arg(QString::fromStdString(symbol.name)); - } - } - - break; - } - - case Qt::BackgroundRole: { - unsigned int address = base_address + 4 * index.row(); - - if (breakpoints.IsAddressBreakPoint(address)) - return QBrush(QColor(0xFF, 0xC0, 0xC0)); - else if (address == program_counter) - return QBrush(QColor(0xC0, 0xC0, 0xFF)); - - break; - } - - case Qt::FontRole: { - if (index.column() == 0 || index.column() == 1) { // 2 is the symbols column - return GetMonospaceFont(); - } - break; - } - - default: - break; - } - - return QVariant(); -} - -QModelIndex DisassemblerModel::IndexFromAbsoluteAddress(unsigned int address) const { - return index((address - base_address) / 4, 0); -} - -const BreakPoints& DisassemblerModel::GetBreakPoints() const { - return breakpoints; -} - -void DisassemblerModel::ParseFromAddress(unsigned int address) { - - // NOTE: A too large value causes lagging when scrolling the disassembly - const unsigned int chunk_size = 1000 * 500; - - // If we haven't loaded anything yet, initialize base address to the parameter address - if (code_size == 0) - base_address = address; - - // If the new area is already loaded, just continue - if (base_address + code_size > address + chunk_size && base_address <= address) - return; - - // Insert rows before currently loaded data - if (base_address > address) { - unsigned int num_rows = (address - base_address) / 4; - - beginInsertRows(QModelIndex(), 0, num_rows); - code_size += num_rows; - base_address = address; - - endInsertRows(); - } - - // Insert rows after currently loaded data - if (base_address + code_size < address + chunk_size) { - unsigned int num_rows = (base_address + chunk_size - code_size - address) / 4; - - beginInsertRows(QModelIndex(), 0, num_rows); - code_size += num_rows; - endInsertRows(); - } - - SetNextInstruction(address); -} - -void DisassemblerModel::OnSelectionChanged(const QModelIndex& new_selection) { - selection = new_selection; -} - -void DisassemblerModel::OnSetOrUnsetBreakpoint() { - if (!selection.isValid()) - return; - - unsigned int address = base_address + selection.row() * 4; - - if (breakpoints.IsAddressBreakPoint(address)) { - breakpoints.Remove(address); - } else { - breakpoints.Add(address); - } - - emit dataChanged(selection, selection); -} - -void DisassemblerModel::SetNextInstruction(unsigned int address) { - QModelIndex cur_index = IndexFromAbsoluteAddress(program_counter); - QModelIndex prev_index = IndexFromAbsoluteAddress(address); - - program_counter = address; - - emit dataChanged(cur_index, cur_index); - emit dataChanged(prev_index, prev_index); -} - -DisassemblerWidget::DisassemblerWidget(QWidget* parent, EmuThread* emu_thread) - : QDockWidget(parent), base_addr(0), emu_thread(emu_thread) { - - disasm_ui.setupUi(this); - - RegisterHotkey("Disassembler", "Start/Stop", QKeySequence(Qt::Key_F5), Qt::ApplicationShortcut); - RegisterHotkey("Disassembler", "Step", QKeySequence(Qt::Key_F10), Qt::ApplicationShortcut); - RegisterHotkey("Disassembler", "Step into", QKeySequence(Qt::Key_F11), Qt::ApplicationShortcut); - RegisterHotkey("Disassembler", "Set Breakpoint", QKeySequence(Qt::Key_F9), - Qt::ApplicationShortcut); - - connect(disasm_ui.button_step, SIGNAL(clicked()), this, SLOT(OnStep())); - connect(disasm_ui.button_pause, SIGNAL(clicked()), this, SLOT(OnPause())); - connect(disasm_ui.button_continue, SIGNAL(clicked()), this, SLOT(OnContinue())); - - connect(GetHotkey("Disassembler", "Start/Stop", this), SIGNAL(activated()), this, - SLOT(OnToggleStartStop())); - connect(GetHotkey("Disassembler", "Step", this), SIGNAL(activated()), this, SLOT(OnStep())); - connect(GetHotkey("Disassembler", "Step into", this), SIGNAL(activated()), this, - SLOT(OnStepInto())); - - setEnabled(false); -} - -void DisassemblerWidget::Init() { - model->ParseFromAddress(Core::CPU().GetPC()); - - disasm_ui.treeView->resizeColumnToContents(0); - disasm_ui.treeView->resizeColumnToContents(1); - disasm_ui.treeView->resizeColumnToContents(2); - - QModelIndex model_index = model->IndexFromAbsoluteAddress(Core::CPU().GetPC()); - disasm_ui.treeView->scrollTo(model_index); - disasm_ui.treeView->selectionModel()->setCurrentIndex( - model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); -} - -void DisassemblerWidget::OnContinue() { - emu_thread->SetRunning(true); -} - -void DisassemblerWidget::OnStep() { - OnStepInto(); // change later -} - -void DisassemblerWidget::OnStepInto() { - emu_thread->SetRunning(false); - emu_thread->ExecStep(); -} - -void DisassemblerWidget::OnPause() { - emu_thread->SetRunning(false); - - // TODO: By now, the CPU might not have actually stopped... - if (Core::System::GetInstance().IsPoweredOn()) { - model->SetNextInstruction(Core::CPU().GetPC()); - } -} - -void DisassemblerWidget::OnToggleStartStop() { - emu_thread->SetRunning(!emu_thread->IsRunning()); -} - -void DisassemblerWidget::OnDebugModeEntered() { - u32 next_instr = Core::CPU().GetPC(); - - if (model->GetBreakPoints().IsAddressBreakPoint(next_instr)) - emu_thread->SetRunning(false); - - model->SetNextInstruction(next_instr); - - QModelIndex model_index = model->IndexFromAbsoluteAddress(next_instr); - disasm_ui.treeView->scrollTo(model_index); - disasm_ui.treeView->selectionModel()->setCurrentIndex( - model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); -} - -void DisassemblerWidget::OnDebugModeLeft() {} - -int DisassemblerWidget::SelectedRow() { - QModelIndex index = disasm_ui.treeView->selectionModel()->currentIndex(); - if (!index.isValid()) - return -1; - - return disasm_ui.treeView->selectionModel()->currentIndex().row(); -} - -void DisassemblerWidget::OnEmulationStarting(EmuThread* emu_thread) { - this->emu_thread = emu_thread; - - model = new DisassemblerModel(this); - disasm_ui.treeView->setModel(model); - - connect(disasm_ui.treeView->selectionModel(), - SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)), model, - SLOT(OnSelectionChanged(const QModelIndex&))); - connect(disasm_ui.button_breakpoint, SIGNAL(clicked()), model, SLOT(OnSetOrUnsetBreakpoint())); - connect(GetHotkey("Disassembler", "Set Breakpoint", this), SIGNAL(activated()), model, - SLOT(OnSetOrUnsetBreakpoint())); - - Init(); - setEnabled(true); -} - -void DisassemblerWidget::OnEmulationStopping() { - disasm_ui.treeView->setModel(nullptr); - delete model; - emu_thread = nullptr; - setEnabled(false); -} diff --git a/src/citra_qt/debugger/disassembler.h b/src/citra_qt/debugger/disassembler.h deleted file mode 100644 index a6e59515c..000000000 --- a/src/citra_qt/debugger/disassembler.h +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <QAbstractListModel> -#include <QDockWidget> -#include "common/break_points.h" -#include "common/common_types.h" -#include "ui_disassembler.h" - -class QAction; -class EmuThread; - -class DisassemblerModel : public QAbstractListModel { - Q_OBJECT - -public: - explicit DisassemblerModel(QObject* parent); - - int columnCount(const QModelIndex& parent = QModelIndex()) const override; - int rowCount(const QModelIndex& parent = QModelIndex()) const override; - QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; - - QModelIndex IndexFromAbsoluteAddress(unsigned int address) const; - const BreakPoints& GetBreakPoints() const; - -public slots: - void ParseFromAddress(unsigned int address); - void OnSelectionChanged(const QModelIndex&); - void OnSetOrUnsetBreakpoint(); - void SetNextInstruction(unsigned int address); - -private: - unsigned int base_address; - unsigned int code_size; - unsigned int program_counter; - - QModelIndex selection; - BreakPoints breakpoints; -}; - -class DisassemblerWidget : public QDockWidget { - Q_OBJECT - -public: - DisassemblerWidget(QWidget* parent, EmuThread* emu_thread); - - void Init(); - -public slots: - void OnContinue(); - void OnStep(); - void OnStepInto(); - void OnPause(); - void OnToggleStartStop(); - - void OnDebugModeEntered(); - void OnDebugModeLeft(); - - void OnEmulationStarting(EmuThread* emu_thread); - void OnEmulationStopping(); - -private: - // returns -1 if no row is selected - int SelectedRow(); - - Ui::DockWidget disasm_ui; - - DisassemblerModel* model; - - u32 base_addr; - - EmuThread* emu_thread; -}; diff --git a/src/citra_qt/debugger/disassembler.ui b/src/citra_qt/debugger/disassembler.ui deleted file mode 100644 index 5ca6dc5d2..000000000 --- a/src/citra_qt/debugger/disassembler.ui +++ /dev/null @@ -1,81 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>DockWidget</class> - <widget class="QDockWidget" name="DockWidget"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>430</width> - <height>401</height> - </rect> - </property> - <property name="windowTitle"> - <string>Disassembly</string> - </property> - <widget class="QWidget" name="dockWidgetContents"> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QPushButton" name="button_step"> - <property name="text"> - <string>Step</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="button_pause"> - <property name="text"> - <string>Pause</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="button_continue"> - <property name="text"> - <string>Continue</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="pushButton"> - <property name="text"> - <string>Step Into</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="button_breakpoint"> - <property name="text"> - <string>Set Breakpoint</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <widget class="QTreeView" name="treeView"> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - <property name="indentation"> - <number>20</number> - </property> - <property name="rootIsDecorated"> - <bool>false</bool> - </property> - <property name="uniformRowHeights"> - <bool>true</bool> - </property> - <attribute name="headerVisible"> - <bool>false</bool> - </attribute> - </widget> - </item> - </layout> - </widget> - </widget> - <resources/> - <connections/> -</ui> diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp index 51257520b..a8e3541cd 100644 --- a/src/citra_qt/game_list.cpp +++ b/src/citra_qt/game_list.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <QApplication> #include <QFileInfo> #include <QHeaderView> #include <QKeyEvent> @@ -194,6 +195,9 @@ void GameList::onFilterCloseClicked() { } GameList::GameList(GMainWindow* parent) : QWidget{parent} { + watcher = new QFileSystemWatcher(this); + connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory); + this->main_window = parent; layout = new QVBoxLayout; tree_view = new QTreeView; @@ -218,7 +222,6 @@ GameList::GameList(GMainWindow* parent) : QWidget{parent} { connect(tree_view, &QTreeView::activated, this, &GameList::ValidateEntry); connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu); - connect(&watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory); // We must register all custom types with the Qt Automoc system so that we are able to use it // with signals/slots. In this case, QList falls under the umbrells of custom types. @@ -269,7 +272,22 @@ void GameList::ValidateEntry(const QModelIndex& item) { emit GameChosen(file_path); } -void GameList::DonePopulating() { +void GameList::DonePopulating(QStringList watch_list) { + // Clear out the old directories to watch for changes and add the new ones + auto watch_dirs = watcher->directories(); + if (!watch_dirs.isEmpty()) { + watcher->removePaths(watch_dirs); + } + // Workaround: Add the watch paths in chunks to allow the gui to refresh + // This prevents the UI from stalling when a large number of watch paths are added + // Also artificially caps the watcher to a certain number of directories + constexpr int LIMIT_WATCH_DIRECTORIES = 5000; + constexpr int SLICE_SIZE = 25; + int len = std::min(watch_list.length(), LIMIT_WATCH_DIRECTORIES); + for (int i = 0; i < len; i += SLICE_SIZE) { + watcher->addPaths(watch_list.mid(i, i + SLICE_SIZE)); + QCoreApplication::processEvents(); + } tree_view->setEnabled(true); int rowCount = tree_view->model()->rowCount(); search_field->setFilterResult(rowCount, rowCount); @@ -309,11 +327,6 @@ void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) { emit ShouldCancelWorker(); - auto watch_dirs = watcher.directories(); - if (!watch_dirs.isEmpty()) { - watcher.removePaths(watch_dirs); - } - UpdateWatcherList(dir_path.toStdString(), deep_scan ? 256 : 0); GameListWorker* worker = new GameListWorker(dir_path, deep_scan); connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection); @@ -359,38 +372,6 @@ void GameList::RefreshGameDirectory() { } } -/** - * Adds the game list folder to the QFileSystemWatcher to check for updates. - * - * The file watcher will fire off an update to the game list when a change is detected in the game - * list folder. - * - * Notice: This method is run on the UI thread because QFileSystemWatcher is not thread safe and - * this function is fast enough to not stall the UI thread. If performance is an issue, it should - * be moved to another thread and properly locked to prevent concurrency issues. - * - * @param dir folder to check for changes in - * @param recursion 0 if recursion is disabled. Any positive number passed to this will add each - * directory recursively to the watcher and will update the file list if any of the folders - * change. The number determines how deep the recursion should traverse. - */ -void GameList::UpdateWatcherList(const std::string& dir, unsigned int recursion) { - const auto callback = [this, recursion](unsigned* num_entries_out, const std::string& directory, - const std::string& virtual_name) -> bool { - std::string physical_name = directory + DIR_SEP + virtual_name; - - if (FileUtil::IsDirectory(physical_name)) { - UpdateWatcherList(physical_name, recursion - 1); - } - return true; - }; - - watcher.addPath(QString::fromStdString(dir)); - if (recursion > 0) { - FileUtil::ForeachDirectoryEntry(nullptr, dir, callback); - } -} - void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) { const auto callback = [this, recursion](unsigned* num_entries_out, const std::string& directory, const std::string& virtual_name) -> bool { @@ -399,7 +380,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign if (stop_processing) return false; // Breaks the callback loop. - if (!FileUtil::IsDirectory(physical_name) && HasSupportedFileExtension(physical_name)) { + bool is_dir = FileUtil::IsDirectory(physical_name); + if (!is_dir && HasSupportedFileExtension(physical_name)) { std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(physical_name); if (!loader) return true; @@ -416,7 +398,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), new GameListItemSize(FileUtil::GetSize(physical_name)), }); - } else if (recursion > 0) { + } else if (is_dir && recursion > 0) { + watch_list.append(QString::fromStdString(physical_name)); AddFstEntriesToGameList(physical_name, recursion - 1); } @@ -428,8 +411,9 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign void GameListWorker::run() { stop_processing = false; + watch_list.append(dir_path); AddFstEntriesToGameList(dir_path.toStdString(), deep_scan ? 256 : 0); - emit Finished(); + emit Finished(watch_list); } void GameListWorker::Cancel() { diff --git a/src/citra_qt/game_list.h b/src/citra_qt/game_list.h index d8f8bc5b6..4823a1296 100644 --- a/src/citra_qt/game_list.h +++ b/src/citra_qt/game_list.h @@ -85,10 +85,9 @@ private slots: private: void AddEntry(const QList<QStandardItem*>& entry_items); void ValidateEntry(const QModelIndex& item); - void DonePopulating(); + void DonePopulating(QStringList watch_list); void PopupContextMenu(const QPoint& menu_location); - void UpdateWatcherList(const std::string& path, unsigned int recursion); void RefreshGameDirectory(); bool containsAllWords(QString haystack, QString userinput); @@ -98,5 +97,5 @@ private: QTreeView* tree_view = nullptr; QStandardItemModel* item_model = nullptr; GameListWorker* current_worker = nullptr; - QFileSystemWatcher watcher; + QFileSystemWatcher* watcher = nullptr; }; diff --git a/src/citra_qt/game_list_p.h b/src/citra_qt/game_list_p.h index 3c11b6dd1..d1118ff7f 100644 --- a/src/citra_qt/game_list_p.h +++ b/src/citra_qt/game_list_p.h @@ -170,9 +170,15 @@ signals: * @param entry_items a list with `QStandardItem`s that make up the columns of the new entry. */ void EntryReady(QList<QStandardItem*> entry_items); - void Finished(); + + /** + * After the worker has traversed the game directory looking for entries, this signal is emmited + * with a list of folders that should be watched for changes as well. + */ + void Finished(QStringList watch_list); private: + QStringList watch_list; QString dir_path; bool deep_scan; std::atomic_bool stop_processing; diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index ea66cc425..d7fad555f 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -16,8 +16,6 @@ #include "citra_qt/bootmanager.h" #include "citra_qt/configuration/config.h" #include "citra_qt/configuration/configure_dialog.h" -#include "citra_qt/debugger/callstack.h" -#include "citra_qt/debugger/disassembler.h" #include "citra_qt/debugger/graphics/graphics.h" #include "citra_qt/debugger/graphics/graphics_breakpoints.h" #include "citra_qt/debugger/graphics/graphics_cmdlists.h" @@ -40,7 +38,6 @@ #include "common/scm_rev.h" #include "common/scope_exit.h" #include "common/string_util.h" -#include "core/arm/disassembler/load_symbol_map.h" #include "core/core.h" #include "core/file_sys/archive_source_sd_savedata.h" #include "core/gdbstub/gdbstub.h" @@ -130,15 +127,6 @@ void GMainWindow::InitializeDebugWidgets() { debug_menu->addAction(microProfileDialog->toggleViewAction()); #endif - disasmWidget = new DisassemblerWidget(this, emu_thread.get()); - addDockWidget(Qt::BottomDockWidgetArea, disasmWidget); - disasmWidget->hide(); - debug_menu->addAction(disasmWidget->toggleViewAction()); - connect(this, &GMainWindow::EmulationStarting, disasmWidget, - &DisassemblerWidget::OnEmulationStarting); - connect(this, &GMainWindow::EmulationStopping, disasmWidget, - &DisassemblerWidget::OnEmulationStopping); - registersWidget = new RegistersWidget(this); addDockWidget(Qt::RightDockWidgetArea, registersWidget); registersWidget->hide(); @@ -148,11 +136,6 @@ void GMainWindow::InitializeDebugWidgets() { connect(this, &GMainWindow::EmulationStopping, registersWidget, &RegistersWidget::OnEmulationStopping); - callstackWidget = new CallstackWidget(this); - addDockWidget(Qt::RightDockWidgetArea, callstackWidget); - callstackWidget->hide(); - debug_menu->addAction(callstackWidget->toggleViewAction()); - graphicsWidget = new GPUCommandStreamWidget(this); addDockWidget(Qt::RightDockWidgetArea, graphicsWidget); graphicsWidget->hide(); @@ -269,8 +252,6 @@ void GMainWindow::ConnectWidgetEvents() { void GMainWindow::ConnectMenuEvents() { // File connect(ui.action_Load_File, &QAction::triggered, this, &GMainWindow::OnMenuLoadFile); - connect(ui.action_Load_Symbol_Map, &QAction::triggered, this, - &GMainWindow::OnMenuLoadSymbolMap); connect(ui.action_Select_Game_List_Root, &QAction::triggered, this, &GMainWindow::OnMenuSelectGameListRoot); connect(ui.action_Exit, &QAction::triggered, this, &QMainWindow::close); @@ -391,26 +372,17 @@ void GMainWindow::BootGame(const QString& filename) { connect(render_window, SIGNAL(Closed()), this, SLOT(OnStopGame())); // BlockingQueuedConnection is important here, it makes sure we've finished refreshing our views // before the CPU continues - connect(emu_thread.get(), SIGNAL(DebugModeEntered()), disasmWidget, SLOT(OnDebugModeEntered()), - Qt::BlockingQueuedConnection); connect(emu_thread.get(), SIGNAL(DebugModeEntered()), registersWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection); - connect(emu_thread.get(), SIGNAL(DebugModeEntered()), callstackWidget, - SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection); connect(emu_thread.get(), SIGNAL(DebugModeEntered()), waitTreeWidget, SLOT(OnDebugModeEntered()), Qt::BlockingQueuedConnection); - connect(emu_thread.get(), SIGNAL(DebugModeLeft()), disasmWidget, SLOT(OnDebugModeLeft()), - Qt::BlockingQueuedConnection); connect(emu_thread.get(), SIGNAL(DebugModeLeft()), registersWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection); - connect(emu_thread.get(), SIGNAL(DebugModeLeft()), callstackWidget, SLOT(OnDebugModeLeft()), - Qt::BlockingQueuedConnection); connect(emu_thread.get(), SIGNAL(DebugModeLeft()), waitTreeWidget, SLOT(OnDebugModeLeft()), Qt::BlockingQueuedConnection); // Update the GUI registersWidget->OnDebugModeEntered(); - callstackWidget->OnDebugModeEntered(); if (ui.action_Single_Window_Mode->isChecked()) { game_list->hide(); } @@ -531,16 +503,6 @@ void GMainWindow::OnMenuLoadFile() { } } -void GMainWindow::OnMenuLoadSymbolMap() { - QString filename = QFileDialog::getOpenFileName( - this, tr("Load Symbol Map"), UISettings::values.symbols_path, tr("Symbol Map (*.*)")); - if (!filename.isEmpty()) { - UISettings::values.symbols_path = QFileInfo(filename).path(); - - LoadSymbolMap(filename.toStdString()); - } -} - void GMainWindow::OnMenuSelectGameListRoot() { QString dir_path = QFileDialog::getExistingDirectory(this, tr("Select Directory")); if (!dir_path.isEmpty()) { diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index 2f398eb7b..cb2e87cbd 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h @@ -10,9 +10,7 @@ #include <QTimer> #include "ui_main.h" -class CallstackWidget; class Config; -class DisassemblerWidget; class EmuThread; class GameList; class GImageInfo; @@ -118,7 +116,6 @@ private slots: void OnGameListLoadFile(QString game_path); void OnGameListOpenSaveFolder(u64 program_id); void OnMenuLoadFile(); - void OnMenuLoadSymbolMap(); /// Called whenever a user selects the "File->Select Game List Root" menu item void OnMenuSelectGameListRoot(); void OnMenuRecentFile(); @@ -152,9 +149,7 @@ private: // Debugger panes ProfilerWidget* profilerWidget; MicroProfileDialog* microProfileDialog; - DisassemblerWidget* disasmWidget; RegistersWidget* registersWidget; - CallstackWidget* callstackWidget; GPUCommandStreamWidget* graphicsWidget; GPUCommandListWidget* graphicsCommandsWidget; GraphicsBreakPointsWidget* graphicsBreakpointsWidget; diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui index f64b878f0..b13d578f5 100644 --- a/src/citra_qt/main.ui +++ b/src/citra_qt/main.ui @@ -58,7 +58,6 @@ </property> </widget> <addaction name="action_Load_File"/> - <addaction name="action_Load_Symbol_Map"/> <addaction name="separator"/> <addaction name="action_Select_Game_List_Root"/> <addaction name="menu_recent_files"/> diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 13277a5c2..4b30185f1 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -38,7 +38,6 @@ set(SRCS param_package.cpp scm_rev.cpp string_util.cpp - symbols.cpp thread.cpp timer.cpp ) @@ -74,7 +73,6 @@ set(HEADERS scope_exit.h string_util.h swap.h - symbols.h synchronized_wrapper.h thread.h thread_queue_list.h diff --git a/src/common/symbols.cpp b/src/common/symbols.cpp deleted file mode 100644 index c4d16af85..000000000 --- a/src/common/symbols.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/symbols.h" - -TSymbolsMap g_symbols; - -namespace Symbols { -bool HasSymbol(u32 address) { - return g_symbols.find(address) != g_symbols.end(); -} - -void Add(u32 address, const std::string& name, u32 size, u32 type) { - if (!HasSymbol(address)) { - TSymbol symbol; - symbol.address = address; - symbol.name = name; - symbol.size = size; - symbol.type = type; - - g_symbols.emplace(address, symbol); - } -} - -TSymbol GetSymbol(u32 address) { - const auto iter = g_symbols.find(address); - - if (iter != g_symbols.end()) - return iter->second; - - return {}; -} - -const std::string GetName(u32 address) { - return GetSymbol(address).name; -} - -void Remove(u32 address) { - g_symbols.erase(address); -} - -void Clear() { - g_symbols.clear(); -} -} diff --git a/src/common/symbols.h b/src/common/symbols.h deleted file mode 100644 index f5a48e05a..000000000 --- a/src/common/symbols.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <map> -#include <string> -#include <utility> -#include "common/common_types.h" - -struct TSymbol { - u32 address = 0; - std::string name; - u32 size = 0; - u32 type = 0; -}; - -typedef std::map<u32, TSymbol> TSymbolsMap; -typedef std::pair<u32, TSymbol> TSymbolsPair; - -namespace Symbols { -bool HasSymbol(u32 address); - -void Add(u32 address, const std::string& name, u32 size, u32 type); -TSymbol GetSymbol(u32 address); -const std::string GetName(u32 address); -void Remove(u32 address); -void Clear(); -} diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a2866fdd8..e404063f0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,6 +1,4 @@ set(SRCS - arm/disassembler/arm_disasm.cpp - arm/disassembler/load_symbol_map.cpp arm/dynarmic/arm_dynarmic.cpp arm/dynarmic/arm_dynarmic_cp15.cpp arm/dyncom/arm_dyncom.cpp @@ -179,8 +177,6 @@ set(SRCS set(HEADERS arm/arm_interface.h - arm/disassembler/arm_disasm.h - arm/disassembler/load_symbol_map.h arm/dynarmic/arm_dynarmic.h arm/dynarmic/arm_dynarmic_cp15.h arm/dyncom/arm_dyncom.h diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp deleted file mode 100644 index 05d6ed1fb..000000000 --- a/src/core/arm/disassembler/arm_disasm.cpp +++ /dev/null @@ -1,1344 +0,0 @@ -// Copyright 2006 The Android Open Source Project - -#include <string> -#include <unordered_set> -#include "common/common_types.h" -#include "common/string_util.h" -#include "core/arm/disassembler/arm_disasm.h" -#include "core/arm/skyeye_common/armsupp.h" - -static const char* cond_names[] = {"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", - "hi", "ls", "ge", "lt", "gt", "le", "", "RESERVED"}; - -static const char* opcode_names[] = { - "invalid", "undefined", "adc", "add", "and", "b", "bl", "bic", - "bkpt", "blx", "bx", "cdp", "clrex", "clz", "cmn", "cmp", - "eor", "ldc", "ldm", "ldr", "ldrb", "ldrbt", "ldrex", "ldrexb", - "ldrexd", "ldrexh", "ldrh", "ldrsb", "ldrsh", "ldrt", "mcr", "mla", - "mov", "mrc", "mrs", "msr", "mul", "mvn", "nop", "orr", - "pkh", "pld", "qadd16", "qadd8", "qasx", "qsax", "qsub16", "qsub8", - "rev", "rev16", "revsh", "rsb", "rsc", "sadd16", "sadd8", "sasx", - "sbc", "sel", "sev", "shadd16", "shadd8", "shasx", "shsax", "shsub16", - "shsub8", "smlad", "smlal", "smlald", "smlsd", "smlsld", "smmla", "smmls", - "smmul", "smuad", "smull", "smusd", "ssat", "ssat16", "ssax", "ssub16", - "ssub8", "stc", "stm", "str", "strb", "strbt", "strex", "strexb", - "strexd", "strexh", "strh", "strt", "sub", "swi", "swp", "swpb", - "sxtab", "sxtab16", "sxtah", "sxtb", "sxtb16", "sxth", "teq", "tst", - "uadd16", "uadd8", "uasx", "uhadd16", "uhadd8", "uhasx", "uhsax", "uhsub16", - "uhsub8", "umlal", "umull", "uqadd16", "uqadd8", "uqasx", "uqsax", "uqsub16", - "uqsub8", "usad8", "usada8", "usat", "usat16", "usax", "usub16", "usub8", - "uxtab", "uxtab16", "uxtah", "uxtb", "uxtb16", "uxth", "wfe", "wfi", - "yield", - - "undefined", "adc", "add", "and", "asr", "b", "bic", "bkpt", - "bl", "blx", "bx", "cmn", "cmp", "eor", "ldmia", "ldr", - "ldrb", "ldrh", "ldrsb", "ldrsh", "lsl", "lsr", "mov", "mul", - "mvn", "neg", "orr", "pop", "push", "ror", "sbc", "stmia", - "str", "strb", "strh", "sub", "swi", "tst", - - nullptr}; - -// Indexed by the shift type (bits 6-5) -static const char* shift_names[] = {"LSL", "LSR", "ASR", "ROR"}; - -static const char* cond_to_str(u32 cond) { - return cond_names[cond]; -} - -std::string ARM_Disasm::Disassemble(u32 addr, u32 insn) { - Opcode opcode = Decode(insn); - switch (opcode) { - case OP_INVALID: - return "Invalid"; - case OP_UNDEFINED: - return "Undefined"; - case OP_ADC: - case OP_ADD: - case OP_AND: - case OP_BIC: - case OP_CMN: - case OP_CMP: - case OP_EOR: - case OP_MOV: - case OP_MVN: - case OP_ORR: - case OP_RSB: - case OP_RSC: - case OP_SBC: - case OP_SUB: - case OP_TEQ: - case OP_TST: - return DisassembleALU(opcode, insn); - case OP_B: - case OP_BL: - return DisassembleBranch(addr, opcode, insn); - case OP_BKPT: - return DisassembleBKPT(insn); - case OP_BLX: - // not supported yet - break; - case OP_BX: - return DisassembleBX(insn); - case OP_CDP: - return "cdp"; - case OP_CLREX: - return "clrex"; - case OP_CLZ: - return DisassembleCLZ(insn); - case OP_LDC: - return "ldc"; - case OP_LDM: - case OP_STM: - return DisassembleMemblock(opcode, insn); - case OP_LDR: - case OP_LDRB: - case OP_LDRBT: - case OP_LDRT: - case OP_STR: - case OP_STRB: - case OP_STRBT: - case OP_STRT: - return DisassembleMem(insn); - case OP_LDREX: - case OP_LDREXB: - case OP_LDREXD: - case OP_LDREXH: - case OP_STREX: - case OP_STREXB: - case OP_STREXD: - case OP_STREXH: - return DisassembleREX(opcode, insn); - case OP_LDRH: - case OP_LDRSB: - case OP_LDRSH: - case OP_STRH: - return DisassembleMemHalf(insn); - case OP_MCR: - case OP_MRC: - return DisassembleMCR(opcode, insn); - case OP_MLA: - return DisassembleMLA(opcode, insn); - case OP_MRS: - return DisassembleMRS(insn); - case OP_MSR: - return DisassembleMSR(insn); - case OP_MUL: - return DisassembleMUL(opcode, insn); - case OP_NOP: - case OP_SEV: - case OP_WFE: - case OP_WFI: - case OP_YIELD: - return DisassembleNoOperands(opcode, insn); - case OP_PKH: - return DisassemblePKH(insn); - case OP_PLD: - return DisassemblePLD(insn); - case OP_QADD16: - case OP_QADD8: - case OP_QASX: - case OP_QSAX: - case OP_QSUB16: - case OP_QSUB8: - case OP_SADD16: - case OP_SADD8: - case OP_SASX: - case OP_SHADD16: - case OP_SHADD8: - case OP_SHASX: - case OP_SHSAX: - case OP_SHSUB16: - case OP_SHSUB8: - case OP_SSAX: - case OP_SSUB16: - case OP_SSUB8: - case OP_UADD16: - case OP_UADD8: - case OP_UASX: - case OP_UHADD16: - case OP_UHADD8: - case OP_UHASX: - case OP_UHSAX: - case OP_UHSUB16: - case OP_UHSUB8: - case OP_UQADD16: - case OP_UQADD8: - case OP_UQASX: - case OP_UQSAX: - case OP_UQSUB16: - case OP_UQSUB8: - case OP_USAX: - case OP_USUB16: - case OP_USUB8: - return DisassembleParallelAddSub(opcode, insn); - case OP_REV: - case OP_REV16: - case OP_REVSH: - return DisassembleREV(opcode, insn); - case OP_SEL: - return DisassembleSEL(insn); - case OP_SMLAD: - case OP_SMLALD: - case OP_SMLSD: - case OP_SMLSLD: - case OP_SMMLA: - case OP_SMMLS: - case OP_SMMUL: - case OP_SMUAD: - case OP_SMUSD: - case OP_USAD8: - case OP_USADA8: - return DisassembleMediaMulDiv(opcode, insn); - case OP_SSAT: - case OP_SSAT16: - case OP_USAT: - case OP_USAT16: - return DisassembleSAT(opcode, insn); - case OP_STC: - return "stc"; - case OP_SWI: - return DisassembleSWI(insn); - case OP_SWP: - case OP_SWPB: - return DisassembleSWP(opcode, insn); - case OP_SXTAB: - case OP_SXTAB16: - case OP_SXTAH: - case OP_SXTB: - case OP_SXTB16: - case OP_SXTH: - case OP_UXTAB: - case OP_UXTAB16: - case OP_UXTAH: - case OP_UXTB: - case OP_UXTB16: - case OP_UXTH: - return DisassembleXT(opcode, insn); - case OP_UMLAL: - case OP_UMULL: - case OP_SMLAL: - case OP_SMULL: - return DisassembleUMLAL(opcode, insn); - default: - return "Error"; - } - return nullptr; -} - -std::string ARM_Disasm::DisassembleALU(Opcode opcode, u32 insn) { - static const u8 kNoOperand1 = 1; - static const u8 kNoDest = 2; - static const u8 kNoSbit = 4; - - std::string rn_str; - std::string rd_str; - - u8 flags = 0; - u8 cond = (insn >> 28) & 0xf; - u8 is_immed = (insn >> 25) & 0x1; - u8 bit_s = (insn >> 20) & 1; - u8 rn = (insn >> 16) & 0xf; - u8 rd = (insn >> 12) & 0xf; - u8 immed = insn & 0xff; - - const char* opname = opcode_names[opcode]; - switch (opcode) { - case OP_CMN: - case OP_CMP: - case OP_TEQ: - case OP_TST: - flags = kNoDest | kNoSbit; - break; - case OP_MOV: - case OP_MVN: - flags = kNoOperand1; - break; - default: - break; - } - - // The "mov" instruction ignores the first operand (rn). - rn_str[0] = 0; - if ((flags & kNoOperand1) == 0) { - rn_str = Common::StringFromFormat("r%d, ", rn); - } - - // The following instructions do not write the result register (rd): - // tst, teq, cmp, cmn. - rd_str[0] = 0; - if ((flags & kNoDest) == 0) { - rd_str = Common::StringFromFormat("r%d, ", rd); - } - - const char* sbit_str = ""; - if (bit_s && !(flags & kNoSbit)) - sbit_str = "s"; - - if (is_immed) { - return Common::StringFromFormat("%s%s%s\t%s%s#%u ; 0x%x", opname, cond_to_str(cond), - sbit_str, rd_str.c_str(), rn_str.c_str(), immed, immed); - } - - u8 shift_is_reg = (insn >> 4) & 1; - u8 rotate = (insn >> 8) & 0xf; - u8 rm = insn & 0xf; - u8 shift_type = (insn >> 5) & 0x3; - u8 rs = (insn >> 8) & 0xf; - u8 shift_amount = (insn >> 7) & 0x1f; - u32 rotated_val = immed; - u8 rotate2 = rotate << 1; - rotated_val = (rotated_val >> rotate2) | (rotated_val << (32 - rotate2)); - - if (!shift_is_reg && shift_type == 0 && shift_amount == 0) { - return Common::StringFromFormat("%s%s%s\t%s%sr%d", opname, cond_to_str(cond), sbit_str, - rd_str.c_str(), rn_str.c_str(), rm); - } - - const char* shift_name = shift_names[shift_type]; - if (shift_is_reg) { - return Common::StringFromFormat("%s%s%s\t%s%sr%d, %s r%d", opname, cond_to_str(cond), - sbit_str, rd_str.c_str(), rn_str.c_str(), rm, shift_name, - rs); - } - if (shift_amount == 0) { - if (shift_type == 3) { - return Common::StringFromFormat("%s%s%s\t%s%sr%d, RRX", opname, cond_to_str(cond), - sbit_str, rd_str.c_str(), rn_str.c_str(), rm); - } - shift_amount = 32; - } - return Common::StringFromFormat("%s%s%s\t%s%sr%d, %s #%u", opname, cond_to_str(cond), sbit_str, - rd_str.c_str(), rn_str.c_str(), rm, shift_name, shift_amount); -} - -std::string ARM_Disasm::DisassembleBranch(u32 addr, Opcode opcode, u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u32 offset = insn & 0xffffff; - // Sign-extend the 24-bit offset - if ((offset >> 23) & 1) - offset |= 0xff000000; - - // Pre-compute the left-shift and the prefetch offset - offset <<= 2; - offset += 8; - addr += offset; - const char* opname = opcode_names[opcode]; - return Common::StringFromFormat("%s%s\t0x%x", opname, cond_to_str(cond), addr); -} - -std::string ARM_Disasm::DisassembleBX(u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 rn = insn & 0xf; - return Common::StringFromFormat("bx%s\tr%d", cond_to_str(cond), rn); -} - -std::string ARM_Disasm::DisassembleBKPT(u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u32 immed = (((insn >> 8) & 0xfff) << 4) | (insn & 0xf); - return Common::StringFromFormat("bkpt%s\t#%d", cond_to_str(cond), immed); -} - -std::string ARM_Disasm::DisassembleCLZ(u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 rd = (insn >> 12) & 0xf; - u8 rm = insn & 0xf; - return Common::StringFromFormat("clz%s\tr%d, r%d", cond_to_str(cond), rd, rm); -} - -std::string ARM_Disasm::DisassembleMediaMulDiv(Opcode opcode, u32 insn) { - u32 cond = BITS(insn, 28, 31); - u32 rd = BITS(insn, 16, 19); - u32 ra = BITS(insn, 12, 15); - u32 rm = BITS(insn, 8, 11); - u32 m = BIT(insn, 5); - u32 rn = BITS(insn, 0, 3); - - std::string cross = ""; - if (m) { - if (opcode == OP_SMMLA || opcode == OP_SMMUL || opcode == OP_SMMLS) - cross = "r"; - else - cross = "x"; - } - - std::string ext_reg = ""; - std::unordered_set<Opcode, std::hash<int>> with_ext_reg = {OP_SMLAD, OP_SMLSD, OP_SMMLA, - OP_SMMLS, OP_USADA8}; - if (with_ext_reg.find(opcode) != with_ext_reg.end()) - ext_reg = Common::StringFromFormat(", r%u", ra); - - std::string rd_low = ""; - if (opcode == OP_SMLALD || opcode == OP_SMLSLD) - rd_low = Common::StringFromFormat("r%u, ", ra); - - return Common::StringFromFormat("%s%s%s\t%sr%u, r%u, r%u%s", opcode_names[opcode], - cross.c_str(), cond_to_str(cond), rd_low.c_str(), rd, rn, rm, - ext_reg.c_str()); -} - -std::string ARM_Disasm::DisassembleMemblock(Opcode opcode, u32 insn) { - std::string tmp_list; - - u8 cond = (insn >> 28) & 0xf; - u8 write_back = (insn >> 21) & 0x1; - u8 bit_s = (insn >> 22) & 0x1; - u8 is_up = (insn >> 23) & 0x1; - u8 is_pre = (insn >> 24) & 0x1; - u8 rn = (insn >> 16) & 0xf; - u16 reg_list = insn & 0xffff; - - const char* opname = opcode_names[opcode]; - - const char* bang = ""; - if (write_back) - bang = "!"; - - const char* carret = ""; - if (bit_s) - carret = "^"; - - const char* comma = ""; - tmp_list[0] = 0; - for (int ii = 0; ii < 16; ++ii) { - if (reg_list & (1 << ii)) { - tmp_list += Common::StringFromFormat("%sr%d", comma, ii); - comma = ","; - } - } - - const char* addr_mode = ""; - if (is_pre) { - if (is_up) { - addr_mode = "ib"; - } else { - addr_mode = "db"; - } - } else { - if (is_up) { - addr_mode = "ia"; - } else { - addr_mode = "da"; - } - } - - return Common::StringFromFormat("%s%s%s\tr%d%s, {%s}%s", opname, cond_to_str(cond), addr_mode, - rn, bang, tmp_list.c_str(), carret); -} - -std::string ARM_Disasm::DisassembleMem(u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 is_reg = (insn >> 25) & 0x1; - u8 is_load = (insn >> 20) & 0x1; - u8 write_back = (insn >> 21) & 0x1; - u8 is_byte = (insn >> 22) & 0x1; - u8 is_up = (insn >> 23) & 0x1; - u8 is_pre = (insn >> 24) & 0x1; - u8 rn = (insn >> 16) & 0xf; - u8 rd = (insn >> 12) & 0xf; - u16 offset = insn & 0xfff; - - const char* opname = "ldr"; - if (!is_load) - opname = "str"; - - const char* bang = ""; - if (write_back) - bang = "!"; - - const char* minus = ""; - if (is_up == 0) - minus = "-"; - - const char* byte = ""; - if (is_byte) - byte = "b"; - - if (is_reg == 0) { - if (is_pre) { - if (offset == 0) { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d]", opname, cond_to_str(cond), - byte, rd, rn); - } else { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d, #%s%u]%s", opname, - cond_to_str(cond), byte, rd, rn, minus, offset, - bang); - } - } else { - const char* transfer = ""; - if (write_back) - transfer = "t"; - - return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], #%s%u", opname, - cond_to_str(cond), byte, transfer, rd, rn, minus, - offset); - } - } - - u8 rm = insn & 0xf; - u8 shift_type = (insn >> 5) & 0x3; - u8 shift_amount = (insn >> 7) & 0x1f; - - const char* shift_name = shift_names[shift_type]; - - if (is_pre) { - if (shift_amount == 0) { - if (shift_type == 0) { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d]%s", opname, - cond_to_str(cond), byte, rd, rn, minus, rm, bang); - } - if (shift_type == 3) { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, RRX]%s", opname, - cond_to_str(cond), byte, rd, rn, minus, rm, bang); - } - shift_amount = 32; - } - return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d, %s #%u]%s", opname, - cond_to_str(cond), byte, rd, rn, minus, rm, shift_name, - shift_amount, bang); - } - - const char* transfer = ""; - if (write_back) - transfer = "t"; - - if (shift_amount == 0) { - if (shift_type == 0) { - return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d", opname, - cond_to_str(cond), byte, transfer, rd, rn, minus, rm); - } - if (shift_type == 3) { - return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, RRX", opname, - cond_to_str(cond), byte, transfer, rd, rn, minus, rm); - } - shift_amount = 32; - } - - return Common::StringFromFormat("%s%s%s%s\tr%d, [r%d], %sr%d, %s #%u", opname, - cond_to_str(cond), byte, transfer, rd, rn, minus, rm, - shift_name, shift_amount); -} - -std::string ARM_Disasm::DisassembleMemHalf(u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 is_load = (insn >> 20) & 0x1; - u8 write_back = (insn >> 21) & 0x1; - u8 is_immed = (insn >> 22) & 0x1; - u8 is_up = (insn >> 23) & 0x1; - u8 is_pre = (insn >> 24) & 0x1; - u8 rn = (insn >> 16) & 0xf; - u8 rd = (insn >> 12) & 0xf; - u8 bits_65 = (insn >> 5) & 0x3; - u8 rm = insn & 0xf; - u8 offset = (((insn >> 8) & 0xf) << 4) | (insn & 0xf); - - const char* opname = "ldr"; - if (is_load == 0) - opname = "str"; - - const char* width = ""; - if (bits_65 == 1) - width = "h"; - else if (bits_65 == 2) - width = "sb"; - else - width = "sh"; - - const char* bang = ""; - if (write_back) - bang = "!"; - const char* minus = ""; - if (is_up == 0) - minus = "-"; - - if (is_immed) { - if (is_pre) { - if (offset == 0) { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d]", opname, cond_to_str(cond), - width, rd, rn); - } else { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d, #%s%u]%s", opname, - cond_to_str(cond), width, rd, rn, minus, offset, - bang); - } - } else { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d], #%s%u", opname, cond_to_str(cond), - width, rd, rn, minus, offset); - } - } - - if (is_pre) { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d, %sr%d]%s", opname, cond_to_str(cond), - width, rd, rn, minus, rm, bang); - } else { - return Common::StringFromFormat("%s%s%s\tr%d, [r%d], %sr%d", opname, cond_to_str(cond), - width, rd, rn, minus, rm); - } -} - -std::string ARM_Disasm::DisassembleMCR(Opcode opcode, u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 crn = (insn >> 16) & 0xf; - u8 crd = (insn >> 12) & 0xf; - u8 cpnum = (insn >> 8) & 0xf; - u8 opcode2 = (insn >> 5) & 0x7; - u8 crm = insn & 0xf; - - const char* opname = opcode_names[opcode]; - return Common::StringFromFormat("%s%s\t%d, 0, r%d, cr%d, cr%d, {%d}", opname, cond_to_str(cond), - cpnum, crd, crn, crm, opcode2); -} - -std::string ARM_Disasm::DisassembleMLA(Opcode opcode, u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 rd = (insn >> 16) & 0xf; - u8 rn = (insn >> 12) & 0xf; - u8 rs = (insn >> 8) & 0xf; - u8 rm = insn & 0xf; - u8 bit_s = (insn >> 20) & 1; - - const char* opname = opcode_names[opcode]; - return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d", opname, cond_to_str(cond), - bit_s ? "s" : "", rd, rm, rs, rn); -} - -std::string ARM_Disasm::DisassembleUMLAL(Opcode opcode, u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 rdhi = (insn >> 16) & 0xf; - u8 rdlo = (insn >> 12) & 0xf; - u8 rs = (insn >> 8) & 0xf; - u8 rm = insn & 0xf; - u8 bit_s = (insn >> 20) & 1; - - const char* opname = opcode_names[opcode]; - return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d, r%d", opname, cond_to_str(cond), - bit_s ? "s" : "", rdlo, rdhi, rm, rs); -} - -std::string ARM_Disasm::DisassembleMUL(Opcode opcode, u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 rd = (insn >> 16) & 0xf; - u8 rs = (insn >> 8) & 0xf; - u8 rm = insn & 0xf; - u8 bit_s = (insn >> 20) & 1; - - const char* opname = opcode_names[opcode]; - return Common::StringFromFormat("%s%s%s\tr%d, r%d, r%d", opname, cond_to_str(cond), - bit_s ? "s" : "", rd, rm, rs); -} - -std::string ARM_Disasm::DisassembleMRS(u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 rd = (insn >> 12) & 0xf; - u8 ps = (insn >> 22) & 1; - - return Common::StringFromFormat("mrs%s\tr%d, %s", cond_to_str(cond), rd, ps ? "spsr" : "cpsr"); -} - -std::string ARM_Disasm::DisassembleMSR(u32 insn) { - char flags[8]; - int flag_index = 0; - u8 cond = (insn >> 28) & 0xf; - u8 is_immed = (insn >> 25) & 0x1; - u8 pd = (insn >> 22) & 1; - u8 mask = (insn >> 16) & 0xf; - - if (mask & 1) - flags[flag_index++] = 'c'; - if (mask & 2) - flags[flag_index++] = 'x'; - if (mask & 4) - flags[flag_index++] = 's'; - if (mask & 8) - flags[flag_index++] = 'f'; - flags[flag_index] = 0; - - if (is_immed) { - u32 immed = insn & 0xff; - u8 rotate = (insn >> 8) & 0xf; - u8 rotate2 = rotate << 1; - u32 rotated_val = (immed >> rotate2) | (immed << (32 - rotate2)); - return Common::StringFromFormat("msr%s\t%s_%s, #0x%x", cond_to_str(cond), - pd ? "spsr" : "cpsr", flags, rotated_val); - } - - u8 rm = insn & 0xf; - - return Common::StringFromFormat("msr%s\t%s_%s, r%d", cond_to_str(cond), pd ? "spsr" : "cpsr", - flags, rm); -} - -std::string ARM_Disasm::DisassembleNoOperands(Opcode opcode, u32 insn) { - u32 cond = BITS(insn, 28, 31); - return Common::StringFromFormat("%s%s", opcode_names[opcode], cond_to_str(cond)); -} - -std::string ARM_Disasm::DisassembleParallelAddSub(Opcode opcode, u32 insn) { - u32 cond = BITS(insn, 28, 31); - u32 rn = BITS(insn, 16, 19); - u32 rd = BITS(insn, 12, 15); - u32 rm = BITS(insn, 0, 3); - - return Common::StringFromFormat("%s%s\tr%u, r%u, r%u", opcode_names[opcode], cond_to_str(cond), - rd, rn, rm); -} - -std::string ARM_Disasm::DisassemblePKH(u32 insn) { - u32 cond = BITS(insn, 28, 31); - u32 rn = BITS(insn, 16, 19); - u32 rd = BITS(insn, 12, 15); - u32 imm5 = BITS(insn, 7, 11); - u32 tb = BIT(insn, 6); - u32 rm = BITS(insn, 0, 3); - - std::string suffix = tb ? "tb" : "bt"; - std::string shift = ""; - - if (tb && imm5 == 0) - imm5 = 32; - - if (imm5 > 0) { - shift = tb ? ", ASR" : ", LSL"; - shift += " #" + std::to_string(imm5); - } - - return Common::StringFromFormat("pkh%s%s\tr%u, r%u, r%u%s", suffix.c_str(), cond_to_str(cond), - rd, rn, rm, shift.c_str()); -} - -std::string ARM_Disasm::DisassemblePLD(u32 insn) { - u8 is_reg = (insn >> 25) & 0x1; - u8 is_up = (insn >> 23) & 0x1; - u8 rn = (insn >> 16) & 0xf; - - const char* minus = ""; - if (is_up == 0) - minus = "-"; - - if (is_reg) { - u8 rm = insn & 0xf; - return Common::StringFromFormat("pld\t[r%d, %sr%d]", rn, minus, rm); - } - - u16 offset = insn & 0xfff; - if (offset == 0) { - return Common::StringFromFormat("pld\t[r%d]", rn); - } else { - return Common::StringFromFormat("pld\t[r%d, #%s%u]", rn, minus, offset); - } -} - -std::string ARM_Disasm::DisassembleREV(Opcode opcode, u32 insn) { - u32 cond = BITS(insn, 28, 31); - u32 rd = BITS(insn, 12, 15); - u32 rm = BITS(insn, 0, 3); - - return Common::StringFromFormat("%s%s\tr%u, r%u", opcode_names[opcode], cond_to_str(cond), rd, - rm); -} - -std::string ARM_Disasm::DisassembleREX(Opcode opcode, u32 insn) { - u32 rn = BITS(insn, 16, 19); - u32 rd = BITS(insn, 12, 15); - u32 rt = BITS(insn, 0, 3); - u32 cond = BITS(insn, 28, 31); - - switch (opcode) { - case OP_STREX: - case OP_STREXB: - case OP_STREXH: - return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opcode_names[opcode], - cond_to_str(cond), rd, rt, rn); - case OP_STREXD: - return Common::StringFromFormat("%s%s\tr%d, r%d, r%d, [r%d]", opcode_names[opcode], - cond_to_str(cond), rd, rt, rt + 1, rn); - - // for LDREX instructions, rd corresponds to Rt from reference manual - case OP_LDREX: - case OP_LDREXB: - case OP_LDREXH: - return Common::StringFromFormat("%s%s\tr%d, [r%d]", opcode_names[opcode], cond_to_str(cond), - rd, rn); - case OP_LDREXD: - return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opcode_names[opcode], - cond_to_str(cond), rd, rd + 1, rn); - default: - return opcode_names[OP_UNDEFINED]; - } -} - -std::string ARM_Disasm::DisassembleSAT(Opcode opcode, u32 insn) { - u32 cond = BITS(insn, 28, 31); - u32 sat_imm = BITS(insn, 16, 20); - u32 rd = BITS(insn, 12, 15); - u32 imm5 = BITS(insn, 7, 11); - u32 sh = BIT(insn, 6); - u32 rn = BITS(insn, 0, 3); - - std::string shift_part = ""; - bool opcode_has_shift = (opcode == OP_SSAT) || (opcode == OP_USAT); - if (opcode_has_shift && !(sh == 0 && imm5 == 0)) { - if (sh == 0) - shift_part += ", LSL #"; - else - shift_part += ", ASR #"; - - if (imm5 == 0) - imm5 = 32; - shift_part += std::to_string(imm5); - } - - if (opcode == OP_SSAT || opcode == OP_SSAT16) - sat_imm++; - - return Common::StringFromFormat("%s%s\tr%u, #%u, r%u%s", opcode_names[opcode], - cond_to_str(cond), rd, sat_imm, rn, shift_part.c_str()); -} - -std::string ARM_Disasm::DisassembleSEL(u32 insn) { - u32 cond = BITS(insn, 28, 31); - u32 rn = BITS(insn, 16, 19); - u32 rd = BITS(insn, 12, 15); - u32 rm = BITS(insn, 0, 3); - - return Common::StringFromFormat("%s%s\tr%u, r%u, r%u", opcode_names[OP_SEL], cond_to_str(cond), - rd, rn, rm); -} - -std::string ARM_Disasm::DisassembleSWI(u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u32 sysnum = insn & 0x00ffffff; - - return Common::StringFromFormat("swi%s 0x%x", cond_to_str(cond), sysnum); -} - -std::string ARM_Disasm::DisassembleSWP(Opcode opcode, u32 insn) { - u8 cond = (insn >> 28) & 0xf; - u8 rn = (insn >> 16) & 0xf; - u8 rd = (insn >> 12) & 0xf; - u8 rm = insn & 0xf; - - const char* opname = opcode_names[opcode]; - return Common::StringFromFormat("%s%s\tr%d, r%d, [r%d]", opname, cond_to_str(cond), rd, rm, rn); -} - -std::string ARM_Disasm::DisassembleXT(Opcode opcode, u32 insn) { - u32 cond = BITS(insn, 28, 31); - u32 rn = BITS(insn, 16, 19); - u32 rd = BITS(insn, 12, 15); - u32 rotate = BITS(insn, 10, 11); - u32 rm = BITS(insn, 0, 3); - - std::string rn_part = ""; - static std::unordered_set<Opcode, std::hash<int>> extend_with_add = { - OP_SXTAB, OP_SXTAB16, OP_SXTAH, OP_UXTAB, OP_UXTAB16, OP_UXTAH}; - if (extend_with_add.find(opcode) != extend_with_add.end()) - rn_part = ", r" + std::to_string(rn); - - std::string rotate_part = ""; - if (rotate != 0) - rotate_part = ", ROR #" + std::to_string(rotate << 3); - - return Common::StringFromFormat("%s%s\tr%u%s, r%u%s", opcode_names[opcode], cond_to_str(cond), - rd, rn_part.c_str(), rm, rotate_part.c_str()); -} - -Opcode ARM_Disasm::Decode(u32 insn) { - u32 bits27_26 = (insn >> 26) & 0x3; - switch (bits27_26) { - case 0x0: - return Decode00(insn); - case 0x1: - return Decode01(insn); - case 0x2: - return Decode10(insn); - case 0x3: - return Decode11(insn); - } - return OP_INVALID; -} - -Opcode ARM_Disasm::Decode00(u32 insn) { - u8 bit25 = (insn >> 25) & 0x1; - u8 bit4 = (insn >> 4) & 0x1; - if (bit25 == 0 && bit4 == 1) { - if ((insn & 0x0ffffff0) == 0x012fff10) { - // Bx instruction - return OP_BX; - } - if ((insn & 0x0ff000f0) == 0x01600010) { - // Clz instruction - return OP_CLZ; - } - if ((insn & 0xfff000f0) == 0xe1200070) { - // Bkpt instruction - return OP_BKPT; - } - u32 bits7_4 = (insn >> 4) & 0xf; - if (bits7_4 == 0x9) { - u32 bit24 = BIT(insn, 24); - if (bit24) { - return DecodeSyncPrimitive(insn); - } - // One of the multiply instructions - return DecodeMUL(insn); - } - - u8 bit7 = (insn >> 7) & 0x1; - if (bit7 == 1) { - // One of the load/store halfword/byte instructions - return DecodeLDRH(insn); - } - } - - u32 op1 = BITS(insn, 20, 24); - if (bit25 && (op1 == 0x12 || op1 == 0x16)) { - // One of the MSR (immediate) and hints instructions - return DecodeMSRImmAndHints(insn); - } - - // One of the data processing instructions - return DecodeALU(insn); -} - -Opcode ARM_Disasm::Decode01(u32 insn) { - u8 is_reg = (insn >> 25) & 0x1; - u8 bit4 = (insn >> 4) & 0x1; - if (is_reg == 1 && bit4 == 1) - return DecodeMedia(insn); - u8 is_load = (insn >> 20) & 0x1; - u8 is_byte = (insn >> 22) & 0x1; - if ((insn & 0xfd70f000) == 0xf550f000) { - // Pre-load - return OP_PLD; - } - if (insn == 0xf57ff01f) { - // Clear-Exclusive - return OP_CLREX; - } - if (is_load) { - if (is_byte) { - // Load byte - return OP_LDRB; - } - // Load word - return OP_LDR; - } - if (is_byte) { - // Store byte - return OP_STRB; - } - // Store word - return OP_STR; -} - -Opcode ARM_Disasm::Decode10(u32 insn) { - u8 bit25 = (insn >> 25) & 0x1; - if (bit25 == 0) { - // LDM/STM - u8 is_load = (insn >> 20) & 0x1; - if (is_load) - return OP_LDM; - return OP_STM; - } - - // Branch with link - if ((insn >> 24) & 1) - return OP_BL; - - return OP_B; -} - -Opcode ARM_Disasm::Decode11(u32 insn) { - u8 bit25 = (insn >> 25) & 0x1; - if (bit25 == 0) { - // LDC, SDC - u8 is_load = (insn >> 20) & 0x1; - if (is_load) { - // LDC - return OP_LDC; - } - // STC - return OP_STC; - } - - u8 bit24 = (insn >> 24) & 0x1; - if (bit24 == 0x1) { - // SWI - return OP_SWI; - } - - u8 bit4 = (insn >> 4) & 0x1; - u8 cpnum = (insn >> 8) & 0xf; - - if (cpnum == 15) { - // Special case for coprocessor 15 - u8 opcode = (insn >> 21) & 0x7; - if (bit4 == 0 || opcode != 0) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - - // MRC, MCR - u8 is_mrc = (insn >> 20) & 0x1; - if (is_mrc) - return OP_MRC; - return OP_MCR; - } - - if (bit4 == 0) { - // CDP - return OP_CDP; - } - // MRC, MCR - u8 is_mrc = (insn >> 20) & 0x1; - if (is_mrc) - return OP_MRC; - return OP_MCR; -} - -Opcode ARM_Disasm::DecodeSyncPrimitive(u32 insn) { - u32 op = BITS(insn, 20, 23); - u32 bit22 = BIT(insn, 22); - switch (op) { - case 0x0: - if (bit22) - return OP_SWPB; - return OP_SWP; - case 0x8: - return OP_STREX; - case 0x9: - return OP_LDREX; - case 0xA: - return OP_STREXD; - case 0xB: - return OP_LDREXD; - case 0xC: - return OP_STREXB; - case 0xD: - return OP_LDREXB; - case 0xE: - return OP_STREXH; - case 0xF: - return OP_LDREXH; - default: - return OP_UNDEFINED; - } -} - -Opcode ARM_Disasm::DecodeParallelAddSub(u32 insn) { - u32 op1 = BITS(insn, 20, 21); - u32 op2 = BITS(insn, 5, 7); - u32 is_unsigned = BIT(insn, 22); - - if (op1 == 0x0 || op2 == 0x5 || op2 == 0x6) - return OP_UNDEFINED; - - // change op1 range from [1, 3] to range [0, 2] - op1--; - - // change op2 range from [0, 4] U {7} to range [0, 5] - if (op2 == 0x7) - op2 = 0x5; - - static std::vector<Opcode> opcodes = { - // op1 = 0 - OP_SADD16, OP_UADD16, OP_SASX, OP_UASX, OP_SSAX, OP_USAX, OP_SSUB16, OP_USUB16, OP_SADD8, - OP_UADD8, OP_SSUB8, OP_USUB8, - // op1 = 1 - OP_QADD16, OP_UQADD16, OP_QASX, OP_UQASX, OP_QSAX, OP_UQSAX, OP_QSUB16, OP_UQSUB16, - OP_QADD8, OP_UQADD8, OP_QSUB8, OP_UQSUB8, - // op1 = 2 - OP_SHADD16, OP_UHADD16, OP_SHASX, OP_UHASX, OP_SHSAX, OP_UHSAX, OP_SHSUB16, OP_UHSUB16, - OP_SHADD8, OP_UHADD8, OP_SHSUB8, OP_UHSUB8}; - - u32 opcode_index = op1 * 12 + op2 * 2 + is_unsigned; - return opcodes[opcode_index]; -} - -Opcode ARM_Disasm::DecodePackingSaturationReversal(u32 insn) { - u32 op1 = BITS(insn, 20, 22); - u32 a = BITS(insn, 16, 19); - u32 op2 = BITS(insn, 5, 7); - - switch (op1) { - case 0x0: - if (BIT(op2, 0) == 0) - return OP_PKH; - if (op2 == 0x3 && a != 0xf) - return OP_SXTAB16; - if (op2 == 0x3 && a == 0xf) - return OP_SXTB16; - if (op2 == 0x5) - return OP_SEL; - break; - case 0x2: - if (BIT(op2, 0) == 0) - return OP_SSAT; - if (op2 == 0x1) - return OP_SSAT16; - if (op2 == 0x3 && a != 0xf) - return OP_SXTAB; - if (op2 == 0x3 && a == 0xf) - return OP_SXTB; - break; - case 0x3: - if (op2 == 0x1) - return OP_REV; - if (BIT(op2, 0) == 0) - return OP_SSAT; - if (op2 == 0x3 && a != 0xf) - return OP_SXTAH; - if (op2 == 0x3 && a == 0xf) - return OP_SXTH; - if (op2 == 0x5) - return OP_REV16; - break; - case 0x4: - if (op2 == 0x3 && a != 0xf) - return OP_UXTAB16; - if (op2 == 0x3 && a == 0xf) - return OP_UXTB16; - break; - case 0x6: - if (BIT(op2, 0) == 0) - return OP_USAT; - if (op2 == 0x1) - return OP_USAT16; - if (op2 == 0x3 && a != 0xf) - return OP_UXTAB; - if (op2 == 0x3 && a == 0xf) - return OP_UXTB; - break; - case 0x7: - if (BIT(op2, 0) == 0) - return OP_USAT; - if (op2 == 0x3 && a != 0xf) - return OP_UXTAH; - if (op2 == 0x3 && a == 0xf) - return OP_UXTH; - if (op2 == 0x5) - return OP_REVSH; - break; - default: - break; - } - - return OP_UNDEFINED; -} - -Opcode ARM_Disasm::DecodeMUL(u32 insn) { - u8 bit24 = (insn >> 24) & 0x1; - if (bit24 != 0) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - u8 bit23 = (insn >> 23) & 0x1; - u8 bit22_U = (insn >> 22) & 0x1; - u8 bit21_A = (insn >> 21) & 0x1; - if (bit23 == 0) { - // 32-bit multiply - if (bit22_U != 0) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - if (bit21_A == 0) - return OP_MUL; - return OP_MLA; - } - // 64-bit multiply - if (bit22_U == 0) { - // Unsigned multiply long - if (bit21_A == 0) - return OP_UMULL; - return OP_UMLAL; - } - // Signed multiply long - if (bit21_A == 0) - return OP_SMULL; - return OP_SMLAL; -} - -Opcode ARM_Disasm::DecodeMSRImmAndHints(u32 insn) { - u32 op = BIT(insn, 22); - u32 op1 = BITS(insn, 16, 19); - u32 op2 = BITS(insn, 0, 7); - - if (op == 0 && op1 == 0) { - switch (op2) { - case 0x0: - return OP_NOP; - case 0x1: - return OP_YIELD; - case 0x2: - return OP_WFE; - case 0x3: - return OP_WFI; - case 0x4: - return OP_SEV; - default: - return OP_UNDEFINED; - } - } - - return OP_MSR; -} - -Opcode ARM_Disasm::DecodeMediaMulDiv(u32 insn) { - u32 op1 = BITS(insn, 20, 22); - u32 op2_h = BITS(insn, 6, 7); - u32 a = BITS(insn, 12, 15); - - switch (op1) { - case 0x0: - if (op2_h == 0x0) { - if (a != 0xf) - return OP_SMLAD; - else - return OP_SMUAD; - } else if (op2_h == 0x1) { - if (a != 0xf) - return OP_SMLSD; - else - return OP_SMUSD; - } - break; - case 0x4: - if (op2_h == 0x0) - return OP_SMLALD; - else if (op2_h == 0x1) - return OP_SMLSLD; - break; - case 0x5: - if (op2_h == 0x0) { - if (a != 0xf) - return OP_SMMLA; - else - return OP_SMMUL; - } else if (op2_h == 0x3) { - return OP_SMMLS; - } - break; - default: - break; - } - - return OP_UNDEFINED; -} - -Opcode ARM_Disasm::DecodeMedia(u32 insn) { - u32 op1 = BITS(insn, 20, 24); - u32 rd = BITS(insn, 12, 15); - u32 op2 = BITS(insn, 5, 7); - - switch (BITS(op1, 3, 4)) { - case 0x0: - // unsigned and signed parallel addition and subtraction - return DecodeParallelAddSub(insn); - case 0x1: - // Packing, unpacking, saturation, and reversal - return DecodePackingSaturationReversal(insn); - case 0x2: - // Signed multiply, signed and unsigned divide - return DecodeMediaMulDiv(insn); - case 0x3: - if (op2 == 0 && rd == 0xf) - return OP_USAD8; - if (op2 == 0 && rd != 0xf) - return OP_USADA8; - break; - default: - break; - } - - return OP_UNDEFINED; -} - -Opcode ARM_Disasm::DecodeLDRH(u32 insn) { - u8 is_load = (insn >> 20) & 0x1; - u8 bits_65 = (insn >> 5) & 0x3; - if (is_load) { - if (bits_65 == 0x1) { - // Load unsigned halfword - return OP_LDRH; - } else if (bits_65 == 0x2) { - // Load signed byte - return OP_LDRSB; - } - // Signed halfword - if (bits_65 != 0x3) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - // Load signed halfword - return OP_LDRSH; - } - // Store halfword - if (bits_65 != 0x1) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - // Store halfword - return OP_STRH; -} - -Opcode ARM_Disasm::DecodeALU(u32 insn) { - u8 is_immed = (insn >> 25) & 0x1; - u8 opcode = (insn >> 21) & 0xf; - u8 bit_s = (insn >> 20) & 1; - u8 shift_is_reg = (insn >> 4) & 1; - u8 bit7 = (insn >> 7) & 1; - if (!is_immed && shift_is_reg && (bit7 != 0)) { - // This is an unexpected bit pattern. Create an undefined - // instruction in case this is ever executed. - return OP_UNDEFINED; - } - switch (opcode) { - case 0x0: - return OP_AND; - case 0x1: - return OP_EOR; - case 0x2: - return OP_SUB; - case 0x3: - return OP_RSB; - case 0x4: - return OP_ADD; - case 0x5: - return OP_ADC; - case 0x6: - return OP_SBC; - case 0x7: - return OP_RSC; - case 0x8: - if (bit_s) - return OP_TST; - return OP_MRS; - case 0x9: - if (bit_s) - return OP_TEQ; - return OP_MSR; - case 0xa: - if (bit_s) - return OP_CMP; - return OP_MRS; - case 0xb: - if (bit_s) - return OP_CMN; - return OP_MSR; - case 0xc: - return OP_ORR; - case 0xd: - return OP_MOV; - case 0xe: - return OP_BIC; - case 0xf: - return OP_MVN; - } - // Unreachable - return OP_INVALID; -} diff --git a/src/core/arm/disassembler/arm_disasm.h b/src/core/arm/disassembler/arm_disasm.h deleted file mode 100644 index 300e228ed..000000000 --- a/src/core/arm/disassembler/arm_disasm.h +++ /dev/null @@ -1,238 +0,0 @@ -// Copyright 2006 The Android Open Source Project - -#pragma once - -#include <string> -#include "common/common_types.h" - -// Note: this list of opcodes must match the list used to initialize -// the opflags[] array in opcode.cpp. -enum Opcode { - OP_INVALID, - OP_UNDEFINED, - OP_ADC, - OP_ADD, - OP_AND, - OP_B, - OP_BL, - OP_BIC, - OP_BKPT, - OP_BLX, - OP_BX, - OP_CDP, - OP_CLREX, - OP_CLZ, - OP_CMN, - OP_CMP, - OP_EOR, - OP_LDC, - OP_LDM, - OP_LDR, - OP_LDRB, - OP_LDRBT, - OP_LDREX, - OP_LDREXB, - OP_LDREXD, - OP_LDREXH, - OP_LDRH, - OP_LDRSB, - OP_LDRSH, - OP_LDRT, - OP_MCR, - OP_MLA, - OP_MOV, - OP_MRC, - OP_MRS, - OP_MSR, - OP_MUL, - OP_MVN, - OP_NOP, - OP_ORR, - OP_PKH, - OP_PLD, - OP_QADD16, - OP_QADD8, - OP_QASX, - OP_QSAX, - OP_QSUB16, - OP_QSUB8, - OP_REV, - OP_REV16, - OP_REVSH, - OP_RSB, - OP_RSC, - OP_SADD16, - OP_SADD8, - OP_SASX, - OP_SBC, - OP_SEL, - OP_SEV, - OP_SHADD16, - OP_SHADD8, - OP_SHASX, - OP_SHSAX, - OP_SHSUB16, - OP_SHSUB8, - OP_SMLAD, - OP_SMLAL, - OP_SMLALD, - OP_SMLSD, - OP_SMLSLD, - OP_SMMLA, - OP_SMMLS, - OP_SMMUL, - OP_SMUAD, - OP_SMULL, - OP_SMUSD, - OP_SSAT, - OP_SSAT16, - OP_SSAX, - OP_SSUB16, - OP_SSUB8, - OP_STC, - OP_STM, - OP_STR, - OP_STRB, - OP_STRBT, - OP_STREX, - OP_STREXB, - OP_STREXD, - OP_STREXH, - OP_STRH, - OP_STRT, - OP_SUB, - OP_SWI, - OP_SWP, - OP_SWPB, - OP_SXTAB, - OP_SXTAB16, - OP_SXTAH, - OP_SXTB, - OP_SXTB16, - OP_SXTH, - OP_TEQ, - OP_TST, - OP_UADD16, - OP_UADD8, - OP_UASX, - OP_UHADD16, - OP_UHADD8, - OP_UHASX, - OP_UHSAX, - OP_UHSUB16, - OP_UHSUB8, - OP_UMLAL, - OP_UMULL, - OP_UQADD16, - OP_UQADD8, - OP_UQASX, - OP_UQSAX, - OP_UQSUB16, - OP_UQSUB8, - OP_USAD8, - OP_USADA8, - OP_USAT, - OP_USAT16, - OP_USAX, - OP_USUB16, - OP_USUB8, - OP_UXTAB, - OP_UXTAB16, - OP_UXTAH, - OP_UXTB, - OP_UXTB16, - OP_UXTH, - OP_WFE, - OP_WFI, - OP_YIELD, - - // Define thumb opcodes - OP_THUMB_UNDEFINED, - OP_THUMB_ADC, - OP_THUMB_ADD, - OP_THUMB_AND, - OP_THUMB_ASR, - OP_THUMB_B, - OP_THUMB_BIC, - OP_THUMB_BKPT, - OP_THUMB_BL, - OP_THUMB_BLX, - OP_THUMB_BX, - OP_THUMB_CMN, - OP_THUMB_CMP, - OP_THUMB_EOR, - OP_THUMB_LDMIA, - OP_THUMB_LDR, - OP_THUMB_LDRB, - OP_THUMB_LDRH, - OP_THUMB_LDRSB, - OP_THUMB_LDRSH, - OP_THUMB_LSL, - OP_THUMB_LSR, - OP_THUMB_MOV, - OP_THUMB_MUL, - OP_THUMB_MVN, - OP_THUMB_NEG, - OP_THUMB_ORR, - OP_THUMB_POP, - OP_THUMB_PUSH, - OP_THUMB_ROR, - OP_THUMB_SBC, - OP_THUMB_STMIA, - OP_THUMB_STR, - OP_THUMB_STRB, - OP_THUMB_STRH, - OP_THUMB_SUB, - OP_THUMB_SWI, - OP_THUMB_TST, - - OP_END // must be last -}; - -class ARM_Disasm { -public: - static std::string Disassemble(u32 addr, u32 insn); - static Opcode Decode(u32 insn); - -private: - static Opcode Decode00(u32 insn); - static Opcode Decode01(u32 insn); - static Opcode Decode10(u32 insn); - static Opcode Decode11(u32 insn); - static Opcode DecodeSyncPrimitive(u32 insn); - static Opcode DecodeParallelAddSub(u32 insn); - static Opcode DecodePackingSaturationReversal(u32 insn); - static Opcode DecodeMUL(u32 insn); - static Opcode DecodeMSRImmAndHints(u32 insn); - static Opcode DecodeMediaMulDiv(u32 insn); - static Opcode DecodeMedia(u32 insn); - static Opcode DecodeLDRH(u32 insn); - static Opcode DecodeALU(u32 insn); - - static std::string DisassembleALU(Opcode opcode, u32 insn); - static std::string DisassembleBranch(u32 addr, Opcode opcode, u32 insn); - static std::string DisassembleBX(u32 insn); - static std::string DisassembleBKPT(u32 insn); - static std::string DisassembleCLZ(u32 insn); - static std::string DisassembleMediaMulDiv(Opcode opcode, u32 insn); - static std::string DisassembleMemblock(Opcode opcode, u32 insn); - static std::string DisassembleMem(u32 insn); - static std::string DisassembleMemHalf(u32 insn); - static std::string DisassembleMCR(Opcode opcode, u32 insn); - static std::string DisassembleMLA(Opcode opcode, u32 insn); - static std::string DisassembleUMLAL(Opcode opcode, u32 insn); - static std::string DisassembleMUL(Opcode opcode, u32 insn); - static std::string DisassembleMRS(u32 insn); - static std::string DisassembleMSR(u32 insn); - static std::string DisassembleNoOperands(Opcode opcode, u32 insn); - static std::string DisassembleParallelAddSub(Opcode opcode, u32 insn); - static std::string DisassemblePKH(u32 insn); - static std::string DisassemblePLD(u32 insn); - static std::string DisassembleREV(Opcode opcode, u32 insn); - static std::string DisassembleREX(Opcode opcode, u32 insn); - static std::string DisassembleSAT(Opcode opcode, u32 insn); - static std::string DisassembleSEL(u32 insn); - static std::string DisassembleSWI(u32 insn); - static std::string DisassembleSWP(Opcode opcode, u32 insn); - static std::string DisassembleXT(Opcode opcode, u32 insn); -}; diff --git a/src/core/arm/disassembler/load_symbol_map.cpp b/src/core/arm/disassembler/load_symbol_map.cpp deleted file mode 100644 index 6863c103a..000000000 --- a/src/core/arm/disassembler/load_symbol_map.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <sstream> -#include <string> -#include <vector> -#include "common/file_util.h" -#include "common/symbols.h" -#include "core/arm/disassembler/load_symbol_map.h" - -/* - * Loads a symbol map file for use with the disassembler - * @param filename String filename path of symbol map file - */ -void LoadSymbolMap(std::string filename) { - std::ifstream infile(filename); - - std::string address_str, function_name, line; - u32 size; - - while (std::getline(infile, line)) { - std::istringstream iss(line); - if (!(iss >> address_str >> size >> function_name)) { - break; // Error parsing - } - u32 address = std::stoul(address_str, nullptr, 16); - - Symbols::Add(address, function_name, size, 2); - } -} diff --git a/src/core/arm/disassembler/load_symbol_map.h b/src/core/arm/disassembler/load_symbol_map.h deleted file mode 100644 index d28c551c3..000000000 --- a/src/core/arm/disassembler/load_symbol_map.h +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <string> - -/* - * Loads a symbol map file for use with the disassembler - * @param filename String filename path of symbol map file - */ -void LoadSymbolMap(std::string filename); diff --git a/src/core/arm/dyncom/arm_dyncom_dec.cpp b/src/core/arm/dyncom/arm_dyncom_dec.cpp index 64dcaae08..dcfcd6561 100644 --- a/src/core/arm/dyncom/arm_dyncom_dec.cpp +++ b/src/core/arm/dyncom/arm_dyncom_dec.cpp @@ -415,7 +415,7 @@ const InstructionSetEncodingItem arm_exclusion_code[] = { }; // clang-format on -ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx) { +ARMDecodeStatus DecodeARMInstruction(u32 instr, int* idx) { int n = 0; int base = 0; int instr_slots = sizeof(arm_instruction) / sizeof(InstructionSetEncodingItem); diff --git a/src/core/arm/dyncom/arm_dyncom_dec.h b/src/core/arm/dyncom/arm_dyncom_dec.h index 2fb7ac37c..1dcf7ecd1 100644 --- a/src/core/arm/dyncom/arm_dyncom_dec.h +++ b/src/core/arm/dyncom/arm_dyncom_dec.h @@ -8,7 +8,7 @@ enum class ARMDecodeStatus { SUCCESS, FAILURE }; -ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx); +ARMDecodeStatus DecodeARMInstruction(u32 instr, int* idx); struct InstructionSetEncodingItem { const char* name; diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index 273bc8167..f4fbb8d04 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp @@ -5,11 +5,11 @@ #define CITRA_IGNORE_EXIT(x) #include <algorithm> +#include <cinttypes> #include <cstdio> #include "common/common_types.h" #include "common/logging/log.h" #include "common/microprofile.h" -#include "core/arm/disassembler/arm_disasm.h" #include "core/arm/dyncom/arm_dyncom_dec.h" #include "core/arm/dyncom/arm_dyncom_interpreter.h" #include "core/arm/dyncom/arm_dyncom_run.h" @@ -808,8 +808,8 @@ MICROPROFILE_DEFINE(DynCom_Decode, "DynCom", "Decode", MP_RGB(255, 64, 64)); static unsigned int InterpreterTranslateInstruction(const ARMul_State* cpu, const u32 phys_addr, ARM_INST_PTR& inst_base) { - unsigned int inst_size = 4; - unsigned int inst = Memory::Read32(phys_addr & 0xFFFFFFFC); + u32 inst_size = 4; + u32 inst = Memory::Read32(phys_addr & 0xFFFFFFFC); // If we are in Thumb mode, we'll translate one Thumb instruction to the corresponding ARM // instruction @@ -827,11 +827,10 @@ static unsigned int InterpreterTranslateInstruction(const ARMul_State* cpu, cons int idx; if (DecodeARMInstruction(inst, &idx) == ARMDecodeStatus::FAILURE) { - std::string disasm = ARM_Disasm::Disassemble(phys_addr, inst); - LOG_ERROR(Core_ARM11, "Decode failure.\tPC : [0x%x]\tInstruction : %s [%x]", phys_addr, - disasm.c_str(), inst); - LOG_ERROR(Core_ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x", cpu->Cpsr, cpu->TFlag, - cpu->Reg[15]); + LOG_ERROR(Core_ARM11, "Decode failure.\tPC: [0x%08" PRIX32 "]\tInstruction: %08" PRIX32, + phys_addr, inst); + LOG_ERROR(Core_ARM11, "cpsr=0x%" PRIX32 ", cpu->TFlag=%d, r15=0x%08" PRIX32, cpu->Cpsr, + cpu->TFlag, cpu->Reg[15]); CITRA_IGNORE_EXIT(-1); } inst_base = arm_instruction_trans[idx](inst, idx); diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h index 5e14345ce..1eba71b48 100644 --- a/src/core/arm/skyeye_common/vfp/vfp_helper.h +++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h @@ -291,7 +291,7 @@ inline s32 vfp_single_pack(const vfp_single* s) { return (s32)val; } -u32 vfp_single_normaliseround(ARMul_State* state, int sd, vfp_single* vs, u32 fpscr, +u32 vfp_single_normaliseround(ARMul_State* state, int sd, vfp_single* vs, u32 fpscr, u32 exceptions, const char* func); // Double-precision @@ -429,5 +429,5 @@ inline u32 fls(u32 x) { u32 vfp_double_multiply(vfp_double* vdd, vfp_double* vdn, vfp_double* vdm, u32 fpscr); u32 vfp_double_add(vfp_double* vdd, vfp_double* vdn, vfp_double* vdm, u32 fpscr); -u32 vfp_double_normaliseround(ARMul_State* state, int dd, vfp_double* vd, u32 fpscr, +u32 vfp_double_normaliseround(ARMul_State* state, int dd, vfp_double* vd, u32 fpscr, u32 exceptions, const char* func); diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp index 2886f351f..7b035f56a 100644 --- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp @@ -82,11 +82,10 @@ static void vfp_double_normalise_denormal(struct vfp_double* vd) { } u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double* vd, u32 fpscr, - const char* func) { + u32 exceptions, const char* func) { u64 significand, incr; int exponent, shift, underflow; u32 rmode; - u32 exceptions = 0; vfp_double_dump("pack: in", vd); @@ -360,7 +359,8 @@ static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 } vdd.significand = vfp_shiftright64jamming(vdd.significand, 1); - exceptions |= vfp_double_normaliseround(state, dd, &vdd, fpscr, "fsqrt"); + exceptions |= vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fsqrt"); + return exceptions; } @@ -492,8 +492,7 @@ static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 else vsd.exponent = vdm.exponent - (1023 - 127); - exceptions |= vfp_single_normaliseround(state, sd, &vsd, fpscr, "fcvts"); - return exceptions; + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fcvts"); pack_nan: vfp_put_float(state, vfp_single_pack(&vsd), sd); @@ -502,7 +501,6 @@ pack_nan: static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { struct vfp_double vdm; - u32 exceptions = 0; u32 m = vfp_get_float(state, dm); LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); @@ -510,13 +508,11 @@ static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 vdm.exponent = 1023 + 63 - 1; vdm.significand = (u64)m; - exceptions |= vfp_double_normaliseround(state, dd, &vdm, fpscr, "fuito"); - return exceptions; + return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fuito"); } static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) { struct vfp_double vdm; - u32 exceptions = 0; u32 m = vfp_get_float(state, dm); LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); @@ -524,8 +520,7 @@ static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 vdm.exponent = 1023 + 63 - 1; vdm.significand = vdm.sign ? (~m + 1) : m; - exceptions |= vfp_double_normaliseround(state, dd, &vdm, fpscr, "fsito"); - return exceptions; + return vfp_double_normaliseround(state, dd, &vdm, fpscr, 0, "fsito"); } static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) { @@ -912,8 +907,7 @@ static u32 vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, in exceptions |= vfp_double_add(&vdd, &vdn, &vdp, fpscr); - exceptions |= vfp_double_normaliseround(state, dd, &vdd, fpscr, func); - return exceptions; + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, func); } /* @@ -970,9 +964,7 @@ static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr vfp_double_normalise_denormal(&vdm); exceptions |= vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); - - exceptions |= vfp_double_normaliseround(state, dd, &vdd, fpscr, "fmul"); - return exceptions; + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fmul"); } /* @@ -994,8 +986,7 @@ static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpsc exceptions |= vfp_double_multiply(&vdd, &vdn, &vdm, fpscr); vdd.sign = vfp_sign_negate(vdd.sign); - exceptions |= vfp_double_normaliseround(state, dd, &vdd, fpscr, "fnmul"); - return exceptions; + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fnmul"); } /* @@ -1016,8 +1007,7 @@ static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr exceptions |= vfp_double_add(&vdd, &vdn, &vdm, fpscr); - exceptions |= vfp_double_normaliseround(state, dd, &vdd, fpscr, "fadd"); - return exceptions; + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fadd"); } /* @@ -1043,8 +1033,7 @@ static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr exceptions |= vfp_double_add(&vdd, &vdn, &vdm, fpscr); - exceptions |= vfp_double_normaliseround(state, dd, &vdd, fpscr, "fsub"); - return exceptions; + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fsub"); } /* @@ -1126,9 +1115,7 @@ static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr } vdd.significand |= (reml != 0); } - - exceptions |= vfp_double_normaliseround(state, dd, &vdd, fpscr, "fdiv"); - return exceptions; + return vfp_double_normaliseround(state, dd, &vdd, fpscr, 0, "fdiv"); vdn_nan: exceptions |= vfp_propagate_nan(&vdd, &vdn, &vdm, fpscr); @@ -1154,8 +1141,7 @@ infinity: invalid: vfp_put_double(state, vfp_double_pack(&vfp_double_default_qnan), dd); - exceptions |= FPSCR_IOC; - return exceptions; + return FPSCR_IOC; } static struct op fops[] = { @@ -1230,7 +1216,7 @@ u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) { except = fop->fn(state, dest, dn, dm, fpscr); LOG_TRACE(Core_ARM11, "VFP: itr%d: exceptions=%08x", vecitr >> FPSCR_LENGTH_BIT, except); - exceptions |= except; + exceptions |= except & ~VFP_NAN_FLAG; /* * CHECK: It appears to be undefined whether we stop when diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp index 1590d89a4..ae5b325f0 100644 --- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp @@ -83,10 +83,9 @@ static void vfp_single_normalise_denormal(struct vfp_single* vs) { } u32 vfp_single_normaliseround(ARMul_State* state, int sd, struct vfp_single* vs, u32 fpscr, - const char* func) { + u32 exceptions, const char* func) { u32 significand, incr, rmode; int exponent, shift, underflow; - u32 exceptions = 0; vfp_single_dump("pack: in", vs); @@ -394,7 +393,8 @@ static u32 vfp_single_fsqrt(ARMul_State* state, int sd, int unused, s32 m, u32 f } vsd.significand = vfp_shiftright32jamming(vsd.significand, 1); - exceptions |= vfp_single_normaliseround(state, sd, &vsd, fpscr, "fsqrt"); + exceptions |= vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fsqrt"); + return exceptions; } @@ -515,8 +515,7 @@ static u32 vfp_single_fcvtd(ARMul_State* state, int dd, int unused, s32 m, u32 f else vdd.exponent = vsm.exponent + (1023 - 127); - exceptions |= vfp_double_normaliseround(state, dd, &vdd, fpscr, "fcvtd"); - return exceptions; + return vfp_double_normaliseround(state, dd, &vdd, fpscr, exceptions, "fcvtd"); pack_nan: vfp_put_double(state, vfp_double_pack(&vdd), dd); @@ -525,26 +524,22 @@ pack_nan: static u32 vfp_single_fuito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { struct vfp_single vs; - u32 exceptions = 0; vs.sign = 0; vs.exponent = 127 + 31 - 1; vs.significand = (u32)m; - exceptions |= vfp_single_normaliseround(state, sd, &vs, fpscr, "fuito"); - return exceptions; + return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fuito"); } static u32 vfp_single_fsito(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { struct vfp_single vs; - u32 exceptions = 0; vs.sign = (m & 0x80000000) >> 16; vs.exponent = 127 + 31 - 1; vs.significand = vs.sign ? -m : m; - exceptions |= vfp_single_normaliseround(state, sd, &vs, fpscr, "fsito"); - return exceptions; + return vfp_single_normaliseround(state, sd, &vs, fpscr, 0, "fsito"); } static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 fpscr) { @@ -936,8 +931,7 @@ static u32 vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s3 exceptions |= vfp_single_add(&vsd, &vsn, &vsp, fpscr); - exceptions |= vfp_single_normaliseround(state, sd, &vsd, fpscr, func); - return exceptions; + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, func); } /* @@ -948,10 +942,8 @@ static u32 vfp_single_multiply_accumulate(ARMul_State* state, int sd, int sn, s3 * sd = sd + (sn * sm) */ static u32 vfp_single_fmac(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) { - u32 exceptions = 0; LOG_TRACE(Core_ARM11, "s%u = %08x", sn, sd); - exceptions |= vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac"); - return exceptions; + return vfp_single_multiply_accumulate(state, sd, sn, m, fpscr, 0, "fmac"); } /* @@ -999,9 +991,7 @@ static u32 vfp_single_fmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) vfp_single_normalise_denormal(&vsm); exceptions |= vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); - - exceptions |= vfp_single_normaliseround(state, sd, &vsd, fpscr, "fmul"); - return exceptions; + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fmul"); } /* @@ -1024,9 +1014,7 @@ static u32 vfp_single_fnmul(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr exceptions |= vfp_single_multiply(&vsd, &vsn, &vsm, fpscr); vsd.sign = vfp_sign_negate(vsd.sign); - - exceptions |= vfp_single_normaliseround(state, sd, &vsd, fpscr, "fnmul"); - return exceptions; + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fnmul"); } /* @@ -1052,8 +1040,7 @@ static u32 vfp_single_fadd(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) exceptions |= vfp_single_add(&vsd, &vsn, &vsm, fpscr); - exceptions |= vfp_single_normaliseround(state, sd, &vsd, fpscr, "fadd"); - return exceptions; + return vfp_single_normaliseround(state, sd, &vsd, fpscr, exceptions, "fadd"); } /* @@ -1148,8 +1135,7 @@ static u32 vfp_single_fdiv(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr) if ((vsd.significand & 0x3f) == 0) vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32); - exceptions |= vfp_single_normaliseround(state, sd, &vsd, fpscr, "fdiv"); - return exceptions; + return vfp_single_normaliseround(state, sd, &vsd, fpscr, 0, "fdiv"); vsn_nan: exceptions |= vfp_propagate_nan(&vsd, &vsn, &vsm, fpscr); @@ -1175,8 +1161,7 @@ infinity: invalid: vfp_put_float(state, vfp_single_pack(&vfp_single_default_qnan), sd); - exceptions |= FPSCR_IOC; - return exceptions; + return FPSCR_IOC; } static struct op fops[] = { @@ -1246,7 +1231,7 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr) { except = fop->fn(state, dest, sn, m, fpscr); LOG_TRACE(Core_ARM11, "itr%d: exceptions=%08x", vecitr >> FPSCR_LENGTH_BIT, except); - exceptions |= except; + exceptions |= except & ~VFP_NAN_FLAG; /* * CHECK: It appears to be undefined whether we stop when diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index b19e831fe..64d01cdd7 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -53,30 +53,29 @@ static std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton:: buttons; static std::unique_ptr<Input::AnalogDevice> circle_pad; -static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) { +DirectionState GetStickDirectionState(s16 circle_pad_x, s16 circle_pad_y) { // 30 degree and 60 degree are angular thresholds for directions constexpr float TAN30 = 0.577350269f; constexpr float TAN60 = 1 / TAN30; // a circle pad radius greater than 40 will trigger circle pad direction constexpr int CIRCLE_PAD_THRESHOLD_SQUARE = 40 * 40; - PadState state; - state.hex = 0; + DirectionState state{false, false, false, false}; if (circle_pad_x * circle_pad_x + circle_pad_y * circle_pad_y > CIRCLE_PAD_THRESHOLD_SQUARE) { float t = std::abs(static_cast<float>(circle_pad_y) / circle_pad_x); if (circle_pad_x != 0 && t < TAN60) { if (circle_pad_x > 0) - state.circle_right.Assign(1); + state.right = true; else - state.circle_left.Assign(1); + state.left = true; } if (circle_pad_x == 0 || t > TAN30) { if (circle_pad_y > 0) - state.circle_up.Assign(1); + state.up = true; else - state.circle_down.Assign(1); + state.down = true; } } @@ -125,7 +124,11 @@ static void UpdatePadCallback(u64 userdata, int cycles_late) { constexpr int MAX_CIRCLEPAD_POS = 0x9C; // Max value for a circle pad position s16 circle_pad_x = static_cast<s16>(circle_pad_x_f * MAX_CIRCLEPAD_POS); s16 circle_pad_y = static_cast<s16>(circle_pad_y_f * MAX_CIRCLEPAD_POS); - state.hex |= GetCirclePadDirectionState(circle_pad_x, circle_pad_y).hex; + const DirectionState direction = GetStickDirectionState(circle_pad_x, circle_pad_y); + state.circle_up.Assign(direction.up); + state.circle_down.Assign(direction.down); + state.circle_left.Assign(direction.left); + state.circle_right.Assign(direction.right); mem->pad.current_state.hex = state.hex; mem->pad.index = next_pad_index; diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index b505cdcd5..1ef972e70 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -176,6 +176,16 @@ ASSERT_REG_POSITION(touch.index_reset_ticks, 0x2A); #undef ASSERT_REG_POSITION #endif // !defined(_MSC_VER) +struct DirectionState { + bool up; + bool down; + bool left; + bool right; +}; + +/// Translates analog stick axes to directions. This is exposed for ir_rst module to use. +DirectionState GetStickDirectionState(s16 circle_pad_x, s16 circle_pad_y); + /** * HID::GetIPCHandles service function * Inputs: diff --git a/src/core/hle/service/ir/ir.cpp b/src/core/hle/service/ir/ir.cpp index 7ac34a990..f06dd552f 100644 --- a/src/core/hle/service/ir/ir.cpp +++ b/src/core/hle/service/ir/ir.cpp @@ -25,6 +25,11 @@ void Shutdown() { ShutdownRST(); } +void ReloadInputDevices() { + ReloadInputDevicesUser(); + ReloadInputDevicesRST(); +} + } // namespace IR } // namespace Service diff --git a/src/core/hle/service/ir/ir.h b/src/core/hle/service/ir/ir.h index c741498e2..6be3e950c 100644 --- a/src/core/hle/service/ir/ir.h +++ b/src/core/hle/service/ir/ir.h @@ -16,5 +16,8 @@ void Init(); /// Shutdown IR service void Shutdown(); +/// Reload input devices. Used when input configuration changed +void ReloadInputDevices(); + } // namespace IR } // namespace Service diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp index 3f1275c53..53807cd91 100644 --- a/src/core/hle/service/ir/ir_rst.cpp +++ b/src/core/hle/service/ir/ir_rst.cpp @@ -2,16 +2,135 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <atomic> +#include "common/bit_field.h" +#include "core/core_timing.h" +#include "core/frontend/input.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" +#include "core/hle/service/hid/hid.h" #include "core/hle/service/ir/ir.h" #include "core/hle/service/ir/ir_rst.h" +#include "core/settings.h" namespace Service { namespace IR { -static Kernel::SharedPtr<Kernel::Event> handle_event; +union PadState { + u32_le hex; + + BitField<14, 1, u32_le> zl; + BitField<15, 1, u32_le> zr; + + BitField<24, 1, u32_le> c_stick_right; + BitField<25, 1, u32_le> c_stick_left; + BitField<26, 1, u32_le> c_stick_up; + BitField<27, 1, u32_le> c_stick_down; +}; + +struct PadDataEntry { + PadState current_state; + PadState delta_additions; + PadState delta_removals; + + s16_le c_stick_x; + s16_le c_stick_y; +}; + +struct SharedMem { + u64_le index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0 + u64_le index_reset_ticks_previous; ///< Previous `index_reset_ticks` + u32_le index; + INSERT_PADDING_WORDS(1); + std::array<PadDataEntry, 8> entries; ///< Last 8 pad entries +}; + +static_assert(sizeof(SharedMem) == 0x98, "SharedMem has wrong size!"); + +static Kernel::SharedPtr<Kernel::Event> update_event; static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory; +static u32 next_pad_index; +static int update_callback_id; +static std::unique_ptr<Input::ButtonDevice> zl_button; +static std::unique_ptr<Input::ButtonDevice> zr_button; +static std::unique_ptr<Input::AnalogDevice> c_stick; +static std::atomic<bool> is_device_reload_pending; +static bool raw_c_stick; +static int update_period; + +static void LoadInputDevices() { + zl_button = Input::CreateDevice<Input::ButtonDevice>( + Settings::values.buttons[Settings::NativeButton::ZL]); + zr_button = Input::CreateDevice<Input::ButtonDevice>( + Settings::values.buttons[Settings::NativeButton::ZR]); + c_stick = Input::CreateDevice<Input::AnalogDevice>( + Settings::values.analogs[Settings::NativeAnalog::CStick]); +} + +static void UnloadInputDevices() { + zl_button = nullptr; + zr_button = nullptr; + c_stick = nullptr; +} + +static void UpdateCallback(u64 userdata, int cycles_late) { + SharedMem* mem = reinterpret_cast<SharedMem*>(shared_memory->GetPointer()); + + if (is_device_reload_pending.exchange(false)) + LoadInputDevices(); + + PadState state; + state.zl.Assign(zl_button->GetStatus()); + state.zr.Assign(zr_button->GetStatus()); + + // Get current c-stick position and update c-stick direction + float c_stick_x_f, c_stick_y_f; + std::tie(c_stick_x_f, c_stick_y_f) = c_stick->GetStatus(); + constexpr int MAX_CSTICK_RADIUS = 0x9C; // Max value for a c-stick radius + const s16 c_stick_x = static_cast<s16>(c_stick_x_f * MAX_CSTICK_RADIUS); + const s16 c_stick_y = static_cast<s16>(c_stick_y_f * MAX_CSTICK_RADIUS); + + if (!raw_c_stick) { + const HID::DirectionState direction = HID::GetStickDirectionState(c_stick_x, c_stick_y); + state.c_stick_up.Assign(direction.up); + state.c_stick_down.Assign(direction.down); + state.c_stick_left.Assign(direction.left); + state.c_stick_right.Assign(direction.right); + } + + // TODO (wwylele): implement raw C-stick data for raw_c_stick = true + + const u32 last_entry_index = mem->index; + mem->index = next_pad_index; + next_pad_index = (next_pad_index + 1) % mem->entries.size(); + + // Get the previous Pad state + PadState old_state{mem->entries[last_entry_index].current_state}; + + // Compute bitmask with 1s for bits different from the old state + PadState changed = {state.hex ^ old_state.hex}; + + // Get the current Pad entry + PadDataEntry& pad_entry = mem->entries[mem->index]; + + // Update entry properties + pad_entry.current_state.hex = state.hex; + pad_entry.delta_additions.hex = changed.hex & state.hex; + pad_entry.delta_removals.hex = changed.hex & old_state.hex; + pad_entry.c_stick_x = c_stick_x; + pad_entry.c_stick_y = c_stick_y; + + // If we just updated index 0, provide a new timestamp + if (mem->index == 0) { + mem->index_reset_ticks_previous = mem->index_reset_ticks; + mem->index_reset_ticks = CoreTiming::GetTicks(); + } + + update_event->Signal(); + + // Reschedule recurrent event + CoreTiming::ScheduleEvent(msToCycles(update_period) - cycles_late, update_callback_id); +} /** * IR::GetHandles service function @@ -22,18 +141,52 @@ static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory; * 4 : Event handle */ static void GetHandles(Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x01, 0, 0); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); + rb.Push(RESULT_SUCCESS); + rb.PushMoveHandles(Kernel::g_handle_table.Create(Service::IR::shared_memory).MoveFrom(), + Kernel::g_handle_table.Create(Service::IR::update_event).MoveFrom()); +} + +/** + * IR::Initialize service function + * Inputs: + * 1 : pad state update period in ms + * 2 : bool output raw c-stick data + */ +static void Initialize(Interface* self) { + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x02, 2, 0); + update_period = static_cast<int>(rp.Pop<u32>()); + raw_c_stick = rp.Pop<bool>(); - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = 0x4000000; - cmd_buff[3] = Kernel::g_handle_table.Create(Service::IR::shared_memory).MoveFrom(); - cmd_buff[4] = Kernel::g_handle_table.Create(Service::IR::handle_event).MoveFrom(); + if (raw_c_stick) + LOG_ERROR(Service_IR, "raw C-stick data is not implemented!"); + + next_pad_index = 0; + is_device_reload_pending.store(true); + CoreTiming::ScheduleEvent(msToCycles(update_period), update_callback_id); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + + LOG_DEBUG(Service_IR, "called. update_period=%d, raw_c_stick=%d", update_period, raw_c_stick); +} + +static void Shutdown(Interface* self) { + IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x03, 1, 0); + + CoreTiming::UnscheduleEvent(update_callback_id, 0); + UnloadInputDevices(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); + LOG_DEBUG(Service_IR, "called"); } const Interface::FunctionInfo FunctionTable[] = { {0x00010000, GetHandles, "GetHandles"}, - {0x00020080, nullptr, "Initialize"}, - {0x00030000, nullptr, "Shutdown"}, + {0x00020080, Initialize, "Initialize"}, + {0x00030000, Shutdown, "Shutdown"}, {0x00090000, nullptr, "WriteToTwoFields"}, }; @@ -43,17 +196,24 @@ IR_RST_Interface::IR_RST_Interface() { void InitRST() { using namespace Kernel; - + // Note: these two kernel objects are even available before Initialize service function is + // called. shared_memory = - SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, - MemoryPermission::ReadWrite, 0, MemoryRegion::BASE, "IR:SharedMemory"); + SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read, + 0, MemoryRegion::BASE, "IRRST:SharedMemory"); + update_event = Event::Create(ResetType::OneShot, "IRRST:UpdateEvent"); - handle_event = Event::Create(ResetType::OneShot, "IR:HandleEvent"); + update_callback_id = CoreTiming::RegisterEvent("IRRST:UpdateCallBack", UpdateCallback); } void ShutdownRST() { shared_memory = nullptr; - handle_event = nullptr; + update_event = nullptr; + UnloadInputDevices(); +} + +void ReloadInputDevicesRST() { + is_device_reload_pending.store(true); } } // namespace IR diff --git a/src/core/hle/service/ir/ir_rst.h b/src/core/hle/service/ir/ir_rst.h index 75b732627..d932bb7e5 100644 --- a/src/core/hle/service/ir/ir_rst.h +++ b/src/core/hle/service/ir/ir_rst.h @@ -21,5 +21,8 @@ public: void InitRST(); void ShutdownRST(); +/// Reload input devices. Used when input configuration changed +void ReloadInputDevicesRST(); + } // namespace IR } // namespace Service diff --git a/src/core/hle/service/ir/ir_user.cpp b/src/core/hle/service/ir/ir_user.cpp index bccf6bce7..226af0083 100644 --- a/src/core/hle/service/ir/ir_user.cpp +++ b/src/core/hle/service/ir/ir_user.cpp @@ -542,7 +542,7 @@ void ShutdownUser() { receive_event = nullptr; } -void ReloadInputDevices() { +void ReloadInputDevicesUser() { if (extra_hid) extra_hid->RequestInputDevicesReload(); } diff --git a/src/core/hle/service/ir/ir_user.h b/src/core/hle/service/ir/ir_user.h index 2401346e8..930650406 100644 --- a/src/core/hle/service/ir/ir_user.h +++ b/src/core/hle/service/ir/ir_user.h @@ -52,7 +52,7 @@ void InitUser(); void ShutdownUser(); /// Reload input devices. Used when input configuration changed -void ReloadInputDevices(); +void ReloadInputDevicesUser(); } // namespace IR } // namespace Service diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 2db823c61..8538cfc9d 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -2,12 +2,12 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <cinttypes> #include <map> #include "common/logging/log.h" #include "common/microprofile.h" #include "common/scope_exit.h" #include "common/string_util.h" -#include "common/symbols.h" #include "core/arm/arm_interface.h" #include "core/core_timing.h" #include "core/hle/function_wrappers.h" @@ -524,13 +524,7 @@ static ResultCode CreateThread(Kernel::Handle* out_handle, s32 priority, u32 ent u32 stack_top, s32 processor_id) { using Kernel::Thread; - std::string name; - if (Symbols::HasSymbol(entry_point)) { - TSymbol symbol = Symbols::GetSymbol(entry_point); - name = symbol.name; - } else { - name = Common::StringFromFormat("unknown-%08x", entry_point); - } + std::string name = Common::StringFromFormat("unknown-%08" PRIX32, entry_point); if (priority > THREADPRIO_LOWEST) { return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS, diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 8eb5200ab..cfcde9167 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -8,7 +8,6 @@ #include "common/common_types.h" #include "common/file_util.h" #include "common/logging/log.h" -#include "common/symbols.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/loader/elf.h" @@ -210,7 +209,6 @@ public: return (u32)(header->e_flags); } SharedPtr<CodeSet> LoadInto(u32 vaddr); - bool LoadSymbols(); int GetNumSegments() const { return (int)(header->e_phnum); @@ -258,8 +256,6 @@ ElfReader::ElfReader(void* ptr) { sections = (Elf32_Shdr*)(base + header->e_shoff); entryPoint = header->e_entry; - - LoadSymbols(); } const char* ElfReader::GetSectionName(int section) const { @@ -362,34 +358,6 @@ SectionID ElfReader::GetSectionByName(const char* name, int firstSection) const return -1; } -bool ElfReader::LoadSymbols() { - bool hasSymbols = false; - SectionID sec = GetSectionByName(".symtab"); - if (sec != -1) { - int stringSection = sections[sec].sh_link; - const char* stringBase = reinterpret_cast<const char*>(GetSectionDataPtr(stringSection)); - - // We have a symbol table! - const Elf32_Sym* symtab = reinterpret_cast<const Elf32_Sym*>(GetSectionDataPtr(sec)); - unsigned int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); - for (unsigned sym = 0; sym < numSymbols; sym++) { - int size = symtab[sym].st_size; - if (size == 0) - continue; - - int type = symtab[sym].st_info & 0xF; - - const char* name = stringBase + symtab[sym].st_name; - - Symbols::Add(symtab[sym].st_value, name, size, type); - - hasSymbols = true; - } - } - - return hasSymbols; -} - //////////////////////////////////////////////////////////////////////////////////////////////////// // Loader namespace diff --git a/src/core/settings.cpp b/src/core/settings.cpp index 3d22c0afa..d2e7c6b97 100644 --- a/src/core/settings.cpp +++ b/src/core/settings.cpp @@ -5,7 +5,7 @@ #include "audio_core/audio_core.h" #include "core/gdbstub/gdbstub.h" #include "core/hle/service/hid/hid.h" -#include "core/hle/service/ir/ir_user.h" +#include "core/hle/service/ir/ir.h" #include "settings.h" #include "video_core/video_core.h" |