diff options
Diffstat (limited to 'src')
116 files changed, 3421 insertions, 1402 deletions
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp index 46f4a07c9..c96fc1374 100644 --- a/src/citra/citra.cpp +++ b/src/citra/citra.cpp | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include "core/settings.h" | 23 | #include "core/settings.h" |
| 24 | #include "core/system.h" | 24 | #include "core/system.h" |
| 25 | #include "core/core.h" | 25 | #include "core/core.h" |
| 26 | #include "core/gdbstub/gdbstub.h" | ||
| 26 | #include "core/loader/loader.h" | 27 | #include "core/loader/loader.h" |
| 27 | 28 | ||
| 28 | #include "citra/config.h" | 29 | #include "citra/config.h" |
| @@ -72,6 +73,8 @@ int main(int argc, char **argv) { | |||
| 72 | Config config; | 73 | Config config; |
| 73 | log_filter.ParseFilterString(Settings::values.log_filter); | 74 | log_filter.ParseFilterString(Settings::values.log_filter); |
| 74 | 75 | ||
| 76 | GDBStub::ToggleServer(Settings::values.use_gdbstub); | ||
| 77 | GDBStub::SetServerPort(static_cast<u32>(Settings::values.gdbstub_port)); | ||
| 75 | 78 | ||
| 76 | EmuWindow_GLFW* emu_window = new EmuWindow_GLFW; | 79 | EmuWindow_GLFW* emu_window = new EmuWindow_GLFW; |
| 77 | 80 | ||
diff --git a/src/citra/config.cpp b/src/citra/config.cpp index 8a98bda87..2f13c29a2 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp | |||
| @@ -75,6 +75,10 @@ void Config::ReadValues() { | |||
| 75 | 75 | ||
| 76 | // Miscellaneous | 76 | // Miscellaneous |
| 77 | Settings::values.log_filter = glfw_config->Get("Miscellaneous", "log_filter", "*:Info"); | 77 | Settings::values.log_filter = glfw_config->Get("Miscellaneous", "log_filter", "*:Info"); |
| 78 | |||
| 79 | // Debugging | ||
| 80 | Settings::values.use_gdbstub = glfw_config->GetBoolean("Debugging", "use_gdbstub", false); | ||
| 81 | Settings::values.gdbstub_port = glfw_config->GetInteger("Debugging", "gdbstub_port", 24689); | ||
| 78 | } | 82 | } |
| 79 | 83 | ||
| 80 | void Config::Reload() { | 84 | void Config::Reload() { |
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index 7e5d49729..5ba40a8ed 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h | |||
| @@ -66,6 +66,11 @@ region_value = | |||
| 66 | # A filter which removes logs below a certain logging level. | 66 | # A filter which removes logs below a certain logging level. |
| 67 | # Examples: *:Debug Kernel.SVC:Trace Service.*:Critical | 67 | # Examples: *:Debug Kernel.SVC:Trace Service.*:Critical |
| 68 | log_filter = *:Info | 68 | log_filter = *:Info |
| 69 | |||
| 70 | [Debugging] | ||
| 71 | # Port for listening to GDB connections. | ||
| 72 | use_gdbstub=false | ||
| 73 | gdbstub_port=24689 | ||
| 69 | )"; | 74 | )"; |
| 70 | 75 | ||
| 71 | } | 76 | } |
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index 747ad5519..bbf6ae001 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt | |||
| @@ -72,7 +72,9 @@ else() | |||
| 72 | endif() | 72 | endif() |
| 73 | 73 | ||
| 74 | if (APPLE) | 74 | if (APPLE) |
| 75 | add_executable(citra-qt MACOSX_BUNDLE ${SRCS} ${HEADERS} ${UI_HDRS}) | 75 | set(MACOSX_ICON "../../dist/citra.icns") |
| 76 | set_source_files_properties(${MACOSX_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION Resources) | ||
| 77 | add_executable(citra-qt MACOSX_BUNDLE ${SRCS} ${HEADERS} ${UI_HDRS} ${MACOSX_ICON}) | ||
| 76 | set_target_properties(citra-qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) | 78 | set_target_properties(citra-qt PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/Info.plist) |
| 77 | else() | 79 | else() |
| 78 | add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS}) | 80 | add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS}) |
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index 1f4981ce1..8e247ff5c 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp | |||
| @@ -62,6 +62,11 @@ void Config::ReadValues() { | |||
| 62 | qt_config->beginGroup("Miscellaneous"); | 62 | qt_config->beginGroup("Miscellaneous"); |
| 63 | Settings::values.log_filter = qt_config->value("log_filter", "*:Info").toString().toStdString(); | 63 | Settings::values.log_filter = qt_config->value("log_filter", "*:Info").toString().toStdString(); |
| 64 | qt_config->endGroup(); | 64 | qt_config->endGroup(); |
| 65 | |||
| 66 | qt_config->beginGroup("Debugging"); | ||
| 67 | Settings::values.use_gdbstub = qt_config->value("use_gdbstub", false).toBool(); | ||
| 68 | Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt(); | ||
| 69 | qt_config->endGroup(); | ||
| 65 | } | 70 | } |
| 66 | 71 | ||
| 67 | void Config::SaveValues() { | 72 | void Config::SaveValues() { |
| @@ -97,6 +102,11 @@ void Config::SaveValues() { | |||
| 97 | qt_config->beginGroup("Miscellaneous"); | 102 | qt_config->beginGroup("Miscellaneous"); |
| 98 | qt_config->setValue("log_filter", QString::fromStdString(Settings::values.log_filter)); | 103 | qt_config->setValue("log_filter", QString::fromStdString(Settings::values.log_filter)); |
| 99 | qt_config->endGroup(); | 104 | qt_config->endGroup(); |
| 105 | |||
| 106 | qt_config->beginGroup("Debugging"); | ||
| 107 | qt_config->setValue("use_gdbstub", Settings::values.use_gdbstub); | ||
| 108 | qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port); | ||
| 109 | qt_config->endGroup(); | ||
| 100 | } | 110 | } |
| 101 | 111 | ||
| 102 | void Config::Reload() { | 112 | void Config::Reload() { |
diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp index d45eed179..793944639 100644 --- a/src/citra_qt/debugger/callstack.cpp +++ b/src/citra_qt/debugger/callstack.cpp | |||
| @@ -29,18 +29,16 @@ CallstackWidget::CallstackWidget(QWidget* parent): QDockWidget(parent) | |||
| 29 | 29 | ||
| 30 | void CallstackWidget::OnDebugModeEntered() | 30 | void CallstackWidget::OnDebugModeEntered() |
| 31 | { | 31 | { |
| 32 | ARM_Interface* app_core = Core::g_app_core; | 32 | // Stack pointer |
| 33 | 33 | const u32 sp = Core::g_app_core->GetReg(13); | |
| 34 | u32 sp = app_core->GetReg(13); //stack pointer | ||
| 35 | u32 ret_addr, call_addr, func_addr; | ||
| 36 | 34 | ||
| 37 | Clear(); | 35 | Clear(); |
| 38 | 36 | ||
| 39 | int counter = 0; | 37 | int counter = 0; |
| 40 | for (u32 addr = 0x10000000; addr >= sp; addr -= 4) | 38 | for (u32 addr = 0x10000000; addr >= sp; addr -= 4) |
| 41 | { | 39 | { |
| 42 | ret_addr = Memory::Read32(addr); | 40 | const u32 ret_addr = Memory::Read32(addr); |
| 43 | call_addr = ret_addr - 4; //get call address??? | 41 | const u32 call_addr = ret_addr - 4; //get call address??? |
| 44 | 42 | ||
| 45 | if (Memory::GetPointer(call_addr) == nullptr) | 43 | if (Memory::GetPointer(call_addr) == nullptr) |
| 46 | break; | 44 | break; |
| @@ -60,7 +58,7 @@ void CallstackWidget::OnDebugModeEntered() | |||
| 60 | // Pre-compute the left-shift and the prefetch offset | 58 | // Pre-compute the left-shift and the prefetch offset |
| 61 | i_offset <<= 2; | 59 | i_offset <<= 2; |
| 62 | i_offset += 8; | 60 | i_offset += 8; |
| 63 | func_addr = call_addr + i_offset; | 61 | const u32 func_addr = call_addr + i_offset; |
| 64 | 62 | ||
| 65 | callstack_model->setItem(counter, 0, new QStandardItem(QString("0x%1").arg(addr, 8, 16, QLatin1Char('0')))); | 63 | callstack_model->setItem(counter, 0, new QStandardItem(QString("0x%1").arg(addr, 8, 16, QLatin1Char('0')))); |
| 66 | callstack_model->setItem(counter, 1, new QStandardItem(QString("0x%1").arg(ret_addr, 8, 16, QLatin1Char('0')))); | 64 | callstack_model->setItem(counter, 1, new QStandardItem(QString("0x%1").arg(ret_addr, 8, 16, QLatin1Char('0')))); |
diff --git a/src/citra_qt/debugger/registers.cpp b/src/citra_qt/debugger/registers.cpp index 6100d67c5..1bd0bfebc 100644 --- a/src/citra_qt/debugger/registers.cpp +++ b/src/citra_qt/debugger/registers.cpp | |||
| @@ -59,16 +59,14 @@ RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) { | |||
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | void RegistersWidget::OnDebugModeEntered() { | 61 | void RegistersWidget::OnDebugModeEntered() { |
| 62 | ARM_Interface* app_core = Core::g_app_core; | 62 | if (!Core::g_app_core) |
| 63 | |||
| 64 | if (app_core == nullptr) | ||
| 65 | return; | 63 | return; |
| 66 | 64 | ||
| 67 | for (int i = 0; i < core_registers->childCount(); ++i) | 65 | for (int i = 0; i < core_registers->childCount(); ++i) |
| 68 | core_registers->child(i)->setText(1, QString("0x%1").arg(app_core->GetReg(i), 8, 16, QLatin1Char('0'))); | 66 | core_registers->child(i)->setText(1, QString("0x%1").arg(Core::g_app_core->GetReg(i), 8, 16, QLatin1Char('0'))); |
| 69 | 67 | ||
| 70 | for (int i = 0; i < vfp_registers->childCount(); ++i) | 68 | for (int i = 0; i < vfp_registers->childCount(); ++i) |
| 71 | vfp_registers->child(i)->setText(1, QString("0x%1").arg(app_core->GetVFPReg(i), 8, 16, QLatin1Char('0'))); | 69 | vfp_registers->child(i)->setText(1, QString("0x%1").arg(Core::g_app_core->GetVFPReg(i), 8, 16, QLatin1Char('0'))); |
| 72 | 70 | ||
| 73 | UpdateCPSRValues(); | 71 | UpdateCPSRValues(); |
| 74 | UpdateVFPSystemRegisterValues(); | 72 | UpdateVFPSystemRegisterValues(); |
diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp index dade3c212..1f8d69a03 100644 --- a/src/citra_qt/game_list.cpp +++ b/src/citra_qt/game_list.cpp | |||
| @@ -80,7 +80,7 @@ void GameList::DonePopulating() | |||
| 80 | void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) | 80 | void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) |
| 81 | { | 81 | { |
| 82 | if (!FileUtil::Exists(dir_path.toStdString()) || !FileUtil::IsDirectory(dir_path.toStdString())) { | 82 | if (!FileUtil::Exists(dir_path.toStdString()) || !FileUtil::IsDirectory(dir_path.toStdString())) { |
| 83 | LOG_ERROR(Frontend, "Could not find game list folder at %s", dir_path.toLatin1().data()); | 83 | LOG_ERROR(Frontend, "Could not find game list folder at %s", dir_path.toLocal8Bit().data()); |
| 84 | return; | 84 | return; |
| 85 | } | 85 | } |
| 86 | 86 | ||
| @@ -119,13 +119,14 @@ void GameList::LoadInterfaceLayout(QSettings& settings) | |||
| 119 | 119 | ||
| 120 | void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, bool deep_scan) | 120 | void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, bool deep_scan) |
| 121 | { | 121 | { |
| 122 | const auto callback = [&](const std::string& directory, | 122 | const auto callback = [&](unsigned* num_entries_out, |
| 123 | const std::string& virtual_name) -> int { | 123 | const std::string& directory, |
| 124 | const std::string& virtual_name) -> bool { | ||
| 124 | 125 | ||
| 125 | std::string physical_name = directory + DIR_SEP + virtual_name; | 126 | std::string physical_name = directory + DIR_SEP + virtual_name; |
| 126 | 127 | ||
| 127 | if (stop_processing) | 128 | if (stop_processing) |
| 128 | return -1; // A negative return value breaks the callback loop. | 129 | return false; // Breaks the callback loop. |
| 129 | 130 | ||
| 130 | if (deep_scan && FileUtil::IsDirectory(physical_name)) { | 131 | if (deep_scan && FileUtil::IsDirectory(physical_name)) { |
| 131 | AddFstEntriesToGameList(physical_name, true); | 132 | AddFstEntriesToGameList(physical_name, true); |
| @@ -135,11 +136,11 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, bool d | |||
| 135 | 136 | ||
| 136 | Loader::FileType guessed_filetype = Loader::GuessFromExtension(filename_extension); | 137 | Loader::FileType guessed_filetype = Loader::GuessFromExtension(filename_extension); |
| 137 | if (guessed_filetype == Loader::FileType::Unknown) | 138 | if (guessed_filetype == Loader::FileType::Unknown) |
| 138 | return 0; | 139 | return true; |
| 139 | Loader::FileType filetype = Loader::IdentifyFile(physical_name); | 140 | Loader::FileType filetype = Loader::IdentifyFile(physical_name); |
| 140 | if (filetype == Loader::FileType::Unknown) { | 141 | if (filetype == Loader::FileType::Unknown) { |
| 141 | LOG_WARNING(Frontend, "File %s is of indeterminate type and is possibly corrupted.", physical_name.c_str()); | 142 | LOG_WARNING(Frontend, "File %s is of indeterminate type and is possibly corrupted.", physical_name.c_str()); |
| 142 | return 0; | 143 | return true; |
| 143 | } | 144 | } |
| 144 | if (guessed_filetype != filetype) { | 145 | if (guessed_filetype != filetype) { |
| 145 | LOG_WARNING(Frontend, "Filetype and extension of file %s do not match.", physical_name.c_str()); | 146 | LOG_WARNING(Frontend, "Filetype and extension of file %s do not match.", physical_name.c_str()); |
| @@ -152,9 +153,10 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, bool d | |||
| 152 | }); | 153 | }); |
| 153 | } | 154 | } |
| 154 | 155 | ||
| 155 | return 0; // We don't care about the found entries | 156 | return true; |
| 156 | }; | 157 | }; |
| 157 | FileUtil::ScanDirectoryTreeAndCallback(dir_path, callback); | 158 | |
| 159 | FileUtil::ForeachDirectoryEntry(nullptr, dir_path, callback); | ||
| 158 | } | 160 | } |
| 159 | 161 | ||
| 160 | void GameListWorker::run() | 162 | void GameListWorker::run() |
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index bf010a2ba..144f11117 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp | |||
| @@ -44,6 +44,7 @@ | |||
| 44 | #include "core/settings.h" | 44 | #include "core/settings.h" |
| 45 | #include "core/system.h" | 45 | #include "core/system.h" |
| 46 | #include "core/arm/disassembler/load_symbol_map.h" | 46 | #include "core/arm/disassembler/load_symbol_map.h" |
| 47 | #include "core/gdbstub/gdbstub.h" | ||
| 47 | #include "core/loader/loader.h" | 48 | #include "core/loader/loader.h" |
| 48 | 49 | ||
| 49 | #include "video_core/video_core.h" | 50 | #include "video_core/video_core.h" |
| @@ -143,6 +144,11 @@ GMainWindow::GMainWindow() : emu_thread(nullptr) | |||
| 143 | 144 | ||
| 144 | game_list->LoadInterfaceLayout(settings); | 145 | game_list->LoadInterfaceLayout(settings); |
| 145 | 146 | ||
| 147 | ui.action_Use_Gdbstub->setChecked(Settings::values.use_gdbstub); | ||
| 148 | SetGdbstubEnabled(ui.action_Use_Gdbstub->isChecked()); | ||
| 149 | |||
| 150 | GDBStub::SetServerPort(static_cast<u32>(Settings::values.gdbstub_port)); | ||
| 151 | |||
| 146 | ui.action_Use_Hardware_Renderer->setChecked(Settings::values.use_hw_renderer); | 152 | ui.action_Use_Hardware_Renderer->setChecked(Settings::values.use_hw_renderer); |
| 147 | SetHardwareRendererEnabled(ui.action_Use_Hardware_Renderer->isChecked()); | 153 | SetHardwareRendererEnabled(ui.action_Use_Hardware_Renderer->isChecked()); |
| 148 | 154 | ||
| @@ -175,6 +181,7 @@ GMainWindow::GMainWindow() : emu_thread(nullptr) | |||
| 175 | connect(ui.action_Stop, SIGNAL(triggered()), this, SLOT(OnStopGame())); | 181 | connect(ui.action_Stop, SIGNAL(triggered()), this, SLOT(OnStopGame())); |
| 176 | connect(ui.action_Use_Hardware_Renderer, SIGNAL(triggered(bool)), this, SLOT(SetHardwareRendererEnabled(bool))); | 182 | connect(ui.action_Use_Hardware_Renderer, SIGNAL(triggered(bool)), this, SLOT(SetHardwareRendererEnabled(bool))); |
| 177 | connect(ui.action_Use_Shader_JIT, SIGNAL(triggered(bool)), this, SLOT(SetShaderJITEnabled(bool))); | 183 | connect(ui.action_Use_Shader_JIT, SIGNAL(triggered(bool)), this, SLOT(SetShaderJITEnabled(bool))); |
| 184 | connect(ui.action_Use_Gdbstub, SIGNAL(triggered(bool)), this, SLOT(SetGdbstubEnabled(bool))); | ||
| 178 | connect(ui.action_Single_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(ToggleWindowMode())); | 185 | connect(ui.action_Single_Window_Mode, SIGNAL(triggered(bool)), this, SLOT(ToggleWindowMode())); |
| 179 | connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog())); | 186 | connect(ui.action_Hotkeys, SIGNAL(triggered()), this, SLOT(OnOpenHotkeysDialog())); |
| 180 | 187 | ||
| @@ -201,7 +208,7 @@ GMainWindow::GMainWindow() : emu_thread(nullptr) | |||
| 201 | 208 | ||
| 202 | show(); | 209 | show(); |
| 203 | 210 | ||
| 204 | game_list->PopulateAsync(settings.value("gameListRootDir").toString(), settings.value("gameListDeepScan").toBool()); | 211 | game_list->PopulateAsync(settings.value("gameListRootDir", ".").toString(), settings.value("gameListDeepScan", false).toBool()); |
| 205 | 212 | ||
| 206 | QStringList args = QApplication::arguments(); | 213 | QStringList args = QApplication::arguments(); |
| 207 | if (args.length() >= 2) { | 214 | if (args.length() >= 2) { |
| @@ -240,7 +247,7 @@ void GMainWindow::OnDisplayTitleBars(bool show) | |||
| 240 | } | 247 | } |
| 241 | 248 | ||
| 242 | void GMainWindow::BootGame(const std::string& filename) { | 249 | void GMainWindow::BootGame(const std::string& filename) { |
| 243 | LOG_INFO(Frontend, "Citra starting...\n"); | 250 | LOG_INFO(Frontend, "Citra starting..."); |
| 244 | 251 | ||
| 245 | // Shutdown previous session if the emu thread is still active... | 252 | // Shutdown previous session if the emu thread is still active... |
| 246 | if (emu_thread != nullptr) | 253 | if (emu_thread != nullptr) |
| @@ -355,7 +362,7 @@ void GMainWindow::UpdateRecentFiles() { | |||
| 355 | } | 362 | } |
| 356 | 363 | ||
| 357 | void GMainWindow::OnGameListLoadFile(QString game_path) { | 364 | void GMainWindow::OnGameListLoadFile(QString game_path) { |
| 358 | BootGame(game_path.toLatin1().data()); | 365 | BootGame(game_path.toLocal8Bit().data()); |
| 359 | } | 366 | } |
| 360 | 367 | ||
| 361 | void GMainWindow::OnMenuLoadFile() { | 368 | void GMainWindow::OnMenuLoadFile() { |
| @@ -367,7 +374,7 @@ void GMainWindow::OnMenuLoadFile() { | |||
| 367 | settings.setValue("romsPath", QFileInfo(filename).path()); | 374 | settings.setValue("romsPath", QFileInfo(filename).path()); |
| 368 | StoreRecentFile(filename); | 375 | StoreRecentFile(filename); |
| 369 | 376 | ||
| 370 | BootGame(filename.toLatin1().data()); | 377 | BootGame(filename.toLocal8Bit().data()); |
| 371 | } | 378 | } |
| 372 | } | 379 | } |
| 373 | 380 | ||
| @@ -379,7 +386,7 @@ void GMainWindow::OnMenuLoadSymbolMap() { | |||
| 379 | if (!filename.isEmpty()) { | 386 | if (!filename.isEmpty()) { |
| 380 | settings.setValue("symbolsPath", QFileInfo(filename).path()); | 387 | settings.setValue("symbolsPath", QFileInfo(filename).path()); |
| 381 | 388 | ||
| 382 | LoadSymbolMap(filename.toLatin1().data()); | 389 | LoadSymbolMap(filename.toLocal8Bit().data()); |
| 383 | } | 390 | } |
| 384 | } | 391 | } |
| 385 | 392 | ||
| @@ -400,7 +407,7 @@ void GMainWindow::OnMenuRecentFile() { | |||
| 400 | QString filename = action->data().toString(); | 407 | QString filename = action->data().toString(); |
| 401 | QFileInfo file_info(filename); | 408 | QFileInfo file_info(filename); |
| 402 | if (file_info.exists()) { | 409 | if (file_info.exists()) { |
| 403 | BootGame(filename.toLatin1().data()); | 410 | BootGame(filename.toLocal8Bit().data()); |
| 404 | StoreRecentFile(filename); // Put the filename on top of the list | 411 | StoreRecentFile(filename); // Put the filename on top of the list |
| 405 | } else { | 412 | } else { |
| 406 | // Display an error message and remove the file from the list. | 413 | // Display an error message and remove the file from the list. |
| @@ -443,10 +450,22 @@ void GMainWindow::OnOpenHotkeysDialog() { | |||
| 443 | 450 | ||
| 444 | void GMainWindow::SetHardwareRendererEnabled(bool enabled) { | 451 | void GMainWindow::SetHardwareRendererEnabled(bool enabled) { |
| 445 | VideoCore::g_hw_renderer_enabled = enabled; | 452 | VideoCore::g_hw_renderer_enabled = enabled; |
| 453 | |||
| 454 | Config config; | ||
| 455 | Settings::values.use_hw_renderer = enabled; | ||
| 456 | config.Save(); | ||
| 457 | } | ||
| 458 | |||
| 459 | void GMainWindow::SetGdbstubEnabled(bool enabled) { | ||
| 460 | GDBStub::ToggleServer(enabled); | ||
| 446 | } | 461 | } |
| 447 | 462 | ||
| 448 | void GMainWindow::SetShaderJITEnabled(bool enabled) { | 463 | void GMainWindow::SetShaderJITEnabled(bool enabled) { |
| 449 | VideoCore::g_shader_jit_enabled = enabled; | 464 | VideoCore::g_shader_jit_enabled = enabled; |
| 465 | |||
| 466 | Config config; | ||
| 467 | Settings::values.use_shader_jit = enabled; | ||
| 468 | config.Save(); | ||
| 450 | } | 469 | } |
| 451 | 470 | ||
| 452 | void GMainWindow::ToggleWindowMode() { | 471 | void GMainWindow::ToggleWindowMode() { |
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h index 6d27ce6a9..f6d429cd9 100644 --- a/src/citra_qt/main.h +++ b/src/citra_qt/main.h | |||
| @@ -99,6 +99,7 @@ private slots: | |||
| 99 | void OnConfigure(); | 99 | void OnConfigure(); |
| 100 | void OnDisplayTitleBars(bool); | 100 | void OnDisplayTitleBars(bool); |
| 101 | void SetHardwareRendererEnabled(bool); | 101 | void SetHardwareRendererEnabled(bool); |
| 102 | void SetGdbstubEnabled(bool); | ||
| 102 | void SetShaderJITEnabled(bool); | 103 | void SetShaderJITEnabled(bool); |
| 103 | void ToggleWindowMode(); | 104 | void ToggleWindowMode(); |
| 104 | 105 | ||
diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui index 997597642..1e8a07cfb 100644 --- a/src/citra_qt/main.ui +++ b/src/citra_qt/main.ui | |||
| @@ -75,6 +75,7 @@ | |||
| 75 | <addaction name="separator"/> | 75 | <addaction name="separator"/> |
| 76 | <addaction name="action_Use_Hardware_Renderer"/> | 76 | <addaction name="action_Use_Hardware_Renderer"/> |
| 77 | <addaction name="action_Use_Shader_JIT"/> | 77 | <addaction name="action_Use_Shader_JIT"/> |
| 78 | <addaction name="action_Use_Gdbstub"/> | ||
| 78 | <addaction name="action_Configure"/> | 79 | <addaction name="action_Configure"/> |
| 79 | </widget> | 80 | </widget> |
| 80 | <widget class="QMenu" name="menu_View"> | 81 | <widget class="QMenu" name="menu_View"> |
| @@ -170,6 +171,14 @@ | |||
| 170 | <string>Use Shader JIT</string> | 171 | <string>Use Shader JIT</string> |
| 171 | </property> | 172 | </property> |
| 172 | </action> | 173 | </action> |
| 174 | <action name="action_Use_Gdbstub"> | ||
| 175 | <property name="checkable"> | ||
| 176 | <bool>true</bool> | ||
| 177 | </property> | ||
| 178 | <property name="text"> | ||
| 179 | <string>Use Gdbstub</string> | ||
| 180 | </property> | ||
| 181 | </action> | ||
| 173 | <action name="action_Configure"> | 182 | <action name="action_Configure"> |
| 174 | <property name="text"> | 183 | <property name="text"> |
| 175 | <string>Configure ...</string> | 184 | <string>Configure ...</string> |
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 1e0d33313..052c0ecd6 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp | |||
| @@ -420,11 +420,16 @@ bool CreateEmptyFile(const std::string &filename) | |||
| 420 | } | 420 | } |
| 421 | 421 | ||
| 422 | 422 | ||
| 423 | int ScanDirectoryTreeAndCallback(const std::string &directory, std::function<int(const std::string&, const std::string&)> callback) | 423 | bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback) |
| 424 | { | 424 | { |
| 425 | LOG_TRACE(Common_Filesystem, "directory %s", directory.c_str()); | 425 | LOG_TRACE(Common_Filesystem, "directory %s", directory.c_str()); |
| 426 | |||
| 426 | // How many files + directories we found | 427 | // How many files + directories we found |
| 427 | int found_entries = 0; | 428 | unsigned found_entries = 0; |
| 429 | |||
| 430 | // Save the status of callback function | ||
| 431 | bool callback_error = false; | ||
| 432 | |||
| 428 | #ifdef _WIN32 | 433 | #ifdef _WIN32 |
| 429 | // Find the first file in the directory. | 434 | // Find the first file in the directory. |
| 430 | WIN32_FIND_DATA ffd; | 435 | WIN32_FIND_DATA ffd; |
| @@ -432,7 +437,7 @@ int ScanDirectoryTreeAndCallback(const std::string &directory, std::function<int | |||
| 432 | HANDLE handle_find = FindFirstFile(Common::UTF8ToTStr(directory + "\\*").c_str(), &ffd); | 437 | HANDLE handle_find = FindFirstFile(Common::UTF8ToTStr(directory + "\\*").c_str(), &ffd); |
| 433 | if (handle_find == INVALID_HANDLE_VALUE) { | 438 | if (handle_find == INVALID_HANDLE_VALUE) { |
| 434 | FindClose(handle_find); | 439 | FindClose(handle_find); |
| 435 | return found_entries; | 440 | return false; |
| 436 | } | 441 | } |
| 437 | // windows loop | 442 | // windows loop |
| 438 | do { | 443 | do { |
| @@ -442,25 +447,22 @@ int ScanDirectoryTreeAndCallback(const std::string &directory, std::function<int | |||
| 442 | 447 | ||
| 443 | DIR *dirp = opendir(directory.c_str()); | 448 | DIR *dirp = opendir(directory.c_str()); |
| 444 | if (!dirp) | 449 | if (!dirp) |
| 445 | return 0; | 450 | return false; |
| 446 | 451 | ||
| 447 | // non windows loop | 452 | // non windows loop |
| 448 | while (!readdir_r(dirp, &dirent, &result) && result) { | 453 | while (!readdir_r(dirp, &dirent, &result) && result) { |
| 449 | const std::string virtual_name(result->d_name); | 454 | const std::string virtual_name(result->d_name); |
| 450 | #endif | 455 | #endif |
| 451 | // check for "." and ".." | 456 | |
| 452 | if (((virtual_name[0] == '.') && (virtual_name[1] == '\0')) || | 457 | if (virtual_name == "." || virtual_name == "..") |
| 453 | ((virtual_name[0] == '.') && (virtual_name[1] == '.') && | ||
| 454 | (virtual_name[2] == '\0'))) | ||
| 455 | continue; | 458 | continue; |
| 456 | 459 | ||
| 457 | int ret = callback(directory, virtual_name); | 460 | unsigned ret_entries; |
| 458 | if (ret < 0) { | 461 | if (!callback(&ret_entries, directory, virtual_name)) { |
| 459 | if (ret != -1) | 462 | callback_error = true; |
| 460 | found_entries = ret; | ||
| 461 | break; | 463 | break; |
| 462 | } | 464 | } |
| 463 | found_entries += ret; | 465 | found_entries += ret_entries; |
| 464 | 466 | ||
| 465 | #ifdef _WIN32 | 467 | #ifdef _WIN32 |
| 466 | } while (FindNextFile(handle_find, &ffd) != 0); | 468 | } while (FindNextFile(handle_find, &ffd) != 0); |
| @@ -469,16 +471,23 @@ int ScanDirectoryTreeAndCallback(const std::string &directory, std::function<int | |||
| 469 | } | 471 | } |
| 470 | closedir(dirp); | 472 | closedir(dirp); |
| 471 | #endif | 473 | #endif |
| 472 | // Return number of entries found. | 474 | |
| 473 | return found_entries; | 475 | if (!callback_error) { |
| 476 | // num_entries_out is allowed to be specified nullptr, in which case we shouldn't try to set it | ||
| 477 | if (num_entries_out != nullptr) | ||
| 478 | *num_entries_out = found_entries; | ||
| 479 | return true; | ||
| 480 | } else { | ||
| 481 | return false; | ||
| 482 | } | ||
| 474 | } | 483 | } |
| 475 | 484 | ||
| 476 | int ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry) | 485 | unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry) |
| 477 | { | 486 | { |
| 478 | const auto callback = [&parent_entry](const std::string& directory, | 487 | const auto callback = [&parent_entry](unsigned* num_entries_out, |
| 479 | const std::string& virtual_name) -> int { | 488 | const std::string& directory, |
| 489 | const std::string& virtual_name) -> bool { | ||
| 480 | FSTEntry entry; | 490 | FSTEntry entry; |
| 481 | int found_entries = 0; | ||
| 482 | entry.virtualName = virtual_name; | 491 | entry.virtualName = virtual_name; |
| 483 | entry.physicalName = directory + DIR_SEP + virtual_name; | 492 | entry.physicalName = directory + DIR_SEP + virtual_name; |
| 484 | 493 | ||
| @@ -486,41 +495,40 @@ int ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry) | |||
| 486 | entry.isDirectory = true; | 495 | entry.isDirectory = true; |
| 487 | // is a directory, lets go inside | 496 | // is a directory, lets go inside |
| 488 | entry.size = ScanDirectoryTree(entry.physicalName, entry); | 497 | entry.size = ScanDirectoryTree(entry.physicalName, entry); |
| 489 | found_entries += (int)entry.size; | 498 | *num_entries_out += (int)entry.size; |
| 490 | } else { // is a file | 499 | } else { // is a file |
| 491 | entry.isDirectory = false; | 500 | entry.isDirectory = false; |
| 492 | entry.size = GetSize(entry.physicalName); | 501 | entry.size = GetSize(entry.physicalName); |
| 493 | } | 502 | } |
| 494 | ++found_entries; | 503 | (*num_entries_out)++; |
| 504 | |||
| 495 | // Push into the tree | 505 | // Push into the tree |
| 496 | parent_entry.children.push_back(entry); | 506 | parent_entry.children.push_back(entry); |
| 497 | return found_entries; | 507 | return true; |
| 498 | }; | 508 | }; |
| 499 | 509 | ||
| 500 | return ScanDirectoryTreeAndCallback(directory, callback); | 510 | unsigned num_entries; |
| 511 | return ForeachDirectoryEntry(&num_entries, directory, callback) ? num_entries : 0; | ||
| 501 | } | 512 | } |
| 502 | 513 | ||
| 503 | 514 | ||
| 504 | bool DeleteDirRecursively(const std::string &directory) | 515 | bool DeleteDirRecursively(const std::string &directory) |
| 505 | { | 516 | { |
| 506 | const static auto callback = [](const std::string& directory, | 517 | const static auto callback = [](unsigned* num_entries_out, |
| 507 | const std::string& virtual_name) -> int { | 518 | const std::string& directory, |
| 519 | const std::string& virtual_name) -> bool { | ||
| 508 | std::string new_path = directory + DIR_SEP_CHR + virtual_name; | 520 | std::string new_path = directory + DIR_SEP_CHR + virtual_name; |
| 509 | if (IsDirectory(new_path)) { | 521 | if (IsDirectory(new_path)) |
| 510 | if (!DeleteDirRecursively(new_path)) { | 522 | return DeleteDirRecursively(new_path); |
| 511 | return -2; | 523 | |
| 512 | } | 524 | return Delete(new_path); |
| 513 | } else if (!Delete(new_path)) { | ||
| 514 | return -2; | ||
| 515 | } | ||
| 516 | return 0; | ||
| 517 | }; | 525 | }; |
| 518 | 526 | ||
| 519 | if (ScanDirectoryTreeAndCallback(directory, callback) == -2) { | 527 | if (!ForeachDirectoryEntry(nullptr, directory, callback)) |
| 520 | return false; | 528 | return false; |
| 521 | } | ||
| 522 | FileUtil::DeleteDir(directory); | ||
| 523 | 529 | ||
| 530 | // Delete the outermost directory | ||
| 531 | FileUtil::DeleteDir(directory); | ||
| 524 | return true; | 532 | return true; |
| 525 | } | 533 | } |
| 526 | 534 | ||
diff --git a/src/common/file_util.h b/src/common/file_util.h index 3d617f573..a85121aa6 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h | |||
| @@ -98,19 +98,24 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename); | |||
| 98 | bool CreateEmptyFile(const std::string &filename); | 98 | bool CreateEmptyFile(const std::string &filename); |
| 99 | 99 | ||
| 100 | /** | 100 | /** |
| 101 | * Scans the directory tree, calling the callback for each file/directory found. | 101 | * @param num_entries_out to be assigned by the callable with the number of iterated directory entries, never null |
| 102 | * The callback must return the number of files and directories which the provided path contains. | 102 | * @param directory the path to the enclosing directory |
| 103 | * If the callback's return value is -1, the callback loop is broken immediately. | 103 | * @param virtual_name the entry name, without any preceding directory info |
| 104 | * If the callback's return value is otherwise negative, the callback loop is broken immediately | 104 | * @return whether handling the entry succeeded |
| 105 | * and the callback's return value is returned from this function (to allow for error handling). | 105 | */ |
| 106 | * @param directory the parent directory to start scanning from | 106 | using DirectoryEntryCallable = std::function<bool(unsigned* num_entries_out, |
| 107 | * @param callback The callback which will be called for each file/directory. It is called | 107 | const std::string& directory, |
| 108 | * with the arguments (const std::string& directory, const std::string& virtual_name). | 108 | const std::string& virtual_name)>; |
| 109 | * The `directory `parameter is the path to the directory which contains the file/directory. | 109 | |
| 110 | * The `virtual_name` parameter is the incomplete file path, without any directory info. | 110 | /** |
| 111 | * @return the total number of files/directories found | 111 | * Scans a directory, calling the callback for each file/directory contained within. |
| 112 | * If the callback returns failure, scanning halts and this function returns failure as well | ||
| 113 | * @param num_entries_out assigned by the function with the number of iterated directory entries, can be null | ||
| 114 | * @param directory the directory to scan | ||
| 115 | * @param callback The callback which will be called for each entry | ||
| 116 | * @return whether scanning the directory succeeded | ||
| 112 | */ | 117 | */ |
| 113 | int ScanDirectoryTreeAndCallback(const std::string &directory, std::function<int(const std::string&, const std::string&)> callback); | 118 | bool ForeachDirectoryEntry(unsigned* num_entries_out, const std::string &directory, DirectoryEntryCallable callback); |
| 114 | 119 | ||
| 115 | /** | 120 | /** |
| 116 | * Scans the directory tree, storing the results. | 121 | * Scans the directory tree, storing the results. |
| @@ -118,7 +123,7 @@ int ScanDirectoryTreeAndCallback(const std::string &directory, std::function<int | |||
| 118 | * @param parent_entry FSTEntry where the filesystem tree results will be stored. | 123 | * @param parent_entry FSTEntry where the filesystem tree results will be stored. |
| 119 | * @return the total number of files/directories found | 124 | * @return the total number of files/directories found |
| 120 | */ | 125 | */ |
| 121 | int ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry); | 126 | unsigned ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry); |
| 122 | 127 | ||
| 123 | // deletes the given directory and anything under it. Returns true on success. | 128 | // deletes the given directory and anything under it. Returns true on success. |
| 124 | bool DeleteDirRecursively(const std::string &directory); | 129 | bool DeleteDirRecursively(const std::string &directory); |
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 92e8e742d..d186ba8f8 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -29,6 +29,7 @@ namespace Log { | |||
| 29 | SUB(Debug, Emulated) \ | 29 | SUB(Debug, Emulated) \ |
| 30 | SUB(Debug, GPU) \ | 30 | SUB(Debug, GPU) \ |
| 31 | SUB(Debug, Breakpoint) \ | 31 | SUB(Debug, Breakpoint) \ |
| 32 | SUB(Debug, GDBStub) \ | ||
| 32 | CLS(Kernel) \ | 33 | CLS(Kernel) \ |
| 33 | SUB(Kernel, SVC) \ | 34 | SUB(Kernel, SVC) \ |
| 34 | CLS(Service) \ | 35 | CLS(Service) \ |
| @@ -43,6 +44,7 @@ namespace Log { | |||
| 43 | SUB(Service, LDR) \ | 44 | SUB(Service, LDR) \ |
| 44 | SUB(Service, NIM) \ | 45 | SUB(Service, NIM) \ |
| 45 | SUB(Service, NWM) \ | 46 | SUB(Service, NWM) \ |
| 47 | SUB(Service, CAM) \ | ||
| 46 | SUB(Service, CFG) \ | 48 | SUB(Service, CFG) \ |
| 47 | SUB(Service, DSP) \ | 49 | SUB(Service, DSP) \ |
| 48 | SUB(Service, HID) \ | 50 | SUB(Service, HID) \ |
diff --git a/src/common/logging/log.h b/src/common/logging/log.h index 5fd3bd7f5..2d9323a7b 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h | |||
| @@ -43,6 +43,7 @@ enum class Class : ClassType { | |||
| 43 | Debug_Emulated, ///< Debug messages from the emulated programs | 43 | Debug_Emulated, ///< Debug messages from the emulated programs |
| 44 | Debug_GPU, ///< GPU debugging tools | 44 | Debug_GPU, ///< GPU debugging tools |
| 45 | Debug_Breakpoint, ///< Logging breakpoints and watchpoints | 45 | Debug_Breakpoint, ///< Logging breakpoints and watchpoints |
| 46 | Debug_GDBStub, ///< GDB Stub | ||
| 46 | Kernel, ///< The HLE implementation of the CTR kernel | 47 | Kernel, ///< The HLE implementation of the CTR kernel |
| 47 | Kernel_SVC, ///< Kernel system calls | 48 | Kernel_SVC, ///< Kernel system calls |
| 48 | Service, ///< HLE implementation of system services. Each major service | 49 | Service, ///< HLE implementation of system services. Each major service |
| @@ -58,6 +59,7 @@ enum class Class : ClassType { | |||
| 58 | Service_LDR, ///< The LDR (3ds dll loader) service | 59 | Service_LDR, ///< The LDR (3ds dll loader) service |
| 59 | Service_NIM, ///< The NIM (Network interface manager) service | 60 | Service_NIM, ///< The NIM (Network interface manager) service |
| 60 | Service_NWM, ///< The NWM (Network wlan manager) service | 61 | Service_NWM, ///< The NWM (Network wlan manager) service |
| 62 | Service_CAM, ///< The CAM (Camera) service | ||
| 61 | Service_CFG, ///< The CFG (Configuration) service | 63 | Service_CFG, ///< The CFG (Configuration) service |
| 62 | Service_DSP, ///< The DSP (DSP control) service | 64 | Service_DSP, ///< The DSP (DSP control) service |
| 63 | Service_HID, ///< The HID (Human interface device) service | 65 | Service_HID, ///< The HID (Human interface device) service |
diff --git a/src/common/vector_math.h b/src/common/vector_math.h index 4928c9bf2..02688e35e 100644 --- a/src/common/vector_math.h +++ b/src/common/vector_math.h | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #pragma once | 32 | #pragma once |
| 33 | 33 | ||
| 34 | #include <cmath> | 34 | #include <cmath> |
| 35 | #include <type_traits> | ||
| 35 | 36 | ||
| 36 | namespace Math { | 37 | namespace Math { |
| 37 | 38 | ||
| @@ -90,6 +91,7 @@ public: | |||
| 90 | { | 91 | { |
| 91 | x-=other.x; y-=other.y; | 92 | x-=other.x; y-=other.y; |
| 92 | } | 93 | } |
| 94 | template<typename Q = T,class = typename std::enable_if<std::is_signed<Q>::value>::type> | ||
| 93 | Vec2<decltype(-T{})> operator -() const | 95 | Vec2<decltype(-T{})> operator -() const |
| 94 | { | 96 | { |
| 95 | return MakeVec(-x,-y); | 97 | return MakeVec(-x,-y); |
| @@ -220,6 +222,7 @@ public: | |||
| 220 | { | 222 | { |
| 221 | x-=other.x; y-=other.y; z-=other.z; | 223 | x-=other.x; y-=other.y; z-=other.z; |
| 222 | } | 224 | } |
| 225 | template<typename Q = T,class = typename std::enable_if<std::is_signed<Q>::value>::type> | ||
| 223 | Vec3<decltype(-T{})> operator -() const | 226 | Vec3<decltype(-T{})> operator -() const |
| 224 | { | 227 | { |
| 225 | return MakeVec(-x,-y,-z); | 228 | return MakeVec(-x,-y,-z); |
| @@ -390,6 +393,7 @@ public: | |||
| 390 | { | 393 | { |
| 391 | x-=other.x; y-=other.y; z-=other.z; w-=other.w; | 394 | x-=other.x; y-=other.y; z-=other.z; w-=other.w; |
| 392 | } | 395 | } |
| 396 | template<typename Q = T,class = typename std::enable_if<std::is_signed<Q>::value>::type> | ||
| 393 | Vec4<decltype(-T{})> operator -() const | 397 | Vec4<decltype(-T{})> operator -() const |
| 394 | { | 398 | { |
| 395 | return MakeVec(-x,-y,-z,-w); | 399 | return MakeVec(-x,-y,-z,-w); |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c17290b9b..861b711c7 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -22,6 +22,7 @@ set(SRCS | |||
| 22 | file_sys/archive_systemsavedata.cpp | 22 | file_sys/archive_systemsavedata.cpp |
| 23 | file_sys/disk_archive.cpp | 23 | file_sys/disk_archive.cpp |
| 24 | file_sys/ivfc_archive.cpp | 24 | file_sys/ivfc_archive.cpp |
| 25 | gdbstub/gdbstub.cpp | ||
| 25 | hle/config_mem.cpp | 26 | hle/config_mem.cpp |
| 26 | hle/hle.cpp | 27 | hle/hle.cpp |
| 27 | hle/applets/applet.cpp | 28 | hle/applets/applet.cpp |
| @@ -149,6 +150,7 @@ set(HEADERS | |||
| 149 | file_sys/disk_archive.h | 150 | file_sys/disk_archive.h |
| 150 | file_sys/file_backend.h | 151 | file_sys/file_backend.h |
| 151 | file_sys/ivfc_archive.h | 152 | file_sys/ivfc_archive.h |
| 153 | gdbstub/gdbstub.h | ||
| 152 | hle/config_mem.h | 154 | hle/config_mem.h |
| 153 | hle/function_wrappers.h | 155 | hle/function_wrappers.h |
| 154 | hle/hle.h | 156 | hle/hle.h |
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index 5cffe513c..533067d4f 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -14,10 +14,6 @@ namespace Core { | |||
| 14 | /// Generic ARM11 CPU interface | 14 | /// Generic ARM11 CPU interface |
| 15 | class ARM_Interface : NonCopyable { | 15 | class ARM_Interface : NonCopyable { |
| 16 | public: | 16 | public: |
| 17 | ARM_Interface() { | ||
| 18 | num_instructions = 0; | ||
| 19 | } | ||
| 20 | |||
| 21 | virtual ~ARM_Interface() { | 17 | virtual ~ARM_Interface() { |
| 22 | } | 18 | } |
| 23 | 19 | ||
| @@ -146,11 +142,11 @@ public: | |||
| 146 | virtual void PrepareReschedule() = 0; | 142 | virtual void PrepareReschedule() = 0; |
| 147 | 143 | ||
| 148 | /// Getter for num_instructions | 144 | /// Getter for num_instructions |
| 149 | u64 GetNumInstructions() { | 145 | u64 GetNumInstructions() const { |
| 150 | return num_instructions; | 146 | return num_instructions; |
| 151 | } | 147 | } |
| 152 | 148 | ||
| 153 | s64 down_count; ///< A decreasing counter of remaining cycles before the next event, decreased by the cpu run loop | 149 | s64 down_count = 0; ///< A decreasing counter of remaining cycles before the next event, decreased by the cpu run loop |
| 154 | 150 | ||
| 155 | protected: | 151 | protected: |
| 156 | 152 | ||
| @@ -162,6 +158,5 @@ protected: | |||
| 162 | 158 | ||
| 163 | private: | 159 | private: |
| 164 | 160 | ||
| 165 | u64 num_instructions; ///< Number of instructions executed | 161 | u64 num_instructions = 0; ///< Number of instructions executed |
| 166 | |||
| 167 | }; | 162 | }; |
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.cpp b/src/core/arm/dyncom/arm_dyncom_dec.cpp index ee4288314..8cd6755cb 100644 --- a/src/core/arm/dyncom/arm_dyncom_dec.cpp +++ b/src/core/arm/dyncom/arm_dyncom_dec.cpp | |||
| @@ -6,10 +6,9 @@ | |||
| 6 | #include "core/arm/skyeye_common/armsupp.h" | 6 | #include "core/arm/skyeye_common/armsupp.h" |
| 7 | 7 | ||
| 8 | const InstructionSetEncodingItem arm_instruction[] = { | 8 | const InstructionSetEncodingItem arm_instruction[] = { |
| 9 | { "vmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 4, 4, 0 }}, | 9 | { "vmla", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }}, |
| 10 | { "vmls", 7, ARMVFP2, { 28, 31, 0xF, 25, 27, 0x1, 23, 23, 1, 11, 11, 0, 8, 9, 0x2, 6, 6, 1, 4, 4, 0 }}, | 10 | { "vmls", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, |
| 11 | { "vnmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 4, 4, 0 }}, | 11 | { "vnmla", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, |
| 12 | { "vnmla", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, | ||
| 13 | { "vnmls", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }}, | 12 | { "vnmls", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }}, |
| 14 | { "vnmul", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, | 13 | { "vnmul", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 }}, |
| 15 | { "vmul", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }}, | 14 | { "vmul", 5, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 }}, |
| @@ -211,7 +210,6 @@ const InstructionSetEncodingItem arm_exclusion_code[] = { | |||
| 211 | { "vmla", 0, ARMVFP2, { 0 }}, | 210 | { "vmla", 0, ARMVFP2, { 0 }}, |
| 212 | { "vmls", 0, ARMVFP2, { 0 }}, | 211 | { "vmls", 0, ARMVFP2, { 0 }}, |
| 213 | { "vnmla", 0, ARMVFP2, { 0 }}, | 212 | { "vnmla", 0, ARMVFP2, { 0 }}, |
| 214 | { "vnmla", 0, ARMVFP2, { 0 }}, | ||
| 215 | { "vnmls", 0, ARMVFP2, { 0 }}, | 213 | { "vnmls", 0, ARMVFP2, { 0 }}, |
| 216 | { "vnmul", 0, ARMVFP2, { 0 }}, | 214 | { "vnmul", 0, ARMVFP2, { 0 }}, |
| 217 | { "vmul", 0, ARMVFP2, { 0 }}, | 215 | { "vmul", 0, ARMVFP2, { 0 }}, |
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index fbd6f94f9..5f8826034 100644 --- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp +++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp | |||
| @@ -23,6 +23,8 @@ | |||
| 23 | #include "core/arm/skyeye_common/armsupp.h" | 23 | #include "core/arm/skyeye_common/armsupp.h" |
| 24 | #include "core/arm/skyeye_common/vfp/vfp.h" | 24 | #include "core/arm/skyeye_common/vfp/vfp.h" |
| 25 | 25 | ||
| 26 | #include "core/gdbstub/gdbstub.h" | ||
| 27 | |||
| 26 | Common::Profiling::TimingCategory profile_execute("DynCom::Execute"); | 28 | Common::Profiling::TimingCategory profile_execute("DynCom::Execute"); |
| 27 | Common::Profiling::TimingCategory profile_decode("DynCom::Decode"); | 29 | Common::Profiling::TimingCategory profile_decode("DynCom::Decode"); |
| 28 | 30 | ||
| @@ -49,7 +51,7 @@ enum { | |||
| 49 | 51 | ||
| 50 | typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper); | 52 | typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper); |
| 51 | 53 | ||
| 52 | static bool CondPassed(ARMul_State* cpu, unsigned int cond) { | 54 | static bool CondPassed(const ARMul_State* cpu, unsigned int cond) { |
| 53 | const bool n_flag = cpu->NFlag != 0; | 55 | const bool n_flag = cpu->NFlag != 0; |
| 54 | const bool z_flag = cpu->ZFlag != 0; | 56 | const bool z_flag = cpu->ZFlag != 0; |
| 55 | const bool c_flag = cpu->CFlag != 0; | 57 | const bool c_flag = cpu->CFlag != 0; |
| @@ -1621,9 +1623,6 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrb)(unsigned int inst, int index) | |||
| 1621 | inst_cream->inst = inst; | 1623 | inst_cream->inst = inst; |
| 1622 | inst_cream->get_addr = get_calc_addr_op(inst); | 1624 | inst_cream->get_addr = get_calc_addr_op(inst); |
| 1623 | 1625 | ||
| 1624 | if (BITS(inst, 12, 15) == 15) { | ||
| 1625 | inst_base->br = INDIRECT_BRANCH; | ||
| 1626 | } | ||
| 1627 | return inst_base; | 1626 | return inst_base; |
| 1628 | } | 1627 | } |
| 1629 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index) | 1628 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index) |
| @@ -1644,9 +1643,6 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index) | |||
| 1644 | DEBUG_MSG; | 1643 | DEBUG_MSG; |
| 1645 | } | 1644 | } |
| 1646 | 1645 | ||
| 1647 | if (BITS(inst, 12, 15) == 15) { | ||
| 1648 | inst_base->br = INDIRECT_BRANCH; | ||
| 1649 | } | ||
| 1650 | return inst_base; | 1646 | return inst_base; |
| 1651 | } | 1647 | } |
| 1652 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index) | 1648 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index) |
| @@ -1701,9 +1697,6 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrh)(unsigned int inst, int index) | |||
| 1701 | inst_cream->inst = inst; | 1697 | inst_cream->inst = inst; |
| 1702 | inst_cream->get_addr = get_calc_addr_op(inst); | 1698 | inst_cream->get_addr = get_calc_addr_op(inst); |
| 1703 | 1699 | ||
| 1704 | if (BITS(inst, 12, 15) == 15) { | ||
| 1705 | inst_base->br = INDIRECT_BRANCH; | ||
| 1706 | } | ||
| 1707 | return inst_base; | 1700 | return inst_base; |
| 1708 | } | 1701 | } |
| 1709 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index) | 1702 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index) |
| @@ -1718,9 +1711,6 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index) | |||
| 1718 | inst_cream->inst = inst; | 1711 | inst_cream->inst = inst; |
| 1719 | inst_cream->get_addr = get_calc_addr_op(inst); | 1712 | inst_cream->get_addr = get_calc_addr_op(inst); |
| 1720 | 1713 | ||
| 1721 | if (BITS(inst, 12, 15) == 15) { | ||
| 1722 | inst_base->br = INDIRECT_BRANCH; | ||
| 1723 | } | ||
| 1724 | return inst_base; | 1714 | return inst_base; |
| 1725 | } | 1715 | } |
| 1726 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index) | 1716 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index) |
| @@ -1735,9 +1725,6 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index) | |||
| 1735 | inst_cream->inst = inst; | 1725 | inst_cream->inst = inst; |
| 1736 | inst_cream->get_addr = get_calc_addr_op(inst); | 1726 | inst_cream->get_addr = get_calc_addr_op(inst); |
| 1737 | 1727 | ||
| 1738 | if (BITS(inst, 12, 15) == 15) { | ||
| 1739 | inst_base->br = INDIRECT_BRANCH; | ||
| 1740 | } | ||
| 1741 | return inst_base; | 1728 | return inst_base; |
| 1742 | } | 1729 | } |
| 1743 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index) | 1730 | static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index) |
| @@ -2595,9 +2582,6 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(str)(unsigned int inst, int index) | |||
| 2595 | inst_cream->inst = inst; | 2582 | inst_cream->inst = inst; |
| 2596 | inst_cream->get_addr = get_calc_addr_op(inst); | 2583 | inst_cream->get_addr = get_calc_addr_op(inst); |
| 2597 | 2584 | ||
| 2598 | if (BITS(inst, 12, 15) == 15) { | ||
| 2599 | inst_base->br = INDIRECT_BRANCH; | ||
| 2600 | } | ||
| 2601 | return inst_base; | 2585 | return inst_base; |
| 2602 | } | 2586 | } |
| 2603 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb)(unsigned int inst, int index) | 2587 | static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb)(unsigned int inst, int index) |
| @@ -2643,9 +2627,6 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(strb)(unsigned int inst, int index) | |||
| 2643 | inst_cream->inst = inst; | 2627 | inst_cream->inst = inst; |
| 2644 | inst_cream->get_addr = get_calc_addr_op(inst); | 2628 | inst_cream->get_addr = get_calc_addr_op(inst); |
| 2645 | 2629 | ||
| 2646 | if (BITS(inst, 12, 15) == 15) { | ||
| 2647 | inst_base->br = INDIRECT_BRANCH; | ||
| 2648 | } | ||
| 2649 | return inst_base; | 2630 | return inst_base; |
| 2650 | } | 2631 | } |
| 2651 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index) | 2632 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index) |
| @@ -2667,9 +2648,6 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index) | |||
| 2667 | DEBUG_MSG; | 2648 | DEBUG_MSG; |
| 2668 | } | 2649 | } |
| 2669 | 2650 | ||
| 2670 | if (BITS(inst, 12, 15) == 15) { | ||
| 2671 | inst_base->br = INDIRECT_BRANCH; | ||
| 2672 | } | ||
| 2673 | return inst_base; | 2651 | return inst_base; |
| 2674 | } | 2652 | } |
| 2675 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){ | 2653 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){ |
| @@ -2683,9 +2661,6 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){ | |||
| 2683 | inst_cream->inst = inst; | 2661 | inst_cream->inst = inst; |
| 2684 | inst_cream->get_addr = get_calc_addr_op(inst); | 2662 | inst_cream->get_addr = get_calc_addr_op(inst); |
| 2685 | 2663 | ||
| 2686 | if (BITS(inst, 12, 15) == 15) { | ||
| 2687 | inst_base->br = INDIRECT_BRANCH; | ||
| 2688 | } | ||
| 2689 | return inst_base; | 2664 | return inst_base; |
| 2690 | } | 2665 | } |
| 2691 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strex)(unsigned int inst, int index) | 2666 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strex)(unsigned int inst, int index) |
| @@ -2727,9 +2702,6 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(strh)(unsigned int inst, int index) | |||
| 2727 | inst_cream->inst = inst; | 2702 | inst_cream->inst = inst; |
| 2728 | inst_cream->get_addr = get_calc_addr_op(inst); | 2703 | inst_cream->get_addr = get_calc_addr_op(inst); |
| 2729 | 2704 | ||
| 2730 | if (BITS(inst, 12, 15) == 15) { | ||
| 2731 | inst_base->br = INDIRECT_BRANCH; | ||
| 2732 | } | ||
| 2733 | return inst_base; | 2705 | return inst_base; |
| 2734 | } | 2706 | } |
| 2735 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index) | 2707 | static ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index) |
| @@ -2755,9 +2727,6 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index) | |||
| 2755 | DEBUG_MSG; | 2727 | DEBUG_MSG; |
| 2756 | } | 2728 | } |
| 2757 | 2729 | ||
| 2758 | if (BITS(inst, 12, 15) == 15) { | ||
| 2759 | inst_base->br = INDIRECT_BRANCH; | ||
| 2760 | } | ||
| 2761 | return inst_base; | 2730 | return inst_base; |
| 2762 | } | 2731 | } |
| 2763 | static ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index) | 2732 | static ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index) |
| @@ -2806,9 +2775,6 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(swp)(unsigned int inst, int index) | |||
| 2806 | inst_cream->Rd = BITS(inst, 12, 15); | 2775 | inst_cream->Rd = BITS(inst, 12, 15); |
| 2807 | inst_cream->Rm = BITS(inst, 0, 3); | 2776 | inst_cream->Rm = BITS(inst, 0, 3); |
| 2808 | 2777 | ||
| 2809 | if (inst_cream->Rd == 15) { | ||
| 2810 | inst_base->br = INDIRECT_BRANCH; | ||
| 2811 | } | ||
| 2812 | return inst_base; | 2778 | return inst_base; |
| 2813 | } | 2779 | } |
| 2814 | static ARM_INST_PTR INTERPRETER_TRANSLATE(swpb)(unsigned int inst, int index){ | 2780 | static ARM_INST_PTR INTERPRETER_TRANSLATE(swpb)(unsigned int inst, int index){ |
| @@ -2823,9 +2789,6 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(swpb)(unsigned int inst, int index){ | |||
| 2823 | inst_cream->Rd = BITS(inst, 12, 15); | 2789 | inst_cream->Rd = BITS(inst, 12, 15); |
| 2824 | inst_cream->Rm = BITS(inst, 0, 3); | 2790 | inst_cream->Rm = BITS(inst, 0, 3); |
| 2825 | 2791 | ||
| 2826 | if (inst_cream->Rd == 15) { | ||
| 2827 | inst_base->br = INDIRECT_BRANCH; | ||
| 2828 | } | ||
| 2829 | return inst_base; | 2792 | return inst_base; |
| 2830 | } | 2793 | } |
| 2831 | static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab)(unsigned int inst, int index){ | 2794 | static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab)(unsigned int inst, int index){ |
| @@ -2913,9 +2876,6 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(tst)(unsigned int inst, int index) | |||
| 2913 | inst_cream->shifter_operand = BITS(inst, 0, 11); | 2876 | inst_cream->shifter_operand = BITS(inst, 0, 11); |
| 2914 | inst_cream->shtop_func = get_shtop(inst); | 2877 | inst_cream->shtop_func = get_shtop(inst); |
| 2915 | 2878 | ||
| 2916 | if (inst_cream->Rd == 15) | ||
| 2917 | inst_base->br = INDIRECT_BRANCH; | ||
| 2918 | |||
| 2919 | return inst_base; | 2879 | return inst_base; |
| 2920 | } | 2880 | } |
| 2921 | 2881 | ||
| @@ -3242,7 +3202,6 @@ const transop_fp_t arm_instruction_trans[] = { | |||
| 3242 | INTERPRETER_TRANSLATE(vmla), | 3202 | INTERPRETER_TRANSLATE(vmla), |
| 3243 | INTERPRETER_TRANSLATE(vmls), | 3203 | INTERPRETER_TRANSLATE(vmls), |
| 3244 | INTERPRETER_TRANSLATE(vnmla), | 3204 | INTERPRETER_TRANSLATE(vnmla), |
| 3245 | INTERPRETER_TRANSLATE(vnmla), | ||
| 3246 | INTERPRETER_TRANSLATE(vnmls), | 3205 | INTERPRETER_TRANSLATE(vnmls), |
| 3247 | INTERPRETER_TRANSLATE(vnmul), | 3206 | INTERPRETER_TRANSLATE(vnmul), |
| 3248 | INTERPRETER_TRANSLATE(vmul), | 3207 | INTERPRETER_TRANSLATE(vmul), |
| @@ -3548,6 +3507,7 @@ static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) { | |||
| 3548 | CITRA_IGNORE_EXIT(-1); | 3507 | CITRA_IGNORE_EXIT(-1); |
| 3549 | } | 3508 | } |
| 3550 | inst_base = arm_instruction_trans[idx](inst, idx); | 3509 | inst_base = arm_instruction_trans[idx](inst, idx); |
| 3510 | |||
| 3551 | translated: | 3511 | translated: |
| 3552 | phys_addr += inst_size; | 3512 | phys_addr += inst_size; |
| 3553 | 3513 | ||
| @@ -3580,6 +3540,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 3580 | Common::Profiling::ScopeTimer timer_execute(profile_execute); | 3540 | Common::Profiling::ScopeTimer timer_execute(profile_execute); |
| 3581 | MICROPROFILE_SCOPE(DynCom_Execute); | 3541 | MICROPROFILE_SCOPE(DynCom_Execute); |
| 3582 | 3542 | ||
| 3543 | GDBStub::BreakpointAddress breakpoint_data; | ||
| 3544 | |||
| 3583 | #undef RM | 3545 | #undef RM |
| 3584 | #undef RS | 3546 | #undef RS |
| 3585 | 3547 | ||
| @@ -3604,224 +3566,235 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 3604 | #define INC_PC(l) ptr += sizeof(arm_inst) + l | 3566 | #define INC_PC(l) ptr += sizeof(arm_inst) + l |
| 3605 | #define INC_PC_STUB ptr += sizeof(arm_inst) | 3567 | #define INC_PC_STUB ptr += sizeof(arm_inst) |
| 3606 | 3568 | ||
| 3569 | #define GDB_BP_CHECK \ | ||
| 3570 | cpu->Cpsr &= ~(1 << 5); \ | ||
| 3571 | cpu->Cpsr |= cpu->TFlag << 5; \ | ||
| 3572 | if (GDBStub::g_server_enabled) { \ | ||
| 3573 | if (GDBStub::IsMemoryBreak() || (breakpoint_data.type != GDBStub::BreakpointType::None && PC == breakpoint_data.address)) { \ | ||
| 3574 | GDBStub::Break(); \ | ||
| 3575 | goto END; \ | ||
| 3576 | } \ | ||
| 3577 | } | ||
| 3578 | |||
| 3607 | // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a | 3579 | // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a |
| 3608 | // clunky switch statement. | 3580 | // clunky switch statement. |
| 3609 | #if defined __GNUC__ || defined __clang__ | 3581 | #if defined __GNUC__ || defined __clang__ |
| 3610 | #define GOTO_NEXT_INST \ | 3582 | #define GOTO_NEXT_INST \ |
| 3583 | GDB_BP_CHECK; \ | ||
| 3611 | if (num_instrs >= cpu->NumInstrsToExecute) goto END; \ | 3584 | if (num_instrs >= cpu->NumInstrsToExecute) goto END; \ |
| 3612 | num_instrs++; \ | 3585 | num_instrs++; \ |
| 3613 | goto *InstLabel[inst_base->idx] | 3586 | goto *InstLabel[inst_base->idx] |
| 3614 | #else | 3587 | #else |
| 3615 | #define GOTO_NEXT_INST \ | 3588 | #define GOTO_NEXT_INST \ |
| 3589 | GDB_BP_CHECK; \ | ||
| 3616 | if (num_instrs >= cpu->NumInstrsToExecute) goto END; \ | 3590 | if (num_instrs >= cpu->NumInstrsToExecute) goto END; \ |
| 3617 | num_instrs++; \ | 3591 | num_instrs++; \ |
| 3618 | switch(inst_base->idx) { \ | 3592 | switch(inst_base->idx) { \ |
| 3619 | case 0: goto VMLA_INST; \ | 3593 | case 0: goto VMLA_INST; \ |
| 3620 | case 1: goto VMLS_INST; \ | 3594 | case 1: goto VMLS_INST; \ |
| 3621 | case 2: goto VNMLA_INST; \ | 3595 | case 2: goto VNMLA_INST; \ |
| 3622 | case 3: goto VNMLA_INST; \ | 3596 | case 3: goto VNMLS_INST; \ |
| 3623 | case 4: goto VNMLS_INST; \ | 3597 | case 4: goto VNMUL_INST; \ |
| 3624 | case 5: goto VNMUL_INST; \ | 3598 | case 5: goto VMUL_INST; \ |
| 3625 | case 6: goto VMUL_INST; \ | 3599 | case 6: goto VADD_INST; \ |
| 3626 | case 7: goto VADD_INST; \ | 3600 | case 7: goto VSUB_INST; \ |
| 3627 | case 8: goto VSUB_INST; \ | 3601 | case 8: goto VDIV_INST; \ |
| 3628 | case 9: goto VDIV_INST; \ | 3602 | case 9: goto VMOVI_INST; \ |
| 3629 | case 10: goto VMOVI_INST; \ | 3603 | case 10: goto VMOVR_INST; \ |
| 3630 | case 11: goto VMOVR_INST; \ | 3604 | case 11: goto VABS_INST; \ |
| 3631 | case 12: goto VABS_INST; \ | 3605 | case 12: goto VNEG_INST; \ |
| 3632 | case 13: goto VNEG_INST; \ | 3606 | case 13: goto VSQRT_INST; \ |
| 3633 | case 14: goto VSQRT_INST; \ | 3607 | case 14: goto VCMP_INST; \ |
| 3634 | case 15: goto VCMP_INST; \ | 3608 | case 15: goto VCMP2_INST; \ |
| 3635 | case 16: goto VCMP2_INST; \ | 3609 | case 16: goto VCVTBDS_INST; \ |
| 3636 | case 17: goto VCVTBDS_INST; \ | 3610 | case 17: goto VCVTBFF_INST; \ |
| 3637 | case 18: goto VCVTBFF_INST; \ | 3611 | case 18: goto VCVTBFI_INST; \ |
| 3638 | case 19: goto VCVTBFI_INST; \ | 3612 | case 19: goto VMOVBRS_INST; \ |
| 3639 | case 20: goto VMOVBRS_INST; \ | 3613 | case 20: goto VMSR_INST; \ |
| 3640 | case 21: goto VMSR_INST; \ | 3614 | case 21: goto VMOVBRC_INST; \ |
| 3641 | case 22: goto VMOVBRC_INST; \ | 3615 | case 22: goto VMRS_INST; \ |
| 3642 | case 23: goto VMRS_INST; \ | 3616 | case 23: goto VMOVBCR_INST; \ |
| 3643 | case 24: goto VMOVBCR_INST; \ | 3617 | case 24: goto VMOVBRRSS_INST; \ |
| 3644 | case 25: goto VMOVBRRSS_INST; \ | 3618 | case 25: goto VMOVBRRD_INST; \ |
| 3645 | case 26: goto VMOVBRRD_INST; \ | 3619 | case 26: goto VSTR_INST; \ |
| 3646 | case 27: goto VSTR_INST; \ | 3620 | case 27: goto VPUSH_INST; \ |
| 3647 | case 28: goto VPUSH_INST; \ | 3621 | case 28: goto VSTM_INST; \ |
| 3648 | case 29: goto VSTM_INST; \ | 3622 | case 29: goto VPOP_INST; \ |
| 3649 | case 30: goto VPOP_INST; \ | 3623 | case 30: goto VLDR_INST; \ |
| 3650 | case 31: goto VLDR_INST; \ | 3624 | case 31: goto VLDM_INST ; \ |
| 3651 | case 32: goto VLDM_INST ; \ | 3625 | case 32: goto SRS_INST; \ |
| 3652 | case 33: goto SRS_INST; \ | 3626 | case 33: goto RFE_INST; \ |
| 3653 | case 34: goto RFE_INST; \ | 3627 | case 34: goto BKPT_INST; \ |
| 3654 | case 35: goto BKPT_INST; \ | 3628 | case 35: goto BLX_INST; \ |
| 3655 | case 36: goto BLX_INST; \ | 3629 | case 36: goto CPS_INST; \ |
| 3656 | case 37: goto CPS_INST; \ | 3630 | case 37: goto PLD_INST; \ |
| 3657 | case 38: goto PLD_INST; \ | 3631 | case 38: goto SETEND_INST; \ |
| 3658 | case 39: goto SETEND_INST; \ | 3632 | case 39: goto CLREX_INST; \ |
| 3659 | case 40: goto CLREX_INST; \ | 3633 | case 40: goto REV16_INST; \ |
| 3660 | case 41: goto REV16_INST; \ | 3634 | case 41: goto USAD8_INST; \ |
| 3661 | case 42: goto USAD8_INST; \ | 3635 | case 42: goto SXTB_INST; \ |
| 3662 | case 43: goto SXTB_INST; \ | 3636 | case 43: goto UXTB_INST; \ |
| 3663 | case 44: goto UXTB_INST; \ | 3637 | case 44: goto SXTH_INST; \ |
| 3664 | case 45: goto SXTH_INST; \ | 3638 | case 45: goto SXTB16_INST; \ |
| 3665 | case 46: goto SXTB16_INST; \ | 3639 | case 46: goto UXTH_INST; \ |
| 3666 | case 47: goto UXTH_INST; \ | 3640 | case 47: goto UXTB16_INST; \ |
| 3667 | case 48: goto UXTB16_INST; \ | 3641 | case 48: goto CPY_INST; \ |
| 3668 | case 49: goto CPY_INST; \ | 3642 | case 49: goto UXTAB_INST; \ |
| 3669 | case 50: goto UXTAB_INST; \ | 3643 | case 50: goto SSUB8_INST; \ |
| 3670 | case 51: goto SSUB8_INST; \ | 3644 | case 51: goto SHSUB8_INST; \ |
| 3671 | case 52: goto SHSUB8_INST; \ | 3645 | case 52: goto SSUBADDX_INST; \ |
| 3672 | case 53: goto SSUBADDX_INST; \ | 3646 | case 53: goto STREX_INST; \ |
| 3673 | case 54: goto STREX_INST; \ | 3647 | case 54: goto STREXB_INST; \ |
| 3674 | case 55: goto STREXB_INST; \ | 3648 | case 55: goto SWP_INST; \ |
| 3675 | case 56: goto SWP_INST; \ | 3649 | case 56: goto SWPB_INST; \ |
| 3676 | case 57: goto SWPB_INST; \ | 3650 | case 57: goto SSUB16_INST; \ |
| 3677 | case 58: goto SSUB16_INST; \ | 3651 | case 58: goto SSAT16_INST; \ |
| 3678 | case 59: goto SSAT16_INST; \ | 3652 | case 59: goto SHSUBADDX_INST; \ |
| 3679 | case 60: goto SHSUBADDX_INST; \ | 3653 | case 60: goto QSUBADDX_INST; \ |
| 3680 | case 61: goto QSUBADDX_INST; \ | 3654 | case 61: goto SHADDSUBX_INST; \ |
| 3681 | case 62: goto SHADDSUBX_INST; \ | 3655 | case 62: goto SHADD8_INST; \ |
| 3682 | case 63: goto SHADD8_INST; \ | 3656 | case 63: goto SHADD16_INST; \ |
| 3683 | case 64: goto SHADD16_INST; \ | 3657 | case 64: goto SEL_INST; \ |
| 3684 | case 65: goto SEL_INST; \ | 3658 | case 65: goto SADDSUBX_INST; \ |
| 3685 | case 66: goto SADDSUBX_INST; \ | 3659 | case 66: goto SADD8_INST; \ |
| 3686 | case 67: goto SADD8_INST; \ | 3660 | case 67: goto SADD16_INST; \ |
| 3687 | case 68: goto SADD16_INST; \ | 3661 | case 68: goto SHSUB16_INST; \ |
| 3688 | case 69: goto SHSUB16_INST; \ | 3662 | case 69: goto UMAAL_INST; \ |
| 3689 | case 70: goto UMAAL_INST; \ | 3663 | case 70: goto UXTAB16_INST; \ |
| 3690 | case 71: goto UXTAB16_INST; \ | 3664 | case 71: goto USUBADDX_INST; \ |
| 3691 | case 72: goto USUBADDX_INST; \ | 3665 | case 72: goto USUB8_INST; \ |
| 3692 | case 73: goto USUB8_INST; \ | 3666 | case 73: goto USUB16_INST; \ |
| 3693 | case 74: goto USUB16_INST; \ | 3667 | case 74: goto USAT16_INST; \ |
| 3694 | case 75: goto USAT16_INST; \ | 3668 | case 75: goto USADA8_INST; \ |
| 3695 | case 76: goto USADA8_INST; \ | 3669 | case 76: goto UQSUBADDX_INST; \ |
| 3696 | case 77: goto UQSUBADDX_INST; \ | 3670 | case 77: goto UQSUB8_INST; \ |
| 3697 | case 78: goto UQSUB8_INST; \ | 3671 | case 78: goto UQSUB16_INST; \ |
| 3698 | case 79: goto UQSUB16_INST; \ | 3672 | case 79: goto UQADDSUBX_INST; \ |
| 3699 | case 80: goto UQADDSUBX_INST; \ | 3673 | case 80: goto UQADD8_INST; \ |
| 3700 | case 81: goto UQADD8_INST; \ | 3674 | case 81: goto UQADD16_INST; \ |
| 3701 | case 82: goto UQADD16_INST; \ | 3675 | case 82: goto SXTAB_INST; \ |
| 3702 | case 83: goto SXTAB_INST; \ | 3676 | case 83: goto UHSUBADDX_INST; \ |
| 3703 | case 84: goto UHSUBADDX_INST; \ | 3677 | case 84: goto UHSUB8_INST; \ |
| 3704 | case 85: goto UHSUB8_INST; \ | 3678 | case 85: goto UHSUB16_INST; \ |
| 3705 | case 86: goto UHSUB16_INST; \ | 3679 | case 86: goto UHADDSUBX_INST; \ |
| 3706 | case 87: goto UHADDSUBX_INST; \ | 3680 | case 87: goto UHADD8_INST; \ |
| 3707 | case 88: goto UHADD8_INST; \ | 3681 | case 88: goto UHADD16_INST; \ |
| 3708 | case 89: goto UHADD16_INST; \ | 3682 | case 89: goto UADDSUBX_INST; \ |
| 3709 | case 90: goto UADDSUBX_INST; \ | 3683 | case 90: goto UADD8_INST; \ |
| 3710 | case 91: goto UADD8_INST; \ | 3684 | case 91: goto UADD16_INST; \ |
| 3711 | case 92: goto UADD16_INST; \ | 3685 | case 92: goto SXTAH_INST; \ |
| 3712 | case 93: goto SXTAH_INST; \ | 3686 | case 93: goto SXTAB16_INST; \ |
| 3713 | case 94: goto SXTAB16_INST; \ | 3687 | case 94: goto QADD8_INST; \ |
| 3714 | case 95: goto QADD8_INST; \ | 3688 | case 95: goto BXJ_INST; \ |
| 3715 | case 96: goto BXJ_INST; \ | 3689 | case 96: goto CLZ_INST; \ |
| 3716 | case 97: goto CLZ_INST; \ | 3690 | case 97: goto UXTAH_INST; \ |
| 3717 | case 98: goto UXTAH_INST; \ | 3691 | case 98: goto BX_INST; \ |
| 3718 | case 99: goto BX_INST; \ | 3692 | case 99: goto REV_INST; \ |
| 3719 | case 100: goto REV_INST; \ | 3693 | case 100: goto BLX_INST; \ |
| 3720 | case 101: goto BLX_INST; \ | 3694 | case 101: goto REVSH_INST; \ |
| 3721 | case 102: goto REVSH_INST; \ | 3695 | case 102: goto QADD_INST; \ |
| 3722 | case 103: goto QADD_INST; \ | 3696 | case 103: goto QADD16_INST; \ |
| 3723 | case 104: goto QADD16_INST; \ | 3697 | case 104: goto QADDSUBX_INST; \ |
| 3724 | case 105: goto QADDSUBX_INST; \ | 3698 | case 105: goto LDREX_INST; \ |
| 3725 | case 106: goto LDREX_INST; \ | 3699 | case 106: goto QDADD_INST; \ |
| 3726 | case 107: goto QDADD_INST; \ | 3700 | case 107: goto QDSUB_INST; \ |
| 3727 | case 108: goto QDSUB_INST; \ | 3701 | case 108: goto QSUB_INST; \ |
| 3728 | case 109: goto QSUB_INST; \ | 3702 | case 109: goto LDREXB_INST; \ |
| 3729 | case 110: goto LDREXB_INST; \ | 3703 | case 110: goto QSUB8_INST; \ |
| 3730 | case 111: goto QSUB8_INST; \ | 3704 | case 111: goto QSUB16_INST; \ |
| 3731 | case 112: goto QSUB16_INST; \ | 3705 | case 112: goto SMUAD_INST; \ |
| 3732 | case 113: goto SMUAD_INST; \ | 3706 | case 113: goto SMMUL_INST; \ |
| 3733 | case 114: goto SMMUL_INST; \ | 3707 | case 114: goto SMUSD_INST; \ |
| 3734 | case 115: goto SMUSD_INST; \ | 3708 | case 115: goto SMLSD_INST; \ |
| 3735 | case 116: goto SMLSD_INST; \ | 3709 | case 116: goto SMLSLD_INST; \ |
| 3736 | case 117: goto SMLSLD_INST; \ | 3710 | case 117: goto SMMLA_INST; \ |
| 3737 | case 118: goto SMMLA_INST; \ | 3711 | case 118: goto SMMLS_INST; \ |
| 3738 | case 119: goto SMMLS_INST; \ | 3712 | case 119: goto SMLALD_INST; \ |
| 3739 | case 120: goto SMLALD_INST; \ | 3713 | case 120: goto SMLAD_INST; \ |
| 3740 | case 121: goto SMLAD_INST; \ | 3714 | case 121: goto SMLAW_INST; \ |
| 3741 | case 122: goto SMLAW_INST; \ | 3715 | case 122: goto SMULW_INST; \ |
| 3742 | case 123: goto SMULW_INST; \ | 3716 | case 123: goto PKHTB_INST; \ |
| 3743 | case 124: goto PKHTB_INST; \ | 3717 | case 124: goto PKHBT_INST; \ |
| 3744 | case 125: goto PKHBT_INST; \ | 3718 | case 125: goto SMUL_INST; \ |
| 3745 | case 126: goto SMUL_INST; \ | 3719 | case 126: goto SMLALXY_INST; \ |
| 3746 | case 127: goto SMLALXY_INST; \ | 3720 | case 127: goto SMLA_INST; \ |
| 3747 | case 128: goto SMLA_INST; \ | 3721 | case 128: goto MCRR_INST; \ |
| 3748 | case 129: goto MCRR_INST; \ | 3722 | case 129: goto MRRC_INST; \ |
| 3749 | case 130: goto MRRC_INST; \ | 3723 | case 130: goto CMP_INST; \ |
| 3750 | case 131: goto CMP_INST; \ | 3724 | case 131: goto TST_INST; \ |
| 3751 | case 132: goto TST_INST; \ | 3725 | case 132: goto TEQ_INST; \ |
| 3752 | case 133: goto TEQ_INST; \ | 3726 | case 133: goto CMN_INST; \ |
| 3753 | case 134: goto CMN_INST; \ | 3727 | case 134: goto SMULL_INST; \ |
| 3754 | case 135: goto SMULL_INST; \ | 3728 | case 135: goto UMULL_INST; \ |
| 3755 | case 136: goto UMULL_INST; \ | 3729 | case 136: goto UMLAL_INST; \ |
| 3756 | case 137: goto UMLAL_INST; \ | 3730 | case 137: goto SMLAL_INST; \ |
| 3757 | case 138: goto SMLAL_INST; \ | 3731 | case 138: goto MUL_INST; \ |
| 3758 | case 139: goto MUL_INST; \ | 3732 | case 139: goto MLA_INST; \ |
| 3759 | case 140: goto MLA_INST; \ | 3733 | case 140: goto SSAT_INST; \ |
| 3760 | case 141: goto SSAT_INST; \ | 3734 | case 141: goto USAT_INST; \ |
| 3761 | case 142: goto USAT_INST; \ | 3735 | case 142: goto MRS_INST; \ |
| 3762 | case 143: goto MRS_INST; \ | 3736 | case 143: goto MSR_INST; \ |
| 3763 | case 144: goto MSR_INST; \ | 3737 | case 144: goto AND_INST; \ |
| 3764 | case 145: goto AND_INST; \ | 3738 | case 145: goto BIC_INST; \ |
| 3765 | case 146: goto BIC_INST; \ | 3739 | case 146: goto LDM_INST; \ |
| 3766 | case 147: goto LDM_INST; \ | 3740 | case 147: goto EOR_INST; \ |
| 3767 | case 148: goto EOR_INST; \ | 3741 | case 148: goto ADD_INST; \ |
| 3768 | case 149: goto ADD_INST; \ | 3742 | case 149: goto RSB_INST; \ |
| 3769 | case 150: goto RSB_INST; \ | 3743 | case 150: goto RSC_INST; \ |
| 3770 | case 151: goto RSC_INST; \ | 3744 | case 151: goto SBC_INST; \ |
| 3771 | case 152: goto SBC_INST; \ | 3745 | case 152: goto ADC_INST; \ |
| 3772 | case 153: goto ADC_INST; \ | 3746 | case 153: goto SUB_INST; \ |
| 3773 | case 154: goto SUB_INST; \ | 3747 | case 154: goto ORR_INST; \ |
| 3774 | case 155: goto ORR_INST; \ | 3748 | case 155: goto MVN_INST; \ |
| 3775 | case 156: goto MVN_INST; \ | 3749 | case 156: goto MOV_INST; \ |
| 3776 | case 157: goto MOV_INST; \ | 3750 | case 157: goto STM_INST; \ |
| 3777 | case 158: goto STM_INST; \ | 3751 | case 158: goto LDM_INST; \ |
| 3778 | case 159: goto LDM_INST; \ | 3752 | case 159: goto LDRSH_INST; \ |
| 3779 | case 160: goto LDRSH_INST; \ | 3753 | case 160: goto STM_INST; \ |
| 3780 | case 161: goto STM_INST; \ | 3754 | case 161: goto LDM_INST; \ |
| 3781 | case 162: goto LDM_INST; \ | 3755 | case 162: goto LDRSB_INST; \ |
| 3782 | case 163: goto LDRSB_INST; \ | 3756 | case 163: goto STRD_INST; \ |
| 3783 | case 164: goto STRD_INST; \ | 3757 | case 164: goto LDRH_INST; \ |
| 3784 | case 165: goto LDRH_INST; \ | 3758 | case 165: goto STRH_INST; \ |
| 3785 | case 166: goto STRH_INST; \ | 3759 | case 166: goto LDRD_INST; \ |
| 3786 | case 167: goto LDRD_INST; \ | 3760 | case 167: goto STRT_INST; \ |
| 3787 | case 168: goto STRT_INST; \ | 3761 | case 168: goto STRBT_INST; \ |
| 3788 | case 169: goto STRBT_INST; \ | 3762 | case 169: goto LDRBT_INST; \ |
| 3789 | case 170: goto LDRBT_INST; \ | 3763 | case 170: goto LDRT_INST; \ |
| 3790 | case 171: goto LDRT_INST; \ | 3764 | case 171: goto MRC_INST; \ |
| 3791 | case 172: goto MRC_INST; \ | 3765 | case 172: goto MCR_INST; \ |
| 3792 | case 173: goto MCR_INST; \ | 3766 | case 173: goto MSR_INST; \ |
| 3793 | case 174: goto MSR_INST; \ | 3767 | case 174: goto MSR_INST; \ |
| 3794 | case 175: goto MSR_INST; \ | 3768 | case 175: goto MSR_INST; \ |
| 3795 | case 176: goto MSR_INST; \ | 3769 | case 176: goto MSR_INST; \ |
| 3796 | case 177: goto MSR_INST; \ | 3770 | case 177: goto MSR_INST; \ |
| 3797 | case 178: goto MSR_INST; \ | 3771 | case 178: goto LDRB_INST; \ |
| 3798 | case 179: goto LDRB_INST; \ | 3772 | case 179: goto STRB_INST; \ |
| 3799 | case 180: goto STRB_INST; \ | 3773 | case 180: goto LDR_INST; \ |
| 3800 | case 181: goto LDR_INST; \ | 3774 | case 181: goto LDRCOND_INST ; \ |
| 3801 | case 182: goto LDRCOND_INST ; \ | 3775 | case 182: goto STR_INST; \ |
| 3802 | case 183: goto STR_INST; \ | 3776 | case 183: goto CDP_INST; \ |
| 3803 | case 184: goto CDP_INST; \ | 3777 | case 184: goto STC_INST; \ |
| 3804 | case 185: goto STC_INST; \ | 3778 | case 185: goto LDC_INST; \ |
| 3805 | case 186: goto LDC_INST; \ | 3779 | case 186: goto LDREXD_INST; \ |
| 3806 | case 187: goto LDREXD_INST; \ | 3780 | case 187: goto STREXD_INST; \ |
| 3807 | case 188: goto STREXD_INST; \ | 3781 | case 188: goto LDREXH_INST; \ |
| 3808 | case 189: goto LDREXH_INST; \ | 3782 | case 189: goto STREXH_INST; \ |
| 3809 | case 190: goto STREXH_INST; \ | 3783 | case 190: goto NOP_INST; \ |
| 3810 | case 191: goto NOP_INST; \ | 3784 | case 191: goto YIELD_INST; \ |
| 3811 | case 192: goto YIELD_INST; \ | 3785 | case 192: goto WFE_INST; \ |
| 3812 | case 193: goto WFE_INST; \ | 3786 | case 193: goto WFI_INST; \ |
| 3813 | case 194: goto WFI_INST; \ | 3787 | case 194: goto SEV_INST; \ |
| 3814 | case 195: goto SEV_INST; \ | 3788 | case 195: goto SWI_INST; \ |
| 3815 | case 196: goto SWI_INST; \ | 3789 | case 196: goto BBL_INST; \ |
| 3816 | case 197: goto BBL_INST; \ | 3790 | case 197: goto B_2_THUMB ; \ |
| 3817 | case 198: goto B_2_THUMB ; \ | 3791 | case 198: goto B_COND_THUMB ; \ |
| 3818 | case 199: goto B_COND_THUMB ; \ | 3792 | case 199: goto BL_1_THUMB ; \ |
| 3819 | case 200: goto BL_1_THUMB ; \ | 3793 | case 200: goto BL_2_THUMB ; \ |
| 3820 | case 201: goto BL_2_THUMB ; \ | 3794 | case 201: goto BLX_1_THUMB ; \ |
| 3821 | case 202: goto BLX_1_THUMB ; \ | 3795 | case 202: goto DISPATCH; \ |
| 3822 | case 203: goto DISPATCH; \ | 3796 | case 203: goto INIT_INST_LENGTH; \ |
| 3823 | case 204: goto INIT_INST_LENGTH; \ | 3797 | case 204: goto END; \ |
| 3824 | case 205: goto END; \ | ||
| 3825 | } | 3798 | } |
| 3826 | #endif | 3799 | #endif |
| 3827 | 3800 | ||
| @@ -3848,7 +3821,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 3848 | // to a clunky switch statement. | 3821 | // to a clunky switch statement. |
| 3849 | #if defined __GNUC__ || defined __clang__ | 3822 | #if defined __GNUC__ || defined __clang__ |
| 3850 | void *InstLabel[] = { | 3823 | void *InstLabel[] = { |
| 3851 | &&VMLA_INST, &&VMLS_INST, &&VNMLA_INST, &&VNMLA_INST, &&VNMLS_INST, &&VNMUL_INST, &&VMUL_INST, &&VADD_INST, &&VSUB_INST, | 3824 | &&VMLA_INST, &&VMLS_INST, &&VNMLA_INST, &&VNMLS_INST, &&VNMUL_INST, &&VMUL_INST, &&VADD_INST, &&VSUB_INST, |
| 3852 | &&VDIV_INST, &&VMOVI_INST, &&VMOVR_INST, &&VABS_INST, &&VNEG_INST, &&VSQRT_INST, &&VCMP_INST, &&VCMP2_INST, &&VCVTBDS_INST, | 3825 | &&VDIV_INST, &&VMOVI_INST, &&VMOVR_INST, &&VABS_INST, &&VNEG_INST, &&VSQRT_INST, &&VCMP_INST, &&VCMP2_INST, &&VCVTBDS_INST, |
| 3853 | &&VCVTBFF_INST, &&VCVTBFI_INST, &&VMOVBRS_INST, &&VMSR_INST, &&VMOVBRC_INST, &&VMRS_INST, &&VMOVBCR_INST, &&VMOVBRRSS_INST, | 3826 | &&VCVTBFF_INST, &&VCVTBFI_INST, &&VMOVBRS_INST, &&VMSR_INST, &&VMOVBRC_INST, &&VMRS_INST, &&VMOVBCR_INST, &&VMOVBRRSS_INST, |
| 3854 | &&VMOVBRRD_INST, &&VSTR_INST, &&VPUSH_INST, &&VSTM_INST, &&VPOP_INST, &&VLDR_INST, &&VLDM_INST, | 3827 | &&VMOVBRRD_INST, &&VSTR_INST, &&VPUSH_INST, &&VSTM_INST, &&VPOP_INST, &&VLDR_INST, &&VLDM_INST, |
| @@ -3903,6 +3876,11 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 3903 | goto END; | 3876 | goto END; |
| 3904 | } | 3877 | } |
| 3905 | 3878 | ||
| 3879 | // Find breakpoint if one exists within the block | ||
| 3880 | if (GDBStub::g_server_enabled && GDBStub::IsConnected()) { | ||
| 3881 | breakpoint_data = GDBStub::GetNextBreakpointFromAddress(cpu->Reg[15], GDBStub::BreakpointType::Execute); | ||
| 3882 | } | ||
| 3883 | |||
| 3906 | inst_base = (arm_inst *)&inst_buf[ptr]; | 3884 | inst_base = (arm_inst *)&inst_buf[ptr]; |
| 3907 | GOTO_NEXT_INST; | 3885 | GOTO_NEXT_INST; |
| 3908 | } | 3886 | } |
| @@ -4454,12 +4432,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4454 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | 4432 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; |
| 4455 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | 4433 | inst_cream->get_addr(cpu, inst_cream->inst, addr); |
| 4456 | 4434 | ||
| 4457 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = Memory::Read8(addr); | 4435 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = cpu->ReadMemory8(addr); |
| 4458 | |||
| 4459 | if (BITS(inst_cream->inst, 12, 15) == 15) { | ||
| 4460 | INC_PC(sizeof(ldst_inst)); | ||
| 4461 | goto DISPATCH; | ||
| 4462 | } | ||
| 4463 | } | 4436 | } |
| 4464 | cpu->Reg[15] += cpu->GetInstructionSize(); | 4437 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4465 | INC_PC(sizeof(ldst_inst)); | 4438 | INC_PC(sizeof(ldst_inst)); |
| @@ -4472,12 +4445,14 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4472 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | 4445 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; |
| 4473 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | 4446 | inst_cream->get_addr(cpu, inst_cream->inst, addr); |
| 4474 | 4447 | ||
| 4475 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = Memory::Read8(addr); | 4448 | const u32 dest_index = BITS(inst_cream->inst, 12, 15); |
| 4449 | const u32 previous_mode = cpu->Mode; | ||
| 4476 | 4450 | ||
| 4477 | if (BITS(inst_cream->inst, 12, 15) == 15) { | 4451 | cpu->ChangePrivilegeMode(USER32MODE); |
| 4478 | INC_PC(sizeof(ldst_inst)); | 4452 | const u8 value = cpu->ReadMemory8(addr); |
| 4479 | goto DISPATCH; | 4453 | cpu->ChangePrivilegeMode(previous_mode); |
| 4480 | } | 4454 | |
| 4455 | cpu->Reg[dest_index] = value; | ||
| 4481 | } | 4456 | } |
| 4482 | cpu->Reg[15] += cpu->GetInstructionSize(); | 4457 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4483 | INC_PC(sizeof(ldst_inst)); | 4458 | INC_PC(sizeof(ldst_inst)); |
| @@ -4513,10 +4488,6 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4513 | cpu->SetExclusiveMemoryAddress(read_addr); | 4488 | cpu->SetExclusiveMemoryAddress(read_addr); |
| 4514 | 4489 | ||
| 4515 | RD = cpu->ReadMemory32(read_addr); | 4490 | RD = cpu->ReadMemory32(read_addr); |
| 4516 | if (inst_cream->Rd == 15) { | ||
| 4517 | INC_PC(sizeof(generic_arm_inst)); | ||
| 4518 | goto DISPATCH; | ||
| 4519 | } | ||
| 4520 | } | 4491 | } |
| 4521 | cpu->Reg[15] += cpu->GetInstructionSize(); | 4492 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4522 | INC_PC(sizeof(generic_arm_inst)); | 4493 | INC_PC(sizeof(generic_arm_inst)); |
| @@ -4531,11 +4502,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4531 | 4502 | ||
| 4532 | cpu->SetExclusiveMemoryAddress(read_addr); | 4503 | cpu->SetExclusiveMemoryAddress(read_addr); |
| 4533 | 4504 | ||
| 4534 | RD = Memory::Read8(read_addr); | 4505 | RD = cpu->ReadMemory8(read_addr); |
| 4535 | if (inst_cream->Rd == 15) { | ||
| 4536 | INC_PC(sizeof(generic_arm_inst)); | ||
| 4537 | goto DISPATCH; | ||
| 4538 | } | ||
| 4539 | } | 4506 | } |
| 4540 | cpu->Reg[15] += cpu->GetInstructionSize(); | 4507 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4541 | INC_PC(sizeof(generic_arm_inst)); | 4508 | INC_PC(sizeof(generic_arm_inst)); |
| @@ -4551,10 +4518,6 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4551 | cpu->SetExclusiveMemoryAddress(read_addr); | 4518 | cpu->SetExclusiveMemoryAddress(read_addr); |
| 4552 | 4519 | ||
| 4553 | RD = cpu->ReadMemory16(read_addr); | 4520 | RD = cpu->ReadMemory16(read_addr); |
| 4554 | if (inst_cream->Rd == 15) { | ||
| 4555 | INC_PC(sizeof(generic_arm_inst)); | ||
| 4556 | goto DISPATCH; | ||
| 4557 | } | ||
| 4558 | } | 4521 | } |
| 4559 | cpu->Reg[15] += cpu->GetInstructionSize(); | 4522 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4560 | INC_PC(sizeof(generic_arm_inst)); | 4523 | INC_PC(sizeof(generic_arm_inst)); |
| @@ -4571,11 +4534,6 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4571 | 4534 | ||
| 4572 | RD = cpu->ReadMemory32(read_addr); | 4535 | RD = cpu->ReadMemory32(read_addr); |
| 4573 | RD2 = cpu->ReadMemory32(read_addr + 4); | 4536 | RD2 = cpu->ReadMemory32(read_addr + 4); |
| 4574 | |||
| 4575 | if (inst_cream->Rd == 15) { | ||
| 4576 | INC_PC(sizeof(generic_arm_inst)); | ||
| 4577 | goto DISPATCH; | ||
| 4578 | } | ||
| 4579 | } | 4537 | } |
| 4580 | cpu->Reg[15] += cpu->GetInstructionSize(); | 4538 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4581 | INC_PC(sizeof(generic_arm_inst)); | 4539 | INC_PC(sizeof(generic_arm_inst)); |
| @@ -4589,10 +4547,6 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4589 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | 4547 | inst_cream->get_addr(cpu, inst_cream->inst, addr); |
| 4590 | 4548 | ||
| 4591 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = cpu->ReadMemory16(addr); | 4549 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = cpu->ReadMemory16(addr); |
| 4592 | if (BITS(inst_cream->inst, 12, 15) == 15) { | ||
| 4593 | INC_PC(sizeof(ldst_inst)); | ||
| 4594 | goto DISPATCH; | ||
| 4595 | } | ||
| 4596 | } | 4550 | } |
| 4597 | cpu->Reg[15] += cpu->GetInstructionSize(); | 4551 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4598 | INC_PC(sizeof(ldst_inst)); | 4552 | INC_PC(sizeof(ldst_inst)); |
| @@ -4604,15 +4558,11 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4604 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | 4558 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { |
| 4605 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | 4559 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; |
| 4606 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | 4560 | inst_cream->get_addr(cpu, inst_cream->inst, addr); |
| 4607 | unsigned int value = Memory::Read8(addr); | 4561 | unsigned int value = cpu->ReadMemory8(addr); |
| 4608 | if (BIT(value, 7)) { | 4562 | if (BIT(value, 7)) { |
| 4609 | value |= 0xffffff00; | 4563 | value |= 0xffffff00; |
| 4610 | } | 4564 | } |
| 4611 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | 4565 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; |
| 4612 | if (BITS(inst_cream->inst, 12, 15) == 15) { | ||
| 4613 | INC_PC(sizeof(ldst_inst)); | ||
| 4614 | goto DISPATCH; | ||
| 4615 | } | ||
| 4616 | } | 4566 | } |
| 4617 | cpu->Reg[15] += cpu->GetInstructionSize(); | 4567 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4618 | INC_PC(sizeof(ldst_inst)); | 4568 | INC_PC(sizeof(ldst_inst)); |
| @@ -4630,10 +4580,6 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4630 | value |= 0xffff0000; | 4580 | value |= 0xffff0000; |
| 4631 | } | 4581 | } |
| 4632 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | 4582 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; |
| 4633 | if (BITS(inst_cream->inst, 12, 15) == 15) { | ||
| 4634 | INC_PC(sizeof(ldst_inst)); | ||
| 4635 | goto DISPATCH; | ||
| 4636 | } | ||
| 4637 | } | 4583 | } |
| 4638 | cpu->Reg[15] += cpu->GetInstructionSize(); | 4584 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4639 | INC_PC(sizeof(ldst_inst)); | 4585 | INC_PC(sizeof(ldst_inst)); |
| @@ -4646,13 +4592,14 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4646 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | 4592 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; |
| 4647 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | 4593 | inst_cream->get_addr(cpu, inst_cream->inst, addr); |
| 4648 | 4594 | ||
| 4649 | unsigned int value = cpu->ReadMemory32(addr); | 4595 | const u32 dest_index = BITS(inst_cream->inst, 12, 15); |
| 4650 | cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; | 4596 | const u32 previous_mode = cpu->Mode; |
| 4651 | 4597 | ||
| 4652 | if (BITS(inst_cream->inst, 12, 15) == 15) { | 4598 | cpu->ChangePrivilegeMode(USER32MODE); |
| 4653 | INC_PC(sizeof(ldst_inst)); | 4599 | const u32 value = cpu->ReadMemory32(addr); |
| 4654 | goto DISPATCH; | 4600 | cpu->ChangePrivilegeMode(previous_mode); |
| 4655 | } | 4601 | |
| 4602 | cpu->Reg[dest_index] = value; | ||
| 4656 | } | 4603 | } |
| 4657 | cpu->Reg[15] += cpu->GetInstructionSize(); | 4604 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4658 | INC_PC(sizeof(ldst_inst)); | 4605 | INC_PC(sizeof(ldst_inst)); |
| @@ -4709,10 +4656,6 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4709 | UPDATE_NFLAG(RD); | 4656 | UPDATE_NFLAG(RD); |
| 4710 | UPDATE_ZFLAG(RD); | 4657 | UPDATE_ZFLAG(RD); |
| 4711 | } | 4658 | } |
| 4712 | if (inst_cream->Rd == 15) { | ||
| 4713 | INC_PC(sizeof(mla_inst)); | ||
| 4714 | goto DISPATCH; | ||
| 4715 | } | ||
| 4716 | } | 4659 | } |
| 4717 | cpu->Reg[15] += cpu->GetInstructionSize(); | 4660 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4718 | INC_PC(sizeof(mla_inst)); | 4661 | INC_PC(sizeof(mla_inst)); |
| @@ -4751,18 +4694,15 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4751 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | 4694 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { |
| 4752 | mrc_inst* inst_cream = (mrc_inst*)inst_base->component; | 4695 | mrc_inst* inst_cream = (mrc_inst*)inst_base->component; |
| 4753 | 4696 | ||
| 4754 | unsigned int inst = inst_cream->inst; | 4697 | if (inst_cream->cp_num == 15) { |
| 4755 | if (inst_cream->Rd == 15) { | 4698 | const uint32_t value = cpu->ReadCP15Register(CRn, OPCODE_1, CRm, OPCODE_2); |
| 4756 | DEBUG_MSG; | 4699 | |
| 4757 | } | 4700 | if (inst_cream->Rd == 15) { |
| 4758 | if (inst_cream->inst == 0xeef04a10) { | 4701 | cpu->Cpsr = (cpu->Cpsr & ~0xF0000000) | (value & 0xF0000000); |
| 4759 | // Undefined instruction fmrx | 4702 | LOAD_NZCVT; |
| 4760 | RD = 0x20000000; | 4703 | } else { |
| 4761 | CITRA_IGNORE_EXIT(-1); | 4704 | RD = value; |
| 4762 | goto END; | 4705 | } |
| 4763 | } else { | ||
| 4764 | if (inst_cream->cp_num == 15) | ||
| 4765 | RD = cpu->ReadCP15Register(CRn, OPCODE_1, CRm, OPCODE_2); | ||
| 4766 | } | 4706 | } |
| 4767 | } | 4707 | } |
| 4768 | cpu->Reg[15] += cpu->GetInstructionSize(); | 4708 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| @@ -4861,10 +4801,6 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 4861 | UPDATE_NFLAG(RD); | 4801 | UPDATE_NFLAG(RD); |
| 4862 | UPDATE_ZFLAG(RD); | 4802 | UPDATE_ZFLAG(RD); |
| 4863 | } | 4803 | } |
| 4864 | if (inst_cream->Rd == 15) { | ||
| 4865 | INC_PC(sizeof(mul_inst)); | ||
| 4866 | goto DISPATCH; | ||
| 4867 | } | ||
| 4868 | } | 4804 | } |
| 4869 | cpu->Reg[15] += cpu->GetInstructionSize(); | 4805 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 4870 | INC_PC(sizeof(mul_inst)); | 4806 | INC_PC(sizeof(mul_inst)); |
| @@ -6027,7 +5963,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6027 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | 5963 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; |
| 6028 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | 5964 | inst_cream->get_addr(cpu, inst_cream->inst, addr); |
| 6029 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; | 5965 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; |
| 6030 | Memory::Write8(addr, value); | 5966 | cpu->WriteMemory8(addr, value); |
| 6031 | } | 5967 | } |
| 6032 | cpu->Reg[15] += cpu->GetInstructionSize(); | 5968 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6033 | INC_PC(sizeof(ldst_inst)); | 5969 | INC_PC(sizeof(ldst_inst)); |
| @@ -6039,8 +5975,13 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6039 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | 5975 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { |
| 6040 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | 5976 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; |
| 6041 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | 5977 | inst_cream->get_addr(cpu, inst_cream->inst, addr); |
| 6042 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; | 5978 | |
| 6043 | Memory::Write8(addr, value); | 5979 | const u32 previous_mode = cpu->Mode; |
| 5980 | const u32 value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; | ||
| 5981 | |||
| 5982 | cpu->ChangePrivilegeMode(USER32MODE); | ||
| 5983 | cpu->WriteMemory8(addr, value); | ||
| 5984 | cpu->ChangePrivilegeMode(previous_mode); | ||
| 6044 | } | 5985 | } |
| 6045 | cpu->Reg[15] += cpu->GetInstructionSize(); | 5986 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6046 | INC_PC(sizeof(ldst_inst)); | 5987 | INC_PC(sizeof(ldst_inst)); |
| @@ -6091,7 +6032,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6091 | 6032 | ||
| 6092 | if (cpu->IsExclusiveMemoryAccess(write_addr)) { | 6033 | if (cpu->IsExclusiveMemoryAccess(write_addr)) { |
| 6093 | cpu->UnsetExclusiveMemoryAddress(); | 6034 | cpu->UnsetExclusiveMemoryAddress(); |
| 6094 | Memory::Write8(write_addr, cpu->Reg[inst_cream->Rm]); | 6035 | cpu->WriteMemory8(write_addr, cpu->Reg[inst_cream->Rm]); |
| 6095 | RD = 0; | 6036 | RD = 0; |
| 6096 | } else { | 6037 | } else { |
| 6097 | // Failed to write due to mutex access | 6038 | // Failed to write due to mutex access |
| @@ -6174,8 +6115,16 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6174 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; | 6115 | ldst_inst* inst_cream = (ldst_inst*)inst_base->component; |
| 6175 | inst_cream->get_addr(cpu, inst_cream->inst, addr); | 6116 | inst_cream->get_addr(cpu, inst_cream->inst, addr); |
| 6176 | 6117 | ||
| 6177 | unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; | 6118 | const u32 previous_mode = cpu->Mode; |
| 6119 | const u32 rt_index = BITS(inst_cream->inst, 12, 15); | ||
| 6120 | |||
| 6121 | u32 value = cpu->Reg[rt_index]; | ||
| 6122 | if (rt_index == 15) | ||
| 6123 | value += 2 * cpu->GetInstructionSize(); | ||
| 6124 | |||
| 6125 | cpu->ChangePrivilegeMode(USER32MODE); | ||
| 6178 | cpu->WriteMemory32(addr, value); | 6126 | cpu->WriteMemory32(addr, value); |
| 6127 | cpu->ChangePrivilegeMode(previous_mode); | ||
| 6179 | } | 6128 | } |
| 6180 | cpu->Reg[15] += cpu->GetInstructionSize(); | 6129 | cpu->Reg[15] += cpu->GetInstructionSize(); |
| 6181 | INC_PC(sizeof(ldst_inst)); | 6130 | INC_PC(sizeof(ldst_inst)); |
| @@ -6250,8 +6199,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { | |||
| 6250 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { | 6199 | if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) { |
| 6251 | swp_inst* inst_cream = (swp_inst*)inst_base->component; | 6200 | swp_inst* inst_cream = (swp_inst*)inst_base->component; |
| 6252 | addr = RN; | 6201 | addr = RN; |
| 6253 | unsigned int value = Memory::Read8(addr); | 6202 | unsigned int value = cpu->ReadMemory8(addr); |
| 6254 | Memory::Write8(addr, (RM & 0xFF)); | 6203 | cpu->WriteMemory8(addr, (RM & 0xFF)); |
| 6255 | RD = value; | 6204 | RD = value; |
| 6256 | } | 6205 | } |
| 6257 | cpu->Reg[15] += cpu->GetInstructionSize(); | 6206 | cpu->Reg[15] += cpu->GetInstructionSize(); |
diff --git a/src/core/arm/dyncom/arm_dyncom_run.h b/src/core/arm/dyncom/arm_dyncom_run.h index 13bef17fc..8eb694fee 100644 --- a/src/core/arm/dyncom/arm_dyncom_run.h +++ b/src/core/arm/dyncom/arm_dyncom_run.h | |||
| @@ -30,7 +30,7 @@ | |||
| 30 | * @return If the PC is being read, then the word-aligned PC value is returned. | 30 | * @return If the PC is being read, then the word-aligned PC value is returned. |
| 31 | * If the PC is not being read, then the value stored in the register is returned. | 31 | * If the PC is not being read, then the value stored in the register is returned. |
| 32 | */ | 32 | */ |
| 33 | static inline u32 CHECK_READ_REG15_WA(ARMul_State* cpu, int Rn) { | 33 | inline u32 CHECK_READ_REG15_WA(const ARMul_State* cpu, int Rn) { |
| 34 | return (Rn == 15) ? ((cpu->Reg[15] & ~0x3) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn]; | 34 | return (Rn == 15) ? ((cpu->Reg[15] & ~0x3) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn]; |
| 35 | } | 35 | } |
| 36 | 36 | ||
| @@ -43,6 +43,6 @@ static inline u32 CHECK_READ_REG15_WA(ARMul_State* cpu, int Rn) { | |||
| 43 | * @return If the PC is being read, then the incremented PC value is returned. | 43 | * @return If the PC is being read, then the incremented PC value is returned. |
| 44 | * If the PC is not being read, then the values stored in the register is returned. | 44 | * If the PC is not being read, then the values stored in the register is returned. |
| 45 | */ | 45 | */ |
| 46 | static inline u32 CHECK_READ_REG15(ARMul_State* cpu, int Rn) { | 46 | inline u32 CHECK_READ_REG15(const ARMul_State* cpu, int Rn) { |
| 47 | return (Rn == 15) ? ((cpu->Reg[15] & ~0x1) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn]; | 47 | return (Rn == 15) ? ((cpu->Reg[15] & ~0x1) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn]; |
| 48 | } | 48 | } |
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.h b/src/core/arm/dyncom/arm_dyncom_thumb.h index 447974363..c1be3c735 100644 --- a/src/core/arm/dyncom/arm_dyncom_thumb.h +++ b/src/core/arm/dyncom/arm_dyncom_thumb.h | |||
| @@ -38,7 +38,7 @@ enum class ThumbDecodeStatus { | |||
| 38 | // Translates a Thumb mode instruction into its ARM equivalent. | 38 | // Translates a Thumb mode instruction into its ARM equivalent. |
| 39 | ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size); | 39 | ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size); |
| 40 | 40 | ||
| 41 | static inline u32 GetThumbInstruction(u32 instr, u32 address) { | 41 | inline u32 GetThumbInstruction(u32 instr, u32 address) { |
| 42 | // Normally you would need to handle instruction endianness, | 42 | // Normally you would need to handle instruction endianness, |
| 43 | // however, it is fixed to little-endian on the MPCore, so | 43 | // however, it is fixed to little-endian on the MPCore, so |
| 44 | // there's no need to check for this beforehand. | 44 | // there's no need to check for this beforehand. |
diff --git a/src/core/arm/skyeye_common/armstate.cpp b/src/core/arm/skyeye_common/armstate.cpp index 0491717dc..2d814345a 100644 --- a/src/core/arm/skyeye_common/armstate.cpp +++ b/src/core/arm/skyeye_common/armstate.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "core/memory.h" | 7 | #include "core/memory.h" |
| 8 | #include "core/arm/skyeye_common/armstate.h" | 8 | #include "core/arm/skyeye_common/armstate.h" |
| 9 | #include "core/arm/skyeye_common/vfp/vfp.h" | 9 | #include "core/arm/skyeye_common/vfp/vfp.h" |
| 10 | #include "core/gdbstub/gdbstub.h" | ||
| 10 | 11 | ||
| 11 | ARMul_State::ARMul_State(PrivilegeMode initial_mode) | 12 | ARMul_State::ARMul_State(PrivilegeMode initial_mode) |
| 12 | { | 13 | { |
| @@ -185,8 +186,25 @@ void ARMul_State::ResetMPCoreCP15Registers() | |||
| 185 | CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000; | 186 | CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000; |
| 186 | } | 187 | } |
| 187 | 188 | ||
| 189 | static void CheckMemoryBreakpoint(u32 address, GDBStub::BreakpointType type) | ||
| 190 | { | ||
| 191 | if (GDBStub::g_server_enabled && GDBStub::CheckBreakpoint(address, type)) { | ||
| 192 | LOG_DEBUG(Debug, "Found memory breakpoint @ %08x", address); | ||
| 193 | GDBStub::Break(true); | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 197 | u8 ARMul_State::ReadMemory8(u32 address) const | ||
| 198 | { | ||
| 199 | CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); | ||
| 200 | |||
| 201 | return Memory::Read8(address); | ||
| 202 | } | ||
| 203 | |||
| 188 | u16 ARMul_State::ReadMemory16(u32 address) const | 204 | u16 ARMul_State::ReadMemory16(u32 address) const |
| 189 | { | 205 | { |
| 206 | CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); | ||
| 207 | |||
| 190 | u16 data = Memory::Read16(address); | 208 | u16 data = Memory::Read16(address); |
| 191 | 209 | ||
| 192 | if (InBigEndianMode()) | 210 | if (InBigEndianMode()) |
| @@ -197,6 +215,8 @@ u16 ARMul_State::ReadMemory16(u32 address) const | |||
| 197 | 215 | ||
| 198 | u32 ARMul_State::ReadMemory32(u32 address) const | 216 | u32 ARMul_State::ReadMemory32(u32 address) const |
| 199 | { | 217 | { |
| 218 | CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); | ||
| 219 | |||
| 200 | u32 data = Memory::Read32(address); | 220 | u32 data = Memory::Read32(address); |
| 201 | 221 | ||
| 202 | if (InBigEndianMode()) | 222 | if (InBigEndianMode()) |
| @@ -207,6 +227,8 @@ u32 ARMul_State::ReadMemory32(u32 address) const | |||
| 207 | 227 | ||
| 208 | u64 ARMul_State::ReadMemory64(u32 address) const | 228 | u64 ARMul_State::ReadMemory64(u32 address) const |
| 209 | { | 229 | { |
| 230 | CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read); | ||
| 231 | |||
| 210 | u64 data = Memory::Read64(address); | 232 | u64 data = Memory::Read64(address); |
| 211 | 233 | ||
| 212 | if (InBigEndianMode()) | 234 | if (InBigEndianMode()) |
| @@ -215,8 +237,17 @@ u64 ARMul_State::ReadMemory64(u32 address) const | |||
| 215 | return data; | 237 | return data; |
| 216 | } | 238 | } |
| 217 | 239 | ||
| 240 | void ARMul_State::WriteMemory8(u32 address, u8 data) | ||
| 241 | { | ||
| 242 | CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write); | ||
| 243 | |||
| 244 | Memory::Write8(address, data); | ||
| 245 | } | ||
| 246 | |||
| 218 | void ARMul_State::WriteMemory16(u32 address, u16 data) | 247 | void ARMul_State::WriteMemory16(u32 address, u16 data) |
| 219 | { | 248 | { |
| 249 | CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write); | ||
| 250 | |||
| 220 | if (InBigEndianMode()) | 251 | if (InBigEndianMode()) |
| 221 | data = Common::swap16(data); | 252 | data = Common::swap16(data); |
| 222 | 253 | ||
| @@ -225,6 +256,8 @@ void ARMul_State::WriteMemory16(u32 address, u16 data) | |||
| 225 | 256 | ||
| 226 | void ARMul_State::WriteMemory32(u32 address, u32 data) | 257 | void ARMul_State::WriteMemory32(u32 address, u32 data) |
| 227 | { | 258 | { |
| 259 | CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write); | ||
| 260 | |||
| 228 | if (InBigEndianMode()) | 261 | if (InBigEndianMode()) |
| 229 | data = Common::swap32(data); | 262 | data = Common::swap32(data); |
| 230 | 263 | ||
| @@ -233,6 +266,8 @@ void ARMul_State::WriteMemory32(u32 address, u32 data) | |||
| 233 | 266 | ||
| 234 | void ARMul_State::WriteMemory64(u32 address, u64 data) | 267 | void ARMul_State::WriteMemory64(u32 address, u64 data) |
| 235 | { | 268 | { |
| 269 | CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write); | ||
| 270 | |||
| 236 | if (InBigEndianMode()) | 271 | if (InBigEndianMode()) |
| 237 | data = Common::swap64(data); | 272 | data = Common::swap64(data); |
| 238 | 273 | ||
diff --git a/src/core/arm/skyeye_common/armstate.h b/src/core/arm/skyeye_common/armstate.h index ceb159d14..d42ff2669 100644 --- a/src/core/arm/skyeye_common/armstate.h +++ b/src/core/arm/skyeye_common/armstate.h | |||
| @@ -153,9 +153,11 @@ public: | |||
| 153 | 153 | ||
| 154 | // Reads/writes data in big/little endian format based on the | 154 | // Reads/writes data in big/little endian format based on the |
| 155 | // state of the E (endian) bit in the APSR. | 155 | // state of the E (endian) bit in the APSR. |
| 156 | u8 ReadMemory8(u32 address) const; | ||
| 156 | u16 ReadMemory16(u32 address) const; | 157 | u16 ReadMemory16(u32 address) const; |
| 157 | u32 ReadMemory32(u32 address) const; | 158 | u32 ReadMemory32(u32 address) const; |
| 158 | u64 ReadMemory64(u32 address) const; | 159 | u64 ReadMemory64(u32 address) const; |
| 160 | void WriteMemory8(u32 address, u8 data); | ||
| 159 | void WriteMemory16(u32 address, u16 data); | 161 | void WriteMemory16(u32 address, u16 data); |
| 160 | void WriteMemory32(u32 address, u32 data); | 162 | void WriteMemory32(u32 address, u32 data); |
| 161 | void WriteMemory64(u32 address, u64 data); | 163 | void WriteMemory64(u32 address, u64 data); |
| @@ -191,23 +193,23 @@ public: | |||
| 191 | return TFlag ? 2 : 4; | 193 | return TFlag ? 2 : 4; |
| 192 | } | 194 | } |
| 193 | 195 | ||
| 194 | std::array<u32, 16> Reg; // The current register file | 196 | std::array<u32, 16> Reg{}; // The current register file |
| 195 | std::array<u32, 2> Reg_usr; | 197 | std::array<u32, 2> Reg_usr{}; |
| 196 | std::array<u32, 2> Reg_svc; // R13_SVC R14_SVC | 198 | std::array<u32, 2> Reg_svc{}; // R13_SVC R14_SVC |
| 197 | std::array<u32, 2> Reg_abort; // R13_ABORT R14_ABORT | 199 | std::array<u32, 2> Reg_abort{}; // R13_ABORT R14_ABORT |
| 198 | std::array<u32, 2> Reg_undef; // R13 UNDEF R14 UNDEF | 200 | std::array<u32, 2> Reg_undef{}; // R13 UNDEF R14 UNDEF |
| 199 | std::array<u32, 2> Reg_irq; // R13_IRQ R14_IRQ | 201 | std::array<u32, 2> Reg_irq{}; // R13_IRQ R14_IRQ |
| 200 | std::array<u32, 7> Reg_firq; // R8---R14 FIRQ | 202 | std::array<u32, 7> Reg_firq{}; // R8---R14 FIRQ |
| 201 | std::array<u32, 7> Spsr; // The exception psr's | 203 | std::array<u32, 7> Spsr{}; // The exception psr's |
| 202 | std::array<u32, CP15_REGISTER_COUNT> CP15; | 204 | std::array<u32, CP15_REGISTER_COUNT> CP15{}; |
| 203 | 205 | ||
| 204 | // FPSID, FPSCR, and FPEXC | 206 | // FPSID, FPSCR, and FPEXC |
| 205 | std::array<u32, VFP_SYSTEM_REGISTER_COUNT> VFP; | 207 | std::array<u32, VFP_SYSTEM_REGISTER_COUNT> VFP{}; |
| 206 | 208 | ||
| 207 | // VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31). | 209 | // VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31). |
| 208 | // VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31), | 210 | // VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31), |
| 209 | // and only 32 singleword registers are accessible (S0-S31). | 211 | // and only 32 singleword registers are accessible (S0-S31). |
| 210 | std::array<u32, 64> ExtReg; | 212 | std::array<u32, 64> ExtReg{}; |
| 211 | 213 | ||
| 212 | u32 Emulate; // To start and stop emulation | 214 | u32 Emulate; // To start and stop emulation |
| 213 | u32 Cpsr; // The current PSR | 215 | u32 Cpsr; // The current PSR |
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp index 0537135e2..a27a7e194 100644 --- a/src/core/arm/skyeye_common/vfp/vfp.cpp +++ b/src/core/arm/skyeye_common/vfp/vfp.cpp | |||
| @@ -113,26 +113,26 @@ void VMOVR(ARMul_State* state, u32 single, u32 d, u32 m) | |||
| 113 | /* Miscellaneous functions */ | 113 | /* Miscellaneous functions */ |
| 114 | s32 vfp_get_float(ARMul_State* state, unsigned int reg) | 114 | s32 vfp_get_float(ARMul_State* state, unsigned int reg) |
| 115 | { | 115 | { |
| 116 | LOG_TRACE(Core_ARM11, "VFP get float: s%d=[%08x]\n", reg, state->ExtReg[reg]); | 116 | LOG_TRACE(Core_ARM11, "VFP get float: s%d=[%08x]", reg, state->ExtReg[reg]); |
| 117 | return state->ExtReg[reg]; | 117 | return state->ExtReg[reg]; |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | void vfp_put_float(ARMul_State* state, s32 val, unsigned int reg) | 120 | void vfp_put_float(ARMul_State* state, s32 val, unsigned int reg) |
| 121 | { | 121 | { |
| 122 | LOG_TRACE(Core_ARM11, "VFP put float: s%d <= [%08x]\n", reg, val); | 122 | LOG_TRACE(Core_ARM11, "VFP put float: s%d <= [%08x]", reg, val); |
| 123 | state->ExtReg[reg] = val; | 123 | state->ExtReg[reg] = val; |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | u64 vfp_get_double(ARMul_State* state, unsigned int reg) | 126 | u64 vfp_get_double(ARMul_State* state, unsigned int reg) |
| 127 | { | 127 | { |
| 128 | u64 result = ((u64) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2]; | 128 | u64 result = ((u64) state->ExtReg[reg*2+1])<<32 | state->ExtReg[reg*2]; |
| 129 | LOG_TRACE(Core_ARM11, "VFP get double: s[%d-%d]=[%016llx]\n", reg * 2 + 1, reg * 2, result); | 129 | LOG_TRACE(Core_ARM11, "VFP get double: s[%d-%d]=[%016llx]", reg * 2 + 1, reg * 2, result); |
| 130 | return result; | 130 | return result; |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | void vfp_put_double(ARMul_State* state, u64 val, unsigned int reg) | 133 | void vfp_put_double(ARMul_State* state, u64 val, unsigned int reg) |
| 134 | { | 134 | { |
| 135 | LOG_TRACE(Core_ARM11, "VFP put double: s[%d-%d] <= [%08x-%08x]\n", reg * 2 + 1, reg * 2, (u32)(val >> 32), (u32)(val & 0xffffffff)); | 135 | LOG_TRACE(Core_ARM11, "VFP put double: s[%d-%d] <= [%08x-%08x]", reg * 2 + 1, reg * 2, (u32)(val >> 32), (u32)(val & 0xffffffff)); |
| 136 | state->ExtReg[reg*2] = (u32) (val & 0xffffffff); | 136 | state->ExtReg[reg*2] = (u32) (val & 0xffffffff); |
| 137 | state->ExtReg[reg*2+1] = (u32) (val>>32); | 137 | state->ExtReg[reg*2+1] = (u32) (val>>32); |
| 138 | } | 138 | } |
| @@ -142,10 +142,10 @@ void vfp_put_double(ARMul_State* state, u64 val, unsigned int reg) | |||
| 142 | */ | 142 | */ |
| 143 | void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) | 143 | void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) |
| 144 | { | 144 | { |
| 145 | LOG_TRACE(Core_ARM11, "VFP: raising exceptions %08x\n", exceptions); | 145 | LOG_TRACE(Core_ARM11, "VFP: raising exceptions %08x", exceptions); |
| 146 | 146 | ||
| 147 | if (exceptions == VFP_EXCEPTION_ERROR) { | 147 | if (exceptions == VFP_EXCEPTION_ERROR) { |
| 148 | LOG_CRITICAL(Core_ARM11, "unhandled bounce %x\n", inst); | 148 | LOG_CRITICAL(Core_ARM11, "unhandled bounce %x", inst); |
| 149 | Crash(); | 149 | Crash(); |
| 150 | } | 150 | } |
| 151 | 151 | ||
diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h index 88908da9f..60a63e6de 100644 --- a/src/core/arm/skyeye_common/vfp/vfp.h +++ b/src/core/arm/skyeye_common/vfp/vfp.h | |||
| @@ -22,7 +22,7 @@ | |||
| 22 | 22 | ||
| 23 | #include "core/arm/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */ | 23 | #include "core/arm/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */ |
| 24 | 24 | ||
| 25 | #define VFP_DEBUG_UNTESTED(x) LOG_TRACE(Core_ARM11, "in func %s, " #x " untested\n", __FUNCTION__); | 25 | #define VFP_DEBUG_UNTESTED(x) LOG_TRACE(Core_ARM11, "in func %s, " #x " untested", __FUNCTION__); |
| 26 | #define CHECK_VFP_ENABLED | 26 | #define CHECK_VFP_ENABLED |
| 27 | #define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]); | 27 | #define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]); |
| 28 | 28 | ||
diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h index 91a8d4d57..210972917 100644 --- a/src/core/arm/skyeye_common/vfp/vfp_helper.h +++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h | |||
| @@ -85,7 +85,7 @@ enum : u32 { | |||
| 85 | 85 | ||
| 86 | #define vfp_single(inst) (((inst) & 0x0000f00) == 0xa00) | 86 | #define vfp_single(inst) (((inst) & 0x0000f00) == 0xa00) |
| 87 | 87 | ||
| 88 | static inline u32 vfp_shiftright32jamming(u32 val, unsigned int shift) | 88 | inline u32 vfp_shiftright32jamming(u32 val, unsigned int shift) |
| 89 | { | 89 | { |
| 90 | if (shift) { | 90 | if (shift) { |
| 91 | if (shift < 32) | 91 | if (shift < 32) |
| @@ -96,7 +96,7 @@ static inline u32 vfp_shiftright32jamming(u32 val, unsigned int shift) | |||
| 96 | return val; | 96 | return val; |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | static inline u64 vfp_shiftright64jamming(u64 val, unsigned int shift) | 99 | inline u64 vfp_shiftright64jamming(u64 val, unsigned int shift) |
| 100 | { | 100 | { |
| 101 | if (shift) { | 101 | if (shift) { |
| 102 | if (shift < 64) | 102 | if (shift < 64) |
| @@ -107,7 +107,7 @@ static inline u64 vfp_shiftright64jamming(u64 val, unsigned int shift) | |||
| 107 | return val; | 107 | return val; |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | static inline u32 vfp_hi64to32jamming(u64 val) | 110 | inline u32 vfp_hi64to32jamming(u64 val) |
| 111 | { | 111 | { |
| 112 | u32 v; | 112 | u32 v; |
| 113 | u32 highval = val >> 32; | 113 | u32 highval = val >> 32; |
| @@ -121,7 +121,7 @@ static inline u32 vfp_hi64to32jamming(u64 val) | |||
| 121 | return v; | 121 | return v; |
| 122 | } | 122 | } |
| 123 | 123 | ||
| 124 | static inline void add128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) | 124 | inline void add128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) |
| 125 | { | 125 | { |
| 126 | *resl = nl + ml; | 126 | *resl = nl + ml; |
| 127 | *resh = nh + mh; | 127 | *resh = nh + mh; |
| @@ -129,7 +129,7 @@ static inline void add128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) | |||
| 129 | *resh += 1; | 129 | *resh += 1; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | static inline void sub128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) | 132 | inline void sub128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) |
| 133 | { | 133 | { |
| 134 | *resl = nl - ml; | 134 | *resl = nl - ml; |
| 135 | *resh = nh - mh; | 135 | *resh = nh - mh; |
| @@ -137,7 +137,7 @@ static inline void sub128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) | |||
| 137 | *resh -= 1; | 137 | *resh -= 1; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | static inline void mul64to128(u64* resh, u64* resl, u64 n, u64 m) | 140 | inline void mul64to128(u64* resh, u64* resl, u64 n, u64 m) |
| 141 | { | 141 | { |
| 142 | u32 nh, nl, mh, ml; | 142 | u32 nh, nl, mh, ml; |
| 143 | u64 rh, rma, rmb, rl; | 143 | u64 rh, rma, rmb, rl; |
| @@ -164,20 +164,20 @@ static inline void mul64to128(u64* resh, u64* resl, u64 n, u64 m) | |||
| 164 | *resh = rh; | 164 | *resh = rh; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | static inline void shift64left(u64* resh, u64* resl, u64 n) | 167 | inline void shift64left(u64* resh, u64* resl, u64 n) |
| 168 | { | 168 | { |
| 169 | *resh = n >> 63; | 169 | *resh = n >> 63; |
| 170 | *resl = n << 1; | 170 | *resl = n << 1; |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | static inline u64 vfp_hi64multiply64(u64 n, u64 m) | 173 | inline u64 vfp_hi64multiply64(u64 n, u64 m) |
| 174 | { | 174 | { |
| 175 | u64 rh, rl; | 175 | u64 rh, rl; |
| 176 | mul64to128(&rh, &rl, n, m); | 176 | mul64to128(&rh, &rl, n, m); |
| 177 | return rh | (rl != 0); | 177 | return rh | (rl != 0); |
| 178 | } | 178 | } |
| 179 | 179 | ||
| 180 | static inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m) | 180 | inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m) |
| 181 | { | 181 | { |
| 182 | u64 mh, ml, remh, reml, termh, terml, z; | 182 | u64 mh, ml, remh, reml, termh, terml, z; |
| 183 | 183 | ||
| @@ -249,7 +249,7 @@ enum : u32 { | |||
| 249 | VFP_SNAN = (VFP_NAN|VFP_NAN_SIGNAL) | 249 | VFP_SNAN = (VFP_NAN|VFP_NAN_SIGNAL) |
| 250 | }; | 250 | }; |
| 251 | 251 | ||
| 252 | static inline int vfp_single_type(vfp_single* s) | 252 | inline int vfp_single_type(const vfp_single* s) |
| 253 | { | 253 | { |
| 254 | int type = VFP_NUMBER; | 254 | int type = VFP_NUMBER; |
| 255 | if (s->exponent == 255) { | 255 | if (s->exponent == 255) { |
| @@ -271,7 +271,7 @@ static inline int vfp_single_type(vfp_single* s) | |||
| 271 | // Unpack a single-precision float. Note that this returns the magnitude | 271 | // Unpack a single-precision float. Note that this returns the magnitude |
| 272 | // of the single-precision float mantissa with the 1. if necessary, | 272 | // of the single-precision float mantissa with the 1. if necessary, |
| 273 | // aligned to bit 30. | 273 | // aligned to bit 30. |
| 274 | static inline void vfp_single_unpack(vfp_single* s, s32 val, u32* fpscr) | 274 | inline void vfp_single_unpack(vfp_single* s, s32 val, u32* fpscr) |
| 275 | { | 275 | { |
| 276 | s->sign = vfp_single_packed_sign(val) >> 16, | 276 | s->sign = vfp_single_packed_sign(val) >> 16, |
| 277 | s->exponent = vfp_single_packed_exponent(val); | 277 | s->exponent = vfp_single_packed_exponent(val); |
| @@ -293,7 +293,7 @@ static inline void vfp_single_unpack(vfp_single* s, s32 val, u32* fpscr) | |||
| 293 | 293 | ||
| 294 | // Re-pack a single-precision float. This assumes that the float is | 294 | // Re-pack a single-precision float. This assumes that the float is |
| 295 | // already normalised such that the MSB is bit 30, _not_ bit 31. | 295 | // already normalised such that the MSB is bit 30, _not_ bit 31. |
| 296 | static inline s32 vfp_single_pack(vfp_single* s) | 296 | inline s32 vfp_single_pack(const vfp_single* s) |
| 297 | { | 297 | { |
| 298 | u32 val = (s->sign << 16) + | 298 | u32 val = (s->sign << 16) + |
| 299 | (s->exponent << VFP_SINGLE_MANTISSA_BITS) + | 299 | (s->exponent << VFP_SINGLE_MANTISSA_BITS) + |
| @@ -335,7 +335,7 @@ struct vfp_double { | |||
| 335 | #define vfp_double_packed_exponent(v) (((v) >> VFP_DOUBLE_MANTISSA_BITS) & ((1 << VFP_DOUBLE_EXPONENT_BITS) - 1)) | 335 | #define vfp_double_packed_exponent(v) (((v) >> VFP_DOUBLE_MANTISSA_BITS) & ((1 << VFP_DOUBLE_EXPONENT_BITS) - 1)) |
| 336 | #define vfp_double_packed_mantissa(v) ((v) & ((1ULL << VFP_DOUBLE_MANTISSA_BITS) - 1)) | 336 | #define vfp_double_packed_mantissa(v) ((v) & ((1ULL << VFP_DOUBLE_MANTISSA_BITS) - 1)) |
| 337 | 337 | ||
| 338 | static inline int vfp_double_type(vfp_double* s) | 338 | inline int vfp_double_type(const vfp_double* s) |
| 339 | { | 339 | { |
| 340 | int type = VFP_NUMBER; | 340 | int type = VFP_NUMBER; |
| 341 | if (s->exponent == 2047) { | 341 | if (s->exponent == 2047) { |
| @@ -357,7 +357,7 @@ static inline int vfp_double_type(vfp_double* s) | |||
| 357 | // Unpack a double-precision float. Note that this returns the magnitude | 357 | // Unpack a double-precision float. Note that this returns the magnitude |
| 358 | // of the double-precision float mantissa with the 1. if necessary, | 358 | // of the double-precision float mantissa with the 1. if necessary, |
| 359 | // aligned to bit 62. | 359 | // aligned to bit 62. |
| 360 | static inline void vfp_double_unpack(vfp_double* s, s64 val, u32* fpscr) | 360 | inline void vfp_double_unpack(vfp_double* s, s64 val, u32* fpscr) |
| 361 | { | 361 | { |
| 362 | s->sign = vfp_double_packed_sign(val) >> 48; | 362 | s->sign = vfp_double_packed_sign(val) >> 48; |
| 363 | s->exponent = vfp_double_packed_exponent(val); | 363 | s->exponent = vfp_double_packed_exponent(val); |
| @@ -379,7 +379,7 @@ static inline void vfp_double_unpack(vfp_double* s, s64 val, u32* fpscr) | |||
| 379 | 379 | ||
| 380 | // Re-pack a double-precision float. This assumes that the float is | 380 | // Re-pack a double-precision float. This assumes that the float is |
| 381 | // already normalised such that the MSB is bit 30, _not_ bit 31. | 381 | // already normalised such that the MSB is bit 30, _not_ bit 31. |
| 382 | static inline s64 vfp_double_pack(vfp_double* s) | 382 | inline s64 vfp_double_pack(const vfp_double* s) |
| 383 | { | 383 | { |
| 384 | u64 val = ((u64)s->sign << 48) + | 384 | u64 val = ((u64)s->sign << 48) + |
| 385 | ((u64)s->exponent << VFP_DOUBLE_MANTISSA_BITS) + | 385 | ((u64)s->exponent << VFP_DOUBLE_MANTISSA_BITS) + |
| @@ -415,7 +415,7 @@ struct op { | |||
| 415 | u32 flags; | 415 | u32 flags; |
| 416 | }; | 416 | }; |
| 417 | 417 | ||
| 418 | static inline u32 fls(u32 x) | 418 | inline u32 fls(u32 x) |
| 419 | { | 419 | { |
| 420 | int r = 32; | 420 | int r = 32; |
| 421 | 421 | ||
diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp index 857e6ce45..45914d479 100644 --- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp | |||
| @@ -65,7 +65,7 @@ static struct vfp_double vfp_double_default_qnan = { | |||
| 65 | 65 | ||
| 66 | static void vfp_double_dump(const char *str, struct vfp_double *d) | 66 | static void vfp_double_dump(const char *str, struct vfp_double *d) |
| 67 | { | 67 | { |
| 68 | LOG_TRACE(Core_ARM11, "VFP: %s: sign=%d exponent=%d significand=%016llx\n", | 68 | LOG_TRACE(Core_ARM11, "VFP: %s: sign=%d exponent=%d significand=%016llx", |
| 69 | str, d->sign != 0, d->exponent, d->significand); | 69 | str, d->sign != 0, d->exponent, d->significand); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| @@ -155,7 +155,7 @@ u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd, | |||
| 155 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) | 155 | } else if ((rmode == FPSCR_ROUND_PLUSINF) ^ (vd->sign != 0)) |
| 156 | incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; | 156 | incr = (1ULL << (VFP_DOUBLE_LOW_BITS + 1)) - 1; |
| 157 | 157 | ||
| 158 | LOG_TRACE(Core_ARM11, "VFP: rounding increment = 0x%08llx\n", incr); | 158 | LOG_TRACE(Core_ARM11, "VFP: rounding increment = 0x%08llx", incr); |
| 159 | 159 | ||
| 160 | /* | 160 | /* |
| 161 | * Is our rounding going to overflow? | 161 | * Is our rounding going to overflow? |
| @@ -210,7 +210,7 @@ pack: | |||
| 210 | vfp_double_dump("pack: final", vd); | 210 | vfp_double_dump("pack: final", vd); |
| 211 | { | 211 | { |
| 212 | s64 d = vfp_double_pack(vd); | 212 | s64 d = vfp_double_pack(vd); |
| 213 | LOG_TRACE(Core_ARM11, "VFP: %s: d(d%d)=%016llx exceptions=%08x\n", func, | 213 | LOG_TRACE(Core_ARM11, "VFP: %s: d(d%d)=%016llx exceptions=%08x", func, |
| 214 | dd, d, exceptions); | 214 | dd, d, exceptions); |
| 215 | vfp_put_double(state, d, dd); | 215 | vfp_put_double(state, d, dd); |
| 216 | } | 216 | } |
| @@ -267,28 +267,28 @@ vfp_propagate_nan(struct vfp_double *vdd, struct vfp_double *vdn, | |||
| 267 | */ | 267 | */ |
| 268 | static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 268 | static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 269 | { | 269 | { |
| 270 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 270 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 271 | vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd); | 271 | vfp_put_double(state, vfp_double_packed_abs(vfp_get_double(state, dm)), dd); |
| 272 | return 0; | 272 | return 0; |
| 273 | } | 273 | } |
| 274 | 274 | ||
| 275 | static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 275 | static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 276 | { | 276 | { |
| 277 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 277 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 278 | vfp_put_double(state, vfp_get_double(state, dm), dd); | 278 | vfp_put_double(state, vfp_get_double(state, dm), dd); |
| 279 | return 0; | 279 | return 0; |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 282 | static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 283 | { | 283 | { |
| 284 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 284 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 285 | vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd); | 285 | vfp_put_double(state, vfp_double_packed_negate(vfp_get_double(state, dm)), dd); |
| 286 | return 0; | 286 | return 0; |
| 287 | } | 287 | } |
| 288 | 288 | ||
| 289 | static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 289 | static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 290 | { | 290 | { |
| 291 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 291 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 292 | vfp_double vdm, vdd, *vdp; | 292 | vfp_double vdm, vdd, *vdp; |
| 293 | int ret, tm; | 293 | int ret, tm; |
| 294 | 294 | ||
| @@ -383,7 +383,7 @@ static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u | |||
| 383 | s64 d, m; | 383 | s64 d, m; |
| 384 | u32 ret = 0; | 384 | u32 ret = 0; |
| 385 | 385 | ||
| 386 | LOG_TRACE(Core_ARM11, "In %s, state=0x%p, fpscr=0x%x\n", __FUNCTION__, state, fpscr); | 386 | LOG_TRACE(Core_ARM11, "In %s, state=0x%p, fpscr=0x%x", __FUNCTION__, state, fpscr); |
| 387 | m = vfp_get_double(state, dm); | 387 | m = vfp_get_double(state, dm); |
| 388 | if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) { | 388 | if (vfp_double_packed_exponent(m) == 2047 && vfp_double_packed_mantissa(m)) { |
| 389 | ret |= FPSCR_CFLAG | FPSCR_VFLAG; | 389 | ret |= FPSCR_CFLAG | FPSCR_VFLAG; |
| @@ -438,32 +438,32 @@ static u32 vfp_compare(ARMul_State* state, int dd, int signal_on_qnan, int dm, u | |||
| 438 | ret |= FPSCR_CFLAG; | 438 | ret |= FPSCR_CFLAG; |
| 439 | } | 439 | } |
| 440 | } | 440 | } |
| 441 | LOG_TRACE(Core_ARM11, "In %s, state=0x%p, ret=0x%x\n", __FUNCTION__, state, ret); | 441 | LOG_TRACE(Core_ARM11, "In %s, state=0x%p, ret=0x%x", __FUNCTION__, state, ret); |
| 442 | 442 | ||
| 443 | return ret; | 443 | return ret; |
| 444 | } | 444 | } |
| 445 | 445 | ||
| 446 | static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 446 | static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 447 | { | 447 | { |
| 448 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 448 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 449 | return vfp_compare(state, dd, 0, dm, fpscr); | 449 | return vfp_compare(state, dd, 0, dm, fpscr); |
| 450 | } | 450 | } |
| 451 | 451 | ||
| 452 | static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 452 | static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 453 | { | 453 | { |
| 454 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 454 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 455 | return vfp_compare(state, dd, 1, dm, fpscr); | 455 | return vfp_compare(state, dd, 1, dm, fpscr); |
| 456 | } | 456 | } |
| 457 | 457 | ||
| 458 | static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 458 | static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 459 | { | 459 | { |
| 460 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 460 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 461 | return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr); | 461 | return vfp_compare(state, dd, 0, VFP_REG_ZERO, fpscr); |
| 462 | } | 462 | } |
| 463 | 463 | ||
| 464 | static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 464 | static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 465 | { | 465 | { |
| 466 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 466 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 467 | return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr); | 467 | return vfp_compare(state, dd, 1, VFP_REG_ZERO, fpscr); |
| 468 | } | 468 | } |
| 469 | 469 | ||
| @@ -474,7 +474,7 @@ static u32 vfp_double_fcvts(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 474 | int tm; | 474 | int tm; |
| 475 | u32 exceptions = 0; | 475 | u32 exceptions = 0; |
| 476 | 476 | ||
| 477 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 477 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 478 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 478 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); |
| 479 | 479 | ||
| 480 | tm = vfp_double_type(&vdm); | 480 | tm = vfp_double_type(&vdm); |
| @@ -516,7 +516,7 @@ static u32 vfp_double_fuito(ARMul_State* state, int dd, int unused, int dm, u32 | |||
| 516 | struct vfp_double vdm; | 516 | struct vfp_double vdm; |
| 517 | u32 m = vfp_get_float(state, dm); | 517 | u32 m = vfp_get_float(state, dm); |
| 518 | 518 | ||
| 519 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 519 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 520 | vdm.sign = 0; | 520 | vdm.sign = 0; |
| 521 | vdm.exponent = 1023 + 63 - 1; | 521 | vdm.exponent = 1023 + 63 - 1; |
| 522 | vdm.significand = (u64)m; | 522 | vdm.significand = (u64)m; |
| @@ -529,7 +529,7 @@ static u32 vfp_double_fsito(ARMul_State* state, int dd, int unused, int dm, u32 | |||
| 529 | struct vfp_double vdm; | 529 | struct vfp_double vdm; |
| 530 | u32 m = vfp_get_float(state, dm); | 530 | u32 m = vfp_get_float(state, dm); |
| 531 | 531 | ||
| 532 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 532 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 533 | vdm.sign = (m & 0x80000000) >> 16; | 533 | vdm.sign = (m & 0x80000000) >> 16; |
| 534 | vdm.exponent = 1023 + 63 - 1; | 534 | vdm.exponent = 1023 + 63 - 1; |
| 535 | vdm.significand = vdm.sign ? (~m + 1) : m; | 535 | vdm.significand = vdm.sign ? (~m + 1) : m; |
| @@ -544,7 +544,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 544 | int rmode = fpscr & FPSCR_RMODE_MASK; | 544 | int rmode = fpscr & FPSCR_RMODE_MASK; |
| 545 | int tm; | 545 | int tm; |
| 546 | 546 | ||
| 547 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 547 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 548 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 548 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); |
| 549 | 549 | ||
| 550 | /* | 550 | /* |
| @@ -605,7 +605,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 605 | } | 605 | } |
| 606 | } | 606 | } |
| 607 | 607 | ||
| 608 | LOG_TRACE(Core_ARM11, "VFP: ftoui: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); | 608 | LOG_TRACE(Core_ARM11, "VFP: ftoui: d(s%d)=%08x exceptions=%08x", sd, d, exceptions); |
| 609 | 609 | ||
| 610 | vfp_put_float(state, d, sd); | 610 | vfp_put_float(state, d, sd); |
| 611 | 611 | ||
| @@ -614,7 +614,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 614 | 614 | ||
| 615 | static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) | 615 | static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) |
| 616 | { | 616 | { |
| 617 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 617 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 618 | return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO); | 618 | return vfp_double_ftoui(state, sd, unused, dm, FPSCR_ROUND_TOZERO); |
| 619 | } | 619 | } |
| 620 | 620 | ||
| @@ -625,7 +625,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 625 | int rmode = fpscr & FPSCR_RMODE_MASK; | 625 | int rmode = fpscr & FPSCR_RMODE_MASK; |
| 626 | int tm; | 626 | int tm; |
| 627 | 627 | ||
| 628 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 628 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 629 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 629 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); |
| 630 | vfp_double_dump("VDM", &vdm); | 630 | vfp_double_dump("VDM", &vdm); |
| 631 | 631 | ||
| @@ -682,7 +682,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 682 | } | 682 | } |
| 683 | } | 683 | } |
| 684 | 684 | ||
| 685 | LOG_TRACE(Core_ARM11, "VFP: ftosi: d(s%d)=%08x exceptions=%08x\n", sd, d, exceptions); | 685 | LOG_TRACE(Core_ARM11, "VFP: ftosi: d(s%d)=%08x exceptions=%08x", sd, d, exceptions); |
| 686 | 686 | ||
| 687 | vfp_put_float(state, (s32)d, sd); | 687 | vfp_put_float(state, (s32)d, sd); |
| 688 | 688 | ||
| @@ -691,7 +691,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32 | |||
| 691 | 691 | ||
| 692 | static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) | 692 | static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) |
| 693 | { | 693 | { |
| 694 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 694 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 695 | return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO); | 695 | return vfp_double_ftosi(state, dd, unused, dm, FPSCR_ROUND_TOZERO); |
| 696 | } | 696 | } |
| 697 | 697 | ||
| @@ -775,7 +775,7 @@ u32 vfp_double_add(struct vfp_double *vdd, struct vfp_double *vdn,struct vfp_dou | |||
| 775 | 775 | ||
| 776 | if (vdn->significand & (1ULL << 63) || | 776 | if (vdn->significand & (1ULL << 63) || |
| 777 | vdm->significand & (1ULL << 63)) { | 777 | vdm->significand & (1ULL << 63)) { |
| 778 | LOG_INFO(Core_ARM11, "VFP: bad FP values in %s\n", __func__); | 778 | LOG_INFO(Core_ARM11, "VFP: bad FP values in %s", __func__); |
| 779 | vfp_double_dump("VDN", vdn); | 779 | vfp_double_dump("VDN", vdn); |
| 780 | vfp_double_dump("VDM", vdm); | 780 | vfp_double_dump("VDM", vdm); |
| 781 | } | 781 | } |
| @@ -843,7 +843,7 @@ vfp_double_multiply(struct vfp_double *vdd, struct vfp_double *vdn, | |||
| 843 | */ | 843 | */ |
| 844 | if (vdn->exponent < vdm->exponent) { | 844 | if (vdn->exponent < vdm->exponent) { |
| 845 | std::swap(vdm, vdn); | 845 | std::swap(vdm, vdn); |
| 846 | LOG_TRACE(Core_ARM11, "VFP: swapping M <-> N\n"); | 846 | LOG_TRACE(Core_ARM11, "VFP: swapping M <-> N"); |
| 847 | } | 847 | } |
| 848 | 848 | ||
| 849 | vdd->sign = vdn->sign ^ vdm->sign; | 849 | vdd->sign = vdn->sign ^ vdm->sign; |
| @@ -927,7 +927,7 @@ vfp_double_multiply_accumulate(ARMul_State* state, int dd, int dn, int dm, u32 f | |||
| 927 | */ | 927 | */ |
| 928 | static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | 928 | static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) |
| 929 | { | 929 | { |
| 930 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 930 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 931 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac"); | 931 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, 0, "fmac"); |
| 932 | } | 932 | } |
| 933 | 933 | ||
| @@ -936,7 +936,7 @@ static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 936 | */ | 936 | */ |
| 937 | static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | 937 | static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) |
| 938 | { | 938 | { |
| 939 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 939 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 940 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac"); | 940 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_MULTIPLY, "fnmac"); |
| 941 | } | 941 | } |
| 942 | 942 | ||
| @@ -945,7 +945,7 @@ static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpsc | |||
| 945 | */ | 945 | */ |
| 946 | static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | 946 | static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) |
| 947 | { | 947 | { |
| 948 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 948 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 949 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc"); | 949 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT, "fmsc"); |
| 950 | } | 950 | } |
| 951 | 951 | ||
| @@ -954,7 +954,7 @@ static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 954 | */ | 954 | */ |
| 955 | static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) | 955 | static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) |
| 956 | { | 956 | { |
| 957 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 957 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 958 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); | 958 | return vfp_double_multiply_accumulate(state, dd, dn, dm, fpscr, NEG_SUBTRACT | NEG_MULTIPLY, "fnmsc"); |
| 959 | } | 959 | } |
| 960 | 960 | ||
| @@ -966,7 +966,7 @@ static u32 vfp_double_fmul(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 966 | struct vfp_double vdd, vdn, vdm; | 966 | struct vfp_double vdd, vdn, vdm; |
| 967 | u32 exceptions; | 967 | u32 exceptions; |
| 968 | 968 | ||
| 969 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 969 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 970 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); | 970 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); |
| 971 | if (vdn.exponent == 0 && vdn.significand) | 971 | if (vdn.exponent == 0 && vdn.significand) |
| 972 | vfp_double_normalise_denormal(&vdn); | 972 | vfp_double_normalise_denormal(&vdn); |
| @@ -987,7 +987,7 @@ static u32 vfp_double_fnmul(ARMul_State* state, int dd, int dn, int dm, u32 fpsc | |||
| 987 | struct vfp_double vdd, vdn, vdm; | 987 | struct vfp_double vdd, vdn, vdm; |
| 988 | u32 exceptions; | 988 | u32 exceptions; |
| 989 | 989 | ||
| 990 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 990 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 991 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); | 991 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); |
| 992 | if (vdn.exponent == 0 && vdn.significand) | 992 | if (vdn.exponent == 0 && vdn.significand) |
| 993 | vfp_double_normalise_denormal(&vdn); | 993 | vfp_double_normalise_denormal(&vdn); |
| @@ -1010,7 +1010,7 @@ static u32 vfp_double_fadd(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 1010 | struct vfp_double vdd, vdn, vdm; | 1010 | struct vfp_double vdd, vdn, vdm; |
| 1011 | u32 exceptions; | 1011 | u32 exceptions; |
| 1012 | 1012 | ||
| 1013 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 1013 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 1014 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); | 1014 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); |
| 1015 | if (vdn.exponent == 0 && vdn.significand) | 1015 | if (vdn.exponent == 0 && vdn.significand) |
| 1016 | vfp_double_normalise_denormal(&vdn); | 1016 | vfp_double_normalise_denormal(&vdn); |
| @@ -1032,7 +1032,7 @@ static u32 vfp_double_fsub(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 1032 | struct vfp_double vdd, vdn, vdm; | 1032 | struct vfp_double vdd, vdn, vdm; |
| 1033 | u32 exceptions; | 1033 | u32 exceptions; |
| 1034 | 1034 | ||
| 1035 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 1035 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 1036 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); | 1036 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); |
| 1037 | if (vdn.exponent == 0 && vdn.significand) | 1037 | if (vdn.exponent == 0 && vdn.significand) |
| 1038 | vfp_double_normalise_denormal(&vdn); | 1038 | vfp_double_normalise_denormal(&vdn); |
| @@ -1060,7 +1060,7 @@ static u32 vfp_double_fdiv(ARMul_State* state, int dd, int dn, int dm, u32 fpscr | |||
| 1060 | u32 exceptions = 0; | 1060 | u32 exceptions = 0; |
| 1061 | int tm, tn; | 1061 | int tm, tn; |
| 1062 | 1062 | ||
| 1063 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 1063 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 1064 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); | 1064 | vfp_double_unpack(&vdn, vfp_get_double(state, dn), &fpscr); |
| 1065 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); | 1065 | vfp_double_unpack(&vdm, vfp_get_double(state, dm), &fpscr); |
| 1066 | 1066 | ||
| @@ -1185,7 +1185,7 @@ u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) | |||
| 1185 | unsigned int vecitr, veclen, vecstride; | 1185 | unsigned int vecitr, veclen, vecstride; |
| 1186 | struct op *fop; | 1186 | struct op *fop; |
| 1187 | 1187 | ||
| 1188 | LOG_TRACE(Core_ARM11, "In %s\n", __FUNCTION__); | 1188 | LOG_TRACE(Core_ARM11, "In %s", __FUNCTION__); |
| 1189 | vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)); | 1189 | vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)); |
| 1190 | 1190 | ||
| 1191 | fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; | 1191 | fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)]; |
| @@ -1216,7 +1216,7 @@ u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) | |||
| 1216 | else | 1216 | else |
| 1217 | veclen = fpscr & FPSCR_LENGTH_MASK; | 1217 | veclen = fpscr & FPSCR_LENGTH_MASK; |
| 1218 | 1218 | ||
| 1219 | LOG_TRACE(Core_ARM11, "VFP: vecstride=%u veclen=%u\n", vecstride, | 1219 | LOG_TRACE(Core_ARM11, "VFP: vecstride=%u veclen=%u", vecstride, |
| 1220 | (veclen >> FPSCR_LENGTH_BIT) + 1); | 1220 | (veclen >> FPSCR_LENGTH_BIT) + 1); |
| 1221 | 1221 | ||
| 1222 | if (!fop->fn) { | 1222 | if (!fop->fn) { |
| @@ -1230,16 +1230,16 @@ u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr) | |||
| 1230 | 1230 | ||
| 1231 | type = (fop->flags & OP_SD) ? 's' : 'd'; | 1231 | type = (fop->flags & OP_SD) ? 's' : 'd'; |
| 1232 | if (op == FOP_EXT) | 1232 | if (op == FOP_EXT) |
| 1233 | LOG_TRACE(Core_ARM11, "VFP: itr%d (%c%u) = op[%u] (d%u)\n", | 1233 | LOG_TRACE(Core_ARM11, "VFP: itr%d (%c%u) = op[%u] (d%u)", |
| 1234 | vecitr >> FPSCR_LENGTH_BIT, | 1234 | vecitr >> FPSCR_LENGTH_BIT, |
| 1235 | type, dest, dn, dm); | 1235 | type, dest, dn, dm); |
| 1236 | else | 1236 | else |
| 1237 | LOG_TRACE(Core_ARM11, "VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n", | 1237 | LOG_TRACE(Core_ARM11, "VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)", |
| 1238 | vecitr >> FPSCR_LENGTH_BIT, | 1238 | vecitr >> FPSCR_LENGTH_BIT, |
| 1239 | type, dest, dn, FOP_TO_IDX(op), dm); | 1239 | type, dest, dn, FOP_TO_IDX(op), dm); |
| 1240 | 1240 | ||
| 1241 | except = fop->fn(state, dest, dn, dm, fpscr); | 1241 | except = fop->fn(state, dest, dn, dm, fpscr); |
| 1242 | LOG_TRACE(Core_ARM11, "VFP: itr%d: exceptions=%08x\n", | 1242 | LOG_TRACE(Core_ARM11, "VFP: itr%d: exceptions=%08x", |
| 1243 | vecitr >> FPSCR_LENGTH_BIT, except); | 1243 | vecitr >> FPSCR_LENGTH_BIT, except); |
| 1244 | 1244 | ||
| 1245 | exceptions |= except; | 1245 | exceptions |= except; |
diff --git a/src/core/core.cpp b/src/core/core.cpp index dddc16708..453c7162d 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -2,6 +2,9 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <memory> | ||
| 6 | |||
| 7 | #include "common/make_unique.h" | ||
| 5 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 6 | 9 | ||
| 7 | #include "core/core.h" | 10 | #include "core/core.h" |
| @@ -13,13 +16,30 @@ | |||
| 13 | #include "core/hle/kernel/thread.h" | 16 | #include "core/hle/kernel/thread.h" |
| 14 | #include "core/hw/hw.h" | 17 | #include "core/hw/hw.h" |
| 15 | 18 | ||
| 19 | #include "core/gdbstub/gdbstub.h" | ||
| 20 | |||
| 16 | namespace Core { | 21 | namespace Core { |
| 17 | 22 | ||
| 18 | ARM_Interface* g_app_core = nullptr; ///< ARM11 application core | 23 | std::unique_ptr<ARM_Interface> g_app_core; ///< ARM11 application core |
| 19 | ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core | 24 | std::unique_ptr<ARM_Interface> g_sys_core; ///< ARM11 system (OS) core |
| 20 | 25 | ||
| 21 | /// Run the core CPU loop | 26 | /// Run the core CPU loop |
| 22 | void RunLoop(int tight_loop) { | 27 | void RunLoop(int tight_loop) { |
| 28 | if (GDBStub::g_server_enabled) { | ||
| 29 | GDBStub::HandlePacket(); | ||
| 30 | |||
| 31 | // If the loop is halted and we want to step, use a tiny (1) number of instructions to execute. | ||
| 32 | // Otherwise get out of the loop function. | ||
| 33 | if (GDBStub::GetCpuHaltFlag()) { | ||
| 34 | if (GDBStub::GetCpuStepFlag()) { | ||
| 35 | GDBStub::SetCpuStepFlag(false); | ||
| 36 | tight_loop = 1; | ||
| 37 | } else { | ||
| 38 | return; | ||
| 39 | } | ||
| 40 | } | ||
| 41 | } | ||
| 42 | |||
| 23 | // If we don't have a currently active thread then don't execute instructions, | 43 | // If we don't have a currently active thread then don't execute instructions, |
| 24 | // instead advance to the next event and try to yield to the next thread | 44 | // instead advance to the next event and try to yield to the next thread |
| 25 | if (Kernel::GetCurrentThread() == nullptr) { | 45 | if (Kernel::GetCurrentThread() == nullptr) { |
| @@ -54,16 +74,16 @@ void Stop() { | |||
| 54 | 74 | ||
| 55 | /// Initialize the core | 75 | /// Initialize the core |
| 56 | int Init() { | 76 | int Init() { |
| 57 | g_sys_core = new ARM_DynCom(USER32MODE); | 77 | g_sys_core = Common::make_unique<ARM_DynCom>(USER32MODE); |
| 58 | g_app_core = new ARM_DynCom(USER32MODE); | 78 | g_app_core = Common::make_unique<ARM_DynCom>(USER32MODE); |
| 59 | 79 | ||
| 60 | LOG_DEBUG(Core, "Initialized OK"); | 80 | LOG_DEBUG(Core, "Initialized OK"); |
| 61 | return 0; | 81 | return 0; |
| 62 | } | 82 | } |
| 63 | 83 | ||
| 64 | void Shutdown() { | 84 | void Shutdown() { |
| 65 | delete g_app_core; | 85 | g_app_core.reset(); |
| 66 | delete g_sys_core; | 86 | g_sys_core.reset(); |
| 67 | 87 | ||
| 68 | LOG_DEBUG(Core, "Shutdown OK"); | 88 | LOG_DEBUG(Core, "Shutdown OK"); |
| 69 | } | 89 | } |
diff --git a/src/core/core.h b/src/core/core.h index 278f0f1cc..453e0a5f0 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | ||
| 7 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 8 | 9 | ||
| 9 | class ARM_Interface; | 10 | class ARM_Interface; |
| @@ -18,13 +19,13 @@ struct ThreadContext { | |||
| 18 | u32 lr; | 19 | u32 lr; |
| 19 | u32 pc; | 20 | u32 pc; |
| 20 | u32 cpsr; | 21 | u32 cpsr; |
| 21 | u32 fpu_registers[32]; | 22 | u32 fpu_registers[64]; |
| 22 | u32 fpscr; | 23 | u32 fpscr; |
| 23 | u32 fpexc; | 24 | u32 fpexc; |
| 24 | }; | 25 | }; |
| 25 | 26 | ||
| 26 | extern ARM_Interface* g_app_core; ///< ARM11 application core | 27 | extern std::unique_ptr<ARM_Interface> g_app_core; ///< ARM11 application core |
| 27 | extern ARM_Interface* g_sys_core; ///< ARM11 system (OS) core | 28 | extern std::unique_ptr<ARM_Interface> g_sys_core; ///< ARM11 system (OS) core |
| 28 | 29 | ||
| 29 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 30 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 30 | 31 | ||
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index c6a1be79d..e7a59a1ed 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h | |||
| @@ -131,6 +131,12 @@ public: | |||
| 131 | * @return Opened directory, or nullptr | 131 | * @return Opened directory, or nullptr |
| 132 | */ | 132 | */ |
| 133 | virtual std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const = 0; | 133 | virtual std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const = 0; |
| 134 | |||
| 135 | /** | ||
| 136 | * Get the free space | ||
| 137 | * @return The number of free bytes in the archive | ||
| 138 | */ | ||
| 139 | virtual u64 GetFreeBytes() const = 0; | ||
| 134 | }; | 140 | }; |
| 135 | 141 | ||
| 136 | class ArchiveFactory : NonCopyable { | 142 | class ArchiveFactory : NonCopyable { |
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp index e9ecd2b1c..0ba502200 100644 --- a/src/core/file_sys/disk_archive.cpp +++ b/src/core/file_sys/disk_archive.cpp | |||
| @@ -74,6 +74,11 @@ std::unique_ptr<DirectoryBackend> DiskArchive::OpenDirectory(const Path& path) c | |||
| 74 | return std::move(directory); | 74 | return std::move(directory); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | u64 DiskArchive::GetFreeBytes() const { | ||
| 78 | // TODO: Stubbed to return 1GiB | ||
| 79 | return 1024 * 1024 * 1024; | ||
| 80 | } | ||
| 81 | |||
| 77 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 82 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 78 | 83 | ||
| 79 | DiskFile::DiskFile(const DiskArchive& archive, const Path& path, const Mode mode) { | 84 | DiskFile::DiskFile(const DiskArchive& archive, const Path& path, const Mode mode) { |
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h index aaac65b17..ef9a98057 100644 --- a/src/core/file_sys/disk_archive.h +++ b/src/core/file_sys/disk_archive.h | |||
| @@ -41,6 +41,7 @@ public: | |||
| 41 | bool CreateDirectory(const Path& path) const override; | 41 | bool CreateDirectory(const Path& path) const override; |
| 42 | bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; | 42 | bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; |
| 43 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | 43 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; |
| 44 | u64 GetFreeBytes() const override; | ||
| 44 | 45 | ||
| 45 | protected: | 46 | protected: |
| 46 | friend class DiskFile; | 47 | friend class DiskFile; |
diff --git a/src/core/file_sys/ivfc_archive.cpp b/src/core/file_sys/ivfc_archive.cpp index 441ca9b53..2efc31a8c 100644 --- a/src/core/file_sys/ivfc_archive.cpp +++ b/src/core/file_sys/ivfc_archive.cpp | |||
| @@ -59,6 +59,11 @@ std::unique_ptr<DirectoryBackend> IVFCArchive::OpenDirectory(const Path& path) c | |||
| 59 | return Common::make_unique<IVFCDirectory>(); | 59 | return Common::make_unique<IVFCDirectory>(); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | u64 IVFCArchive::GetFreeBytes() const { | ||
| 63 | LOG_WARNING(Service_FS, "Attempted to get the free space in an IVFC archive"); | ||
| 64 | return 0; | ||
| 65 | } | ||
| 66 | |||
| 62 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 67 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 63 | 68 | ||
| 64 | size_t IVFCFile::Read(const u64 offset, const size_t length, u8* buffer) const { | 69 | size_t IVFCFile::Read(const u64 offset, const size_t length, u8* buffer) const { |
diff --git a/src/core/file_sys/ivfc_archive.h b/src/core/file_sys/ivfc_archive.h index c15a6c4ae..f3fd82de4 100644 --- a/src/core/file_sys/ivfc_archive.h +++ b/src/core/file_sys/ivfc_archive.h | |||
| @@ -42,6 +42,7 @@ public: | |||
| 42 | bool CreateDirectory(const Path& path) const override; | 42 | bool CreateDirectory(const Path& path) const override; |
| 43 | bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; | 43 | bool RenameDirectory(const Path& src_path, const Path& dest_path) const override; |
| 44 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; | 44 | std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; |
| 45 | u64 GetFreeBytes() const override; | ||
| 45 | 46 | ||
| 46 | protected: | 47 | protected: |
| 47 | std::shared_ptr<FileUtil::IOFile> romfs_file; | 48 | std::shared_ptr<FileUtil::IOFile> romfs_file; |
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp new file mode 100644 index 000000000..3a2445241 --- /dev/null +++ b/src/core/gdbstub/gdbstub.cpp | |||
| @@ -0,0 +1,960 @@ | |||
| 1 | // Copyright 2013 Dolphin Emulator Project | ||
| 2 | // Licensed under GPLv2+ | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // Originally written by Sven Peter <sven@fail0verflow.com> for anergistic. | ||
| 6 | |||
| 7 | #include <algorithm> | ||
| 8 | #include <climits> | ||
| 9 | #include <csignal> | ||
| 10 | #include <cstdarg> | ||
| 11 | #include <cstdio> | ||
| 12 | #include <cstring> | ||
| 13 | #include <fcntl.h> | ||
| 14 | #include <map> | ||
| 15 | #include <numeric> | ||
| 16 | |||
| 17 | #ifdef _MSC_VER | ||
| 18 | #include <WinSock2.h> | ||
| 19 | #include <ws2tcpip.h> | ||
| 20 | #include <common/x64/abi.h> | ||
| 21 | #include <io.h> | ||
| 22 | #include <iphlpapi.h> | ||
| 23 | #define SHUT_RDWR 2 | ||
| 24 | #else | ||
| 25 | #include <unistd.h> | ||
| 26 | #include <sys/select.h> | ||
| 27 | #include <sys/socket.h> | ||
| 28 | #include <sys/un.h> | ||
| 29 | #include <netinet/in.h> | ||
| 30 | #endif | ||
| 31 | |||
| 32 | #include "common/logging/log.h" | ||
| 33 | #include "common/string_util.h" | ||
| 34 | #include "core/core.h" | ||
| 35 | #include "core/memory.h" | ||
| 36 | #include "core/arm/arm_interface.h" | ||
| 37 | #include "core/gdbstub/gdbstub.h" | ||
| 38 | |||
| 39 | const int GDB_BUFFER_SIZE = 10000; | ||
| 40 | |||
| 41 | const char GDB_STUB_START = '$'; | ||
| 42 | const char GDB_STUB_END = '#'; | ||
| 43 | const char GDB_STUB_ACK = '+'; | ||
| 44 | const char GDB_STUB_NACK = '-'; | ||
| 45 | |||
| 46 | #ifndef SIGTRAP | ||
| 47 | const u32 SIGTRAP = 5; | ||
| 48 | #endif | ||
| 49 | |||
| 50 | #ifndef SIGTERM | ||
| 51 | const u32 SIGTERM = 15; | ||
| 52 | #endif | ||
| 53 | |||
| 54 | #ifndef MSG_WAITALL | ||
| 55 | const u32 MSG_WAITALL = 8; | ||
| 56 | #endif | ||
| 57 | |||
| 58 | const u32 R0_REGISTER = 0; | ||
| 59 | const u32 R15_REGISTER = 15; | ||
| 60 | const u32 CPSR_REGISTER = 25; | ||
| 61 | const u32 FPSCR_REGISTER = 58; | ||
| 62 | |||
| 63 | namespace GDBStub { | ||
| 64 | |||
| 65 | static int gdbserver_socket = -1; | ||
| 66 | |||
| 67 | static u8 command_buffer[GDB_BUFFER_SIZE]; | ||
| 68 | static u32 command_length; | ||
| 69 | |||
| 70 | static u32 latest_signal = 0; | ||
| 71 | static bool step_break = false; | ||
| 72 | static bool memory_break = false; | ||
| 73 | |||
| 74 | // Binding to a port within the reserved ports range (0-1023) requires root permissions, | ||
| 75 | // so default to a port outside of that range. | ||
| 76 | static u16 gdbstub_port = 24689; | ||
| 77 | |||
| 78 | static bool halt_loop = true; | ||
| 79 | static bool step_loop = false; | ||
| 80 | std::atomic<bool> g_server_enabled(false); | ||
| 81 | |||
| 82 | #ifdef _WIN32 | ||
| 83 | WSADATA InitData; | ||
| 84 | #endif | ||
| 85 | |||
| 86 | struct Breakpoint { | ||
| 87 | bool active; | ||
| 88 | PAddr addr; | ||
| 89 | u32 len; | ||
| 90 | }; | ||
| 91 | |||
| 92 | static std::map<u32, Breakpoint> breakpoints_execute; | ||
| 93 | static std::map<u32, Breakpoint> breakpoints_read; | ||
| 94 | static std::map<u32, Breakpoint> breakpoints_write; | ||
| 95 | |||
| 96 | /** | ||
| 97 | * Turns hex string character into the equivalent byte. | ||
| 98 | * | ||
| 99 | * @param hex Input hex character to be turned into byte. | ||
| 100 | */ | ||
| 101 | static u8 HexCharToValue(u8 hex) { | ||
| 102 | if (hex >= '0' && hex <= '9') { | ||
| 103 | return hex - '0'; | ||
| 104 | } else if (hex >= 'a' && hex <= 'f') { | ||
| 105 | return hex - 'a' + 0xA; | ||
| 106 | } else if (hex >= 'A' && hex <= 'F') { | ||
| 107 | return hex - 'A' + 0xA; | ||
| 108 | } | ||
| 109 | |||
| 110 | LOG_ERROR(Debug_GDBStub, "Invalid nibble: %c (%02x)\n", hex, hex); | ||
| 111 | return 0; | ||
| 112 | } | ||
| 113 | |||
| 114 | /** | ||
| 115 | * Turn nibble of byte into hex string character. | ||
| 116 | * | ||
| 117 | * @param n Nibble to be turned into hex character. | ||
| 118 | */ | ||
| 119 | static u8 NibbleToHex(u8 n) { | ||
| 120 | n &= 0xF; | ||
| 121 | if (n < 0xA) { | ||
| 122 | return '0' + n; | ||
| 123 | } else { | ||
| 124 | return 'A' + n - 0xA; | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | /** | ||
| 129 | * Converts input hex string characters into an array of equivalent of u8 bytes. | ||
| 130 | * | ||
| 131 | * @param dest Pointer to buffer to store u8 bytes. | ||
| 132 | * @param src Pointer to array of output hex string characters. | ||
| 133 | * @param len Length of src array. | ||
| 134 | */ | ||
| 135 | static u32 HexToInt(u8* src, u32 len) { | ||
| 136 | u32 output = 0; | ||
| 137 | while (len-- > 0) { | ||
| 138 | output = (output << 4) | HexCharToValue(src[0]); | ||
| 139 | src++; | ||
| 140 | } | ||
| 141 | return output; | ||
| 142 | } | ||
| 143 | |||
| 144 | /** | ||
| 145 | * Converts input array of u8 bytes into their equivalent hex string characters. | ||
| 146 | * | ||
| 147 | * @param dest Pointer to buffer to store output hex string characters. | ||
| 148 | * @param src Pointer to array of u8 bytes. | ||
| 149 | * @param len Length of src array. | ||
| 150 | */ | ||
| 151 | static void MemToGdbHex(u8* dest, u8* src, u32 len) { | ||
| 152 | while (len-- > 0) { | ||
| 153 | u8 tmp = *src++; | ||
| 154 | *dest++ = NibbleToHex(tmp >> 4); | ||
| 155 | *dest++ = NibbleToHex(tmp); | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | /** | ||
| 160 | * Converts input gdb-formatted hex string characters into an array of equivalent of u8 bytes. | ||
| 161 | * | ||
| 162 | * @param dest Pointer to buffer to store u8 bytes. | ||
| 163 | * @param src Pointer to array of output hex string characters. | ||
| 164 | * @param len Length of src array. | ||
| 165 | */ | ||
| 166 | static void GdbHexToMem(u8* dest, u8* src, u32 len) { | ||
| 167 | while (len-- > 0) { | ||
| 168 | *dest++ = (HexCharToValue(src[0]) << 4) | HexCharToValue(src[1]); | ||
| 169 | src += 2; | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | /** | ||
| 174 | * Convert a u32 into a gdb-formatted hex string. | ||
| 175 | * | ||
| 176 | * @param dest Pointer to buffer to store output hex string characters. | ||
| 177 | */ | ||
| 178 | static void IntToGdbHex(u8* dest, u32 v) { | ||
| 179 | for (int i = 0; i < 8; i += 2) { | ||
| 180 | dest[i + 1] = NibbleToHex(v >> (4 * i)); | ||
| 181 | dest[i] = NibbleToHex(v >> (4 * (i + 1))); | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | /** | ||
| 186 | * Convert a gdb-formatted hex string into a u32. | ||
| 187 | * | ||
| 188 | * @param src Pointer to hex string. | ||
| 189 | */ | ||
| 190 | static u32 GdbHexToInt(u8* src) { | ||
| 191 | u32 output = 0; | ||
| 192 | |||
| 193 | for (int i = 0; i < 8; i += 2) { | ||
| 194 | output = (output << 4) | HexCharToValue(src[7 - i - 1]); | ||
| 195 | output = (output << 4) | HexCharToValue(src[7 - i]); | ||
| 196 | } | ||
| 197 | |||
| 198 | return output; | ||
| 199 | } | ||
| 200 | |||
| 201 | /// Read a byte from the gdb client. | ||
| 202 | static u8 ReadByte() { | ||
| 203 | u8 c; | ||
| 204 | size_t received_size = recv(gdbserver_socket, reinterpret_cast<char*>(&c), 1, MSG_WAITALL); | ||
| 205 | if (received_size != 1) { | ||
| 206 | LOG_ERROR(Debug_GDBStub, "recv failed : %ld", received_size); | ||
| 207 | Shutdown(); | ||
| 208 | } | ||
| 209 | |||
| 210 | return c; | ||
| 211 | } | ||
| 212 | |||
| 213 | /// Calculate the checksum of the current command buffer. | ||
| 214 | static u8 CalculateChecksum(u8 *buffer, u32 length) { | ||
| 215 | return static_cast<u8>(std::accumulate(buffer, buffer + length, 0, std::plus<u8>())); | ||
| 216 | } | ||
| 217 | |||
| 218 | /** | ||
| 219 | * Get the list of breakpoints for a given breakpoint type. | ||
| 220 | * | ||
| 221 | * @param type Type of breakpoint list. | ||
| 222 | */ | ||
| 223 | static std::map<u32, Breakpoint>& GetBreakpointList(BreakpointType type) { | ||
| 224 | switch (type) { | ||
| 225 | case BreakpointType::Execute: | ||
| 226 | return breakpoints_execute; | ||
| 227 | case BreakpointType::Read: | ||
| 228 | return breakpoints_read; | ||
| 229 | case BreakpointType::Write: | ||
| 230 | return breakpoints_write; | ||
| 231 | default: | ||
| 232 | return breakpoints_read; | ||
| 233 | } | ||
| 234 | } | ||
| 235 | |||
| 236 | /** | ||
| 237 | * Remove the breakpoint from the given address of the specified type. | ||
| 238 | * | ||
| 239 | * @param type Type of breakpoint. | ||
| 240 | * @param addr Address of breakpoint. | ||
| 241 | */ | ||
| 242 | static void RemoveBreakpoint(BreakpointType type, PAddr addr) { | ||
| 243 | std::map<u32, Breakpoint>& p = GetBreakpointList(type); | ||
| 244 | |||
| 245 | auto bp = p.find(addr); | ||
| 246 | if (bp != p.end()) { | ||
| 247 | LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: %08x bytes at %08x of type %d\n", bp->second.len, bp->second.addr, type); | ||
| 248 | p.erase(addr); | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | BreakpointAddress GetNextBreakpointFromAddress(PAddr addr, BreakpointType type) { | ||
| 253 | std::map<u32, Breakpoint>& p = GetBreakpointList(type); | ||
| 254 | auto next_breakpoint = p.lower_bound(addr); | ||
| 255 | BreakpointAddress breakpoint; | ||
| 256 | |||
| 257 | if (next_breakpoint != p.end()) { | ||
| 258 | breakpoint.address = next_breakpoint->first; | ||
| 259 | breakpoint.type = type; | ||
| 260 | } else { | ||
| 261 | breakpoint.address = 0; | ||
| 262 | breakpoint.type = BreakpointType::None; | ||
| 263 | } | ||
| 264 | |||
| 265 | return breakpoint; | ||
| 266 | } | ||
| 267 | |||
| 268 | bool CheckBreakpoint(PAddr addr, BreakpointType type) { | ||
| 269 | if (!IsConnected()) { | ||
| 270 | return false; | ||
| 271 | } | ||
| 272 | |||
| 273 | std::map<u32, Breakpoint>& p = GetBreakpointList(type); | ||
| 274 | |||
| 275 | auto bp = p.find(addr); | ||
| 276 | if (bp != p.end()) { | ||
| 277 | u32 len = bp->second.len; | ||
| 278 | |||
| 279 | // IDA Pro defaults to 4-byte breakpoints for all non-hardware breakpoints | ||
| 280 | // no matter if it's a 4-byte or 2-byte instruction. When you execute a | ||
| 281 | // Thumb instruction with a 4-byte breakpoint set, it will set a breakpoint on | ||
| 282 | // two instructions instead of the single instruction you placed the breakpoint | ||
| 283 | // on. So, as a way to make sure that execution breakpoints are only breaking | ||
| 284 | // on the instruction that was specified, set the length of an execution | ||
| 285 | // breakpoint to 1. This should be fine since the CPU should never begin executing | ||
| 286 | // an instruction anywhere except the beginning of the instruction. | ||
| 287 | if (type == BreakpointType::Execute) { | ||
| 288 | len = 1; | ||
| 289 | } | ||
| 290 | |||
| 291 | if (bp->second.active && (addr >= bp->second.addr && addr < bp->second.addr + len)) { | ||
| 292 | LOG_DEBUG(Debug_GDBStub, "Found breakpoint type %d @ %08x, range: %08x - %08x (%d bytes)\n", type, addr, bp->second.addr, bp->second.addr + len, len); | ||
| 293 | return true; | ||
| 294 | } | ||
| 295 | } | ||
| 296 | |||
| 297 | return false; | ||
| 298 | } | ||
| 299 | |||
| 300 | /** | ||
| 301 | * Send packet to gdb client. | ||
| 302 | * | ||
| 303 | * @param packet Packet to be sent to client. | ||
| 304 | */ | ||
| 305 | static void SendPacket(const char packet) { | ||
| 306 | size_t sent_size = send(gdbserver_socket, &packet, 1, 0); | ||
| 307 | if (sent_size != 1) { | ||
| 308 | LOG_ERROR(Debug_GDBStub, "send failed"); | ||
| 309 | } | ||
| 310 | } | ||
| 311 | |||
| 312 | /** | ||
| 313 | * Send reply to gdb client. | ||
| 314 | * | ||
| 315 | * @param reply Reply to be sent to client. | ||
| 316 | */ | ||
| 317 | static void SendReply(const char* reply) { | ||
| 318 | if (!IsConnected()) { | ||
| 319 | return; | ||
| 320 | } | ||
| 321 | |||
| 322 | memset(command_buffer, 0, sizeof(command_buffer)); | ||
| 323 | |||
| 324 | command_length = strlen(reply); | ||
| 325 | if (command_length + 4 > sizeof(command_buffer)) { | ||
| 326 | LOG_ERROR(Debug_GDBStub, "command_buffer overflow in SendReply"); | ||
| 327 | return; | ||
| 328 | } | ||
| 329 | |||
| 330 | memcpy(command_buffer + 1, reply, command_length); | ||
| 331 | |||
| 332 | u8 checksum = CalculateChecksum(command_buffer, command_length + 1); | ||
| 333 | command_buffer[0] = GDB_STUB_START; | ||
| 334 | command_buffer[command_length + 1] = GDB_STUB_END; | ||
| 335 | command_buffer[command_length + 2] = NibbleToHex(checksum >> 4); | ||
| 336 | command_buffer[command_length + 3] = NibbleToHex(checksum); | ||
| 337 | |||
| 338 | u8* ptr = command_buffer; | ||
| 339 | u32 left = command_length + 4; | ||
| 340 | while (left > 0) { | ||
| 341 | int sent_size = send(gdbserver_socket, reinterpret_cast<char*>(ptr), left, 0); | ||
| 342 | if (sent_size < 0) { | ||
| 343 | LOG_ERROR(Debug_GDBStub, "gdb: send failed"); | ||
| 344 | return Shutdown(); | ||
| 345 | } | ||
| 346 | |||
| 347 | left -= sent_size; | ||
| 348 | ptr += sent_size; | ||
| 349 | } | ||
| 350 | } | ||
| 351 | |||
| 352 | /// Handle query command from gdb client. | ||
| 353 | static void HandleQuery() { | ||
| 354 | LOG_DEBUG(Debug_GDBStub, "gdb: query '%s'\n", command_buffer + 1); | ||
| 355 | |||
| 356 | if (!strcmp(reinterpret_cast<const char*>(command_buffer + 1), "TStatus")) { | ||
| 357 | SendReply("T0"); | ||
| 358 | } else { | ||
| 359 | SendReply(""); | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 | /// Handle set thread command from gdb client. | ||
| 364 | static void HandleSetThread() { | ||
| 365 | if (memcmp(command_buffer, "Hg0", 3) == 0 || | ||
| 366 | memcmp(command_buffer, "Hc-1", 4) == 0 || | ||
| 367 | memcmp(command_buffer, "Hc0", 4) == 0 || | ||
| 368 | memcmp(command_buffer, "Hc1", 4) == 0) { | ||
| 369 | return SendReply("OK"); | ||
| 370 | } | ||
| 371 | |||
| 372 | SendReply("E01"); | ||
| 373 | } | ||
| 374 | |||
| 375 | /** | ||
| 376 | * Send signal packet to client. | ||
| 377 | * | ||
| 378 | * @param signal Signal to be sent to client. | ||
| 379 | */ | ||
| 380 | void SendSignal(u32 signal) { | ||
| 381 | if (gdbserver_socket == -1) { | ||
| 382 | return; | ||
| 383 | } | ||
| 384 | |||
| 385 | latest_signal = signal; | ||
| 386 | |||
| 387 | std::string buffer = Common::StringFromFormat("T%02x%02x:%08x;%02x:%08x;", latest_signal, 15, htonl(Core::g_app_core->GetPC()), 13, htonl(Core::g_app_core->GetReg(13))); | ||
| 388 | LOG_DEBUG(Debug_GDBStub, "Response: %s", buffer.c_str()); | ||
| 389 | SendReply(buffer.c_str()); | ||
| 390 | } | ||
| 391 | |||
| 392 | /// Read command from gdb client. | ||
| 393 | static void ReadCommand() { | ||
| 394 | command_length = 0; | ||
| 395 | memset(command_buffer, 0, sizeof(command_buffer)); | ||
| 396 | |||
| 397 | u8 c = ReadByte(); | ||
| 398 | if (c == '+') { | ||
| 399 | //ignore ack | ||
| 400 | return; | ||
| 401 | } else if (c == 0x03) { | ||
| 402 | LOG_INFO(Debug_GDBStub, "gdb: found break command\n"); | ||
| 403 | halt_loop = true; | ||
| 404 | SendSignal(SIGTRAP); | ||
| 405 | return; | ||
| 406 | } else if (c != GDB_STUB_START) { | ||
| 407 | LOG_DEBUG(Debug_GDBStub, "gdb: read invalid byte %02x\n", c); | ||
| 408 | return; | ||
| 409 | } | ||
| 410 | |||
| 411 | while ((c = ReadByte()) != GDB_STUB_END) { | ||
| 412 | if (command_length >= sizeof(command_buffer)) { | ||
| 413 | LOG_ERROR(Debug_GDBStub, "gdb: command_buffer overflow\n"); | ||
| 414 | SendPacket(GDB_STUB_NACK); | ||
| 415 | return; | ||
| 416 | } | ||
| 417 | command_buffer[command_length++] = c; | ||
| 418 | } | ||
| 419 | |||
| 420 | u8 checksum_received = HexCharToValue(ReadByte()) << 4; | ||
| 421 | checksum_received |= HexCharToValue(ReadByte()); | ||
| 422 | |||
| 423 | u8 checksum_calculated = CalculateChecksum(command_buffer, command_length); | ||
| 424 | |||
| 425 | if (checksum_received != checksum_calculated) { | ||
| 426 | LOG_ERROR(Debug_GDBStub, "gdb: invalid checksum: calculated %02x and read %02x for $%s# (length: %d)\n", | ||
| 427 | checksum_calculated, checksum_received, command_buffer, command_length); | ||
| 428 | |||
| 429 | command_length = 0; | ||
| 430 | |||
| 431 | SendPacket(GDB_STUB_NACK); | ||
| 432 | return; | ||
| 433 | } | ||
| 434 | |||
| 435 | SendPacket(GDB_STUB_ACK); | ||
| 436 | } | ||
| 437 | |||
| 438 | /// Check if there is data to be read from the gdb client. | ||
| 439 | static bool IsDataAvailable() { | ||
| 440 | if (!IsConnected()) { | ||
| 441 | return false; | ||
| 442 | } | ||
| 443 | |||
| 444 | fd_set fd_socket; | ||
| 445 | |||
| 446 | FD_ZERO(&fd_socket); | ||
| 447 | FD_SET(gdbserver_socket, &fd_socket); | ||
| 448 | |||
| 449 | struct timeval t; | ||
| 450 | t.tv_sec = 0; | ||
| 451 | t.tv_usec = 0; | ||
| 452 | |||
| 453 | if (select(gdbserver_socket + 1, &fd_socket, nullptr, nullptr, &t) < 0) { | ||
| 454 | LOG_ERROR(Debug_GDBStub, "select failed"); | ||
| 455 | return false; | ||
| 456 | } | ||
| 457 | |||
| 458 | return FD_ISSET(gdbserver_socket, &fd_socket); | ||
| 459 | } | ||
| 460 | |||
| 461 | /// Send requested register to gdb client. | ||
| 462 | static void ReadRegister() { | ||
| 463 | static u8 reply[64]; | ||
| 464 | memset(reply, 0, sizeof(reply)); | ||
| 465 | |||
| 466 | u32 id = HexCharToValue(command_buffer[1]); | ||
| 467 | if (command_buffer[2] != '\0') { | ||
| 468 | id <<= 4; | ||
| 469 | id |= HexCharToValue(command_buffer[2]); | ||
| 470 | } | ||
| 471 | |||
| 472 | if (id >= R0_REGISTER && id <= R15_REGISTER) { | ||
| 473 | IntToGdbHex(reply, Core::g_app_core->GetReg(id)); | ||
| 474 | } else if (id == CPSR_REGISTER) { | ||
| 475 | IntToGdbHex(reply, Core::g_app_core->GetCPSR()); | ||
| 476 | } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { | ||
| 477 | IntToGdbHex(reply, Core::g_app_core->GetVFPReg(id - CPSR_REGISTER - 1)); // VFP registers should start at 26, so one after CSPR_REGISTER | ||
| 478 | } else if (id == FPSCR_REGISTER) { | ||
| 479 | IntToGdbHex(reply, Core::g_app_core->GetVFPSystemReg(VFP_FPSCR)); // Get FPSCR | ||
| 480 | IntToGdbHex(reply + 8, 0); | ||
| 481 | } else { | ||
| 482 | return SendReply("E01"); | ||
| 483 | } | ||
| 484 | |||
| 485 | SendReply(reinterpret_cast<char*>(reply)); | ||
| 486 | } | ||
| 487 | |||
| 488 | /// Send all registers to the gdb client. | ||
| 489 | static void ReadRegisters() { | ||
| 490 | static u8 buffer[GDB_BUFFER_SIZE - 4]; | ||
| 491 | memset(buffer, 0, sizeof(buffer)); | ||
| 492 | |||
| 493 | u8* bufptr = buffer; | ||
| 494 | for (int i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) { | ||
| 495 | if (reg <= R15_REGISTER) { | ||
| 496 | IntToGdbHex(bufptr + i * CHAR_BIT, Core::g_app_core->GetReg(reg)); | ||
| 497 | } else if (reg == CPSR_REGISTER) { | ||
| 498 | IntToGdbHex(bufptr + i * CHAR_BIT, Core::g_app_core->GetCPSR()); | ||
| 499 | } else if (reg == CPSR_REGISTER - 1) { | ||
| 500 | // Dummy FPA register, ignore | ||
| 501 | IntToGdbHex(bufptr + i * CHAR_BIT, 0); | ||
| 502 | } else if (reg < CPSR_REGISTER) { | ||
| 503 | // Dummy FPA registers, ignore | ||
| 504 | IntToGdbHex(bufptr + i * CHAR_BIT, 0); | ||
| 505 | IntToGdbHex(bufptr + (i + 1) * CHAR_BIT, 0); | ||
| 506 | IntToGdbHex(bufptr + (i + 2) * CHAR_BIT, 0); | ||
| 507 | i += 2; | ||
| 508 | } else if (reg > CPSR_REGISTER && reg < FPSCR_REGISTER) { | ||
| 509 | IntToGdbHex(bufptr + i * CHAR_BIT, Core::g_app_core->GetVFPReg(reg - CPSR_REGISTER - 1)); | ||
| 510 | IntToGdbHex(bufptr + (i + 1) * CHAR_BIT, 0); | ||
| 511 | i++; | ||
| 512 | } else if (reg == FPSCR_REGISTER) { | ||
| 513 | IntToGdbHex(bufptr + i * CHAR_BIT, Core::g_app_core->GetVFPSystemReg(VFP_FPSCR)); | ||
| 514 | } | ||
| 515 | } | ||
| 516 | |||
| 517 | SendReply(reinterpret_cast<char*>(buffer)); | ||
| 518 | } | ||
| 519 | |||
| 520 | /// Modify data of register specified by gdb client. | ||
| 521 | static void WriteRegister() { | ||
| 522 | u8* buffer_ptr = command_buffer + 3; | ||
| 523 | |||
| 524 | u32 id = HexCharToValue(command_buffer[1]); | ||
| 525 | if (command_buffer[2] != '=') { | ||
| 526 | ++buffer_ptr; | ||
| 527 | id <<= 4; | ||
| 528 | id |= HexCharToValue(command_buffer[2]); | ||
| 529 | } | ||
| 530 | |||
| 531 | if (id >= R0_REGISTER && id <= R15_REGISTER) { | ||
| 532 | Core::g_app_core->SetReg(id, GdbHexToInt(buffer_ptr)); | ||
| 533 | } else if (id == CPSR_REGISTER) { | ||
| 534 | Core::g_app_core->SetCPSR(GdbHexToInt(buffer_ptr)); | ||
| 535 | } else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) { | ||
| 536 | Core::g_app_core->SetVFPReg(id - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr)); | ||
| 537 | } else if (id == FPSCR_REGISTER) { | ||
| 538 | Core::g_app_core->SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr)); | ||
| 539 | } else { | ||
| 540 | return SendReply("E01"); | ||
| 541 | } | ||
| 542 | |||
| 543 | SendReply("OK"); | ||
| 544 | } | ||
| 545 | |||
| 546 | /// Modify all registers with data received from the client. | ||
| 547 | static void WriteRegisters() { | ||
| 548 | u8* buffer_ptr = command_buffer + 1; | ||
| 549 | |||
| 550 | if (command_buffer[0] != 'G') | ||
| 551 | return SendReply("E01"); | ||
| 552 | |||
| 553 | for (int i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) { | ||
| 554 | if (reg <= R15_REGISTER) { | ||
| 555 | Core::g_app_core->SetReg(reg, GdbHexToInt(buffer_ptr + i * CHAR_BIT)); | ||
| 556 | } else if (reg == CPSR_REGISTER) { | ||
| 557 | Core::g_app_core->SetCPSR(GdbHexToInt(buffer_ptr + i * CHAR_BIT)); | ||
| 558 | } else if (reg == CPSR_REGISTER - 1) { | ||
| 559 | // Dummy FPA register, ignore | ||
| 560 | } else if (reg < CPSR_REGISTER) { | ||
| 561 | // Dummy FPA registers, ignore | ||
| 562 | i += 2; | ||
| 563 | } else if (reg > CPSR_REGISTER && reg < FPSCR_REGISTER) { | ||
| 564 | Core::g_app_core->SetVFPReg(reg - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr + i * CHAR_BIT)); | ||
| 565 | i++; // Skip padding | ||
| 566 | } else if (reg == FPSCR_REGISTER) { | ||
| 567 | Core::g_app_core->SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr + i * CHAR_BIT)); | ||
| 568 | } | ||
| 569 | } | ||
| 570 | |||
| 571 | SendReply("OK"); | ||
| 572 | } | ||
| 573 | |||
| 574 | /// Read location in memory specified by gdb client. | ||
| 575 | static void ReadMemory() { | ||
| 576 | static u8 reply[GDB_BUFFER_SIZE - 4]; | ||
| 577 | |||
| 578 | auto start_offset = command_buffer+1; | ||
| 579 | auto addr_pos = std::find(start_offset, command_buffer+command_length, ','); | ||
| 580 | PAddr addr = HexToInt(start_offset, addr_pos - start_offset); | ||
| 581 | |||
| 582 | start_offset = addr_pos+1; | ||
| 583 | u32 len = HexToInt(start_offset, (command_buffer + command_length) - start_offset); | ||
| 584 | |||
| 585 | LOG_DEBUG(Debug_GDBStub, "gdb: addr: %08x len: %08x\n", addr, len); | ||
| 586 | |||
| 587 | if (len * 2 > sizeof(reply)) { | ||
| 588 | SendReply("E01"); | ||
| 589 | } | ||
| 590 | |||
| 591 | u8* data = Memory::GetPointer(addr); | ||
| 592 | if (!data) { | ||
| 593 | return SendReply("E0"); | ||
| 594 | } | ||
| 595 | |||
| 596 | MemToGdbHex(reply, data, len); | ||
| 597 | reply[len * 2] = '\0'; | ||
| 598 | SendReply(reinterpret_cast<char*>(reply)); | ||
| 599 | } | ||
| 600 | |||
| 601 | /// Modify location in memory with data received from the gdb client. | ||
| 602 | static void WriteMemory() { | ||
| 603 | auto start_offset = command_buffer+1; | ||
| 604 | auto addr_pos = std::find(start_offset, command_buffer+command_length, ','); | ||
| 605 | PAddr addr = HexToInt(start_offset, addr_pos - start_offset); | ||
| 606 | |||
| 607 | start_offset = addr_pos+1; | ||
| 608 | auto len_pos = std::find(start_offset, command_buffer+command_length, ':'); | ||
| 609 | u32 len = HexToInt(start_offset, len_pos - start_offset); | ||
| 610 | |||
| 611 | u8* dst = Memory::GetPointer(addr); | ||
| 612 | if (!dst) { | ||
| 613 | return SendReply("E00"); | ||
| 614 | } | ||
| 615 | |||
| 616 | GdbHexToMem(dst, len_pos + 1, len); | ||
| 617 | SendReply("OK"); | ||
| 618 | } | ||
| 619 | |||
| 620 | void Break(bool is_memory_break) { | ||
| 621 | if (!halt_loop) { | ||
| 622 | halt_loop = true; | ||
| 623 | SendSignal(SIGTRAP); | ||
| 624 | } | ||
| 625 | |||
| 626 | memory_break = is_memory_break; | ||
| 627 | } | ||
| 628 | |||
| 629 | /// Tell the CPU that it should perform a single step. | ||
| 630 | static void Step() { | ||
| 631 | step_loop = true; | ||
| 632 | halt_loop = true; | ||
| 633 | step_break = true; | ||
| 634 | SendSignal(SIGTRAP); | ||
| 635 | } | ||
| 636 | |||
| 637 | bool IsMemoryBreak() { | ||
| 638 | if (IsConnected()) { | ||
| 639 | return false; | ||
| 640 | } | ||
| 641 | |||
| 642 | return memory_break; | ||
| 643 | } | ||
| 644 | |||
| 645 | /// Tell the CPU to continue executing. | ||
| 646 | static void Continue() { | ||
| 647 | memory_break = false; | ||
| 648 | step_break = false; | ||
| 649 | step_loop = false; | ||
| 650 | halt_loop = false; | ||
| 651 | } | ||
| 652 | |||
| 653 | /** | ||
| 654 | * Commit breakpoint to list of breakpoints. | ||
| 655 | * | ||
| 656 | * @param type Type of breakpoint. | ||
| 657 | * @param addr Address of breakpoint. | ||
| 658 | * @param len Length of breakpoint. | ||
| 659 | */ | ||
| 660 | bool CommitBreakpoint(BreakpointType type, PAddr addr, u32 len) { | ||
| 661 | std::map<u32, Breakpoint>& p = GetBreakpointList(type); | ||
| 662 | |||
| 663 | Breakpoint breakpoint; | ||
| 664 | breakpoint.active = true; | ||
| 665 | breakpoint.addr = addr; | ||
| 666 | breakpoint.len = len; | ||
| 667 | p.insert({ addr, breakpoint }); | ||
| 668 | |||
| 669 | LOG_DEBUG(Debug_GDBStub, "gdb: added %d breakpoint: %08x bytes at %08x\n", type, breakpoint.len, breakpoint.addr); | ||
| 670 | |||
| 671 | return true; | ||
| 672 | } | ||
| 673 | |||
| 674 | /// Handle add breakpoint command from gdb client. | ||
| 675 | static void AddBreakpoint() { | ||
| 676 | BreakpointType type; | ||
| 677 | |||
| 678 | u8 type_id = HexCharToValue(command_buffer[1]); | ||
| 679 | switch (type_id) { | ||
| 680 | case 0: | ||
| 681 | case 1: | ||
| 682 | type = BreakpointType::Execute; | ||
| 683 | break; | ||
| 684 | case 2: | ||
| 685 | type = BreakpointType::Write; | ||
| 686 | break; | ||
| 687 | case 3: | ||
| 688 | type = BreakpointType::Read; | ||
| 689 | break; | ||
| 690 | case 4: | ||
| 691 | type = BreakpointType::Access; | ||
| 692 | break; | ||
| 693 | default: | ||
| 694 | return SendReply("E01"); | ||
| 695 | } | ||
| 696 | |||
| 697 | auto start_offset = command_buffer+3; | ||
| 698 | auto addr_pos = std::find(start_offset, command_buffer+command_length, ','); | ||
| 699 | PAddr addr = HexToInt(start_offset, addr_pos - start_offset); | ||
| 700 | |||
| 701 | start_offset = addr_pos+1; | ||
| 702 | u32 len = HexToInt(start_offset, (command_buffer + command_length) - start_offset); | ||
| 703 | |||
| 704 | if (type == BreakpointType::Access) { | ||
| 705 | // Access is made up of Read and Write types, so add both breakpoints | ||
| 706 | type = BreakpointType::Read; | ||
| 707 | |||
| 708 | if (!CommitBreakpoint(type, addr, len)) { | ||
| 709 | return SendReply("E02"); | ||
| 710 | } | ||
| 711 | |||
| 712 | type = BreakpointType::Write; | ||
| 713 | } | ||
| 714 | |||
| 715 | if (!CommitBreakpoint(type, addr, len)) { | ||
| 716 | return SendReply("E02"); | ||
| 717 | } | ||
| 718 | |||
| 719 | SendReply("OK"); | ||
| 720 | } | ||
| 721 | |||
| 722 | /// Handle remove breakpoint command from gdb client. | ||
| 723 | static void RemoveBreakpoint() { | ||
| 724 | BreakpointType type; | ||
| 725 | |||
| 726 | u8 type_id = HexCharToValue(command_buffer[1]); | ||
| 727 | switch (type_id) { | ||
| 728 | case 0: | ||
| 729 | case 1: | ||
| 730 | type = BreakpointType::Execute; | ||
| 731 | break; | ||
| 732 | case 2: | ||
| 733 | type = BreakpointType::Write; | ||
| 734 | break; | ||
| 735 | case 3: | ||
| 736 | type = BreakpointType::Read; | ||
| 737 | break; | ||
| 738 | case 4: | ||
| 739 | type = BreakpointType::Access; | ||
| 740 | break; | ||
| 741 | default: | ||
| 742 | return SendReply("E01"); | ||
| 743 | } | ||
| 744 | |||
| 745 | auto start_offset = command_buffer+3; | ||
| 746 | auto addr_pos = std::find(start_offset, command_buffer+command_length, ','); | ||
| 747 | PAddr addr = HexToInt(start_offset, addr_pos - start_offset); | ||
| 748 | |||
| 749 | start_offset = addr_pos+1; | ||
| 750 | u32 len = HexToInt(start_offset, (command_buffer + command_length) - start_offset); | ||
| 751 | |||
| 752 | if (type == BreakpointType::Access) { | ||
| 753 | // Access is made up of Read and Write types, so add both breakpoints | ||
| 754 | type = BreakpointType::Read; | ||
| 755 | RemoveBreakpoint(type, addr); | ||
| 756 | |||
| 757 | type = BreakpointType::Write; | ||
| 758 | } | ||
| 759 | |||
| 760 | RemoveBreakpoint(type, addr); | ||
| 761 | SendReply("OK"); | ||
| 762 | } | ||
| 763 | |||
| 764 | void HandlePacket() { | ||
| 765 | if (!IsConnected()) { | ||
| 766 | return; | ||
| 767 | } | ||
| 768 | |||
| 769 | if (!IsDataAvailable()) { | ||
| 770 | return; | ||
| 771 | } | ||
| 772 | |||
| 773 | ReadCommand(); | ||
| 774 | if (command_length == 0) { | ||
| 775 | return; | ||
| 776 | } | ||
| 777 | |||
| 778 | LOG_DEBUG(Debug_GDBStub, "Packet: %s", command_buffer); | ||
| 779 | |||
| 780 | switch (command_buffer[0]) { | ||
| 781 | case 'q': | ||
| 782 | HandleQuery(); | ||
| 783 | break; | ||
| 784 | case 'H': | ||
| 785 | HandleSetThread(); | ||
| 786 | break; | ||
| 787 | case '?': | ||
| 788 | SendSignal(latest_signal); | ||
| 789 | break; | ||
| 790 | case 'k': | ||
| 791 | Shutdown(); | ||
| 792 | LOG_INFO(Debug_GDBStub, "killed by gdb"); | ||
| 793 | return; | ||
| 794 | case 'g': | ||
| 795 | ReadRegisters(); | ||
| 796 | break; | ||
| 797 | case 'G': | ||
| 798 | WriteRegisters(); | ||
| 799 | break; | ||
| 800 | case 'p': | ||
| 801 | ReadRegister(); | ||
| 802 | break; | ||
| 803 | case 'P': | ||
| 804 | WriteRegister(); | ||
| 805 | break; | ||
| 806 | case 'm': | ||
| 807 | ReadMemory(); | ||
| 808 | break; | ||
| 809 | case 'M': | ||
| 810 | WriteMemory(); | ||
| 811 | break; | ||
| 812 | case 's': | ||
| 813 | Step(); | ||
| 814 | return; | ||
| 815 | case 'C': | ||
| 816 | case 'c': | ||
| 817 | Continue(); | ||
| 818 | return; | ||
| 819 | case 'z': | ||
| 820 | RemoveBreakpoint(); | ||
| 821 | break; | ||
| 822 | case 'Z': | ||
| 823 | AddBreakpoint(); | ||
| 824 | break; | ||
| 825 | default: | ||
| 826 | SendReply(""); | ||
| 827 | break; | ||
| 828 | } | ||
| 829 | } | ||
| 830 | |||
| 831 | void SetServerPort(u16 port) { | ||
| 832 | gdbstub_port = port; | ||
| 833 | } | ||
| 834 | |||
| 835 | void ToggleServer(bool status) { | ||
| 836 | if (status) { | ||
| 837 | g_server_enabled = status; | ||
| 838 | |||
| 839 | // Start server | ||
| 840 | if (!IsConnected() && Core::g_sys_core != nullptr) { | ||
| 841 | Init(); | ||
| 842 | } | ||
| 843 | } | ||
| 844 | else { | ||
| 845 | // Stop server | ||
| 846 | if (IsConnected()) { | ||
| 847 | Shutdown(); | ||
| 848 | } | ||
| 849 | |||
| 850 | g_server_enabled = status; | ||
| 851 | } | ||
| 852 | } | ||
| 853 | |||
| 854 | void Init(u16 port) { | ||
| 855 | if (!g_server_enabled) { | ||
| 856 | // Set the halt loop to false in case the user enabled the gdbstub mid-execution. | ||
| 857 | // This way the CPU can still execute normally. | ||
| 858 | halt_loop = false; | ||
| 859 | step_loop = false; | ||
| 860 | return; | ||
| 861 | } | ||
| 862 | |||
| 863 | // Setup initial gdbstub status | ||
| 864 | halt_loop = true; | ||
| 865 | step_loop = false; | ||
| 866 | |||
| 867 | breakpoints_execute.clear(); | ||
| 868 | breakpoints_read.clear(); | ||
| 869 | breakpoints_write.clear(); | ||
| 870 | |||
| 871 | // Start gdb server | ||
| 872 | LOG_INFO(Debug_GDBStub, "Starting GDB server on port %d...", port); | ||
| 873 | |||
| 874 | sockaddr_in saddr_server = {}; | ||
| 875 | saddr_server.sin_family = AF_INET; | ||
| 876 | saddr_server.sin_port = htons(port); | ||
| 877 | saddr_server.sin_addr.s_addr = INADDR_ANY; | ||
| 878 | |||
| 879 | #ifdef _WIN32 | ||
| 880 | WSAStartup(MAKEWORD(2, 2), &InitData); | ||
| 881 | #endif | ||
| 882 | |||
| 883 | int tmpsock = socket(PF_INET, SOCK_STREAM, 0); | ||
| 884 | if (tmpsock == -1) { | ||
| 885 | LOG_ERROR(Debug_GDBStub, "Failed to create gdb socket"); | ||
| 886 | } | ||
| 887 | |||
| 888 | const sockaddr* server_addr = reinterpret_cast<const sockaddr*>(&saddr_server); | ||
| 889 | socklen_t server_addrlen = sizeof(saddr_server); | ||
| 890 | if (bind(tmpsock, server_addr, server_addrlen) < 0) { | ||
| 891 | LOG_ERROR(Debug_GDBStub, "Failed to bind gdb socket"); | ||
| 892 | } | ||
| 893 | |||
| 894 | if (listen(tmpsock, 1) < 0) { | ||
| 895 | LOG_ERROR(Debug_GDBStub, "Failed to listen to gdb socket"); | ||
| 896 | } | ||
| 897 | |||
| 898 | // Wait for gdb to connect | ||
| 899 | LOG_INFO(Debug_GDBStub, "Waiting for gdb to connect...\n"); | ||
| 900 | sockaddr_in saddr_client; | ||
| 901 | sockaddr* client_addr = reinterpret_cast<sockaddr*>(&saddr_client); | ||
| 902 | socklen_t client_addrlen = sizeof(saddr_client); | ||
| 903 | gdbserver_socket = accept(tmpsock, client_addr, &client_addrlen); | ||
| 904 | if (gdbserver_socket < 0) { | ||
| 905 | // In the case that we couldn't start the server for whatever reason, just start CPU execution like normal. | ||
| 906 | halt_loop = false; | ||
| 907 | step_loop = false; | ||
| 908 | |||
| 909 | LOG_ERROR(Debug_GDBStub, "Failed to accept gdb client"); | ||
| 910 | } | ||
| 911 | else { | ||
| 912 | LOG_INFO(Debug_GDBStub, "Client connected.\n"); | ||
| 913 | saddr_client.sin_addr.s_addr = ntohl(saddr_client.sin_addr.s_addr); | ||
| 914 | } | ||
| 915 | |||
| 916 | // Clean up temporary socket if it's still alive at this point. | ||
| 917 | if (tmpsock != -1) { | ||
| 918 | shutdown(tmpsock, SHUT_RDWR); | ||
| 919 | } | ||
| 920 | } | ||
| 921 | |||
| 922 | void Init() { | ||
| 923 | Init(gdbstub_port); | ||
| 924 | } | ||
| 925 | |||
| 926 | void Shutdown() { | ||
| 927 | if (!g_server_enabled) { | ||
| 928 | return; | ||
| 929 | } | ||
| 930 | |||
| 931 | LOG_INFO(Debug_GDBStub, "Stopping GDB ..."); | ||
| 932 | if (gdbserver_socket != -1) { | ||
| 933 | shutdown(gdbserver_socket, SHUT_RDWR); | ||
| 934 | gdbserver_socket = -1; | ||
| 935 | } | ||
| 936 | |||
| 937 | #ifdef _WIN32 | ||
| 938 | WSACleanup(); | ||
| 939 | #endif | ||
| 940 | |||
| 941 | LOG_INFO(Debug_GDBStub, "GDB stopped."); | ||
| 942 | } | ||
| 943 | |||
| 944 | bool IsConnected() { | ||
| 945 | return g_server_enabled && gdbserver_socket != -1; | ||
| 946 | } | ||
| 947 | |||
| 948 | bool GetCpuHaltFlag() { | ||
| 949 | return halt_loop; | ||
| 950 | } | ||
| 951 | |||
| 952 | bool GetCpuStepFlag() { | ||
| 953 | return step_loop; | ||
| 954 | } | ||
| 955 | |||
| 956 | void SetCpuStepFlag(bool is_step) { | ||
| 957 | step_loop = is_step; | ||
| 958 | } | ||
| 959 | |||
| 960 | }; | ||
diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h new file mode 100644 index 000000000..aff705a32 --- /dev/null +++ b/src/core/gdbstub/gdbstub.h | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | // Copyright 2013 Dolphin Emulator Project | ||
| 2 | // Licensed under GPLv2+ | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | // Originally written by Sven Peter <sven@fail0verflow.com> for anergistic. | ||
| 6 | |||
| 7 | #pragma once | ||
| 8 | #include <atomic> | ||
| 9 | |||
| 10 | namespace GDBStub { | ||
| 11 | |||
| 12 | /// Breakpoint Method | ||
| 13 | enum class BreakpointType { | ||
| 14 | None, ///< None | ||
| 15 | Execute, ///< Execution Breakpoint | ||
| 16 | Read, ///< Read Breakpoint | ||
| 17 | Write, ///< Write Breakpoint | ||
| 18 | Access ///< Access (R/W) Breakpoint | ||
| 19 | }; | ||
| 20 | |||
| 21 | struct BreakpointAddress { | ||
| 22 | PAddr address; | ||
| 23 | BreakpointType type; | ||
| 24 | }; | ||
| 25 | |||
| 26 | /// If set to false, the server will never be started and no gdbstub-related functions will be executed. | ||
| 27 | extern std::atomic<bool> g_server_enabled; | ||
| 28 | |||
| 29 | /** | ||
| 30 | * Set the port the gdbstub should use to listen for connections. | ||
| 31 | * | ||
| 32 | * @param port Port to listen for connection | ||
| 33 | */ | ||
| 34 | void SetServerPort(u16 port); | ||
| 35 | |||
| 36 | /** | ||
| 37 | * Set the g_server_enabled flag and start or stop the server if possible. | ||
| 38 | * | ||
| 39 | * @param status Set the server to enabled or disabled. | ||
| 40 | */ | ||
| 41 | void ToggleServer(bool status); | ||
| 42 | |||
| 43 | /// Start the gdbstub server. | ||
| 44 | void Init(); | ||
| 45 | |||
| 46 | /// Stop gdbstub server. | ||
| 47 | void Shutdown(); | ||
| 48 | |||
| 49 | /// Returns true if there is an active socket connection. | ||
| 50 | bool IsConnected(); | ||
| 51 | |||
| 52 | /** | ||
| 53 | * Signal to the gdbstub server that it should halt CPU execution. | ||
| 54 | * | ||
| 55 | * @param is_memory_break If true, the break resulted from a memory breakpoint. | ||
| 56 | */ | ||
| 57 | void Break(bool is_memory_break = false); | ||
| 58 | |||
| 59 | /// Determine if there was a memory breakpoint. | ||
| 60 | bool IsMemoryBreak(); | ||
| 61 | |||
| 62 | /// Read and handle packet from gdb client. | ||
| 63 | void HandlePacket(); | ||
| 64 | |||
| 65 | /** | ||
| 66 | * Get the nearest breakpoint of the specified type at the given address. | ||
| 67 | * | ||
| 68 | * @param addr Address to search from. | ||
| 69 | * @param type Type of breakpoint. | ||
| 70 | */ | ||
| 71 | BreakpointAddress GetNextBreakpointFromAddress(u32 addr, GDBStub::BreakpointType type); | ||
| 72 | |||
| 73 | /** | ||
| 74 | * Check if a breakpoint of the specified type exists at the given address. | ||
| 75 | * | ||
| 76 | * @param addr Address of breakpoint. | ||
| 77 | * @param type Type of breakpoint. | ||
| 78 | */ | ||
| 79 | bool CheckBreakpoint(u32 addr, GDBStub::BreakpointType type); | ||
| 80 | |||
| 81 | // If set to true, the CPU will halt at the beginning of the next CPU loop. | ||
| 82 | bool GetCpuHaltFlag(); | ||
| 83 | |||
| 84 | // If set to true and the CPU is halted, the CPU will step one instruction. | ||
| 85 | bool GetCpuStepFlag(); | ||
| 86 | |||
| 87 | /** | ||
| 88 | * When set to true, the CPU will step one instruction when the CPU is halted next. | ||
| 89 | * | ||
| 90 | * @param is_step | ||
| 91 | */ | ||
| 92 | void SetCpuStepFlag(bool is_step); | ||
| 93 | |||
| 94 | } | ||
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index 5846a161b..3501e45db 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h | |||
| @@ -159,6 +159,14 @@ template<ResultCode func(s32*, u32, s32)> void Wrap() { | |||
| 159 | FuncReturn(retval); | 159 | FuncReturn(retval); |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | template<ResultCode func(s64*, u32, s32)> void Wrap() { | ||
| 163 | s64 param_1 = 0; | ||
| 164 | u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw; | ||
| 165 | Core::g_app_core->SetReg(1, (u32)param_1); | ||
| 166 | Core::g_app_core->SetReg(2, (u32)(param_1 >> 32)); | ||
| 167 | FuncReturn(retval); | ||
| 168 | } | ||
| 169 | |||
| 162 | template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() { | 170 | template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() { |
| 163 | u32 param_1 = 0; | 171 | u32 param_1 = 0; |
| 164 | u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw; | 172 | u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw; |
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index 195286422..5c3c47acf 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp | |||
| @@ -45,30 +45,32 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, | |||
| 45 | 45 | ||
| 46 | // Wait current thread (acquire the arbiter)... | 46 | // Wait current thread (acquire the arbiter)... |
| 47 | case ArbitrationType::WaitIfLessThan: | 47 | case ArbitrationType::WaitIfLessThan: |
| 48 | if ((s32)Memory::Read32(address) <= value) { | 48 | if ((s32)Memory::Read32(address) < value) { |
| 49 | Kernel::WaitCurrentThread_ArbitrateAddress(address); | 49 | Kernel::WaitCurrentThread_ArbitrateAddress(address); |
| 50 | } | 50 | } |
| 51 | break; | 51 | break; |
| 52 | case ArbitrationType::WaitIfLessThanWithTimeout: | 52 | case ArbitrationType::WaitIfLessThanWithTimeout: |
| 53 | if ((s32)Memory::Read32(address) <= value) { | 53 | if ((s32)Memory::Read32(address) < value) { |
| 54 | Kernel::WaitCurrentThread_ArbitrateAddress(address); | 54 | Kernel::WaitCurrentThread_ArbitrateAddress(address); |
| 55 | GetCurrentThread()->WakeAfterDelay(nanoseconds); | 55 | GetCurrentThread()->WakeAfterDelay(nanoseconds); |
| 56 | } | 56 | } |
| 57 | break; | 57 | break; |
| 58 | case ArbitrationType::DecrementAndWaitIfLessThan: | 58 | case ArbitrationType::DecrementAndWaitIfLessThan: |
| 59 | { | 59 | { |
| 60 | s32 memory_value = Memory::Read32(address) - 1; | 60 | s32 memory_value = Memory::Read32(address); |
| 61 | Memory::Write32(address, memory_value); | 61 | if (memory_value < value) { |
| 62 | if (memory_value <= value) { | 62 | // Only change the memory value if the thread should wait |
| 63 | Memory::Write32(address, (s32)memory_value - 1); | ||
| 63 | Kernel::WaitCurrentThread_ArbitrateAddress(address); | 64 | Kernel::WaitCurrentThread_ArbitrateAddress(address); |
| 64 | } | 65 | } |
| 65 | break; | 66 | break; |
| 66 | } | 67 | } |
| 67 | case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout: | 68 | case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout: |
| 68 | { | 69 | { |
| 69 | s32 memory_value = Memory::Read32(address) - 1; | 70 | s32 memory_value = Memory::Read32(address); |
| 70 | Memory::Write32(address, memory_value); | 71 | if (memory_value < value) { |
| 71 | if (memory_value <= value) { | 72 | // Only change the memory value if the thread should wait |
| 73 | Memory::Write32(address, (s32)memory_value - 1); | ||
| 72 | Kernel::WaitCurrentThread_ArbitrateAddress(address); | 74 | Kernel::WaitCurrentThread_ArbitrateAddress(address); |
| 73 | GetCurrentThread()->WakeAfterDelay(nanoseconds); | 75 | GetCurrentThread()->WakeAfterDelay(nanoseconds); |
| 74 | } | 76 | } |
| @@ -82,6 +84,13 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, | |||
| 82 | 84 | ||
| 83 | HLE::Reschedule(__func__); | 85 | HLE::Reschedule(__func__); |
| 84 | 86 | ||
| 87 | // The calls that use a timeout seem to always return a Timeout error even if they did not put the thread to sleep | ||
| 88 | if (type == ArbitrationType::WaitIfLessThanWithTimeout || | ||
| 89 | type == ArbitrationType::DecrementAndWaitIfLessThanWithTimeout) { | ||
| 90 | |||
| 91 | return ResultCode(ErrorDescription::Timeout, ErrorModule::OS, | ||
| 92 | ErrorSummary::StatusChanged, ErrorLevel::Info); | ||
| 93 | } | ||
| 85 | return RESULT_SUCCESS; | 94 | return RESULT_SUCCESS; |
| 86 | } | 95 | } |
| 87 | 96 | ||
diff --git a/src/core/hle/kernel/memory.cpp b/src/core/hle/kernel/memory.cpp index e4fc5f3c4..0cfb43fc7 100644 --- a/src/core/hle/kernel/memory.cpp +++ b/src/core/hle/kernel/memory.cpp | |||
| @@ -51,6 +51,7 @@ void MemoryInit(u32 mem_type) { | |||
| 51 | for (int i = 0; i < 3; ++i) { | 51 | for (int i = 0; i < 3; ++i) { |
| 52 | memory_regions[i].base = base; | 52 | memory_regions[i].base = base; |
| 53 | memory_regions[i].size = memory_region_sizes[mem_type][i]; | 53 | memory_regions[i].size = memory_region_sizes[mem_type][i]; |
| 54 | memory_regions[i].used = 0; | ||
| 54 | memory_regions[i].linear_heap_memory = std::make_shared<std::vector<u8>>(); | 55 | memory_regions[i].linear_heap_memory = std::make_shared<std::vector<u8>>(); |
| 55 | 56 | ||
| 56 | base += memory_regions[i].size; | 57 | base += memory_regions[i].size; |
| @@ -72,6 +73,7 @@ void MemoryShutdown() { | |||
| 72 | for (auto& region : memory_regions) { | 73 | for (auto& region : memory_regions) { |
| 73 | region.base = 0; | 74 | region.base = 0; |
| 74 | region.size = 0; | 75 | region.size = 0; |
| 76 | region.used = 0; | ||
| 75 | region.linear_heap_memory = nullptr; | 77 | region.linear_heap_memory = nullptr; |
| 76 | } | 78 | } |
| 77 | } | 79 | } |
diff --git a/src/core/hle/kernel/memory.h b/src/core/hle/kernel/memory.h index 36690b091..091c1f89f 100644 --- a/src/core/hle/kernel/memory.h +++ b/src/core/hle/kernel/memory.h | |||
| @@ -17,6 +17,7 @@ class VMManager; | |||
| 17 | struct MemoryRegionInfo { | 17 | struct MemoryRegionInfo { |
| 18 | u32 base; // Not an address, but offset from start of FCRAM | 18 | u32 base; // Not an address, but offset from start of FCRAM |
| 19 | u32 size; | 19 | u32 size; |
| 20 | u32 used; | ||
| 20 | 21 | ||
| 21 | std::shared_ptr<std::vector<u8>> linear_heap_memory; | 22 | std::shared_ptr<std::vector<u8>> linear_heap_memory; |
| 22 | }; | 23 | }; |
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index c2b4963d4..d148efde2 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -111,6 +111,7 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) { | |||
| 111 | segment.offset, segment.size, memory_state).Unwrap(); | 111 | segment.offset, segment.size, memory_state).Unwrap(); |
| 112 | vm_manager.Reprotect(vma, permissions); | 112 | vm_manager.Reprotect(vma, permissions); |
| 113 | misc_memory_used += segment.size; | 113 | misc_memory_used += segment.size; |
| 114 | memory_region->used += segment.size; | ||
| 114 | }; | 115 | }; |
| 115 | 116 | ||
| 116 | // Map CodeSet segments | 117 | // Map CodeSet segments |
| @@ -123,6 +124,7 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) { | |||
| 123 | std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, MemoryState::Locked | 124 | std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, MemoryState::Locked |
| 124 | ).Unwrap(); | 125 | ).Unwrap(); |
| 125 | misc_memory_used += stack_size; | 126 | misc_memory_used += stack_size; |
| 127 | memory_region->used += stack_size; | ||
| 126 | 128 | ||
| 127 | vm_manager.LogLayout(Log::Level::Debug); | 129 | vm_manager.LogLayout(Log::Level::Debug); |
| 128 | Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority); | 130 | Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority); |
| @@ -165,6 +167,7 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission per | |||
| 165 | vm_manager.Reprotect(vma, perms); | 167 | vm_manager.Reprotect(vma, perms); |
| 166 | 168 | ||
| 167 | heap_used += size; | 169 | heap_used += size; |
| 170 | memory_region->used += size; | ||
| 168 | 171 | ||
| 169 | return MakeResult<VAddr>(heap_end - size); | 172 | return MakeResult<VAddr>(heap_end - size); |
| 170 | } | 173 | } |
| @@ -182,6 +185,7 @@ ResultCode Process::HeapFree(VAddr target, u32 size) { | |||
| 182 | if (result.IsError()) return result; | 185 | if (result.IsError()) return result; |
| 183 | 186 | ||
| 184 | heap_used -= size; | 187 | heap_used -= size; |
| 188 | memory_region->used -= size; | ||
| 185 | 189 | ||
| 186 | return RESULT_SUCCESS; | 190 | return RESULT_SUCCESS; |
| 187 | } | 191 | } |
| @@ -217,6 +221,7 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p | |||
| 217 | vm_manager.Reprotect(vma, perms); | 221 | vm_manager.Reprotect(vma, perms); |
| 218 | 222 | ||
| 219 | linear_heap_used += size; | 223 | linear_heap_used += size; |
| 224 | memory_region->used += size; | ||
| 220 | 225 | ||
| 221 | return MakeResult<VAddr>(target); | 226 | return MakeResult<VAddr>(target); |
| 222 | } | 227 | } |
| @@ -243,6 +248,7 @@ ResultCode Process::LinearFree(VAddr target, u32 size) { | |||
| 243 | if (result.IsError()) return result; | 248 | if (result.IsError()) return result; |
| 244 | 249 | ||
| 245 | linear_heap_used -= size; | 250 | linear_heap_used -= size; |
| 251 | memory_region->used -= size; | ||
| 246 | 252 | ||
| 247 | if (target + size == heap_end) { | 253 | if (target + size == heap_end) { |
| 248 | // End of linear heap has been freed, so check what's the last allocated block in it and | 254 | // End of linear heap has been freed, so check what's the last allocated block in it and |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 00fa995f6..bf32f653d 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include "core/hle/kernel/kernel.h" | 20 | #include "core/hle/kernel/kernel.h" |
| 21 | #include "core/hle/kernel/process.h" | 21 | #include "core/hle/kernel/process.h" |
| 22 | #include "core/hle/kernel/thread.h" | 22 | #include "core/hle/kernel/thread.h" |
| 23 | #include "core/hle/kernel/memory.h" | ||
| 23 | #include "core/hle/kernel/mutex.h" | 24 | #include "core/hle/kernel/mutex.h" |
| 24 | #include "core/hle/result.h" | 25 | #include "core/hle/result.h" |
| 25 | #include "core/memory.h" | 26 | #include "core/memory.h" |
| @@ -118,6 +119,7 @@ void Thread::Stop() { | |||
| 118 | 119 | ||
| 119 | Kernel::g_current_process->used_tls_slots[tls_index] = false; | 120 | Kernel::g_current_process->used_tls_slots[tls_index] = false; |
| 120 | g_current_process->misc_memory_used -= Memory::TLS_ENTRY_SIZE; | 121 | g_current_process->misc_memory_used -= Memory::TLS_ENTRY_SIZE; |
| 122 | g_current_process->memory_region->used -= Memory::TLS_ENTRY_SIZE; | ||
| 121 | 123 | ||
| 122 | HLE::Reschedule(__func__); | 124 | HLE::Reschedule(__func__); |
| 123 | } | 125 | } |
| @@ -298,7 +300,7 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { | |||
| 298 | 300 | ||
| 299 | thread->waitsynch_waited = false; | 301 | thread->waitsynch_waited = false; |
| 300 | 302 | ||
| 301 | if (thread->status == THREADSTATUS_WAIT_SYNCH) { | 303 | if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) { |
| 302 | thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, | 304 | thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, |
| 303 | ErrorSummary::StatusChanged, ErrorLevel::Info)); | 305 | ErrorSummary::StatusChanged, ErrorLevel::Info)); |
| 304 | 306 | ||
| @@ -416,6 +418,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, | |||
| 416 | 418 | ||
| 417 | ASSERT_MSG(thread->tls_index != -1, "Out of TLS space"); | 419 | ASSERT_MSG(thread->tls_index != -1, "Out of TLS space"); |
| 418 | g_current_process->misc_memory_used += Memory::TLS_ENTRY_SIZE; | 420 | g_current_process->misc_memory_used += Memory::TLS_ENTRY_SIZE; |
| 421 | g_current_process->memory_region->used += Memory::TLS_ENTRY_SIZE; | ||
| 419 | 422 | ||
| 420 | // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used | 423 | // TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used |
| 421 | // to initialize the context | 424 | // to initialize the context |
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp index 08b3ea8c0..ce6bbd719 100644 --- a/src/core/hle/kernel/timer.cpp +++ b/src/core/hle/kernel/timer.cpp | |||
| @@ -42,6 +42,9 @@ bool Timer::ShouldWait() { | |||
| 42 | 42 | ||
| 43 | void Timer::Acquire() { | 43 | void Timer::Acquire() { |
| 44 | ASSERT_MSG( !ShouldWait(), "object unavailable!"); | 44 | ASSERT_MSG( !ShouldWait(), "object unavailable!"); |
| 45 | |||
| 46 | if (reset_type == RESETTYPE_ONESHOT) | ||
| 47 | signaled = false; | ||
| 45 | } | 48 | } |
| 46 | 49 | ||
| 47 | void Timer::Set(s64 initial, s64 interval) { | 50 | void Timer::Set(s64 initial, s64 interval) { |
| @@ -84,9 +87,6 @@ static void TimerCallback(u64 timer_handle, int cycles_late) { | |||
| 84 | // Resume all waiting threads | 87 | // Resume all waiting threads |
| 85 | timer->WakeupAllWaitingThreads(); | 88 | timer->WakeupAllWaitingThreads(); |
| 86 | 89 | ||
| 87 | if (timer->reset_type == RESETTYPE_ONESHOT) | ||
| 88 | timer->signaled = false; | ||
| 89 | |||
| 90 | if (timer->interval_delay != 0) { | 90 | if (timer->interval_delay != 0) { |
| 91 | // Reschedule the timer with the interval delay | 91 | // Reschedule the timer with the interval delay |
| 92 | u64 interval_microseconds = timer->interval_delay / 1000; | 92 | u64 interval_microseconds = timer->interval_delay / 1000; |
diff --git a/src/core/hle/service/act_u.cpp b/src/core/hle/service/act_u.cpp index 57f49c91f..bbe8e1625 100644 --- a/src/core/hle/service/act_u.cpp +++ b/src/core/hle/service/act_u.cpp | |||
| @@ -10,14 +10,15 @@ | |||
| 10 | 10 | ||
| 11 | namespace ACT_U { | 11 | namespace ACT_U { |
| 12 | 12 | ||
| 13 | // Empty arrays are illegal -- commented out until an entry is added. | 13 | const Interface::FunctionInfo FunctionTable[] = { |
| 14 | //const Interface::FunctionInfo FunctionTable[] = { }; | 14 | {0x000600C2, nullptr, "GetAccountDataBlock"}, |
| 15 | }; | ||
| 15 | 16 | ||
| 16 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 17 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 17 | // Interface class | 18 | // Interface class |
| 18 | 19 | ||
| 19 | Interface::Interface() { | 20 | Interface::Interface() { |
| 20 | //Register(FunctionTable); | 21 | Register(FunctionTable); |
| 21 | } | 22 | } |
| 22 | 23 | ||
| 23 | } // namespace | 24 | } // namespace |
diff --git a/src/core/hle/service/am/am_net.cpp b/src/core/hle/service/am/am_net.cpp index aa391f3b2..7515a4e6e 100644 --- a/src/core/hle/service/am/am_net.cpp +++ b/src/core/hle/service/am/am_net.cpp | |||
| @@ -10,6 +10,36 @@ namespace Service { | |||
| 10 | namespace AM { | 10 | namespace AM { |
| 11 | 11 | ||
| 12 | const Interface::FunctionInfo FunctionTable[] = { | 12 | const Interface::FunctionInfo FunctionTable[] = { |
| 13 | {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"}, | ||
| 14 | {0x00020082, GetTitleIDList, "GetTitleIDList"}, | ||
| 15 | {0x00030084, nullptr, "ListTitles"}, | ||
| 16 | {0x000400C0, nullptr, "DeleteApplicationTitle"}, | ||
| 17 | {0x000500C0, nullptr, "GetTitleProductCode"}, | ||
| 18 | {0x00080000, nullptr, "TitleIDListGetTotal3"}, | ||
| 19 | {0x00090082, nullptr, "GetTitleIDList3"}, | ||
| 20 | {0x000A0000, nullptr, "GetDeviceID"}, | ||
| 21 | {0x000D0084, nullptr, "ListTitles2"}, | ||
| 22 | {0x00140040, nullptr, "FinishInstallToMedia"}, | ||
| 23 | {0x00180080, nullptr, "InitializeTitleDatabase"}, | ||
| 24 | {0x00190040, nullptr, "ReloadDBS"}, | ||
| 25 | {0x001A00C0, nullptr, "GetDSiWareExportSize"}, | ||
| 26 | {0x001B0144, nullptr, "ExportDSiWare"}, | ||
| 27 | {0x001C0084, nullptr, "ImportDSiWare"}, | ||
| 28 | {0x00230080, nullptr, "TitleIDListGetTotal2"}, | ||
| 29 | {0x002400C2, nullptr, "GetTitleIDList2"}, | ||
| 30 | {0x04010080, nullptr, "InstallFIRM"}, | ||
| 31 | {0x04020040, nullptr, "StartInstallCIADB0"}, | ||
| 32 | {0x04030000, nullptr, "StartInstallCIADB1"}, | ||
| 33 | {0x04040002, nullptr, "AbortCIAInstall"}, | ||
| 34 | {0x04050002, nullptr, "CloseCIAFinalizeInstall"}, | ||
| 35 | {0x04060002, nullptr, "CloseCIA"}, | ||
| 36 | {0x040700C2, nullptr, "FinalizeTitlesInstall"}, | ||
| 37 | {0x04080042, nullptr, "GetCiaFileInfo"}, | ||
| 38 | {0x040E00C2, nullptr, "InstallTitlesFinish"}, | ||
| 39 | {0x040F0000, nullptr, "InstallNATIVEFIRM"}, | ||
| 40 | {0x041000C0, nullptr, "DeleteTitle"}, | ||
| 41 | {0x04120000, nullptr, "Initialize"}, | ||
| 42 | {0x041700C0, nullptr, "MigrateAGBtoSAV"}, | ||
| 13 | {0x08010000, nullptr, "OpenTicket"}, | 43 | {0x08010000, nullptr, "OpenTicket"}, |
| 14 | {0x08020002, nullptr, "TicketAbortInstall"}, | 44 | {0x08020002, nullptr, "TicketAbortInstall"}, |
| 15 | {0x08030002, nullptr, "TicketFinalizeInstall"}, | 45 | {0x08030002, nullptr, "TicketFinalizeInstall"}, |
diff --git a/src/core/hle/service/am/am_sys.cpp b/src/core/hle/service/am/am_sys.cpp index 864fc14df..715b7b55d 100644 --- a/src/core/hle/service/am/am_sys.cpp +++ b/src/core/hle/service/am/am_sys.cpp | |||
| @@ -12,6 +12,21 @@ namespace AM { | |||
| 12 | const Interface::FunctionInfo FunctionTable[] = { | 12 | const Interface::FunctionInfo FunctionTable[] = { |
| 13 | {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"}, | 13 | {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"}, |
| 14 | {0x00020082, GetTitleIDList, "GetTitleIDList"}, | 14 | {0x00020082, GetTitleIDList, "GetTitleIDList"}, |
| 15 | {0x00030084, nullptr, "ListTitles"}, | ||
| 16 | {0x000400C0, nullptr, "DeleteApplicationTitle"}, | ||
| 17 | {0x000500C0, nullptr, "GetTitleProductCode"}, | ||
| 18 | {0x00080000, nullptr, "TitleIDListGetTotal3"}, | ||
| 19 | {0x00090082, nullptr, "GetTitleIDList3"}, | ||
| 20 | {0x000A0000, nullptr, "GetDeviceID"}, | ||
| 21 | {0x000D0084, nullptr, "ListTitles2"}, | ||
| 22 | {0x00140040, nullptr, "FinishInstallToMedia"}, | ||
| 23 | {0x00180080, nullptr, "InitializeTitleDatabase"}, | ||
| 24 | {0x00190040, nullptr, "ReloadDBS"}, | ||
| 25 | {0x001A00C0, nullptr, "GetDSiWareExportSize"}, | ||
| 26 | {0x001B0144, nullptr, "ExportDSiWare"}, | ||
| 27 | {0x001C0084, nullptr, "ImportDSiWare"}, | ||
| 28 | {0x00230080, nullptr, "TitleIDListGetTotal2"}, | ||
| 29 | {0x002400C2, nullptr, "GetTitleIDList2"} | ||
| 15 | }; | 30 | }; |
| 16 | 31 | ||
| 17 | AM_SYS_Interface::AM_SYS_Interface() { | 32 | AM_SYS_Interface::AM_SYS_Interface() { |
diff --git a/src/core/hle/service/am/am_u.cpp b/src/core/hle/service/am/am_u.cpp index 6bf84b36b..b1e1ea5e4 100644 --- a/src/core/hle/service/am/am_u.cpp +++ b/src/core/hle/service/am/am_u.cpp | |||
| @@ -12,6 +12,34 @@ namespace AM { | |||
| 12 | const Interface::FunctionInfo FunctionTable[] = { | 12 | const Interface::FunctionInfo FunctionTable[] = { |
| 13 | {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"}, | 13 | {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"}, |
| 14 | {0x00020082, GetTitleIDList, "GetTitleIDList"}, | 14 | {0x00020082, GetTitleIDList, "GetTitleIDList"}, |
| 15 | {0x00030084, nullptr, "ListTitles"}, | ||
| 16 | {0x000400C0, nullptr, "DeleteApplicationTitle"}, | ||
| 17 | {0x000500C0, nullptr, "GetTitleProductCode"}, | ||
| 18 | {0x00080000, nullptr, "TitleIDListGetTotal3"}, | ||
| 19 | {0x00090082, nullptr, "GetTitleIDList3"}, | ||
| 20 | {0x000A0000, nullptr, "GetDeviceID"}, | ||
| 21 | {0x000D0084, nullptr, "ListTitles2"}, | ||
| 22 | {0x00140040, nullptr, "FinishInstallToMedia"}, | ||
| 23 | {0x00180080, nullptr, "InitializeTitleDatabase"}, | ||
| 24 | {0x00190040, nullptr, "ReloadDBS"}, | ||
| 25 | {0x001A00C0, nullptr, "GetDSiWareExportSize"}, | ||
| 26 | {0x001B0144, nullptr, "ExportDSiWare"}, | ||
| 27 | {0x001C0084, nullptr, "ImportDSiWare"}, | ||
| 28 | {0x00230080, nullptr, "TitleIDListGetTotal2"}, | ||
| 29 | {0x002400C2, nullptr, "GetTitleIDList2"}, | ||
| 30 | {0x04010080, nullptr, "InstallFIRM"}, | ||
| 31 | {0x04020040, nullptr, "StartInstallCIADB0"}, | ||
| 32 | {0x04030000, nullptr, "StartInstallCIADB1"}, | ||
| 33 | {0x04040002, nullptr, "AbortCIAInstall"}, | ||
| 34 | {0x04050002, nullptr, "CloseCIAFinalizeInstall"}, | ||
| 35 | {0x04060002, nullptr, "CloseCIA"}, | ||
| 36 | {0x040700C2, nullptr, "FinalizeTitlesInstall"}, | ||
| 37 | {0x04080042, nullptr, "GetCiaFileInfo"}, | ||
| 38 | {0x040E00C2, nullptr, "InstallTitlesFinish"}, | ||
| 39 | {0x040F0000, nullptr, "InstallNATIVEFIRM"}, | ||
| 40 | {0x041000C0, nullptr, "DeleteTitle"}, | ||
| 41 | {0x04120000, nullptr, "Initialize"}, | ||
| 42 | {0x041700C0, nullptr, "MigrateAGBtoSAV"} | ||
| 15 | }; | 43 | }; |
| 16 | 44 | ||
| 17 | AM_U_Interface::AM_U_Interface() { | 45 | AM_U_Interface::AM_U_Interface() { |
diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp index 3ac6ff94f..e5fd9165c 100644 --- a/src/core/hle/service/apt/apt_s.cpp +++ b/src/core/hle/service/apt/apt_s.cpp | |||
| @@ -91,6 +91,12 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 91 | {0x004E0000, nullptr, "HardwareResetAsync"}, | 91 | {0x004E0000, nullptr, "HardwareResetAsync"}, |
| 92 | {0x004F0080, nullptr, "SetApplicationCpuTimeLimit"}, | 92 | {0x004F0080, nullptr, "SetApplicationCpuTimeLimit"}, |
| 93 | {0x00500040, nullptr, "GetApplicationCpuTimeLimit"}, | 93 | {0x00500040, nullptr, "GetApplicationCpuTimeLimit"}, |
| 94 | {0x00510080, nullptr, "GetStartupArgument"}, | ||
| 95 | {0x00520104, nullptr, "Wrap1"}, | ||
| 96 | {0x00530104, nullptr, "Unwrap1"}, | ||
| 97 | {0x00580002, nullptr, "GetProgramID"}, | ||
| 98 | {0x01010000, nullptr, "CheckNew3DSApp"}, | ||
| 99 | {0x01020000, nullptr, "CheckNew3DS"} | ||
| 94 | }; | 100 | }; |
| 95 | 101 | ||
| 96 | APT_S_Interface::APT_S_Interface() { | 102 | APT_S_Interface::APT_S_Interface() { |
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp index 146bfd595..aba627f54 100644 --- a/src/core/hle/service/apt/apt_u.cpp +++ b/src/core/hle/service/apt/apt_u.cpp | |||
| @@ -92,6 +92,12 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 92 | {0x004E0000, nullptr, "HardwareResetAsync"}, | 92 | {0x004E0000, nullptr, "HardwareResetAsync"}, |
| 93 | {0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, | 93 | {0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, |
| 94 | {0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, | 94 | {0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, |
| 95 | {0x00510080, nullptr, "GetStartupArgument"}, | ||
| 96 | {0x00520104, nullptr, "Wrap1"}, | ||
| 97 | {0x00530104, nullptr, "Unwrap1"}, | ||
| 98 | {0x00580002, nullptr, "GetProgramID"}, | ||
| 99 | {0x01010000, nullptr, "CheckNew3DSApp"}, | ||
| 100 | {0x01020000, nullptr, "CheckNew3DS"} | ||
| 95 | }; | 101 | }; |
| 96 | 102 | ||
| 97 | APT_U_Interface::APT_U_Interface() { | 103 | APT_U_Interface::APT_U_Interface() { |
diff --git a/src/core/hle/service/boss/boss_u.cpp b/src/core/hle/service/boss/boss_u.cpp index ed978b963..9f17711bb 100644 --- a/src/core/hle/service/boss/boss_u.cpp +++ b/src/core/hle/service/boss/boss_u.cpp | |||
| @@ -11,6 +11,9 @@ namespace BOSS { | |||
| 11 | 11 | ||
| 12 | const Interface::FunctionInfo FunctionTable[] = { | 12 | const Interface::FunctionInfo FunctionTable[] = { |
| 13 | {0x00020100, nullptr, "GetStorageInfo"}, | 13 | {0x00020100, nullptr, "GetStorageInfo"}, |
| 14 | {0x000C0082, nullptr, "UnregisterTask"}, | ||
| 15 | {0x001E0042, nullptr, "CancelTask"}, | ||
| 16 | {0x00330042, nullptr, "StartBgImmediate"}, | ||
| 14 | }; | 17 | }; |
| 15 | 18 | ||
| 16 | BOSS_U_Interface::BOSS_U_Interface() { | 19 | BOSS_U_Interface::BOSS_U_Interface() { |
diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h index edd524841..e9abdcb1f 100644 --- a/src/core/hle/service/cam/cam.h +++ b/src/core/hle/service/cam/cam.h | |||
| @@ -10,6 +10,162 @@ | |||
| 10 | namespace Service { | 10 | namespace Service { |
| 11 | namespace CAM { | 11 | namespace CAM { |
| 12 | 12 | ||
| 13 | enum class Port : u8 { | ||
| 14 | None = 0, | ||
| 15 | Cam1 = 1, | ||
| 16 | Cam2 = 2, | ||
| 17 | Both = Cam1 | Cam2 | ||
| 18 | }; | ||
| 19 | |||
| 20 | enum class CameraSelect : u8 { | ||
| 21 | None = 0, | ||
| 22 | Out1 = 1, | ||
| 23 | In1 = 2, | ||
| 24 | Out2 = 4, | ||
| 25 | In1Out1 = Out1 | In1, | ||
| 26 | Out1Out2 = Out1 | Out2, | ||
| 27 | In1Out2 = In1 | Out2, | ||
| 28 | All = Out1 | In1 | Out2 | ||
| 29 | }; | ||
| 30 | |||
| 31 | enum class Effect : u8 { | ||
| 32 | None = 0, | ||
| 33 | Mono = 1, | ||
| 34 | Sepia = 2, | ||
| 35 | Negative = 3, | ||
| 36 | Negafilm = 4, | ||
| 37 | Sepia01 = 5 | ||
| 38 | }; | ||
| 39 | |||
| 40 | enum class Context : u8 { | ||
| 41 | None = 0, | ||
| 42 | A = 1, | ||
| 43 | B = 2, | ||
| 44 | Both = A | B | ||
| 45 | }; | ||
| 46 | |||
| 47 | enum class Flip : u8 { | ||
| 48 | None = 0, | ||
| 49 | Horizontal = 1, | ||
| 50 | Vertical = 2, | ||
| 51 | Reverse = 3 | ||
| 52 | }; | ||
| 53 | |||
| 54 | enum class Size : u8 { | ||
| 55 | VGA = 0, | ||
| 56 | QVGA = 1, | ||
| 57 | QQVGA = 2, | ||
| 58 | CIF = 3, | ||
| 59 | QCIF = 4, | ||
| 60 | DS_LCD = 5, | ||
| 61 | DS_LCDx4 = 6, | ||
| 62 | CTR_TOP_LCD = 7, | ||
| 63 | CTR_BOTTOM_LCD = QVGA | ||
| 64 | }; | ||
| 65 | |||
| 66 | enum class FrameRate : u8 { | ||
| 67 | Rate_15 = 0, | ||
| 68 | Rate_15_To_5 = 1, | ||
| 69 | Rate_15_To_2 = 2, | ||
| 70 | Rate_10 = 3, | ||
| 71 | Rate_8_5 = 4, | ||
| 72 | Rate_5 = 5, | ||
| 73 | Rate_20 = 6, | ||
| 74 | Rate_20_To_5 = 7, | ||
| 75 | Rate_30 = 8, | ||
| 76 | Rate_30_To_5 = 9, | ||
| 77 | Rate_15_To_10 = 10, | ||
| 78 | Rate_20_To_10 = 11, | ||
| 79 | Rate_30_To_10 = 12 | ||
| 80 | }; | ||
| 81 | |||
| 82 | enum class ShutterSoundType : u8 { | ||
| 83 | Normal = 0, | ||
| 84 | Movie = 1, | ||
| 85 | MovieEnd = 2 | ||
| 86 | }; | ||
| 87 | |||
| 88 | enum class WhiteBalance : u8 { | ||
| 89 | BalanceAuto = 0, | ||
| 90 | Balance3200K = 1, | ||
| 91 | Balance4150K = 2, | ||
| 92 | Balance5200K = 3, | ||
| 93 | Balance6000K = 4, | ||
| 94 | Balance7000K = 5, | ||
| 95 | BalanceMax = 6, | ||
| 96 | BalanceNormal = BalanceAuto, | ||
| 97 | BalanceTungsten = Balance3200K, | ||
| 98 | BalanceWhiteFluorescentLight = Balance4150K, | ||
| 99 | BalanceDaylight = Balance5200K, | ||
| 100 | BalanceCloudy = Balance6000K, | ||
| 101 | BalanceHorizon = Balance6000K, | ||
| 102 | BalanceShade = Balance7000K | ||
| 103 | }; | ||
| 104 | |||
| 105 | enum class PhotoMode : u8 { | ||
| 106 | Normal = 0, | ||
| 107 | Portrait = 1, | ||
| 108 | Landscape = 2, | ||
| 109 | Nightview = 3, | ||
| 110 | Letter0 = 4 | ||
| 111 | }; | ||
| 112 | |||
| 113 | enum class LensCorrection : u8 { | ||
| 114 | Off = 0, | ||
| 115 | On70 = 1, | ||
| 116 | On90 = 2, | ||
| 117 | Dark = Off, | ||
| 118 | Normal = On70, | ||
| 119 | Bright = On90 | ||
| 120 | }; | ||
| 121 | |||
| 122 | enum class Contrast : u8 { | ||
| 123 | Pattern01 = 1, | ||
| 124 | Pattern02 = 2, | ||
| 125 | Pattern03 = 3, | ||
| 126 | Pattern04 = 4, | ||
| 127 | Pattern05 = 5, | ||
| 128 | Pattern06 = 6, | ||
| 129 | Pattern07 = 7, | ||
| 130 | Pattern08 = 8, | ||
| 131 | Pattern09 = 9, | ||
| 132 | Pattern10 = 10, | ||
| 133 | Pattern11 = 11, | ||
| 134 | Low = Pattern05, | ||
| 135 | Normal = Pattern06, | ||
| 136 | High = Pattern07 | ||
| 137 | }; | ||
| 138 | |||
| 139 | enum class OutputFormat : u8 { | ||
| 140 | YUV422 = 0, | ||
| 141 | RGB565 = 1 | ||
| 142 | }; | ||
| 143 | |||
| 144 | struct PackageParameterCameraSelect { | ||
| 145 | CameraSelect camera; | ||
| 146 | s8 exposure; | ||
| 147 | WhiteBalance white_balance; | ||
| 148 | s8 sharpness; | ||
| 149 | bool auto_exposure; | ||
| 150 | bool auto_white_balance; | ||
| 151 | FrameRate frame_rate; | ||
| 152 | PhotoMode photo_mode; | ||
| 153 | Contrast contrast; | ||
| 154 | LensCorrection lens_correction; | ||
| 155 | bool noise_filter; | ||
| 156 | u8 padding; | ||
| 157 | s16 auto_exposure_window_x; | ||
| 158 | s16 auto_exposure_window_y; | ||
| 159 | s16 auto_exposure_window_width; | ||
| 160 | s16 auto_exposure_window_height; | ||
| 161 | s16 auto_white_balance_window_x; | ||
| 162 | s16 auto_white_balance_window_y; | ||
| 163 | s16 auto_white_balance_window_width; | ||
| 164 | s16 auto_white_balance_window_height; | ||
| 165 | }; | ||
| 166 | |||
| 167 | static_assert(sizeof(PackageParameterCameraSelect) == 28, "PackageParameterCameraSelect structure size is wrong"); | ||
| 168 | |||
| 13 | /// Initialize CAM service(s) | 169 | /// Initialize CAM service(s) |
| 14 | void Init(); | 170 | void Init(); |
| 15 | 171 | ||
diff --git a/src/core/hle/service/cam/cam_u.cpp b/src/core/hle/service/cam/cam_u.cpp index 55083e0c7..1c292ea23 100644 --- a/src/core/hle/service/cam/cam_u.cpp +++ b/src/core/hle/service/cam/cam_u.cpp | |||
| @@ -54,12 +54,17 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 54 | {0x002A0080, nullptr, "GetLatestVsyncTiming"}, | 54 | {0x002A0080, nullptr, "GetLatestVsyncTiming"}, |
| 55 | {0x002B0000, nullptr, "GetStereoCameraCalibrationData"}, | 55 | {0x002B0000, nullptr, "GetStereoCameraCalibrationData"}, |
| 56 | {0x002C0400, nullptr, "SetStereoCameraCalibrationData"}, | 56 | {0x002C0400, nullptr, "SetStereoCameraCalibrationData"}, |
| 57 | {0x002D00C0, nullptr, "WriteRegisterI2c"}, | ||
| 58 | {0x002E00C0, nullptr, "WriteMcuVariableI2c"}, | ||
| 59 | {0x002F0080, nullptr, "ReadRegisterI2cExclusive"}, | ||
| 60 | {0x00300080, nullptr, "ReadMcuVariableI2cExclusive"}, | ||
| 57 | {0x00310180, nullptr, "SetImageQualityCalibrationData"}, | 61 | {0x00310180, nullptr, "SetImageQualityCalibrationData"}, |
| 58 | {0x00320000, nullptr, "GetImageQualityCalibrationData"}, | 62 | {0x00320000, nullptr, "GetImageQualityCalibrationData"}, |
| 59 | {0x003302C0, nullptr, "SetPackageParameterWithoutContext"}, | 63 | {0x003302C0, nullptr, "SetPackageParameterWithoutContext"}, |
| 60 | {0x00340140, nullptr, "SetPackageParameterWithContext"}, | 64 | {0x00340140, nullptr, "SetPackageParameterWithContext"}, |
| 61 | {0x003501C0, nullptr, "SetPackageParameterWithContextDetail"}, | 65 | {0x003501C0, nullptr, "SetPackageParameterWithContextDetail"}, |
| 62 | {0x00360000, nullptr, "GetSuitableY2rStandardCoefficient"}, | 66 | {0x00360000, nullptr, "GetSuitableY2rStandardCoefficient"}, |
| 67 | {0x00370202, nullptr, "PlayShutterSoundWithWave"}, | ||
| 63 | {0x00380040, nullptr, "PlayShutterSound"}, | 68 | {0x00380040, nullptr, "PlayShutterSound"}, |
| 64 | {0x00390000, nullptr, "DriverInitialize"}, | 69 | {0x00390000, nullptr, "DriverInitialize"}, |
| 65 | {0x003A0000, nullptr, "DriverFinalize"}, | 70 | {0x003A0000, nullptr, "DriverFinalize"}, |
diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp index 6a1d961ac..6318bf2a7 100644 --- a/src/core/hle/service/csnd_snd.cpp +++ b/src/core/hle/service/csnd_snd.cpp | |||
| @@ -2,7 +2,10 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <cstring> | ||
| 5 | #include "core/hle/hle.h" | 6 | #include "core/hle/hle.h" |
| 7 | #include "core/hle/kernel/mutex.h" | ||
| 8 | #include "core/hle/kernel/shared_memory.h" | ||
| 6 | #include "core/hle/service/csnd_snd.h" | 9 | #include "core/hle/service/csnd_snd.h" |
| 7 | 10 | ||
| 8 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 11 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -11,17 +14,18 @@ | |||
| 11 | namespace CSND_SND { | 14 | namespace CSND_SND { |
| 12 | 15 | ||
| 13 | const Interface::FunctionInfo FunctionTable[] = { | 16 | const Interface::FunctionInfo FunctionTable[] = { |
| 14 | {0x00010140, nullptr, "Initialize"}, | 17 | {0x00010140, Initialize, "Initialize"}, |
| 15 | {0x00020000, nullptr, "Shutdown"}, | 18 | {0x00020000, Shutdown, "Shutdown"}, |
| 16 | {0x00030040, nullptr, "ExecuteType0Commands"}, | 19 | {0x00030040, ExecuteType0Commands, "ExecuteType0Commands"}, |
| 17 | {0x00040080, nullptr, "ExecuteType1Commands"}, | 20 | {0x00040080, nullptr, "ExecuteType1Commands"}, |
| 18 | {0x00050000, nullptr, "AcquireSoundChannels"}, | 21 | {0x00050000, AcquireSoundChannels, "AcquireSoundChannels"}, |
| 19 | {0x00060000, nullptr, "ReleaseSoundChannels"}, | 22 | {0x00060000, nullptr, "ReleaseSoundChannels"}, |
| 20 | {0x00070000, nullptr, "AcquireCaptureDevice"}, | 23 | {0x00070000, nullptr, "AcquireCaptureDevice"}, |
| 21 | {0x00080040, nullptr, "ReleaseCaptureDevice"}, | 24 | {0x00080040, nullptr, "ReleaseCaptureDevice"}, |
| 22 | {0x00090082, nullptr, "FlushDCache"}, | 25 | {0x00090082, nullptr, "FlushDataCache"}, |
| 23 | {0x000A0082, nullptr, "StoreDCache"}, | 26 | {0x000A0082, nullptr, "StoreDataCache"}, |
| 24 | {0x000B0082, nullptr, "InvalidateDCache"}, | 27 | {0x000B0082, nullptr, "InvalidateDataCache"}, |
| 28 | {0x000C0000, nullptr, "Reset"}, | ||
| 25 | }; | 29 | }; |
| 26 | 30 | ||
| 27 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 31 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| @@ -31,4 +35,51 @@ Interface::Interface() { | |||
| 31 | Register(FunctionTable); | 35 | Register(FunctionTable); |
| 32 | } | 36 | } |
| 33 | 37 | ||
| 38 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory = nullptr; | ||
| 39 | static Kernel::SharedPtr<Kernel::Mutex> mutex = nullptr; | ||
| 40 | |||
| 41 | void Initialize(Service::Interface* self) { | ||
| 42 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 43 | |||
| 44 | shared_memory = Kernel::SharedMemory::Create(cmd_buff[1], | ||
| 45 | Kernel::MemoryPermission::ReadWrite, | ||
| 46 | Kernel::MemoryPermission::ReadWrite, "CSNDSharedMem"); | ||
| 47 | |||
| 48 | mutex = Kernel::Mutex::Create(false); | ||
| 49 | |||
| 50 | cmd_buff[1] = 0; | ||
| 51 | cmd_buff[2] = 0x4000000; | ||
| 52 | cmd_buff[3] = Kernel::g_handle_table.Create(mutex).MoveFrom(); | ||
| 53 | cmd_buff[4] = Kernel::g_handle_table.Create(shared_memory).MoveFrom(); | ||
| 54 | } | ||
| 55 | |||
| 56 | void ExecuteType0Commands(Service::Interface* self) { | ||
| 57 | u32* const cmd_buff = Kernel::GetCommandBuffer(); | ||
| 58 | u8* const ptr = shared_memory->GetPointer(cmd_buff[1]); | ||
| 59 | |||
| 60 | if (shared_memory != nullptr && ptr != nullptr) { | ||
| 61 | Type0Command command; | ||
| 62 | std::memcpy(&command, ptr, sizeof(Type0Command)); | ||
| 63 | |||
| 64 | LOG_WARNING(Service, "(STUBBED) CSND_SND::ExecuteType0Commands"); | ||
| 65 | command.finished |= 1; | ||
| 66 | cmd_buff[1] = 0; | ||
| 67 | |||
| 68 | std::memcpy(ptr, &command, sizeof(Type0Command)); | ||
| 69 | } else { | ||
| 70 | cmd_buff[1] = 1; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | void AcquireSoundChannels(Service::Interface* self) { | ||
| 75 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 76 | cmd_buff[1] = 0; | ||
| 77 | cmd_buff[2] = 0xFFFFFF00; | ||
| 78 | } | ||
| 79 | |||
| 80 | void Shutdown(Service::Interface* self) { | ||
| 81 | shared_memory = nullptr; | ||
| 82 | mutex = nullptr; | ||
| 83 | } | ||
| 84 | |||
| 34 | } // namespace | 85 | } // namespace |
diff --git a/src/core/hle/service/csnd_snd.h b/src/core/hle/service/csnd_snd.h index a84752473..e861f3327 100644 --- a/src/core/hle/service/csnd_snd.h +++ b/src/core/hle/service/csnd_snd.h | |||
| @@ -20,4 +20,17 @@ public: | |||
| 20 | } | 20 | } |
| 21 | }; | 21 | }; |
| 22 | 22 | ||
| 23 | struct Type0Command { | ||
| 24 | // command id and next command offset | ||
| 25 | u32 command_id; | ||
| 26 | u32 finished; | ||
| 27 | u32 flags; | ||
| 28 | u8 parameters[20]; | ||
| 29 | }; | ||
| 30 | |||
| 31 | void Initialize(Service::Interface* self); | ||
| 32 | void ExecuteType0Commands(Service::Interface* self); | ||
| 33 | void AcquireSoundChannels(Service::Interface* self); | ||
| 34 | void Shutdown(Service::Interface* self); | ||
| 35 | |||
| 23 | } // namespace | 36 | } // namespace |
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index ce5619069..d6b8d1318 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp | |||
| @@ -150,13 +150,13 @@ static void RegisterInterruptEvents(Service::Interface* self) { | |||
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | /** | 152 | /** |
| 153 | * DSP_DSP::WriteReg0x10 service function | 153 | * DSP_DSP::SetSemaphore service function |
| 154 | * Inputs: | 154 | * Inputs: |
| 155 | * 1 : Unknown (observed only half word used) | 155 | * 1 : Unknown (observed only half word used) |
| 156 | * Outputs: | 156 | * Outputs: |
| 157 | * 1 : Result of function, 0 on success, otherwise error code | 157 | * 1 : Result of function, 0 on success, otherwise error code |
| 158 | */ | 158 | */ |
| 159 | static void WriteReg0x10(Service::Interface* self) { | 159 | static void SetSemaphore(Service::Interface* self) { |
| 160 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 160 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 161 | 161 | ||
| 162 | SignalInterrupt(); | 162 | SignalInterrupt(); |
| @@ -276,12 +276,17 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 276 | {0x00020040, nullptr, "RecvDataIsReady"}, | 276 | {0x00020040, nullptr, "RecvDataIsReady"}, |
| 277 | {0x00030080, nullptr, "SendData"}, | 277 | {0x00030080, nullptr, "SendData"}, |
| 278 | {0x00040040, nullptr, "SendDataIsEmpty"}, | 278 | {0x00040040, nullptr, "SendDataIsEmpty"}, |
| 279 | {0x00070040, WriteReg0x10, "WriteReg0x10"}, | 279 | {0x000500C2, nullptr, "SendFifoEx"}, |
| 280 | {0x000600C0, nullptr, "RecvFifoEx"}, | ||
| 281 | {0x00070040, SetSemaphore, "SetSemaphore"}, | ||
| 280 | {0x00080000, nullptr, "GetSemaphore"}, | 282 | {0x00080000, nullptr, "GetSemaphore"}, |
| 281 | {0x00090040, nullptr, "ClearSemaphore"}, | 283 | {0x00090040, nullptr, "ClearSemaphore"}, |
| 284 | {0x000A0040, nullptr, "MaskSemaphore"}, | ||
| 282 | {0x000B0000, nullptr, "CheckSemaphoreRequest"}, | 285 | {0x000B0000, nullptr, "CheckSemaphoreRequest"}, |
| 283 | {0x000C0040, ConvertProcessAddressFromDspDram, "ConvertProcessAddressFromDspDram"}, | 286 | {0x000C0040, ConvertProcessAddressFromDspDram, "ConvertProcessAddressFromDspDram"}, |
| 284 | {0x000D0082, WriteProcessPipe, "WriteProcessPipe"}, | 287 | {0x000D0082, WriteProcessPipe, "WriteProcessPipe"}, |
| 288 | {0x000E00C0, nullptr, "ReadPipe"}, | ||
| 289 | {0x000F0080, nullptr, "GetPipeReadableSize"}, | ||
| 285 | {0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"}, | 290 | {0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"}, |
| 286 | {0x001100C2, LoadComponent, "LoadComponent"}, | 291 | {0x001100C2, LoadComponent, "LoadComponent"}, |
| 287 | {0x00120000, nullptr, "UnloadComponent"}, | 292 | {0x00120000, nullptr, "UnloadComponent"}, |
| @@ -295,7 +300,10 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 295 | {0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"}, | 300 | {0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"}, |
| 296 | {0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"}, | 301 | {0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"}, |
| 297 | {0x001C0082, nullptr, "SetIirFilterEQ"}, | 302 | {0x001C0082, nullptr, "SetIirFilterEQ"}, |
| 303 | {0x001D00C0, nullptr, "ReadMultiEx_SPI2"}, | ||
| 304 | {0x001E00C2, nullptr, "WriteMultiEx_SPI2"}, | ||
| 298 | {0x001F0000, GetHeadphoneStatus, "GetHeadphoneStatus"}, | 305 | {0x001F0000, GetHeadphoneStatus, "GetHeadphoneStatus"}, |
| 306 | {0x00200040, nullptr, "ForceHeadphoneOut"}, | ||
| 299 | {0x00210000, nullptr, "GetIsDspOccupied"}, | 307 | {0x00210000, nullptr, "GetIsDspOccupied"}, |
| 300 | }; | 308 | }; |
| 301 | 309 | ||
diff --git a/src/core/hle/service/frd/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp index 3a5897d06..9e70ec901 100644 --- a/src/core/hle/service/frd/frd_u.cpp +++ b/src/core/hle/service/frd/frd_u.cpp | |||
| @@ -11,25 +11,58 @@ namespace FRD { | |||
| 11 | 11 | ||
| 12 | const Interface::FunctionInfo FunctionTable[] = { | 12 | const Interface::FunctionInfo FunctionTable[] = { |
| 13 | {0x00010000, nullptr, "HasLoggedIn"}, | 13 | {0x00010000, nullptr, "HasLoggedIn"}, |
| 14 | {0x00020000, nullptr, "IsOnline"}, | ||
| 14 | {0x00030000, nullptr, "Login"}, | 15 | {0x00030000, nullptr, "Login"}, |
| 15 | {0x00040000, nullptr, "Logout"}, | 16 | {0x00040000, nullptr, "Logout"}, |
| 16 | {0x00050000, nullptr, "GetFriendKey"}, | 17 | {0x00050000, nullptr, "GetMyFriendKey"}, |
| 18 | {0x00060000, nullptr, "GetMyPreference"}, | ||
| 19 | {0x00070000, nullptr, "GetMyProfile"}, | ||
| 17 | {0x00080000, nullptr, "GetMyPresence"}, | 20 | {0x00080000, nullptr, "GetMyPresence"}, |
| 18 | {0x00090000, nullptr, "GetMyScreenName"}, | 21 | {0x00090000, nullptr, "GetMyScreenName"}, |
| 19 | {0x00100040, nullptr, "GetPassword"}, | 22 | {0x000A0000, nullptr, "GetMyMii"}, |
| 23 | {0x000B0000, nullptr, "GetMyLocalAccountId"}, | ||
| 24 | {0x000C0000, nullptr, "GetMyPlayingGame"}, | ||
| 25 | {0x000D0000, nullptr, "GetMyFavoriteGame"}, | ||
| 26 | {0x000E0000, nullptr, "GetMyNcPrincipalId"}, | ||
| 27 | {0x000F0000, nullptr, "GetMyComment"}, | ||
| 28 | {0x00100040, nullptr, "GetMyPassword"}, | ||
| 20 | {0x00110080, nullptr, "GetFriendKeyList"}, | 29 | {0x00110080, nullptr, "GetFriendKeyList"}, |
| 30 | {0x00120042, nullptr, "GetFriendPresence"}, | ||
| 31 | {0x00130142, nullptr, "GetFriendScreenName"}, | ||
| 32 | {0x00140044, nullptr, "GetFriendMii"}, | ||
| 33 | {0x00150042, nullptr, "GetFriendProfile"}, | ||
| 34 | {0x00160042, nullptr, "GetFriendRelationship"}, | ||
| 35 | {0x00170042, nullptr, "GetFriendAttributeFlags"}, | ||
| 36 | {0x00180044, nullptr, "GetFriendPlayingGame"}, | ||
| 21 | {0x00190042, nullptr, "GetFriendFavoriteGame"}, | 37 | {0x00190042, nullptr, "GetFriendFavoriteGame"}, |
| 22 | {0x001A00C4, nullptr, "GetFriendInfo"}, | 38 | {0x001A00C4, nullptr, "GetFriendInfo"}, |
| 23 | {0x001B0080, nullptr, "IsOnFriendList"}, | 39 | {0x001B0080, nullptr, "IsIncludedInFriendList"}, |
| 24 | {0x001C0042, nullptr, "DecodeLocalFriendCode"}, | 40 | {0x001C0042, nullptr, "UnscrambleLocalFriendCode"}, |
| 25 | {0x001D0002, nullptr, "SetCurrentlyPlayingText"}, | 41 | {0x001D0002, nullptr, "UpdateGameModeDescription"}, |
| 42 | {0x001E02C2, nullptr, "UpdateGameMode"}, | ||
| 43 | {0x001F0042, nullptr, "SendInvitation"}, | ||
| 44 | {0x00200002, nullptr, "AttachToEventNotification"}, | ||
| 45 | {0x00210040, nullptr, "SetNotificationMask"}, | ||
| 46 | {0x00220040, nullptr, "GetEventNotification"}, | ||
| 26 | {0x00230000, nullptr, "GetLastResponseResult"}, | 47 | {0x00230000, nullptr, "GetLastResponseResult"}, |
| 48 | {0x00240040, nullptr, "PrincipalIdToFriendCode"}, | ||
| 49 | {0x00250080, nullptr, "FriendCodeToPrincipalId"}, | ||
| 50 | {0x00260080, nullptr, "IsValidFriendCode"}, | ||
| 27 | {0x00270040, nullptr, "ResultToErrorCode"}, | 51 | {0x00270040, nullptr, "ResultToErrorCode"}, |
| 28 | {0x00280244, nullptr, "RequestGameAuthentication"}, | 52 | {0x00280244, nullptr, "RequestGameAuthentication"}, |
| 29 | {0x00290000, nullptr, "GetGameAuthenticationData"}, | 53 | {0x00290000, nullptr, "GetGameAuthenticationData"}, |
| 30 | {0x002A0204, nullptr, "RequestServiceLocator"}, | 54 | {0x002A0204, nullptr, "RequestServiceLocator"}, |
| 31 | {0x002B0000, nullptr, "GetServiceLocatorData"}, | 55 | {0x002B0000, nullptr, "GetServiceLocatorData"}, |
| 56 | {0x002C0002, nullptr, "DetectNatProperties"}, | ||
| 57 | {0x002D0000, nullptr, "GetNatProperties"}, | ||
| 58 | {0x002E0000, nullptr, "GetServerTimeInterval"}, | ||
| 59 | {0x002F0040, nullptr, "AllowHalfAwake"}, | ||
| 60 | {0x00300000, nullptr, "GetServerTypes"}, | ||
| 61 | {0x00310082, nullptr, "GetFriendComment"}, | ||
| 32 | {0x00320042, nullptr, "SetClientSdkVersion"}, | 62 | {0x00320042, nullptr, "SetClientSdkVersion"}, |
| 63 | {0x00330000, nullptr, "GetMyApproachContext"}, | ||
| 64 | {0x00340046, nullptr, "AddFriendWithApproach"}, | ||
| 65 | {0x00350082, nullptr, "DecryptApproachContext"}, | ||
| 33 | }; | 66 | }; |
| 34 | 67 | ||
| 35 | FRD_U_Interface::FRD_U_Interface() { | 68 | FRD_U_Interface::FRD_U_Interface() { |
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 6c0df67c3..d64b3656a 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp | |||
| @@ -403,6 +403,13 @@ ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle a | |||
| 403 | return MakeResult<Kernel::SharedPtr<Directory>>(std::move(directory)); | 403 | return MakeResult<Kernel::SharedPtr<Directory>>(std::move(directory)); |
| 404 | } | 404 | } |
| 405 | 405 | ||
| 406 | ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) { | ||
| 407 | ArchiveBackend* archive = GetArchive(archive_handle); | ||
| 408 | if (archive == nullptr) | ||
| 409 | return ERR_INVALID_HANDLE; | ||
| 410 | return MakeResult<u64>(archive->GetFreeBytes()); | ||
| 411 | } | ||
| 412 | |||
| 406 | ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) { | 413 | ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) { |
| 407 | auto archive_itr = id_code_map.find(id_code); | 414 | auto archive_itr = id_code_map.find(id_code); |
| 408 | if (archive_itr == id_code_map.end()) { | 415 | if (archive_itr == id_code_map.end()) { |
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 6f7048710..952deb4d4 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h | |||
| @@ -167,6 +167,13 @@ ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle a | |||
| 167 | const FileSys::Path& path); | 167 | const FileSys::Path& path); |
| 168 | 168 | ||
| 169 | /** | 169 | /** |
| 170 | * Get the free space in an Archive | ||
| 171 | * @param archive_handle Handle to an open Archive object | ||
| 172 | * @return The number of free bytes in the archive | ||
| 173 | */ | ||
| 174 | ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle); | ||
| 175 | |||
| 176 | /** | ||
| 170 | * Erases the contents of the physical folder that contains the archive | 177 | * Erases the contents of the physical folder that contains the archive |
| 171 | * identified by the specified id code and path | 178 | * identified by the specified id code and path |
| 172 | * @param id_code The id of the archive to format | 179 | * @param id_code The id of the archive to format |
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index ae52083f9..632620a56 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp | |||
| @@ -497,6 +497,33 @@ static void FormatThisUserSaveData(Service::Interface* self) { | |||
| 497 | } | 497 | } |
| 498 | 498 | ||
| 499 | /** | 499 | /** |
| 500 | * FS_User::GetFreeBytes service function | ||
| 501 | * Inputs: | ||
| 502 | * 0: 0x08120080 | ||
| 503 | * 1: Archive handle low word | ||
| 504 | * 2: Archive handle high word | ||
| 505 | * Outputs: | ||
| 506 | * 1: Result of function, 0 on success, otherwise error code | ||
| 507 | * 2: Free byte count low word | ||
| 508 | * 3: Free byte count high word | ||
| 509 | */ | ||
| 510 | static void GetFreeBytes(Service::Interface* self) { | ||
| 511 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 512 | |||
| 513 | ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]); | ||
| 514 | ResultVal<u64> bytes_res = GetFreeBytesInArchive(archive_handle); | ||
| 515 | |||
| 516 | cmd_buff[1] = bytes_res.Code().raw; | ||
| 517 | if (bytes_res.Succeeded()) { | ||
| 518 | cmd_buff[2] = (u32)*bytes_res; | ||
| 519 | cmd_buff[3] = *bytes_res >> 32; | ||
| 520 | } else { | ||
| 521 | cmd_buff[2] = 0; | ||
| 522 | cmd_buff[3] = 0; | ||
| 523 | } | ||
| 524 | } | ||
| 525 | |||
| 526 | /** | ||
| 500 | * FS_User::CreateExtSaveData service function | 527 | * FS_User::CreateExtSaveData service function |
| 501 | * Inputs: | 528 | * Inputs: |
| 502 | * 0 : 0x08510242 | 529 | * 0 : 0x08510242 |
| @@ -681,96 +708,114 @@ static void GetPriority(Service::Interface* self) { | |||
| 681 | } | 708 | } |
| 682 | 709 | ||
| 683 | const Interface::FunctionInfo FunctionTable[] = { | 710 | const Interface::FunctionInfo FunctionTable[] = { |
| 684 | {0x000100C6, nullptr, "Dummy1"}, | 711 | {0x000100C6, nullptr, "Dummy1"}, |
| 685 | {0x040100C4, nullptr, "Control"}, | 712 | {0x040100C4, nullptr, "Control"}, |
| 686 | {0x08010002, Initialize, "Initialize"}, | 713 | {0x08010002, Initialize, "Initialize"}, |
| 687 | {0x080201C2, OpenFile, "OpenFile"}, | 714 | {0x080201C2, OpenFile, "OpenFile"}, |
| 688 | {0x08030204, OpenFileDirectly, "OpenFileDirectly"}, | 715 | {0x08030204, OpenFileDirectly, "OpenFileDirectly"}, |
| 689 | {0x08040142, DeleteFile, "DeleteFile"}, | 716 | {0x08040142, DeleteFile, "DeleteFile"}, |
| 690 | {0x08050244, RenameFile, "RenameFile"}, | 717 | {0x08050244, RenameFile, "RenameFile"}, |
| 691 | {0x08060142, DeleteDirectory, "DeleteDirectory"}, | 718 | {0x08060142, DeleteDirectory, "DeleteDirectory"}, |
| 692 | {0x08070142, nullptr, "DeleteDirectoryRecursively"}, | 719 | {0x08070142, nullptr, "DeleteDirectoryRecursively"}, |
| 693 | {0x08080202, CreateFile, "CreateFile"}, | 720 | {0x08080202, CreateFile, "CreateFile"}, |
| 694 | {0x08090182, CreateDirectory, "CreateDirectory"}, | 721 | {0x08090182, CreateDirectory, "CreateDirectory"}, |
| 695 | {0x080A0244, RenameDirectory, "RenameDirectory"}, | 722 | {0x080A0244, RenameDirectory, "RenameDirectory"}, |
| 696 | {0x080B0102, OpenDirectory, "OpenDirectory"}, | 723 | {0x080B0102, OpenDirectory, "OpenDirectory"}, |
| 697 | {0x080C00C2, OpenArchive, "OpenArchive"}, | 724 | {0x080C00C2, OpenArchive, "OpenArchive"}, |
| 698 | {0x080D0144, nullptr, "ControlArchive"}, | 725 | {0x080D0144, nullptr, "ControlArchive"}, |
| 699 | {0x080E0080, CloseArchive, "CloseArchive"}, | 726 | {0x080E0080, CloseArchive, "CloseArchive"}, |
| 700 | {0x080F0180, FormatThisUserSaveData,"FormatThisUserSaveData"}, | 727 | {0x080F0180, FormatThisUserSaveData, "FormatThisUserSaveData"}, |
| 701 | {0x08100200, nullptr, "CreateSystemSaveData"}, | 728 | {0x08100200, nullptr, "CreateSystemSaveData"}, |
| 702 | {0x08110040, nullptr, "DeleteSystemSaveData"}, | 729 | {0x08110040, nullptr, "DeleteSystemSaveData"}, |
| 703 | {0x08120080, nullptr, "GetFreeBytes"}, | 730 | {0x08120080, GetFreeBytes, "GetFreeBytes"}, |
| 704 | {0x08130000, nullptr, "GetCardType"}, | 731 | {0x08130000, nullptr, "GetCardType"}, |
| 705 | {0x08140000, nullptr, "GetSdmcArchiveResource"}, | 732 | {0x08140000, nullptr, "GetSdmcArchiveResource"}, |
| 706 | {0x08150000, nullptr, "GetNandArchiveResource"}, | 733 | {0x08150000, nullptr, "GetNandArchiveResource"}, |
| 707 | {0x08160000, nullptr, "GetSdmcFatfsErro"}, | 734 | {0x08160000, nullptr, "GetSdmcFatfsError"}, |
| 708 | {0x08170000, IsSdmcDetected, "IsSdmcDetected"}, | 735 | {0x08170000, IsSdmcDetected, "IsSdmcDetected"}, |
| 709 | {0x08180000, IsSdmcWriteable, "IsSdmcWritable"}, | 736 | {0x08180000, IsSdmcWriteable, "IsSdmcWritable"}, |
| 710 | {0x08190042, nullptr, "GetSdmcCid"}, | 737 | {0x08190042, nullptr, "GetSdmcCid"}, |
| 711 | {0x081A0042, nullptr, "GetNandCid"}, | 738 | {0x081A0042, nullptr, "GetNandCid"}, |
| 712 | {0x081B0000, nullptr, "GetSdmcSpeedInfo"}, | 739 | {0x081B0000, nullptr, "GetSdmcSpeedInfo"}, |
| 713 | {0x081C0000, nullptr, "GetNandSpeedInfo"}, | 740 | {0x081C0000, nullptr, "GetNandSpeedInfo"}, |
| 714 | {0x081D0042, nullptr, "GetSdmcLog"}, | 741 | {0x081D0042, nullptr, "GetSdmcLog"}, |
| 715 | {0x081E0042, nullptr, "GetNandLog"}, | 742 | {0x081E0042, nullptr, "GetNandLog"}, |
| 716 | {0x081F0000, nullptr, "ClearSdmcLog"}, | 743 | {0x081F0000, nullptr, "ClearSdmcLog"}, |
| 717 | {0x08200000, nullptr, "ClearNandLog"}, | 744 | {0x08200000, nullptr, "ClearNandLog"}, |
| 718 | {0x08210000, CardSlotIsInserted, "CardSlotIsInserted"}, | 745 | {0x08210000, CardSlotIsInserted, "CardSlotIsInserted"}, |
| 719 | {0x08220000, nullptr, "CardSlotPowerOn"}, | 746 | {0x08220000, nullptr, "CardSlotPowerOn"}, |
| 720 | {0x08230000, nullptr, "CardSlotPowerOff"}, | 747 | {0x08230000, nullptr, "CardSlotPowerOff"}, |
| 721 | {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"}, | 748 | {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"}, |
| 722 | {0x08250040, nullptr, "CardNorDirectCommand"}, | 749 | {0x08250040, nullptr, "CardNorDirectCommand"}, |
| 723 | {0x08260080, nullptr, "CardNorDirectCommandWithAddress"}, | 750 | {0x08260080, nullptr, "CardNorDirectCommandWithAddress"}, |
| 724 | {0x08270082, nullptr, "CardNorDirectRead"}, | 751 | {0x08270082, nullptr, "CardNorDirectRead"}, |
| 725 | {0x082800C2, nullptr, "CardNorDirectReadWithAddress"}, | 752 | {0x082800C2, nullptr, "CardNorDirectReadWithAddress"}, |
| 726 | {0x08290082, nullptr, "CardNorDirectWrite"}, | 753 | {0x08290082, nullptr, "CardNorDirectWrite"}, |
| 727 | {0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"}, | 754 | {0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"}, |
| 728 | {0x082B00C2, nullptr, "CardNorDirectRead_4xIO"}, | 755 | {0x082B00C2, nullptr, "CardNorDirectRead_4xIO"}, |
| 729 | {0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"}, | 756 | {0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"}, |
| 730 | {0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"}, | 757 | {0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"}, |
| 731 | {0x082E0040, nullptr, "GetProductInfo"}, | 758 | {0x082E0040, nullptr, "GetProductInfo"}, |
| 732 | {0x082F0040, nullptr, "GetProgramLaunchInfo"}, | 759 | {0x082F0040, nullptr, "GetProgramLaunchInfo"}, |
| 733 | {0x08300182, nullptr, "CreateExtSaveData"}, | 760 | {0x08300182, nullptr, "CreateExtSaveData"}, |
| 734 | {0x08310180, nullptr, "CreateSharedExtSaveData"}, | 761 | {0x08310180, nullptr, "CreateSharedExtSaveData"}, |
| 735 | {0x08320102, nullptr, "ReadExtSaveDataIcon"}, | 762 | {0x08320102, nullptr, "ReadExtSaveDataIcon"}, |
| 736 | {0x08330082, nullptr, "EnumerateExtSaveData"}, | 763 | {0x08330082, nullptr, "EnumerateExtSaveData"}, |
| 737 | {0x08340082, nullptr, "EnumerateSharedExtSaveData"}, | 764 | {0x08340082, nullptr, "EnumerateSharedExtSaveData"}, |
| 738 | {0x08350080, nullptr, "DeleteExtSaveData"}, | 765 | {0x08350080, nullptr, "DeleteExtSaveData"}, |
| 739 | {0x08360080, nullptr, "DeleteSharedExtSaveData"}, | 766 | {0x08360080, nullptr, "DeleteSharedExtSaveData"}, |
| 740 | {0x08370040, nullptr, "SetCardSpiBaudRate"}, | 767 | {0x08370040, nullptr, "SetCardSpiBaudRate"}, |
| 741 | {0x08380040, nullptr, "SetCardSpiBusMode"}, | 768 | {0x08380040, nullptr, "SetCardSpiBusMode"}, |
| 742 | {0x08390000, nullptr, "SendInitializeInfoTo9"}, | 769 | {0x08390000, nullptr, "SendInitializeInfoTo9"}, |
| 743 | {0x083A0100, nullptr, "GetSpecialContentIndex"}, | 770 | {0x083A0100, nullptr, "GetSpecialContentIndex"}, |
| 744 | {0x083B00C2, nullptr, "GetLegacyRomHeader"}, | 771 | {0x083B00C2, nullptr, "GetLegacyRomHeader"}, |
| 745 | {0x083C00C2, nullptr, "GetLegacyBannerData"}, | 772 | {0x083C00C2, nullptr, "GetLegacyBannerData"}, |
| 746 | {0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"}, | 773 | {0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"}, |
| 747 | {0x083E00C2, nullptr, "QueryTotalQuotaSize"}, | 774 | {0x083E00C2, nullptr, "QueryTotalQuotaSize"}, |
| 748 | {0x083F00C0, nullptr, "GetExtDataBlockSize"}, | 775 | {0x083F00C0, nullptr, "GetExtDataBlockSize"}, |
| 749 | {0x08400040, nullptr, "AbnegateAccessRight"}, | 776 | {0x08400040, nullptr, "AbnegateAccessRight"}, |
| 750 | {0x08410000, nullptr, "DeleteSdmcRoot"}, | 777 | {0x08410000, nullptr, "DeleteSdmcRoot"}, |
| 751 | {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"}, | 778 | {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"}, |
| 752 | {0x08430000, nullptr, "InitializeCtrFileSystem"}, | 779 | {0x08430000, nullptr, "InitializeCtrFileSystem"}, |
| 753 | {0x08440000, nullptr, "CreateSeed"}, | 780 | {0x08440000, nullptr, "CreateSeed"}, |
| 754 | {0x084500C2, nullptr, "GetFormatInfo"}, | 781 | {0x084500C2, nullptr, "GetFormatInfo"}, |
| 755 | {0x08460102, nullptr, "GetLegacyRomHeader2"}, | 782 | {0x08460102, nullptr, "GetLegacyRomHeader2"}, |
| 756 | {0x08470180, nullptr, "FormatCtrCardUserSaveData"}, | 783 | {0x08470180, nullptr, "FormatCtrCardUserSaveData"}, |
| 757 | {0x08480042, nullptr, "GetSdmcCtrRootPath"}, | 784 | {0x08480042, nullptr, "GetSdmcCtrRootPath"}, |
| 758 | {0x08490040, nullptr, "GetArchiveResource"}, | 785 | {0x08490040, nullptr, "GetArchiveResource"}, |
| 759 | {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"}, | 786 | {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"}, |
| 760 | {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"}, | 787 | {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"}, |
| 761 | {0x084C0242, FormatSaveData, "FormatSaveData"}, | 788 | {0x084C0242, FormatSaveData, "FormatSaveData"}, |
| 762 | {0x084D0102, nullptr, "GetLegacySubBannerData"}, | 789 | {0x084D0102, nullptr, "GetLegacySubBannerData"}, |
| 763 | {0x084E0342, nullptr, "UpdateSha256Context"}, | 790 | {0x084E0342, nullptr, "UpdateSha256Context"}, |
| 764 | {0x084F0102, nullptr, "ReadSpecialFile"}, | 791 | {0x084F0102, nullptr, "ReadSpecialFile"}, |
| 765 | {0x08500040, nullptr, "GetSpecialFileSize"}, | 792 | {0x08500040, nullptr, "GetSpecialFileSize"}, |
| 766 | {0x08510242, CreateExtSaveData, "CreateExtSaveData"}, | 793 | {0x08510242, CreateExtSaveData, "CreateExtSaveData"}, |
| 767 | {0x08520100, DeleteExtSaveData, "DeleteExtSaveData"}, | 794 | {0x08520100, DeleteExtSaveData, "DeleteExtSaveData"}, |
| 768 | {0x08560240, CreateSystemSaveData, "CreateSystemSaveData"}, | 795 | {0x08530142, nullptr, "ReadExtSaveDataIcon"}, |
| 769 | {0x08570080, DeleteSystemSaveData, "DeleteSystemSaveData"}, | 796 | {0x085400C0, nullptr, "GetExtDataBlockSize"}, |
| 770 | {0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"}, | 797 | {0x08550102, nullptr, "EnumerateExtSaveData"}, |
| 798 | {0x08560240, CreateSystemSaveData, "CreateSystemSaveData"}, | ||
| 799 | {0x08570080, DeleteSystemSaveData, "DeleteSystemSaveData"}, | ||
| 800 | {0x08580000, nullptr, "StartDeviceMoveAsSource"}, | ||
| 801 | {0x08590200, nullptr, "StartDeviceMoveAsDestination"}, | ||
| 802 | {0x085A00C0, nullptr, "SetArchivePriority"}, | ||
| 803 | {0x085B0080, nullptr, "GetArchivePriority"}, | ||
| 804 | {0x085C00C0, nullptr, "SetCtrCardLatencyParameter"}, | ||
| 805 | {0x085D01C0, nullptr, "SetFsCompatibilityInfo"}, | ||
| 806 | {0x085E0040, nullptr, "ResetCardCompatibilityParameter"}, | ||
| 807 | {0x085F0040, nullptr, "SwitchCleanupInvalidSaveData"}, | ||
| 808 | {0x08600042, nullptr, "EnumerateSystemSaveData"}, | ||
| 771 | {0x08610042, InitializeWithSdkVersion, "InitializeWithSdkVersion"}, | 809 | {0x08610042, InitializeWithSdkVersion, "InitializeWithSdkVersion"}, |
| 772 | {0x08620040, SetPriority, "SetPriority"}, | 810 | {0x08620040, SetPriority, "SetPriority"}, |
| 773 | {0x08630000, GetPriority, "GetPriority"}, | 811 | {0x08630000, GetPriority, "GetPriority"}, |
| 812 | {0x08640000, nullptr, "GetNandInfo"}, | ||
| 813 | {0x08650140, nullptr, "SetSaveDataSecureValue"}, | ||
| 814 | {0x086600C0, nullptr, "GetSaveDataSecureValue"}, | ||
| 815 | {0x086700C4, nullptr, "ControlSecureSave"}, | ||
| 816 | {0x08680000, nullptr, "GetMediaType"}, | ||
| 817 | {0x08690000, nullptr, "GetNandEraseCount"}, | ||
| 818 | {0x086A0082, nullptr, "ReadNandReport"} | ||
| 774 | }; | 819 | }; |
| 775 | 820 | ||
| 776 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 821 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 481da0c9f..98b11c798 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp | |||
| @@ -275,7 +275,7 @@ static void FlushDataCache(Service::Interface* self) { | |||
| 275 | u32 size = cmd_buff[2]; | 275 | u32 size = cmd_buff[2]; |
| 276 | u32 process = cmd_buff[4]; | 276 | u32 process = cmd_buff[4]; |
| 277 | 277 | ||
| 278 | VideoCore::g_renderer->hw_rasterizer->NotifyFlush(Memory::VirtualToPhysicalAddress(address), size); | 278 | VideoCore::g_renderer->rasterizer->InvalidateRegion(Memory::VirtualToPhysicalAddress(address), size); |
| 279 | 279 | ||
| 280 | // TODO(purpasmart96): Verify return header on HW | 280 | // TODO(purpasmart96): Verify return header on HW |
| 281 | 281 | ||
| @@ -365,7 +365,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { | |||
| 365 | 365 | ||
| 366 | // GX request DMA - typically used for copying memory from GSP heap to VRAM | 366 | // GX request DMA - typically used for copying memory from GSP heap to VRAM |
| 367 | case CommandId::REQUEST_DMA: | 367 | case CommandId::REQUEST_DMA: |
| 368 | VideoCore::g_renderer->hw_rasterizer->NotifyPreRead(Memory::VirtualToPhysicalAddress(command.dma_request.source_address), | 368 | VideoCore::g_renderer->rasterizer->FlushRegion(Memory::VirtualToPhysicalAddress(command.dma_request.source_address), |
| 369 | command.dma_request.size); | 369 | command.dma_request.size); |
| 370 | 370 | ||
| 371 | memcpy(Memory::GetPointer(command.dma_request.dest_address), | 371 | memcpy(Memory::GetPointer(command.dma_request.dest_address), |
| @@ -373,7 +373,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { | |||
| 373 | command.dma_request.size); | 373 | command.dma_request.size); |
| 374 | SignalInterrupt(InterruptId::DMA); | 374 | SignalInterrupt(InterruptId::DMA); |
| 375 | 375 | ||
| 376 | VideoCore::g_renderer->hw_rasterizer->NotifyFlush(Memory::VirtualToPhysicalAddress(command.dma_request.dest_address), | 376 | VideoCore::g_renderer->rasterizer->InvalidateRegion(Memory::VirtualToPhysicalAddress(command.dma_request.dest_address), |
| 377 | command.dma_request.size); | 377 | command.dma_request.size); |
| 378 | break; | 378 | break; |
| 379 | 379 | ||
| @@ -467,7 +467,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { | |||
| 467 | if (region.size == 0) | 467 | if (region.size == 0) |
| 468 | break; | 468 | break; |
| 469 | 469 | ||
| 470 | VideoCore::g_renderer->hw_rasterizer->NotifyFlush( | 470 | VideoCore::g_renderer->rasterizer->InvalidateRegion( |
| 471 | Memory::VirtualToPhysicalAddress(region.address), region.size); | 471 | Memory::VirtualToPhysicalAddress(region.address), region.size); |
| 472 | } | 472 | } |
| 473 | break; | 473 | break; |
diff --git a/src/core/hle/service/gsp_lcd.cpp b/src/core/hle/service/gsp_lcd.cpp index 9e36732b4..59ee9b73c 100644 --- a/src/core/hle/service/gsp_lcd.cpp +++ b/src/core/hle/service/gsp_lcd.cpp | |||
| @@ -11,14 +11,18 @@ | |||
| 11 | 11 | ||
| 12 | namespace GSP_LCD { | 12 | namespace GSP_LCD { |
| 13 | 13 | ||
| 14 | /*const Interface::FunctionInfo FunctionTable[] = { | 14 | const Interface::FunctionInfo FunctionTable[] = { |
| 15 | };*/ | 15 | {0x000F0000, nullptr, "PowerOnAllBacklights"}, |
| 16 | {0x00100000, nullptr, "PowerOffAllBacklights"}, | ||
| 17 | {0x00110040, nullptr, "PowerOnBacklight"}, | ||
| 18 | {0x00120040, nullptr, "PowerOffBacklight"}, | ||
| 19 | }; | ||
| 16 | 20 | ||
| 17 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 21 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
| 18 | // Interface class | 22 | // Interface class |
| 19 | 23 | ||
| 20 | Interface::Interface() { | 24 | Interface::Interface() { |
| 21 | //Register(FunctionTable); | 25 | Register(FunctionTable); |
| 22 | } | 26 | } |
| 23 | 27 | ||
| 24 | } // namespace | 28 | } // namespace |
diff --git a/src/core/hle/service/hid/hid_user.cpp b/src/core/hle/service/hid/hid_user.cpp index fbfb9e885..e103881b1 100644 --- a/src/core/hle/service/hid/hid_user.cpp +++ b/src/core/hle/service/hid/hid_user.cpp | |||
| @@ -11,6 +11,8 @@ namespace HID { | |||
| 11 | 11 | ||
| 12 | const Interface::FunctionInfo FunctionTable[] = { | 12 | const Interface::FunctionInfo FunctionTable[] = { |
| 13 | {0x000A0000, GetIPCHandles, "GetIPCHandles"}, | 13 | {0x000A0000, GetIPCHandles, "GetIPCHandles"}, |
| 14 | {0x000B0000, nullptr, "StartAnalogStickCalibration"}, | ||
| 15 | {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, | ||
| 14 | {0x00110000, EnableAccelerometer, "EnableAccelerometer"}, | 16 | {0x00110000, EnableAccelerometer, "EnableAccelerometer"}, |
| 15 | {0x00120000, DisableAccelerometer, "DisableAccelerometer"}, | 17 | {0x00120000, DisableAccelerometer, "DisableAccelerometer"}, |
| 16 | {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"}, | 18 | {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"}, |
diff --git a/src/core/hle/service/http_c.cpp b/src/core/hle/service/http_c.cpp index 0a3aba0a0..43d8a3b85 100644 --- a/src/core/hle/service/http_c.cpp +++ b/src/core/hle/service/http_c.cpp | |||
| @@ -47,10 +47,18 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 47 | {0x00220040, nullptr, "GetResponseStatusCode"}, | 47 | {0x00220040, nullptr, "GetResponseStatusCode"}, |
| 48 | {0x002300C0, nullptr, "GetResponseStatusCodeTimeout"}, | 48 | {0x002300C0, nullptr, "GetResponseStatusCodeTimeout"}, |
| 49 | {0x00240082, nullptr, "AddTrustedRootCA"}, | 49 | {0x00240082, nullptr, "AddTrustedRootCA"}, |
| 50 | {0x00250080, nullptr, "AddDefaultCert"}, | ||
| 51 | {0x00260080, nullptr, "SelectRootCertChain"}, | ||
| 52 | {0x002700C4, nullptr, "SetClientCert"}, | ||
| 53 | {0x002D0000, nullptr, "CreateRootCertChain"}, | ||
| 54 | {0x002E0040, nullptr, "DestroyRootCertChain"}, | ||
| 55 | {0x002F0082, nullptr, "RootCertChainAddCert"}, | ||
| 56 | {0x00300080, nullptr, "RootCertChainAddDefaultCert"}, | ||
| 50 | {0x00350186, nullptr, "SetDefaultProxy"}, | 57 | {0x00350186, nullptr, "SetDefaultProxy"}, |
| 51 | {0x00360000, nullptr, "ClearDNSCache"}, | 58 | {0x00360000, nullptr, "ClearDNSCache"}, |
| 52 | {0x00370080, nullptr, "SetKeepAlive"}, | 59 | {0x00370080, nullptr, "SetKeepAlive"}, |
| 53 | {0x003800C0, nullptr, "Finalize"}, | 60 | {0x003800C0, nullptr, "SetPostDataTypeSize"}, |
| 61 | {0x00390000, nullptr, "Finalize"}, | ||
| 54 | }; | 62 | }; |
| 55 | 63 | ||
| 56 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 64 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp index 25e70d321..1f27e9c1f 100644 --- a/src/core/hle/service/mic_u.cpp +++ b/src/core/hle/service/mic_u.cpp | |||
| @@ -18,14 +18,14 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 18 | {0x00050000, nullptr, "StopSampling"}, | 18 | {0x00050000, nullptr, "StopSampling"}, |
| 19 | {0x00060000, nullptr, "IsSampling"}, | 19 | {0x00060000, nullptr, "IsSampling"}, |
| 20 | {0x00070000, nullptr, "GetEventHandle"}, | 20 | {0x00070000, nullptr, "GetEventHandle"}, |
| 21 | {0x00080040, nullptr, "SetControl"}, | 21 | {0x00080040, nullptr, "SetGain"}, |
| 22 | {0x00090000, nullptr, "GetControl"}, | 22 | {0x00090000, nullptr, "GetGain"}, |
| 23 | {0x000A0040, nullptr, "SetBias"}, | 23 | {0x000A0040, nullptr, "SetPower"}, |
| 24 | {0x000B0000, nullptr, "GetBias"}, | 24 | {0x000B0000, nullptr, "GetPower"}, |
| 25 | {0x000C0042, nullptr, "size"}, | 25 | {0x000C0042, nullptr, "size"}, |
| 26 | {0x000D0040, nullptr, "SetClamp"}, | 26 | {0x000D0040, nullptr, "SetClamp"}, |
| 27 | {0x000E0000, nullptr, "GetClamp"}, | 27 | {0x000E0000, nullptr, "GetClamp"}, |
| 28 | {0x000F0040, nullptr, "unknown_input1"}, | 28 | {0x000F0040, nullptr, "SetAllowShellClosed"}, |
| 29 | {0x00100040, nullptr, "unknown_input2"}, | 29 | {0x00100040, nullptr, "unknown_input2"}, |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
diff --git a/src/core/hle/service/ndm_u.cpp b/src/core/hle/service/ndm_u.cpp index df3c97193..ad247fd1f 100644 --- a/src/core/hle/service/ndm_u.cpp +++ b/src/core/hle/service/ndm_u.cpp | |||
| @@ -14,10 +14,26 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 14 | {0x00010042, nullptr, "EnterExclusiveState"}, | 14 | {0x00010042, nullptr, "EnterExclusiveState"}, |
| 15 | {0x00020002, nullptr, "LeaveExclusiveState"}, | 15 | {0x00020002, nullptr, "LeaveExclusiveState"}, |
| 16 | {0x00030000, nullptr, "QueryExclusiveMode"}, | 16 | {0x00030000, nullptr, "QueryExclusiveMode"}, |
| 17 | {0x00040002, nullptr, "LockState"}, | ||
| 18 | {0x00050002, nullptr, "UnlockState"}, | ||
| 17 | {0x00060040, nullptr, "SuspendDaemons"}, | 19 | {0x00060040, nullptr, "SuspendDaemons"}, |
| 20 | {0x00070040, nullptr, "ResumeDaemons"}, | ||
| 18 | {0x00080040, nullptr, "DisableWifiUsage"}, | 21 | {0x00080040, nullptr, "DisableWifiUsage"}, |
| 19 | {0x00090000, nullptr, "EnableWifiUsage"}, | 22 | {0x00090000, nullptr, "EnableWifiUsage"}, |
| 23 | {0x000A0000, nullptr, "GetCurrentState"}, | ||
| 24 | {0x000B0000, nullptr, "GetTargetState"}, | ||
| 25 | {0x000C0000, nullptr, "<Stubbed>"}, | ||
| 26 | {0x000D0040, nullptr, "QueryStatus"}, | ||
| 27 | {0x000E0040, nullptr, "GetDaemonDisableCount"}, | ||
| 28 | {0x000F0000, nullptr, "GetSchedulerDisableCount"}, | ||
| 29 | {0x00100040, nullptr, "SetScanInterval"}, | ||
| 30 | {0x00110000, nullptr, "GetScanInterval"}, | ||
| 31 | {0x00120040, nullptr, "SetRetryInterval"}, | ||
| 32 | {0x00130000, nullptr, "GetRetryInterval"}, | ||
| 20 | {0x00140040, nullptr, "OverrideDefaultDaemons"}, | 33 | {0x00140040, nullptr, "OverrideDefaultDaemons"}, |
| 34 | {0x00150000, nullptr, "ResetDefaultDaemons"}, | ||
| 35 | {0x00160000, nullptr, "GetDefaultDaemons"}, | ||
| 36 | {0x00170000, nullptr, "ClearHalfAwakeMacFilter"}, | ||
| 21 | }; | 37 | }; |
| 22 | 38 | ||
| 23 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 39 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/service/news/news_s.cpp b/src/core/hle/service/news/news_s.cpp index 2f8c37d9e..5b8db3288 100644 --- a/src/core/hle/service/news/news_s.cpp +++ b/src/core/hle/service/news/news_s.cpp | |||
| @@ -11,6 +11,18 @@ namespace NEWS { | |||
| 11 | 11 | ||
| 12 | const Interface::FunctionInfo FunctionTable[] = { | 12 | const Interface::FunctionInfo FunctionTable[] = { |
| 13 | {0x000100C6, nullptr, "AddNotification"}, | 13 | {0x000100C6, nullptr, "AddNotification"}, |
| 14 | {0x00050000, nullptr, "GetTotalNotifications"}, | ||
| 15 | {0x00060042, nullptr, "SetNewsDBHeader"}, | ||
| 16 | {0x00070082, nullptr, "SetNotificationHeader"}, | ||
| 17 | {0x00080082, nullptr, "SetNotificationMessage"}, | ||
| 18 | {0x00090082, nullptr, "SetNotificationImage"}, | ||
| 19 | {0x000A0042, nullptr, "GetNewsDBHeader"}, | ||
| 20 | {0x000B0082, nullptr, "GetNotificationHeader"}, | ||
| 21 | {0x000C0082, nullptr, "GetNotificationMessage"}, | ||
| 22 | {0x000D0082, nullptr, "GetNotificationImage"}, | ||
| 23 | {0x000E0040, nullptr, "SetInfoLEDPattern"}, | ||
| 24 | {0x00120082, nullptr, "GetNotificationHeaderOther"}, | ||
| 25 | {0x00130000, nullptr, "WriteNewsDBSavedata"}, | ||
| 14 | }; | 26 | }; |
| 15 | 27 | ||
| 16 | NEWS_S_Interface::NEWS_S_Interface() { | 28 | NEWS_S_Interface::NEWS_S_Interface() { |
diff --git a/src/core/hle/service/nim/nim_s.cpp b/src/core/hle/service/nim/nim_s.cpp index 5d8bc059f..1172770ac 100644 --- a/src/core/hle/service/nim/nim_s.cpp +++ b/src/core/hle/service/nim/nim_s.cpp | |||
| @@ -11,6 +11,9 @@ namespace NIM { | |||
| 11 | 11 | ||
| 12 | const Interface::FunctionInfo FunctionTable[] = { | 12 | const Interface::FunctionInfo FunctionTable[] = { |
| 13 | {0x000A0000, nullptr, "CheckSysupdateAvailableSOAP"}, | 13 | {0x000A0000, nullptr, "CheckSysupdateAvailableSOAP"}, |
| 14 | {0x0016020A, nullptr, "ListTitles"}, | ||
| 15 | {0x002D0042, nullptr, "DownloadTickets"}, | ||
| 16 | {0x00420240, nullptr, "StartDownload"}, | ||
| 14 | }; | 17 | }; |
| 15 | 18 | ||
| 16 | NIM_S_Interface::NIM_S_Interface() { | 19 | NIM_S_Interface::NIM_S_Interface() { |
diff --git a/src/core/hle/service/ns_s.cpp b/src/core/hle/service/ns_s.cpp index 6b3ef6ece..99e8e0880 100644 --- a/src/core/hle/service/ns_s.cpp +++ b/src/core/hle/service/ns_s.cpp | |||
| @@ -12,7 +12,16 @@ | |||
| 12 | namespace NS_S { | 12 | namespace NS_S { |
| 13 | 13 | ||
| 14 | const Interface::FunctionInfo FunctionTable[] = { | 14 | const Interface::FunctionInfo FunctionTable[] = { |
| 15 | {0x000100C0, nullptr, "LaunchFIRM"}, | ||
| 15 | {0x000200C0, nullptr, "LaunchTitle"}, | 16 | {0x000200C0, nullptr, "LaunchTitle"}, |
| 17 | {0x000500C0, nullptr, "LaunchApplicationFIRM"}, | ||
| 18 | {0x00060042, nullptr, "SetFIRMParams4A0"}, | ||
| 19 | {0x00070042, nullptr, "CardUpdateInitialize"}, | ||
| 20 | {0x000D0140, nullptr, "SetFIRMParams4B0"}, | ||
| 21 | {0x000E0000, nullptr, "ShutdownAsync"}, | ||
| 22 | {0x00100180, nullptr, "RebootSystem"}, | ||
| 23 | {0x00150140, nullptr, "LaunchApplication"}, | ||
| 24 | {0x00160000, nullptr, "HardRebootSystem"}, | ||
| 16 | }; | 25 | }; |
| 17 | 26 | ||
| 18 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 27 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp index 18b22956f..adca64a3a 100644 --- a/src/core/hle/service/nwm_uds.cpp +++ b/src/core/hle/service/nwm_uds.cpp | |||
| @@ -106,14 +106,32 @@ static void Initialize(Service::Interface* self) { | |||
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | const Interface::FunctionInfo FunctionTable[] = { | 108 | const Interface::FunctionInfo FunctionTable[] = { |
| 109 | {0x00020000, nullptr, "Scrap"}, | ||
| 109 | {0x00030000, Shutdown, "Shutdown"}, | 110 | {0x00030000, Shutdown, "Shutdown"}, |
| 111 | {0x00040402, nullptr, "CreateNetwork"}, | ||
| 112 | {0x00050040, nullptr, "EjectClient"}, | ||
| 113 | {0x00060000, nullptr, "EjectSpectator"}, | ||
| 114 | {0x00070080, nullptr, "UpdateNetworkAttribute"}, | ||
| 115 | {0x00080000, nullptr, "DestroyNetwork"}, | ||
| 116 | {0x000A0000, nullptr, "DisconnectNetwork"}, | ||
| 117 | {0x000B0000, nullptr, "GetConnectionStatus"}, | ||
| 118 | {0x000D0040, nullptr, "GetNodeInformation"}, | ||
| 110 | {0x000F0404, RecvBeaconBroadcastData, "RecvBeaconBroadcastData"}, | 119 | {0x000F0404, RecvBeaconBroadcastData, "RecvBeaconBroadcastData"}, |
| 111 | {0x00100042, nullptr, "SetBeaconAdditionalData"}, | 120 | {0x00100042, nullptr, "SetBeaconAdditionalData"}, |
| 121 | {0x00110040, nullptr, "GetApplicationData"}, | ||
| 122 | {0x00120100, nullptr, "Bind"}, | ||
| 123 | {0x00130040, nullptr, "Unbind"}, | ||
| 112 | {0x001400C0, nullptr, "RecvBroadcastDataFrame"}, | 124 | {0x001400C0, nullptr, "RecvBroadcastDataFrame"}, |
| 125 | {0x00150080, nullptr, "SetMaxSendDelay"}, | ||
| 126 | {0x00170182, nullptr, "SendTo"}, | ||
| 127 | {0x001A0000, nullptr, "GetChannel"}, | ||
| 113 | {0x001B0302, Initialize, "Initialize"}, | 128 | {0x001B0302, Initialize, "Initialize"}, |
| 114 | {0x001D0044, nullptr, "BeginHostingNetwork"}, | 129 | {0x001D0044, nullptr, "BeginHostingNetwork"}, |
| 115 | {0x001E0084, nullptr, "ConnectToNetwork"}, | 130 | {0x001E0084, nullptr, "ConnectToNetwork"}, |
| 116 | {0x001F0006, nullptr, "DecryptBeaconData"}, | 131 | {0x001F0006, nullptr, "DecryptBeaconData"}, |
| 132 | {0x00200040, nullptr, "Flush"}, | ||
| 133 | {0x00210080, nullptr, "SetProbeResponseParam"}, | ||
| 134 | {0x00220402, nullptr, "ScanOnConnection"}, | ||
| 117 | }; | 135 | }; |
| 118 | 136 | ||
| 119 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 137 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/service/pm_app.cpp b/src/core/hle/service/pm_app.cpp index 7420a62f4..48646ed72 100644 --- a/src/core/hle/service/pm_app.cpp +++ b/src/core/hle/service/pm_app.cpp | |||
| @@ -19,6 +19,10 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 19 | {0x00070042, nullptr, "GetFIRMLaunchParams"}, | 19 | {0x00070042, nullptr, "GetFIRMLaunchParams"}, |
| 20 | {0x00080100, nullptr, "GetTitleExheaderFlags"}, | 20 | {0x00080100, nullptr, "GetTitleExheaderFlags"}, |
| 21 | {0x00090042, nullptr, "SetFIRMLaunchParams"}, | 21 | {0x00090042, nullptr, "SetFIRMLaunchParams"}, |
| 22 | {0x000A0140, nullptr, "SetResourceLimit"}, | ||
| 23 | {0x000B0140, nullptr, "GetResourceLimitMax"}, | ||
| 24 | {0x000C0080, nullptr, "UnregisterProcess"}, | ||
| 25 | {0x000D0240, nullptr, "LaunchTitleUpdate"}, | ||
| 22 | }; | 26 | }; |
| 23 | 27 | ||
| 24 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 28 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp index 2c7d49c9f..22c1093ff 100644 --- a/src/core/hle/service/ptm/ptm.cpp +++ b/src/core/hle/service/ptm/ptm.cpp | |||
| @@ -68,6 +68,18 @@ void GetBatteryChargeState(Service::Interface* self) { | |||
| 68 | LOG_WARNING(Service_PTM, "(STUBBED) called"); | 68 | LOG_WARNING(Service_PTM, "(STUBBED) called"); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | void GetTotalStepCount(Service::Interface* self) { | ||
| 72 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 73 | |||
| 74 | // TODO: This function is only a stub, | ||
| 75 | // it returns 0 as the total step count | ||
| 76 | |||
| 77 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 78 | cmd_buff[2] = 0; | ||
| 79 | |||
| 80 | LOG_WARNING(Service_PTM, "(STUBBED) called"); | ||
| 81 | } | ||
| 82 | |||
| 71 | void IsLegacyPowerOff(Service::Interface* self) { | 83 | void IsLegacyPowerOff(Service::Interface* self) { |
| 72 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 84 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 73 | 85 | ||
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h index b690003cb..f2e76441f 100644 --- a/src/core/hle/service/ptm/ptm.h +++ b/src/core/hle/service/ptm/ptm.h | |||
| @@ -72,6 +72,14 @@ void GetBatteryLevel(Interface* self); | |||
| 72 | void GetBatteryChargeState(Interface* self); | 72 | void GetBatteryChargeState(Interface* self); |
| 73 | 73 | ||
| 74 | /** | 74 | /** |
| 75 | * PTM::GetTotalStepCount service function | ||
| 76 | * Outputs: | ||
| 77 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 78 | * 2 : Output of function, * = total step count | ||
| 79 | */ | ||
| 80 | void GetTotalStepCount(Interface* self); | ||
| 81 | |||
| 82 | /** | ||
| 75 | * PTM::IsLegacyPowerOff service function | 83 | * PTM::IsLegacyPowerOff service function |
| 76 | * Outputs: | 84 | * Outputs: |
| 77 | * 1: Result code, 0 on success, otherwise error code | 85 | * 1: Result code, 0 on success, otherwise error code |
diff --git a/src/core/hle/service/ptm/ptm_sysm.cpp b/src/core/hle/service/ptm/ptm_sysm.cpp index 655658f3b..3ecfab05c 100644 --- a/src/core/hle/service/ptm/ptm_sysm.cpp +++ b/src/core/hle/service/ptm/ptm_sysm.cpp | |||
| @@ -39,7 +39,8 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 39 | {0x08110000, nullptr, "GetShellStatus"}, | 39 | {0x08110000, nullptr, "GetShellStatus"}, |
| 40 | {0x08120000, nullptr, "IsShutdownByBatteryEmpty"}, | 40 | {0x08120000, nullptr, "IsShutdownByBatteryEmpty"}, |
| 41 | {0x08130000, nullptr, "FormatSavedata"}, | 41 | {0x08130000, nullptr, "FormatSavedata"}, |
| 42 | {0x08140000, nullptr, "GetLegacyJumpProhibitedFlag"} | 42 | {0x08140000, nullptr, "GetLegacyJumpProhibitedFlag"}, |
| 43 | {0x08180040, nullptr, "ConfigureNew3DSCPU"}, | ||
| 43 | }; | 44 | }; |
| 44 | 45 | ||
| 45 | PTM_Sysm_Interface::PTM_Sysm_Interface() { | 46 | PTM_Sysm_Interface::PTM_Sysm_Interface() { |
diff --git a/src/core/hle/service/ptm/ptm_u.cpp b/src/core/hle/service/ptm/ptm_u.cpp index 3f5e9c7c1..09dc38c3e 100644 --- a/src/core/hle/service/ptm/ptm_u.cpp +++ b/src/core/hle/service/ptm/ptm_u.cpp | |||
| @@ -23,7 +23,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 23 | {0x00090000, nullptr, "GetPedometerState"}, | 23 | {0x00090000, nullptr, "GetPedometerState"}, |
| 24 | {0x000A0042, nullptr, "GetStepHistoryEntry"}, | 24 | {0x000A0042, nullptr, "GetStepHistoryEntry"}, |
| 25 | {0x000B00C2, nullptr, "GetStepHistory"}, | 25 | {0x000B00C2, nullptr, "GetStepHistory"}, |
| 26 | {0x000C0000, nullptr, "GetTotalStepCount"}, | 26 | {0x000C0000, GetTotalStepCount, "GetTotalStepCount"}, |
| 27 | {0x000D0040, nullptr, "SetPedometerRecordingMode"}, | 27 | {0x000D0040, nullptr, "SetPedometerRecordingMode"}, |
| 28 | {0x000E0000, nullptr, "GetPedometerRecordingMode"}, | 28 | {0x000E0000, nullptr, "GetPedometerRecordingMode"}, |
| 29 | {0x000F0084, nullptr, "GetStepHistoryAll"}, | 29 | {0x000F0084, nullptr, "GetStepHistoryAll"}, |
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp index 633b66fe2..822b093f4 100644 --- a/src/core/hle/service/soc_u.cpp +++ b/src/core/hle/service/soc_u.cpp | |||
| @@ -552,13 +552,23 @@ static void RecvFrom(Service::Interface* self) { | |||
| 552 | u32 flags = cmd_buffer[3]; | 552 | u32 flags = cmd_buffer[3]; |
| 553 | socklen_t addr_len = static_cast<socklen_t>(cmd_buffer[4]); | 553 | socklen_t addr_len = static_cast<socklen_t>(cmd_buffer[4]); |
| 554 | 554 | ||
| 555 | u8* output_buff = Memory::GetPointer(cmd_buffer[0x104 >> 2]); | 555 | struct |
| 556 | { | ||
| 557 | u32 output_buffer_descriptor; | ||
| 558 | u32 output_buffer_addr; | ||
| 559 | u32 address_buffer_descriptor; | ||
| 560 | u32 output_src_address_buffer; | ||
| 561 | } buffer_parameters; | ||
| 562 | |||
| 563 | std::memcpy(&buffer_parameters, &cmd_buffer[64], sizeof(buffer_parameters)); | ||
| 564 | |||
| 565 | u8* output_buff = Memory::GetPointer(buffer_parameters.output_buffer_addr); | ||
| 556 | sockaddr src_addr; | 566 | sockaddr src_addr; |
| 557 | socklen_t src_addr_len = sizeof(src_addr); | 567 | socklen_t src_addr_len = sizeof(src_addr); |
| 558 | int ret = ::recvfrom(socket_handle, (char*)output_buff, len, flags, &src_addr, &src_addr_len); | 568 | int ret = ::recvfrom(socket_handle, (char*)output_buff, len, flags, &src_addr, &src_addr_len); |
| 559 | 569 | ||
| 560 | if (cmd_buffer[0x1A0 >> 2] != 0) { | 570 | if (buffer_parameters.output_src_address_buffer != 0) { |
| 561 | CTRSockAddr* ctr_src_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[0x1A0 >> 2])); | 571 | CTRSockAddr* ctr_src_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(buffer_parameters.output_src_address_buffer)); |
| 562 | *ctr_src_addr = CTRSockAddr::FromPlatform(src_addr); | 572 | *ctr_src_addr = CTRSockAddr::FromPlatform(src_addr); |
| 563 | } | 573 | } |
| 564 | 574 | ||
diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp index e634276fc..9ecb72c77 100644 --- a/src/core/hle/service/ssl_c.cpp +++ b/src/core/hle/service/ssl_c.cpp | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <random> | ||
| 6 | |||
| 5 | #include "core/hle/hle.h" | 7 | #include "core/hle/hle.h" |
| 6 | #include "core/hle/service/ssl_c.h" | 8 | #include "core/hle/service/ssl_c.h" |
| 7 | 9 | ||
| @@ -10,11 +12,64 @@ | |||
| 10 | 12 | ||
| 11 | namespace SSL_C { | 13 | namespace SSL_C { |
| 12 | 14 | ||
| 15 | // TODO: Implement a proper CSPRNG in the future when actual security is needed | ||
| 16 | static std::mt19937 rand_gen; | ||
| 17 | |||
| 18 | static void Initialize(Service::Interface* self) { | ||
| 19 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 20 | |||
| 21 | // Seed random number generator when the SSL service is initialized | ||
| 22 | std::random_device rand_device; | ||
| 23 | rand_gen.seed(rand_device()); | ||
| 24 | |||
| 25 | // Stub, return success | ||
| 26 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 27 | } | ||
| 28 | |||
| 29 | static void GenerateRandomData(Service::Interface* self) { | ||
| 30 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 31 | |||
| 32 | u32 size = cmd_buff[1]; | ||
| 33 | VAddr address = cmd_buff[3]; | ||
| 34 | u8* output_buff = Memory::GetPointer(address); | ||
| 35 | |||
| 36 | // Fill the output buffer with random data. | ||
| 37 | u32 data = 0; | ||
| 38 | u32 i = 0; | ||
| 39 | while (i < size) { | ||
| 40 | if ((i % 4) == 0) { | ||
| 41 | // The random number generator returns 4 bytes worth of data, so generate new random data when i == 0 and when i is divisible by 4 | ||
| 42 | data = rand_gen(); | ||
| 43 | } | ||
| 44 | |||
| 45 | if (size > 4) { | ||
| 46 | // Use up the entire 4 bytes of the random data for as long as possible | ||
| 47 | *(u32*)(output_buff + i) = data; | ||
| 48 | i += 4; | ||
| 49 | } else if (size == 2) { | ||
| 50 | *(u16*)(output_buff + i) = (u16)(data & 0xffff); | ||
| 51 | i += 2; | ||
| 52 | } else { | ||
| 53 | *(u8*)(output_buff + i) = (u8)(data & 0xff); | ||
| 54 | i++; | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | // Stub, return success | ||
| 59 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 60 | } | ||
| 61 | |||
| 13 | const Interface::FunctionInfo FunctionTable[] = { | 62 | const Interface::FunctionInfo FunctionTable[] = { |
| 63 | {0x00010002, Initialize, "Initialize"}, | ||
| 14 | {0x000200C2, nullptr, "CreateContext"}, | 64 | {0x000200C2, nullptr, "CreateContext"}, |
| 65 | {0x00030000, nullptr, "CreateRootCertChain"}, | ||
| 66 | {0x00040040, nullptr, "DestroyRootCertChain"}, | ||
| 15 | {0x00050082, nullptr, "AddTrustedRootCA"}, | 67 | {0x00050082, nullptr, "AddTrustedRootCA"}, |
| 68 | {0x00060080, nullptr, "RootCertChainAddDefaultCert"}, | ||
| 69 | {0x00110042, GenerateRandomData, "GenerateRandomData"}, | ||
| 16 | {0x00150082, nullptr, "Read"}, | 70 | {0x00150082, nullptr, "Read"}, |
| 17 | {0x00170082, nullptr, "Write"}, | 71 | {0x00170082, nullptr, "Write"}, |
| 72 | {0x00180080, nullptr, "ContextSetRootCertChain"}, | ||
| 18 | }; | 73 | }; |
| 19 | 74 | ||
| 20 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 75 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp index 6b1b71fe4..69d0bf4a3 100644 --- a/src/core/hle/service/y2r_u.cpp +++ b/src/core/hle/service/y2r_u.cpp | |||
| @@ -267,7 +267,7 @@ static void StartConversion(Service::Interface* self) { | |||
| 267 | // dst_image_size would seem to be perfect for this, but it doesn't include the gap :( | 267 | // dst_image_size would seem to be perfect for this, but it doesn't include the gap :( |
| 268 | u32 total_output_size = conversion.input_lines * | 268 | u32 total_output_size = conversion.input_lines * |
| 269 | (conversion.dst.transfer_unit + conversion.dst.gap); | 269 | (conversion.dst.transfer_unit + conversion.dst.gap); |
| 270 | VideoCore::g_renderer->hw_rasterizer->NotifyFlush( | 270 | VideoCore::g_renderer->rasterizer->InvalidateRegion( |
| 271 | Memory::VirtualToPhysicalAddress(conversion.dst.address), total_output_size); | 271 | Memory::VirtualToPhysicalAddress(conversion.dst.address), total_output_size); |
| 272 | 272 | ||
| 273 | LOG_DEBUG(Service_Y2R, "called"); | 273 | LOG_DEBUG(Service_Y2R, "called"); |
| @@ -375,21 +375,41 @@ static void DriverFinalize(Service::Interface* self) { | |||
| 375 | 375 | ||
| 376 | const Interface::FunctionInfo FunctionTable[] = { | 376 | const Interface::FunctionInfo FunctionTable[] = { |
| 377 | {0x00010040, SetInputFormat, "SetInputFormat"}, | 377 | {0x00010040, SetInputFormat, "SetInputFormat"}, |
| 378 | {0x00020000, nullptr, "GetInputFormat"}, | ||
| 378 | {0x00030040, SetOutputFormat, "SetOutputFormat"}, | 379 | {0x00030040, SetOutputFormat, "SetOutputFormat"}, |
| 380 | {0x00040000, nullptr, "GetOutputFormat"}, | ||
| 379 | {0x00050040, SetRotation, "SetRotation"}, | 381 | {0x00050040, SetRotation, "SetRotation"}, |
| 382 | {0x00060000, nullptr, "GetRotation"}, | ||
| 380 | {0x00070040, SetBlockAlignment, "SetBlockAlignment"}, | 383 | {0x00070040, SetBlockAlignment, "SetBlockAlignment"}, |
| 384 | {0x00080000, nullptr, "GetBlockAlignment"}, | ||
| 385 | {0x00090040, nullptr, "SetSpacialDithering"}, | ||
| 386 | {0x000A0000, nullptr, "GetSpacialDithering"}, | ||
| 387 | {0x000B0040, nullptr, "SetTemporalDithering"}, | ||
| 388 | {0x000C0000, nullptr, "GetTemporalDithering"}, | ||
| 381 | {0x000D0040, SetTransferEndInterrupt, "SetTransferEndInterrupt"}, | 389 | {0x000D0040, SetTransferEndInterrupt, "SetTransferEndInterrupt"}, |
| 382 | {0x000F0000, GetTransferEndEvent, "GetTransferEndEvent"}, | 390 | {0x000F0000, GetTransferEndEvent, "GetTransferEndEvent"}, |
| 383 | {0x00100102, SetSendingY, "SetSendingY"}, | 391 | {0x00100102, SetSendingY, "SetSendingY"}, |
| 384 | {0x00110102, SetSendingU, "SetSendingU"}, | 392 | {0x00110102, SetSendingU, "SetSendingU"}, |
| 385 | {0x00120102, SetSendingV, "SetSendingV"}, | 393 | {0x00120102, SetSendingV, "SetSendingV"}, |
| 386 | {0x00130102, SetSendingYUYV, "SetSendingYUYV"}, | 394 | {0x00130102, SetSendingYUYV, "SetSendingYUYV"}, |
| 395 | {0x00140000, nullptr, "IsFinishedSendingYuv"}, | ||
| 396 | {0x00150000, nullptr, "IsFinishedSendingY"}, | ||
| 397 | {0x00160000, nullptr, "IsFinishedSendingU"}, | ||
| 398 | {0x00170000, nullptr, "IsFinishedSendingV"}, | ||
| 387 | {0x00180102, SetReceiving, "SetReceiving"}, | 399 | {0x00180102, SetReceiving, "SetReceiving"}, |
| 400 | {0x00190000, nullptr, "IsFinishedReceiving"}, | ||
| 388 | {0x001A0040, SetInputLineWidth, "SetInputLineWidth"}, | 401 | {0x001A0040, SetInputLineWidth, "SetInputLineWidth"}, |
| 402 | {0x001B0000, nullptr, "GetInputLineWidth"}, | ||
| 389 | {0x001C0040, SetInputLines, "SetInputLines"}, | 403 | {0x001C0040, SetInputLines, "SetInputLines"}, |
| 404 | {0x001D0000, nullptr, "GetInputLines"}, | ||
| 390 | {0x001E0100, SetCoefficient, "SetCoefficient"}, | 405 | {0x001E0100, SetCoefficient, "SetCoefficient"}, |
| 406 | {0x001F0000, nullptr, "GetCoefficient"}, | ||
| 391 | {0x00200040, SetStandardCoefficient, "SetStandardCoefficient"}, | 407 | {0x00200040, SetStandardCoefficient, "SetStandardCoefficient"}, |
| 408 | {0x00210040, nullptr, "GetStandardCoefficientParams"}, | ||
| 392 | {0x00220040, SetAlpha, "SetAlpha"}, | 409 | {0x00220040, SetAlpha, "SetAlpha"}, |
| 410 | {0x00230000, nullptr, "GetAlpha"}, | ||
| 411 | {0x00240200, nullptr, "SetDitheringWeightParams"}, | ||
| 412 | {0x00250000, nullptr, "GetDitheringWeightParams"}, | ||
| 393 | {0x00260000, StartConversion, "StartConversion"}, | 413 | {0x00260000, StartConversion, "StartConversion"}, |
| 394 | {0x00270000, StopConversion, "StopConversion"}, | 414 | {0x00270000, StopConversion, "StopConversion"}, |
| 395 | {0x00280000, IsBusyConversion, "IsBusyConversion"}, | 415 | {0x00280000, IsBusyConversion, "IsBusyConversion"}, |
| @@ -397,6 +417,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 397 | {0x002A0000, PingProcess, "PingProcess"}, | 417 | {0x002A0000, PingProcess, "PingProcess"}, |
| 398 | {0x002B0000, DriverInitialize, "DriverInitialize"}, | 418 | {0x002B0000, DriverInitialize, "DriverInitialize"}, |
| 399 | {0x002C0000, DriverFinalize, "DriverFinalize"}, | 419 | {0x002C0000, DriverFinalize, "DriverFinalize"}, |
| 420 | {0x002D0000, nullptr, "GetPackageParameter"}, | ||
| 400 | }; | 421 | }; |
| 401 | 422 | ||
| 402 | //////////////////////////////////////////////////////////////////////////////////////////////////// | 423 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 45d5f3c5d..e39edcc16 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp | |||
| @@ -778,6 +778,51 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 | |||
| 778 | return RESULT_SUCCESS; | 778 | return RESULT_SUCCESS; |
| 779 | } | 779 | } |
| 780 | 780 | ||
| 781 | static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) { | ||
| 782 | using Kernel::MemoryRegion; | ||
| 783 | |||
| 784 | LOG_TRACE(Kernel_SVC, "called type=%u param=%d", type, param); | ||
| 785 | |||
| 786 | switch ((SystemInfoType)type) { | ||
| 787 | case SystemInfoType::REGION_MEMORY_USAGE: | ||
| 788 | switch ((SystemInfoMemUsageRegion)param) { | ||
| 789 | case SystemInfoMemUsageRegion::ALL: | ||
| 790 | *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::APPLICATION)->used | ||
| 791 | + Kernel::GetMemoryRegion(Kernel::MemoryRegion::SYSTEM)->used | ||
| 792 | + Kernel::GetMemoryRegion(Kernel::MemoryRegion::BASE)->used; | ||
| 793 | break; | ||
| 794 | case SystemInfoMemUsageRegion::APPLICATION: | ||
| 795 | *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::APPLICATION)->used; | ||
| 796 | break; | ||
| 797 | case SystemInfoMemUsageRegion::SYSTEM: | ||
| 798 | *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::SYSTEM)->used; | ||
| 799 | break; | ||
| 800 | case SystemInfoMemUsageRegion::BASE: | ||
| 801 | *out = Kernel::GetMemoryRegion(Kernel::MemoryRegion::BASE)->used; | ||
| 802 | break; | ||
| 803 | default: | ||
| 804 | LOG_ERROR(Kernel_SVC, "unknown GetSystemInfo type=0 region: param=%d", param); | ||
| 805 | *out = 0; | ||
| 806 | break; | ||
| 807 | } | ||
| 808 | break; | ||
| 809 | case SystemInfoType::KERNEL_ALLOCATED_PAGES: | ||
| 810 | LOG_ERROR(Kernel_SVC, "unimplemented GetSystemInfo type=2 param=%d", param); | ||
| 811 | *out = 0; | ||
| 812 | break; | ||
| 813 | case SystemInfoType::KERNEL_SPAWNED_PIDS: | ||
| 814 | *out = 5; | ||
| 815 | break; | ||
| 816 | default: | ||
| 817 | LOG_ERROR(Kernel_SVC, "unknown GetSystemInfo type=%u param=%d", type, param); | ||
| 818 | *out = 0; | ||
| 819 | break; | ||
| 820 | } | ||
| 821 | |||
| 822 | // This function never returns an error, even if invalid parameters were passed. | ||
| 823 | return RESULT_SUCCESS; | ||
| 824 | } | ||
| 825 | |||
| 781 | static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) { | 826 | static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) { |
| 782 | LOG_TRACE(Kernel_SVC, "called process=0x%08X type=%u", process_handle, type); | 827 | LOG_TRACE(Kernel_SVC, "called process=0x%08X type=%u", process_handle, type); |
| 783 | 828 | ||
| @@ -877,7 +922,7 @@ static const FunctionDef SVC_Table[] = { | |||
| 877 | {0x27, HLE::Wrap<DuplicateHandle>, "DuplicateHandle"}, | 922 | {0x27, HLE::Wrap<DuplicateHandle>, "DuplicateHandle"}, |
| 878 | {0x28, HLE::Wrap<GetSystemTick>, "GetSystemTick"}, | 923 | {0x28, HLE::Wrap<GetSystemTick>, "GetSystemTick"}, |
| 879 | {0x29, nullptr, "GetHandleInfo"}, | 924 | {0x29, nullptr, "GetHandleInfo"}, |
| 880 | {0x2A, nullptr, "GetSystemInfo"}, | 925 | {0x2A, HLE::Wrap<GetSystemInfo>, "GetSystemInfo"}, |
| 881 | {0x2B, HLE::Wrap<GetProcessInfo>, "GetProcessInfo"}, | 926 | {0x2B, HLE::Wrap<GetProcessInfo>, "GetProcessInfo"}, |
| 882 | {0x2C, nullptr, "GetThreadInfo"}, | 927 | {0x2C, nullptr, "GetThreadInfo"}, |
| 883 | {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"}, | 928 | {0x2D, HLE::Wrap<ConnectToPort>, "ConnectToPort"}, |
diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h index 12de9ffbe..4b9c71e06 100644 --- a/src/core/hle/svc.h +++ b/src/core/hle/svc.h | |||
| @@ -41,6 +41,35 @@ enum ArbitrationType { | |||
| 41 | 41 | ||
| 42 | namespace SVC { | 42 | namespace SVC { |
| 43 | 43 | ||
| 44 | /// Values accepted by svcGetSystemInfo's type parameter. | ||
| 45 | enum class SystemInfoType { | ||
| 46 | /** | ||
| 47 | * Reports total used memory for all regions or a specific one, according to the extra | ||
| 48 | * parameter. See `SystemInfoMemUsageRegion`. | ||
| 49 | */ | ||
| 50 | REGION_MEMORY_USAGE = 0, | ||
| 51 | /** | ||
| 52 | * Returns the memory usage for certain allocations done internally by the kernel. | ||
| 53 | */ | ||
| 54 | KERNEL_ALLOCATED_PAGES = 2, | ||
| 55 | /** | ||
| 56 | * "This returns the total number of processes which were launched directly by the kernel. | ||
| 57 | * For the ARM11 NATIVE_FIRM kernel, this is 5, for processes sm, fs, pm, loader, and pxi." | ||
| 58 | */ | ||
| 59 | KERNEL_SPAWNED_PIDS = 26, | ||
| 60 | }; | ||
| 61 | |||
| 62 | /** | ||
| 63 | * Accepted by svcGetSystemInfo param with REGION_MEMORY_USAGE type. Selects a region to query | ||
| 64 | * memory usage of. | ||
| 65 | */ | ||
| 66 | enum class SystemInfoMemUsageRegion { | ||
| 67 | ALL = 0, | ||
| 68 | APPLICATION = 1, | ||
| 69 | SYSTEM = 2, | ||
| 70 | BASE = 3, | ||
| 71 | }; | ||
| 72 | |||
| 44 | void CallSVC(u32 immediate); | 73 | void CallSVC(u32 immediate); |
| 45 | 74 | ||
| 46 | } // namespace | 75 | } // namespace |
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index bc7bde903..4bd3a632d 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp | |||
| @@ -26,7 +26,7 @@ | |||
| 26 | #include "core/tracer/recorder.h" | 26 | #include "core/tracer/recorder.h" |
| 27 | 27 | ||
| 28 | #include "video_core/command_processor.h" | 28 | #include "video_core/command_processor.h" |
| 29 | #include "video_core/hwrasterizer_base.h" | 29 | #include "video_core/rasterizer_interface.h" |
| 30 | #include "video_core/renderer_base.h" | 30 | #include "video_core/renderer_base.h" |
| 31 | #include "video_core/utils.h" | 31 | #include "video_core/utils.h" |
| 32 | #include "video_core/video_core.h" | 32 | #include "video_core/video_core.h" |
| @@ -141,7 +141,7 @@ inline void Write(u32 addr, const T data) { | |||
| 141 | GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC1); | 141 | GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC1); |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetStartAddress(), config.GetEndAddress() - config.GetStartAddress()); | 144 | VideoCore::g_renderer->rasterizer->InvalidateRegion(config.GetStartAddress(), config.GetEndAddress() - config.GetStartAddress()); |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | // Reset "trigger" flag and set the "finish" flag | 147 | // Reset "trigger" flag and set the "finish" flag |
| @@ -172,7 +172,7 @@ inline void Write(u32 addr, const T data) { | |||
| 172 | u32 output_gap = config.texture_copy.output_gap * 16; | 172 | u32 output_gap = config.texture_copy.output_gap * 16; |
| 173 | 173 | ||
| 174 | size_t contiguous_input_size = config.texture_copy.size / input_width * (input_width + input_gap); | 174 | size_t contiguous_input_size = config.texture_copy.size / input_width * (input_width + input_gap); |
| 175 | VideoCore::g_renderer->hw_rasterizer->NotifyPreRead(config.GetPhysicalInputAddress(), contiguous_input_size); | 175 | VideoCore::g_renderer->rasterizer->FlushRegion(config.GetPhysicalInputAddress(), contiguous_input_size); |
| 176 | 176 | ||
| 177 | u32 remaining_size = config.texture_copy.size; | 177 | u32 remaining_size = config.texture_copy.size; |
| 178 | u32 remaining_input = input_width; | 178 | u32 remaining_input = input_width; |
| @@ -205,7 +205,7 @@ inline void Write(u32 addr, const T data) { | |||
| 205 | config.flags); | 205 | config.flags); |
| 206 | 206 | ||
| 207 | size_t contiguous_output_size = config.texture_copy.size / output_width * (output_width + output_gap); | 207 | size_t contiguous_output_size = config.texture_copy.size / output_width * (output_width + output_gap); |
| 208 | VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetPhysicalOutputAddress(), contiguous_output_size); | 208 | VideoCore::g_renderer->rasterizer->InvalidateRegion(config.GetPhysicalOutputAddress(), contiguous_output_size); |
| 209 | 209 | ||
| 210 | GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF); | 210 | GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF); |
| 211 | break; | 211 | break; |
| @@ -232,7 +232,7 @@ inline void Write(u32 addr, const T data) { | |||
| 232 | u32 input_size = config.input_width * config.input_height * GPU::Regs::BytesPerPixel(config.input_format); | 232 | u32 input_size = config.input_width * config.input_height * GPU::Regs::BytesPerPixel(config.input_format); |
| 233 | u32 output_size = output_width * output_height * GPU::Regs::BytesPerPixel(config.output_format); | 233 | u32 output_size = output_width * output_height * GPU::Regs::BytesPerPixel(config.output_format); |
| 234 | 234 | ||
| 235 | VideoCore::g_renderer->hw_rasterizer->NotifyPreRead(config.GetPhysicalInputAddress(), input_size); | 235 | VideoCore::g_renderer->rasterizer->FlushRegion(config.GetPhysicalInputAddress(), input_size); |
| 236 | 236 | ||
| 237 | for (u32 y = 0; y < output_height; ++y) { | 237 | for (u32 y = 0; y < output_height; ++y) { |
| 238 | for (u32 x = 0; x < output_width; ++x) { | 238 | for (u32 x = 0; x < output_width; ++x) { |
| @@ -339,7 +339,7 @@ inline void Write(u32 addr, const T data) { | |||
| 339 | g_regs.display_transfer_config.trigger = 0; | 339 | g_regs.display_transfer_config.trigger = 0; |
| 340 | GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF); | 340 | GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF); |
| 341 | 341 | ||
| 342 | VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetPhysicalOutputAddress(), output_size); | 342 | VideoCore::g_renderer->rasterizer->InvalidateRegion(config.GetPhysicalOutputAddress(), output_size); |
| 343 | } | 343 | } |
| 344 | break; | 344 | break; |
| 345 | } | 345 | } |
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index 111b6a409..8eed6a50a 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp | |||
| @@ -181,14 +181,14 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, Shared | |||
| 181 | 181 | ||
| 182 | for (unsigned current_inprogress = 0; current_inprogress < remaining && pos < end_pos; current_inprogress++) { | 182 | for (unsigned current_inprogress = 0; current_inprogress < remaining && pos < end_pos; current_inprogress++) { |
| 183 | const auto& table = reloc_table[current_inprogress]; | 183 | const auto& table = reloc_table[current_inprogress]; |
| 184 | LOG_TRACE(Loader, "(t=%d,skip=%u,patch=%u)\n", current_segment_reloc_table, | 184 | LOG_TRACE(Loader, "(t=%d,skip=%u,patch=%u)", current_segment_reloc_table, |
| 185 | (u32)table.skip, (u32)table.patch); | 185 | (u32)table.skip, (u32)table.patch); |
| 186 | pos += table.skip; | 186 | pos += table.skip; |
| 187 | s32 num_patches = table.patch; | 187 | s32 num_patches = table.patch; |
| 188 | while (0 < num_patches && pos < end_pos) { | 188 | while (0 < num_patches && pos < end_pos) { |
| 189 | u32 in_addr = (u8*)pos - program_image.data(); | 189 | u32 in_addr = (u8*)pos - program_image.data(); |
| 190 | u32 addr = TranslateAddr(*pos, &loadinfo, offsets); | 190 | u32 addr = TranslateAddr(*pos, &loadinfo, offsets); |
| 191 | LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)\n", | 191 | LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)", |
| 192 | base_addr + in_addr, addr, current_segment_reloc_table, *pos); | 192 | base_addr + in_addr, addr, current_segment_reloc_table, *pos); |
| 193 | switch (current_segment_reloc_table) { | 193 | switch (current_segment_reloc_table) { |
| 194 | case 0: | 194 | case 0: |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index 8de95dacf..a7f2715ba 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -71,6 +71,7 @@ enum class ResultStatus { | |||
| 71 | ErrorNotUsed, | 71 | ErrorNotUsed, |
| 72 | ErrorAlreadyLoaded, | 72 | ErrorAlreadyLoaded, |
| 73 | ErrorMemoryAllocationFailed, | 73 | ErrorMemoryAllocationFailed, |
| 74 | ErrorEncrypted, | ||
| 74 | }; | 75 | }; |
| 75 | 76 | ||
| 76 | static inline u32 MakeMagic(char a, char b, char c, char d) { | 77 | static inline u32 MakeMagic(char a, char b, char c, char d) { |
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 094d74100..68b3f546e 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp | |||
| @@ -128,9 +128,8 @@ ResultStatus AppLoader_NCCH::LoadExec() { | |||
| 128 | if (ResultStatus::Success == ReadCode(code)) { | 128 | if (ResultStatus::Success == ReadCode(code)) { |
| 129 | std::string process_name = Common::StringFromFixedZeroTerminatedBuffer( | 129 | std::string process_name = Common::StringFromFixedZeroTerminatedBuffer( |
| 130 | (const char*)exheader_header.codeset_info.name, 8); | 130 | (const char*)exheader_header.codeset_info.name, 8); |
| 131 | u64 program_id = *reinterpret_cast<u64_le const*>(&ncch_header.program_id[0]); | ||
| 132 | 131 | ||
| 133 | SharedPtr<CodeSet> codeset = CodeSet::Create(process_name, program_id); | 132 | SharedPtr<CodeSet> codeset = CodeSet::Create(process_name, ncch_header.program_id); |
| 134 | 133 | ||
| 135 | codeset->code.offset = 0; | 134 | codeset->code.offset = 0; |
| 136 | codeset->code.addr = exheader_header.codeset_info.text.address; | 135 | codeset->code.addr = exheader_header.codeset_info.text.address; |
| @@ -266,6 +265,11 @@ ResultStatus AppLoader_NCCH::Load() { | |||
| 266 | LOG_DEBUG(Loader, "Thread priority: 0x%X" , priority); | 265 | LOG_DEBUG(Loader, "Thread priority: 0x%X" , priority); |
| 267 | LOG_DEBUG(Loader, "Resource limit category: %d" , resource_limit_category); | 266 | LOG_DEBUG(Loader, "Resource limit category: %d" , resource_limit_category); |
| 268 | 267 | ||
| 268 | if (exheader_header.arm11_system_local_caps.program_id != ncch_header.program_id) { | ||
| 269 | LOG_ERROR(Loader, "ExHeader Program ID mismatch: the ROM is probably encrypted."); | ||
| 270 | return ResultStatus::ErrorEncrypted; | ||
| 271 | } | ||
| 272 | |||
| 269 | // Read ExeFS... | 273 | // Read ExeFS... |
| 270 | 274 | ||
| 271 | exefs_offset = ncch_header.exefs_offset * kBlockSize; | 275 | exefs_offset = ncch_header.exefs_offset * kBlockSize; |
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h index d875e4cf3..ca6772a78 100644 --- a/src/core/loader/ncch.h +++ b/src/core/loader/ncch.h | |||
| @@ -17,31 +17,31 @@ | |||
| 17 | 17 | ||
| 18 | struct NCCH_Header { | 18 | struct NCCH_Header { |
| 19 | u8 signature[0x100]; | 19 | u8 signature[0x100]; |
| 20 | u32 magic; | 20 | u32_le magic; |
| 21 | u32 content_size; | 21 | u32_le content_size; |
| 22 | u8 partition_id[8]; | 22 | u8 partition_id[8]; |
| 23 | u16 maker_code; | 23 | u16_le maker_code; |
| 24 | u16 version; | 24 | u16_le version; |
| 25 | u8 reserved_0[4]; | 25 | u8 reserved_0[4]; |
| 26 | u8 program_id[8]; | 26 | u64_le program_id; |
| 27 | u8 reserved_1[0x10]; | 27 | u8 reserved_1[0x10]; |
| 28 | u8 logo_region_hash[0x20]; | 28 | u8 logo_region_hash[0x20]; |
| 29 | u8 product_code[0x10]; | 29 | u8 product_code[0x10]; |
| 30 | u8 extended_header_hash[0x20]; | 30 | u8 extended_header_hash[0x20]; |
| 31 | u32 extended_header_size; | 31 | u32_le extended_header_size; |
| 32 | u8 reserved_2[4]; | 32 | u8 reserved_2[4]; |
| 33 | u8 flags[8]; | 33 | u8 flags[8]; |
| 34 | u32 plain_region_offset; | 34 | u32_le plain_region_offset; |
| 35 | u32 plain_region_size; | 35 | u32_le plain_region_size; |
| 36 | u32 logo_region_offset; | 36 | u32_le logo_region_offset; |
| 37 | u32 logo_region_size; | 37 | u32_le logo_region_size; |
| 38 | u32 exefs_offset; | 38 | u32_le exefs_offset; |
| 39 | u32 exefs_size; | 39 | u32_le exefs_size; |
| 40 | u32 exefs_hash_region_size; | 40 | u32_le exefs_hash_region_size; |
| 41 | u8 reserved_3[4]; | 41 | u8 reserved_3[4]; |
| 42 | u32 romfs_offset; | 42 | u32_le romfs_offset; |
| 43 | u32 romfs_size; | 43 | u32_le romfs_size; |
| 44 | u32 romfs_hash_region_size; | 44 | u32_le romfs_hash_region_size; |
| 45 | u8 reserved_4[4]; | 45 | u8 reserved_4[4]; |
| 46 | u8 exefs_super_block_hash[0x20]; | 46 | u8 exefs_super_block_hash[0x20]; |
| 47 | u8 romfs_super_block_hash[0x20]; | 47 | u8 romfs_super_block_hash[0x20]; |
| @@ -109,8 +109,8 @@ struct ExHeader_StorageInfo { | |||
| 109 | }; | 109 | }; |
| 110 | 110 | ||
| 111 | struct ExHeader_ARM11_SystemLocalCaps { | 111 | struct ExHeader_ARM11_SystemLocalCaps { |
| 112 | u8 program_id[8]; | 112 | u64_le program_id; |
| 113 | u32 core_version; | 113 | u32_le core_version; |
| 114 | u8 reserved_flags[2]; | 114 | u8 reserved_flags[2]; |
| 115 | union { | 115 | union { |
| 116 | u8 flags0; | 116 | u8 flags0; |
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index b80795e0c..fc79c3ee9 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -26,9 +26,9 @@ enum class PageType { | |||
| 26 | }; | 26 | }; |
| 27 | 27 | ||
| 28 | /** | 28 | /** |
| 29 | * A (reasonably) fast way of allowing switchable and remmapable process address spaces. It loosely | 29 | * A (reasonably) fast way of allowing switchable and remappable process address spaces. It loosely |
| 30 | * mimics the way a real CPU page table works, but instead is optimized for minimal decoding and | 30 | * mimics the way a real CPU page table works, but instead is optimized for minimal decoding and |
| 31 | * fetching requirements when acessing. In the usual case of an access to regular memory, it only | 31 | * fetching requirements when accessing. In the usual case of an access to regular memory, it only |
| 32 | * requires an indexed fetch and a check for NULL. | 32 | * requires an indexed fetch and a check for NULL. |
| 33 | */ | 33 | */ |
| 34 | struct PageTable { | 34 | struct PageTable { |
diff --git a/src/core/settings.h b/src/core/settings.h index 0b05e5bee..97ddcdff9 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <string> | 7 | #include <string> |
| 8 | #include <array> | 8 | #include <array> |
| 9 | #include <common/file_util.h> | ||
| 9 | 10 | ||
| 10 | namespace Settings { | 11 | namespace Settings { |
| 11 | 12 | ||
| @@ -60,6 +61,10 @@ struct Values { | |||
| 60 | float bg_blue; | 61 | float bg_blue; |
| 61 | 62 | ||
| 62 | std::string log_filter; | 63 | std::string log_filter; |
| 64 | |||
| 65 | // Debugging | ||
| 66 | bool use_gdbstub; | ||
| 67 | u16 gdbstub_port; | ||
| 63 | } extern values; | 68 | } extern values; |
| 64 | 69 | ||
| 65 | } | 70 | } |
diff --git a/src/core/system.cpp b/src/core/system.cpp index 3cd84bf5e..7e9c56538 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp | |||
| @@ -12,6 +12,8 @@ | |||
| 12 | 12 | ||
| 13 | #include "video_core/video_core.h" | 13 | #include "video_core/video_core.h" |
| 14 | 14 | ||
| 15 | #include "core/gdbstub/gdbstub.h" | ||
| 16 | |||
| 15 | namespace System { | 17 | namespace System { |
| 16 | 18 | ||
| 17 | void Init(EmuWindow* emu_window) { | 19 | void Init(EmuWindow* emu_window) { |
| @@ -22,9 +24,11 @@ void Init(EmuWindow* emu_window) { | |||
| 22 | Kernel::Init(); | 24 | Kernel::Init(); |
| 23 | HLE::Init(); | 25 | HLE::Init(); |
| 24 | VideoCore::Init(emu_window); | 26 | VideoCore::Init(emu_window); |
| 27 | GDBStub::Init(); | ||
| 25 | } | 28 | } |
| 26 | 29 | ||
| 27 | void Shutdown() { | 30 | void Shutdown() { |
| 31 | GDBStub::Shutdown(); | ||
| 28 | VideoCore::Shutdown(); | 32 | VideoCore::Shutdown(); |
| 29 | HLE::Shutdown(); | 33 | HLE::Shutdown(); |
| 30 | Kernel::Shutdown(); | 34 | Kernel::Shutdown(); |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 8c9d76ab4..c3d7294d5 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | set(SRCS | 1 | set(SRCS |
| 2 | renderer_opengl/gl_rasterizer.cpp | 2 | renderer_opengl/gl_rasterizer.cpp |
| 3 | renderer_opengl/gl_rasterizer_cache.cpp | 3 | renderer_opengl/gl_rasterizer_cache.cpp |
| 4 | renderer_opengl/gl_shader_gen.cpp | ||
| 4 | renderer_opengl/gl_shader_util.cpp | 5 | renderer_opengl/gl_shader_util.cpp |
| 5 | renderer_opengl/gl_state.cpp | 6 | renderer_opengl/gl_state.cpp |
| 6 | renderer_opengl/renderer_opengl.cpp | 7 | renderer_opengl/renderer_opengl.cpp |
| @@ -10,8 +11,10 @@ set(SRCS | |||
| 10 | pica.cpp | 11 | pica.cpp |
| 11 | primitive_assembly.cpp | 12 | primitive_assembly.cpp |
| 12 | rasterizer.cpp | 13 | rasterizer.cpp |
| 14 | renderer_base.cpp | ||
| 13 | shader/shader.cpp | 15 | shader/shader.cpp |
| 14 | shader/shader_interpreter.cpp | 16 | shader/shader_interpreter.cpp |
| 17 | swrasterizer.cpp | ||
| 15 | utils.cpp | 18 | utils.cpp |
| 16 | video_core.cpp | 19 | video_core.cpp |
| 17 | ) | 20 | ) |
| @@ -21,21 +24,22 @@ set(HEADERS | |||
| 21 | renderer_opengl/gl_rasterizer.h | 24 | renderer_opengl/gl_rasterizer.h |
| 22 | renderer_opengl/gl_rasterizer_cache.h | 25 | renderer_opengl/gl_rasterizer_cache.h |
| 23 | renderer_opengl/gl_resource_manager.h | 26 | renderer_opengl/gl_resource_manager.h |
| 27 | renderer_opengl/gl_shader_gen.h | ||
| 24 | renderer_opengl/gl_shader_util.h | 28 | renderer_opengl/gl_shader_util.h |
| 25 | renderer_opengl/gl_shaders.h | ||
| 26 | renderer_opengl/gl_state.h | 29 | renderer_opengl/gl_state.h |
| 27 | renderer_opengl/pica_to_gl.h | 30 | renderer_opengl/pica_to_gl.h |
| 28 | renderer_opengl/renderer_opengl.h | 31 | renderer_opengl/renderer_opengl.h |
| 29 | clipper.h | 32 | clipper.h |
| 30 | command_processor.h | 33 | command_processor.h |
| 31 | gpu_debugger.h | 34 | gpu_debugger.h |
| 32 | hwrasterizer_base.h | ||
| 33 | pica.h | 35 | pica.h |
| 34 | primitive_assembly.h | 36 | primitive_assembly.h |
| 35 | rasterizer.h | 37 | rasterizer.h |
| 38 | rasterizer_interface.h | ||
| 36 | renderer_base.h | 39 | renderer_base.h |
| 37 | shader/shader.h | 40 | shader/shader.h |
| 38 | shader/shader_interpreter.h | 41 | shader/shader_interpreter.h |
| 42 | swrasterizer.h | ||
| 39 | utils.h | 43 | utils.h |
| 40 | video_core.h | 44 | video_core.h |
| 41 | ) | 45 | ) |
diff --git a/src/video_core/clipper.cpp b/src/video_core/clipper.cpp index ed99c4f13..5d609da06 100644 --- a/src/video_core/clipper.cpp +++ b/src/video_core/clipper.cpp | |||
| @@ -78,7 +78,7 @@ static void InitScreenCoordinates(OutputVertex& vtx) | |||
| 78 | vtx.screenpos[2] = viewport.offset_z + vtx.pos.z * inv_w * viewport.zscale; | 78 | vtx.screenpos[2] = viewport.offset_z + vtx.pos.z * inv_w * viewport.zscale; |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) { | 81 | void ProcessTriangle(const OutputVertex &v0, const OutputVertex &v1, const OutputVertex &v2) { |
| 82 | using boost::container::static_vector; | 82 | using boost::container::static_vector; |
| 83 | 83 | ||
| 84 | // Clipping a planar n-gon against a plane will remove at least 1 vertex and introduces 2 at | 84 | // Clipping a planar n-gon against a plane will remove at least 1 vertex and introduces 2 at |
diff --git a/src/video_core/clipper.h b/src/video_core/clipper.h index 6ed01e877..f85d8d4c9 100644 --- a/src/video_core/clipper.h +++ b/src/video_core/clipper.h | |||
| @@ -14,7 +14,7 @@ namespace Clipper { | |||
| 14 | 14 | ||
| 15 | using Shader::OutputVertex; | 15 | using Shader::OutputVertex; |
| 16 | 16 | ||
| 17 | void ProcessTriangle(OutputVertex& v0, OutputVertex& v1, OutputVertex& v2); | 17 | void ProcessTriangle(const OutputVertex& v0, const OutputVertex& v1, const OutputVertex& v2); |
| 18 | 18 | ||
| 19 | } // namespace | 19 | } // namespace |
| 20 | 20 | ||
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 47afd8938..35b976c60 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp | |||
| @@ -157,6 +157,8 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 157 | 157 | ||
| 158 | // TODO: What happens if a loader overwrites a previous one's data? | 158 | // TODO: What happens if a loader overwrites a previous one's data? |
| 159 | for (unsigned component = 0; component < loader_config.component_count; ++component) { | 159 | for (unsigned component = 0; component < loader_config.component_count; ++component) { |
| 160 | if (component >= 12) | ||
| 161 | LOG_ERROR(HW_GPU, "Overflow in the vertex attribute loader %u trying to load component %u", loader, component); | ||
| 160 | u32 attribute_index = loader_config.GetComponent(component); | 162 | u32 attribute_index = loader_config.GetComponent(component); |
| 161 | vertex_attribute_sources[attribute_index] = load_address; | 163 | vertex_attribute_sources[attribute_index] = load_address; |
| 162 | vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count); | 164 | vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count); |
| @@ -334,19 +336,14 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 334 | } | 336 | } |
| 335 | } | 337 | } |
| 336 | 338 | ||
| 337 | if (Settings::values.use_hw_renderer) { | 339 | // Send to renderer |
| 338 | // Send to hardware renderer | 340 | using Pica::Shader::OutputVertex; |
| 339 | static auto AddHWTriangle = [](const Pica::Shader::OutputVertex& v0, | 341 | auto AddTriangle = []( |
| 340 | const Pica::Shader::OutputVertex& v1, | 342 | const OutputVertex& v0, const OutputVertex& v1, const OutputVertex& v2) { |
| 341 | const Pica::Shader::OutputVertex& v2) { | 343 | VideoCore::g_renderer->rasterizer->AddTriangle(v0, v1, v2); |
| 342 | VideoCore::g_renderer->hw_rasterizer->AddTriangle(v0, v1, v2); | 344 | }; |
| 343 | }; | ||
| 344 | 345 | ||
| 345 | primitive_assembler.SubmitVertex(output, AddHWTriangle); | 346 | primitive_assembler.SubmitVertex(output, AddTriangle); |
| 346 | } else { | ||
| 347 | // Send to triangle clipper | ||
| 348 | primitive_assembler.SubmitVertex(output, Clipper::ProcessTriangle); | ||
| 349 | } | ||
| 350 | } | 347 | } |
| 351 | 348 | ||
| 352 | for (auto& range : memory_accesses.ranges) { | 349 | for (auto& range : memory_accesses.ranges) { |
| @@ -354,9 +351,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 354 | range.second, range.first); | 351 | range.second, range.first); |
| 355 | } | 352 | } |
| 356 | 353 | ||
| 357 | if (Settings::values.use_hw_renderer) { | 354 | VideoCore::g_renderer->rasterizer->DrawTriangles(); |
| 358 | VideoCore::g_renderer->hw_rasterizer->DrawTriangles(); | ||
| 359 | } | ||
| 360 | 355 | ||
| 361 | #if PICA_DUMP_GEOMETRY | 356 | #if PICA_DUMP_GEOMETRY |
| 362 | geometry_dumper.Dump(); | 357 | geometry_dumper.Dump(); |
| @@ -473,7 +468,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) { | |||
| 473 | break; | 468 | break; |
| 474 | } | 469 | } |
| 475 | 470 | ||
| 476 | VideoCore::g_renderer->hw_rasterizer->NotifyPicaRegisterChanged(id); | 471 | VideoCore::g_renderer->rasterizer->NotifyPicaRegisterChanged(id); |
| 477 | 472 | ||
| 478 | if (g_debug_context) | 473 | if (g_debug_context) |
| 479 | g_debug_context->OnEvent(DebugContext::Event::PicaCommandProcessed, reinterpret_cast<void*>(&id)); | 474 | g_debug_context->OnEvent(DebugContext::Event::PicaCommandProcessed, reinterpret_cast<void*>(&id)); |
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index aa1f1484c..4f66dbd65 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp | |||
| @@ -46,10 +46,8 @@ void DebugContext::OnEvent(Event event, void* data) { | |||
| 46 | { | 46 | { |
| 47 | std::unique_lock<std::mutex> lock(breakpoint_mutex); | 47 | std::unique_lock<std::mutex> lock(breakpoint_mutex); |
| 48 | 48 | ||
| 49 | if (Settings::values.use_hw_renderer) { | 49 | // Commit the hardware renderer's framebuffer so it will show on debug widgets |
| 50 | // Commit the hardware renderer's framebuffer so it will show on debug widgets | 50 | VideoCore::g_renderer->rasterizer->FlushFramebuffer(); |
| 51 | VideoCore::g_renderer->hw_rasterizer->CommitFramebuffer(); | ||
| 52 | } | ||
| 53 | 51 | ||
| 54 | // TODO: Should stop the CPU thread here once we multithread emulation. | 52 | // TODO: Should stop the CPU thread here once we multithread emulation. |
| 55 | 53 | ||
| @@ -641,7 +639,7 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { | |||
| 641 | // Initialize write structure | 639 | // Initialize write structure |
| 642 | png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); | 640 | png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); |
| 643 | if (png_ptr == nullptr) { | 641 | if (png_ptr == nullptr) { |
| 644 | LOG_ERROR(Debug_GPU, "Could not allocate write struct\n"); | 642 | LOG_ERROR(Debug_GPU, "Could not allocate write struct"); |
| 645 | goto finalise; | 643 | goto finalise; |
| 646 | 644 | ||
| 647 | } | 645 | } |
| @@ -649,13 +647,13 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { | |||
| 649 | // Initialize info structure | 647 | // Initialize info structure |
| 650 | info_ptr = png_create_info_struct(png_ptr); | 648 | info_ptr = png_create_info_struct(png_ptr); |
| 651 | if (info_ptr == nullptr) { | 649 | if (info_ptr == nullptr) { |
| 652 | LOG_ERROR(Debug_GPU, "Could not allocate info struct\n"); | 650 | LOG_ERROR(Debug_GPU, "Could not allocate info struct"); |
| 653 | goto finalise; | 651 | goto finalise; |
| 654 | } | 652 | } |
| 655 | 653 | ||
| 656 | // Setup Exception handling | 654 | // Setup Exception handling |
| 657 | if (setjmp(png_jmpbuf(png_ptr))) { | 655 | if (setjmp(png_jmpbuf(png_ptr))) { |
| 658 | LOG_ERROR(Debug_GPU, "Error during png creation\n"); | 656 | LOG_ERROR(Debug_GPU, "Error during png creation"); |
| 659 | goto finalise; | 657 | goto finalise; |
| 660 | } | 658 | } |
| 661 | 659 | ||
diff --git a/src/video_core/pica.h b/src/video_core/pica.h index ff81b409d..2f1b2dec4 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h | |||
| @@ -317,6 +317,7 @@ struct Regs { | |||
| 317 | }; | 317 | }; |
| 318 | 318 | ||
| 319 | union { | 319 | union { |
| 320 | u32 sources_raw; | ||
| 320 | BitField< 0, 4, Source> color_source1; | 321 | BitField< 0, 4, Source> color_source1; |
| 321 | BitField< 4, 4, Source> color_source2; | 322 | BitField< 4, 4, Source> color_source2; |
| 322 | BitField< 8, 4, Source> color_source3; | 323 | BitField< 8, 4, Source> color_source3; |
| @@ -326,6 +327,7 @@ struct Regs { | |||
| 326 | }; | 327 | }; |
| 327 | 328 | ||
| 328 | union { | 329 | union { |
| 330 | u32 modifiers_raw; | ||
| 329 | BitField< 0, 4, ColorModifier> color_modifier1; | 331 | BitField< 0, 4, ColorModifier> color_modifier1; |
| 330 | BitField< 4, 4, ColorModifier> color_modifier2; | 332 | BitField< 4, 4, ColorModifier> color_modifier2; |
| 331 | BitField< 8, 4, ColorModifier> color_modifier3; | 333 | BitField< 8, 4, ColorModifier> color_modifier3; |
| @@ -335,6 +337,7 @@ struct Regs { | |||
| 335 | }; | 337 | }; |
| 336 | 338 | ||
| 337 | union { | 339 | union { |
| 340 | u32 ops_raw; | ||
| 338 | BitField< 0, 4, Operation> color_op; | 341 | BitField< 0, 4, Operation> color_op; |
| 339 | BitField<16, 4, Operation> alpha_op; | 342 | BitField<16, 4, Operation> alpha_op; |
| 340 | }; | 343 | }; |
| @@ -348,6 +351,7 @@ struct Regs { | |||
| 348 | }; | 351 | }; |
| 349 | 352 | ||
| 350 | union { | 353 | union { |
| 354 | u32 scales_raw; | ||
| 351 | BitField< 0, 2, u32> color_scale; | 355 | BitField< 0, 2, u32> color_scale; |
| 352 | BitField<16, 2, u32> alpha_scale; | 356 | BitField<16, 2, u32> alpha_scale; |
| 353 | }; | 357 | }; |
diff --git a/src/video_core/primitive_assembly.cpp b/src/video_core/primitive_assembly.cpp index 44a8dbfe9..d5a0a96a4 100644 --- a/src/video_core/primitive_assembly.cpp +++ b/src/video_core/primitive_assembly.cpp | |||
| @@ -39,13 +39,12 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(VertexType& vtx, TriangleHandl | |||
| 39 | 39 | ||
| 40 | buffer[buffer_index] = vtx; | 40 | buffer[buffer_index] = vtx; |
| 41 | 41 | ||
| 42 | if (topology == Regs::TriangleTopology::Strip) { | 42 | strip_ready |= (buffer_index == 1); |
| 43 | strip_ready |= (buffer_index == 1); | 43 | |
| 44 | if (topology == Regs::TriangleTopology::Strip) | ||
| 44 | buffer_index = !buffer_index; | 45 | buffer_index = !buffer_index; |
| 45 | } else if (topology == Regs::TriangleTopology::Fan) { | 46 | else if (topology == Regs::TriangleTopology::Fan) |
| 46 | buffer_index = 1; | 47 | buffer_index = 1; |
| 47 | strip_ready = true; | ||
| 48 | } | ||
| 49 | break; | 48 | break; |
| 50 | 49 | ||
| 51 | default: | 50 | default: |
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 7abf60292..ecfdbc9e8 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp | |||
| @@ -462,7 +462,7 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 462 | } | 462 | } |
| 463 | 463 | ||
| 464 | default: | 464 | default: |
| 465 | LOG_ERROR(HW_GPU, "Unknown texture coordinate wrapping mode %x\n", (int)mode); | 465 | LOG_ERROR(HW_GPU, "Unknown texture coordinate wrapping mode %x", (int)mode); |
| 466 | UNIMPLEMENTED(); | 466 | UNIMPLEMENTED(); |
| 467 | return 0; | 467 | return 0; |
| 468 | } | 468 | } |
| @@ -498,7 +498,8 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 498 | // with some basic arithmetic. Alpha combiners can be configured separately but work | 498 | // with some basic arithmetic. Alpha combiners can be configured separately but work |
| 499 | // analogously. | 499 | // analogously. |
| 500 | Math::Vec4<u8> combiner_output; | 500 | Math::Vec4<u8> combiner_output; |
| 501 | Math::Vec4<u8> combiner_buffer = { | 501 | Math::Vec4<u8> combiner_buffer = {0, 0, 0, 0}; |
| 502 | Math::Vec4<u8> next_combiner_buffer = { | ||
| 502 | regs.tev_combiner_buffer_color.r, regs.tev_combiner_buffer_color.g, | 503 | regs.tev_combiner_buffer_color.r, regs.tev_combiner_buffer_color.g, |
| 503 | regs.tev_combiner_buffer_color.b, regs.tev_combiner_buffer_color.a | 504 | regs.tev_combiner_buffer_color.b, regs.tev_combiner_buffer_color.a |
| 504 | }; | 505 | }; |
| @@ -541,7 +542,7 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 541 | return combiner_output; | 542 | return combiner_output; |
| 542 | 543 | ||
| 543 | default: | 544 | default: |
| 544 | LOG_ERROR(HW_GPU, "Unknown color combiner source %d\n", (int)source); | 545 | LOG_ERROR(HW_GPU, "Unknown color combiner source %d", (int)source); |
| 545 | UNIMPLEMENTED(); | 546 | UNIMPLEMENTED(); |
| 546 | return {0, 0, 0, 0}; | 547 | return {0, 0, 0, 0}; |
| 547 | } | 548 | } |
| @@ -679,7 +680,7 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 679 | return { (u8)result, (u8)result, (u8)result }; | 680 | return { (u8)result, (u8)result, (u8)result }; |
| 680 | } | 681 | } |
| 681 | default: | 682 | default: |
| 682 | LOG_ERROR(HW_GPU, "Unknown color combiner operation %d\n", (int)op); | 683 | LOG_ERROR(HW_GPU, "Unknown color combiner operation %d", (int)op); |
| 683 | UNIMPLEMENTED(); | 684 | UNIMPLEMENTED(); |
| 684 | return {0, 0, 0}; | 685 | return {0, 0, 0}; |
| 685 | } | 686 | } |
| @@ -716,7 +717,7 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 716 | return (std::min(255, (input[0] + input[1])) * input[2]) / 255; | 717 | return (std::min(255, (input[0] + input[1])) * input[2]) / 255; |
| 717 | 718 | ||
| 718 | default: | 719 | default: |
| 719 | LOG_ERROR(HW_GPU, "Unknown alpha combiner operation %d\n", (int)op); | 720 | LOG_ERROR(HW_GPU, "Unknown alpha combiner operation %d", (int)op); |
| 720 | UNIMPLEMENTED(); | 721 | UNIMPLEMENTED(); |
| 721 | return 0; | 722 | return 0; |
| 722 | } | 723 | } |
| @@ -747,14 +748,16 @@ static void ProcessTriangleInternal(const Shader::OutputVertex& v0, | |||
| 747 | combiner_output[2] = std::min((unsigned)255, color_output.b() * tev_stage.GetColorMultiplier()); | 748 | combiner_output[2] = std::min((unsigned)255, color_output.b() * tev_stage.GetColorMultiplier()); |
| 748 | combiner_output[3] = std::min((unsigned)255, alpha_output * tev_stage.GetAlphaMultiplier()); | 749 | combiner_output[3] = std::min((unsigned)255, alpha_output * tev_stage.GetAlphaMultiplier()); |
| 749 | 750 | ||
| 751 | combiner_buffer = next_combiner_buffer; | ||
| 752 | |||
| 750 | if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_index)) { | 753 | if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_index)) { |
| 751 | combiner_buffer.r() = combiner_output.r(); | 754 | next_combiner_buffer.r() = combiner_output.r(); |
| 752 | combiner_buffer.g() = combiner_output.g(); | 755 | next_combiner_buffer.g() = combiner_output.g(); |
| 753 | combiner_buffer.b() = combiner_output.b(); | 756 | next_combiner_buffer.b() = combiner_output.b(); |
| 754 | } | 757 | } |
| 755 | 758 | ||
| 756 | if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_index)) { | 759 | if (regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_index)) { |
| 757 | combiner_buffer.a() = combiner_output.a(); | 760 | next_combiner_buffer.a() = combiner_output.a(); |
| 758 | } | 761 | } |
| 759 | } | 762 | } |
| 760 | 763 | ||
diff --git a/src/video_core/hwrasterizer_base.h b/src/video_core/rasterizer_interface.h index 54b8892fb..008c5827b 100644 --- a/src/video_core/hwrasterizer_base.h +++ b/src/video_core/rasterizer_interface.h | |||
| @@ -12,10 +12,11 @@ struct OutputVertex; | |||
| 12 | } | 12 | } |
| 13 | } | 13 | } |
| 14 | 14 | ||
| 15 | class HWRasterizer { | 15 | namespace VideoCore { |
| 16 | |||
| 17 | class RasterizerInterface { | ||
| 16 | public: | 18 | public: |
| 17 | virtual ~HWRasterizer() { | 19 | virtual ~RasterizerInterface() {} |
| 18 | } | ||
| 19 | 20 | ||
| 20 | /// Initialize API-specific GPU objects | 21 | /// Initialize API-specific GPU objects |
| 21 | virtual void InitObjects() = 0; | 22 | virtual void InitObjects() = 0; |
| @@ -32,14 +33,16 @@ public: | |||
| 32 | virtual void DrawTriangles() = 0; | 33 | virtual void DrawTriangles() = 0; |
| 33 | 34 | ||
| 34 | /// Commit the rasterizer's framebuffer contents immediately to the current 3DS memory framebuffer | 35 | /// Commit the rasterizer's framebuffer contents immediately to the current 3DS memory framebuffer |
| 35 | virtual void CommitFramebuffer() = 0; | 36 | virtual void FlushFramebuffer() = 0; |
| 36 | 37 | ||
| 37 | /// Notify rasterizer that the specified PICA register has been changed | 38 | /// Notify rasterizer that the specified PICA register has been changed |
| 38 | virtual void NotifyPicaRegisterChanged(u32 id) = 0; | 39 | virtual void NotifyPicaRegisterChanged(u32 id) = 0; |
| 39 | 40 | ||
| 40 | /// Notify rasterizer that the specified 3DS memory region will be read from after this notification | 41 | /// Notify rasterizer that any caches of the specified region should be flushed to 3DS memory. |
| 41 | virtual void NotifyPreRead(PAddr addr, u32 size) = 0; | 42 | virtual void FlushRegion(PAddr addr, u32 size) = 0; |
| 42 | 43 | ||
| 43 | /// Notify rasterizer that a 3DS memory region has been changed | 44 | /// Notify rasterizer that any caches of the specified region should be discraded and reloaded from 3DS memory. |
| 44 | virtual void NotifyFlush(PAddr addr, u32 size) = 0; | 45 | virtual void InvalidateRegion(PAddr addr, u32 size) = 0; |
| 45 | }; | 46 | }; |
| 47 | |||
| 48 | } | ||
diff --git a/src/video_core/renderer_base.cpp b/src/video_core/renderer_base.cpp new file mode 100644 index 000000000..6467ff723 --- /dev/null +++ b/src/video_core/renderer_base.cpp | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <memory> | ||
| 6 | |||
| 7 | #include "common/make_unique.h" | ||
| 8 | |||
| 9 | #include "core/settings.h" | ||
| 10 | |||
| 11 | #include "video_core/renderer_base.h" | ||
| 12 | #include "video_core/video_core.h" | ||
| 13 | #include "video_core/swrasterizer.h" | ||
| 14 | #include "video_core/renderer_opengl/gl_rasterizer.h" | ||
| 15 | |||
| 16 | void RendererBase::RefreshRasterizerSetting() { | ||
| 17 | bool hw_renderer_enabled = VideoCore::g_hw_renderer_enabled; | ||
| 18 | if (rasterizer == nullptr || opengl_rasterizer_active != hw_renderer_enabled) { | ||
| 19 | opengl_rasterizer_active = hw_renderer_enabled; | ||
| 20 | |||
| 21 | if (hw_renderer_enabled) { | ||
| 22 | rasterizer = Common::make_unique<RasterizerOpenGL>(); | ||
| 23 | } else { | ||
| 24 | rasterizer = Common::make_unique<VideoCore::SWRasterizer>(); | ||
| 25 | } | ||
| 26 | rasterizer->InitObjects(); | ||
| 27 | rasterizer->Reset(); | ||
| 28 | } | ||
| 29 | } | ||
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h index 6587bcf27..506bff815 100644 --- a/src/video_core/renderer_base.h +++ b/src/video_core/renderer_base.h | |||
| @@ -8,7 +8,7 @@ | |||
| 8 | 8 | ||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | 10 | ||
| 11 | #include "video_core/hwrasterizer_base.h" | 11 | #include "video_core/rasterizer_interface.h" |
| 12 | 12 | ||
| 13 | class EmuWindow; | 13 | class EmuWindow; |
| 14 | 14 | ||
| @@ -54,10 +54,14 @@ public: | |||
| 54 | return m_current_frame; | 54 | return m_current_frame; |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | std::unique_ptr<HWRasterizer> hw_rasterizer; | 57 | void RefreshRasterizerSetting(); |
| 58 | |||
| 59 | std::unique_ptr<VideoCore::RasterizerInterface> rasterizer; | ||
| 58 | 60 | ||
| 59 | protected: | 61 | protected: |
| 60 | f32 m_current_fps; ///< Current framerate, should be set by the renderer | 62 | f32 m_current_fps; ///< Current framerate, should be set by the renderer |
| 61 | int m_current_frame; ///< Current frame, should be set by the renderer | 63 | int m_current_frame; ///< Current frame, should be set by the renderer |
| 62 | 64 | ||
| 65 | private: | ||
| 66 | bool opengl_rasterizer_active = false; | ||
| 63 | }; | 67 | }; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index a613fe136..092351dce 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -8,6 +8,8 @@ | |||
| 8 | #include <glad/glad.h> | 8 | #include <glad/glad.h> |
| 9 | 9 | ||
| 10 | #include "common/color.h" | 10 | #include "common/color.h" |
| 11 | #include "common/file_util.h" | ||
| 12 | #include "common/make_unique.h" | ||
| 11 | #include "common/math_util.h" | 13 | #include "common/math_util.h" |
| 12 | #include "common/microprofile.h" | 14 | #include "common/microprofile.h" |
| 13 | #include "common/profiler.h" | 15 | #include "common/profiler.h" |
| @@ -19,7 +21,7 @@ | |||
| 19 | #include "video_core/pica.h" | 21 | #include "video_core/pica.h" |
| 20 | #include "video_core/utils.h" | 22 | #include "video_core/utils.h" |
| 21 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 23 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 22 | #include "video_core/renderer_opengl/gl_shaders.h" | 24 | #include "video_core/renderer_opengl/gl_shader_gen.h" |
| 23 | #include "video_core/renderer_opengl/gl_shader_util.h" | 25 | #include "video_core/renderer_opengl/gl_shader_util.h" |
| 24 | #include "video_core/renderer_opengl/pica_to_gl.h" | 26 | #include "video_core/renderer_opengl/pica_to_gl.h" |
| 25 | 27 | ||
| @@ -38,69 +40,42 @@ RasterizerOpenGL::RasterizerOpenGL() : last_fb_color_addr(0), last_fb_depth_addr | |||
| 38 | RasterizerOpenGL::~RasterizerOpenGL() { } | 40 | RasterizerOpenGL::~RasterizerOpenGL() { } |
| 39 | 41 | ||
| 40 | void RasterizerOpenGL::InitObjects() { | 42 | void RasterizerOpenGL::InitObjects() { |
| 41 | // Create the hardware shader program and get attrib/uniform locations | ||
| 42 | shader.Create(GLShaders::g_vertex_shader_hw, GLShaders::g_fragment_shader_hw); | ||
| 43 | attrib_position = glGetAttribLocation(shader.handle, "vert_position"); | ||
| 44 | attrib_color = glGetAttribLocation(shader.handle, "vert_color"); | ||
| 45 | attrib_texcoords = glGetAttribLocation(shader.handle, "vert_texcoords"); | ||
| 46 | |||
| 47 | uniform_alphatest_enabled = glGetUniformLocation(shader.handle, "alphatest_enabled"); | ||
| 48 | uniform_alphatest_func = glGetUniformLocation(shader.handle, "alphatest_func"); | ||
| 49 | uniform_alphatest_ref = glGetUniformLocation(shader.handle, "alphatest_ref"); | ||
| 50 | |||
| 51 | uniform_tex = glGetUniformLocation(shader.handle, "tex"); | ||
| 52 | |||
| 53 | uniform_tev_combiner_buffer_color = glGetUniformLocation(shader.handle, "tev_combiner_buffer_color"); | ||
| 54 | |||
| 55 | const auto tev_stages = Pica::g_state.regs.GetTevStages(); | ||
| 56 | for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { | ||
| 57 | auto& uniform_tev_cfg = uniform_tev_cfgs[tev_stage_index]; | ||
| 58 | |||
| 59 | std::string tev_ref_str = "tev_cfgs[" + std::to_string(tev_stage_index) + "]"; | ||
| 60 | uniform_tev_cfg.enabled = glGetUniformLocation(shader.handle, (tev_ref_str + ".enabled").c_str()); | ||
| 61 | uniform_tev_cfg.color_sources = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_sources").c_str()); | ||
| 62 | uniform_tev_cfg.alpha_sources = glGetUniformLocation(shader.handle, (tev_ref_str + ".alpha_sources").c_str()); | ||
| 63 | uniform_tev_cfg.color_modifiers = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_modifiers").c_str()); | ||
| 64 | uniform_tev_cfg.alpha_modifiers = glGetUniformLocation(shader.handle, (tev_ref_str + ".alpha_modifiers").c_str()); | ||
| 65 | uniform_tev_cfg.color_alpha_op = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_alpha_op").c_str()); | ||
| 66 | uniform_tev_cfg.color_alpha_multiplier = glGetUniformLocation(shader.handle, (tev_ref_str + ".color_alpha_multiplier").c_str()); | ||
| 67 | uniform_tev_cfg.const_color = glGetUniformLocation(shader.handle, (tev_ref_str + ".const_color").c_str()); | ||
| 68 | uniform_tev_cfg.updates_combiner_buffer_color_alpha = glGetUniformLocation(shader.handle, (tev_ref_str + ".updates_combiner_buffer_color_alpha").c_str()); | ||
| 69 | } | ||
| 70 | |||
| 71 | // Create sampler objects | 43 | // Create sampler objects |
| 72 | for (size_t i = 0; i < texture_samplers.size(); ++i) { | 44 | for (size_t i = 0; i < texture_samplers.size(); ++i) { |
| 73 | texture_samplers[i].Create(); | 45 | texture_samplers[i].Create(); |
| 74 | state.texture_units[i].sampler = texture_samplers[i].sampler.handle; | 46 | state.texture_units[i].sampler = texture_samplers[i].sampler.handle; |
| 75 | } | 47 | } |
| 76 | 48 | ||
| 77 | // Generate VBO and VAO | 49 | // Generate VBO, VAO and UBO |
| 78 | vertex_buffer.Create(); | 50 | vertex_buffer.Create(); |
| 79 | vertex_array.Create(); | 51 | vertex_array.Create(); |
| 52 | uniform_buffer.Create(); | ||
| 80 | 53 | ||
| 81 | // Update OpenGL state | ||
| 82 | state.draw.vertex_array = vertex_array.handle; | 54 | state.draw.vertex_array = vertex_array.handle; |
| 83 | state.draw.vertex_buffer = vertex_buffer.handle; | 55 | state.draw.vertex_buffer = vertex_buffer.handle; |
| 84 | state.draw.shader_program = shader.handle; | 56 | state.draw.uniform_buffer = uniform_buffer.handle; |
| 85 | |||
| 86 | state.Apply(); | 57 | state.Apply(); |
| 87 | 58 | ||
| 88 | // Set the texture samplers to correspond to different texture units | 59 | // Bind the UBO to binding point 0 |
| 89 | glUniform1i(uniform_tex, 0); | 60 | glBindBufferBase(GL_UNIFORM_BUFFER, 0, uniform_buffer.handle); |
| 90 | glUniform1i(uniform_tex + 1, 1); | 61 | |
| 91 | glUniform1i(uniform_tex + 2, 2); | 62 | uniform_block_data.dirty = true; |
| 92 | 63 | ||
| 93 | // Set vertex attributes | 64 | // Set vertex attributes |
| 94 | glVertexAttribPointer(attrib_position, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); | 65 | glVertexAttribPointer(GLShader::ATTRIBUTE_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, position)); |
| 95 | glVertexAttribPointer(attrib_color, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); | 66 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_POSITION); |
| 96 | glVertexAttribPointer(attrib_texcoords, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); | 67 | |
| 97 | glVertexAttribPointer(attrib_texcoords + 1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); | 68 | glVertexAttribPointer(GLShader::ATTRIBUTE_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, color)); |
| 98 | glVertexAttribPointer(attrib_texcoords + 2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); | 69 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_COLOR); |
| 99 | glEnableVertexAttribArray(attrib_position); | 70 | |
| 100 | glEnableVertexAttribArray(attrib_color); | 71 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD0, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord0)); |
| 101 | glEnableVertexAttribArray(attrib_texcoords); | 72 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD1, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord1)); |
| 102 | glEnableVertexAttribArray(attrib_texcoords + 1); | 73 | glVertexAttribPointer(GLShader::ATTRIBUTE_TEXCOORD2, 2, GL_FLOAT, GL_FALSE, sizeof(HardwareVertex), (GLvoid*)offsetof(HardwareVertex, tex_coord2)); |
| 103 | glEnableVertexAttribArray(attrib_texcoords + 2); | 74 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD0); |
| 75 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD1); | ||
| 76 | glEnableVertexAttribArray(GLShader::ATTRIBUTE_TEXCOORD2); | ||
| 77 | |||
| 78 | SetShader(); | ||
| 104 | 79 | ||
| 105 | // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation | 80 | // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation |
| 106 | fb_color_texture.texture.Create(); | 81 | fb_color_texture.texture.Create(); |
| @@ -150,63 +125,17 @@ void RasterizerOpenGL::InitObjects() { | |||
| 150 | } | 125 | } |
| 151 | 126 | ||
| 152 | void RasterizerOpenGL::Reset() { | 127 | void RasterizerOpenGL::Reset() { |
| 153 | const auto& regs = Pica::g_state.regs; | ||
| 154 | |||
| 155 | SyncCullMode(); | 128 | SyncCullMode(); |
| 156 | SyncBlendEnabled(); | 129 | SyncBlendEnabled(); |
| 157 | SyncBlendFuncs(); | 130 | SyncBlendFuncs(); |
| 158 | SyncBlendColor(); | 131 | SyncBlendColor(); |
| 159 | SyncAlphaTest(); | ||
| 160 | SyncLogicOp(); | 132 | SyncLogicOp(); |
| 161 | SyncStencilTest(); | 133 | SyncStencilTest(); |
| 162 | SyncDepthTest(); | 134 | SyncDepthTest(); |
| 163 | 135 | ||
| 164 | // TEV stage 0 | 136 | SetShader(); |
| 165 | SyncTevSources(0, regs.tev_stage0); | ||
| 166 | SyncTevModifiers(0, regs.tev_stage0); | ||
| 167 | SyncTevOps(0, regs.tev_stage0); | ||
| 168 | SyncTevColor(0, regs.tev_stage0); | ||
| 169 | SyncTevMultipliers(0, regs.tev_stage0); | ||
| 170 | |||
| 171 | // TEV stage 1 | ||
| 172 | SyncTevSources(1, regs.tev_stage1); | ||
| 173 | SyncTevModifiers(1, regs.tev_stage1); | ||
| 174 | SyncTevOps(1, regs.tev_stage1); | ||
| 175 | SyncTevColor(1, regs.tev_stage1); | ||
| 176 | SyncTevMultipliers(1, regs.tev_stage1); | ||
| 177 | |||
| 178 | // TEV stage 2 | ||
| 179 | SyncTevSources(2, regs.tev_stage2); | ||
| 180 | SyncTevModifiers(2, regs.tev_stage2); | ||
| 181 | SyncTevOps(2, regs.tev_stage2); | ||
| 182 | SyncTevColor(2, regs.tev_stage2); | ||
| 183 | SyncTevMultipliers(2, regs.tev_stage2); | ||
| 184 | |||
| 185 | // TEV stage 3 | ||
| 186 | SyncTevSources(3, regs.tev_stage3); | ||
| 187 | SyncTevModifiers(3, regs.tev_stage3); | ||
| 188 | SyncTevOps(3, regs.tev_stage3); | ||
| 189 | SyncTevColor(3, regs.tev_stage3); | ||
| 190 | SyncTevMultipliers(3, regs.tev_stage3); | ||
| 191 | |||
| 192 | // TEV stage 4 | ||
| 193 | SyncTevSources(4, regs.tev_stage4); | ||
| 194 | SyncTevModifiers(4, regs.tev_stage4); | ||
| 195 | SyncTevOps(4, regs.tev_stage4); | ||
| 196 | SyncTevColor(4, regs.tev_stage4); | ||
| 197 | SyncTevMultipliers(4, regs.tev_stage4); | ||
| 198 | |||
| 199 | // TEV stage 5 | ||
| 200 | SyncTevSources(5, regs.tev_stage5); | ||
| 201 | SyncTevModifiers(5, regs.tev_stage5); | ||
| 202 | SyncTevOps(5, regs.tev_stage5); | ||
| 203 | SyncTevColor(5, regs.tev_stage5); | ||
| 204 | SyncTevMultipliers(5, regs.tev_stage5); | ||
| 205 | 137 | ||
| 206 | SyncCombinerColor(); | 138 | res_cache.InvalidateAll(); |
| 207 | SyncCombinerWriteFlags(); | ||
| 208 | |||
| 209 | res_cache.FullFlush(); | ||
| 210 | } | 139 | } |
| 211 | 140 | ||
| 212 | void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0, | 141 | void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0, |
| @@ -221,6 +150,16 @@ void RasterizerOpenGL::DrawTriangles() { | |||
| 221 | SyncFramebuffer(); | 150 | SyncFramebuffer(); |
| 222 | SyncDrawState(); | 151 | SyncDrawState(); |
| 223 | 152 | ||
| 153 | if (state.draw.shader_dirty) { | ||
| 154 | SetShader(); | ||
| 155 | state.draw.shader_dirty = false; | ||
| 156 | } | ||
| 157 | |||
| 158 | if (uniform_block_data.dirty) { | ||
| 159 | glBufferData(GL_UNIFORM_BUFFER, sizeof(UniformData), &uniform_block_data.data, GL_STATIC_DRAW); | ||
| 160 | uniform_block_data.dirty = false; | ||
| 161 | } | ||
| 162 | |||
| 224 | glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW); | 163 | glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW); |
| 225 | glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size()); | 164 | glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size()); |
| 226 | 165 | ||
| @@ -237,11 +176,11 @@ void RasterizerOpenGL::DrawTriangles() { | |||
| 237 | u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(regs.framebuffer.depth_format) | 176 | u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(regs.framebuffer.depth_format) |
| 238 | * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight(); | 177 | * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight(); |
| 239 | 178 | ||
| 240 | res_cache.NotifyFlush(cur_fb_color_addr, cur_fb_color_size, true); | 179 | res_cache.InvalidateInRange(cur_fb_color_addr, cur_fb_color_size, true); |
| 241 | res_cache.NotifyFlush(cur_fb_depth_addr, cur_fb_depth_size, true); | 180 | res_cache.InvalidateInRange(cur_fb_depth_addr, cur_fb_depth_size, true); |
| 242 | } | 181 | } |
| 243 | 182 | ||
| 244 | void RasterizerOpenGL::CommitFramebuffer() { | 183 | void RasterizerOpenGL::FlushFramebuffer() { |
| 245 | CommitColorBuffer(); | 184 | CommitColorBuffer(); |
| 246 | CommitDepthBuffer(); | 185 | CommitDepthBuffer(); |
| 247 | } | 186 | } |
| @@ -249,9 +188,6 @@ void RasterizerOpenGL::CommitFramebuffer() { | |||
| 249 | void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | 188 | void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { |
| 250 | const auto& regs = Pica::g_state.regs; | 189 | const auto& regs = Pica::g_state.regs; |
| 251 | 190 | ||
| 252 | if (!Settings::values.use_hw_renderer) | ||
| 253 | return; | ||
| 254 | |||
| 255 | switch(id) { | 191 | switch(id) { |
| 256 | // Culling | 192 | // Culling |
| 257 | case PICA_REG_INDEX(cull_mode): | 193 | case PICA_REG_INDEX(cull_mode): |
| @@ -272,6 +208,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 272 | // Alpha test | 208 | // Alpha test |
| 273 | case PICA_REG_INDEX(output_merger.alpha_test): | 209 | case PICA_REG_INDEX(output_merger.alpha_test): |
| 274 | SyncAlphaTest(); | 210 | SyncAlphaTest(); |
| 211 | state.draw.shader_dirty = true; | ||
| 275 | break; | 212 | break; |
| 276 | 213 | ||
| 277 | // Stencil test | 214 | // Stencil test |
| @@ -290,126 +227,63 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { | |||
| 290 | SyncLogicOp(); | 227 | SyncLogicOp(); |
| 291 | break; | 228 | break; |
| 292 | 229 | ||
| 293 | // TEV stage 0 | 230 | // TEV stages |
| 294 | case PICA_REG_INDEX(tev_stage0.color_source1): | 231 | case PICA_REG_INDEX(tev_stage0.color_source1): |
| 295 | SyncTevSources(0, regs.tev_stage0); | ||
| 296 | break; | ||
| 297 | case PICA_REG_INDEX(tev_stage0.color_modifier1): | 232 | case PICA_REG_INDEX(tev_stage0.color_modifier1): |
| 298 | SyncTevModifiers(0, regs.tev_stage0); | ||
| 299 | break; | ||
| 300 | case PICA_REG_INDEX(tev_stage0.color_op): | 233 | case PICA_REG_INDEX(tev_stage0.color_op): |
| 301 | SyncTevOps(0, regs.tev_stage0); | ||
| 302 | break; | ||
| 303 | case PICA_REG_INDEX(tev_stage0.const_r): | ||
| 304 | SyncTevColor(0, regs.tev_stage0); | ||
| 305 | break; | ||
| 306 | case PICA_REG_INDEX(tev_stage0.color_scale): | 234 | case PICA_REG_INDEX(tev_stage0.color_scale): |
| 307 | SyncTevMultipliers(0, regs.tev_stage0); | ||
| 308 | break; | ||
| 309 | |||
| 310 | // TEV stage 1 | ||
| 311 | case PICA_REG_INDEX(tev_stage1.color_source1): | 235 | case PICA_REG_INDEX(tev_stage1.color_source1): |
| 312 | SyncTevSources(1, regs.tev_stage1); | ||
| 313 | break; | ||
| 314 | case PICA_REG_INDEX(tev_stage1.color_modifier1): | 236 | case PICA_REG_INDEX(tev_stage1.color_modifier1): |
| 315 | SyncTevModifiers(1, regs.tev_stage1); | ||
| 316 | break; | ||
| 317 | case PICA_REG_INDEX(tev_stage1.color_op): | 237 | case PICA_REG_INDEX(tev_stage1.color_op): |
| 318 | SyncTevOps(1, regs.tev_stage1); | ||
| 319 | break; | ||
| 320 | case PICA_REG_INDEX(tev_stage1.const_r): | ||
| 321 | SyncTevColor(1, regs.tev_stage1); | ||
| 322 | break; | ||
| 323 | case PICA_REG_INDEX(tev_stage1.color_scale): | 238 | case PICA_REG_INDEX(tev_stage1.color_scale): |
| 324 | SyncTevMultipliers(1, regs.tev_stage1); | ||
| 325 | break; | ||
| 326 | |||
| 327 | // TEV stage 2 | ||
| 328 | case PICA_REG_INDEX(tev_stage2.color_source1): | 239 | case PICA_REG_INDEX(tev_stage2.color_source1): |
| 329 | SyncTevSources(2, regs.tev_stage2); | ||
| 330 | break; | ||
| 331 | case PICA_REG_INDEX(tev_stage2.color_modifier1): | 240 | case PICA_REG_INDEX(tev_stage2.color_modifier1): |
| 332 | SyncTevModifiers(2, regs.tev_stage2); | ||
| 333 | break; | ||
| 334 | case PICA_REG_INDEX(tev_stage2.color_op): | 241 | case PICA_REG_INDEX(tev_stage2.color_op): |
| 335 | SyncTevOps(2, regs.tev_stage2); | ||
| 336 | break; | ||
| 337 | case PICA_REG_INDEX(tev_stage2.const_r): | ||
| 338 | SyncTevColor(2, regs.tev_stage2); | ||
| 339 | break; | ||
| 340 | case PICA_REG_INDEX(tev_stage2.color_scale): | 242 | case PICA_REG_INDEX(tev_stage2.color_scale): |
| 341 | SyncTevMultipliers(2, regs.tev_stage2); | ||
| 342 | break; | ||
| 343 | |||
| 344 | // TEV stage 3 | ||
| 345 | case PICA_REG_INDEX(tev_stage3.color_source1): | 243 | case PICA_REG_INDEX(tev_stage3.color_source1): |
| 346 | SyncTevSources(3, regs.tev_stage3); | ||
| 347 | break; | ||
| 348 | case PICA_REG_INDEX(tev_stage3.color_modifier1): | 244 | case PICA_REG_INDEX(tev_stage3.color_modifier1): |
| 349 | SyncTevModifiers(3, regs.tev_stage3); | ||
| 350 | break; | ||
| 351 | case PICA_REG_INDEX(tev_stage3.color_op): | 245 | case PICA_REG_INDEX(tev_stage3.color_op): |
| 352 | SyncTevOps(3, regs.tev_stage3); | ||
| 353 | break; | ||
| 354 | case PICA_REG_INDEX(tev_stage3.const_r): | ||
| 355 | SyncTevColor(3, regs.tev_stage3); | ||
| 356 | break; | ||
| 357 | case PICA_REG_INDEX(tev_stage3.color_scale): | 246 | case PICA_REG_INDEX(tev_stage3.color_scale): |
| 358 | SyncTevMultipliers(3, regs.tev_stage3); | ||
| 359 | break; | ||
| 360 | |||
| 361 | // TEV stage 4 | ||
| 362 | case PICA_REG_INDEX(tev_stage4.color_source1): | 247 | case PICA_REG_INDEX(tev_stage4.color_source1): |
| 363 | SyncTevSources(4, regs.tev_stage4); | ||
| 364 | break; | ||
| 365 | case PICA_REG_INDEX(tev_stage4.color_modifier1): | 248 | case PICA_REG_INDEX(tev_stage4.color_modifier1): |
| 366 | SyncTevModifiers(4, regs.tev_stage4); | ||
| 367 | break; | ||
| 368 | case PICA_REG_INDEX(tev_stage4.color_op): | 249 | case PICA_REG_INDEX(tev_stage4.color_op): |
| 369 | SyncTevOps(4, regs.tev_stage4); | 250 | case PICA_REG_INDEX(tev_stage4.color_scale): |
| 251 | case PICA_REG_INDEX(tev_stage5.color_source1): | ||
| 252 | case PICA_REG_INDEX(tev_stage5.color_modifier1): | ||
| 253 | case PICA_REG_INDEX(tev_stage5.color_op): | ||
| 254 | case PICA_REG_INDEX(tev_stage5.color_scale): | ||
| 255 | case PICA_REG_INDEX(tev_combiner_buffer_input): | ||
| 256 | state.draw.shader_dirty = true; | ||
| 370 | break; | 257 | break; |
| 371 | case PICA_REG_INDEX(tev_stage4.const_r): | 258 | case PICA_REG_INDEX(tev_stage0.const_r): |
| 372 | SyncTevColor(4, regs.tev_stage4); | 259 | SyncTevConstColor(0, regs.tev_stage0); |
| 373 | break; | 260 | break; |
| 374 | case PICA_REG_INDEX(tev_stage4.color_scale): | 261 | case PICA_REG_INDEX(tev_stage1.const_r): |
| 375 | SyncTevMultipliers(4, regs.tev_stage4); | 262 | SyncTevConstColor(1, regs.tev_stage1); |
| 376 | break; | 263 | break; |
| 377 | 264 | case PICA_REG_INDEX(tev_stage2.const_r): | |
| 378 | // TEV stage 5 | 265 | SyncTevConstColor(2, regs.tev_stage2); |
| 379 | case PICA_REG_INDEX(tev_stage5.color_source1): | ||
| 380 | SyncTevSources(5, regs.tev_stage5); | ||
| 381 | break; | 266 | break; |
| 382 | case PICA_REG_INDEX(tev_stage5.color_modifier1): | 267 | case PICA_REG_INDEX(tev_stage3.const_r): |
| 383 | SyncTevModifiers(5, regs.tev_stage5); | 268 | SyncTevConstColor(3, regs.tev_stage3); |
| 384 | break; | 269 | break; |
| 385 | case PICA_REG_INDEX(tev_stage5.color_op): | 270 | case PICA_REG_INDEX(tev_stage4.const_r): |
| 386 | SyncTevOps(5, regs.tev_stage5); | 271 | SyncTevConstColor(4, regs.tev_stage4); |
| 387 | break; | 272 | break; |
| 388 | case PICA_REG_INDEX(tev_stage5.const_r): | 273 | case PICA_REG_INDEX(tev_stage5.const_r): |
| 389 | SyncTevColor(5, regs.tev_stage5); | 274 | SyncTevConstColor(5, regs.tev_stage5); |
| 390 | break; | ||
| 391 | case PICA_REG_INDEX(tev_stage5.color_scale): | ||
| 392 | SyncTevMultipliers(5, regs.tev_stage5); | ||
| 393 | break; | 275 | break; |
| 394 | 276 | ||
| 395 | // TEV combiner buffer color | 277 | // TEV combiner buffer color |
| 396 | case PICA_REG_INDEX(tev_combiner_buffer_color): | 278 | case PICA_REG_INDEX(tev_combiner_buffer_color): |
| 397 | SyncCombinerColor(); | 279 | SyncCombinerColor(); |
| 398 | break; | 280 | break; |
| 399 | |||
| 400 | // TEV combiner buffer write flags | ||
| 401 | case PICA_REG_INDEX(tev_combiner_buffer_input): | ||
| 402 | SyncCombinerWriteFlags(); | ||
| 403 | break; | ||
| 404 | } | 281 | } |
| 405 | } | 282 | } |
| 406 | 283 | ||
| 407 | void RasterizerOpenGL::NotifyPreRead(PAddr addr, u32 size) { | 284 | void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) { |
| 408 | const auto& regs = Pica::g_state.regs; | 285 | const auto& regs = Pica::g_state.regs; |
| 409 | 286 | ||
| 410 | if (!Settings::values.use_hw_renderer) | ||
| 411 | return; | ||
| 412 | |||
| 413 | PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress(); | 287 | PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress(); |
| 414 | u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format) | 288 | u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format) |
| 415 | * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight(); | 289 | * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight(); |
| @@ -426,12 +300,9 @@ void RasterizerOpenGL::NotifyPreRead(PAddr addr, u32 size) { | |||
| 426 | CommitDepthBuffer(); | 300 | CommitDepthBuffer(); |
| 427 | } | 301 | } |
| 428 | 302 | ||
| 429 | void RasterizerOpenGL::NotifyFlush(PAddr addr, u32 size) { | 303 | void RasterizerOpenGL::InvalidateRegion(PAddr addr, u32 size) { |
| 430 | const auto& regs = Pica::g_state.regs; | 304 | const auto& regs = Pica::g_state.regs; |
| 431 | 305 | ||
| 432 | if (!Settings::values.use_hw_renderer) | ||
| 433 | return; | ||
| 434 | |||
| 435 | PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress(); | 306 | PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress(); |
| 436 | u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format) | 307 | u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format) |
| 437 | * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight(); | 308 | * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight(); |
| @@ -448,7 +319,7 @@ void RasterizerOpenGL::NotifyFlush(PAddr addr, u32 size) { | |||
| 448 | ReloadDepthBuffer(); | 319 | ReloadDepthBuffer(); |
| 449 | 320 | ||
| 450 | // Notify cache of flush in case the region touches a cached resource | 321 | // Notify cache of flush in case the region touches a cached resource |
| 451 | res_cache.NotifyFlush(addr, size); | 322 | res_cache.InvalidateInRange(addr, size); |
| 452 | } | 323 | } |
| 453 | 324 | ||
| 454 | void RasterizerOpenGL::SamplerInfo::Create() { | 325 | void RasterizerOpenGL::SamplerInfo::Create() { |
| @@ -592,6 +463,47 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica:: | |||
| 592 | state.Apply(); | 463 | state.Apply(); |
| 593 | } | 464 | } |
| 594 | 465 | ||
| 466 | void RasterizerOpenGL::SetShader() { | ||
| 467 | PicaShaderConfig config = PicaShaderConfig::CurrentConfig(); | ||
| 468 | std::unique_ptr<PicaShader> shader = Common::make_unique<PicaShader>(); | ||
| 469 | |||
| 470 | // Find (or generate) the GLSL shader for the current TEV state | ||
| 471 | auto cached_shader = shader_cache.find(config); | ||
| 472 | if (cached_shader != shader_cache.end()) { | ||
| 473 | current_shader = cached_shader->second.get(); | ||
| 474 | |||
| 475 | state.draw.shader_program = current_shader->shader.handle; | ||
| 476 | state.Apply(); | ||
| 477 | } else { | ||
| 478 | LOG_DEBUG(Render_OpenGL, "Creating new shader"); | ||
| 479 | |||
| 480 | shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str()); | ||
| 481 | |||
| 482 | state.draw.shader_program = shader->shader.handle; | ||
| 483 | state.Apply(); | ||
| 484 | |||
| 485 | // Set the texture samplers to correspond to different texture units | ||
| 486 | GLuint uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[0]"); | ||
| 487 | if (uniform_tex != -1) { glUniform1i(uniform_tex, 0); } | ||
| 488 | uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[1]"); | ||
| 489 | if (uniform_tex != -1) { glUniform1i(uniform_tex, 1); } | ||
| 490 | uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[2]"); | ||
| 491 | if (uniform_tex != -1) { glUniform1i(uniform_tex, 2); } | ||
| 492 | |||
| 493 | current_shader = shader_cache.emplace(config, std::move(shader)).first->second.get(); | ||
| 494 | |||
| 495 | unsigned int block_index = glGetUniformBlockIndex(current_shader->shader.handle, "shader_data"); | ||
| 496 | glUniformBlockBinding(current_shader->shader.handle, block_index, 0); | ||
| 497 | } | ||
| 498 | |||
| 499 | // Update uniforms | ||
| 500 | SyncAlphaTest(); | ||
| 501 | SyncCombinerColor(); | ||
| 502 | auto& tev_stages = Pica::g_state.regs.GetTevStages(); | ||
| 503 | for (int index = 0; index < tev_stages.size(); ++index) | ||
| 504 | SyncTevConstColor(index, tev_stages[index]); | ||
| 505 | } | ||
| 506 | |||
| 595 | void RasterizerOpenGL::SyncFramebuffer() { | 507 | void RasterizerOpenGL::SyncFramebuffer() { |
| 596 | const auto& regs = Pica::g_state.regs; | 508 | const auto& regs = Pica::g_state.regs; |
| 597 | 509 | ||
| @@ -675,12 +587,12 @@ void RasterizerOpenGL::SyncCullMode() { | |||
| 675 | 587 | ||
| 676 | case Pica::Regs::CullMode::KeepClockWise: | 588 | case Pica::Regs::CullMode::KeepClockWise: |
| 677 | state.cull.enabled = true; | 589 | state.cull.enabled = true; |
| 678 | state.cull.mode = GL_BACK; | 590 | state.cull.front_face = GL_CW; |
| 679 | break; | 591 | break; |
| 680 | 592 | ||
| 681 | case Pica::Regs::CullMode::KeepCounterClockWise: | 593 | case Pica::Regs::CullMode::KeepCounterClockWise: |
| 682 | state.cull.enabled = true; | 594 | state.cull.enabled = true; |
| 683 | state.cull.mode = GL_FRONT; | 595 | state.cull.front_face = GL_CCW; |
| 684 | break; | 596 | break; |
| 685 | 597 | ||
| 686 | default: | 598 | default: |
| @@ -712,9 +624,10 @@ void RasterizerOpenGL::SyncBlendColor() { | |||
| 712 | 624 | ||
| 713 | void RasterizerOpenGL::SyncAlphaTest() { | 625 | void RasterizerOpenGL::SyncAlphaTest() { |
| 714 | const auto& regs = Pica::g_state.regs; | 626 | const auto& regs = Pica::g_state.regs; |
| 715 | glUniform1i(uniform_alphatest_enabled, regs.output_merger.alpha_test.enable); | 627 | if (regs.output_merger.alpha_test.ref != uniform_block_data.data.alphatest_ref) { |
| 716 | glUniform1i(uniform_alphatest_func, (GLint)regs.output_merger.alpha_test.func.Value()); | 628 | uniform_block_data.data.alphatest_ref = regs.output_merger.alpha_test.ref; |
| 717 | glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f); | 629 | uniform_block_data.dirty = true; |
| 630 | } | ||
| 718 | } | 631 | } |
| 719 | 632 | ||
| 720 | void RasterizerOpenGL::SyncLogicOp() { | 633 | void RasterizerOpenGL::SyncLogicOp() { |
| @@ -744,55 +657,19 @@ void RasterizerOpenGL::SyncDepthTest() { | |||
| 744 | state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE; | 657 | state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE; |
| 745 | } | 658 | } |
| 746 | 659 | ||
| 747 | void RasterizerOpenGL::SyncTevSources(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { | ||
| 748 | GLint color_srcs[3] = { (GLint)config.color_source1.Value(), | ||
| 749 | (GLint)config.color_source2.Value(), | ||
| 750 | (GLint)config.color_source3.Value() }; | ||
| 751 | GLint alpha_srcs[3] = { (GLint)config.alpha_source1.Value(), | ||
| 752 | (GLint)config.alpha_source2.Value(), | ||
| 753 | (GLint)config.alpha_source3.Value() }; | ||
| 754 | |||
| 755 | glUniform3iv(uniform_tev_cfgs[stage_index].color_sources, 1, color_srcs); | ||
| 756 | glUniform3iv(uniform_tev_cfgs[stage_index].alpha_sources, 1, alpha_srcs); | ||
| 757 | } | ||
| 758 | |||
| 759 | void RasterizerOpenGL::SyncTevModifiers(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { | ||
| 760 | GLint color_mods[3] = { (GLint)config.color_modifier1.Value(), | ||
| 761 | (GLint)config.color_modifier2.Value(), | ||
| 762 | (GLint)config.color_modifier3.Value() }; | ||
| 763 | GLint alpha_mods[3] = { (GLint)config.alpha_modifier1.Value(), | ||
| 764 | (GLint)config.alpha_modifier2.Value(), | ||
| 765 | (GLint)config.alpha_modifier3.Value() }; | ||
| 766 | |||
| 767 | glUniform3iv(uniform_tev_cfgs[stage_index].color_modifiers, 1, color_mods); | ||
| 768 | glUniform3iv(uniform_tev_cfgs[stage_index].alpha_modifiers, 1, alpha_mods); | ||
| 769 | } | ||
| 770 | |||
| 771 | void RasterizerOpenGL::SyncTevOps(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { | ||
| 772 | glUniform2i(uniform_tev_cfgs[stage_index].color_alpha_op, (GLint)config.color_op.Value(), (GLint)config.alpha_op.Value()); | ||
| 773 | } | ||
| 774 | |||
| 775 | void RasterizerOpenGL::SyncTevColor(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { | ||
| 776 | auto const_color = PicaToGL::ColorRGBA8(config.const_color); | ||
| 777 | glUniform4fv(uniform_tev_cfgs[stage_index].const_color, 1, const_color.data()); | ||
| 778 | } | ||
| 779 | |||
| 780 | void RasterizerOpenGL::SyncTevMultipliers(unsigned stage_index, const Pica::Regs::TevStageConfig& config) { | ||
| 781 | glUniform2i(uniform_tev_cfgs[stage_index].color_alpha_multiplier, config.GetColorMultiplier(), config.GetAlphaMultiplier()); | ||
| 782 | } | ||
| 783 | |||
| 784 | void RasterizerOpenGL::SyncCombinerColor() { | 660 | void RasterizerOpenGL::SyncCombinerColor() { |
| 785 | auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); | 661 | auto combiner_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.tev_combiner_buffer_color.raw); |
| 786 | glUniform4fv(uniform_tev_combiner_buffer_color, 1, combiner_color.data()); | 662 | if (combiner_color != uniform_block_data.data.tev_combiner_buffer_color) { |
| 663 | uniform_block_data.data.tev_combiner_buffer_color = combiner_color; | ||
| 664 | uniform_block_data.dirty = true; | ||
| 665 | } | ||
| 787 | } | 666 | } |
| 788 | 667 | ||
| 789 | void RasterizerOpenGL::SyncCombinerWriteFlags() { | 668 | void RasterizerOpenGL::SyncTevConstColor(int stage_index, const Pica::Regs::TevStageConfig& tev_stage) { |
| 790 | const auto& regs = Pica::g_state.regs; | 669 | auto const_color = PicaToGL::ColorRGBA8(tev_stage.const_color); |
| 791 | const auto tev_stages = regs.GetTevStages(); | 670 | if (const_color != uniform_block_data.data.const_color[stage_index]) { |
| 792 | for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { | 671 | uniform_block_data.data.const_color[stage_index] = const_color; |
| 793 | glUniform2i(uniform_tev_cfgs[tev_stage_index].updates_combiner_buffer_color_alpha, | 672 | uniform_block_data.dirty = true; |
| 794 | regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_index), | ||
| 795 | regs.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_index)); | ||
| 796 | } | 673 | } |
| 797 | } | 674 | } |
| 798 | 675 | ||
| @@ -806,9 +683,8 @@ void RasterizerOpenGL::SyncDrawState() { | |||
| 806 | // OpenGL uses different y coordinates, so negate corner offset and flip origin | 683 | // OpenGL uses different y coordinates, so negate corner offset and flip origin |
| 807 | // TODO: Ensure viewport_corner.x should not be negated or origin flipped | 684 | // TODO: Ensure viewport_corner.x should not be negated or origin flipped |
| 808 | // TODO: Use floating-point viewports for accuracy if supported | 685 | // TODO: Use floating-point viewports for accuracy if supported |
| 809 | glViewport((GLsizei)static_cast<float>(regs.viewport_corner.x), | 686 | glViewport((GLsizei)regs.viewport_corner.x, |
| 810 | -(GLsizei)static_cast<float>(regs.viewport_corner.y) | 687 | (GLsizei)regs.viewport_corner.y, |
| 811 | + regs.framebuffer.GetHeight() - viewport_height, | ||
| 812 | viewport_width, viewport_height); | 688 | viewport_width, viewport_height); |
| 813 | 689 | ||
| 814 | // Sync bound texture(s), upload if not cached | 690 | // Sync bound texture(s), upload if not cached |
| @@ -824,12 +700,7 @@ void RasterizerOpenGL::SyncDrawState() { | |||
| 824 | } | 700 | } |
| 825 | } | 701 | } |
| 826 | 702 | ||
| 827 | // Skip processing TEV stages that simply pass the previous stage results through | 703 | state.draw.uniform_buffer = uniform_buffer.handle; |
| 828 | const auto tev_stages = regs.GetTevStages(); | ||
| 829 | for (unsigned tev_stage_index = 0; tev_stage_index < tev_stages.size(); ++tev_stage_index) { | ||
| 830 | glUniform1i(uniform_tev_cfgs[tev_stage_index].enabled, !IsPassThroughTevStage(tev_stages[tev_stage_index])); | ||
| 831 | } | ||
| 832 | |||
| 833 | state.Apply(); | 704 | state.Apply(); |
| 834 | } | 705 | } |
| 835 | 706 | ||
| @@ -852,7 +723,7 @@ void RasterizerOpenGL::ReloadColorBuffer() { | |||
| 852 | for (int x = 0; x < fb_color_texture.width; ++x) { | 723 | for (int x = 0; x < fb_color_texture.width; ++x) { |
| 853 | const u32 coarse_y = y & ~7; | 724 | const u32 coarse_y = y & ~7; |
| 854 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel; | 725 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel; |
| 855 | u32 gl_pixel_index = (x + y * fb_color_texture.width) * bytes_per_pixel; | 726 | u32 gl_pixel_index = (x + (fb_color_texture.height - 1 - y) * fb_color_texture.width) * bytes_per_pixel; |
| 856 | 727 | ||
| 857 | u8* pixel = color_buffer + dst_offset; | 728 | u8* pixel = color_buffer + dst_offset; |
| 858 | memcpy(&temp_fb_color_buffer[gl_pixel_index], pixel, bytes_per_pixel); | 729 | memcpy(&temp_fb_color_buffer[gl_pixel_index], pixel, bytes_per_pixel); |
| @@ -898,7 +769,7 @@ void RasterizerOpenGL::ReloadDepthBuffer() { | |||
| 898 | for (int x = 0; x < fb_depth_texture.width; ++x) { | 769 | for (int x = 0; x < fb_depth_texture.width; ++x) { |
| 899 | const u32 coarse_y = y & ~7; | 770 | const u32 coarse_y = y & ~7; |
| 900 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; | 771 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; |
| 901 | u32 gl_pixel_index = (x + y * fb_depth_texture.width); | 772 | u32 gl_pixel_index = (x + (fb_depth_texture.height - 1 - y) * fb_depth_texture.width); |
| 902 | 773 | ||
| 903 | u8* pixel = depth_buffer + dst_offset; | 774 | u8* pixel = depth_buffer + dst_offset; |
| 904 | u32 depth_stencil = *(u32*)pixel; | 775 | u32 depth_stencil = *(u32*)pixel; |
| @@ -910,7 +781,7 @@ void RasterizerOpenGL::ReloadDepthBuffer() { | |||
| 910 | for (int x = 0; x < fb_depth_texture.width; ++x) { | 781 | for (int x = 0; x < fb_depth_texture.width; ++x) { |
| 911 | const u32 coarse_y = y & ~7; | 782 | const u32 coarse_y = y & ~7; |
| 912 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; | 783 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; |
| 913 | u32 gl_pixel_index = (x + y * fb_depth_texture.width) * gl_bpp; | 784 | u32 gl_pixel_index = (x + (fb_depth_texture.height - 1 - y) * fb_depth_texture.width) * gl_bpp; |
| 914 | 785 | ||
| 915 | u8* pixel = depth_buffer + dst_offset; | 786 | u8* pixel = depth_buffer + dst_offset; |
| 916 | memcpy(&temp_fb_depth_data[gl_pixel_index], pixel, bytes_per_pixel); | 787 | memcpy(&temp_fb_depth_data[gl_pixel_index], pixel, bytes_per_pixel); |
| @@ -965,7 +836,7 @@ void RasterizerOpenGL::CommitColorBuffer() { | |||
| 965 | for (int x = 0; x < fb_color_texture.width; ++x) { | 836 | for (int x = 0; x < fb_color_texture.width; ++x) { |
| 966 | const u32 coarse_y = y & ~7; | 837 | const u32 coarse_y = y & ~7; |
| 967 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel; | 838 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel; |
| 968 | u32 gl_pixel_index = x * bytes_per_pixel + y * fb_color_texture.width * bytes_per_pixel; | 839 | u32 gl_pixel_index = x * bytes_per_pixel + (fb_color_texture.height - 1 - y) * fb_color_texture.width * bytes_per_pixel; |
| 969 | 840 | ||
| 970 | u8* pixel = color_buffer + dst_offset; | 841 | u8* pixel = color_buffer + dst_offset; |
| 971 | memcpy(pixel, &temp_gl_color_buffer[gl_pixel_index], bytes_per_pixel); | 842 | memcpy(pixel, &temp_gl_color_buffer[gl_pixel_index], bytes_per_pixel); |
| @@ -1007,7 +878,7 @@ void RasterizerOpenGL::CommitDepthBuffer() { | |||
| 1007 | for (int x = 0; x < fb_depth_texture.width; ++x) { | 878 | for (int x = 0; x < fb_depth_texture.width; ++x) { |
| 1008 | const u32 coarse_y = y & ~7; | 879 | const u32 coarse_y = y & ~7; |
| 1009 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; | 880 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; |
| 1010 | u32 gl_pixel_index = (x + y * fb_depth_texture.width); | 881 | u32 gl_pixel_index = (x + (fb_depth_texture.height - 1 - y) * fb_depth_texture.width); |
| 1011 | 882 | ||
| 1012 | u8* pixel = depth_buffer + dst_offset; | 883 | u8* pixel = depth_buffer + dst_offset; |
| 1013 | u32 depth_stencil = ((u32*)temp_gl_depth_data)[gl_pixel_index]; | 884 | u32 depth_stencil = ((u32*)temp_gl_depth_data)[gl_pixel_index]; |
| @@ -1019,7 +890,7 @@ void RasterizerOpenGL::CommitDepthBuffer() { | |||
| 1019 | for (int x = 0; x < fb_depth_texture.width; ++x) { | 890 | for (int x = 0; x < fb_depth_texture.width; ++x) { |
| 1020 | const u32 coarse_y = y & ~7; | 891 | const u32 coarse_y = y & ~7; |
| 1021 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; | 892 | u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; |
| 1022 | u32 gl_pixel_index = (x + y * fb_depth_texture.width) * gl_bpp; | 893 | u32 gl_pixel_index = (x + (fb_depth_texture.height - 1 - y) * fb_depth_texture.width) * gl_bpp; |
| 1023 | 894 | ||
| 1024 | u8* pixel = depth_buffer + dst_offset; | 895 | u8* pixel = depth_buffer + dst_offset; |
| 1025 | memcpy(pixel, &temp_gl_depth_data[gl_pixel_index], bytes_per_pixel); | 896 | memcpy(pixel, &temp_gl_depth_data[gl_pixel_index], bytes_per_pixel); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 1fe307846..92b1f812e 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -4,60 +4,128 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstddef> | ||
| 8 | #include <cstring> | ||
| 9 | #include <memory> | ||
| 7 | #include <vector> | 10 | #include <vector> |
| 11 | #include <unordered_map> | ||
| 8 | 12 | ||
| 9 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "common/hash.h" | ||
| 10 | 15 | ||
| 11 | #include "video_core/hwrasterizer_base.h" | 16 | #include "video_core/pica.h" |
| 17 | #include "video_core/rasterizer_interface.h" | ||
| 12 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | 18 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" |
| 13 | #include "video_core/renderer_opengl/gl_state.h" | 19 | #include "video_core/renderer_opengl/gl_state.h" |
| 14 | #include "video_core/shader/shader_interpreter.h" | 20 | #include "video_core/shader/shader_interpreter.h" |
| 15 | 21 | ||
| 16 | class RasterizerOpenGL : public HWRasterizer { | 22 | /** |
| 23 | * This struct contains all state used to generate the GLSL shader program that emulates the current | ||
| 24 | * Pica register configuration. This struct is used as a cache key for generated GLSL shader | ||
| 25 | * programs. The functions in gl_shader_gen.cpp should retrieve state from this struct only, not by | ||
| 26 | * directly accessing Pica registers. This should reduce the risk of bugs in shader generation where | ||
| 27 | * Pica state is not being captured in the shader cache key, thereby resulting in (what should be) | ||
| 28 | * two separate shaders sharing the same key. | ||
| 29 | */ | ||
| 30 | struct PicaShaderConfig { | ||
| 31 | /// Construct a PicaShaderConfig with the current Pica register configuration. | ||
| 32 | static PicaShaderConfig CurrentConfig() { | ||
| 33 | PicaShaderConfig res; | ||
| 34 | const auto& regs = Pica::g_state.regs; | ||
| 35 | |||
| 36 | res.alpha_test_func = regs.output_merger.alpha_test.enable ? | ||
| 37 | regs.output_merger.alpha_test.func.Value() : Pica::Regs::CompareFunc::Always; | ||
| 38 | |||
| 39 | // Copy relevant TevStageConfig fields only. We're doing this manually (instead of calling | ||
| 40 | // the GetTevStages() function) because BitField explicitly disables copies. | ||
| 41 | |||
| 42 | res.tev_stages[0].sources_raw = regs.tev_stage0.sources_raw; | ||
| 43 | res.tev_stages[1].sources_raw = regs.tev_stage1.sources_raw; | ||
| 44 | res.tev_stages[2].sources_raw = regs.tev_stage2.sources_raw; | ||
| 45 | res.tev_stages[3].sources_raw = regs.tev_stage3.sources_raw; | ||
| 46 | res.tev_stages[4].sources_raw = regs.tev_stage4.sources_raw; | ||
| 47 | res.tev_stages[5].sources_raw = regs.tev_stage5.sources_raw; | ||
| 48 | |||
| 49 | res.tev_stages[0].modifiers_raw = regs.tev_stage0.modifiers_raw; | ||
| 50 | res.tev_stages[1].modifiers_raw = regs.tev_stage1.modifiers_raw; | ||
| 51 | res.tev_stages[2].modifiers_raw = regs.tev_stage2.modifiers_raw; | ||
| 52 | res.tev_stages[3].modifiers_raw = regs.tev_stage3.modifiers_raw; | ||
| 53 | res.tev_stages[4].modifiers_raw = regs.tev_stage4.modifiers_raw; | ||
| 54 | res.tev_stages[5].modifiers_raw = regs.tev_stage5.modifiers_raw; | ||
| 55 | |||
| 56 | res.tev_stages[0].ops_raw = regs.tev_stage0.ops_raw; | ||
| 57 | res.tev_stages[1].ops_raw = regs.tev_stage1.ops_raw; | ||
| 58 | res.tev_stages[2].ops_raw = regs.tev_stage2.ops_raw; | ||
| 59 | res.tev_stages[3].ops_raw = regs.tev_stage3.ops_raw; | ||
| 60 | res.tev_stages[4].ops_raw = regs.tev_stage4.ops_raw; | ||
| 61 | res.tev_stages[5].ops_raw = regs.tev_stage5.ops_raw; | ||
| 62 | |||
| 63 | res.tev_stages[0].scales_raw = regs.tev_stage0.scales_raw; | ||
| 64 | res.tev_stages[1].scales_raw = regs.tev_stage1.scales_raw; | ||
| 65 | res.tev_stages[2].scales_raw = regs.tev_stage2.scales_raw; | ||
| 66 | res.tev_stages[3].scales_raw = regs.tev_stage3.scales_raw; | ||
| 67 | res.tev_stages[4].scales_raw = regs.tev_stage4.scales_raw; | ||
| 68 | res.tev_stages[5].scales_raw = regs.tev_stage5.scales_raw; | ||
| 69 | |||
| 70 | res.combiner_buffer_input = | ||
| 71 | regs.tev_combiner_buffer_input.update_mask_rgb.Value() | | ||
| 72 | regs.tev_combiner_buffer_input.update_mask_a.Value() << 4; | ||
| 73 | |||
| 74 | return res; | ||
| 75 | } | ||
| 76 | |||
| 77 | bool TevStageUpdatesCombinerBufferColor(unsigned stage_index) const { | ||
| 78 | return (stage_index < 4) && (combiner_buffer_input & (1 << stage_index)); | ||
| 79 | } | ||
| 80 | |||
| 81 | bool TevStageUpdatesCombinerBufferAlpha(unsigned stage_index) const { | ||
| 82 | return (stage_index < 4) && ((combiner_buffer_input >> 4) & (1 << stage_index)); | ||
| 83 | } | ||
| 84 | |||
| 85 | bool operator ==(const PicaShaderConfig& o) const { | ||
| 86 | return std::memcmp(this, &o, sizeof(PicaShaderConfig)) == 0; | ||
| 87 | }; | ||
| 88 | |||
| 89 | Pica::Regs::CompareFunc alpha_test_func; | ||
| 90 | std::array<Pica::Regs::TevStageConfig, 6> tev_stages = {}; | ||
| 91 | u8 combiner_buffer_input; | ||
| 92 | }; | ||
| 93 | |||
| 94 | namespace std { | ||
| 95 | |||
| 96 | template <> | ||
| 97 | struct hash<PicaShaderConfig> { | ||
| 98 | size_t operator()(const PicaShaderConfig& k) const { | ||
| 99 | return Common::ComputeHash64(&k, sizeof(PicaShaderConfig)); | ||
| 100 | } | ||
| 101 | }; | ||
| 102 | |||
| 103 | } // namespace std | ||
| 104 | |||
| 105 | class RasterizerOpenGL : public VideoCore::RasterizerInterface { | ||
| 17 | public: | 106 | public: |
| 18 | 107 | ||
| 19 | RasterizerOpenGL(); | 108 | RasterizerOpenGL(); |
| 20 | ~RasterizerOpenGL() override; | 109 | ~RasterizerOpenGL() override; |
| 21 | 110 | ||
| 22 | /// Initialize API-specific GPU objects | ||
| 23 | void InitObjects() override; | 111 | void InitObjects() override; |
| 24 | |||
| 25 | /// Reset the rasterizer, such as flushing all caches and updating all state | ||
| 26 | void Reset() override; | 112 | void Reset() override; |
| 27 | |||
| 28 | /// Queues the primitive formed by the given vertices for rendering | ||
| 29 | void AddTriangle(const Pica::Shader::OutputVertex& v0, | 113 | void AddTriangle(const Pica::Shader::OutputVertex& v0, |
| 30 | const Pica::Shader::OutputVertex& v1, | 114 | const Pica::Shader::OutputVertex& v1, |
| 31 | const Pica::Shader::OutputVertex& v2) override; | 115 | const Pica::Shader::OutputVertex& v2) override; |
| 32 | |||
| 33 | /// Draw the current batch of triangles | ||
| 34 | void DrawTriangles() override; | 116 | void DrawTriangles() override; |
| 35 | 117 | void FlushFramebuffer() override; | |
| 36 | /// Commit the rasterizer's framebuffer contents immediately to the current 3DS memory framebuffer | ||
| 37 | void CommitFramebuffer() override; | ||
| 38 | |||
| 39 | /// Notify rasterizer that the specified PICA register has been changed | ||
| 40 | void NotifyPicaRegisterChanged(u32 id) override; | 118 | void NotifyPicaRegisterChanged(u32 id) override; |
| 119 | void FlushRegion(PAddr addr, u32 size) override; | ||
| 120 | void InvalidateRegion(PAddr addr, u32 size) override; | ||
| 41 | 121 | ||
| 42 | /// Notify rasterizer that the specified 3DS memory region will be read from after this notification | 122 | /// OpenGL shader generated for a given Pica register state |
| 43 | void NotifyPreRead(PAddr addr, u32 size) override; | 123 | struct PicaShader { |
| 44 | 124 | /// OpenGL shader resource | |
| 45 | /// Notify rasterizer that a 3DS memory region has been changed | 125 | OGLShader shader; |
| 46 | void NotifyFlush(PAddr addr, u32 size) override; | 126 | }; |
| 47 | 127 | ||
| 48 | private: | 128 | private: |
| 49 | /// Structure used for managing texture environment states | ||
| 50 | struct TEVConfigUniforms { | ||
| 51 | GLuint enabled; | ||
| 52 | GLuint color_sources; | ||
| 53 | GLuint alpha_sources; | ||
| 54 | GLuint color_modifiers; | ||
| 55 | GLuint alpha_modifiers; | ||
| 56 | GLuint color_alpha_op; | ||
| 57 | GLuint color_alpha_multiplier; | ||
| 58 | GLuint const_color; | ||
| 59 | GLuint updates_combiner_buffer_color_alpha; | ||
| 60 | }; | ||
| 61 | 129 | ||
| 62 | /// Structure used for storing information about color textures | 130 | /// Structure used for storing information about color textures |
| 63 | struct TextureInfo { | 131 | struct TextureInfo { |
| @@ -123,12 +191,27 @@ private: | |||
| 123 | GLfloat tex_coord2[2]; | 191 | GLfloat tex_coord2[2]; |
| 124 | }; | 192 | }; |
| 125 | 193 | ||
| 194 | /// Uniform structure for the Uniform Buffer Object, all members must be 16-byte aligned | ||
| 195 | struct UniformData { | ||
| 196 | // A vec4 color for each of the six tev stages | ||
| 197 | std::array<GLfloat, 4> const_color[6]; | ||
| 198 | std::array<GLfloat, 4> tev_combiner_buffer_color; | ||
| 199 | GLint alphatest_ref; | ||
| 200 | INSERT_PADDING_BYTES(12); | ||
| 201 | }; | ||
| 202 | |||
| 203 | static_assert(sizeof(UniformData) == 0x80, "The size of the UniformData structure has changed, update the structure in the shader"); | ||
| 204 | static_assert(sizeof(UniformData) < 16000, "UniformData structure must be less than 16kb as per the OpenGL spec"); | ||
| 205 | |||
| 126 | /// Reconfigure the OpenGL color texture to use the given format and dimensions | 206 | /// Reconfigure the OpenGL color texture to use the given format and dimensions |
| 127 | void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height); | 207 | void ReconfigureColorTexture(TextureInfo& texture, Pica::Regs::ColorFormat format, u32 width, u32 height); |
| 128 | 208 | ||
| 129 | /// Reconfigure the OpenGL depth texture to use the given format and dimensions | 209 | /// Reconfigure the OpenGL depth texture to use the given format and dimensions |
| 130 | void ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height); | 210 | void ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height); |
| 131 | 211 | ||
| 212 | /// Sets the OpenGL shader in accordance with the current PICA register state | ||
| 213 | void SetShader(); | ||
| 214 | |||
| 132 | /// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer | 215 | /// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer |
| 133 | void SyncFramebuffer(); | 216 | void SyncFramebuffer(); |
| 134 | 217 | ||
| @@ -156,27 +239,12 @@ private: | |||
| 156 | /// Syncs the depth test states to match the PICA register | 239 | /// Syncs the depth test states to match the PICA register |
| 157 | void SyncDepthTest(); | 240 | void SyncDepthTest(); |
| 158 | 241 | ||
| 159 | /// Syncs the specified TEV stage's color and alpha sources to match the PICA register | 242 | /// Syncs the TEV constant color to match the PICA register |
| 160 | void SyncTevSources(unsigned stage_index, const Pica::Regs::TevStageConfig& config); | 243 | void SyncTevConstColor(int tev_index, const Pica::Regs::TevStageConfig& tev_stage); |
| 161 | |||
| 162 | /// Syncs the specified TEV stage's color and alpha modifiers to match the PICA register | ||
| 163 | void SyncTevModifiers(unsigned stage_index, const Pica::Regs::TevStageConfig& config); | ||
| 164 | |||
| 165 | /// Syncs the specified TEV stage's color and alpha combiner operations to match the PICA register | ||
| 166 | void SyncTevOps(unsigned stage_index, const Pica::Regs::TevStageConfig& config); | ||
| 167 | |||
| 168 | /// Syncs the specified TEV stage's constant color to match the PICA register | ||
| 169 | void SyncTevColor(unsigned stage_index, const Pica::Regs::TevStageConfig& config); | ||
| 170 | |||
| 171 | /// Syncs the specified TEV stage's color and alpha multipliers to match the PICA register | ||
| 172 | void SyncTevMultipliers(unsigned stage_index, const Pica::Regs::TevStageConfig& config); | ||
| 173 | 244 | ||
| 174 | /// Syncs the TEV combiner color buffer to match the PICA register | 245 | /// Syncs the TEV combiner color buffer to match the PICA register |
| 175 | void SyncCombinerColor(); | 246 | void SyncCombinerColor(); |
| 176 | 247 | ||
| 177 | /// Syncs the TEV combiner write flags to match the PICA register | ||
| 178 | void SyncCombinerWriteFlags(); | ||
| 179 | |||
| 180 | /// Syncs the remaining OpenGL drawing state to match the current PICA state | 248 | /// Syncs the remaining OpenGL drawing state to match the current PICA state |
| 181 | void SyncDrawState(); | 249 | void SyncDrawState(); |
| 182 | 250 | ||
| @@ -213,21 +281,17 @@ private: | |||
| 213 | std::array<SamplerInfo, 3> texture_samplers; | 281 | std::array<SamplerInfo, 3> texture_samplers; |
| 214 | TextureInfo fb_color_texture; | 282 | TextureInfo fb_color_texture; |
| 215 | DepthTextureInfo fb_depth_texture; | 283 | DepthTextureInfo fb_depth_texture; |
| 216 | OGLShader shader; | 284 | |
| 285 | std::unordered_map<PicaShaderConfig, std::unique_ptr<PicaShader>> shader_cache; | ||
| 286 | const PicaShader* current_shader = nullptr; | ||
| 287 | |||
| 288 | struct { | ||
| 289 | UniformData data; | ||
| 290 | bool dirty; | ||
| 291 | } uniform_block_data; | ||
| 292 | |||
| 217 | OGLVertexArray vertex_array; | 293 | OGLVertexArray vertex_array; |
| 218 | OGLBuffer vertex_buffer; | 294 | OGLBuffer vertex_buffer; |
| 295 | OGLBuffer uniform_buffer; | ||
| 219 | OGLFramebuffer framebuffer; | 296 | OGLFramebuffer framebuffer; |
| 220 | |||
| 221 | // Hardware vertex shader | ||
| 222 | GLuint attrib_position; | ||
| 223 | GLuint attrib_color; | ||
| 224 | GLuint attrib_texcoords; | ||
| 225 | |||
| 226 | // Hardware fragment shader | ||
| 227 | GLuint uniform_alphatest_enabled; | ||
| 228 | GLuint uniform_alphatest_func; | ||
| 229 | GLuint uniform_alphatest_ref; | ||
| 230 | GLuint uniform_tex; | ||
| 231 | GLuint uniform_tev_combiner_buffer_color; | ||
| 232 | TEVConfigUniforms uniform_tev_cfgs[6]; | ||
| 233 | }; | 297 | }; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 10d4ab0b6..a9ad46fe0 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | #include "video_core/renderer_opengl/pica_to_gl.h" | 15 | #include "video_core/renderer_opengl/pica_to_gl.h" |
| 16 | 16 | ||
| 17 | RasterizerCacheOpenGL::~RasterizerCacheOpenGL() { | 17 | RasterizerCacheOpenGL::~RasterizerCacheOpenGL() { |
| 18 | FullFlush(); | 18 | InvalidateAll(); |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | MICROPROFILE_DEFINE(OpenGL_TextureUpload, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); | 21 | MICROPROFILE_DEFINE(OpenGL_TextureUpload, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); |
| @@ -58,8 +58,7 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, unsigned text | |||
| 58 | } | 58 | } |
| 59 | } | 59 | } |
| 60 | 60 | ||
| 61 | void RasterizerCacheOpenGL::NotifyFlush(PAddr addr, u32 size, bool ignore_hash) { | 61 | void RasterizerCacheOpenGL::InvalidateInRange(PAddr addr, u32 size, bool ignore_hash) { |
| 62 | // Flush any texture that falls in the flushed region | ||
| 63 | // TODO: Optimize by also inserting upper bound (addr + size) of each texture into the same map and also narrow using lower_bound | 62 | // TODO: Optimize by also inserting upper bound (addr + size) of each texture into the same map and also narrow using lower_bound |
| 64 | auto cache_upper_bound = texture_cache.upper_bound(addr + size); | 63 | auto cache_upper_bound = texture_cache.upper_bound(addr + size); |
| 65 | 64 | ||
| @@ -77,6 +76,6 @@ void RasterizerCacheOpenGL::NotifyFlush(PAddr addr, u32 size, bool ignore_hash) | |||
| 77 | } | 76 | } |
| 78 | } | 77 | } |
| 79 | 78 | ||
| 80 | void RasterizerCacheOpenGL::FullFlush() { | 79 | void RasterizerCacheOpenGL::InvalidateAll() { |
| 81 | texture_cache.clear(); | 80 | texture_cache.clear(); |
| 82 | } | 81 | } |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 98a48ffbe..b69651427 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h | |||
| @@ -23,11 +23,11 @@ public: | |||
| 23 | LoadAndBindTexture(state, texture_unit, Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format)); | 23 | LoadAndBindTexture(state, texture_unit, Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format)); |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | /// Flush any cached resource that touches the flushed region | 26 | /// Invalidate any cached resource intersecting the specified region. |
| 27 | void NotifyFlush(PAddr addr, u32 size, bool ignore_hash = false); | 27 | void InvalidateInRange(PAddr addr, u32 size, bool ignore_hash = false); |
| 28 | 28 | ||
| 29 | /// Flush all cached OpenGL resources tracked by this cache manager | 29 | /// Invalidate all cached OpenGL resources tracked by this cache manager |
| 30 | void FullFlush(); | 30 | void InvalidateAll(); |
| 31 | 31 | ||
| 32 | private: | 32 | private: |
| 33 | struct CachedTexture { | 33 | struct CachedTexture { |
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index 65034d40d..eb128966c 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.h +++ b/src/video_core/renderer_opengl/gl_resource_manager.h | |||
| @@ -71,7 +71,7 @@ public: | |||
| 71 | /// Creates a new internal OpenGL resource and stores the handle | 71 | /// Creates a new internal OpenGL resource and stores the handle |
| 72 | void Create(const char* vert_shader, const char* frag_shader) { | 72 | void Create(const char* vert_shader, const char* frag_shader) { |
| 73 | if (handle != 0) return; | 73 | if (handle != 0) return; |
| 74 | handle = ShaderUtil::LoadShaders(vert_shader, frag_shader); | 74 | handle = GLShader::LoadProgram(vert_shader, frag_shader); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | /// Deletes the internal OpenGL resource | 77 | /// Deletes the internal OpenGL resource |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp new file mode 100644 index 000000000..38de5d469 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -0,0 +1,392 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "video_core/pica.h" | ||
| 6 | #include "video_core/renderer_opengl/gl_rasterizer.h" | ||
| 7 | #include "video_core/renderer_opengl/gl_shader_gen.h" | ||
| 8 | |||
| 9 | using Pica::Regs; | ||
| 10 | using TevStageConfig = Regs::TevStageConfig; | ||
| 11 | |||
| 12 | namespace GLShader { | ||
| 13 | |||
| 14 | /// Detects if a TEV stage is configured to be skipped (to avoid generating unnecessary code) | ||
| 15 | static bool IsPassThroughTevStage(const TevStageConfig& stage) { | ||
| 16 | return (stage.color_op == TevStageConfig::Operation::Replace && | ||
| 17 | stage.alpha_op == TevStageConfig::Operation::Replace && | ||
| 18 | stage.color_source1 == TevStageConfig::Source::Previous && | ||
| 19 | stage.alpha_source1 == TevStageConfig::Source::Previous && | ||
| 20 | stage.color_modifier1 == TevStageConfig::ColorModifier::SourceColor && | ||
| 21 | stage.alpha_modifier1 == TevStageConfig::AlphaModifier::SourceAlpha && | ||
| 22 | stage.GetColorMultiplier() == 1 && | ||
| 23 | stage.GetAlphaMultiplier() == 1); | ||
| 24 | } | ||
| 25 | |||
| 26 | /// Writes the specified TEV stage source component(s) | ||
| 27 | static void AppendSource(std::string& out, TevStageConfig::Source source, | ||
| 28 | const std::string& index_name) { | ||
| 29 | using Source = TevStageConfig::Source; | ||
| 30 | switch (source) { | ||
| 31 | case Source::PrimaryColor: | ||
| 32 | out += "primary_color"; | ||
| 33 | break; | ||
| 34 | case Source::PrimaryFragmentColor: | ||
| 35 | // HACK: Until we implement fragment lighting, use primary_color | ||
| 36 | out += "primary_color"; | ||
| 37 | break; | ||
| 38 | case Source::SecondaryFragmentColor: | ||
| 39 | // HACK: Until we implement fragment lighting, use zero | ||
| 40 | out += "vec4(0.0)"; | ||
| 41 | break; | ||
| 42 | case Source::Texture0: | ||
| 43 | out += "texture(tex[0], texcoord[0])"; | ||
| 44 | break; | ||
| 45 | case Source::Texture1: | ||
| 46 | out += "texture(tex[1], texcoord[1])"; | ||
| 47 | break; | ||
| 48 | case Source::Texture2: | ||
| 49 | out += "texture(tex[2], texcoord[2])"; | ||
| 50 | break; | ||
| 51 | case Source::PreviousBuffer: | ||
| 52 | out += "combiner_buffer"; | ||
| 53 | break; | ||
| 54 | case Source::Constant: | ||
| 55 | ((out += "const_color[") += index_name) += ']'; | ||
| 56 | break; | ||
| 57 | case Source::Previous: | ||
| 58 | out += "last_tex_env_out"; | ||
| 59 | break; | ||
| 60 | default: | ||
| 61 | out += "vec4(0.0)"; | ||
| 62 | LOG_CRITICAL(Render_OpenGL, "Unknown source op %u", source); | ||
| 63 | break; | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | /// Writes the color components to use for the specified TEV stage color modifier | ||
| 68 | static void AppendColorModifier(std::string& out, TevStageConfig::ColorModifier modifier, | ||
| 69 | TevStageConfig::Source source, const std::string& index_name) { | ||
| 70 | using ColorModifier = TevStageConfig::ColorModifier; | ||
| 71 | switch (modifier) { | ||
| 72 | case ColorModifier::SourceColor: | ||
| 73 | AppendSource(out, source, index_name); | ||
| 74 | out += ".rgb"; | ||
| 75 | break; | ||
| 76 | case ColorModifier::OneMinusSourceColor: | ||
| 77 | out += "vec3(1.0) - "; | ||
| 78 | AppendSource(out, source, index_name); | ||
| 79 | out += ".rgb"; | ||
| 80 | break; | ||
| 81 | case ColorModifier::SourceAlpha: | ||
| 82 | AppendSource(out, source, index_name); | ||
| 83 | out += ".aaa"; | ||
| 84 | break; | ||
| 85 | case ColorModifier::OneMinusSourceAlpha: | ||
| 86 | out += "vec3(1.0) - "; | ||
| 87 | AppendSource(out, source, index_name); | ||
| 88 | out += ".aaa"; | ||
| 89 | break; | ||
| 90 | case ColorModifier::SourceRed: | ||
| 91 | AppendSource(out, source, index_name); | ||
| 92 | out += ".rrr"; | ||
| 93 | break; | ||
| 94 | case ColorModifier::OneMinusSourceRed: | ||
| 95 | out += "vec3(1.0) - "; | ||
| 96 | AppendSource(out, source, index_name); | ||
| 97 | out += ".rrr"; | ||
| 98 | break; | ||
| 99 | case ColorModifier::SourceGreen: | ||
| 100 | AppendSource(out, source, index_name); | ||
| 101 | out += ".ggg"; | ||
| 102 | break; | ||
| 103 | case ColorModifier::OneMinusSourceGreen: | ||
| 104 | out += "vec3(1.0) - "; | ||
| 105 | AppendSource(out, source, index_name); | ||
| 106 | out += ".ggg"; | ||
| 107 | break; | ||
| 108 | case ColorModifier::SourceBlue: | ||
| 109 | AppendSource(out, source, index_name); | ||
| 110 | out += ".bbb"; | ||
| 111 | break; | ||
| 112 | case ColorModifier::OneMinusSourceBlue: | ||
| 113 | out += "vec3(1.0) - "; | ||
| 114 | AppendSource(out, source, index_name); | ||
| 115 | out += ".bbb"; | ||
| 116 | break; | ||
| 117 | default: | ||
| 118 | out += "vec3(0.0)"; | ||
| 119 | LOG_CRITICAL(Render_OpenGL, "Unknown color modifier op %u", modifier); | ||
| 120 | break; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | /// Writes the alpha component to use for the specified TEV stage alpha modifier | ||
| 125 | static void AppendAlphaModifier(std::string& out, TevStageConfig::AlphaModifier modifier, | ||
| 126 | TevStageConfig::Source source, const std::string& index_name) { | ||
| 127 | using AlphaModifier = TevStageConfig::AlphaModifier; | ||
| 128 | switch (modifier) { | ||
| 129 | case AlphaModifier::SourceAlpha: | ||
| 130 | AppendSource(out, source, index_name); | ||
| 131 | out += ".a"; | ||
| 132 | break; | ||
| 133 | case AlphaModifier::OneMinusSourceAlpha: | ||
| 134 | out += "1.0 - "; | ||
| 135 | AppendSource(out, source, index_name); | ||
| 136 | out += ".a"; | ||
| 137 | break; | ||
| 138 | case AlphaModifier::SourceRed: | ||
| 139 | AppendSource(out, source, index_name); | ||
| 140 | out += ".r"; | ||
| 141 | break; | ||
| 142 | case AlphaModifier::OneMinusSourceRed: | ||
| 143 | out += "1.0 - "; | ||
| 144 | AppendSource(out, source, index_name); | ||
| 145 | out += ".r"; | ||
| 146 | break; | ||
| 147 | case AlphaModifier::SourceGreen: | ||
| 148 | AppendSource(out, source, index_name); | ||
| 149 | out += ".g"; | ||
| 150 | break; | ||
| 151 | case AlphaModifier::OneMinusSourceGreen: | ||
| 152 | out += "1.0 - "; | ||
| 153 | AppendSource(out, source, index_name); | ||
| 154 | out += ".g"; | ||
| 155 | break; | ||
| 156 | case AlphaModifier::SourceBlue: | ||
| 157 | AppendSource(out, source, index_name); | ||
| 158 | out += ".b"; | ||
| 159 | break; | ||
| 160 | case AlphaModifier::OneMinusSourceBlue: | ||
| 161 | out += "1.0 - "; | ||
| 162 | AppendSource(out, source, index_name); | ||
| 163 | out += ".b"; | ||
| 164 | break; | ||
| 165 | default: | ||
| 166 | out += "0.0"; | ||
| 167 | LOG_CRITICAL(Render_OpenGL, "Unknown alpha modifier op %u", modifier); | ||
| 168 | break; | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | /// Writes the combiner function for the color components for the specified TEV stage operation | ||
| 173 | static void AppendColorCombiner(std::string& out, TevStageConfig::Operation operation, | ||
| 174 | const std::string& variable_name) { | ||
| 175 | out += "clamp("; | ||
| 176 | using Operation = TevStageConfig::Operation; | ||
| 177 | switch (operation) { | ||
| 178 | case Operation::Replace: | ||
| 179 | out += variable_name + "[0]"; | ||
| 180 | break; | ||
| 181 | case Operation::Modulate: | ||
| 182 | out += variable_name + "[0] * " + variable_name + "[1]"; | ||
| 183 | break; | ||
| 184 | case Operation::Add: | ||
| 185 | out += variable_name + "[0] + " + variable_name + "[1]"; | ||
| 186 | break; | ||
| 187 | case Operation::AddSigned: | ||
| 188 | out += variable_name + "[0] + " + variable_name + "[1] - vec3(0.5)"; | ||
| 189 | break; | ||
| 190 | case Operation::Lerp: | ||
| 191 | // TODO(bunnei): Verify if HW actually does this per-component, otherwise we can just use builtin lerp | ||
| 192 | out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (vec3(1.0) - " + variable_name + "[2])"; | ||
| 193 | break; | ||
| 194 | case Operation::Subtract: | ||
| 195 | out += variable_name + "[0] - " + variable_name + "[1]"; | ||
| 196 | break; | ||
| 197 | case Operation::MultiplyThenAdd: | ||
| 198 | out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]"; | ||
| 199 | break; | ||
| 200 | case Operation::AddThenMultiply: | ||
| 201 | out += "min(" + variable_name + "[0] + " + variable_name + "[1], vec3(1.0)) * " + variable_name + "[2]"; | ||
| 202 | break; | ||
| 203 | default: | ||
| 204 | out += "vec3(0.0)"; | ||
| 205 | LOG_CRITICAL(Render_OpenGL, "Unknown color combiner operation: %u", operation); | ||
| 206 | break; | ||
| 207 | } | ||
| 208 | out += ", vec3(0.0), vec3(1.0))"; // Clamp result to 0.0, 1.0 | ||
| 209 | } | ||
| 210 | |||
| 211 | /// Writes the combiner function for the alpha component for the specified TEV stage operation | ||
| 212 | static void AppendAlphaCombiner(std::string& out, TevStageConfig::Operation operation, | ||
| 213 | const std::string& variable_name) { | ||
| 214 | out += "clamp("; | ||
| 215 | using Operation = TevStageConfig::Operation; | ||
| 216 | switch (operation) { | ||
| 217 | case Operation::Replace: | ||
| 218 | out += variable_name + "[0]"; | ||
| 219 | break; | ||
| 220 | case Operation::Modulate: | ||
| 221 | out += variable_name + "[0] * " + variable_name + "[1]"; | ||
| 222 | break; | ||
| 223 | case Operation::Add: | ||
| 224 | out += variable_name + "[0] + " + variable_name + "[1]"; | ||
| 225 | break; | ||
| 226 | case Operation::AddSigned: | ||
| 227 | out += variable_name + "[0] + " + variable_name + "[1] - 0.5"; | ||
| 228 | break; | ||
| 229 | case Operation::Lerp: | ||
| 230 | out += variable_name + "[0] * " + variable_name + "[2] + " + variable_name + "[1] * (1.0 - " + variable_name + "[2])"; | ||
| 231 | break; | ||
| 232 | case Operation::Subtract: | ||
| 233 | out += variable_name + "[0] - " + variable_name + "[1]"; | ||
| 234 | break; | ||
| 235 | case Operation::MultiplyThenAdd: | ||
| 236 | out += variable_name + "[0] * " + variable_name + "[1] + " + variable_name + "[2]"; | ||
| 237 | break; | ||
| 238 | case Operation::AddThenMultiply: | ||
| 239 | out += "min(" + variable_name + "[0] + " + variable_name + "[1], 1.0) * " + variable_name + "[2]"; | ||
| 240 | break; | ||
| 241 | default: | ||
| 242 | out += "0.0"; | ||
| 243 | LOG_CRITICAL(Render_OpenGL, "Unknown alpha combiner operation: %u", operation); | ||
| 244 | break; | ||
| 245 | } | ||
| 246 | out += ", 0.0, 1.0)"; | ||
| 247 | } | ||
| 248 | |||
| 249 | /// Writes the if-statement condition used to evaluate alpha testing | ||
| 250 | static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) { | ||
| 251 | using CompareFunc = Regs::CompareFunc; | ||
| 252 | switch (func) { | ||
| 253 | case CompareFunc::Never: | ||
| 254 | out += "true"; | ||
| 255 | break; | ||
| 256 | case CompareFunc::Always: | ||
| 257 | out += "false"; | ||
| 258 | break; | ||
| 259 | case CompareFunc::Equal: | ||
| 260 | case CompareFunc::NotEqual: | ||
| 261 | case CompareFunc::LessThan: | ||
| 262 | case CompareFunc::LessThanOrEqual: | ||
| 263 | case CompareFunc::GreaterThan: | ||
| 264 | case CompareFunc::GreaterThanOrEqual: | ||
| 265 | { | ||
| 266 | static const char* op[] = { "!=", "==", ">=", ">", "<=", "<", }; | ||
| 267 | unsigned index = (unsigned)func - (unsigned)CompareFunc::Equal; | ||
| 268 | out += "int(last_tex_env_out.a * 255.0f) " + std::string(op[index]) + " alphatest_ref"; | ||
| 269 | break; | ||
| 270 | } | ||
| 271 | |||
| 272 | default: | ||
| 273 | out += "false"; | ||
| 274 | LOG_CRITICAL(Render_OpenGL, "Unknown alpha test condition %u", func); | ||
| 275 | break; | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 279 | /// Writes the code to emulate the specified TEV stage | ||
| 280 | static void WriteTevStage(std::string& out, const PicaShaderConfig& config, unsigned index) { | ||
| 281 | auto& stage = config.tev_stages[index]; | ||
| 282 | if (!IsPassThroughTevStage(stage)) { | ||
| 283 | std::string index_name = std::to_string(index); | ||
| 284 | |||
| 285 | out += "vec3 color_results_" + index_name + "[3] = vec3[3]("; | ||
| 286 | AppendColorModifier(out, stage.color_modifier1, stage.color_source1, index_name); | ||
| 287 | out += ", "; | ||
| 288 | AppendColorModifier(out, stage.color_modifier2, stage.color_source2, index_name); | ||
| 289 | out += ", "; | ||
| 290 | AppendColorModifier(out, stage.color_modifier3, stage.color_source3, index_name); | ||
| 291 | out += ");\n"; | ||
| 292 | |||
| 293 | out += "vec3 color_output_" + index_name + " = "; | ||
| 294 | AppendColorCombiner(out, stage.color_op, "color_results_" + index_name); | ||
| 295 | out += ";\n"; | ||
| 296 | |||
| 297 | out += "float alpha_results_" + index_name + "[3] = float[3]("; | ||
| 298 | AppendAlphaModifier(out, stage.alpha_modifier1, stage.alpha_source1, index_name); | ||
| 299 | out += ", "; | ||
| 300 | AppendAlphaModifier(out, stage.alpha_modifier2, stage.alpha_source2, index_name); | ||
| 301 | out += ", "; | ||
| 302 | AppendAlphaModifier(out, stage.alpha_modifier3, stage.alpha_source3, index_name); | ||
| 303 | out += ");\n"; | ||
| 304 | |||
| 305 | out += "float alpha_output_" + index_name + " = "; | ||
| 306 | AppendAlphaCombiner(out, stage.alpha_op, "alpha_results_" + index_name); | ||
| 307 | out += ";\n"; | ||
| 308 | |||
| 309 | out += "last_tex_env_out = vec4(" | ||
| 310 | "clamp(color_output_" + index_name + " * " + std::to_string(stage.GetColorMultiplier()) + ".0, vec3(0.0), vec3(1.0))," | ||
| 311 | "clamp(alpha_output_" + index_name + " * " + std::to_string(stage.GetAlphaMultiplier()) + ".0, 0.0, 1.0));\n"; | ||
| 312 | } | ||
| 313 | |||
| 314 | out += "combiner_buffer = next_combiner_buffer;\n"; | ||
| 315 | |||
| 316 | if (config.TevStageUpdatesCombinerBufferColor(index)) | ||
| 317 | out += "next_combiner_buffer.rgb = last_tex_env_out.rgb;\n"; | ||
| 318 | |||
| 319 | if (config.TevStageUpdatesCombinerBufferAlpha(index)) | ||
| 320 | out += "next_combiner_buffer.a = last_tex_env_out.a;\n"; | ||
| 321 | } | ||
| 322 | |||
| 323 | std::string GenerateFragmentShader(const PicaShaderConfig& config) { | ||
| 324 | std::string out = R"( | ||
| 325 | #version 330 core | ||
| 326 | #define NUM_TEV_STAGES 6 | ||
| 327 | |||
| 328 | in vec4 primary_color; | ||
| 329 | in vec2 texcoord[3]; | ||
| 330 | |||
| 331 | out vec4 color; | ||
| 332 | |||
| 333 | layout (std140) uniform shader_data { | ||
| 334 | vec4 const_color[NUM_TEV_STAGES]; | ||
| 335 | vec4 tev_combiner_buffer_color; | ||
| 336 | int alphatest_ref; | ||
| 337 | }; | ||
| 338 | |||
| 339 | uniform sampler2D tex[3]; | ||
| 340 | |||
| 341 | void main() { | ||
| 342 | )"; | ||
| 343 | |||
| 344 | // Do not do any sort of processing if it's obvious we're not going to pass the alpha test | ||
| 345 | if (config.alpha_test_func == Regs::CompareFunc::Never) { | ||
| 346 | out += "discard; }"; | ||
| 347 | return out; | ||
| 348 | } | ||
| 349 | |||
| 350 | out += "vec4 combiner_buffer = vec4(0.0);\n"; | ||
| 351 | out += "vec4 next_combiner_buffer = tev_combiner_buffer_color;\n"; | ||
| 352 | out += "vec4 last_tex_env_out = vec4(0.0);\n"; | ||
| 353 | |||
| 354 | for (size_t index = 0; index < config.tev_stages.size(); ++index) | ||
| 355 | WriteTevStage(out, config, (unsigned)index); | ||
| 356 | |||
| 357 | if (config.alpha_test_func != Regs::CompareFunc::Always) { | ||
| 358 | out += "if ("; | ||
| 359 | AppendAlphaTestCondition(out, config.alpha_test_func); | ||
| 360 | out += ") discard;\n"; | ||
| 361 | } | ||
| 362 | |||
| 363 | out += "color = last_tex_env_out;\n}"; | ||
| 364 | |||
| 365 | return out; | ||
| 366 | } | ||
| 367 | |||
| 368 | std::string GenerateVertexShader() { | ||
| 369 | std::string out = "#version 330 core\n"; | ||
| 370 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + ") in vec4 vert_position;\n"; | ||
| 371 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_COLOR) + ") in vec4 vert_color;\n"; | ||
| 372 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD0) + ") in vec2 vert_texcoord0;\n"; | ||
| 373 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD1) + ") in vec2 vert_texcoord1;\n"; | ||
| 374 | out += "layout(location = " + std::to_string((int)ATTRIBUTE_TEXCOORD2) + ") in vec2 vert_texcoord2;\n"; | ||
| 375 | |||
| 376 | out += R"( | ||
| 377 | out vec4 primary_color; | ||
| 378 | out vec2 texcoord[3]; | ||
| 379 | |||
| 380 | void main() { | ||
| 381 | primary_color = vert_color; | ||
| 382 | texcoord[0] = vert_texcoord0; | ||
| 383 | texcoord[1] = vert_texcoord1; | ||
| 384 | texcoord[2] = vert_texcoord2; | ||
| 385 | gl_Position = vec4(vert_position.x, vert_position.y, -vert_position.z, vert_position.w); | ||
| 386 | } | ||
| 387 | )"; | ||
| 388 | |||
| 389 | return out; | ||
| 390 | } | ||
| 391 | |||
| 392 | } // namespace GLShader | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h new file mode 100644 index 000000000..0ca9d2879 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_shader_gen.h | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <string> | ||
| 8 | |||
| 9 | #include "video_core/renderer_opengl/gl_rasterizer.h" | ||
| 10 | |||
| 11 | namespace GLShader { | ||
| 12 | |||
| 13 | /** | ||
| 14 | * Generates the GLSL vertex shader program source code for the current Pica state | ||
| 15 | * @returns String of the shader source code | ||
| 16 | */ | ||
| 17 | std::string GenerateVertexShader(); | ||
| 18 | |||
| 19 | /** | ||
| 20 | * Generates the GLSL fragment shader program source code for the current Pica state | ||
| 21 | * @param config ShaderCacheKey object generated for the current Pica state, used for the shader | ||
| 22 | * configuration (NOTE: Use state in this struct only, not the Pica registers!) | ||
| 23 | * @returns String of the shader source code | ||
| 24 | */ | ||
| 25 | std::string GenerateFragmentShader(const PicaShaderConfig& config); | ||
| 26 | |||
| 27 | } // namespace GLShader | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp index 4cf246c06..e3f7a5868 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.cpp +++ b/src/video_core/renderer_opengl/gl_shader_util.cpp | |||
| @@ -8,9 +8,9 @@ | |||
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "video_core/renderer_opengl/gl_shader_util.h" | 9 | #include "video_core/renderer_opengl/gl_shader_util.h" |
| 10 | 10 | ||
| 11 | namespace ShaderUtil { | 11 | namespace GLShader { |
| 12 | 12 | ||
| 13 | GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { | 13 | GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) { |
| 14 | 14 | ||
| 15 | // Create the shaders | 15 | // Create the shaders |
| 16 | GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER); | 16 | GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER); |
| @@ -65,6 +65,7 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { | |||
| 65 | GLuint program_id = glCreateProgram(); | 65 | GLuint program_id = glCreateProgram(); |
| 66 | glAttachShader(program_id, vertex_shader_id); | 66 | glAttachShader(program_id, vertex_shader_id); |
| 67 | glAttachShader(program_id, fragment_shader_id); | 67 | glAttachShader(program_id, fragment_shader_id); |
| 68 | |||
| 68 | glLinkProgram(program_id); | 69 | glLinkProgram(program_id); |
| 69 | 70 | ||
| 70 | // Check the program | 71 | // Check the program |
| @@ -87,4 +88,4 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { | |||
| 87 | return program_id; | 88 | return program_id; |
| 88 | } | 89 | } |
| 89 | 90 | ||
| 90 | } | 91 | } // namespace GLShader |
diff --git a/src/video_core/renderer_opengl/gl_shader_util.h b/src/video_core/renderer_opengl/gl_shader_util.h index c9d7cc380..046aae14f 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.h +++ b/src/video_core/renderer_opengl/gl_shader_util.h | |||
| @@ -6,8 +6,22 @@ | |||
| 6 | 6 | ||
| 7 | #include <glad/glad.h> | 7 | #include <glad/glad.h> |
| 8 | 8 | ||
| 9 | namespace ShaderUtil { | 9 | namespace GLShader { |
| 10 | 10 | ||
| 11 | GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path); | 11 | enum Attributes { |
| 12 | ATTRIBUTE_POSITION, | ||
| 13 | ATTRIBUTE_COLOR, | ||
| 14 | ATTRIBUTE_TEXCOORD0, | ||
| 15 | ATTRIBUTE_TEXCOORD1, | ||
| 16 | ATTRIBUTE_TEXCOORD2, | ||
| 17 | }; | ||
| 12 | 18 | ||
| 13 | } | 19 | /** |
| 20 | * Utility function to create and compile an OpenGL GLSL shader program (vertex + fragment shader) | ||
| 21 | * @param vertex_shader String of the GLSL vertex shader program | ||
| 22 | * @param fragment_shader String of the GLSL fragment shader program | ||
| 23 | * @returns Handle of the newly created OpenGL shader object | ||
| 24 | */ | ||
| 25 | GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader); | ||
| 26 | |||
| 27 | } // namespace | ||
diff --git a/src/video_core/renderer_opengl/gl_shaders.h b/src/video_core/renderer_opengl/gl_shaders.h deleted file mode 100644 index a8cb2f595..000000000 --- a/src/video_core/renderer_opengl/gl_shaders.h +++ /dev/null | |||
| @@ -1,337 +0,0 @@ | |||
| 1 | // Copyright 2014 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | namespace GLShaders { | ||
| 8 | |||
| 9 | const char g_vertex_shader[] = R"( | ||
| 10 | #version 150 core | ||
| 11 | |||
| 12 | in vec2 vert_position; | ||
| 13 | in vec2 vert_tex_coord; | ||
| 14 | out vec2 frag_tex_coord; | ||
| 15 | |||
| 16 | // This is a truncated 3x3 matrix for 2D transformations: | ||
| 17 | // The upper-left 2x2 submatrix performs scaling/rotation/mirroring. | ||
| 18 | // The third column performs translation. | ||
| 19 | // The third row could be used for projection, which we don't need in 2D. It hence is assumed to | ||
| 20 | // implicitly be [0, 0, 1] | ||
| 21 | uniform mat3x2 modelview_matrix; | ||
| 22 | |||
| 23 | void main() { | ||
| 24 | // Multiply input position by the rotscale part of the matrix and then manually translate by | ||
| 25 | // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector | ||
| 26 | // to `vec3(vert_position.xy, 1.0)` | ||
| 27 | gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0); | ||
| 28 | frag_tex_coord = vert_tex_coord; | ||
| 29 | } | ||
| 30 | )"; | ||
| 31 | |||
| 32 | const char g_fragment_shader[] = R"( | ||
| 33 | #version 150 core | ||
| 34 | |||
| 35 | in vec2 frag_tex_coord; | ||
| 36 | out vec4 color; | ||
| 37 | |||
| 38 | uniform sampler2D color_texture; | ||
| 39 | |||
| 40 | void main() { | ||
| 41 | color = texture(color_texture, frag_tex_coord); | ||
| 42 | } | ||
| 43 | )"; | ||
| 44 | |||
| 45 | const char g_vertex_shader_hw[] = R"( | ||
| 46 | #version 150 core | ||
| 47 | |||
| 48 | #define NUM_VTX_ATTR 7 | ||
| 49 | |||
| 50 | in vec4 vert_position; | ||
| 51 | in vec4 vert_color; | ||
| 52 | in vec2 vert_texcoords[3]; | ||
| 53 | |||
| 54 | out vec4 o[NUM_VTX_ATTR]; | ||
| 55 | |||
| 56 | void main() { | ||
| 57 | o[2] = vert_color; | ||
| 58 | o[3] = vec4(vert_texcoords[0].xy, vert_texcoords[1].xy); | ||
| 59 | o[5] = vec4(0.0, 0.0, vert_texcoords[2].xy); | ||
| 60 | |||
| 61 | gl_Position = vec4(vert_position.x, -vert_position.y, -vert_position.z, vert_position.w); | ||
| 62 | } | ||
| 63 | )"; | ||
| 64 | |||
| 65 | // TODO: Create a shader constructor and cache that builds this program with minimal conditionals instead of using tev_cfg uniforms | ||
| 66 | const char g_fragment_shader_hw[] = R"( | ||
| 67 | #version 150 core | ||
| 68 | |||
| 69 | #define NUM_VTX_ATTR 7 | ||
| 70 | #define NUM_TEV_STAGES 6 | ||
| 71 | |||
| 72 | #define SOURCE_PRIMARYCOLOR 0x0 | ||
| 73 | #define SOURCE_PRIMARYFRAGMENTCOLOR 0x1 | ||
| 74 | #define SOURCE_SECONDARYFRAGMENTCOLOR 0x2 | ||
| 75 | #define SOURCE_TEXTURE0 0x3 | ||
| 76 | #define SOURCE_TEXTURE1 0x4 | ||
| 77 | #define SOURCE_TEXTURE2 0x5 | ||
| 78 | #define SOURCE_TEXTURE3 0x6 | ||
| 79 | #define SOURCE_PREVIOUSBUFFER 0xd | ||
| 80 | #define SOURCE_CONSTANT 0xe | ||
| 81 | #define SOURCE_PREVIOUS 0xf | ||
| 82 | |||
| 83 | #define COLORMODIFIER_SOURCECOLOR 0x0 | ||
| 84 | #define COLORMODIFIER_ONEMINUSSOURCECOLOR 0x1 | ||
| 85 | #define COLORMODIFIER_SOURCEALPHA 0x2 | ||
| 86 | #define COLORMODIFIER_ONEMINUSSOURCEALPHA 0x3 | ||
| 87 | #define COLORMODIFIER_SOURCERED 0x4 | ||
| 88 | #define COLORMODIFIER_ONEMINUSSOURCERED 0x5 | ||
| 89 | #define COLORMODIFIER_SOURCEGREEN 0x8 | ||
| 90 | #define COLORMODIFIER_ONEMINUSSOURCEGREEN 0x9 | ||
| 91 | #define COLORMODIFIER_SOURCEBLUE 0xc | ||
| 92 | #define COLORMODIFIER_ONEMINUSSOURCEBLUE 0xd | ||
| 93 | |||
| 94 | #define ALPHAMODIFIER_SOURCEALPHA 0x0 | ||
| 95 | #define ALPHAMODIFIER_ONEMINUSSOURCEALPHA 0x1 | ||
| 96 | #define ALPHAMODIFIER_SOURCERED 0x2 | ||
| 97 | #define ALPHAMODIFIER_ONEMINUSSOURCERED 0x3 | ||
| 98 | #define ALPHAMODIFIER_SOURCEGREEN 0x4 | ||
| 99 | #define ALPHAMODIFIER_ONEMINUSSOURCEGREEN 0x5 | ||
| 100 | #define ALPHAMODIFIER_SOURCEBLUE 0x6 | ||
| 101 | #define ALPHAMODIFIER_ONEMINUSSOURCEBLUE 0x7 | ||
| 102 | |||
| 103 | #define OPERATION_REPLACE 0 | ||
| 104 | #define OPERATION_MODULATE 1 | ||
| 105 | #define OPERATION_ADD 2 | ||
| 106 | #define OPERATION_ADDSIGNED 3 | ||
| 107 | #define OPERATION_LERP 4 | ||
| 108 | #define OPERATION_SUBTRACT 5 | ||
| 109 | #define OPERATION_MULTIPLYTHENADD 8 | ||
| 110 | #define OPERATION_ADDTHENMULTIPLY 9 | ||
| 111 | |||
| 112 | #define COMPAREFUNC_NEVER 0 | ||
| 113 | #define COMPAREFUNC_ALWAYS 1 | ||
| 114 | #define COMPAREFUNC_EQUAL 2 | ||
| 115 | #define COMPAREFUNC_NOTEQUAL 3 | ||
| 116 | #define COMPAREFUNC_LESSTHAN 4 | ||
| 117 | #define COMPAREFUNC_LESSTHANOREQUAL 5 | ||
| 118 | #define COMPAREFUNC_GREATERTHAN 6 | ||
| 119 | #define COMPAREFUNC_GREATERTHANOREQUAL 7 | ||
| 120 | |||
| 121 | in vec4 o[NUM_VTX_ATTR]; | ||
| 122 | out vec4 color; | ||
| 123 | |||
| 124 | uniform bool alphatest_enabled; | ||
| 125 | uniform int alphatest_func; | ||
| 126 | uniform float alphatest_ref; | ||
| 127 | |||
| 128 | uniform sampler2D tex[3]; | ||
| 129 | |||
| 130 | uniform vec4 tev_combiner_buffer_color; | ||
| 131 | |||
| 132 | struct TEVConfig | ||
| 133 | { | ||
| 134 | bool enabled; | ||
| 135 | ivec3 color_sources; | ||
| 136 | ivec3 alpha_sources; | ||
| 137 | ivec3 color_modifiers; | ||
| 138 | ivec3 alpha_modifiers; | ||
| 139 | ivec2 color_alpha_op; | ||
| 140 | ivec2 color_alpha_multiplier; | ||
| 141 | vec4 const_color; | ||
| 142 | bvec2 updates_combiner_buffer_color_alpha; | ||
| 143 | }; | ||
| 144 | |||
| 145 | uniform TEVConfig tev_cfgs[NUM_TEV_STAGES]; | ||
| 146 | |||
| 147 | vec4 g_combiner_buffer; | ||
| 148 | vec4 g_last_tex_env_out; | ||
| 149 | vec4 g_const_color; | ||
| 150 | |||
| 151 | vec4 GetSource(int source) { | ||
| 152 | if (source == SOURCE_PRIMARYCOLOR) { | ||
| 153 | return o[2]; | ||
| 154 | } else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) { | ||
| 155 | // HACK: Until we implement fragment lighting, use primary_color | ||
| 156 | return o[2]; | ||
| 157 | } else if (source == SOURCE_SECONDARYFRAGMENTCOLOR) { | ||
| 158 | // HACK: Until we implement fragment lighting, use zero | ||
| 159 | return vec4(0.0, 0.0, 0.0, 0.0); | ||
| 160 | } else if (source == SOURCE_TEXTURE0) { | ||
| 161 | return texture(tex[0], o[3].xy); | ||
| 162 | } else if (source == SOURCE_TEXTURE1) { | ||
| 163 | return texture(tex[1], o[3].zw); | ||
| 164 | } else if (source == SOURCE_TEXTURE2) { | ||
| 165 | // TODO: Unverified | ||
| 166 | return texture(tex[2], o[5].zw); | ||
| 167 | } else if (source == SOURCE_TEXTURE3) { | ||
| 168 | // TODO: no 4th texture? | ||
| 169 | } else if (source == SOURCE_PREVIOUSBUFFER) { | ||
| 170 | return g_combiner_buffer; | ||
| 171 | } else if (source == SOURCE_CONSTANT) { | ||
| 172 | return g_const_color; | ||
| 173 | } else if (source == SOURCE_PREVIOUS) { | ||
| 174 | return g_last_tex_env_out; | ||
| 175 | } | ||
| 176 | |||
| 177 | return vec4(0.0); | ||
| 178 | } | ||
| 179 | |||
| 180 | vec3 GetColorModifier(int factor, vec4 color) { | ||
| 181 | if (factor == COLORMODIFIER_SOURCECOLOR) { | ||
| 182 | return color.rgb; | ||
| 183 | } else if (factor == COLORMODIFIER_ONEMINUSSOURCECOLOR) { | ||
| 184 | return vec3(1.0) - color.rgb; | ||
| 185 | } else if (factor == COLORMODIFIER_SOURCEALPHA) { | ||
| 186 | return color.aaa; | ||
| 187 | } else if (factor == COLORMODIFIER_ONEMINUSSOURCEALPHA) { | ||
| 188 | return vec3(1.0) - color.aaa; | ||
| 189 | } else if (factor == COLORMODIFIER_SOURCERED) { | ||
| 190 | return color.rrr; | ||
| 191 | } else if (factor == COLORMODIFIER_ONEMINUSSOURCERED) { | ||
| 192 | return vec3(1.0) - color.rrr; | ||
| 193 | } else if (factor == COLORMODIFIER_SOURCEGREEN) { | ||
| 194 | return color.ggg; | ||
| 195 | } else if (factor == COLORMODIFIER_ONEMINUSSOURCEGREEN) { | ||
| 196 | return vec3(1.0) - color.ggg; | ||
| 197 | } else if (factor == COLORMODIFIER_SOURCEBLUE) { | ||
| 198 | return color.bbb; | ||
| 199 | } else if (factor == COLORMODIFIER_ONEMINUSSOURCEBLUE) { | ||
| 200 | return vec3(1.0) - color.bbb; | ||
| 201 | } | ||
| 202 | |||
| 203 | return vec3(0.0); | ||
| 204 | } | ||
| 205 | |||
| 206 | float GetAlphaModifier(int factor, vec4 color) { | ||
| 207 | if (factor == ALPHAMODIFIER_SOURCEALPHA) { | ||
| 208 | return color.a; | ||
| 209 | } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEALPHA) { | ||
| 210 | return 1.0 - color.a; | ||
| 211 | } else if (factor == ALPHAMODIFIER_SOURCERED) { | ||
| 212 | return color.r; | ||
| 213 | } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCERED) { | ||
| 214 | return 1.0 - color.r; | ||
| 215 | } else if (factor == ALPHAMODIFIER_SOURCEGREEN) { | ||
| 216 | return color.g; | ||
| 217 | } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEGREEN) { | ||
| 218 | return 1.0 - color.g; | ||
| 219 | } else if (factor == ALPHAMODIFIER_SOURCEBLUE) { | ||
| 220 | return color.b; | ||
| 221 | } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEBLUE) { | ||
| 222 | return 1.0 - color.b; | ||
| 223 | } | ||
| 224 | |||
| 225 | return 0.0; | ||
| 226 | } | ||
| 227 | |||
| 228 | vec3 ColorCombine(int op, vec3 color[3]) { | ||
| 229 | if (op == OPERATION_REPLACE) { | ||
| 230 | return color[0]; | ||
| 231 | } else if (op == OPERATION_MODULATE) { | ||
| 232 | return color[0] * color[1]; | ||
| 233 | } else if (op == OPERATION_ADD) { | ||
| 234 | return min(color[0] + color[1], 1.0); | ||
| 235 | } else if (op == OPERATION_ADDSIGNED) { | ||
| 236 | return clamp(color[0] + color[1] - vec3(0.5), 0.0, 1.0); | ||
| 237 | } else if (op == OPERATION_LERP) { | ||
| 238 | return color[0] * color[2] + color[1] * (vec3(1.0) - color[2]); | ||
| 239 | } else if (op == OPERATION_SUBTRACT) { | ||
| 240 | return max(color[0] - color[1], 0.0); | ||
| 241 | } else if (op == OPERATION_MULTIPLYTHENADD) { | ||
| 242 | return min(color[0] * color[1] + color[2], 1.0); | ||
| 243 | } else if (op == OPERATION_ADDTHENMULTIPLY) { | ||
| 244 | return min(color[0] + color[1], 1.0) * color[2]; | ||
| 245 | } | ||
| 246 | |||
| 247 | return vec3(0.0); | ||
| 248 | } | ||
| 249 | |||
| 250 | float AlphaCombine(int op, float alpha[3]) { | ||
| 251 | if (op == OPERATION_REPLACE) { | ||
| 252 | return alpha[0]; | ||
| 253 | } else if (op == OPERATION_MODULATE) { | ||
| 254 | return alpha[0] * alpha[1]; | ||
| 255 | } else if (op == OPERATION_ADD) { | ||
| 256 | return min(alpha[0] + alpha[1], 1.0); | ||
| 257 | } else if (op == OPERATION_ADDSIGNED) { | ||
| 258 | return clamp(alpha[0] + alpha[1] - 0.5, 0.0, 1.0); | ||
| 259 | } else if (op == OPERATION_LERP) { | ||
| 260 | return alpha[0] * alpha[2] + alpha[1] * (1.0 - alpha[2]); | ||
| 261 | } else if (op == OPERATION_SUBTRACT) { | ||
| 262 | return max(alpha[0] - alpha[1], 0.0); | ||
| 263 | } else if (op == OPERATION_MULTIPLYTHENADD) { | ||
| 264 | return min(alpha[0] * alpha[1] + alpha[2], 1.0); | ||
| 265 | } else if (op == OPERATION_ADDTHENMULTIPLY) { | ||
| 266 | return min(alpha[0] + alpha[1], 1.0) * alpha[2]; | ||
| 267 | } | ||
| 268 | |||
| 269 | return 0.0; | ||
| 270 | } | ||
| 271 | |||
| 272 | void main(void) { | ||
| 273 | g_combiner_buffer = tev_combiner_buffer_color; | ||
| 274 | |||
| 275 | for (int tex_env_idx = 0; tex_env_idx < NUM_TEV_STAGES; ++tex_env_idx) { | ||
| 276 | if (tev_cfgs[tex_env_idx].enabled) { | ||
| 277 | g_const_color = tev_cfgs[tex_env_idx].const_color; | ||
| 278 | |||
| 279 | vec3 color_results[3] = vec3[3](GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.x, GetSource(tev_cfgs[tex_env_idx].color_sources.x)), | ||
| 280 | GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.y, GetSource(tev_cfgs[tex_env_idx].color_sources.y)), | ||
| 281 | GetColorModifier(tev_cfgs[tex_env_idx].color_modifiers.z, GetSource(tev_cfgs[tex_env_idx].color_sources.z))); | ||
| 282 | vec3 color_output = ColorCombine(tev_cfgs[tex_env_idx].color_alpha_op.x, color_results); | ||
| 283 | |||
| 284 | float alpha_results[3] = float[3](GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.x, GetSource(tev_cfgs[tex_env_idx].alpha_sources.x)), | ||
| 285 | GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.y, GetSource(tev_cfgs[tex_env_idx].alpha_sources.y)), | ||
| 286 | GetAlphaModifier(tev_cfgs[tex_env_idx].alpha_modifiers.z, GetSource(tev_cfgs[tex_env_idx].alpha_sources.z))); | ||
| 287 | float alpha_output = AlphaCombine(tev_cfgs[tex_env_idx].color_alpha_op.y, alpha_results); | ||
| 288 | |||
| 289 | g_last_tex_env_out = vec4(min(color_output * tev_cfgs[tex_env_idx].color_alpha_multiplier.x, 1.0), min(alpha_output * tev_cfgs[tex_env_idx].color_alpha_multiplier.y, 1.0)); | ||
| 290 | } | ||
| 291 | |||
| 292 | if (tev_cfgs[tex_env_idx].updates_combiner_buffer_color_alpha.x) { | ||
| 293 | g_combiner_buffer.rgb = g_last_tex_env_out.rgb; | ||
| 294 | } | ||
| 295 | |||
| 296 | if (tev_cfgs[tex_env_idx].updates_combiner_buffer_color_alpha.y) { | ||
| 297 | g_combiner_buffer.a = g_last_tex_env_out.a; | ||
| 298 | } | ||
| 299 | } | ||
| 300 | |||
| 301 | if (alphatest_enabled) { | ||
| 302 | if (alphatest_func == COMPAREFUNC_NEVER) { | ||
| 303 | discard; | ||
| 304 | } else if (alphatest_func == COMPAREFUNC_ALWAYS) { | ||
| 305 | |||
| 306 | } else if (alphatest_func == COMPAREFUNC_EQUAL) { | ||
| 307 | if (g_last_tex_env_out.a != alphatest_ref) { | ||
| 308 | discard; | ||
| 309 | } | ||
| 310 | } else if (alphatest_func == COMPAREFUNC_NOTEQUAL) { | ||
| 311 | if (g_last_tex_env_out.a == alphatest_ref) { | ||
| 312 | discard; | ||
| 313 | } | ||
| 314 | } else if (alphatest_func == COMPAREFUNC_LESSTHAN) { | ||
| 315 | if (g_last_tex_env_out.a >= alphatest_ref) { | ||
| 316 | discard; | ||
| 317 | } | ||
| 318 | } else if (alphatest_func == COMPAREFUNC_LESSTHANOREQUAL) { | ||
| 319 | if (g_last_tex_env_out.a > alphatest_ref) { | ||
| 320 | discard; | ||
| 321 | } | ||
| 322 | } else if (alphatest_func == COMPAREFUNC_GREATERTHAN) { | ||
| 323 | if (g_last_tex_env_out.a <= alphatest_ref) { | ||
| 324 | discard; | ||
| 325 | } | ||
| 326 | } else if (alphatest_func == COMPAREFUNC_GREATERTHANOREQUAL) { | ||
| 327 | if (g_last_tex_env_out.a < alphatest_ref) { | ||
| 328 | discard; | ||
| 329 | } | ||
| 330 | } | ||
| 331 | } | ||
| 332 | |||
| 333 | color = g_last_tex_env_out; | ||
| 334 | } | ||
| 335 | )"; | ||
| 336 | |||
| 337 | } | ||
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index 77b2816cb..a82372995 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -11,6 +11,7 @@ OpenGLState::OpenGLState() { | |||
| 11 | // These all match default OpenGL values | 11 | // These all match default OpenGL values |
| 12 | cull.enabled = false; | 12 | cull.enabled = false; |
| 13 | cull.mode = GL_BACK; | 13 | cull.mode = GL_BACK; |
| 14 | cull.front_face = GL_CCW; | ||
| 14 | 15 | ||
| 15 | depth.test_enabled = false; | 16 | depth.test_enabled = false; |
| 16 | depth.test_func = GL_LESS; | 17 | depth.test_func = GL_LESS; |
| @@ -67,6 +68,10 @@ void OpenGLState::Apply() { | |||
| 67 | glCullFace(cull.mode); | 68 | glCullFace(cull.mode); |
| 68 | } | 69 | } |
| 69 | 70 | ||
| 71 | if (cull.front_face != cur_state.cull.front_face) { | ||
| 72 | glFrontFace(cull.front_face); | ||
| 73 | } | ||
| 74 | |||
| 70 | // Depth test | 75 | // Depth test |
| 71 | if (depth.test_enabled != cur_state.depth.test_enabled) { | 76 | if (depth.test_enabled != cur_state.depth.test_enabled) { |
| 72 | if (depth.test_enabled) { | 77 | if (depth.test_enabled) { |
| @@ -180,6 +185,11 @@ void OpenGLState::Apply() { | |||
| 180 | glBindBuffer(GL_ARRAY_BUFFER, draw.vertex_buffer); | 185 | glBindBuffer(GL_ARRAY_BUFFER, draw.vertex_buffer); |
| 181 | } | 186 | } |
| 182 | 187 | ||
| 188 | // Uniform buffer | ||
| 189 | if (draw.uniform_buffer != cur_state.draw.uniform_buffer) { | ||
| 190 | glBindBuffer(GL_UNIFORM_BUFFER, draw.uniform_buffer); | ||
| 191 | } | ||
| 192 | |||
| 183 | // Shader program | 193 | // Shader program |
| 184 | if (draw.shader_program != cur_state.draw.shader_program) { | 194 | if (draw.shader_program != cur_state.draw.shader_program) { |
| 185 | glUseProgram(draw.shader_program); | 195 | glUseProgram(draw.shader_program); |
| @@ -214,6 +224,9 @@ void OpenGLState::ResetBuffer(GLuint id) { | |||
| 214 | if (cur_state.draw.vertex_buffer == id) { | 224 | if (cur_state.draw.vertex_buffer == id) { |
| 215 | cur_state.draw.vertex_buffer = 0; | 225 | cur_state.draw.vertex_buffer = 0; |
| 216 | } | 226 | } |
| 227 | if (cur_state.draw.uniform_buffer == id) { | ||
| 228 | cur_state.draw.uniform_buffer = 0; | ||
| 229 | } | ||
| 217 | } | 230 | } |
| 218 | 231 | ||
| 219 | void OpenGLState::ResetVertexArray(GLuint id) { | 232 | void OpenGLState::ResetVertexArray(GLuint id) { |
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 6ecbedbb4..b8ab45bb8 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -11,6 +11,7 @@ public: | |||
| 11 | struct { | 11 | struct { |
| 12 | bool enabled; // GL_CULL_FACE | 12 | bool enabled; // GL_CULL_FACE |
| 13 | GLenum mode; // GL_CULL_FACE_MODE | 13 | GLenum mode; // GL_CULL_FACE_MODE |
| 14 | GLenum front_face; // GL_FRONT_FACE | ||
| 14 | } cull; | 15 | } cull; |
| 15 | 16 | ||
| 16 | struct { | 17 | struct { |
| @@ -64,7 +65,9 @@ public: | |||
| 64 | GLuint framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING | 65 | GLuint framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING |
| 65 | GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING | 66 | GLuint vertex_array; // GL_VERTEX_ARRAY_BINDING |
| 66 | GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING | 67 | GLuint vertex_buffer; // GL_ARRAY_BUFFER_BINDING |
| 68 | GLuint uniform_buffer; // GL_UNIFORM_BUFFER_BINDING | ||
| 67 | GLuint shader_program; // GL_CURRENT_PROGRAM | 69 | GLuint shader_program; // GL_CURRENT_PROGRAM |
| 70 | bool shader_dirty; | ||
| 68 | } draw; | 71 | } draw; |
| 69 | 72 | ||
| 70 | OpenGLState(); | 73 | OpenGLState(); |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 4202d828c..c34215340 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -21,9 +21,44 @@ | |||
| 21 | #include "video_core/debug_utils/debug_utils.h" | 21 | #include "video_core/debug_utils/debug_utils.h" |
| 22 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 22 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 23 | #include "video_core/renderer_opengl/gl_shader_util.h" | 23 | #include "video_core/renderer_opengl/gl_shader_util.h" |
| 24 | #include "video_core/renderer_opengl/gl_shaders.h" | ||
| 25 | #include "video_core/renderer_opengl/renderer_opengl.h" | 24 | #include "video_core/renderer_opengl/renderer_opengl.h" |
| 26 | 25 | ||
| 26 | static const char vertex_shader[] = R"( | ||
| 27 | #version 150 core | ||
| 28 | |||
| 29 | in vec2 vert_position; | ||
| 30 | in vec2 vert_tex_coord; | ||
| 31 | out vec2 frag_tex_coord; | ||
| 32 | |||
| 33 | // This is a truncated 3x3 matrix for 2D transformations: | ||
| 34 | // The upper-left 2x2 submatrix performs scaling/rotation/mirroring. | ||
| 35 | // The third column performs translation. | ||
| 36 | // The third row could be used for projection, which we don't need in 2D. It hence is assumed to | ||
| 37 | // implicitly be [0, 0, 1] | ||
| 38 | uniform mat3x2 modelview_matrix; | ||
| 39 | |||
| 40 | void main() { | ||
| 41 | // Multiply input position by the rotscale part of the matrix and then manually translate by | ||
| 42 | // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector | ||
| 43 | // to `vec3(vert_position.xy, 1.0)` | ||
| 44 | gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0); | ||
| 45 | frag_tex_coord = vert_tex_coord; | ||
| 46 | } | ||
| 47 | )"; | ||
| 48 | |||
| 49 | static const char fragment_shader[] = R"( | ||
| 50 | #version 150 core | ||
| 51 | |||
| 52 | in vec2 frag_tex_coord; | ||
| 53 | out vec4 color; | ||
| 54 | |||
| 55 | uniform sampler2D color_texture; | ||
| 56 | |||
| 57 | void main() { | ||
| 58 | color = texture(color_texture, frag_tex_coord); | ||
| 59 | } | ||
| 60 | )"; | ||
| 61 | |||
| 27 | /** | 62 | /** |
| 28 | * Vertex structure that the drawn screen rectangles are composed of. | 63 | * Vertex structure that the drawn screen rectangles are composed of. |
| 29 | */ | 64 | */ |
| @@ -58,7 +93,6 @@ static std::array<GLfloat, 3*2> MakeOrthographicMatrix(const float width, const | |||
| 58 | 93 | ||
| 59 | /// RendererOpenGL constructor | 94 | /// RendererOpenGL constructor |
| 60 | RendererOpenGL::RendererOpenGL() { | 95 | RendererOpenGL::RendererOpenGL() { |
| 61 | hw_rasterizer.reset(new RasterizerOpenGL()); | ||
| 62 | resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); | 96 | resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); |
| 63 | resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; | 97 | resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; |
| 64 | } | 98 | } |
| @@ -122,15 +156,7 @@ void RendererOpenGL::SwapBuffers() { | |||
| 122 | 156 | ||
| 123 | profiler.BeginFrame(); | 157 | profiler.BeginFrame(); |
| 124 | 158 | ||
| 125 | bool hw_renderer_enabled = VideoCore::g_hw_renderer_enabled; | 159 | RefreshRasterizerSetting(); |
| 126 | if (Settings::values.use_hw_renderer != hw_renderer_enabled) { | ||
| 127 | // TODO: Save new setting value to config file for next startup | ||
| 128 | Settings::values.use_hw_renderer = hw_renderer_enabled; | ||
| 129 | |||
| 130 | if (Settings::values.use_hw_renderer) { | ||
| 131 | hw_rasterizer->Reset(); | ||
| 132 | } | ||
| 133 | } | ||
| 134 | 160 | ||
| 135 | if (Pica::g_debug_context && Pica::g_debug_context->recorder) { | 161 | if (Pica::g_debug_context && Pica::g_debug_context->recorder) { |
| 136 | Pica::g_debug_context->recorder->FrameFinished(); | 162 | Pica::g_debug_context->recorder->FrameFinished(); |
| @@ -207,7 +233,7 @@ void RendererOpenGL::InitOpenGLObjects() { | |||
| 207 | glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f); | 233 | glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f); |
| 208 | 234 | ||
| 209 | // Link shaders and get variable locations | 235 | // Link shaders and get variable locations |
| 210 | program_id = ShaderUtil::LoadShaders(GLShaders::g_vertex_shader, GLShaders::g_fragment_shader); | 236 | program_id = GLShader::LoadProgram(vertex_shader, fragment_shader); |
| 211 | uniform_modelview_matrix = glGetUniformLocation(program_id, "modelview_matrix"); | 237 | uniform_modelview_matrix = glGetUniformLocation(program_id, "modelview_matrix"); |
| 212 | uniform_color_texture = glGetUniformLocation(program_id, "color_texture"); | 238 | uniform_color_texture = glGetUniformLocation(program_id, "color_texture"); |
| 213 | attrib_position = glGetAttribLocation(program_id, "vert_position"); | 239 | attrib_position = glGetAttribLocation(program_id, "vert_position"); |
| @@ -221,6 +247,7 @@ void RendererOpenGL::InitOpenGLObjects() { | |||
| 221 | 247 | ||
| 222 | state.draw.vertex_array = vertex_array_handle; | 248 | state.draw.vertex_array = vertex_array_handle; |
| 223 | state.draw.vertex_buffer = vertex_buffer_handle; | 249 | state.draw.vertex_buffer = vertex_buffer_handle; |
| 250 | state.draw.uniform_buffer = 0; | ||
| 224 | state.Apply(); | 251 | state.Apply(); |
| 225 | 252 | ||
| 226 | // Attach vertex data to VAO | 253 | // Attach vertex data to VAO |
| @@ -250,8 +277,6 @@ void RendererOpenGL::InitOpenGLObjects() { | |||
| 250 | 277 | ||
| 251 | state.texture_units[0].texture_2d = 0; | 278 | state.texture_units[0].texture_2d = 0; |
| 252 | state.Apply(); | 279 | state.Apply(); |
| 253 | |||
| 254 | hw_rasterizer->InitObjects(); | ||
| 255 | } | 280 | } |
| 256 | 281 | ||
| 257 | void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, | 282 | void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, |
| @@ -440,6 +465,8 @@ void RendererOpenGL::Init() { | |||
| 440 | LOG_INFO(Render_OpenGL, "GL_VENDOR: %s", glGetString(GL_VENDOR)); | 465 | LOG_INFO(Render_OpenGL, "GL_VENDOR: %s", glGetString(GL_VENDOR)); |
| 441 | LOG_INFO(Render_OpenGL, "GL_RENDERER: %s", glGetString(GL_RENDERER)); | 466 | LOG_INFO(Render_OpenGL, "GL_RENDERER: %s", glGetString(GL_RENDERER)); |
| 442 | InitOpenGLObjects(); | 467 | InitOpenGLObjects(); |
| 468 | |||
| 469 | RefreshRasterizerSetting(); | ||
| 443 | } | 470 | } |
| 444 | 471 | ||
| 445 | /// Shutdown the renderer | 472 | /// Shutdown the renderer |
diff --git a/src/video_core/swrasterizer.cpp b/src/video_core/swrasterizer.cpp new file mode 100644 index 000000000..03df15b01 --- /dev/null +++ b/src/video_core/swrasterizer.cpp | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "video_core/clipper.h" | ||
| 6 | #include "video_core/swrasterizer.h" | ||
| 7 | |||
| 8 | namespace VideoCore { | ||
| 9 | |||
| 10 | void SWRasterizer::AddTriangle(const Pica::Shader::OutputVertex& v0, | ||
| 11 | const Pica::Shader::OutputVertex& v1, | ||
| 12 | const Pica::Shader::OutputVertex& v2) { | ||
| 13 | Pica::Clipper::ProcessTriangle(v0, v1, v2); | ||
| 14 | } | ||
| 15 | |||
| 16 | } | ||
diff --git a/src/video_core/swrasterizer.h b/src/video_core/swrasterizer.h new file mode 100644 index 000000000..9a9a76d7a --- /dev/null +++ b/src/video_core/swrasterizer.h | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | // Copyright 2015 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | |||
| 9 | #include "video_core/rasterizer_interface.h" | ||
| 10 | |||
| 11 | namespace VideoCore { | ||
| 12 | |||
| 13 | class SWRasterizer : public RasterizerInterface { | ||
| 14 | void InitObjects() override {} | ||
| 15 | void Reset() override {} | ||
| 16 | void AddTriangle(const Pica::Shader::OutputVertex& v0, | ||
| 17 | const Pica::Shader::OutputVertex& v1, | ||
| 18 | const Pica::Shader::OutputVertex& v2) override; | ||
| 19 | void DrawTriangles() override {} | ||
| 20 | void FlushFramebuffer() override {} | ||
| 21 | void NotifyPicaRegisterChanged(u32 id) override {} | ||
| 22 | void FlushRegion(PAddr addr, u32 size) override {} | ||
| 23 | void InvalidateRegion(PAddr addr, u32 size) override {} | ||
| 24 | }; | ||
| 25 | |||
| 26 | } | ||
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index eaddda668..912db91a4 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp | |||
| @@ -2,7 +2,10 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <memory> | ||
| 6 | |||
| 5 | #include "common/emu_window.h" | 7 | #include "common/emu_window.h" |
| 8 | #include "common/make_unique.h" | ||
| 6 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 7 | 10 | ||
| 8 | #include "core/core.h" | 11 | #include "core/core.h" |
| @@ -18,8 +21,8 @@ | |||
| 18 | 21 | ||
| 19 | namespace VideoCore { | 22 | namespace VideoCore { |
| 20 | 23 | ||
| 21 | EmuWindow* g_emu_window = nullptr; ///< Frontend emulator window | 24 | EmuWindow* g_emu_window = nullptr; ///< Frontend emulator window |
| 22 | RendererBase* g_renderer = nullptr; ///< Renderer plugin | 25 | std::unique_ptr<RendererBase> g_renderer; ///< Renderer plugin |
| 23 | 26 | ||
| 24 | std::atomic<bool> g_hw_renderer_enabled; | 27 | std::atomic<bool> g_hw_renderer_enabled; |
| 25 | std::atomic<bool> g_shader_jit_enabled; | 28 | std::atomic<bool> g_shader_jit_enabled; |
| @@ -29,7 +32,7 @@ void Init(EmuWindow* emu_window) { | |||
| 29 | Pica::Init(); | 32 | Pica::Init(); |
| 30 | 33 | ||
| 31 | g_emu_window = emu_window; | 34 | g_emu_window = emu_window; |
| 32 | g_renderer = new RendererOpenGL(); | 35 | g_renderer = Common::make_unique<RendererOpenGL>(); |
| 33 | g_renderer->SetWindow(g_emu_window); | 36 | g_renderer->SetWindow(g_emu_window); |
| 34 | g_renderer->Init(); | 37 | g_renderer->Init(); |
| 35 | 38 | ||
| @@ -40,7 +43,7 @@ void Init(EmuWindow* emu_window) { | |||
| 40 | void Shutdown() { | 43 | void Shutdown() { |
| 41 | Pica::Shutdown(); | 44 | Pica::Shutdown(); |
| 42 | 45 | ||
| 43 | delete g_renderer; | 46 | g_renderer.reset(); |
| 44 | 47 | ||
| 45 | LOG_DEBUG(Render, "shutdown OK"); | 48 | LOG_DEBUG(Render, "shutdown OK"); |
| 46 | } | 49 | } |
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h index 2867bf03e..accb0a4eb 100644 --- a/src/video_core/video_core.h +++ b/src/video_core/video_core.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <atomic> | 7 | #include <atomic> |
| 8 | #include <memory> | ||
| 8 | 9 | ||
| 9 | class EmuWindow; | 10 | class EmuWindow; |
| 10 | class RendererBase; | 11 | class RendererBase; |
| @@ -29,8 +30,8 @@ static const int kScreenBottomHeight = 240; ///< 3DS bottom screen height | |||
| 29 | // Video core renderer | 30 | // Video core renderer |
| 30 | // --------------------- | 31 | // --------------------- |
| 31 | 32 | ||
| 32 | extern RendererBase* g_renderer; ///< Renderer plugin | 33 | extern std::unique_ptr<RendererBase> g_renderer; ///< Renderer plugin |
| 33 | extern EmuWindow* g_emu_window; ///< Emu window | 34 | extern EmuWindow* g_emu_window; ///< Emu window |
| 34 | 35 | ||
| 35 | // TODO: Wrap these in a user settings struct along with any other graphics settings (often set from qt ui) | 36 | // TODO: Wrap these in a user settings struct along with any other graphics settings (often set from qt ui) |
| 36 | extern std::atomic<bool> g_hw_renderer_enabled; | 37 | extern std::atomic<bool> g_hw_renderer_enabled; |