summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/citra/citra.cpp3
-rw-r--r--src/citra/config.cpp4
-rw-r--r--src/citra/default_ini.h5
-rw-r--r--src/citra_qt/CMakeLists.txt4
-rw-r--r--src/citra_qt/config.cpp10
-rw-r--r--src/citra_qt/debugger/callstack.cpp12
-rw-r--r--src/citra_qt/debugger/registers.cpp8
-rw-r--r--src/citra_qt/game_list.cpp18
-rw-r--r--src/citra_qt/main.cpp31
-rw-r--r--src/citra_qt/main.h1
-rw-r--r--src/citra_qt/main.ui9
-rw-r--r--src/common/file_util.cpp80
-rw-r--r--src/common/file_util.h31
-rw-r--r--src/common/logging/backend.cpp2
-rw-r--r--src/common/logging/log.h2
-rw-r--r--src/common/vector_math.h4
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/arm/arm_interface.h11
-rw-r--r--src/core/arm/dyncom/arm_dyncom_dec.cpp8
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp587
-rw-r--r--src/core/arm/dyncom/arm_dyncom_run.h4
-rw-r--r--src/core/arm/dyncom/arm_dyncom_thumb.h2
-rw-r--r--src/core/arm/skyeye_common/armstate.cpp35
-rw-r--r--src/core/arm/skyeye_common/armstate.h24
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.cpp12
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.h2
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp_helper.h32
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpdouble.cpp76
-rw-r--r--src/core/core.cpp32
-rw-r--r--src/core/core.h7
-rw-r--r--src/core/file_sys/archive_backend.h6
-rw-r--r--src/core/file_sys/disk_archive.cpp5
-rw-r--r--src/core/file_sys/disk_archive.h1
-rw-r--r--src/core/file_sys/ivfc_archive.cpp5
-rw-r--r--src/core/file_sys/ivfc_archive.h1
-rw-r--r--src/core/gdbstub/gdbstub.cpp960
-rw-r--r--src/core/gdbstub/gdbstub.h94
-rw-r--r--src/core/hle/function_wrappers.h8
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp25
-rw-r--r--src/core/hle/kernel/memory.cpp2
-rw-r--r--src/core/hle/kernel/memory.h1
-rw-r--r--src/core/hle/kernel/process.cpp6
-rw-r--r--src/core/hle/kernel/thread.cpp5
-rw-r--r--src/core/hle/kernel/timer.cpp6
-rw-r--r--src/core/hle/service/act_u.cpp7
-rw-r--r--src/core/hle/service/am/am_net.cpp30
-rw-r--r--src/core/hle/service/am/am_sys.cpp15
-rw-r--r--src/core/hle/service/am/am_u.cpp28
-rw-r--r--src/core/hle/service/apt/apt_s.cpp6
-rw-r--r--src/core/hle/service/apt/apt_u.cpp6
-rw-r--r--src/core/hle/service/boss/boss_u.cpp3
-rw-r--r--src/core/hle/service/cam/cam.h156
-rw-r--r--src/core/hle/service/cam/cam_u.cpp5
-rw-r--r--src/core/hle/service/csnd_snd.cpp65
-rw-r--r--src/core/hle/service/csnd_snd.h13
-rw-r--r--src/core/hle/service/dsp_dsp.cpp14
-rw-r--r--src/core/hle/service/frd/frd_u.cpp43
-rw-r--r--src/core/hle/service/fs/archive.cpp7
-rw-r--r--src/core/hle/service/fs/archive.h7
-rw-r--r--src/core/hle/service/fs/fs_user.cpp223
-rw-r--r--src/core/hle/service/gsp_gpu.cpp8
-rw-r--r--src/core/hle/service/gsp_lcd.cpp10
-rw-r--r--src/core/hle/service/hid/hid_user.cpp2
-rw-r--r--src/core/hle/service/http_c.cpp10
-rw-r--r--src/core/hle/service/mic_u.cpp10
-rw-r--r--src/core/hle/service/ndm_u.cpp16
-rw-r--r--src/core/hle/service/news/news_s.cpp12
-rw-r--r--src/core/hle/service/nim/nim_s.cpp3
-rw-r--r--src/core/hle/service/ns_s.cpp9
-rw-r--r--src/core/hle/service/nwm_uds.cpp18
-rw-r--r--src/core/hle/service/pm_app.cpp4
-rw-r--r--src/core/hle/service/ptm/ptm.cpp12
-rw-r--r--src/core/hle/service/ptm/ptm.h8
-rw-r--r--src/core/hle/service/ptm/ptm_sysm.cpp3
-rw-r--r--src/core/hle/service/ptm/ptm_u.cpp2
-rw-r--r--src/core/hle/service/soc_u.cpp16
-rw-r--r--src/core/hle/service/ssl_c.cpp55
-rw-r--r--src/core/hle/service/y2r_u.cpp23
-rw-r--r--src/core/hle/svc.cpp47
-rw-r--r--src/core/hle/svc.h29
-rw-r--r--src/core/hw/gpu.cpp12
-rw-r--r--src/core/loader/3dsx.cpp4
-rw-r--r--src/core/loader/loader.h1
-rw-r--r--src/core/loader/ncch.cpp8
-rw-r--r--src/core/loader/ncch.h36
-rw-r--r--src/core/memory.cpp4
-rw-r--r--src/core/settings.h5
-rw-r--r--src/core/system.cpp4
-rw-r--r--src/video_core/CMakeLists.txt8
-rw-r--r--src/video_core/clipper.cpp2
-rw-r--r--src/video_core/clipper.h2
-rw-r--r--src/video_core/command_processor.cpp27
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp12
-rw-r--r--src/video_core/pica.h4
-rw-r--r--src/video_core/primitive_assembly.cpp9
-rw-r--r--src/video_core/rasterizer.cpp21
-rw-r--r--src/video_core/rasterizer_interface.h (renamed from src/video_core/hwrasterizer_base.h)19
-rw-r--r--src/video_core/renderer_base.cpp29
-rw-r--r--src/video_core/renderer_base.h8
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp383
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h188
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h8
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp392
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h27
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.h20
-rw-r--r--src/video_core/renderer_opengl/gl_shaders.h337
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp13
-rw-r--r--src/video_core/renderer_opengl/gl_state.h3
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp55
-rw-r--r--src/video_core/swrasterizer.cpp16
-rw-r--r--src/video_core/swrasterizer.h26
-rw-r--r--src/video_core/video_core.cpp11
-rw-r--r--src/video_core/video_core.h5
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
80void Config::Reload() { 84void 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
68log_filter = *:Info 68log_filter = *:Info
69
70[Debugging]
71# Port for listening to GDB connections.
72use_gdbstub=false
73gdbstub_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()
72endif() 72endif()
73 73
74if (APPLE) 74if (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)
77else() 79else()
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
67void Config::SaveValues() { 72void 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
102void Config::Reload() { 112void 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
30void CallstackWidget::OnDebugModeEntered() 30void 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
61void RegistersWidget::OnDebugModeEntered() { 61void 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()
80void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) 80void 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
120void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, bool deep_scan) 120void 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
160void GameListWorker::run() 162void 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
242void GMainWindow::BootGame(const std::string& filename) { 249void 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
357void GMainWindow::OnGameListLoadFile(QString game_path) { 364void GMainWindow::OnGameListLoadFile(QString game_path) {
358 BootGame(game_path.toLatin1().data()); 365 BootGame(game_path.toLocal8Bit().data());
359} 366}
360 367
361void GMainWindow::OnMenuLoadFile() { 368void 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
444void GMainWindow::SetHardwareRendererEnabled(bool enabled) { 451void 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
459void GMainWindow::SetGdbstubEnabled(bool enabled) {
460 GDBStub::ToggleServer(enabled);
446} 461}
447 462
448void GMainWindow::SetShaderJITEnabled(bool enabled) { 463void 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
452void GMainWindow::ToggleWindowMode() { 471void 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
423int ScanDirectoryTreeAndCallback(const std::string &directory, std::function<int(const std::string&, const std::string&)> callback) 423bool 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
476int ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry) 485unsigned 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
504bool DeleteDirRecursively(const std::string &directory) 515bool 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);
98bool CreateEmptyFile(const std::string &filename); 98bool 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 106using 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 */
113int ScanDirectoryTreeAndCallback(const std::string &directory, std::function<int(const std::string&, const std::string&)> callback); 118bool 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 */
121int ScanDirectoryTree(const std::string &directory, FSTEntry& parent_entry); 126unsigned 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.
124bool DeleteDirRecursively(const std::string &directory); 129bool 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
36namespace Math { 37namespace 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
15class ARM_Interface : NonCopyable { 15class ARM_Interface : NonCopyable {
16public: 16public:
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
155protected: 151protected:
156 152
@@ -162,6 +158,5 @@ protected:
162 158
163private: 159private:
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
8const InstructionSetEncodingItem arm_instruction[] = { 8const 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
26Common::Profiling::TimingCategory profile_execute("DynCom::Execute"); 28Common::Profiling::TimingCategory profile_execute("DynCom::Execute");
27Common::Profiling::TimingCategory profile_decode("DynCom::Decode"); 29Common::Profiling::TimingCategory profile_decode("DynCom::Decode");
28 30
@@ -49,7 +51,7 @@ enum {
49 51
50typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper); 52typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper);
51 53
52static bool CondPassed(ARMul_State* cpu, unsigned int cond) { 54static 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}
1629static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index) 1628static 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}
1652static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index) 1648static 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}
1709static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index) 1702static 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}
1726static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index) 1716static 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}
1743static ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index) 1730static 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}
2603static ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb)(unsigned int inst, int index) 2587static 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}
2651static ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index) 2632static 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}
2675static ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){ 2653static 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}
2691static ARM_INST_PTR INTERPRETER_TRANSLATE(strex)(unsigned int inst, int index) 2666static 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}
2735static ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index) 2707static 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}
2763static ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index) 2732static 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}
2814static ARM_INST_PTR INTERPRETER_TRANSLATE(swpb)(unsigned int inst, int index){ 2780static 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}
2831static ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab)(unsigned int inst, int index){ 2794static 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
3551translated: 3511translated:
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 */
33static inline u32 CHECK_READ_REG15_WA(ARMul_State* cpu, int Rn) { 33inline 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 */
46static inline u32 CHECK_READ_REG15(ARMul_State* cpu, int Rn) { 46inline 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.
39ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size); 39ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size);
40 40
41static inline u32 GetThumbInstruction(u32 instr, u32 address) { 41inline 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
11ARMul_State::ARMul_State(PrivilegeMode initial_mode) 12ARMul_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
189static 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
197u8 ARMul_State::ReadMemory8(u32 address) const
198{
199 CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
200
201 return Memory::Read8(address);
202}
203
188u16 ARMul_State::ReadMemory16(u32 address) const 204u16 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
198u32 ARMul_State::ReadMemory32(u32 address) const 216u32 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
208u64 ARMul_State::ReadMemory64(u32 address) const 228u64 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
240void ARMul_State::WriteMemory8(u32 address, u8 data)
241{
242 CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write);
243
244 Memory::Write8(address, data);
245}
246
218void ARMul_State::WriteMemory16(u32 address, u16 data) 247void 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
226void ARMul_State::WriteMemory32(u32 address, u32 data) 257void 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
234void ARMul_State::WriteMemory64(u32 address, u64 data) 267void 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 */
114s32 vfp_get_float(ARMul_State* state, unsigned int reg) 114s32 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
120void vfp_put_float(ARMul_State* state, s32 val, unsigned int reg) 120void 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
126u64 vfp_get_double(ARMul_State* state, unsigned int reg) 126u64 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
133void vfp_put_double(ARMul_State* state, u64 val, unsigned int reg) 133void 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 */
143void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpscr) 143void 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
88static inline u32 vfp_shiftright32jamming(u32 val, unsigned int shift) 88inline 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
99static inline u64 vfp_shiftright64jamming(u64 val, unsigned int shift) 99inline 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
110static inline u32 vfp_hi64to32jamming(u64 val) 110inline 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
124static inline void add128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) 124inline 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
132static inline void sub128(u64* resh, u64* resl, u64 nh, u64 nl, u64 mh, u64 ml) 132inline 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
140static inline void mul64to128(u64* resh, u64* resl, u64 n, u64 m) 140inline 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
167static inline void shift64left(u64* resh, u64* resl, u64 n) 167inline 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
173static inline u64 vfp_hi64multiply64(u64 n, u64 m) 173inline 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
180static inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m) 180inline 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
252static inline int vfp_single_type(vfp_single* s) 252inline 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.
274static inline void vfp_single_unpack(vfp_single* s, s32 val, u32* fpscr) 274inline 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.
296static inline s32 vfp_single_pack(vfp_single* s) 296inline 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
338static inline int vfp_double_type(vfp_double* s) 338inline 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.
360static inline void vfp_double_unpack(vfp_double* s, s64 val, u32* fpscr) 360inline 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.
382static inline s64 vfp_double_pack(vfp_double* s) 382inline 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
418static inline u32 fls(u32 x) 418inline 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
66static void vfp_double_dump(const char *str, struct vfp_double *d) 66static 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 */
268static u32 vfp_double_fabs(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) 268static 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
275static u32 vfp_double_fcpy(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) 275static 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
282static u32 vfp_double_fneg(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) 282static 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
289static u32 vfp_double_fsqrt(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) 289static 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
446static u32 vfp_double_fcmp(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) 446static 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
452static u32 vfp_double_fcmpe(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) 452static 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
458static u32 vfp_double_fcmpz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) 458static 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
464static u32 vfp_double_fcmpez(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) 464static 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
615static u32 vfp_double_ftouiz(ARMul_State* state, int sd, int unused, int dm, u32 fpscr) 615static 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
692static u32 vfp_double_ftosiz(ARMul_State* state, int dd, int unused, int dm, u32 fpscr) 692static 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 */
928static u32 vfp_double_fmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) 928static 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 */
937static u32 vfp_double_fnmac(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) 937static 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 */
946static u32 vfp_double_fmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) 946static 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 */
955static u32 vfp_double_fnmsc(ARMul_State* state, int dd, int dn, int dm, u32 fpscr) 955static 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
16namespace Core { 21namespace Core {
17 22
18ARM_Interface* g_app_core = nullptr; ///< ARM11 application core 23std::unique_ptr<ARM_Interface> g_app_core; ///< ARM11 application core
19ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core 24std::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
22void RunLoop(int tight_loop) { 27void 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
56int Init() { 76int 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
64void Shutdown() { 84void 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
9class ARM_Interface; 10class 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
26extern ARM_Interface* g_app_core; ///< ARM11 application core 27extern std::unique_ptr<ARM_Interface> g_app_core; ///< ARM11 application core
27extern ARM_Interface* g_sys_core; ///< ARM11 system (OS) core 28extern 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
136class ArchiveFactory : NonCopyable { 142class 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
77u64 DiskArchive::GetFreeBytes() const {
78 // TODO: Stubbed to return 1GiB
79 return 1024 * 1024 * 1024;
80}
81
77//////////////////////////////////////////////////////////////////////////////////////////////////// 82////////////////////////////////////////////////////////////////////////////////////////////////////
78 83
79DiskFile::DiskFile(const DiskArchive& archive, const Path& path, const Mode mode) { 84DiskFile::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
45protected: 46protected:
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
62u64 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
64size_t IVFCFile::Read(const u64 offset, const size_t length, u8* buffer) const { 69size_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
46protected: 47protected:
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
39const int GDB_BUFFER_SIZE = 10000;
40
41const char GDB_STUB_START = '$';
42const char GDB_STUB_END = '#';
43const char GDB_STUB_ACK = '+';
44const char GDB_STUB_NACK = '-';
45
46#ifndef SIGTRAP
47const u32 SIGTRAP = 5;
48#endif
49
50#ifndef SIGTERM
51const u32 SIGTERM = 15;
52#endif
53
54#ifndef MSG_WAITALL
55const u32 MSG_WAITALL = 8;
56#endif
57
58const u32 R0_REGISTER = 0;
59const u32 R15_REGISTER = 15;
60const u32 CPSR_REGISTER = 25;
61const u32 FPSCR_REGISTER = 58;
62
63namespace GDBStub {
64
65static int gdbserver_socket = -1;
66
67static u8 command_buffer[GDB_BUFFER_SIZE];
68static u32 command_length;
69
70static u32 latest_signal = 0;
71static bool step_break = false;
72static 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.
76static u16 gdbstub_port = 24689;
77
78static bool halt_loop = true;
79static bool step_loop = false;
80std::atomic<bool> g_server_enabled(false);
81
82#ifdef _WIN32
83WSADATA InitData;
84#endif
85
86struct Breakpoint {
87 bool active;
88 PAddr addr;
89 u32 len;
90};
91
92static std::map<u32, Breakpoint> breakpoints_execute;
93static std::map<u32, Breakpoint> breakpoints_read;
94static 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 */
101static 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 */
119static 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*/
135static 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 */
151static 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 */
166static 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 */
178static 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 */
190static 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.
202static 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.
214static 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 */
223static 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 */
242static 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
252BreakpointAddress 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
268bool 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 */
305static 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 */
317static 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.
353static 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.
364static 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 */
380void 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.
393static 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.
439static 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.
462static 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.
489static 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.
521static 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.
547static 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.
575static 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.
602static 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
620void 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.
630static void Step() {
631 step_loop = true;
632 halt_loop = true;
633 step_break = true;
634 SendSignal(SIGTRAP);
635}
636
637bool IsMemoryBreak() {
638 if (IsConnected()) {
639 return false;
640 }
641
642 return memory_break;
643}
644
645/// Tell the CPU to continue executing.
646static 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 */
660bool 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.
675static 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.
723static 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
764void 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
831void SetServerPort(u16 port) {
832 gdbstub_port = port;
833}
834
835void 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
854void 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
922void Init() {
923 Init(gdbstub_port);
924}
925
926void 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
944bool IsConnected() {
945 return g_server_enabled && gdbserver_socket != -1;
946}
947
948bool GetCpuHaltFlag() {
949 return halt_loop;
950}
951
952bool GetCpuStepFlag() {
953 return step_loop;
954}
955
956void 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
10namespace GDBStub {
11
12/// Breakpoint Method
13enum 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
21struct 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.
27extern 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 */
34void 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 */
41void ToggleServer(bool status);
42
43/// Start the gdbstub server.
44void Init();
45
46/// Stop gdbstub server.
47void Shutdown();
48
49/// Returns true if there is an active socket connection.
50bool 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 */
57void Break(bool is_memory_break = false);
58
59/// Determine if there was a memory breakpoint.
60bool IsMemoryBreak();
61
62/// Read and handle packet from gdb client.
63void 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 */
71BreakpointAddress 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 */
79bool CheckBreakpoint(u32 addr, GDBStub::BreakpointType type);
80
81// If set to true, the CPU will halt at the beginning of the next CPU loop.
82bool GetCpuHaltFlag();
83
84// If set to true and the CPU is halted, the CPU will step one instruction.
85bool 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 */
92void 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
162template<ResultCode func(s64*, u32, s32)> void Wrap() {
163 s64 param_1 = 0;
164 u32 retval = func(&param_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
162template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() { 170template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() {
163 u32 param_1 = 0; 171 u32 param_1 = 0;
164 u32 retval = func(&param_1, PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw; 172 u32 retval = func(&param_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;
17struct MemoryRegionInfo { 17struct 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
43void Timer::Acquire() { 43void 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
47void Timer::Set(s64 initial, s64 interval) { 50void 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
11namespace ACT_U { 11namespace ACT_U {
12 12
13// Empty arrays are illegal -- commented out until an entry is added. 13const 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
19Interface::Interface() { 20Interface::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 {
10namespace AM { 10namespace AM {
11 11
12const Interface::FunctionInfo FunctionTable[] = { 12const 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 {
12const Interface::FunctionInfo FunctionTable[] = { 12const 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
17AM_SYS_Interface::AM_SYS_Interface() { 32AM_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 {
12const Interface::FunctionInfo FunctionTable[] = { 12const 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
17AM_U_Interface::AM_U_Interface() { 45AM_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
96APT_S_Interface::APT_S_Interface() { 102APT_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
97APT_U_Interface::APT_U_Interface() { 103APT_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
12const Interface::FunctionInfo FunctionTable[] = { 12const 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
16BOSS_U_Interface::BOSS_U_Interface() { 19BOSS_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 @@
10namespace Service { 10namespace Service {
11namespace CAM { 11namespace CAM {
12 12
13enum class Port : u8 {
14 None = 0,
15 Cam1 = 1,
16 Cam2 = 2,
17 Both = Cam1 | Cam2
18};
19
20enum 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
31enum class Effect : u8 {
32 None = 0,
33 Mono = 1,
34 Sepia = 2,
35 Negative = 3,
36 Negafilm = 4,
37 Sepia01 = 5
38};
39
40enum class Context : u8 {
41 None = 0,
42 A = 1,
43 B = 2,
44 Both = A | B
45};
46
47enum class Flip : u8 {
48 None = 0,
49 Horizontal = 1,
50 Vertical = 2,
51 Reverse = 3
52};
53
54enum 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
66enum 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
82enum class ShutterSoundType : u8 {
83 Normal = 0,
84 Movie = 1,
85 MovieEnd = 2
86};
87
88enum 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
105enum class PhotoMode : u8 {
106 Normal = 0,
107 Portrait = 1,
108 Landscape = 2,
109 Nightview = 3,
110 Letter0 = 4
111};
112
113enum class LensCorrection : u8 {
114 Off = 0,
115 On70 = 1,
116 On90 = 2,
117 Dark = Off,
118 Normal = On70,
119 Bright = On90
120};
121
122enum 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
139enum class OutputFormat : u8 {
140 YUV422 = 0,
141 RGB565 = 1
142};
143
144struct 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
167static_assert(sizeof(PackageParameterCameraSelect) == 28, "PackageParameterCameraSelect structure size is wrong");
168
13/// Initialize CAM service(s) 169/// Initialize CAM service(s)
14void Init(); 170void 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 @@
11namespace CSND_SND { 14namespace CSND_SND {
12 15
13const Interface::FunctionInfo FunctionTable[] = { 16const 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
38static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory = nullptr;
39static Kernel::SharedPtr<Kernel::Mutex> mutex = nullptr;
40
41void 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
56void 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
74void AcquireSoundChannels(Service::Interface* self) {
75 u32* cmd_buff = Kernel::GetCommandBuffer();
76 cmd_buff[1] = 0;
77 cmd_buff[2] = 0xFFFFFF00;
78}
79
80void 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
23struct Type0Command {
24 // command id and next command offset
25 u32 command_id;
26 u32 finished;
27 u32 flags;
28 u8 parameters[20];
29};
30
31void Initialize(Service::Interface* self);
32void ExecuteType0Commands(Service::Interface* self);
33void AcquireSoundChannels(Service::Interface* self);
34void 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 */
159static void WriteReg0x10(Service::Interface* self) { 159static 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
12const Interface::FunctionInfo FunctionTable[] = { 12const 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
35FRD_U_Interface::FRD_U_Interface() { 68FRD_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
406ResultVal<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
406ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) { 413ResultCode 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 */
174ResultVal<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 */
510static 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
683const Interface::FunctionInfo FunctionTable[] = { 710const 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
12namespace GSP_LCD { 12namespace GSP_LCD {
13 13
14/*const Interface::FunctionInfo FunctionTable[] = { 14const 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
20Interface::Interface() { 24Interface::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
12const Interface::FunctionInfo FunctionTable[] = { 12const 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
12const Interface::FunctionInfo FunctionTable[] = { 12const 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
16NEWS_S_Interface::NEWS_S_Interface() { 28NEWS_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
12const Interface::FunctionInfo FunctionTable[] = { 12const 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
16NIM_S_Interface::NIM_S_Interface() { 19NIM_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 @@
12namespace NS_S { 12namespace NS_S {
13 13
14const Interface::FunctionInfo FunctionTable[] = { 14const 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
108const Interface::FunctionInfo FunctionTable[] = { 108const 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
71void 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
71void IsLegacyPowerOff(Service::Interface* self) { 83void 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);
72void GetBatteryChargeState(Interface* self); 72void 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 */
80void 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
45PTM_Sysm_Interface::PTM_Sysm_Interface() { 46PTM_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
11namespace SSL_C { 13namespace SSL_C {
12 14
15// TODO: Implement a proper CSPRNG in the future when actual security is needed
16static std::mt19937 rand_gen;
17
18static 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
29static 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
13const Interface::FunctionInfo FunctionTable[] = { 62const 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
376const Interface::FunctionInfo FunctionTable[] = { 376const 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
781static 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
781static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) { 826static 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
42namespace SVC { 42namespace SVC {
43 43
44/// Values accepted by svcGetSystemInfo's type parameter.
45enum 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 */
66enum class SystemInfoMemUsageRegion {
67 ALL = 0,
68 APPLICATION = 1,
69 SYSTEM = 2,
70 BASE = 3,
71};
72
44void CallSVC(u32 immediate); 73void 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
76static inline u32 MakeMagic(char a, char b, char c, char d) { 77static 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
18struct NCCH_Header { 18struct 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
111struct ExHeader_ARM11_SystemLocalCaps { 111struct 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 */
34struct PageTable { 34struct 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
10namespace Settings { 11namespace 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
15namespace System { 17namespace System {
16 18
17void Init(EmuWindow* emu_window) { 19void 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
27void Shutdown() { 30void 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 @@
1set(SRCS 1set(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
81void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) { 81void 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
15using Shader::OutputVertex; 15using Shader::OutputVertex;
16 16
17void ProcessTriangle(OutputVertex& v0, OutputVertex& v1, OutputVertex& v2); 17void 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
15class HWRasterizer { 15namespace VideoCore {
16
17class RasterizerInterface {
16public: 18public:
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
16void 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
13class EmuWindow; 13class 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
59protected: 61protected:
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
65private:
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
38RasterizerOpenGL::~RasterizerOpenGL() { } 40RasterizerOpenGL::~RasterizerOpenGL() { }
39 41
40void RasterizerOpenGL::InitObjects() { 42void 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
152void RasterizerOpenGL::Reset() { 127void 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
212void RasterizerOpenGL::AddTriangle(const Pica::Shader::OutputVertex& v0, 141void 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
244void RasterizerOpenGL::CommitFramebuffer() { 183void RasterizerOpenGL::FlushFramebuffer() {
245 CommitColorBuffer(); 184 CommitColorBuffer();
246 CommitDepthBuffer(); 185 CommitDepthBuffer();
247} 186}
@@ -249,9 +188,6 @@ void RasterizerOpenGL::CommitFramebuffer() {
249void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { 188void 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
407void RasterizerOpenGL::NotifyPreRead(PAddr addr, u32 size) { 284void 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
429void RasterizerOpenGL::NotifyFlush(PAddr addr, u32 size) { 303void 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
454void RasterizerOpenGL::SamplerInfo::Create() { 325void RasterizerOpenGL::SamplerInfo::Create() {
@@ -592,6 +463,47 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::
592 state.Apply(); 463 state.Apply();
593} 464}
594 465
466void 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
595void RasterizerOpenGL::SyncFramebuffer() { 507void 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
713void RasterizerOpenGL::SyncAlphaTest() { 625void 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
720void RasterizerOpenGL::SyncLogicOp() { 633void 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
747void 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
759void 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
771void 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
775void 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
780void 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
784void RasterizerOpenGL::SyncCombinerColor() { 660void 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
789void RasterizerOpenGL::SyncCombinerWriteFlags() { 668void 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
16class 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 */
30struct 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
94namespace std {
95
96template <>
97struct hash<PicaShaderConfig> {
98 size_t operator()(const PicaShaderConfig& k) const {
99 return Common::ComputeHash64(&k, sizeof(PicaShaderConfig));
100 }
101};
102
103} // namespace std
104
105class RasterizerOpenGL : public VideoCore::RasterizerInterface {
17public: 106public:
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
48private: 128private:
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
17RasterizerCacheOpenGL::~RasterizerCacheOpenGL() { 17RasterizerCacheOpenGL::~RasterizerCacheOpenGL() {
18 FullFlush(); 18 InvalidateAll();
19} 19}
20 20
21MICROPROFILE_DEFINE(OpenGL_TextureUpload, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192)); 21MICROPROFILE_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
61void RasterizerCacheOpenGL::NotifyFlush(PAddr addr, u32 size, bool ignore_hash) { 61void 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
80void RasterizerCacheOpenGL::FullFlush() { 79void 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
32private: 32private:
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
9using Pica::Regs;
10using TevStageConfig = Regs::TevStageConfig;
11
12namespace GLShader {
13
14/// Detects if a TEV stage is configured to be skipped (to avoid generating unnecessary code)
15static 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)
27static 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
68static 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
125static 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
173static 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
212static 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
250static 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
280static 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
323std::string GenerateFragmentShader(const PicaShaderConfig& config) {
324 std::string out = R"(
325#version 330 core
326#define NUM_TEV_STAGES 6
327
328in vec4 primary_color;
329in vec2 texcoord[3];
330
331out vec4 color;
332
333layout (std140) uniform shader_data {
334 vec4 const_color[NUM_TEV_STAGES];
335 vec4 tev_combiner_buffer_color;
336 int alphatest_ref;
337};
338
339uniform sampler2D tex[3];
340
341void 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
368std::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"(
377out vec4 primary_color;
378out vec2 texcoord[3];
379
380void 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
11namespace 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 */
17std::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 */
25std::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
11namespace ShaderUtil { 11namespace GLShader {
12 12
13GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { 13GLuint 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
9namespace ShaderUtil { 9namespace GLShader {
10 10
11GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path); 11enum 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 */
25GLuint 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
7namespace GLShaders {
8
9const char g_vertex_shader[] = R"(
10#version 150 core
11
12in vec2 vert_position;
13in vec2 vert_tex_coord;
14out 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]
21uniform mat3x2 modelview_matrix;
22
23void 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
32const char g_fragment_shader[] = R"(
33#version 150 core
34
35in vec2 frag_tex_coord;
36out vec4 color;
37
38uniform sampler2D color_texture;
39
40void main() {
41 color = texture(color_texture, frag_tex_coord);
42}
43)";
44
45const char g_vertex_shader_hw[] = R"(
46#version 150 core
47
48#define NUM_VTX_ATTR 7
49
50in vec4 vert_position;
51in vec4 vert_color;
52in vec2 vert_texcoords[3];
53
54out vec4 o[NUM_VTX_ATTR];
55
56void 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
66const 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
121in vec4 o[NUM_VTX_ATTR];
122out vec4 color;
123
124uniform bool alphatest_enabled;
125uniform int alphatest_func;
126uniform float alphatest_ref;
127
128uniform sampler2D tex[3];
129
130uniform vec4 tev_combiner_buffer_color;
131
132struct 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
145uniform TEVConfig tev_cfgs[NUM_TEV_STAGES];
146
147vec4 g_combiner_buffer;
148vec4 g_last_tex_env_out;
149vec4 g_const_color;
150
151vec4 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
180vec3 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
206float 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
228vec3 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
250float 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
272void 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
219void OpenGLState::ResetVertexArray(GLuint id) { 232void 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
26static const char vertex_shader[] = R"(
27#version 150 core
28
29in vec2 vert_position;
30in vec2 vert_tex_coord;
31out 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]
38uniform mat3x2 modelview_matrix;
39
40void 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
49static const char fragment_shader[] = R"(
50#version 150 core
51
52in vec2 frag_tex_coord;
53out vec4 color;
54
55uniform sampler2D color_texture;
56
57void 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
60RendererOpenGL::RendererOpenGL() { 95RendererOpenGL::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
257void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, 282void 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
8namespace VideoCore {
9
10void 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
11namespace VideoCore {
12
13class 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
19namespace VideoCore { 22namespace VideoCore {
20 23
21EmuWindow* g_emu_window = nullptr; ///< Frontend emulator window 24EmuWindow* g_emu_window = nullptr; ///< Frontend emulator window
22RendererBase* g_renderer = nullptr; ///< Renderer plugin 25std::unique_ptr<RendererBase> g_renderer; ///< Renderer plugin
23 26
24std::atomic<bool> g_hw_renderer_enabled; 27std::atomic<bool> g_hw_renderer_enabled;
25std::atomic<bool> g_shader_jit_enabled; 28std::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) {
40void Shutdown() { 43void 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
9class EmuWindow; 10class EmuWindow;
10class RendererBase; 11class 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
32extern RendererBase* g_renderer; ///< Renderer plugin 33extern std::unique_ptr<RendererBase> g_renderer; ///< Renderer plugin
33extern EmuWindow* g_emu_window; ///< Emu window 34extern 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)
36extern std::atomic<bool> g_hw_renderer_enabled; 37extern std::atomic<bool> g_hw_renderer_enabled;