summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/assets/citra.icobin509287 -> 0 bytes
-rw-r--r--src/citra/citra.rc18
-rw-r--r--src/citra/config.cpp1
-rw-r--r--src/citra/resource.hbin898 -> 431 bytes
-rw-r--r--src/citra_qt/CMakeLists.txt14
-rw-r--r--src/citra_qt/bootmanager.cpp2
-rw-r--r--src/citra_qt/bootmanager.h2
-rw-r--r--src/citra_qt/citra-qt.rcbin566 -> 275 bytes
-rw-r--r--src/citra_qt/config.cpp2
-rw-r--r--src/citra_qt/debugger/callstack.cpp2
-rw-r--r--src/citra_qt/debugger/callstack.ui3
-rw-r--r--src/citra_qt/debugger/graphics_cmdlists.cpp4
-rw-r--r--src/citra_qt/debugger/graphics_framebuffer.cpp3
-rw-r--r--src/citra_qt/main.cpp2
-rw-r--r--src/citra_qt/main.ui17
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/color.h (renamed from src/video_core/color.h)3
-rw-r--r--src/common/emu_window.cpp2
-rw-r--r--src/common/file_util.cpp2
-rw-r--r--src/common/logging/backend.cpp1
-rw-r--r--src/common/logging/log.h5
-rw-r--r--src/common/math_util.h2
-rw-r--r--src/common/swap.h2
-rw-r--r--src/common/vector_math.h (renamed from src/video_core/math.h)2
-rw-r--r--src/core/CMakeLists.txt83
-rw-r--r--src/core/arm/disassembler/arm_disasm.cpp2
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp2
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp39
-rw-r--r--src/core/arm/dyncom/arm_dyncom_thumb.cpp102
-rw-r--r--src/core/arm/interpreter/arminit.cpp1
-rw-r--r--src/core/arm/interpreter/armsupp.cpp2
-rw-r--r--src/core/arm/skyeye_common/arm_regformat.h2
-rw-r--r--src/core/arm/skyeye_common/armdefs.h34
-rw-r--r--src/core/arm/skyeye_common/armemu.h47
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.cpp4
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.h1
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp_helper.h4
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpinstr.cpp18
-rw-r--r--src/core/core_timing.cpp2
-rw-r--r--src/core/core_timing.h2
-rw-r--r--src/core/file_sys/archive_extsavedata.cpp13
-rw-r--r--src/core/file_sys/archive_extsavedata.h4
-rw-r--r--src/core/file_sys/archive_savedata.cpp2
-rw-r--r--src/core/hle/function_wrappers.h17
-rw-r--r--src/core/hle/kernel/event.cpp3
-rw-r--r--src/core/hle/kernel/kernel.cpp22
-rw-r--r--src/core/hle/kernel/kernel.h6
-rw-r--r--src/core/hle/kernel/mutex.cpp9
-rw-r--r--src/core/hle/kernel/resource_limit.h8
-rw-r--r--src/core/hle/kernel/semaphore.cpp10
-rw-r--r--src/core/hle/kernel/thread.cpp84
-rw-r--r--src/core/hle/kernel/thread.h14
-rw-r--r--src/core/hle/kernel/timer.cpp2
-rw-r--r--src/core/hle/kernel/vm_manager.cpp245
-rw-r--r--src/core/hle/kernel/vm_manager.h200
-rw-r--r--src/core/hle/service/am/am.cpp55
-rw-r--r--src/core/hle/service/am/am.h47
-rw-r--r--src/core/hle/service/am/am_app.cpp20
-rw-r--r--src/core/hle/service/am/am_app.h22
-rw-r--r--src/core/hle/service/am/am_net.cpp (renamed from src/core/hle/service/am_net.cpp)17
-rw-r--r--src/core/hle/service/am/am_net.h22
-rw-r--r--src/core/hle/service/am/am_sys.cpp22
-rw-r--r--src/core/hle/service/am/am_sys.h22
-rw-r--r--src/core/hle/service/am/am_u.cpp22
-rw-r--r--src/core/hle/service/am/am_u.h22
-rw-r--r--src/core/hle/service/am_app.cpp23
-rw-r--r--src/core/hle/service/am_app.h23
-rw-r--r--src/core/hle/service/am_net.h23
-rw-r--r--src/core/hle/service/am_sys.cpp62
-rw-r--r--src/core/hle/service/am_sys.h23
-rw-r--r--src/core/hle/service/apt/apt.cpp4
-rw-r--r--src/core/hle/service/apt/apt.h8
-rw-r--r--src/core/hle/service/boss/boss.cpp29
-rw-r--r--src/core/hle/service/boss/boss.h20
-rw-r--r--src/core/hle/service/boss/boss_p.cpp20
-rw-r--r--src/core/hle/service/boss/boss_p.h22
-rw-r--r--src/core/hle/service/boss/boss_u.cpp21
-rw-r--r--src/core/hle/service/boss/boss_u.h22
-rw-r--r--src/core/hle/service/boss_p.cpp23
-rw-r--r--src/core/hle/service/boss_p.h23
-rw-r--r--src/core/hle/service/boss_u.cpp24
-rw-r--r--src/core/hle/service/boss_u.h23
-rw-r--r--src/core/hle/service/cam/cam.cpp35
-rw-r--r--src/core/hle/service/cam/cam.h20
-rw-r--r--src/core/hle/service/cam/cam_c.cpp20
-rw-r--r--src/core/hle/service/cam/cam_c.h22
-rw-r--r--src/core/hle/service/cam/cam_q.cpp20
-rw-r--r--src/core/hle/service/cam/cam_q.h22
-rw-r--r--src/core/hle/service/cam/cam_s.cpp20
-rw-r--r--src/core/hle/service/cam/cam_s.h22
-rw-r--r--src/core/hle/service/cam/cam_u.cpp20
-rw-r--r--src/core/hle/service/cam/cam_u.h22
-rw-r--r--src/core/hle/service/cam_u.cpp23
-rw-r--r--src/core/hle/service/cam_u.h23
-rw-r--r--src/core/hle/service/cecd/cecd.cpp31
-rw-r--r--src/core/hle/service/cecd/cecd.h20
-rw-r--r--src/core/hle/service/cecd/cecd_s.cpp20
-rw-r--r--src/core/hle/service/cecd/cecd_s.h (renamed from src/core/hle/service/cecd_s.h)13
-rw-r--r--src/core/hle/service/cecd/cecd_u.cpp20
-rw-r--r--src/core/hle/service/cecd/cecd_u.h (renamed from src/core/hle/service/cecd_u.h)13
-rw-r--r--src/core/hle/service/cecd_s.cpp23
-rw-r--r--src/core/hle/service/cecd_u.cpp23
-rw-r--r--src/core/hle/service/cfg/cfg.cpp4
-rw-r--r--src/core/hle/service/frd/frd.cpp29
-rw-r--r--src/core/hle/service/frd/frd.h20
-rw-r--r--src/core/hle/service/frd/frd_a.cpp20
-rw-r--r--src/core/hle/service/frd/frd_a.h (renamed from src/core/hle/service/frd_a.h)13
-rw-r--r--src/core/hle/service/frd/frd_u.cpp (renamed from src/core/hle/service/frd_u.cpp)17
-rw-r--r--src/core/hle/service/frd/frd_u.h (renamed from src/core/hle/service/frd_u.h)13
-rw-r--r--src/core/hle/service/frd_a.cpp23
-rw-r--r--src/core/hle/service/fs/archive.cpp29
-rw-r--r--src/core/hle/service/fs/archive.h4
-rw-r--r--src/core/hle/service/fs/fs_user.cpp20
-rw-r--r--src/core/hle/service/gsp_gpu.cpp68
-rw-r--r--src/core/hle/service/hid/hid.cpp6
-rw-r--r--src/core/hle/service/hid/hid_spvr.cpp2
-rw-r--r--src/core/hle/service/hid/hid_user.h2
-rw-r--r--src/core/hle/service/news/news.cpp31
-rw-r--r--src/core/hle/service/news/news.h20
-rw-r--r--src/core/hle/service/news/news_s.cpp21
-rw-r--r--src/core/hle/service/news/news_s.h (renamed from src/core/hle/service/news_s.h)13
-rw-r--r--src/core/hle/service/news/news_u.cpp21
-rw-r--r--src/core/hle/service/news/news_u.h (renamed from src/core/hle/service/news_u.h)13
-rw-r--r--src/core/hle/service/news_s.cpp24
-rw-r--r--src/core/hle/service/news_u.cpp24
-rw-r--r--src/core/hle/service/nim/nim.cpp42
-rw-r--r--src/core/hle/service/nim/nim.h30
-rw-r--r--src/core/hle/service/nim/nim_aoc.cpp (renamed from src/core/hle/service/nim_aoc.cpp)16
-rw-r--r--src/core/hle/service/nim/nim_aoc.h22
-rw-r--r--src/core/hle/service/nim/nim_s.cpp22
-rw-r--r--src/core/hle/service/nim/nim_s.h22
-rw-r--r--src/core/hle/service/nim/nim_u.cpp27
-rw-r--r--src/core/hle/service/nim/nim_u.h22
-rw-r--r--src/core/hle/service/nim_aoc.h23
-rw-r--r--src/core/hle/service/nim_u.cpp48
-rw-r--r--src/core/hle/service/nim_u.h23
-rw-r--r--src/core/hle/service/ptm/ptm.h6
-rw-r--r--src/core/hle/service/ptm/ptm_play.cpp2
-rw-r--r--src/core/hle/service/service.cpp60
-rw-r--r--src/core/hle/service/soc_u.cpp30
-rw-r--r--src/core/hle/svc.cpp32
-rw-r--r--src/core/hw/gpu.cpp17
-rw-r--r--src/core/hw/hw.cpp2
-rw-r--r--src/core/hw/lcd.cpp2
-rw-r--r--src/core/hw/lcd.h2
-rw-r--r--src/core/loader/3dsx.cpp2
-rw-r--r--src/core/mem_map.cpp55
-rw-r--r--src/core/mem_map.h8
-rw-r--r--src/core/memory.cpp12
-rw-r--r--src/core/memory.h2
-rw-r--r--src/core/memory_setup.h7
-rw-r--r--src/core/settings.h1
-rw-r--r--src/video_core/CMakeLists.txt2
-rw-r--r--src/video_core/command_processor.cpp78
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp6
-rw-r--r--src/video_core/debug_utils/debug_utils.h3
-rw-r--r--src/video_core/pica.h93
-rw-r--r--src/video_core/rasterizer.cpp80
-rw-r--r--src/video_core/renderer_opengl/generated/gl_3_2_core.c16
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp169
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h3
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp2
-rw-r--r--src/video_core/renderer_opengl/gl_shaders.h24
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp49
-rw-r--r--src/video_core/renderer_opengl/gl_state.h11
-rw-r--r--src/video_core/renderer_opengl/pica_to_gl.h31
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp10
-rw-r--r--src/video_core/vertex_shader.cpp33
168 files changed, 2544 insertions, 1211 deletions
diff --git a/src/assets/citra.ico b/src/assets/citra.ico
deleted file mode 100644
index 4fef651e2..000000000
--- a/src/assets/citra.ico
+++ /dev/null
Binary files differ
diff --git a/src/citra/citra.rc b/src/citra/citra.rc
index 0165e93da..b0edb2e6b 100644
--- a/src/citra/citra.rc
+++ b/src/citra/citra.rc
@@ -1,9 +1,9 @@
1///////////////////////////////////////////////////////////////////////////// 1/////////////////////////////////////////////////////////////////////////////
2// 2//
3// Icon 3// Icon
4// 4//
5 5
6// Icon with lowest ID value placed first to ensure application icon 6// Icon with lowest ID value placed first to ensure application icon
7// remains consistent on all systems. 7// remains consistent on all systems.
8GLFW_ICON ICON "..\\assets\\citra.ico" 8GLFW_ICON ICON "..\\..\\dist\\citra.ico"
9 9
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index 846479fd7..1378567c1 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -66,7 +66,6 @@ void Config::ReadValues() {
66 Settings::values.pad_cright_key = glfw_config->GetInteger("Controls", "pad_cright", GLFW_KEY_L); 66 Settings::values.pad_cright_key = glfw_config->GetInteger("Controls", "pad_cright", GLFW_KEY_L);
67 67
68 // Core 68 // Core
69 Settings::values.gpu_refresh_rate = glfw_config->GetInteger("Core", "gpu_refresh_rate", 30);
70 Settings::values.frame_skip = glfw_config->GetInteger("Core", "frame_skip", 0); 69 Settings::values.frame_skip = glfw_config->GetInteger("Core", "frame_skip", 0);
71 70
72 // Renderer 71 // Renderer
diff --git a/src/citra/resource.h b/src/citra/resource.h
index 0d42c8a8a..127896424 100644
--- a/src/citra/resource.h
+++ b/src/citra/resource.h
Binary files differ
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index efccdbec6..c2d1ad240 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -89,15 +89,15 @@ if (Qt5_FOUND AND MSVC)
89 ) 89 )
90 set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/") 90 set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
91 set(PLATFORMS ${DLL_DEST}platforms/) 91 set(PLATFORMS ${DLL_DEST}platforms/)
92 92
93 # windows commandline expects the / to be \ so switch them 93 # windows commandline expects the / to be \ so switch them
94 string(REPLACE "/" "\\" Qt5_DLL_DIR ${Qt5_DLL_DIR}) 94 string(REPLACE "/" "\\\\" Qt5_DLL_DIR ${Qt5_DLL_DIR})
95 string(REPLACE "/" "\\" Qt5_PLATFORMS_DIR ${Qt5_PLATFORMS_DIR}) 95 string(REPLACE "/" "\\\\" Qt5_PLATFORMS_DIR ${Qt5_PLATFORMS_DIR})
96 string(REPLACE "/" "\\" DLL_DEST ${DLL_DEST}) 96 string(REPLACE "/" "\\\\" DLL_DEST ${DLL_DEST})
97 string(REPLACE "/" "\\" PLATFORMS ${PLATFORMS}) 97 string(REPLACE "/" "\\\\" PLATFORMS ${PLATFORMS})
98 98
99 # /NJH /NJS /NDL /NFL /NC /NS /NP - Silence any output 99 # /NJH /NJS /NDL /NFL /NC /NS /NP - Silence any output
100 # cmake adds an extra check for command success which doesn't work too well with robocopy 100 # cmake adds an extra check for command success which doesn't work too well with robocopy
101 # so trick it into thinking the command was successful with the || cmd /c "exit /b 0" 101 # so trick it into thinking the command was successful with the || cmd /c "exit /b 0"
102 add_custom_command(TARGET citra-qt POST_BUILD 102 add_custom_command(TARGET citra-qt POST_BUILD
103 COMMAND robocopy ${Qt5_DLL_DIR} ${DLL_DEST} ${Qt5_DLLS} /NJH /NJS /NDL /NFL /NC /NS /NP || cmd /c "exit /b 0" 103 COMMAND robocopy ${Qt5_DLL_DIR} ${DLL_DEST} ${Qt5_DLLS} /NJH /NJS /NDL /NFL /NC /NS /NP || cmd /c "exit /b 0"
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 72b55e94d..3db09c65b 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -57,7 +57,7 @@ void EmuThread::run() {
57 Core::SingleStep(); 57 Core::SingleStep();
58 emit DebugModeEntered(); 58 emit DebugModeEntered();
59 yieldCurrentThread(); 59 yieldCurrentThread();
60 60
61 was_active = false; 61 was_active = false;
62 } else { 62 } else {
63 std::unique_lock<std::mutex> lock(running_mutex); 63 std::unique_lock<std::mutex> lock(running_mutex);
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h
index 16809eaae..475124319 100644
--- a/src/citra_qt/bootmanager.h
+++ b/src/citra_qt/bootmanager.h
@@ -80,7 +80,7 @@ signals:
80 * @warning When connecting to this signal from other threads, make sure to specify either Qt::QueuedConnection (invoke slot within the destination object's message thread) or even Qt::BlockingQueuedConnection (additionally block source thread until slot returns) 80 * @warning When connecting to this signal from other threads, make sure to specify either Qt::QueuedConnection (invoke slot within the destination object's message thread) or even Qt::BlockingQueuedConnection (additionally block source thread until slot returns)
81 */ 81 */
82 void DebugModeEntered(); 82 void DebugModeEntered();
83 83
84 /** 84 /**
85 * Emitted right before the CPU continues execution 85 * Emitted right before the CPU continues execution
86 * 86 *
diff --git a/src/citra_qt/citra-qt.rc b/src/citra_qt/citra-qt.rc
index dd6f834f5..3c7239853 100644
--- a/src/citra_qt/citra-qt.rc
+++ b/src/citra_qt/citra-qt.rc
Binary files differ
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index 460f4ec07..2a9af1f38 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -49,7 +49,6 @@ void Config::ReadValues() {
49 qt_config->endGroup(); 49 qt_config->endGroup();
50 50
51 qt_config->beginGroup("Core"); 51 qt_config->beginGroup("Core");
52 Settings::values.gpu_refresh_rate = qt_config->value("gpu_refresh_rate", 30).toInt();
53 Settings::values.frame_skip = qt_config->value("frame_skip", 0).toInt(); 52 Settings::values.frame_skip = qt_config->value("frame_skip", 0).toInt();
54 qt_config->endGroup(); 53 qt_config->endGroup();
55 54
@@ -102,7 +101,6 @@ void Config::SaveValues() {
102 qt_config->endGroup(); 101 qt_config->endGroup();
103 102
104 qt_config->beginGroup("Core"); 103 qt_config->beginGroup("Core");
105 qt_config->setValue("gpu_refresh_rate", Settings::values.gpu_refresh_rate);
106 qt_config->setValue("frame_skip", Settings::values.frame_skip); 104 qt_config->setValue("frame_skip", Settings::values.frame_skip);
107 qt_config->endGroup(); 105 qt_config->endGroup();
108 106
diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp
index 94e204717..6799ce844 100644
--- a/src/citra_qt/debugger/callstack.cpp
+++ b/src/citra_qt/debugger/callstack.cpp
@@ -39,7 +39,7 @@ void CallstackWidget::OnDebugModeEntered()
39 { 39 {
40 ret_addr = Memory::Read32(addr); 40 ret_addr = Memory::Read32(addr);
41 call_addr = ret_addr - 4; //get call address??? 41 call_addr = ret_addr - 4; //get call address???
42 42
43 if (Memory::GetPointer(call_addr) == nullptr) 43 if (Memory::GetPointer(call_addr) == nullptr)
44 break; 44 break;
45 45
diff --git a/src/citra_qt/debugger/callstack.ui b/src/citra_qt/debugger/callstack.ui
index b0e31120f..248ea3dd7 100644
--- a/src/citra_qt/debugger/callstack.ui
+++ b/src/citra_qt/debugger/callstack.ui
@@ -17,6 +17,9 @@
17 <layout class="QVBoxLayout" name="verticalLayout"> 17 <layout class="QVBoxLayout" name="verticalLayout">
18 <item> 18 <item>
19 <widget class="QTreeView" name="treeView"> 19 <widget class="QTreeView" name="treeView">
20 <property name="editTriggers">
21 <set>QAbstractItemView::NoEditTriggers</set>
22 </property>
20 <property name="alternatingRowColors"> 23 <property name="alternatingRowColors">
21 <bool>true</bool> 24 <bool>true</bool>
22 </property> 25 </property>
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp
index 804c735a3..cabf5fe07 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.cpp
+++ b/src/citra_qt/debugger/graphics_cmdlists.cpp
@@ -11,10 +11,10 @@
11#include <QSpinBox> 11#include <QSpinBox>
12#include <QComboBox> 12#include <QComboBox>
13 13
14#include "video_core/pica.h" 14#include "common/vector_math.h"
15#include "video_core/math.h"
16 15
17#include "video_core/debug_utils/debug_utils.h" 16#include "video_core/debug_utils/debug_utils.h"
17#include "video_core/pica.h"
18 18
19#include "graphics_cmdlists.h" 19#include "graphics_cmdlists.h"
20 20
diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp
index e07344591..6bbe7572c 100644
--- a/src/citra_qt/debugger/graphics_framebuffer.cpp
+++ b/src/citra_qt/debugger/graphics_framebuffer.cpp
@@ -9,10 +9,11 @@
9#include <QPushButton> 9#include <QPushButton>
10#include <QSpinBox> 10#include <QSpinBox>
11 11
12#include "common/color.h"
13
12#include "core/hw/gpu.h" 14#include "core/hw/gpu.h"
13#include "core/memory.h" 15#include "core/memory.h"
14 16
15#include "video_core/color.h"
16#include "video_core/pica.h" 17#include "video_core/pica.h"
17#include "video_core/utils.h" 18#include "video_core/utils.h"
18 19
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index f6010459a..8041816a0 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -127,7 +127,7 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
127 127
128 ui.action_Use_Hardware_Renderer->setChecked(Settings::values.use_hw_renderer); 128 ui.action_Use_Hardware_Renderer->setChecked(Settings::values.use_hw_renderer);
129 SetHardwareRendererEnabled(ui.action_Use_Hardware_Renderer->isChecked()); 129 SetHardwareRendererEnabled(ui.action_Use_Hardware_Renderer->isChecked());
130 130
131 ui.action_Single_Window_Mode->setChecked(settings.value("singleWindowMode", true).toBool()); 131 ui.action_Single_Window_Mode->setChecked(settings.value("singleWindowMode", true).toBool());
132 ToggleWindowMode(); 132 ToggleWindowMode();
133 133
diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui
index 0942c28c8..9a809ee6c 100644
--- a/src/citra_qt/main.ui
+++ b/src/citra_qt/main.ui
@@ -24,7 +24,20 @@
24 <bool>true</bool> 24 <bool>true</bool>
25 </property> 25 </property>
26 <widget class="QWidget" name="centralwidget"> 26 <widget class="QWidget" name="centralwidget">
27 <layout class="QHBoxLayout" name="horizontalLayout"/> 27 <layout class="QHBoxLayout" name="horizontalLayout">
28 <property name="leftMargin">
29 <number>0</number>
30 </property>
31 <property name="topMargin">
32 <number>0</number>
33 </property>
34 <property name="rightMargin">
35 <number>0</number>
36 </property>
37 <property name="bottomMargin">
38 <number>0</number>
39 </property>
40 </layout>
28 </widget> 41 </widget>
29 <widget class="QMenuBar" name="menubar"> 42 <widget class="QMenuBar" name="menubar">
30 <property name="geometry"> 43 <property name="geometry">
@@ -92,7 +105,7 @@
92 </action> 105 </action>
93 <action name="action_Start"> 106 <action name="action_Start">
94 <property name="enabled"> 107 <property name="enabled">
95 <bool>false</bool> 108 <bool>false</bool>
96 </property> 109 </property>
97 <property name="text"> 110 <property name="text">
98 <string>&amp;Start</string> 111 <string>&amp;Start</string>
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index dbaaac77b..e78f4f144 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -24,6 +24,7 @@ set(HEADERS
24 bit_field.h 24 bit_field.h
25 break_points.h 25 break_points.h
26 chunk_file.h 26 chunk_file.h
27 color.h
27 common_funcs.h 28 common_funcs.h
28 common_paths.h 29 common_paths.h
29 common_types.h 30 common_types.h
@@ -54,6 +55,7 @@ set(HEADERS
54 thread_queue_list.h 55 thread_queue_list.h
55 thunk.h 56 thunk.h
56 timer.h 57 timer.h
58 vector_math.h
57 ) 59 )
58 60
59create_directory_groups(${SRCS} ${HEADERS}) 61create_directory_groups(${SRCS} ${HEADERS})
diff --git a/src/video_core/color.h b/src/common/color.h
index 4d2026eb0..422fdc8af 100644
--- a/src/video_core/color.h
+++ b/src/common/color.h
@@ -6,8 +6,7 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/swap.h" 8#include "common/swap.h"
9 9#include "common/vector_math.h"
10#include "video_core/math.h"
11 10
12namespace Color { 11namespace Color {
13 12
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index f5b6c7301..43facb85c 100644
--- a/src/common/emu_window.cpp
+++ b/src/common/emu_window.cpp
@@ -32,7 +32,7 @@ std::tuple<unsigned,unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsig
32 32
33 new_x = std::max(new_x, framebuffer_layout.bottom_screen.left); 33 new_x = std::max(new_x, framebuffer_layout.bottom_screen.left);
34 new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1); 34 new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1);
35 35
36 new_y = std::max(new_y, framebuffer_layout.bottom_screen.top); 36 new_y = std::max(new_y, framebuffer_layout.bottom_screen.top);
37 new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom-1); 37 new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom-1);
38 38
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 7cdd1484f..24648ea33 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -16,7 +16,7 @@
16 #include <io.h> 16 #include <io.h>
17 #include <direct.h> // getcwd 17 #include <direct.h> // getcwd
18 #include <tchar.h> 18 #include <tchar.h>
19 19
20 // 64 bit offsets for windows 20 // 64 bit offsets for windows
21 #define fseeko _fseeki64 21 #define fseeko _fseeki64
22 #define ftello _ftelli64 22 #define ftello _ftelli64
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 6ca8cb78d..d85e58373 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -37,6 +37,7 @@ namespace Log {
37 SUB(Service, APT) \ 37 SUB(Service, APT) \
38 SUB(Service, GSP) \ 38 SUB(Service, GSP) \
39 SUB(Service, AC) \ 39 SUB(Service, AC) \
40 SUB(Service, AM) \
40 SUB(Service, PTM) \ 41 SUB(Service, PTM) \
41 SUB(Service, LDR) \ 42 SUB(Service, LDR) \
42 SUB(Service, NIM) \ 43 SUB(Service, NIM) \
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index d720d7fe0..5b3a731e9 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -57,13 +57,14 @@ enum class Class : ClassType {
57 Service_APT, ///< The APT (Applets) service 57 Service_APT, ///< The APT (Applets) service
58 Service_GSP, ///< The GSP (GPU control) service 58 Service_GSP, ///< The GSP (GPU control) service
59 Service_AC, ///< The AC (WiFi status) service 59 Service_AC, ///< The AC (WiFi status) service
60 Service_AM, ///< The AM (Application manager) service
60 Service_PTM, ///< The PTM (Power status & misc.) service 61 Service_PTM, ///< The PTM (Power status & misc.) service
61 Service_LDR, ///< The LDR (3ds dll loader) service 62 Service_LDR, ///< The LDR (3ds dll loader) service
62 Service_NIM, ///< The NIM (Network interface manager) service 63 Service_NIM, ///< The NIM (Network interface manager) service
63 Service_NWM, ///< The NWM (Network manager) service 64 Service_NWM, ///< The NWM (Network wlan manager) service
64 Service_CFG, ///< The CFG (Configuration) service 65 Service_CFG, ///< The CFG (Configuration) service
65 Service_DSP, ///< The DSP (DSP control) service 66 Service_DSP, ///< The DSP (DSP control) service
66 Service_HID, ///< The HID (User input) service 67 Service_HID, ///< The HID (Human interface device) service
67 Service_SOC, ///< The SOC (Socket) service 68 Service_SOC, ///< The SOC (Socket) service
68 Service_Y2R, ///< The Y2R (YUV to RGB conversion) service 69 Service_Y2R, ///< The Y2R (YUV to RGB conversion) service
69 HW, ///< Low-level hardware emulation 70 HW, ///< Low-level hardware emulation
diff --git a/src/common/math_util.h b/src/common/math_util.h
index 4b0910741..d44b06e74 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -12,7 +12,7 @@ namespace MathUtil
12{ 12{
13 13
14inline bool IntervalsIntersect(unsigned start0, unsigned length0, unsigned start1, unsigned length1) { 14inline bool IntervalsIntersect(unsigned start0, unsigned length0, unsigned start1, unsigned length1) {
15 return (std::max(start0, start1) <= std::min(start0 + length0, start1 + length1)); 15 return (std::max(start0, start1) < std::min(start0 + length0, start1 + length1));
16} 16}
17 17
18template<typename T> 18template<typename T>
diff --git a/src/common/swap.h b/src/common/swap.h
index 7e37655bf..588cebc70 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -135,7 +135,7 @@ template <>
135inline void swap<8>(u8* data) { 135inline void swap<8>(u8* data) {
136 *reinterpret_cast<u64*>(data) = swap64(data); 136 *reinterpret_cast<u64*>(data) = swap64(data);
137} 137}
138 138
139} // Namespace Common 139} // Namespace Common
140 140
141 141
diff --git a/src/video_core/math.h b/src/common/vector_math.h
index f9a822658..4928c9bf2 100644
--- a/src/video_core/math.h
+++ b/src/common/vector_math.h
@@ -461,7 +461,7 @@ public:
461 // e.g. Vec2 uv() { return Vec2(x,y); } 461 // e.g. Vec2 uv() { return Vec2(x,y); }
462 462
463 // _DEFINE_SWIZZLER2 defines a single such function 463 // _DEFINE_SWIZZLER2 defines a single such function
464 // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r) 464 // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r)
465 // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and permutations (xy<->yx) 465 // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and permutations (xy<->yx)
466#define _DEFINE_SWIZZLER2(a, b, name) const Vec2<T> name() const { return Vec2<T>(a, b); } 466#define _DEFINE_SWIZZLER2(a, b, name) const Vec2<T> name() const { return Vec2<T>(a, b); }
467#define DEFINE_SWIZZLER2_COMP1(a, a2) \ 467#define DEFINE_SWIZZLER2_COMP1(a, a2) \
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 5caaee474..057b8ca0c 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -36,20 +36,29 @@ set(SRCS
36 hle/kernel/shared_memory.cpp 36 hle/kernel/shared_memory.cpp
37 hle/kernel/thread.cpp 37 hle/kernel/thread.cpp
38 hle/kernel/timer.cpp 38 hle/kernel/timer.cpp
39 hle/kernel/vm_manager.cpp
39 hle/service/ac_u.cpp 40 hle/service/ac_u.cpp
40 hle/service/act_u.cpp 41 hle/service/act_u.cpp
41 hle/service/am_app.cpp 42 hle/service/am/am.cpp
42 hle/service/am_net.cpp 43 hle/service/am/am_app.cpp
43 hle/service/am_sys.cpp 44 hle/service/am/am_net.cpp
45 hle/service/am/am_sys.cpp
46 hle/service/am/am_u.cpp
44 hle/service/apt/apt.cpp 47 hle/service/apt/apt.cpp
45 hle/service/apt/apt_a.cpp 48 hle/service/apt/apt_a.cpp
46 hle/service/apt/apt_s.cpp 49 hle/service/apt/apt_s.cpp
47 hle/service/apt/apt_u.cpp 50 hle/service/apt/apt_u.cpp
48 hle/service/boss_p.cpp 51 hle/service/boss/boss.cpp
49 hle/service/boss_u.cpp 52 hle/service/boss/boss_p.cpp
50 hle/service/cam_u.cpp 53 hle/service/boss/boss_u.cpp
51 hle/service/cecd_s.cpp 54 hle/service/cam/cam.cpp
52 hle/service/cecd_u.cpp 55 hle/service/cam/cam_c.cpp
56 hle/service/cam/cam_q.cpp
57 hle/service/cam/cam_s.cpp
58 hle/service/cam/cam_u.cpp
59 hle/service/cecd/cecd.cpp
60 hle/service/cecd/cecd_s.cpp
61 hle/service/cecd/cecd_u.cpp
53 hle/service/cfg/cfg.cpp 62 hle/service/cfg/cfg.cpp
54 hle/service/cfg/cfg_i.cpp 63 hle/service/cfg/cfg_i.cpp
55 hle/service/cfg/cfg_s.cpp 64 hle/service/cfg/cfg_s.cpp
@@ -57,8 +66,9 @@ set(SRCS
57 hle/service/csnd_snd.cpp 66 hle/service/csnd_snd.cpp
58 hle/service/dsp_dsp.cpp 67 hle/service/dsp_dsp.cpp
59 hle/service/err_f.cpp 68 hle/service/err_f.cpp
60 hle/service/frd_a.cpp 69 hle/service/frd/frd.cpp
61 hle/service/frd_u.cpp 70 hle/service/frd/frd_a.cpp
71 hle/service/frd/frd_u.cpp
62 hle/service/fs/archive.cpp 72 hle/service/fs/archive.cpp
63 hle/service/fs/fs_user.cpp 73 hle/service/fs/fs_user.cpp
64 hle/service/gsp_gpu.cpp 74 hle/service/gsp_gpu.cpp
@@ -74,10 +84,13 @@ set(SRCS
74 hle/service/ldr_ro.cpp 84 hle/service/ldr_ro.cpp
75 hle/service/mic_u.cpp 85 hle/service/mic_u.cpp
76 hle/service/ndm_u.cpp 86 hle/service/ndm_u.cpp
77 hle/service/news_s.cpp 87 hle/service/news/news.cpp
78 hle/service/news_u.cpp 88 hle/service/news/news_s.cpp
79 hle/service/nim_aoc.cpp 89 hle/service/news/news_u.cpp
80 hle/service/nim_u.cpp 90 hle/service/nim/nim.cpp
91 hle/service/nim/nim_aoc.cpp
92 hle/service/nim/nim_s.cpp
93 hle/service/nim/nim_u.cpp
81 hle/service/ns_s.cpp 94 hle/service/ns_s.cpp
82 hle/service/nwm_uds.cpp 95 hle/service/nwm_uds.cpp
83 hle/service/pm_app.cpp 96 hle/service/pm_app.cpp
@@ -116,7 +129,6 @@ set(HEADERS
116 arm/dyncom/arm_dyncom_thumb.h 129 arm/dyncom/arm_dyncom_thumb.h
117 arm/skyeye_common/arm_regformat.h 130 arm/skyeye_common/arm_regformat.h
118 arm/skyeye_common/armdefs.h 131 arm/skyeye_common/armdefs.h
119 arm/skyeye_common/armemu.h
120 arm/skyeye_common/armmmu.h 132 arm/skyeye_common/armmmu.h
121 arm/skyeye_common/vfp/asm_vfp.h 133 arm/skyeye_common/vfp/asm_vfp.h
122 arm/skyeye_common/vfp/vfp.h 134 arm/skyeye_common/vfp/vfp.h
@@ -148,21 +160,30 @@ set(HEADERS
148 hle/kernel/shared_memory.h 160 hle/kernel/shared_memory.h
149 hle/kernel/thread.h 161 hle/kernel/thread.h
150 hle/kernel/timer.h 162 hle/kernel/timer.h
163 hle/kernel/vm_manager.h
151 hle/result.h 164 hle/result.h
152 hle/service/ac_u.h 165 hle/service/ac_u.h
153 hle/service/act_u.h 166 hle/service/act_u.h
154 hle/service/am_app.h 167 hle/service/am/am.h
155 hle/service/am_net.h 168 hle/service/am/am_app.h
156 hle/service/am_sys.h 169 hle/service/am/am_net.h
170 hle/service/am/am_sys.h
171 hle/service/am/am_u.h
157 hle/service/apt/apt.h 172 hle/service/apt/apt.h
158 hle/service/apt/apt_a.h 173 hle/service/apt/apt_a.h
159 hle/service/apt/apt_s.h 174 hle/service/apt/apt_s.h
160 hle/service/apt/apt_u.h 175 hle/service/apt/apt_u.h
161 hle/service/boss_p.h 176 hle/service/boss/boss.h
162 hle/service/boss_u.h 177 hle/service/boss/boss_p.h
163 hle/service/cam_u.h 178 hle/service/boss/boss_u.h
164 hle/service/cecd_s.h 179 hle/service/cam/cam.h
165 hle/service/cecd_u.h 180 hle/service/cam/cam_c.h
181 hle/service/cam/cam_q.h
182 hle/service/cam/cam_s.h
183 hle/service/cam/cam_u.h
184 hle/service/cecd/cecd.h
185 hle/service/cecd/cecd_s.h
186 hle/service/cecd/cecd_u.h
166 hle/service/cfg/cfg.h 187 hle/service/cfg/cfg.h
167 hle/service/cfg/cfg_i.h 188 hle/service/cfg/cfg_i.h
168 hle/service/cfg/cfg_s.h 189 hle/service/cfg/cfg_s.h
@@ -170,8 +191,9 @@ set(HEADERS
170 hle/service/csnd_snd.h 191 hle/service/csnd_snd.h
171 hle/service/dsp_dsp.h 192 hle/service/dsp_dsp.h
172 hle/service/err_f.h 193 hle/service/err_f.h
173 hle/service/frd_a.h 194 hle/service/frd/frd.h
174 hle/service/frd_u.h 195 hle/service/frd/frd_a.h
196 hle/service/frd/frd_u.h
175 hle/service/fs/archive.h 197 hle/service/fs/archive.h
176 hle/service/fs/fs_user.h 198 hle/service/fs/fs_user.h
177 hle/service/gsp_gpu.h 199 hle/service/gsp_gpu.h
@@ -187,10 +209,13 @@ set(HEADERS
187 hle/service/ldr_ro.h 209 hle/service/ldr_ro.h
188 hle/service/mic_u.h 210 hle/service/mic_u.h
189 hle/service/ndm_u.h 211 hle/service/ndm_u.h
190 hle/service/news_s.h 212 hle/service/news/news.h
191 hle/service/news_u.h 213 hle/service/news/news_s.h
192 hle/service/nim_aoc.h 214 hle/service/news/news_u.h
193 hle/service/nim_u.h 215 hle/service/nim/nim.h
216 hle/service/nim/nim_aoc.h
217 hle/service/nim/nim_s.h
218 hle/service/nim/nim_u.h
194 hle/service/ns_s.h 219 hle/service/ns_s.h
195 hle/service/nwm_uds.h 220 hle/service/nwm_uds.h
196 hle/service/pm_app.h 221 hle/service/pm_app.h
diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp
index 913dc1454..f6d44d85a 100644
--- a/src/core/arm/disassembler/arm_disasm.cpp
+++ b/src/core/arm/disassembler/arm_disasm.cpp
@@ -813,7 +813,7 @@ Opcode ARM_Disasm::Decode11(uint32_t insn) {
813 // SWI 813 // SWI
814 return OP_SWI; 814 return OP_SWI;
815 } 815 }
816 816
817 uint8_t bit4 = (insn >> 4) & 0x1; 817 uint8_t bit4 = (insn >> 4) & 0x1;
818 uint8_t cpnum = (insn >> 8) & 0xf; 818 uint8_t cpnum = (insn >> 8) & 0xf;
819 819
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index 0072ae533..529c4ac70 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -6,7 +6,7 @@
6 6
7#include "common/make_unique.h" 7#include "common/make_unique.h"
8 8
9#include "core/arm/skyeye_common/armemu.h" 9#include "core/arm/skyeye_common/armdefs.h"
10#include "core/arm/skyeye_common/vfp/vfp.h" 10#include "core/arm/skyeye_common/vfp/vfp.h"
11 11
12#include "core/arm/dyncom/arm_dyncom.h" 12#include "core/arm/dyncom/arm_dyncom.h"
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index e4b5486e0..b00eb49a9 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -134,7 +134,7 @@ static unsigned int DPO(Immediate)(ARMul_State* cpu, unsigned int sht_oper) {
134 unsigned int immed_8 = BITS(sht_oper, 0, 7); 134 unsigned int immed_8 = BITS(sht_oper, 0, 7);
135 unsigned int rotate_imm = BITS(sht_oper, 8, 11); 135 unsigned int rotate_imm = BITS(sht_oper, 8, 11);
136 unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2); 136 unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2);
137 if (rotate_imm == 0) 137 if (rotate_imm == 0)
138 cpu->shifter_carry_out = cpu->CFlag; 138 cpu->shifter_carry_out = cpu->CFlag;
139 else 139 else
140 cpu->shifter_carry_out = BIT(shifter_operand, 31); 140 cpu->shifter_carry_out = BIT(shifter_operand, 31);
@@ -521,7 +521,7 @@ static void MLnS(ImmediateOffset)(ARMul_State* cpu, unsigned int inst, unsigned
521 addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8; 521 addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8;
522 else 522 else
523 addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8; 523 addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8;
524 524
525 virt_addr = addr; 525 virt_addr = addr;
526} 526}
527 527
@@ -550,7 +550,7 @@ static void MLnS(ImmediatePreIndexed)(ARMul_State* cpu, unsigned int inst, unsig
550 550
551 if (U_BIT) 551 if (U_BIT)
552 addr = rn + offset_8; 552 addr = rn + offset_8;
553 else 553 else
554 addr = rn - offset_8; 554 addr = rn - offset_8;
555 555
556 virt_addr = addr; 556 virt_addr = addr;
@@ -1306,8 +1306,8 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index)
1306 inst_cream->Rd = BITS(inst, 12, 15); 1306 inst_cream->Rd = BITS(inst, 12, 15);
1307 inst_cream->shifter_operand = BITS(inst, 0, 11); 1307 inst_cream->shifter_operand = BITS(inst, 0, 11);
1308 inst_cream->shtop_func = get_shtop(inst); 1308 inst_cream->shtop_func = get_shtop(inst);
1309 1309
1310 if (inst_cream->Rd == 15) 1310 if (inst_cream->Rd == 15)
1311 inst_base->br = INDIRECT_BRANCH; 1311 inst_base->br = INDIRECT_BRANCH;
1312 1312
1313 return inst_base; 1313 return inst_base;
@@ -1350,7 +1350,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index)
1350 inst_cream->shifter_operand = BITS(inst, 0, 11); 1350 inst_cream->shifter_operand = BITS(inst, 0, 11);
1351 inst_cream->shtop_func = get_shtop(inst); 1351 inst_cream->shtop_func = get_shtop(inst);
1352 1352
1353 if (inst_cream->Rd == 15) 1353 if (inst_cream->Rd == 15)
1354 inst_base->br = INDIRECT_BRANCH; 1354 inst_base->br = INDIRECT_BRANCH;
1355 return inst_base; 1355 return inst_base;
1356} 1356}
@@ -3269,7 +3269,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(yield)(unsigned int inst, int index)
3269#define VFP_INTERPRETER_STRUCT 3269#define VFP_INTERPRETER_STRUCT
3270#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 3270#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
3271#undef VFP_INTERPRETER_STRUCT 3271#undef VFP_INTERPRETER_STRUCT
3272 3272
3273#define VFP_INTERPRETER_TRANS 3273#define VFP_INTERPRETER_TRANS
3274#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 3274#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
3275#undef VFP_INTERPRETER_TRANS 3275#undef VFP_INTERPRETER_TRANS
@@ -3478,9 +3478,9 @@ const transop_fp_t arm_instruction_trans[] = {
3478 INTERPRETER_TRANSLATE(bbl), 3478 INTERPRETER_TRANSLATE(bbl),
3479 3479
3480 // All the thumb instructions should be placed the end of table 3480 // All the thumb instructions should be placed the end of table
3481 INTERPRETER_TRANSLATE(b_2_thumb), 3481 INTERPRETER_TRANSLATE(b_2_thumb),
3482 INTERPRETER_TRANSLATE(b_cond_thumb), 3482 INTERPRETER_TRANSLATE(b_cond_thumb),
3483 INTERPRETER_TRANSLATE(bl_1_thumb), 3483 INTERPRETER_TRANSLATE(bl_1_thumb),
3484 INTERPRETER_TRANSLATE(bl_2_thumb), 3484 INTERPRETER_TRANSLATE(bl_2_thumb),
3485 INTERPRETER_TRANSLATE(blx_1_thumb) 3485 INTERPRETER_TRANSLATE(blx_1_thumb)
3486}; 3486};
@@ -3564,17 +3564,13 @@ static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) {
3564 unsigned int inst, inst_size = 4; 3564 unsigned int inst, inst_size = 4;
3565 int idx; 3565 int idx;
3566 int ret = NON_BRANCH; 3566 int ret = NON_BRANCH;
3567 int thumb = 0;
3568 int size = 0; // instruction size of basic block 3567 int size = 0; // instruction size of basic block
3569 bb_start = top; 3568 bb_start = top;
3570 3569
3571 if (cpu->TFlag)
3572 thumb = THUMB;
3573
3574 u32 phys_addr = addr; 3570 u32 phys_addr = addr;
3575 u32 pc_start = cpu->Reg[15]; 3571 u32 pc_start = cpu->Reg[15];
3576 3572
3577 while(ret == NON_BRANCH) { 3573 while (ret == NON_BRANCH) {
3578 inst = Memory::Read32(phys_addr & 0xFFFFFFFC); 3574 inst = Memory::Read32(phys_addr & 0xFFFFFFFC);
3579 3575
3580 size++; 3576 size++;
@@ -3890,7 +3886,6 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
3890 3886
3891 #define CurrentModeHasSPSR (cpu->Mode != SYSTEM32MODE) && (cpu->Mode != USER32MODE) 3887 #define CurrentModeHasSPSR (cpu->Mode != SYSTEM32MODE) && (cpu->Mode != USER32MODE)
3892 #define PC (cpu->Reg[15]) 3888 #define PC (cpu->Reg[15])
3893 #define CHECK_EXT_INT if (!cpu->NirqSig && !(cpu->Cpsr & 0x80)) goto END;
3894 3889
3895 // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback 3890 // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback
3896 // to a clunky switch statement. 3891 // to a clunky switch statement.
@@ -4343,7 +4338,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4343 } 4338 }
4344 } 4339 }
4345 if (BIT(inst, 13)) { 4340 if (BIT(inst, 13)) {
4346 if (cpu->Mode == USER32MODE) 4341 if (cpu->Mode == USER32MODE)
4347 cpu->Reg[13] = ReadMemory32(cpu, addr); 4342 cpu->Reg[13] = ReadMemory32(cpu, addr);
4348 else 4343 else
4349 cpu->Reg_usr[0] = ReadMemory32(cpu, addr); 4344 cpu->Reg_usr[0] = ReadMemory32(cpu, addr);
@@ -4351,7 +4346,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4351 addr += 4; 4346 addr += 4;
4352 } 4347 }
4353 if (BIT(inst, 14)) { 4348 if (BIT(inst, 14)) {
4354 if (cpu->Mode == USER32MODE) 4349 if (cpu->Mode == USER32MODE)
4355 cpu->Reg[14] = ReadMemory32(cpu, addr); 4350 cpu->Reg[14] = ReadMemory32(cpu, addr);
4356 else 4351 else
4357 cpu->Reg_usr[1] = ReadMemory32(cpu, addr); 4352 cpu->Reg_usr[1] = ReadMemory32(cpu, addr);
@@ -5153,7 +5148,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5153 REV16_INST: 5148 REV16_INST:
5154 REVSH_INST: 5149 REVSH_INST:
5155 { 5150 {
5156 5151
5157 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { 5152 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
5158 rev_inst* const inst_cream = (rev_inst*)inst_base->component; 5153 rev_inst* const inst_cream = (rev_inst*)inst_base->component;
5159 5154
@@ -5726,7 +5721,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5726 5721
5727 if (do_swap) 5722 if (do_swap)
5728 rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16)); 5723 rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16));
5729 5724
5730 const s32 product1 = (s16)(rn_val & 0xFFFF) * (s16)(rm_val & 0xFFFF); 5725 const s32 product1 = (s16)(rn_val & 0xFFFF) * (s16)(rm_val & 0xFFFF);
5731 const s32 product2 = (s16)((rn_val >> 16) & 0xFFFF) * (s16)((rm_val >> 16) & 0xFFFF); 5726 const s32 product2 = (s16)((rn_val >> 16) & 0xFFFF) * (s16)((rm_val >> 16) & 0xFFFF);
5732 s64 result; 5727 s64 result;
@@ -6588,7 +6583,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6588 { 6583 {
6589 u32 lo_val = 0; 6584 u32 lo_val = 0;
6590 u32 hi_val = 0; 6585 u32 hi_val = 0;
6591 6586
6592 // UHADD16 6587 // UHADD16
6593 if (op2 == 0x00) { 6588 if (op2 == 0x00) {
6594 lo_val = (rn_val & 0xFFFF) + (rm_val & 0xFFFF); 6589 lo_val = (rn_val & 0xFFFF) + (rm_val & 0xFFFF);
@@ -6777,7 +6772,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6777 6772
6778 u16 lo_val = 0; 6773 u16 lo_val = 0;
6779 u16 hi_val = 0; 6774 u16 hi_val = 0;
6780 6775
6781 // UQADD16 6776 // UQADD16
6782 if (op2 == 0x00) { 6777 if (op2 == 0x00) {
6783 lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, rm_val & 0xFFFF); 6778 lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, rm_val & 0xFFFF);
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
index 08b5c0b77..3e79c44c0 100644
--- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
@@ -184,38 +184,27 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
184 case 9: // LDR Rd,[PC,#imm8] 184 case 9: // LDR Rd,[PC,#imm8]
185 *ainstr = 0xE59F0000 // base 185 *ainstr = 0xE59F0000 // base
186 | ((tinstr & 0x0700) << (12 - 8)) // Rd 186 | ((tinstr & 0x0700) << (12 - 8)) // Rd
187 |((tinstr & 0x00FF) << (2 - 0)); // off8 187 |((tinstr & 0x00FF) << (2 - 0)); // off8
188 break; 188 break;
189 189
190 case 10: 190 case 10:
191 case 11: 191 case 11:
192 // TODO: Format 7 and Format 8 perform the same ARM encoding, so the following could be 192 {
193 // merged into a single subset, saving on the following boolean: 193 static const ARMword subset[8] = {
194 194 0xE7800000, // STR Rd,[Rb,Ro]
195 if ((tinstr & (1 << 9)) == 0) {
196 static const ARMword subset[4] = {
197 0xE7800000, // STR Rd,[Rb,Ro]
198 0xE7C00000, // STRB Rd,[Rb,Ro]
199 0xE7900000, // LDR Rd,[Rb,Ro]
200 0xE7D00000 // LDRB Rd,[Rb,Ro]
201 };
202
203 *ainstr = subset[(tinstr & 0x0C00) >> 10] // base
204 |((tinstr & 0x0007) << (12 - 0)) // Rd
205 |((tinstr & 0x0038) << (16 - 3)) // Rb
206 |((tinstr & 0x01C0) >> 6); // Ro
207
208 } else {
209 static const ARMword subset[4] = {
210 0xE18000B0, // STRH Rd,[Rb,Ro] 195 0xE18000B0, // STRH Rd,[Rb,Ro]
196 0xE7C00000, // STRB Rd,[Rb,Ro]
211 0xE19000D0, // LDRSB Rd,[Rb,Ro] 197 0xE19000D0, // LDRSB Rd,[Rb,Ro]
198 0xE7900000, // LDR Rd,[Rb,Ro]
212 0xE19000B0, // LDRH Rd,[Rb,Ro] 199 0xE19000B0, // LDRH Rd,[Rb,Ro]
200 0xE7D00000, // LDRB Rd,[Rb,Ro]
213 0xE19000F0 // LDRSH Rd,[Rb,Ro] 201 0xE19000F0 // LDRSH Rd,[Rb,Ro]
214 }; 202 };
215 *ainstr = subset[(tinstr & 0x0C00) >> 10] // base 203
216 |((tinstr & 0x0007) << (12 - 0)) // Rd 204 *ainstr = subset[(tinstr & 0xE00) >> 9] // base
217 |((tinstr & 0x0038) << (16 - 3)) // Rb 205 |((tinstr & 0x0007) << (12 - 0)) // Rd
218 |((tinstr & 0x01C0) >> 6); // Ro 206 |((tinstr & 0x0038) << (16 - 3)) // Rb
207 |((tinstr & 0x01C0) >> 6); // Ro
219 } 208 }
220 break; 209 break;
221 210
@@ -285,9 +274,46 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
285 ? 0xE24DDF00 // SUB 274 ? 0xE24DDF00 // SUB
286 : 0xE28DDF00) // ADD 275 : 0xE28DDF00) // ADD
287 |(tinstr & 0x007F); // off7 276 |(tinstr & 0x007F); // off7
288 } else if ((tinstr & 0x0F00) == 0x0e00) 277 } else if ((tinstr & 0x0F00) == 0x0e00) {
289 *ainstr = 0xEF000000 | 0x180000; // base | BKPT mask 278 // BKPT
290 else { 279 *ainstr = 0xEF000000 // base
280 | BITS(tinstr, 0, 3) // imm4 field;
281 | (BITS(tinstr, 4, 7) << 8); // beginning 4 bits of imm12
282 } else if ((tinstr & 0x0F00) == 0x0200) {
283 static const ARMword subset[4] = {
284 0xE6BF0070, // SXTH
285 0xE6AF0070, // SXTB
286 0xE6FF0070, // UXTH
287 0xE6EF0070, // UXTB
288 };
289
290 *ainstr = subset[BITS(tinstr, 6, 7)] // base
291 | (BITS(tinstr, 0, 2) << 12) // Rd
292 | BITS(tinstr, 3, 5); // Rm
293 } else if ((tinstr & 0x0F00) == 0x600) {
294 if (BIT(tinstr, 5) == 0) {
295 // SETEND
296 *ainstr = 0xF1010000 // base
297 | (BIT(tinstr, 3) << 9); // endian specifier
298 } else {
299 // CPS
300 *ainstr = 0xF1080000 // base
301 | (BIT(tinstr, 0) << 6) // fiq bit
302 | (BIT(tinstr, 1) << 7) // irq bit
303 | (BIT(tinstr, 2) << 8) // abort bit
304 | (BIT(tinstr, 4) << 18); // enable bit
305 }
306 } else if ((tinstr & 0x0F00) == 0x0a00) {
307 static const ARMword subset[3] = {
308 0xE6BF0F30, // REV
309 0xE6BF0FB0, // REV16
310 0xE6FF0FB0, // REVSH
311 };
312
313 *ainstr = subset[BITS(tinstr, 6, 7)] // base
314 | (BITS(tinstr, 0, 2) << 12) // Rd
315 | BITS(tinstr, 3, 5); // Rm
316 } else {
291 static const ARMword subset[4] = { 317 static const ARMword subset[4] = {
292 0xE92D0000, // STMDB sp!,{rlist} 318 0xE92D0000, // STMDB sp!,{rlist}
293 0xE92D4000, // STMDB sp!,{rlist,lr} 319 0xE92D4000, // STMDB sp!,{rlist,lr}
@@ -301,11 +327,25 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
301 327
302 case 24: // STMIA 328 case 24: // STMIA
303 case 25: // LDMIA 329 case 25: // LDMIA
304 *ainstr = ((tinstr & (1 << 11)) // base 330 if (tinstr & (1 << 11))
305 ? 0xE8B00000 // LDMIA 331 {
306 : 0xE8A00000) // STMIA 332 unsigned int base = 0xE8900000;
307 |((tinstr & 0x0700) << (16 - 8)) // Rb 333 unsigned int rn = BITS(tinstr, 8, 10);
308 |(tinstr & 0x00FF); // mask8 334
335 // Writeback
336 if ((tinstr & (1 << rn)) == 0)
337 base |= (1 << 21);
338
339 *ainstr = base // base (LDMIA)
340 | (rn << 16) // Rn
341 | (tinstr & 0x00FF); // Register list
342 }
343 else
344 {
345 *ainstr = 0xE8A00000 // base (STMIA)
346 | (BITS(tinstr, 8, 10) << 16) // Rn
347 | (tinstr & 0x00FF); // Register list
348 }
309 break; 349 break;
310 350
311 case 26: // Bcc 351 case 26: // Bcc
diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp
index 680a94a39..4f7a48fab 100644
--- a/src/core/arm/interpreter/arminit.cpp
+++ b/src/core/arm/interpreter/arminit.cpp
@@ -17,7 +17,6 @@
17 17
18#include <cstring> 18#include <cstring>
19#include "core/arm/skyeye_common/armdefs.h" 19#include "core/arm/skyeye_common/armdefs.h"
20#include "core/arm/skyeye_common/armemu.h"
21#include "core/arm/skyeye_common/vfp/vfp.h" 20#include "core/arm/skyeye_common/vfp/vfp.h"
22 21
23/***************************************************************************\ 22/***************************************************************************\
diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp
index 1b078dc71..83f7f3e2c 100644
--- a/src/core/arm/interpreter/armsupp.cpp
+++ b/src/core/arm/interpreter/armsupp.cpp
@@ -628,7 +628,7 @@ void WriteCP15Register(ARMul_State* cpu, u32 value, u32 crn, u32 opcode_1, u32 c
628 cpu->CP15[CP15_DATA_SYNC_BARRIER] = value; 628 cpu->CP15[CP15_DATA_SYNC_BARRIER] = value;
629 else if (opcode_2 == 5) 629 else if (opcode_2 == 5)
630 cpu->CP15[CP15_DATA_MEMORY_BARRIER] = value; 630 cpu->CP15[CP15_DATA_MEMORY_BARRIER] = value;
631 631
632 } 632 }
633 else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2) 633 else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2)
634 { 634 {
diff --git a/src/core/arm/skyeye_common/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h
index 6c89774eb..a92effbb4 100644
--- a/src/core/arm/skyeye_common/arm_regformat.h
+++ b/src/core/arm/skyeye_common/arm_regformat.h
@@ -59,6 +59,8 @@ enum {
59 VFP_FPSID, 59 VFP_FPSID,
60 VFP_FPSCR, 60 VFP_FPSCR,
61 VFP_FPEXC, 61 VFP_FPEXC,
62 VFP_MVFR0,
63 VFP_MVFR1,
62 64
63 // Not an actual register. 65 // Not an actual register.
64 // All VFP system registers should be defined above this. 66 // All VFP system registers should be defined above this.
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h
index 470f9508d..d2c901100 100644
--- a/src/core/arm/skyeye_common/armdefs.h
+++ b/src/core/arm/skyeye_common/armdefs.h
@@ -1,16 +1,16 @@
1/* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator. 1/* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator.
2 Copyright (C) 1994 Advanced RISC Machines Ltd. 2 Copyright (C) 1994 Advanced RISC Machines Ltd.
3 3
4 This program is free software; you can redistribute it and/or modify 4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or 6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version. 7 (at your option) any later version.
8 8
9 This program is distributed in the hope that it will be useful, 9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details. 12 GNU General Public License for more details.
13 13
14 You should have received a copy of the GNU General Public License 14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software 15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
@@ -262,6 +262,34 @@ enum ConditionCode {
262 NV = 15, 262 NV = 15,
263}; 263};
264 264
265// Flags for use with the APSR.
266enum : u32 {
267 NBIT = (1U << 31U),
268 ZBIT = (1 << 30),
269 CBIT = (1 << 29),
270 VBIT = (1 << 28),
271 QBIT = (1 << 27),
272 JBIT = (1 << 24),
273 EBIT = (1 << 9),
274 ABIT = (1 << 8),
275 IBIT = (1 << 7),
276 FBIT = (1 << 6),
277 TBIT = (1 << 5),
278
279 // Masks for groups of bits in the APSR.
280 MODEBITS = 0x1F,
281 INTBITS = 0x1C0,
282};
283
284// Values for Emulate.
285enum {
286 STOP = 0, // Stop
287 CHANGEMODE = 1, // Change mode
288 ONCE = 2, // Execute just one iteration
289 RUN = 3 // Continuous execution
290};
291
292
265extern bool AddOverflow(ARMword, ARMword, ARMword); 293extern bool AddOverflow(ARMword, ARMword, ARMword);
266extern bool SubOverflow(ARMword, ARMword, ARMword); 294extern bool SubOverflow(ARMword, ARMword, ARMword);
267 295
diff --git a/src/core/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h
deleted file mode 100644
index 7e0965052..000000000
--- a/src/core/arm/skyeye_common/armemu.h
+++ /dev/null
@@ -1,47 +0,0 @@
1/* armemu.h -- ARMulator emulation macros: ARM6 Instruction Emulator.
2 Copyright (C) 1994 Advanced RISC Machines Ltd.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18#pragma once
19
20#include "core/arm/skyeye_common/armdefs.h"
21
22// Flags for use with the APSR.
23enum : u32 {
24 NBIT = (1U << 31U),
25 ZBIT = (1 << 30),
26 CBIT = (1 << 29),
27 VBIT = (1 << 28),
28 QBIT = (1 << 27),
29 JBIT = (1 << 24),
30 EBIT = (1 << 9),
31 ABIT = (1 << 8),
32 IBIT = (1 << 7),
33 FBIT = (1 << 6),
34 TBIT = (1 << 5),
35
36 // Masks for groups of bits in the APSR.
37 MODEBITS = 0x1F,
38 INTBITS = 0x1C0,
39};
40
41// Values for Emulate.
42enum {
43 STOP = 0, // Stop
44 CHANGEMODE = 1, // Change mode
45 ONCE = 2, // Execute just one interation
46 RUN = 3 // Continuous execution
47};
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp
index b88d47750..571d6c2f2 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfp.cpp
@@ -33,6 +33,10 @@ unsigned VFPInit(ARMul_State* state)
33 state->VFP[VFP_FPEXC] = 0; 33 state->VFP[VFP_FPEXC] = 0;
34 state->VFP[VFP_FPSCR] = 0; 34 state->VFP[VFP_FPSCR] = 0;
35 35
36 // ARM11 MPCore feature register values.
37 state->VFP[VFP_MVFR0] = 0x11111111;
38 state->VFP[VFP_MVFR1] = 0;
39
36 return 0; 40 return 0;
37} 41}
38 42
diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h
index 727350f14..acefae9bb 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.h
+++ b/src/core/arm/skyeye_common/vfp/vfp.h
@@ -22,7 +22,6 @@
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_UNIMPLEMENTED(x) LOG_ERROR(Core_ARM11, "in func %s, " #x " unimplemented\n", __FUNCTION__); exit(-1);
26#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\n", __FUNCTION__);
27#define CHECK_VFP_ENABLED 26#define CHECK_VFP_ENABLED
28#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]);
diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h
index ccc0212ab..2007d6dc4 100644
--- a/src/core/arm/skyeye_common/vfp/vfp_helper.h
+++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h
@@ -18,10 +18,10 @@
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/ 19*/
20 20
21/* 21/*
22 * The following code is derivative from Linux Android kernel vfp 22 * The following code is derivative from Linux Android kernel vfp
23 * floating point support. 23 * floating point support.
24 * 24 *
25 * Copyright (C) 2004 ARM Limited. 25 * Copyright (C) 2004 ARM Limited.
26 * Written by Deep Blue Solutions Limited. 26 * Written by Deep Blue Solutions Limited.
27 * 27 *
diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
index 3ed918a93..67fe63aa4 100644
--- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
@@ -1068,10 +1068,12 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrc)(unsigned int inst, int index)
1068#ifdef VFP_INTERPRETER_IMPL 1068#ifdef VFP_INTERPRETER_IMPL
1069VMOVBRC_INST: 1069VMOVBRC_INST:
1070{ 1070{
1071 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1071 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
1072 CHECK_VFP_ENABLED; 1072 CHECK_VFP_ENABLED;
1073 1073
1074 VFP_DEBUG_UNIMPLEMENTED(VMOVBRC); 1074 vmovbrc_inst* const inst_cream = (vmovbrc_inst*)inst_base->component;
1075
1076 cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index] = cpu->Reg[inst_cream->t];
1075 } 1077 }
1076 cpu->Reg[15] += GET_INST_SIZE(cpu); 1078 cpu->Reg[15] += GET_INST_SIZE(cpu);
1077 INC_PC(sizeof(vmovbrc_inst)); 1079 INC_PC(sizeof(vmovbrc_inst));
@@ -1139,12 +1141,10 @@ VMRS_INST:
1139 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSID]; 1141 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSID];
1140 break; 1142 break;
1141 case 6: 1143 case 6:
1142 /* MVFR1, VFPv3 only ? */ 1144 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR1];
1143 LOG_TRACE(Core_ARM11, "\tr%d <= MVFR1 unimplemented\n", inst_cream->Rt);
1144 break; 1145 break;
1145 case 7: 1146 case 7:
1146 /* MVFR0, VFPv3 only? */ 1147 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR0];
1147 LOG_TRACE(Core_ARM11, "\tr%d <= MVFR0 unimplemented\n", inst_cream->Rt);
1148 break; 1148 break;
1149 case 8: 1149 case 8:
1150 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPEXC]; 1150 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPEXC];
@@ -1195,10 +1195,12 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbcr)(unsigned int inst, int index)
1195#ifdef VFP_INTERPRETER_IMPL 1195#ifdef VFP_INTERPRETER_IMPL
1196VMOVBCR_INST: 1196VMOVBCR_INST:
1197{ 1197{
1198 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1198 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
1199 CHECK_VFP_ENABLED; 1199 CHECK_VFP_ENABLED;
1200 1200
1201 VFP_DEBUG_UNIMPLEMENTED(VMOVBCR); 1201 vmovbcr_inst* const inst_cream = (vmovbcr_inst*) inst_base->component;
1202
1203 cpu->Reg[inst_cream->t] = cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index];
1202 } 1204 }
1203 cpu->Reg[15] += GET_INST_SIZE(cpu); 1205 cpu->Reg[15] += GET_INST_SIZE(cpu);
1204 INC_PC(sizeof(vmovbcr_inst)); 1206 INC_PC(sizeof(vmovbcr_inst));
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index f70c84c3d..e53c2e606 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -549,7 +549,7 @@ std::string GetScheduledEventsSummary() {
549 const char* name = event_types[event->type].name; 549 const char* name = event_types[event->type].name;
550 if (!name) 550 if (!name)
551 name = "[unknown]"; 551 name = "[unknown]";
552 text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)event->time, 552 text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)event->time,
553 (u32)(event->userdata >> 32), (u32)(event->userdata)); 553 (u32)(event->userdata >> 32), (u32)(event->userdata));
554 event = event->next; 554 event = event->next;
555 } 555 }
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 01519608d..64f5b06d9 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -87,7 +87,7 @@ void UnregisterAllEvents();
87/// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from disk, 87/// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from disk,
88/// when we implement state saves. 88/// when we implement state saves.
89/** 89/**
90 * Schedules an event to run after the specified number of cycles, 90 * Schedules an event to run after the specified number of cycles,
91 * with an optional parameter to be passed to the callback handler. 91 * with an optional parameter to be passed to the callback handler.
92 * This must be run ONLY from within the cpu thread. 92 * This must be run ONLY from within the cpu thread.
93 * @param cycles_into_future The number of cycles after which this event will be fired 93 * @param cycles_into_future The number of cycles after which this event will be fired
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index 38d498d0e..e50c58a52 100644
--- a/src/core/file_sys/archive_extsavedata.cpp
+++ b/src/core/file_sys/archive_extsavedata.cpp
@@ -30,8 +30,8 @@ std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path)
30std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) { 30std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) {
31 if (shared) 31 if (shared)
32 return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(), SYSTEM_ID.c_str()); 32 return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(), SYSTEM_ID.c_str());
33 33
34 return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(), 34 return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(),
35 SYSTEM_ID.c_str(), SDCARD_ID.c_str()); 35 SYSTEM_ID.c_str(), SDCARD_ID.c_str());
36} 36}
37 37
@@ -71,7 +71,7 @@ bool ArchiveFactory_ExtSaveData::Initialize() {
71} 71}
72 72
73ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(const Path& path) { 73ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(const Path& path) {
74 std::string fullpath = GetExtSaveDataPath(mount_point, path); 74 std::string fullpath = GetExtSaveDataPath(mount_point, path) + "user/";
75 if (!FileUtil::Exists(fullpath)) { 75 if (!FileUtil::Exists(fullpath)) {
76 // TODO(Subv): Check error code, this one is probably wrong 76 // TODO(Subv): Check error code, this one is probably wrong
77 return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, 77 return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS,
@@ -82,8 +82,11 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(cons
82} 82}
83 83
84ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path) { 84ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path) {
85 std::string fullpath = GetExtSaveDataPath(mount_point, path); 85 // These folders are always created with the ExtSaveData
86 FileUtil::CreateFullPath(fullpath); 86 std::string user_path = GetExtSaveDataPath(mount_point, path) + "user/";
87 std::string boss_path = GetExtSaveDataPath(mount_point, path) + "boss/";
88 FileUtil::CreateFullPath(user_path);
89 FileUtil::CreateFullPath(boss_path);
87 return RESULT_SUCCESS; 90 return RESULT_SUCCESS;
88} 91}
89 92
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h
index c77c04e44..ef0b27bde 100644
--- a/src/core/file_sys/archive_extsavedata.h
+++ b/src/core/file_sys/archive_extsavedata.h
@@ -35,14 +35,14 @@ public:
35private: 35private:
36 /** 36 /**
37 * This holds the full directory path for this archive, it is only set after a successful call 37 * This holds the full directory path for this archive, it is only set after a successful call
38 * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>. 38 * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>.
39 * See GetExtSaveDataPath for the code that extracts this data from an archive path. 39 * See GetExtSaveDataPath for the code that extracts this data from an archive path.
40 */ 40 */
41 std::string mount_point; 41 std::string mount_point;
42}; 42};
43 43
44/** 44/**
45 * Constructs a path to the concrete ExtData archive in the host filesystem based on the 45 * Constructs a path to the concrete ExtData archive in the host filesystem based on the
46 * input Path and base mount point. 46 * input Path and base mount point.
47 * @param mount_point The base mount point of the ExtSaveData archives. 47 * @param mount_point The base mount point of the ExtSaveData archives.
48 * @param path The path that identifies the requested concrete ExtSaveData archive. 48 * @param path The path that identifies the requested concrete ExtSaveData archive.
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
index 8dff51966..a92309377 100644
--- a/src/core/file_sys/archive_savedata.cpp
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -21,7 +21,7 @@
21namespace FileSys { 21namespace FileSys {
22 22
23static std::string GetSaveDataContainerPath(const std::string& sdmc_directory) { 23static std::string GetSaveDataContainerPath(const std::string& sdmc_directory) {
24 return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(), 24 return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(),
25 SYSTEM_ID.c_str(), SDCARD_ID.c_str()); 25 SYSTEM_ID.c_str(), SDCARD_ID.c_str());
26} 26}
27 27
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 23c86a72d..5949cb470 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -9,11 +9,15 @@
9#include "core/arm/arm_interface.h" 9#include "core/arm/arm_interface.h"
10#include "core/memory.h" 10#include "core/memory.h"
11#include "core/hle/hle.h" 11#include "core/hle/hle.h"
12#include "core/hle/result.h"
12 13
13namespace HLE { 14namespace HLE {
14 15
15#define PARAM(n) Core::g_app_core->GetReg(n) 16#define PARAM(n) Core::g_app_core->GetReg(n)
16 17
18/// An invalid result code that is meant to be overwritten when a thread resumes from waiting
19static const ResultCode RESULT_INVALID(0xDEADC0DE);
20
17/** 21/**
18 * HLE a function return from the current ARM11 userland process 22 * HLE a function return from the current ARM11 userland process
19 * @param res Result to return 23 * @param res Result to return
@@ -57,8 +61,11 @@ template<ResultCode func(s32*, u32*, s32, bool, s64)> void Wrap() {
57 s32 param_1 = 0; 61 s32 param_1 = 0;
58 s32 retval = func(&param_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), 62 s32 retval = func(&param_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2),
59 (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))).raw; 63 (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))).raw;
60 Core::g_app_core->SetReg(1, (u32)param_1); 64
61 FuncReturn(retval); 65 if (retval != RESULT_INVALID.raw) {
66 Core::g_app_core->SetReg(1, (u32)param_1);
67 FuncReturn(retval);
68 }
62} 69}
63 70
64template<ResultCode func(u32, u32, u32, u32, s64)> void Wrap() { 71template<ResultCode func(u32, u32, u32, u32, s64)> void Wrap() {
@@ -73,7 +80,11 @@ template<ResultCode func(u32*)> void Wrap(){
73} 80}
74 81
75template<ResultCode func(u32, s64)> void Wrap() { 82template<ResultCode func(u32, s64)> void Wrap() {
76 FuncReturn(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw); 83 s32 retval = func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw;
84
85 if (retval != RESULT_INVALID.raw) {
86 FuncReturn(retval);
87 }
77} 88}
78 89
79template<ResultCode func(void*, void*, u32)> void Wrap(){ 90template<ResultCode func(void*, void*, u32)> void Wrap(){
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index e45deb1c6..f338f3266 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -41,10 +41,7 @@ void Event::Acquire() {
41 41
42void Event::Signal() { 42void Event::Signal() {
43 signaled = true; 43 signaled = true;
44
45 WakeupAllWaitingThreads(); 44 WakeupAllWaitingThreads();
46
47 HLE::Reschedule(__func__);
48} 45}
49 46
50void Event::Clear() { 47void Event::Clear() {
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 726e4d2ff..20e11da16 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -32,27 +32,13 @@ void WaitObject::RemoveWaitingThread(Thread* thread) {
32 waiting_threads.erase(itr); 32 waiting_threads.erase(itr);
33} 33}
34 34
35SharedPtr<Thread> WaitObject::WakeupNextThread() {
36 if (waiting_threads.empty())
37 return nullptr;
38
39 auto next_thread = std::move(waiting_threads.front());
40 waiting_threads.erase(waiting_threads.begin());
41
42 next_thread->ReleaseWaitObject(this);
43
44 return next_thread;
45}
46
47void WaitObject::WakeupAllWaitingThreads() { 35void WaitObject::WakeupAllWaitingThreads() {
48 auto waiting_threads_copy = waiting_threads; 36 for (auto thread : waiting_threads)
37 thread->ResumeFromWait();
49 38
50 // We use a copy because ReleaseWaitObject will remove the thread from this object's 39 waiting_threads.clear();
51 // waiting_threads list
52 for (auto thread : waiting_threads_copy)
53 thread->ReleaseWaitObject(this);
54 40
55 ASSERT_MSG(waiting_threads.empty(), "failed to awaken all waiting threads!"); 41 HLE::Reschedule(__func__);
56} 42}
57 43
58HandleTable::HandleTable() { 44HandleTable::HandleTable() {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index a5a0f4800..64595f758 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -140,12 +140,6 @@ public:
140 */ 140 */
141 void RemoveWaitingThread(Thread* thread); 141 void RemoveWaitingThread(Thread* thread);
142 142
143 /**
144 * Wake up the next thread waiting on this object
145 * @return Pointer to the thread that was resumed, nullptr if no threads are waiting
146 */
147 SharedPtr<Thread> WakeupNextThread();
148
149 /// Wake up all threads waiting on this object 143 /// Wake up all threads waiting on this object
150 void WakeupAllWaitingThreads(); 144 void WakeupAllWaitingThreads();
151 145
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 6aa73df86..edb97d324 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -23,12 +23,7 @@ static void ResumeWaitingThread(Mutex* mutex) {
23 // Reset mutex lock thread handle, nothing is waiting 23 // Reset mutex lock thread handle, nothing is waiting
24 mutex->lock_count = 0; 24 mutex->lock_count = 0;
25 mutex->holding_thread = nullptr; 25 mutex->holding_thread = nullptr;
26 26 mutex->WakeupAllWaitingThreads();
27 // Find the next waiting thread for the mutex...
28 auto next_thread = mutex->WakeupNextThread();
29 if (next_thread != nullptr) {
30 mutex->Acquire(next_thread);
31 }
32} 27}
33 28
34void ReleaseThreadMutexes(Thread* thread) { 29void ReleaseThreadMutexes(Thread* thread) {
@@ -94,8 +89,6 @@ void Mutex::Release() {
94 ResumeWaitingThread(this); 89 ResumeWaitingThread(this);
95 } 90 }
96 } 91 }
97
98 HLE::Reschedule(__func__);
99} 92}
100 93
101} // namespace 94} // namespace
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index 201ec0db9..1b8249c74 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -81,13 +81,13 @@ public:
81 s32 max_timers = 0; 81 s32 max_timers = 0;
82 s32 max_shared_mems = 0; 82 s32 max_shared_mems = 0;
83 s32 max_address_arbiters = 0; 83 s32 max_address_arbiters = 0;
84 84
85 /// Max CPU time that the processes in this category can utilize 85 /// Max CPU time that the processes in this category can utilize
86 s32 max_cpu_time = 0; 86 s32 max_cpu_time = 0;
87 87
88 // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind that 88 // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind that
89 // APPLICATION resource limits should not be affected by the objects created by service modules. 89 // APPLICATION resource limits should not be affected by the objects created by service modules.
90 // Currently we have no way of distinguishing if a Create was called by the running application, 90 // Currently we have no way of distinguishing if a Create was called by the running application,
91 // or by a service module. Approach this once we have separated the service modules into their own processes 91 // or by a service module. Approach this once we have separated the service modules into their own processes
92 92
93 /// Current memory that the processes in this category are using 93 /// Current memory that the processes in this category are using
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index dbb4c9b7f..4b359ed07 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -42,19 +42,13 @@ void Semaphore::Acquire() {
42 42
43ResultVal<s32> Semaphore::Release(s32 release_count) { 43ResultVal<s32> Semaphore::Release(s32 release_count) {
44 if (max_count - available_count < release_count) 44 if (max_count - available_count < release_count)
45 return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, 45 return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel,
46 ErrorSummary::InvalidArgument, ErrorLevel::Permanent); 46 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
47 47
48 s32 previous_count = available_count; 48 s32 previous_count = available_count;
49 available_count += release_count; 49 available_count += release_count;
50 50
51 // Notify some of the threads that the semaphore has been released 51 WakeupAllWaitingThreads();
52 // stop once the semaphore is full again or there are no more waiting threads
53 while (!ShouldWait() && WakeupNextThread() != nullptr) {
54 Acquire();
55 }
56
57 HLE::Reschedule(__func__);
58 52
59 return MakeResult<s32>(previous_count); 53 return MakeResult<s32>(previous_count);
60} 54}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 690d33b55..4729a7fe0 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -13,6 +13,7 @@
13#include "common/thread_queue_list.h" 13#include "common/thread_queue_list.h"
14 14
15#include "core/arm/arm_interface.h" 15#include "core/arm/arm_interface.h"
16#include "core/arm/skyeye_common/armdefs.h"
16#include "core/core.h" 17#include "core/core.h"
17#include "core/core_timing.h" 18#include "core/core_timing.h"
18#include "core/hle/hle.h" 19#include "core/hle/hle.h"
@@ -100,7 +101,7 @@ void Thread::Stop() {
100 } 101 }
101 102
102 status = THREADSTATUS_DEAD; 103 status = THREADSTATUS_DEAD;
103 104
104 WakeupAllWaitingThreads(); 105 WakeupAllWaitingThreads();
105 106
106 // Clean up any dangling references in objects that this thread was waiting for 107 // Clean up any dangling references in objects that this thread was waiting for
@@ -169,7 +170,7 @@ static void PriorityBoostStarvedThreads() {
169 } 170 }
170} 171}
171 172
172/** 173/**
173 * Switches the CPU's active thread context to that of the specified thread 174 * Switches the CPU's active thread context to that of the specified thread
174 * @param new_thread The thread to switch to 175 * @param new_thread The thread to switch to
175 */ 176 */
@@ -193,8 +194,22 @@ static void SwitchContext(Thread* new_thread) {
193 if (new_thread) { 194 if (new_thread) {
194 DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running."); 195 DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running.");
195 196
197 // Cancel any outstanding wakeup events for this thread
198 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle);
199
196 current_thread = new_thread; 200 current_thread = new_thread;
197 201
202 // If the thread was waited by a svcWaitSynch call, step back PC by one instruction to rerun
203 // the SVC when the thread wakes up. This is necessary to ensure that the thread can acquire
204 // the requested wait object(s) before continuing.
205 if (new_thread->waitsynch_waited) {
206 // CPSR flag indicates CPU mode
207 bool thumb_mode = (new_thread->context.cpsr & TBIT) != 0;
208
209 // SVC instruction is 2 bytes for THUMB, 4 bytes for ARM
210 new_thread->context.pc -= thumb_mode ? 2 : 4;
211 }
212
198 ready_queue.remove(new_thread->current_priority, new_thread); 213 ready_queue.remove(new_thread->current_priority, new_thread);
199 new_thread->status = THREADSTATUS_RUNNING; 214 new_thread->status = THREADSTATUS_RUNNING;
200 215
@@ -243,6 +258,7 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa
243 thread->wait_set_output = wait_set_output; 258 thread->wait_set_output = wait_set_output;
244 thread->wait_all = wait_all; 259 thread->wait_all = wait_all;
245 thread->wait_objects = std::move(wait_objects); 260 thread->wait_objects = std::move(wait_objects);
261 thread->waitsynch_waited = true;
246 thread->status = THREADSTATUS_WAIT_SYNCH; 262 thread->status = THREADSTATUS_WAIT_SYNCH;
247} 263}
248 264
@@ -268,6 +284,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
268 return; 284 return;
269 } 285 }
270 286
287 thread->waitsynch_waited = false;
288
271 if (thread->status == THREADSTATUS_WAIT_SYNCH) { 289 if (thread->status == THREADSTATUS_WAIT_SYNCH) {
272 thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, 290 thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
273 ErrorSummary::StatusChanged, ErrorLevel::Info)); 291 ErrorSummary::StatusChanged, ErrorLevel::Info));
@@ -288,63 +306,20 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
288 CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, callback_handle); 306 CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, callback_handle);
289} 307}
290 308
291void Thread::ReleaseWaitObject(WaitObject* wait_object) {
292 if (status != THREADSTATUS_WAIT_SYNCH || wait_objects.empty()) {
293 LOG_CRITICAL(Kernel, "thread is not waiting on any objects!");
294 return;
295 }
296
297 // Remove this thread from the waiting object's thread list
298 wait_object->RemoveWaitingThread(this);
299
300 unsigned index = 0;
301 bool wait_all_failed = false; // Will be set to true if any object is unavailable
302
303 // Iterate through all waiting objects to check availability...
304 for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) {
305 if ((*itr)->ShouldWait())
306 wait_all_failed = true;
307
308 // The output should be the last index of wait_object
309 if (*itr == wait_object)
310 index = itr - wait_objects.begin();
311 }
312
313 // If we are waiting on all objects...
314 if (wait_all) {
315 // Resume the thread only if all are available...
316 if (!wait_all_failed) {
317 SetWaitSynchronizationResult(RESULT_SUCCESS);
318 SetWaitSynchronizationOutput(-1);
319
320 ResumeFromWait();
321 }
322 } else {
323 // Otherwise, resume
324 SetWaitSynchronizationResult(RESULT_SUCCESS);
325
326 if (wait_set_output)
327 SetWaitSynchronizationOutput(index);
328
329 ResumeFromWait();
330 }
331}
332
333void Thread::ResumeFromWait() { 309void Thread::ResumeFromWait() {
334 // Cancel any outstanding wakeup events for this thread
335 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
336
337 switch (status) { 310 switch (status) {
338 case THREADSTATUS_WAIT_SYNCH: 311 case THREADSTATUS_WAIT_SYNCH:
339 // Remove this thread from all other WaitObjects
340 for (auto wait_object : wait_objects)
341 wait_object->RemoveWaitingThread(this);
342 break;
343 case THREADSTATUS_WAIT_ARB: 312 case THREADSTATUS_WAIT_ARB:
344 case THREADSTATUS_WAIT_SLEEP: 313 case THREADSTATUS_WAIT_SLEEP:
345 break; 314 break;
346 case THREADSTATUS_RUNNING: 315
347 case THREADSTATUS_READY: 316 case THREADSTATUS_READY:
317 // If the thread is waiting on multiple wait objects, it might be awoken more than once
318 // before actually resuming. We can ignore subsequent wakeups if the thread status has
319 // already been set to THREADSTATUS_READY.
320 return;
321
322 case THREADSTATUS_RUNNING:
348 DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId()); 323 DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId());
349 return; 324 return;
350 case THREADSTATUS_DEAD: 325 case THREADSTATUS_DEAD:
@@ -353,7 +328,7 @@ void Thread::ResumeFromWait() {
353 GetObjectId()); 328 GetObjectId());
354 return; 329 return;
355 } 330 }
356 331
357 ready_queue.push_back(current_priority, this); 332 ready_queue.push_back(current_priority, this);
358 status = THREADSTATUS_READY; 333 status = THREADSTATUS_READY;
359} 334}
@@ -415,6 +390,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
415 thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom(); 390 thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom();
416 thread->owner_process = g_current_process; 391 thread->owner_process = g_current_process;
417 thread->tls_index = -1; 392 thread->tls_index = -1;
393 thread->waitsynch_waited = false;
418 394
419 // Find the next available TLS index, and mark it as used 395 // Find the next available TLS index, and mark it as used
420 auto& used_tls_slots = Kernel::g_current_process->used_tls_slots; 396 auto& used_tls_slots = Kernel::g_current_process->used_tls_slots;
@@ -504,7 +480,7 @@ void Reschedule() {
504 } else if (next) { 480 } else if (next) {
505 LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId()); 481 LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId());
506 } 482 }
507 483
508 SwitchContext(next); 484 SwitchContext(next);
509} 485}
510 486
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 389928178..b8160bb2c 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -94,12 +94,6 @@ public:
94 * @return The thread's ID 94 * @return The thread's ID
95 */ 95 */
96 u32 GetThreadId() const { return thread_id; } 96 u32 GetThreadId() const { return thread_id; }
97
98 /**
99 * Release an acquired wait object
100 * @param wait_object WaitObject to release
101 */
102 void ReleaseWaitObject(WaitObject* wait_object);
103 97
104 /** 98 /**
105 * Resumes a thread from waiting 99 * Resumes a thread from waiting
@@ -152,6 +146,8 @@ public:
152 146
153 s32 tls_index; ///< Index of the Thread Local Storage of the thread 147 s32 tls_index; ///< Index of the Thread Local Storage of the thread
154 148
149 bool waitsynch_waited; ///< Set to true if the last svcWaitSynch call caused the thread to wait
150
155 /// Mutexes currently held by this thread, which will be released when it exits. 151 /// Mutexes currently held by this thread, which will be released when it exits.
156 boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; 152 boost::container::flat_set<SharedPtr<Mutex>> held_mutexes;
157 153
@@ -163,12 +159,12 @@ public:
163 159
164 std::string name; 160 std::string name;
165 161
162 /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
163 Handle callback_handle;
164
166private: 165private:
167 Thread(); 166 Thread();
168 ~Thread() override; 167 ~Thread() override;
169
170 /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
171 Handle callback_handle;
172}; 168};
173 169
174/** 170/**
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 25d066bf1..8aa4110a6 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -88,7 +88,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
88 if (timer->interval_delay != 0) { 88 if (timer->interval_delay != 0) {
89 // Reschedule the timer with the interval delay 89 // Reschedule the timer with the interval delay
90 u64 interval_microseconds = timer->interval_delay / 1000; 90 u64 interval_microseconds = timer->interval_delay / 1000;
91 CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, 91 CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,
92 timer_callback_event_type, timer_handle); 92 timer_callback_event_type, timer_handle);
93 } 93 }
94} 94}
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
new file mode 100644
index 000000000..b2dd21542
--- /dev/null
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -0,0 +1,245 @@
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 "common/assert.h"
6
7#include "core/hle/kernel/vm_manager.h"
8#include "core/memory_setup.h"
9
10namespace Kernel {
11
12bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
13 ASSERT(base + size == next.base);
14 if (permissions != next.permissions ||
15 meminfo_state != next.meminfo_state ||
16 type != next.type) {
17 return false;
18 }
19 if (type == VMAType::AllocatedMemoryBlock &&
20 (backing_block != next.backing_block || offset + size != next.offset)) {
21 return false;
22 }
23 if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) {
24 return false;
25 }
26 if (type == VMAType::MMIO && paddr + size != next.paddr) {
27 return false;
28 }
29 return true;
30}
31
32VMManager::VMManager() {
33 Reset();
34}
35
36void VMManager::Reset() {
37 vma_map.clear();
38
39 // Initialize the map with a single free region covering the entire managed space.
40 VirtualMemoryArea initial_vma;
41 initial_vma.size = MAX_ADDRESS;
42 vma_map.emplace(initial_vma.base, initial_vma);
43
44 UpdatePageTableForVMA(initial_vma);
45}
46
47VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
48 return std::prev(vma_map.upper_bound(target));
49}
50
51ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
52 std::shared_ptr<std::vector<u8>> block, u32 offset, u32 size, MemoryState state) {
53 ASSERT(block != nullptr);
54 ASSERT(offset + size <= block->size());
55
56 // This is the appropriately sized VMA that will turn into our allocation.
57 CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
58 VirtualMemoryArea& final_vma = vma_handle->second;
59 ASSERT(final_vma.size == size);
60
61 final_vma.type = VMAType::AllocatedMemoryBlock;
62 final_vma.permissions = VMAPermission::ReadWrite;
63 final_vma.meminfo_state = state;
64 final_vma.backing_block = block;
65 final_vma.offset = offset;
66 UpdatePageTableForVMA(final_vma);
67
68 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
69}
70
71ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8 * memory, u32 size, MemoryState state) {
72 ASSERT(memory != nullptr);
73
74 // This is the appropriately sized VMA that will turn into our allocation.
75 CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
76 VirtualMemoryArea& final_vma = vma_handle->second;
77 ASSERT(final_vma.size == size);
78
79 final_vma.type = VMAType::BackingMemory;
80 final_vma.permissions = VMAPermission::ReadWrite;
81 final_vma.meminfo_state = state;
82 final_vma.backing_memory = memory;
83 UpdatePageTableForVMA(final_vma);
84
85 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
86}
87
88ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state) {
89 // This is the appropriately sized VMA that will turn into our allocation.
90 CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
91 VirtualMemoryArea& final_vma = vma_handle->second;
92 ASSERT(final_vma.size == size);
93
94 final_vma.type = VMAType::MMIO;
95 final_vma.permissions = VMAPermission::ReadWrite;
96 final_vma.meminfo_state = state;
97 final_vma.paddr = paddr;
98 UpdatePageTableForVMA(final_vma);
99
100 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
101}
102
103void VMManager::Unmap(VMAHandle vma_handle) {
104 VMAIter iter = StripIterConstness(vma_handle);
105
106 VirtualMemoryArea& vma = iter->second;
107 vma.type = VMAType::Free;
108 vma.permissions = VMAPermission::None;
109 vma.meminfo_state = MemoryState::Free;
110
111 vma.backing_block = nullptr;
112 vma.offset = 0;
113 vma.backing_memory = nullptr;
114 vma.paddr = 0;
115
116 UpdatePageTableForVMA(vma);
117
118 MergeAdjacent(iter);
119}
120
121void VMManager::Reprotect(VMAHandle vma_handle, VMAPermission new_perms) {
122 VMAIter iter = StripIterConstness(vma_handle);
123
124 VirtualMemoryArea& vma = iter->second;
125 vma.permissions = new_perms;
126 UpdatePageTableForVMA(vma);
127
128 MergeAdjacent(iter);
129}
130
131VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) {
132 // This uses a neat C++ trick to convert a const_iterator to a regular iterator, given
133 // non-const access to its container.
134 return vma_map.erase(iter, iter); // Erases an empty range of elements
135}
136
137ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
138 ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: %8X", size);
139 ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: %08X", base);
140
141 VMAIter vma_handle = StripIterConstness(FindVMA(base));
142 if (vma_handle == vma_map.end()) {
143 // Target address is outside the range managed by the kernel
144 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
145 ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E01BF5
146 }
147
148 VirtualMemoryArea& vma = vma_handle->second;
149 if (vma.type != VMAType::Free) {
150 // Region is already allocated
151 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
152 ErrorSummary::InvalidState, ErrorLevel::Usage); // 0xE0A01BF5
153 }
154
155 u32 start_in_vma = base - vma.base;
156 u32 end_in_vma = start_in_vma + size;
157
158 if (end_in_vma > vma.size) {
159 // Requested allocation doesn't fit inside VMA
160 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
161 ErrorSummary::InvalidState, ErrorLevel::Usage); // 0xE0A01BF5
162 }
163
164 if (end_in_vma != vma.size) {
165 // Split VMA at the end of the allocated region
166 SplitVMA(vma_handle, end_in_vma);
167 }
168 if (start_in_vma != 0) {
169 // Split VMA at the start of the allocated region
170 vma_handle = SplitVMA(vma_handle, start_in_vma);
171 }
172
173 return MakeResult<VMAIter>(vma_handle);
174}
175
176VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u32 offset_in_vma) {
177 VirtualMemoryArea& old_vma = vma_handle->second;
178 VirtualMemoryArea new_vma = old_vma; // Make a copy of the VMA
179
180 // For now, don't allow no-op VMA splits (trying to split at a boundary) because it's probably
181 // a bug. This restriction might be removed later.
182 ASSERT(offset_in_vma < old_vma.size);
183 ASSERT(offset_in_vma > 0);
184
185 old_vma.size = offset_in_vma;
186 new_vma.base += offset_in_vma;
187 new_vma.size -= offset_in_vma;
188
189 switch (new_vma.type) {
190 case VMAType::Free:
191 break;
192 case VMAType::AllocatedMemoryBlock:
193 new_vma.offset += offset_in_vma;
194 break;
195 case VMAType::BackingMemory:
196 new_vma.backing_memory += offset_in_vma;
197 break;
198 case VMAType::MMIO:
199 new_vma.paddr += offset_in_vma;
200 break;
201 }
202
203 ASSERT(old_vma.CanBeMergedWith(new_vma));
204
205 return vma_map.emplace_hint(std::next(vma_handle), new_vma.base, new_vma);
206}
207
208VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) {
209 VMAIter next_vma = std::next(iter);
210 if (next_vma != vma_map.end() && iter->second.CanBeMergedWith(next_vma->second)) {
211 iter->second.size += next_vma->second.size;
212 vma_map.erase(next_vma);
213 }
214
215 if (iter != vma_map.begin()) {
216 VMAIter prev_vma = std::prev(iter);
217 if (prev_vma->second.CanBeMergedWith(iter->second)) {
218 prev_vma->second.size += iter->second.size;
219 vma_map.erase(iter);
220 iter = prev_vma;
221 }
222 }
223
224 return iter;
225}
226
227void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
228 switch (vma.type) {
229 case VMAType::Free:
230 Memory::UnmapRegion(vma.base, vma.size);
231 break;
232 case VMAType::AllocatedMemoryBlock:
233 Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_block->data() + vma.offset);
234 break;
235 case VMAType::BackingMemory:
236 Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_memory);
237 break;
238 case VMAType::MMIO:
239 // TODO(yuriks): Add support for MMIO handlers.
240 Memory::MapIoRegion(vma.base, vma.size);
241 break;
242 }
243}
244
245}
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
new file mode 100644
index 000000000..22b724603
--- /dev/null
+++ b/src/core/hle/kernel/vm_manager.h
@@ -0,0 +1,200 @@
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 <map>
8#include <memory>
9#include <string>
10#include <vector>
11
12#include "common/common_types.h"
13
14#include "core/hle/result.h"
15
16namespace Kernel {
17
18enum class VMAType : u8 {
19 /// VMA represents an unmapped region of the address space.
20 Free,
21 /// VMA is backed by a ref-counted allocate memory block.
22 AllocatedMemoryBlock,
23 /// VMA is backed by a raw, unmanaged pointer.
24 BackingMemory,
25 /// VMA is mapped to MMIO registers at a fixed PAddr.
26 MMIO,
27 // TODO(yuriks): Implement MemoryAlias to support MAP/UNMAP
28};
29
30/// Permissions for mapped memory blocks
31enum class VMAPermission : u8 {
32 None = 0,
33 Read = 1,
34 Write = 2,
35 Execute = 4,
36
37 ReadWrite = Read | Write,
38 ReadExecute = Read | Execute,
39 WriteExecute = Write | Execute,
40 ReadWriteExecute = Read | Write | Execute,
41};
42
43/// Set of values returned in MemoryInfo.state by svcQueryMemory.
44enum class MemoryState : u8 {
45 Free = 0,
46 Reserved = 1,
47 IO = 2,
48 Static = 3,
49 Code = 4,
50 Private = 5,
51 Shared = 6,
52 Continuous = 7,
53 Aliased = 8,
54 Alias = 9,
55 AliasCode = 10,
56 Locked = 11,
57};
58
59/**
60 * Represents a VMA in an address space. A VMA is a contiguous region of virtual addressing space
61 * with homogeneous attributes across its extents. In this particular implementation each VMA is
62 * also backed by a single host memory allocation.
63 */
64struct VirtualMemoryArea {
65 /// Virtual base address of the region.
66 VAddr base = 0;
67 /// Size of the region.
68 u32 size = 0;
69
70 VMAType type = VMAType::Free;
71 VMAPermission permissions = VMAPermission::None;
72 /// Tag returned by svcQueryMemory. Not otherwise used.
73 MemoryState meminfo_state = MemoryState::Free;
74
75 // Settings for type = AllocatedMemoryBlock
76 /// Memory block backing this VMA.
77 std::shared_ptr<std::vector<u8>> backing_block = nullptr;
78 /// Offset into the backing_memory the mapping starts from.
79 u32 offset = 0;
80
81 // Settings for type = BackingMemory
82 /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed.
83 u8* backing_memory = nullptr;
84
85 // Settings for type = MMIO
86 /// Physical address of the register area this VMA maps to.
87 PAddr paddr = 0;
88
89 /// Tests if this area can be merged to the right with `next`.
90 bool CanBeMergedWith(const VirtualMemoryArea& next) const;
91};
92
93/**
94 * Manages a process' virtual addressing space. This class maintains a list of allocated and free
95 * regions in the address space, along with their attributes, and allows kernel clients to
96 * manipulate it, adjusting the page table to match.
97 *
98 * This is similar in idea and purpose to the VM manager present in operating system kernels, with
99 * the main difference being that it doesn't have to support swapping or memory mapping of files.
100 * The implementation is also simplified by not having to allocate page frames. See these articles
101 * about the Linux kernel for an explantion of the concept and implementation:
102 * - http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/
103 * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/
104 */
105class VMManager {
106 // TODO(yuriks): Make page tables switchable to support multiple VMManagers
107public:
108 /**
109 * The maximum amount of address space managed by the kernel. Addresses above this are never used.
110 * @note This is the limit used by the New 3DS kernel. Old 3DS used 0x20000000.
111 */
112 static const u32 MAX_ADDRESS = 0x40000000;
113
114 /**
115 * A map covering the entirety of the managed address space, keyed by the `base` field of each
116 * VMA. It must always be modified by splitting or merging VMAs, so that the invariant
117 * `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be
118 * merged when possible so that no two similar and adjacent regions exist that have not been
119 * merged.
120 */
121 std::map<VAddr, VirtualMemoryArea> vma_map;
122 using VMAHandle = decltype(vma_map)::const_iterator;
123
124 VMManager();
125
126 /// Clears the address space map, re-initializing with a single free area.
127 void Reset();
128
129 /// Finds the VMA in which the given address is included in, or `vma_map.end()`.
130 VMAHandle FindVMA(VAddr target) const;
131
132 // TODO(yuriks): Should these functions actually return the handle?
133
134 /**
135 * Maps part of a ref-counted block of memory at a given address.
136 *
137 * @param target The guest address to start the mapping at.
138 * @param block The block to be mapped.
139 * @param offset Offset into `block` to map from.
140 * @param size Size of the mapping.
141 * @param state MemoryState tag to attach to the VMA.
142 */
143 ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block,
144 u32 offset, u32 size, MemoryState state);
145
146 /**
147 * Maps an unmanaged host memory pointer at a given address.
148 *
149 * @param target The guest address to start the mapping at.
150 * @param memory The memory to be mapped.
151 * @param size Size of the mapping.
152 * @param state MemoryState tag to attach to the VMA.
153 */
154 ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u32 size, MemoryState state);
155
156 /**
157 * Maps a memory-mapped IO region at a given address.
158 *
159 * @param target The guest address to start the mapping at.
160 * @param paddr The physical address where the registers are present.
161 * @param size Size of the mapping.
162 * @param state MemoryState tag to attach to the VMA.
163 */
164 ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state);
165
166 /// Unmaps the given VMA.
167 void Unmap(VMAHandle vma);
168
169 /// Changes the permissions of the given VMA.
170 void Reprotect(VMAHandle vma, VMAPermission new_perms);
171
172private:
173 using VMAIter = decltype(vma_map)::iterator;
174
175 /// Converts a VMAHandle to a mutable VMAIter.
176 VMAIter StripIterConstness(const VMAHandle& iter);
177
178 /**
179 * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing
180 * the appropriate error checking.
181 */
182 ResultVal<VMAIter> CarveVMA(VAddr base, u32 size);
183
184 /**
185 * Splits a VMA in two, at the specified offset.
186 * @returns the right side of the split, with the original iterator becoming the left side.
187 */
188 VMAIter SplitVMA(VMAIter vma, u32 offset_in_vma);
189
190 /**
191 * Checks for and merges the specified VMA with adjacent ones if possible.
192 * @returns the merged VMA or the original if no merging was possible.
193 */
194 VMAIter MergeAdjacent(VMAIter vma);
195
196 /// Updates the pages corresponding to this VMA so they match the VMA's attributes.
197 void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
198};
199
200}
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
new file mode 100644
index 000000000..57dc1ece7
--- /dev/null
+++ b/src/core/hle/service/am/am.cpp
@@ -0,0 +1,55 @@
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 "common/logging/log.h"
6
7#include "core/hle/service/service.h"
8#include "core/hle/service/am/am_app.h"
9#include "core/hle/service/am/am_net.h"
10#include "core/hle/service/am/am_sys.h"
11
12#include "core/hle/hle.h"
13#include "core/hle/kernel/event.h"
14#include "core/hle/kernel/shared_memory.h"
15
16namespace Service {
17namespace AM {
18
19void TitleIDListGetTotal(Service::Interface* self) {
20 u32* cmd_buff = Kernel::GetCommandBuffer();
21 u32 media_type = cmd_buff[1] & 0xFF;
22
23 cmd_buff[1] = RESULT_SUCCESS.raw;
24 cmd_buff[2] = 0;
25
26 LOG_WARNING(Service_AM, "(STUBBED) media_type %u", media_type);
27}
28
29void GetTitleIDList(Service::Interface* self) {
30 u32* cmd_buff = Kernel::GetCommandBuffer();
31 u32 num_titles = cmd_buff[1];
32 u32 media_type = cmd_buff[2] & 0xFF;
33 u32 addr = cmd_buff[4];
34
35 cmd_buff[1] = RESULT_SUCCESS.raw;
36 cmd_buff[2] = 0;
37
38 LOG_WARNING(Service_AM, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type);
39}
40
41void Init() {
42 using namespace Kernel;
43
44 AddService(new AM_APP_Interface);
45 AddService(new AM_NET_Interface);
46 AddService(new AM_SYS_Interface);
47}
48
49void Shutdown() {
50
51}
52
53} // namespace AM
54
55} // namespace Service
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
new file mode 100644
index 000000000..063b8bd09
--- /dev/null
+++ b/src/core/hle/service/am/am.h
@@ -0,0 +1,47 @@
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 "core/hle/kernel/kernel.h"
8#include "core/hle/service/service.h"
9
10namespace Service {
11namespace AM {
12
13/**
14 * AM::TitleIDListGetTotal service function
15 * Gets the number of installed titles in the requested media type
16 * Inputs:
17 * 0 : Command header (0x00010040)
18 * 1 : Media type to load the titles from
19 * Outputs:
20 * 1 : Result, 0 on success, otherwise error code
21 * 2 : The number of titles in the requested media type
22 */
23void TitleIDListGetTotal(Service::Interface* self);
24
25/**
26 * AM::GetTitleIDList service function
27 * Loads information about the desired number of titles from the desired media type into an array
28 * Inputs:
29 * 0 : Command header (0x00020082)
30 * 1 : The maximum number of titles to load
31 * 2 : Media type to load the titles from
32 * 3 : Descriptor of the output buffer pointer
33 * 4 : Address of the output buffer
34 * Outputs:
35 * 1 : Result, 0 on success, otherwise error code
36 * 2 : The number of titles loaded from the requested media type
37 */
38void GetTitleIDList(Service::Interface* self);
39
40/// Initialize AM service
41void Init();
42
43/// Shutdown AM service
44void Shutdown();
45
46} // namespace AM
47} // namespace Service
diff --git a/src/core/hle/service/am/am_app.cpp b/src/core/hle/service/am/am_app.cpp
new file mode 100644
index 000000000..c6fc81bc3
--- /dev/null
+++ b/src/core/hle/service/am/am_app.cpp
@@ -0,0 +1,20 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/hle.h"
6#include "core/hle/service/am/am.h"
7#include "core/hle/service/am/am_app.h"
8
9namespace Service {
10namespace AM {
11
12// Empty arrays are illegal -- commented out until an entry is added.
13//const Interface::FunctionInfo FunctionTable[] = { };
14
15AM_APP_Interface::AM_APP_Interface() {
16 //Register(FunctionTable);
17}
18
19} // namespace AM
20} // namespace Service
diff --git a/src/core/hle/service/am/am_app.h b/src/core/hle/service/am/am_app.h
new file mode 100644
index 000000000..fd6017d14
--- /dev/null
+++ b/src/core/hle/service/am/am_app.h
@@ -0,0 +1,22 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included..
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9namespace Service {
10namespace AM {
11
12class AM_APP_Interface : public Service::Interface {
13public:
14 AM_APP_Interface();
15
16 std::string GetPortName() const override {
17 return "am:app";
18 }
19};
20
21} // namespace AM
22} // namespace Service
diff --git a/src/core/hle/service/am_net.cpp b/src/core/hle/service/am/am_net.cpp
index ba2a499f1..b1af0e9d8 100644
--- a/src/core/hle/service/am_net.cpp
+++ b/src/core/hle/service/am/am_net.cpp
@@ -3,12 +3,11 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/hle.h" 5#include "core/hle/hle.h"
6#include "core/hle/service/am_net.h" 6#include "core/hle/service/am/am.h"
7#include "core/hle/service/am/am_net.h"
7 8
8//////////////////////////////////////////////////////////////////////////////////////////////////// 9namespace Service {
9// Namespace AM_NET 10namespace AM {
10
11namespace AM_NET {
12 11
13const Interface::FunctionInfo FunctionTable[] = { 12const Interface::FunctionInfo FunctionTable[] = {
14 {0x08010000, nullptr, "OpenTicket"}, 13 {0x08010000, nullptr, "OpenTicket"},
@@ -33,11 +32,9 @@ const Interface::FunctionInfo FunctionTable[] = {
33 {0x081B00C2, nullptr, "InstallTitlesFinish"}, 32 {0x081B00C2, nullptr, "InstallTitlesFinish"},
34}; 33};
35 34
36//////////////////////////////////////////////////////////////////////////////////////////////////// 35AM_NET_Interface::AM_NET_Interface() {
37// Interface class
38
39Interface::Interface() {
40 Register(FunctionTable); 36 Register(FunctionTable);
41} 37}
42 38
43} // namespace 39} // namespace AM
40} // namespace Service
diff --git a/src/core/hle/service/am/am_net.h b/src/core/hle/service/am/am_net.h
new file mode 100644
index 000000000..25d2c3f23
--- /dev/null
+++ b/src/core/hle/service/am/am_net.h
@@ -0,0 +1,22 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included..
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9namespace Service {
10namespace AM {
11
12class AM_NET_Interface : public Service::Interface {
13public:
14 AM_NET_Interface();
15
16 std::string GetPortName() const override {
17 return "am:net";
18 }
19};
20
21} // namespace AM
22} // namespace Service
diff --git a/src/core/hle/service/am/am_sys.cpp b/src/core/hle/service/am/am_sys.cpp
new file mode 100644
index 000000000..864fc14df
--- /dev/null
+++ b/src/core/hle/service/am/am_sys.cpp
@@ -0,0 +1,22 @@
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 "core/hle/hle.h"
6#include "core/hle/service/am/am.h"
7#include "core/hle/service/am/am_sys.h"
8
9namespace Service {
10namespace AM {
11
12const Interface::FunctionInfo FunctionTable[] = {
13 {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"},
14 {0x00020082, GetTitleIDList, "GetTitleIDList"},
15};
16
17AM_SYS_Interface::AM_SYS_Interface() {
18 Register(FunctionTable);
19}
20
21} // namespace AM
22} // namespace Service
diff --git a/src/core/hle/service/am/am_sys.h b/src/core/hle/service/am/am_sys.h
new file mode 100644
index 000000000..b114f1d35
--- /dev/null
+++ b/src/core/hle/service/am/am_sys.h
@@ -0,0 +1,22 @@
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 "core/hle/service/service.h"
8
9namespace Service {
10namespace AM {
11
12class AM_SYS_Interface : public Service::Interface {
13public:
14 AM_SYS_Interface();
15
16 std::string GetPortName() const override {
17 return "am:sys";
18 }
19};
20
21} // namespace AM
22} // namespace Service
diff --git a/src/core/hle/service/am/am_u.cpp b/src/core/hle/service/am/am_u.cpp
new file mode 100644
index 000000000..6bf84b36b
--- /dev/null
+++ b/src/core/hle/service/am/am_u.cpp
@@ -0,0 +1,22 @@
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 "core/hle/hle.h"
6#include "core/hle/service/am/am.h"
7#include "core/hle/service/am/am_u.h"
8
9namespace Service {
10namespace AM {
11
12const Interface::FunctionInfo FunctionTable[] = {
13 {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"},
14 {0x00020082, GetTitleIDList, "GetTitleIDList"},
15};
16
17AM_U_Interface::AM_U_Interface() {
18 Register(FunctionTable);
19}
20
21} // namespace AM
22} // namespace Service
diff --git a/src/core/hle/service/am/am_u.h b/src/core/hle/service/am/am_u.h
new file mode 100644
index 000000000..3b2454b6c
--- /dev/null
+++ b/src/core/hle/service/am/am_u.h
@@ -0,0 +1,22 @@
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 "core/hle/service/service.h"
8
9namespace Service {
10namespace AM {
11
12class AM_U_Interface : public Service::Interface {
13public:
14 AM_U_Interface();
15
16 std::string GetPortName() const override {
17 return "am:u";
18 }
19};
20
21} // namespace AM
22} // namespace Service
diff --git a/src/core/hle/service/am_app.cpp b/src/core/hle/service/am_app.cpp
deleted file mode 100644
index 684b753f0..000000000
--- a/src/core/hle/service/am_app.cpp
+++ /dev/null
@@ -1,23 +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#include "core/hle/hle.h"
6#include "core/hle/service/am_app.h"
7
8////////////////////////////////////////////////////////////////////////////////////////////////////
9// Namespace AM_APP
10
11namespace AM_APP {
12
13// Empty arrays are illegal -- commented out until an entry is added.
14//const Interface::FunctionInfo FunctionTable[] = { };
15
16////////////////////////////////////////////////////////////////////////////////////////////////////
17// Interface class
18
19Interface::Interface() {
20 //Register(FunctionTable);
21}
22
23} // namespace
diff --git a/src/core/hle/service/am_app.h b/src/core/hle/service/am_app.h
deleted file mode 100644
index 50dc2f5a2..000000000
--- a/src/core/hle/service/am_app.h
+++ /dev/null
@@ -1,23 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace AM_APP
11
12namespace AM_APP {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "am:app";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/am_net.h b/src/core/hle/service/am_net.h
deleted file mode 100644
index 616c33ee8..000000000
--- a/src/core/hle/service/am_net.h
+++ /dev/null
@@ -1,23 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace AM_NET
11
12namespace AM_NET {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "am:net";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/am_sys.cpp b/src/core/hle/service/am_sys.cpp
deleted file mode 100644
index f9e3fe4b7..000000000
--- a/src/core/hle/service/am_sys.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
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 "common/logging/log.h"
6
7#include "core/hle/hle.h"
8#include "core/hle/service/am_sys.h"
9
10namespace AM_SYS {
11
12/**
13 * Gets the number of installed titles in the requested media type
14 * Inputs:
15 * 0: Command header (0x00010040)
16 * 1: Media type to load the titles from
17 * Outputs:
18 * 1: Result, 0 on success, otherwise error code
19 * 2: The number of titles in the requested media type
20 */
21static void TitleIDListGetTotal(Service::Interface* self) {
22 u32* cmd_buff = Kernel::GetCommandBuffer();
23 u32 media_type = cmd_buff[1] & 0xFF;
24
25 cmd_buff[1] = RESULT_SUCCESS.raw;
26 cmd_buff[2] = 0;
27 LOG_WARNING(Service_CFG, "(STUBBED) media_type %u", media_type);
28}
29
30/**
31 * Loads information about the desired number of titles from the desired media type into an array
32 * Inputs:
33 * 0: Command header (0x00020082)
34 * 1: The maximum number of titles to load
35 * 2: Media type to load the titles from
36 * 3: Descriptor of the output buffer pointer
37 * 4: Address of the output buffer
38 * Outputs:
39 * 1: Result, 0 on success, otherwise error code
40 * 2: The number of titles loaded from the requested media type
41 */
42static void GetTitleIDList(Service::Interface* self) {
43 u32* cmd_buff = Kernel::GetCommandBuffer();
44 u32 num_titles = cmd_buff[1];
45 u32 media_type = cmd_buff[2] & 0xFF;
46 u32 addr = cmd_buff[4];
47
48 cmd_buff[1] = RESULT_SUCCESS.raw;
49 cmd_buff[2] = 0;
50 LOG_WARNING(Service_CFG, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type);
51}
52
53const Interface::FunctionInfo FunctionTable[] = {
54 {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"},
55 {0x00020082, GetTitleIDList, "GetTitleIDList"},
56};
57
58Interface::Interface() {
59 Register(FunctionTable);
60}
61
62} // namespace
diff --git a/src/core/hle/service/am_sys.h b/src/core/hle/service/am_sys.h
deleted file mode 100644
index bb6178a43..000000000
--- a/src/core/hle/service/am_sys.h
+++ /dev/null
@@ -1,23 +0,0 @@
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 "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace AM_SYS
11
12namespace AM_SYS {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "am:sys";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 3fd4cfb08..5d14f393d 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -151,7 +151,7 @@ void SendParameter(Service::Interface* self) {
151 u32 handle = cmd_buff[6]; 151 u32 handle = cmd_buff[6];
152 u32 size = cmd_buff[7]; 152 u32 size = cmd_buff[7];
153 u32 in_param_buffer_ptr = cmd_buff[8]; 153 u32 in_param_buffer_ptr = cmd_buff[8];
154 154
155 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 155 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
156 156
157 LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," 157 LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
@@ -283,7 +283,7 @@ void Init() {
283 AddService(new APT_A_Interface); 283 AddService(new APT_A_Interface);
284 AddService(new APT_S_Interface); 284 AddService(new APT_S_Interface);
285 AddService(new APT_U_Interface); 285 AddService(new APT_U_Interface);
286 286
287 // Load the shared system font (if available). 287 // Load the shared system font (if available).
288 // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header 288 // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header
289 // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided 289 // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index e7fa39325..a03e1712a 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -63,7 +63,7 @@ void Initialize(Service::Interface* self);
63 * 4 : Handle to shared font memory 63 * 4 : Handle to shared font memory
64 */ 64 */
65void GetSharedFont(Service::Interface* self); 65void GetSharedFont(Service::Interface* self);
66 66
67/** 67/**
68 * APT::NotifyToWait service function 68 * APT::NotifyToWait service function
69 * Inputs: 69 * Inputs:
@@ -88,7 +88,7 @@ void Enable(Service::Interface* self);
88 * 4 : Home Menu AppId 88 * 4 : Home Menu AppId
89 * 5 : AppID of currently active app 89 * 5 : AppID of currently active app
90 */ 90 */
91void GetAppletManInfo(Service::Interface* self); 91void GetAppletManInfo(Service::Interface* self);
92 92
93/** 93/**
94 * APT::IsRegistered service function. This returns whether the specified AppID is registered with NS yet. 94 * APT::IsRegistered service function. This returns whether the specified AppID is registered with NS yet.
@@ -100,14 +100,14 @@ void GetAppletManInfo(Service::Interface* self);
100 * Outputs: 100 * Outputs:
101 * 0 : Return header 101 * 0 : Return header
102 * 1 : Result of function, 0 on success, otherwise error code 102 * 1 : Result of function, 0 on success, otherwise error code
103 * 2 : Output, 0 = not registered, 1 = registered. 103 * 2 : Output, 0 = not registered, 1 = registered.
104 */ 104 */
105void IsRegistered(Service::Interface* self); 105void IsRegistered(Service::Interface* self);
106 106
107void InquireNotification(Service::Interface* self); 107void InquireNotification(Service::Interface* self);
108 108
109/** 109/**
110 * APT::SendParameter service function. This sets the parameter data state. 110 * APT::SendParameter service function. This sets the parameter data state.
111 * Inputs: 111 * Inputs:
112 * 1 : Source AppID 112 * 1 : Source AppID
113 * 2 : Destination AppID 113 * 2 : Destination AppID
diff --git a/src/core/hle/service/boss/boss.cpp b/src/core/hle/service/boss/boss.cpp
new file mode 100644
index 000000000..d38140f19
--- /dev/null
+++ b/src/core/hle/service/boss/boss.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 "core/hle/service/service.h"
6#include "core/hle/service/boss/boss.h"
7#include "core/hle/service/boss/boss_p.h"
8#include "core/hle/service/boss/boss_u.h"
9
10#include "core/hle/kernel/event.h"
11#include "core/hle/kernel/shared_memory.h"
12#include "core/hle/hle.h"
13
14namespace Service {
15namespace BOSS {
16
17void Init() {
18 using namespace Kernel;
19
20 AddService(new BOSS_P_Interface);
21 AddService(new BOSS_U_Interface);
22}
23
24void Shutdown() {
25}
26
27} // namespace BOSS
28
29} // namespace Service
diff --git a/src/core/hle/service/boss/boss.h b/src/core/hle/service/boss/boss.h
new file mode 100644
index 000000000..a6942ada6
--- /dev/null
+++ b/src/core/hle/service/boss/boss.h
@@ -0,0 +1,20 @@
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 "core/hle/kernel/kernel.h"
8#include "core/hle/service/service.h"
9
10namespace Service {
11namespace BOSS {
12
13/// Initialize BOSS service(s)
14void Init();
15
16/// Shutdown BOSS service(s)
17void Shutdown();
18
19} // namespace BOSS
20} // namespace Service
diff --git a/src/core/hle/service/boss/boss_p.cpp b/src/core/hle/service/boss/boss_p.cpp
new file mode 100644
index 000000000..089f5f186
--- /dev/null
+++ b/src/core/hle/service/boss/boss_p.cpp
@@ -0,0 +1,20 @@
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 "core/hle/hle.h"
6#include "core/hle/service/boss/boss.h"
7#include "core/hle/service/boss/boss_p.h"
8
9namespace Service {
10namespace BOSS {
11
12// Empty arrays are illegal -- commented out until an entry is added.
13// const Interface::FunctionInfo FunctionTable[] = { };
14
15BOSS_P_Interface::BOSS_P_Interface() {
16 //Register(FunctionTable);
17}
18
19} // namespace BOSS
20} // namespace Service
diff --git a/src/core/hle/service/boss/boss_p.h b/src/core/hle/service/boss/boss_p.h
new file mode 100644
index 000000000..32112c251
--- /dev/null
+++ b/src/core/hle/service/boss/boss_p.h
@@ -0,0 +1,22 @@
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 "core/hle/service/service.h"
8
9namespace Service {
10namespace BOSS {
11
12class BOSS_P_Interface : public Service::Interface {
13public:
14 BOSS_P_Interface();
15
16 std::string GetPortName() const override {
17 return "boss:P";
18 }
19};
20
21} // namespace BOSS
22} // namespace Service
diff --git a/src/core/hle/service/boss/boss_u.cpp b/src/core/hle/service/boss/boss_u.cpp
new file mode 100644
index 000000000..ed978b963
--- /dev/null
+++ b/src/core/hle/service/boss/boss_u.cpp
@@ -0,0 +1,21 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/hle.h"
6#include "core/hle/service/boss/boss.h"
7#include "core/hle/service/boss/boss_u.h"
8
9namespace Service {
10namespace BOSS {
11
12const Interface::FunctionInfo FunctionTable[] = {
13 {0x00020100, nullptr, "GetStorageInfo"},
14};
15
16BOSS_U_Interface::BOSS_U_Interface() {
17 Register(FunctionTable);
18}
19
20} // namespace BOSS
21} // namespace Service
diff --git a/src/core/hle/service/boss/boss_u.h b/src/core/hle/service/boss/boss_u.h
new file mode 100644
index 000000000..d047d8cf2
--- /dev/null
+++ b/src/core/hle/service/boss/boss_u.h
@@ -0,0 +1,22 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included..
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9namespace Service {
10namespace BOSS {
11
12class BOSS_U_Interface : public Service::Interface {
13public:
14 BOSS_U_Interface();
15
16 std::string GetPortName() const override {
17 return "boss:U";
18 }
19};
20
21} // namespace BOSS
22} // namespace Service
diff --git a/src/core/hle/service/boss_p.cpp b/src/core/hle/service/boss_p.cpp
deleted file mode 100644
index 8280830e5..000000000
--- a/src/core/hle/service/boss_p.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
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 "core/hle/hle.h"
6#include "core/hle/service/boss_p.h"
7
8////////////////////////////////////////////////////////////////////////////////////////////////////
9// Namespace BOSS_P
10
11namespace BOSS_P {
12
13// Empty arrays are illegal -- commented out until an entry is added.
14// const Interface::FunctionInfo FunctionTable[] = { };
15
16////////////////////////////////////////////////////////////////////////////////////////////////////
17// Interface class
18
19Interface::Interface() {
20 //Register(FunctionTable);
21}
22
23} // namespace
diff --git a/src/core/hle/service/boss_p.h b/src/core/hle/service/boss_p.h
deleted file mode 100644
index 71f1e7464..000000000
--- a/src/core/hle/service/boss_p.h
+++ /dev/null
@@ -1,23 +0,0 @@
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 "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace BOSS_P
11
12namespace BOSS_P {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "boss:P";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/boss_u.cpp b/src/core/hle/service/boss_u.cpp
deleted file mode 100644
index 2c322bdfd..000000000
--- a/src/core/hle/service/boss_u.cpp
+++ /dev/null
@@ -1,24 +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#include "core/hle/hle.h"
6#include "core/hle/service/boss_u.h"
7
8////////////////////////////////////////////////////////////////////////////////////////////////////
9// Namespace BOSS_U
10
11namespace BOSS_U {
12
13const Interface::FunctionInfo FunctionTable[] = {
14 {0x00020100, nullptr, "GetStorageInfo"},
15};
16
17////////////////////////////////////////////////////////////////////////////////////////////////////
18// Interface class
19
20Interface::Interface() {
21 Register(FunctionTable);
22}
23
24} // namespace
diff --git a/src/core/hle/service/boss_u.h b/src/core/hle/service/boss_u.h
deleted file mode 100644
index 2668f2dfd..000000000
--- a/src/core/hle/service/boss_u.h
+++ /dev/null
@@ -1,23 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace BOSS_U
11
12namespace BOSS_U {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "boss:U";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp
new file mode 100644
index 000000000..4f34b699b
--- /dev/null
+++ b/src/core/hle/service/cam/cam.cpp
@@ -0,0 +1,35 @@
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 "common/logging/log.h"
6
7#include "core/hle/service/service.h"
8#include "core/hle/service/cam/cam.h"
9#include "core/hle/service/cam/cam_c.h"
10#include "core/hle/service/cam/cam_q.h"
11#include "core/hle/service/cam/cam_s.h"
12#include "core/hle/service/cam/cam_u.h"
13
14#include "core/hle/kernel/event.h"
15#include "core/hle/kernel/shared_memory.h"
16#include "core/hle/hle.h"
17
18namespace Service {
19namespace CAM {
20
21void Init() {
22 using namespace Kernel;
23
24 AddService(new CAM_C_Interface);
25 AddService(new CAM_Q_Interface);
26 AddService(new CAM_S_Interface);
27 AddService(new CAM_U_Interface);
28}
29
30void Shutdown() {
31}
32
33} // namespace CAM
34
35} // namespace Service
diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h
new file mode 100644
index 000000000..edd524841
--- /dev/null
+++ b/src/core/hle/service/cam/cam.h
@@ -0,0 +1,20 @@
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 "core/hle/kernel/kernel.h"
8#include "core/hle/service/service.h"
9
10namespace Service {
11namespace CAM {
12
13/// Initialize CAM service(s)
14void Init();
15
16/// Shutdown CAM service(s)
17void Shutdown();
18
19} // namespace CAM
20} // namespace Service
diff --git a/src/core/hle/service/cam/cam_c.cpp b/src/core/hle/service/cam/cam_c.cpp
new file mode 100644
index 000000000..d35adcb9f
--- /dev/null
+++ b/src/core/hle/service/cam/cam_c.cpp
@@ -0,0 +1,20 @@
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 "core/hle/hle.h"
6#include "core/hle/service/cam/cam.h"
7#include "core/hle/service/cam/cam_c.h"
8
9namespace Service {
10namespace CAM {
11
12// Empty arrays are illegal -- commented out until an entry is added.
13//const Interface::FunctionInfo FunctionTable[] = { };
14
15CAM_C_Interface::CAM_C_Interface() {
16 //Register(FunctionTable);
17}
18
19} // namespace CAM
20} // namespace Service
diff --git a/src/core/hle/service/cam/cam_c.h b/src/core/hle/service/cam/cam_c.h
new file mode 100644
index 000000000..6b296c00d
--- /dev/null
+++ b/src/core/hle/service/cam/cam_c.h
@@ -0,0 +1,22 @@
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 "core/hle/service/service.h"
8
9namespace Service {
10namespace CAM {
11
12class CAM_C_Interface : public Service::Interface {
13public:
14 CAM_C_Interface();
15
16 std::string GetPortName() const override {
17 return "cam:c";
18 }
19};
20
21} // namespace CAM
22} // namespace Service
diff --git a/src/core/hle/service/cam/cam_q.cpp b/src/core/hle/service/cam/cam_q.cpp
new file mode 100644
index 000000000..c2760a102
--- /dev/null
+++ b/src/core/hle/service/cam/cam_q.cpp
@@ -0,0 +1,20 @@
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 "core/hle/hle.h"
6#include "core/hle/service/cam/cam.h"
7#include "core/hle/service/cam/cam_q.h"
8
9namespace Service {
10namespace CAM {
11
12// Empty arrays are illegal -- commented out until an entry is added.
13//const Interface::FunctionInfo FunctionTable[] = { };
14
15CAM_Q_Interface::CAM_Q_Interface() {
16 //Register(FunctionTable);
17}
18
19} // namespace CAM
20} // namespace Service
diff --git a/src/core/hle/service/cam/cam_q.h b/src/core/hle/service/cam/cam_q.h
new file mode 100644
index 000000000..07cc12534
--- /dev/null
+++ b/src/core/hle/service/cam/cam_q.h
@@ -0,0 +1,22 @@
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 "core/hle/service/service.h"
8
9namespace Service {
10namespace CAM {
11
12class CAM_Q_Interface : public Service::Interface {
13public:
14 CAM_Q_Interface();
15
16 std::string GetPortName() const override {
17 return "cam:q";
18 }
19};
20
21} // namespace CAM
22} // namespace Service
diff --git a/src/core/hle/service/cam/cam_s.cpp b/src/core/hle/service/cam/cam_s.cpp
new file mode 100644
index 000000000..aefbf7df4
--- /dev/null
+++ b/src/core/hle/service/cam/cam_s.cpp
@@ -0,0 +1,20 @@
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 "core/hle/hle.h"
6#include "core/hle/service/cam/cam.h"
7#include "core/hle/service/cam/cam_s.h"
8
9namespace Service {
10namespace CAM {
11
12// Empty arrays are illegal -- commented out until an entry is added.
13//const Interface::FunctionInfo FunctionTable[] = { };
14
15CAM_S_Interface::CAM_S_Interface() {
16 //Register(FunctionTable);
17}
18
19} // namespace CAM
20} // namespace Service
diff --git a/src/core/hle/service/cam/cam_s.h b/src/core/hle/service/cam/cam_s.h
new file mode 100644
index 000000000..0a5d6fca2
--- /dev/null
+++ b/src/core/hle/service/cam/cam_s.h
@@ -0,0 +1,22 @@
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 "core/hle/service/service.h"
8
9namespace Service {
10namespace CAM {
11
12class CAM_S_Interface : public Service::Interface {
13public:
14 CAM_S_Interface();
15
16 std::string GetPortName() const override {
17 return "cam:s";
18 }
19};
20
21} // namespace CAM
22} // namespace Service
diff --git a/src/core/hle/service/cam/cam_u.cpp b/src/core/hle/service/cam/cam_u.cpp
new file mode 100644
index 000000000..1c6aca955
--- /dev/null
+++ b/src/core/hle/service/cam/cam_u.cpp
@@ -0,0 +1,20 @@
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 "core/hle/hle.h"
6#include "core/hle/service/cam/cam.h"
7#include "core/hle/service/cam/cam_u.h"
8
9namespace Service {
10namespace CAM {
11
12// Empty arrays are illegal -- commented out until an entry is added.
13//const Interface::FunctionInfo FunctionTable[] = { };
14
15CAM_U_Interface::CAM_U_Interface() {
16 //Register(FunctionTable);
17}
18
19} // namespace CAM
20} // namespace Service
diff --git a/src/core/hle/service/cam/cam_u.h b/src/core/hle/service/cam/cam_u.h
new file mode 100644
index 000000000..369264037
--- /dev/null
+++ b/src/core/hle/service/cam/cam_u.h
@@ -0,0 +1,22 @@
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 "core/hle/service/service.h"
8
9namespace Service {
10namespace CAM {
11
12class CAM_U_Interface : public Service::Interface {
13public:
14 CAM_U_Interface();
15
16 std::string GetPortName() const override {
17 return "cam:u";
18 }
19};
20
21} // namespace CAM
22} // namespace Service
diff --git a/src/core/hle/service/cam_u.cpp b/src/core/hle/service/cam_u.cpp
deleted file mode 100644
index fcfd87715..000000000
--- a/src/core/hle/service/cam_u.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
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 "core/hle/hle.h"
6#include "core/hle/service/cam_u.h"
7
8////////////////////////////////////////////////////////////////////////////////////////////////////
9// Namespace CAM_U
10
11namespace CAM_U {
12
13// Empty arrays are illegal -- commented out until an entry is added.
14//const Interface::FunctionInfo FunctionTable[] = { };
15
16////////////////////////////////////////////////////////////////////////////////////////////////////
17// Interface class
18
19Interface::Interface() {
20 //Register(FunctionTable);
21}
22
23} // namespace
diff --git a/src/core/hle/service/cam_u.h b/src/core/hle/service/cam_u.h
deleted file mode 100644
index 878c20a84..000000000
--- a/src/core/hle/service/cam_u.h
+++ /dev/null
@@ -1,23 +0,0 @@
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 "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace CAM_U
11
12namespace CAM_U {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "cam:u";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp
new file mode 100644
index 000000000..db0e52b79
--- /dev/null
+++ b/src/core/hle/service/cecd/cecd.cpp
@@ -0,0 +1,31 @@
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 "common/logging/log.h"
6
7#include "core/hle/service/service.h"
8#include "core/hle/service/cecd/cecd.h"
9#include "core/hle/service/cecd/cecd_s.h"
10#include "core/hle/service/cecd/cecd_u.h"
11
12#include "core/hle/kernel/event.h"
13#include "core/hle/kernel/shared_memory.h"
14#include "core/hle/hle.h"
15
16namespace Service {
17namespace CECD {
18
19void Init() {
20 using namespace Kernel;
21
22 AddService(new CECD_S_Interface);
23 AddService(new CECD_U_Interface);
24}
25
26void Shutdown() {
27}
28
29} // namespace CECD
30
31} // namespace Service
diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h
new file mode 100644
index 000000000..32fd2045d
--- /dev/null
+++ b/src/core/hle/service/cecd/cecd.h
@@ -0,0 +1,20 @@
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 "core/hle/kernel/kernel.h"
8#include "core/hle/service/service.h"
9
10namespace Service {
11namespace CECD {
12
13/// Initialize CECD service(s)
14void Init();
15
16/// Shutdown CECD service(s)
17void Shutdown();
18
19} // namespace CECD
20} // namespace Service
diff --git a/src/core/hle/service/cecd/cecd_s.cpp b/src/core/hle/service/cecd/cecd_s.cpp
new file mode 100644
index 000000000..72d7e8d44
--- /dev/null
+++ b/src/core/hle/service/cecd/cecd_s.cpp
@@ -0,0 +1,20 @@
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 "core/hle/hle.h"
6#include "core/hle/service/cecd/cecd.h"
7#include "core/hle/service/cecd/cecd_s.h"
8
9namespace Service {
10namespace CECD {
11
12// Empty arrays are illegal -- commented out until an entry is added.
13//const Interface::FunctionInfo FunctionTable[] = { };
14
15CECD_S_Interface::CECD_S_Interface() {
16 //Register(FunctionTable);
17}
18
19} // namespace CECD
20} // namespace Service
diff --git a/src/core/hle/service/cecd_s.h b/src/core/hle/service/cecd/cecd_s.h
index d880d0391..df5c01849 100644
--- a/src/core/hle/service/cecd_s.h
+++ b/src/core/hle/service/cecd/cecd_s.h
@@ -6,18 +6,17 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9//////////////////////////////////////////////////////////////////////////////////////////////////// 9namespace Service {
10// Namespace CECD_S 10namespace CECD {
11 11
12namespace CECD_S { 12class CECD_S_Interface : public Interface {
13
14class Interface : public Service::Interface {
15public: 13public:
16 Interface(); 14 CECD_S_Interface();
17 15
18 std::string GetPortName() const override { 16 std::string GetPortName() const override {
19 return "cecd:s"; 17 return "cecd:s";
20 } 18 }
21}; 19};
22 20
23} // namespace 21} // namespace CECD
22} // namespace Service
diff --git a/src/core/hle/service/cecd/cecd_u.cpp b/src/core/hle/service/cecd/cecd_u.cpp
new file mode 100644
index 000000000..0a23bafbc
--- /dev/null
+++ b/src/core/hle/service/cecd/cecd_u.cpp
@@ -0,0 +1,20 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/hle.h"
6#include "core/hle/service/cecd/cecd.h"
7#include "core/hle/service/cecd/cecd_u.h"
8
9namespace Service {
10namespace CECD {
11
12// Empty arrays are illegal -- commented out until an entry is added.
13//const Interface::FunctionInfo FunctionTable[] = { };
14
15CECD_U_Interface::CECD_U_Interface() {
16 //Register(FunctionTable);
17}
18
19} // namespace CECD
20} // namespace Service
diff --git a/src/core/hle/service/cecd_u.h b/src/core/hle/service/cecd/cecd_u.h
index e67564135..394030ffc 100644
--- a/src/core/hle/service/cecd_u.h
+++ b/src/core/hle/service/cecd/cecd_u.h
@@ -6,18 +6,17 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9//////////////////////////////////////////////////////////////////////////////////////////////////// 9namespace Service {
10// Namespace CECD_U 10namespace CECD {
11 11
12namespace CECD_U { 12class CECD_U_Interface : public Interface {
13
14class Interface : public Service::Interface {
15public: 13public:
16 Interface(); 14 CECD_U_Interface();
17 15
18 std::string GetPortName() const override { 16 std::string GetPortName() const override {
19 return "cecd:u"; 17 return "cecd:u";
20 } 18 }
21}; 19};
22 20
23} // namespace 21} // namespace CECD
22} // namespace Service
diff --git a/src/core/hle/service/cecd_s.cpp b/src/core/hle/service/cecd_s.cpp
deleted file mode 100644
index b298f151d..000000000
--- a/src/core/hle/service/cecd_s.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
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 "core/hle/hle.h"
6#include "core/hle/service/cecd_s.h"
7
8////////////////////////////////////////////////////////////////////////////////////////////////////
9// Namespace CECD_S
10
11namespace CECD_S {
12
13// Empty arrays are illegal -- commented out until an entry is added.
14//const Interface::FunctionInfo FunctionTable[] = { };
15
16////////////////////////////////////////////////////////////////////////////////////////////////////
17// Interface class
18
19Interface::Interface() {
20 //Register(FunctionTable);
21}
22
23} // namespace
diff --git a/src/core/hle/service/cecd_u.cpp b/src/core/hle/service/cecd_u.cpp
deleted file mode 100644
index 9125364bc..000000000
--- a/src/core/hle/service/cecd_u.cpp
+++ /dev/null
@@ -1,23 +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#include "core/hle/hle.h"
6#include "core/hle/service/cecd_u.h"
7
8////////////////////////////////////////////////////////////////////////////////////////////////////
9// Namespace CECD_U
10
11namespace CECD_U {
12
13// Empty arrays are illegal -- commented out until an entry is added.
14//const Interface::FunctionInfo FunctionTable[] = { };
15
16////////////////////////////////////////////////////////////////////////////////////////////////////
17// Interface class
18
19Interface::Interface() {
20 //Register(FunctionTable);
21}
22
23} // namespace
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index d42682883..62ad90fdc 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -315,11 +315,11 @@ void Init() {
315 AddService(new CFG_I_Interface); 315 AddService(new CFG_I_Interface);
316 AddService(new CFG_S_Interface); 316 AddService(new CFG_S_Interface);
317 AddService(new CFG_U_Interface); 317 AddService(new CFG_U_Interface);
318 318
319 // Open the SystemSaveData archive 0x00010017 319 // Open the SystemSaveData archive 0x00010017
320 FileSys::Path archive_path(cfg_system_savedata_id); 320 FileSys::Path archive_path(cfg_system_savedata_id);
321 auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); 321 auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path);
322 322
323 // If the archive didn't exist, create the files inside 323 // If the archive didn't exist, create the files inside
324 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { 324 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
325 // Format the archive to create the directories 325 // Format the archive to create the directories
diff --git a/src/core/hle/service/frd/frd.cpp b/src/core/hle/service/frd/frd.cpp
new file mode 100644
index 000000000..2911ab402
--- /dev/null
+++ b/src/core/hle/service/frd/frd.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 "core/hle/service/service.h"
6#include "core/hle/service/frd/frd.h"
7#include "core/hle/service/frd/frd_a.h"
8#include "core/hle/service/frd/frd_u.h"
9
10#include "core/hle/kernel/event.h"
11#include "core/hle/kernel/shared_memory.h"
12#include "core/hle/hle.h"
13
14namespace Service {
15namespace FRD {
16
17void Init() {
18 using namespace Kernel;
19
20 AddService(new FRD_A_Interface);
21 AddService(new FRD_U_Interface);
22}
23
24void Shutdown() {
25}
26
27} // namespace FRD
28
29} // namespace Service
diff --git a/src/core/hle/service/frd/frd.h b/src/core/hle/service/frd/frd.h
new file mode 100644
index 000000000..41f7a2f6b
--- /dev/null
+++ b/src/core/hle/service/frd/frd.h
@@ -0,0 +1,20 @@
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 "core/hle/kernel/kernel.h"
8#include "core/hle/service/service.h"
9
10namespace Service {
11namespace FRD {
12
13/// Initialize FRD service(s)
14void Init();
15
16/// Shutdown FRD service(s)
17void Shutdown();
18
19} // namespace FRD
20} // namespace Service
diff --git a/src/core/hle/service/frd/frd_a.cpp b/src/core/hle/service/frd/frd_a.cpp
new file mode 100644
index 000000000..1c438a337
--- /dev/null
+++ b/src/core/hle/service/frd/frd_a.cpp
@@ -0,0 +1,20 @@
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 "core/hle/hle.h"
6#include "core/hle/service/frd/frd.h"
7#include "core/hle/service/frd/frd_a.h"
8
9namespace Service {
10namespace FRD {
11
12// Empty arrays are illegal -- commented out until an entry is added.
13// const Interface::FunctionInfo FunctionTable[] = { };
14
15FRD_A_Interface::FRD_A_Interface() {
16 //Register(FunctionTable);
17}
18
19} // namespace FRD
20} // namespace Service
diff --git a/src/core/hle/service/frd_a.h b/src/core/hle/service/frd/frd_a.h
index f068c6108..006d1cadd 100644
--- a/src/core/hle/service/frd_a.h
+++ b/src/core/hle/service/frd/frd_a.h
@@ -6,18 +6,17 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9//////////////////////////////////////////////////////////////////////////////////////////////////// 9namespace Service {
10// Namespace FRD_A 10namespace FRD {
11 11
12namespace FRD_A { 12class FRD_A_Interface : public Service::Interface {
13
14class Interface : public Service::Interface {
15public: 13public:
16 Interface(); 14 FRD_A_Interface();
17 15
18 std::string GetPortName() const override { 16 std::string GetPortName() const override {
19 return "frd:a"; 17 return "frd:a";
20 } 18 }
21}; 19};
22 20
23} // namespace 21} // namespace FRD
22} // namespace Service
diff --git a/src/core/hle/service/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp
index 6d2ff1e21..439c7282e 100644
--- a/src/core/hle/service/frd_u.cpp
+++ b/src/core/hle/service/frd/frd_u.cpp
@@ -3,12 +3,11 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/hle.h" 5#include "core/hle/hle.h"
6#include "core/hle/service/frd_u.h" 6#include "core/hle/service/frd/frd.h"
7#include "core/hle/service/frd/frd_u.h"
7 8
8//////////////////////////////////////////////////////////////////////////////////////////////////// 9namespace Service {
9// Namespace FRD_U 10namespace FRD {
10
11namespace FRD_U {
12 11
13const Interface::FunctionInfo FunctionTable[] = { 12const Interface::FunctionInfo FunctionTable[] = {
14 {0x00050000, nullptr, "GetFriendKey"}, 13 {0x00050000, nullptr, "GetFriendKey"},
@@ -22,11 +21,9 @@ const Interface::FunctionInfo FunctionTable[] = {
22 {0x00320042, nullptr, "SetClientSdkVersion"} 21 {0x00320042, nullptr, "SetClientSdkVersion"}
23}; 22};
24 23
25//////////////////////////////////////////////////////////////////////////////////////////////////// 24FRD_U_Interface::FRD_U_Interface() {
26// Interface class
27
28Interface::Interface() {
29 Register(FunctionTable); 25 Register(FunctionTable);
30} 26}
31 27
32} // namespace 28} // namespace FRD
29} // namespace Service
diff --git a/src/core/hle/service/frd_u.h b/src/core/hle/service/frd/frd_u.h
index ab8897d5b..07e43f155 100644
--- a/src/core/hle/service/frd_u.h
+++ b/src/core/hle/service/frd/frd_u.h
@@ -6,18 +6,17 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9//////////////////////////////////////////////////////////////////////////////////////////////////// 9namespace Service {
10// Namespace FRD_U 10namespace FRD {
11 11
12namespace FRD_U { 12class FRD_U_Interface : public Service::Interface {
13
14class Interface : public Service::Interface {
15public: 13public:
16 Interface(); 14 FRD_U_Interface();
17 15
18 std::string GetPortName() const override { 16 std::string GetPortName() const override {
19 return "frd:u"; 17 return "frd:u";
20 } 18 }
21}; 19};
22 20
23} // namespace 21} // namespace FRD
22} // namespace Service
diff --git a/src/core/hle/service/frd_a.cpp b/src/core/hle/service/frd_a.cpp
deleted file mode 100644
index 569979319..000000000
--- a/src/core/hle/service/frd_a.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
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 "core/hle/hle.h"
6#include "core/hle/service/frd_a.h"
7
8////////////////////////////////////////////////////////////////////////////////////////////////////
9// Namespace FRD_A
10
11namespace FRD_A {
12
13// Empty arrays are illegal -- commented out until an entry is added.
14// const Interface::FunctionInfo FunctionTable[] = { };
15
16////////////////////////////////////////////////////////////////////////////////////////////////////
17// Interface class
18
19Interface::Interface() {
20 //Register(FunctionTable);
21}
22
23} // namespace
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index 6d4a9c7c9..4e275cb13 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -254,7 +254,7 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi
254 254
255 CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path)); 255 CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path));
256 256
257 // This should never even happen in the first place with 64-bit handles, 257 // This should never even happen in the first place with 64-bit handles,
258 while (handle_map.count(next_handle) != 0) { 258 while (handle_map.count(next_handle) != 0) {
259 ++next_handle; 259 ++next_handle;
260 } 260 }
@@ -406,7 +406,7 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) {
406 return archive_itr->second->Format(path); 406 return archive_itr->second->Format(path);
407} 407}
408 408
409ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low) { 409ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size) {
410 // Construct the binary path to the archive first 410 // Construct the binary path to the archive first
411 FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); 411 FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low);
412 412
@@ -421,9 +421,25 @@ ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low) {
421 } 421 }
422 422
423 std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); 423 std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND);
424 std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path); 424 std::string game_path = FileSys::GetExtSaveDataPath(base_path, path);
425 if (!FileUtil::CreateFullPath(extsavedata_path)) 425 // These two folders are always created with the ExtSaveData
426 std::string user_path = game_path + "user/";
427 std::string boss_path = game_path + "boss/";
428 if (!FileUtil::CreateFullPath(user_path))
429 return ResultCode(-1); // TODO(Subv): Find the right error code
430 if (!FileUtil::CreateFullPath(boss_path))
431 return ResultCode(-1); // TODO(Subv): Find the right error code
432
433 u8* smdh_icon = Memory::GetPointer(icon_buffer);
434 if (!smdh_icon)
426 return ResultCode(-1); // TODO(Subv): Find the right error code 435 return ResultCode(-1); // TODO(Subv): Find the right error code
436
437 // Create the icon
438 FileUtil::IOFile icon_file(game_path + "icon", "wb+");
439 if (!icon_file.IsGood())
440 return ResultCode(-1); // TODO(Subv): Find the right error code
441
442 icon_file.WriteBytes(smdh_icon, icon_size);
427 return RESULT_SUCCESS; 443 return RESULT_SUCCESS;
428} 444}
429 445
@@ -441,6 +457,7 @@ ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low) {
441 return ResultCode(-1); // TODO(Subv): Find the right error code 457 return ResultCode(-1); // TODO(Subv): Find the right error code
442 } 458 }
443 459
460 // Delete all directories (/user, /boss) and the icon file.
444 std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); 461 std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND);
445 std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path); 462 std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path);
446 if (!FileUtil::DeleteDirRecursively(extsavedata_path)) 463 if (!FileUtil::DeleteDirRecursively(extsavedata_path))
@@ -488,7 +505,7 @@ void ArchiveInit() {
488 RegisterArchiveType(std::move(sdmc_factory), ArchiveIdCode::SDMC); 505 RegisterArchiveType(std::move(sdmc_factory), ArchiveIdCode::SDMC);
489 else 506 else
490 LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); 507 LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
491 508
492 // Create the SaveData archive 509 // Create the SaveData archive
493 auto savedata_factory = Common::make_unique<FileSys::ArchiveFactory_SaveData>(sdmc_directory); 510 auto savedata_factory = Common::make_unique<FileSys::ArchiveFactory_SaveData>(sdmc_directory);
494 RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData); 511 RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData);
@@ -503,7 +520,7 @@ void ArchiveInit() {
503 if (sharedextsavedata_factory->Initialize()) 520 if (sharedextsavedata_factory->Initialize())
504 RegisterArchiveType(std::move(sharedextsavedata_factory), ArchiveIdCode::SharedExtSaveData); 521 RegisterArchiveType(std::move(sharedextsavedata_factory), ArchiveIdCode::SharedExtSaveData);
505 else 522 else
506 LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s", 523 LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s",
507 sharedextsavedata_factory->GetMountPoint().c_str()); 524 sharedextsavedata_factory->GetMountPoint().c_str());
508 525
509 // Create the SaveDataCheck archive, basically a small variation of the RomFS archive 526 // Create the SaveDataCheck archive, basically a small variation of the RomFS archive
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index faab0cb79..357b6b096 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -177,9 +177,11 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path = File
177 * @param media_type The media type of the archive to create (NAND / SDMC) 177 * @param media_type The media type of the archive to create (NAND / SDMC)
178 * @param high The high word of the extdata id to create 178 * @param high The high word of the extdata id to create
179 * @param low The low word of the extdata id to create 179 * @param low The low word of the extdata id to create
180 * @param icon_buffer VAddr of the SMDH icon for this ExtSaveData
181 * @param icon_size Size of the SMDH icon
180 * @return ResultCode 0 on success or the corresponding code on error 182 * @return ResultCode 0 on success or the corresponding code on error
181 */ 183 */
182ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low); 184ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size);
183 185
184/** 186/**
185 * Deletes the SharedExtSaveData archive for the specified extdata ID 187 * Deletes the SharedExtSaveData archive for the specified extdata ID
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index b25c8941d..0ad44e55e 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -434,7 +434,7 @@ static void IsSdmcWriteable(Service::Interface* self) {
434} 434}
435 435
436/** 436/**
437 * FS_User::FormatSaveData service function, 437 * FS_User::FormatSaveData service function,
438 * formats the SaveData specified by the input path. 438 * formats the SaveData specified by the input path.
439 * Inputs: 439 * Inputs:
440 * 0 : 0x084C0242 440 * 0 : 0x084C0242
@@ -504,9 +504,9 @@ static void FormatThisUserSaveData(Service::Interface* self) {
504 * 6 : Unknown 504 * 6 : Unknown
505 * 7 : Unknown 505 * 7 : Unknown
506 * 8 : Unknown 506 * 8 : Unknown
507 * 9 : Unknown 507 * 9 : Size of the SMDH icon
508 * 10: Unknown 508 * 10: (SMDH Size << 4) | 0x0000000A
509 * 11: Unknown 509 * 11: Pointer to the SMDH icon for the new ExtSaveData
510 * Outputs: 510 * Outputs:
511 * 1 : Result of function, 0 on success, otherwise error code 511 * 1 : Result of function, 0 on success, otherwise error code
512 */ 512 */
@@ -516,14 +516,16 @@ static void CreateExtSaveData(Service::Interface* self) {
516 MediaType media_type = static_cast<MediaType>(cmd_buff[1] & 0xFF); 516 MediaType media_type = static_cast<MediaType>(cmd_buff[1] & 0xFF);
517 u32 save_low = cmd_buff[2]; 517 u32 save_low = cmd_buff[2];
518 u32 save_high = cmd_buff[3]; 518 u32 save_high = cmd_buff[3];
519 u32 icon_size = cmd_buff[9];
520 VAddr icon_buffer = cmd_buff[11];
519 521
520 LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X " 522 LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X "
521 "cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X " 523 "cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X "
522 "cmd_buff[9]=%08X cmd_buff[10]=%08X cmd_buff[11]=%08X", save_high, save_low, 524 "icon_size=%08X icon_descriptor=%08X icon_buffer=%08X", save_high, save_low,
523 cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9], 525 cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], icon_size,
524 cmd_buff[10], cmd_buff[11]); 526 cmd_buff[10], icon_buffer);
525 527
526 cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low).raw; 528 cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low, icon_buffer, icon_size).raw;
527} 529}
528 530
529/** 531/**
@@ -544,7 +546,7 @@ static void DeleteExtSaveData(Service::Interface* self) {
544 u32 save_high = cmd_buff[3]; 546 u32 save_high = cmd_buff[3];
545 u32 unknown = cmd_buff[4]; // TODO(Subv): Figure out what this is 547 u32 unknown = cmd_buff[4]; // TODO(Subv): Figure out what this is
546 548
547 LOG_WARNING(Service_FS, "(STUBBED) save_low=%08X save_high=%08X media_type=%08X unknown=%08X", 549 LOG_WARNING(Service_FS, "(STUBBED) save_low=%08X save_high=%08X media_type=%08X unknown=%08X",
548 save_low, save_high, cmd_buff[1] & 0xFF, unknown); 550 save_low, save_high, cmd_buff[1] & 0xFF, unknown);
549 551
550 cmd_buff[1] = DeleteExtSaveData(media_type, save_high, save_low).raw; 552 cmd_buff[1] = DeleteExtSaveData(media_type, save_high, save_low).raw;
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index c56475ae4..4b0b4229d 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -167,7 +167,7 @@ static void WriteHWRegsWithMask(Service::Interface* self) {
167 u32* cmd_buff = Kernel::GetCommandBuffer(); 167 u32* cmd_buff = Kernel::GetCommandBuffer();
168 u32 reg_addr = cmd_buff[1]; 168 u32 reg_addr = cmd_buff[1];
169 u32 size = cmd_buff[2]; 169 u32 size = cmd_buff[2];
170 170
171 u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]); 171 u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]);
172 u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]); 172 u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]);
173 173
@@ -208,21 +208,21 @@ static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
208 PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); 208 PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left);
209 PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); 209 PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right);
210 if (info.active_fb == 0) { 210 if (info.active_fb == 0) {
211 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4, 211 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4,
212 &phys_address_left); 212 &phys_address_left);
213 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4, 213 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4,
214 &phys_address_right); 214 &phys_address_right);
215 } else { 215 } else {
216 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4, 216 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4,
217 &phys_address_left); 217 &phys_address_left);
218 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4, 218 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4,
219 &phys_address_right); 219 &phys_address_right);
220 } 220 }
221 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4, 221 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4,
222 &info.stride); 222 &info.stride);
223 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4, 223 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4,
224 &info.format); 224 &info.format);
225 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4, 225 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4,
226 &info.shown_fb); 226 &info.shown_fb);
227} 227}
228 228
@@ -374,7 +374,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
374 { 374 {
375 auto& params = command.set_command_list_last; 375 auto& params = command.set_command_list_last;
376 376
377 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.address)), 377 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.address)),
378 Memory::VirtualToPhysicalAddress(params.address) >> 3); 378 Memory::VirtualToPhysicalAddress(params.address) >> 3);
379 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.size)), params.size); 379 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.size)), params.size);
380 380
@@ -470,7 +470,7 @@ static void SetLcdForceBlack(Service::Interface* self) {
470 470
471 LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_top), data.raw); // Top LCD 471 LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_top), data.raw); // Top LCD
472 LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_bottom), data.raw); // Bottom LCD 472 LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_bottom), data.raw); // Bottom LCD
473 473
474 cmd_buff[1] = RESULT_SUCCESS.raw; 474 cmd_buff[1] = RESULT_SUCCESS.raw;
475} 475}
476 476
@@ -496,6 +496,52 @@ static void TriggerCmdReqQueue(Service::Interface* self) {
496 cmd_buff[1] = 0; // No error 496 cmd_buff[1] = 0; // No error
497} 497}
498 498
499/**
500 * GSP_GPU::ImportDisplayCaptureInfo service function
501 *
502 * Returns information about the current framebuffer state
503 *
504 * Inputs:
505 * 0: Header 0x00180000
506 * Outputs:
507 * 1: Result code
508 * 2: Left framebuffer virtual address for the main screen
509 * 3: Right framebuffer virtual address for the main screen
510 * 4: Main screen framebuffer format
511 * 5: Main screen framebuffer width
512 * 6: Left framebuffer virtual address for the bottom screen
513 * 7: Right framebuffer virtual address for the bottom screen
514 * 8: Bottom screen framebuffer format
515 * 9: Bottom screen framebuffer width
516 */
517static void ImportDisplayCaptureInfo(Service::Interface* self) {
518 u32* cmd_buff = Kernel::GetCommandBuffer();
519
520 // TODO(Subv): We're always returning the framebuffer structures for thread_id = 0,
521 // because we only support a single running application at a time.
522 // This should always return the framebuffer data that is currently displayed on the screen.
523
524 u32 thread_id = 0;
525
526 FrameBufferUpdate* top_screen = GetFrameBufferInfo(thread_id, 0);
527 FrameBufferUpdate* bottom_screen = GetFrameBufferInfo(thread_id, 1);
528
529 cmd_buff[2] = top_screen->framebuffer_info[top_screen->index].address_left;
530 cmd_buff[3] = top_screen->framebuffer_info[top_screen->index].address_right;
531 cmd_buff[4] = top_screen->framebuffer_info[top_screen->index].format;
532 cmd_buff[5] = top_screen->framebuffer_info[top_screen->index].stride;
533
534 cmd_buff[6] = bottom_screen->framebuffer_info[bottom_screen->index].address_left;
535 cmd_buff[7] = bottom_screen->framebuffer_info[bottom_screen->index].address_right;
536 cmd_buff[8] = bottom_screen->framebuffer_info[bottom_screen->index].format;
537 cmd_buff[9] = bottom_screen->framebuffer_info[bottom_screen->index].stride;
538
539 cmd_buff[1] = RESULT_SUCCESS.raw;
540
541 LOG_WARNING(Service_GSP, "called");
542}
543
544
499const Interface::FunctionInfo FunctionTable[] = { 545const Interface::FunctionInfo FunctionTable[] = {
500 {0x00010082, WriteHWRegs, "WriteHWRegs"}, 546 {0x00010082, WriteHWRegs, "WriteHWRegs"},
501 {0x00020084, WriteHWRegsWithMask, "WriteHWRegsWithMask"}, 547 {0x00020084, WriteHWRegsWithMask, "WriteHWRegsWithMask"},
@@ -520,7 +566,7 @@ const Interface::FunctionInfo FunctionTable[] = {
520 {0x00150002, nullptr, "TryAcquireRight"}, 566 {0x00150002, nullptr, "TryAcquireRight"},
521 {0x00160042, nullptr, "AcquireRight"}, 567 {0x00160042, nullptr, "AcquireRight"},
522 {0x00170000, nullptr, "ReleaseRight"}, 568 {0x00170000, nullptr, "ReleaseRight"},
523 {0x00180000, nullptr, "ImportDisplayCaptureInfo"}, 569 {0x00180000, ImportDisplayCaptureInfo, "ImportDisplayCaptureInfo"},
524 {0x00190000, nullptr, "SaveVramSysArea"}, 570 {0x00190000, nullptr, "SaveVramSysArea"},
525 {0x001A0000, nullptr, "RestoreVramSysArea"}, 571 {0x001A0000, nullptr, "RestoreVramSysArea"},
526 {0x001B0000, nullptr, "ResetGpuCore"}, 572 {0x001B0000, nullptr, "ResetGpuCore"},
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 2d2133b2e..c7c1bb5ab 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -58,7 +58,7 @@ void Update() {
58 58
59 mem->pad.current_state.hex = state.hex; 59 mem->pad.current_state.hex = state.hex;
60 mem->pad.index = next_pad_index; 60 mem->pad.index = next_pad_index;
61 ++next_touch_index %= mem->pad.entries.size(); 61 next_touch_index = (next_touch_index + 1) % mem->pad.entries.size();
62 62
63 // Get the previous Pad state 63 // Get the previous Pad state
64 u32 last_entry_index = (mem->pad.index - 1) % mem->pad.entries.size(); 64 u32 last_entry_index = (mem->pad.index - 1) % mem->pad.entries.size();
@@ -88,7 +88,7 @@ void Update() {
88 } 88 }
89 89
90 mem->touch.index = next_touch_index; 90 mem->touch.index = next_touch_index;
91 ++next_touch_index %= mem->touch.entries.size(); 91 next_touch_index = (next_touch_index + 1) % mem->touch.entries.size();
92 92
93 // Get the current touch entry 93 // Get the current touch entry
94 TouchDataEntry* touch_entry = &mem->touch.entries[mem->touch.index]; 94 TouchDataEntry* touch_entry = &mem->touch.entries[mem->touch.index];
@@ -106,7 +106,7 @@ void Update() {
106 mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks; 106 mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks;
107 mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks(); 107 mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks();
108 } 108 }
109 109
110 // Signal both handles when there's an update to Pad or touch 110 // Signal both handles when there's an update to Pad or touch
111 event_pad_or_touch_1->Signal(); 111 event_pad_or_touch_1->Signal();
112 event_pad_or_touch_2->Signal(); 112 event_pad_or_touch_2->Signal();
diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp
index 02db12efd..532931ae0 100644
--- a/src/core/hle/service/hid/hid_spvr.cpp
+++ b/src/core/hle/service/hid/hid_spvr.cpp
@@ -25,6 +25,6 @@ const Interface::FunctionInfo FunctionTable[] = {
25HID_SPVR_Interface::HID_SPVR_Interface() { 25HID_SPVR_Interface::HID_SPVR_Interface() {
26 Register(FunctionTable); 26 Register(FunctionTable);
27} 27}
28 28
29} // namespace HID 29} // namespace HID
30} // namespace Service 30} // namespace Service
diff --git a/src/core/hle/service/hid/hid_user.h b/src/core/hle/service/hid/hid_user.h
index 0eeec2c25..baf7fed79 100644
--- a/src/core/hle/service/hid/hid_user.h
+++ b/src/core/hle/service/hid/hid_user.h
@@ -11,7 +11,7 @@
11 11
12namespace Service { 12namespace Service {
13namespace HID { 13namespace HID {
14 14
15/** 15/**
16 * HID service interface. 16 * HID service interface.
17 */ 17 */
diff --git a/src/core/hle/service/news/news.cpp b/src/core/hle/service/news/news.cpp
new file mode 100644
index 000000000..63cbd3850
--- /dev/null
+++ b/src/core/hle/service/news/news.cpp
@@ -0,0 +1,31 @@
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 "common/logging/log.h"
6
7#include "core/hle/service/service.h"
8#include "core/hle/service/news/news.h"
9#include "core/hle/service/news/news_s.h"
10#include "core/hle/service/news/news_u.h"
11
12#include "core/hle/hle.h"
13#include "core/hle/kernel/event.h"
14#include "core/hle/kernel/shared_memory.h"
15
16namespace Service {
17namespace NEWS {
18
19void Init() {
20 using namespace Kernel;
21
22 AddService(new NEWS_S_Interface);
23 AddService(new NEWS_U_Interface);
24}
25
26void Shutdown() {
27}
28
29} // namespace NEWS
30
31} // namespace Service
diff --git a/src/core/hle/service/news/news.h b/src/core/hle/service/news/news.h
new file mode 100644
index 000000000..b31ade255
--- /dev/null
+++ b/src/core/hle/service/news/news.h
@@ -0,0 +1,20 @@
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 "core/hle/kernel/kernel.h"
8#include "core/hle/service/service.h"
9
10namespace Service {
11namespace NEWS {
12
13/// Initialize NEWS service(s)
14void Init();
15
16/// Shutdown NEWS service(s)
17void Shutdown();
18
19} // namespace NEWS
20} // namespace Service
diff --git a/src/core/hle/service/news/news_s.cpp b/src/core/hle/service/news/news_s.cpp
new file mode 100644
index 000000000..2f8c37d9e
--- /dev/null
+++ b/src/core/hle/service/news/news_s.cpp
@@ -0,0 +1,21 @@
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 "core/hle/hle.h"
6#include "core/hle/service/news/news.h"
7#include "core/hle/service/news/news_s.h"
8
9namespace Service {
10namespace NEWS {
11
12const Interface::FunctionInfo FunctionTable[] = {
13 {0x000100C6, nullptr, "AddNotification"},
14};
15
16NEWS_S_Interface::NEWS_S_Interface() {
17 Register(FunctionTable);
18}
19
20} // namespace NEWS
21} // namespace Service
diff --git a/src/core/hle/service/news_s.h b/src/core/hle/service/news/news_s.h
index f8b4636d5..f58b969a8 100644
--- a/src/core/hle/service/news_s.h
+++ b/src/core/hle/service/news/news_s.h
@@ -6,18 +6,17 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9//////////////////////////////////////////////////////////////////////////////////////////////////// 9namespace Service {
10// Namespace NEWS_S 10namespace NEWS {
11 11
12namespace NEWS_S { 12class NEWS_S_Interface : public Service::Interface {
13
14class Interface : public Service::Interface {
15public: 13public:
16 Interface(); 14 NEWS_S_Interface();
17 15
18 std::string GetPortName() const override { 16 std::string GetPortName() const override {
19 return "news:s"; 17 return "news:s";
20 } 18 }
21}; 19};
22 20
23} // namespace 21} // namespace NEWS
22} // namespace Service
diff --git a/src/core/hle/service/news/news_u.cpp b/src/core/hle/service/news/news_u.cpp
new file mode 100644
index 000000000..81f45a244
--- /dev/null
+++ b/src/core/hle/service/news/news_u.cpp
@@ -0,0 +1,21 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/hle.h"
6#include "core/hle/service/news/news.h"
7#include "core/hle/service/news/news_u.h"
8
9namespace Service {
10namespace NEWS {
11
12const Interface::FunctionInfo FunctionTable[] = {
13 {0x000100C6, nullptr, "AddNotification"},
14};
15
16NEWS_U_Interface::NEWS_U_Interface() {
17 Register(FunctionTable);
18}
19
20} // namespace NEWS
21} // namespace Service
diff --git a/src/core/hle/service/news_u.h b/src/core/hle/service/news/news_u.h
index 0473cd19c..2720053d0 100644
--- a/src/core/hle/service/news_u.h
+++ b/src/core/hle/service/news/news_u.h
@@ -6,18 +6,17 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9//////////////////////////////////////////////////////////////////////////////////////////////////// 9namespace Service {
10// Namespace NEWS_U 10namespace NEWS {
11 11
12namespace NEWS_U { 12class NEWS_U_Interface : public Service::Interface {
13
14class Interface : public Service::Interface {
15public: 13public:
16 Interface(); 14 NEWS_U_Interface();
17 15
18 std::string GetPortName() const override { 16 std::string GetPortName() const override {
19 return "news:u"; 17 return "news:u";
20 } 18 }
21}; 19};
22 20
23} // namespace 21} // namespace NEWS
22} // namespace Service
diff --git a/src/core/hle/service/news_s.cpp b/src/core/hle/service/news_s.cpp
deleted file mode 100644
index 302d588c7..000000000
--- a/src/core/hle/service/news_s.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
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 "core/hle/hle.h"
6#include "core/hle/service/news_s.h"
7
8////////////////////////////////////////////////////////////////////////////////////////////////////
9// Namespace NEWS_S
10
11namespace NEWS_S {
12
13const Interface::FunctionInfo FunctionTable[] = {
14 {0x000100C6, nullptr, "AddNotification"},
15};
16
17////////////////////////////////////////////////////////////////////////////////////////////////////
18// Interface class
19
20Interface::Interface() {
21 Register(FunctionTable);
22}
23
24} // namespace
diff --git a/src/core/hle/service/news_u.cpp b/src/core/hle/service/news_u.cpp
deleted file mode 100644
index 7d835aa30..000000000
--- a/src/core/hle/service/news_u.cpp
+++ /dev/null
@@ -1,24 +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#include "core/hle/hle.h"
6#include "core/hle/service/news_u.h"
7
8////////////////////////////////////////////////////////////////////////////////////////////////////
9// Namespace NEWS_U
10
11namespace NEWS_U {
12
13const Interface::FunctionInfo FunctionTable[] = {
14 {0x000100C8, nullptr, "AddNotification"},
15};
16
17////////////////////////////////////////////////////////////////////////////////////////////////////
18// Interface class
19
20Interface::Interface() {
21 Register(FunctionTable);
22}
23
24} // namespace
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
new file mode 100644
index 000000000..73b0ee52a
--- /dev/null
+++ b/src/core/hle/service/nim/nim.cpp
@@ -0,0 +1,42 @@
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 "common/logging/log.h"
6
7#include "core/hle/service/service.h"
8#include "core/hle/service/nim/nim.h"
9#include "core/hle/service/nim/nim_aoc.h"
10#include "core/hle/service/nim/nim_s.h"
11#include "core/hle/service/nim/nim_u.h"
12
13#include "core/hle/kernel/event.h"
14#include "core/hle/kernel/shared_memory.h"
15#include "core/hle/hle.h"
16
17namespace Service {
18namespace NIM {
19
20void CheckSysUpdateAvailable(Service::Interface* self) {
21 u32* cmd_buff = Kernel::GetCommandBuffer();
22
23 cmd_buff[1] = RESULT_SUCCESS.raw;
24 cmd_buff[2] = 0; // No update available
25
26 LOG_WARNING(Service_NWM, "(STUBBED) called");
27}
28
29void Init() {
30 using namespace Kernel;
31
32 AddService(new NIM_AOC_Interface);
33 AddService(new NIM_S_Interface);
34 AddService(new NIM_U_Interface);
35}
36
37void Shutdown() {
38}
39
40} // namespace NIM
41
42} // namespace Service
diff --git a/src/core/hle/service/nim/nim.h b/src/core/hle/service/nim/nim.h
new file mode 100644
index 000000000..f7635c747
--- /dev/null
+++ b/src/core/hle/service/nim/nim.h
@@ -0,0 +1,30 @@
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 "core/hle/kernel/kernel.h"
8#include "core/hle/service/service.h"
9
10namespace Service {
11namespace NIM {
12
13/**
14 * NIM::CheckSysUpdateAvailable service function
15 * Inputs:
16 * 1 : None
17 * Outputs:
18 * 1 : Result of function, 0 on success, otherwise error code
19 * 2 : flag, 0 = no system update available, 1 = system update available.
20 */
21void CheckSysUpdateAvailable(Service::Interface* self);
22
23/// Initialize NIM service(s)
24void Init();
25
26/// Shutdown NIM service(s)
27void Shutdown();
28
29} // namespace NIM
30} // namespace Service
diff --git a/src/core/hle/service/nim_aoc.cpp b/src/core/hle/service/nim/nim_aoc.cpp
index 7a6aea91a..e6b1b6145 100644
--- a/src/core/hle/service/nim_aoc.cpp
+++ b/src/core/hle/service/nim/nim_aoc.cpp
@@ -3,12 +3,11 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/hle.h" 5#include "core/hle/hle.h"
6#include "core/hle/service/nim_aoc.h" 6#include "core/hle/service/nim/nim.h"
7#include "core/hle/service/nim/nim_aoc.h"
7 8
8//////////////////////////////////////////////////////////////////////////////////////////////////// 9namespace Service {
9// Namespace NIM_AOC 10namespace NIM {
10
11namespace NIM_AOC {
12 11
13const Interface::FunctionInfo FunctionTable[] = { 12const Interface::FunctionInfo FunctionTable[] = {
14 {0x00030042, nullptr, "SetApplicationId"}, 13 {0x00030042, nullptr, "SetApplicationId"},
@@ -20,11 +19,10 @@ const Interface::FunctionInfo FunctionTable[] = {
20 {0x00240282, nullptr, "CalculateContentsRequiredSize"}, 19 {0x00240282, nullptr, "CalculateContentsRequiredSize"},
21 {0x00250000, nullptr, "RefreshServerTime"}, 20 {0x00250000, nullptr, "RefreshServerTime"},
22}; 21};
23////////////////////////////////////////////////////////////////////////////////////////////////////
24// Interface class
25 22
26Interface::Interface() { 23NIM_AOC_Interface::NIM_AOC_Interface() {
27 Register(FunctionTable); 24 Register(FunctionTable);
28} 25}
29 26
30} // namespace 27} // namespace NIM
28} // namespace Service
diff --git a/src/core/hle/service/nim/nim_aoc.h b/src/core/hle/service/nim/nim_aoc.h
new file mode 100644
index 000000000..aace45b5a
--- /dev/null
+++ b/src/core/hle/service/nim/nim_aoc.h
@@ -0,0 +1,22 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included..
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9namespace Service {
10namespace NIM {
11
12class NIM_AOC_Interface : public Service::Interface {
13public:
14 NIM_AOC_Interface();
15
16 std::string GetPortName() const override {
17 return "nim:aoc";
18 }
19};
20
21} // namespace NIM
22} // namespace Service
diff --git a/src/core/hle/service/nim/nim_s.cpp b/src/core/hle/service/nim/nim_s.cpp
new file mode 100644
index 000000000..5d8bc059f
--- /dev/null
+++ b/src/core/hle/service/nim/nim_s.cpp
@@ -0,0 +1,22 @@
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 "core/hle/hle.h"
6#include "core/hle/service/nim/nim.h"
7#include "core/hle/service/nim/nim_s.h"
8
9namespace Service {
10namespace NIM {
11
12const Interface::FunctionInfo FunctionTable[] = {
13 {0x000A0000, nullptr, "CheckSysupdateAvailableSOAP"},
14};
15
16NIM_S_Interface::NIM_S_Interface() {
17 Register(FunctionTable);
18}
19
20} // namespace NIM
21} // namespace Service
22
diff --git a/src/core/hle/service/nim/nim_s.h b/src/core/hle/service/nim/nim_s.h
new file mode 100644
index 000000000..f4bf73d26
--- /dev/null
+++ b/src/core/hle/service/nim/nim_s.h
@@ -0,0 +1,22 @@
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 "core/hle/service/service.h"
8
9namespace Service {
10namespace NIM {
11
12class NIM_S_Interface : public Service::Interface {
13public:
14 NIM_S_Interface();
15
16 std::string GetPortName() const override {
17 return "nim:s";
18 }
19};
20
21} // namespace NIM
22} // namespace Service
diff --git a/src/core/hle/service/nim/nim_u.cpp b/src/core/hle/service/nim/nim_u.cpp
new file mode 100644
index 000000000..066570a85
--- /dev/null
+++ b/src/core/hle/service/nim/nim_u.cpp
@@ -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#include "core/hle/hle.h"
6#include "core/hle/service/nim/nim.h"
7#include "core/hle/service/nim/nim_u.h"
8
9namespace Service {
10namespace NIM {
11
12const Interface::FunctionInfo FunctionTable[] = {
13 {0x00010000, nullptr, "StartSysUpdate"},
14 {0x00020000, nullptr, "GetUpdateDownloadProgress"},
15 {0x00040000, nullptr, "FinishTitlesInstall"},
16 {0x00050000, nullptr, "CheckForSysUpdateEvent"},
17 {0x00090000, CheckSysUpdateAvailable, "CheckSysUpdateAvailable"},
18 {0x000A0000, nullptr, "GetState"},
19};
20
21NIM_U_Interface::NIM_U_Interface() {
22 Register(FunctionTable);
23}
24
25} // namespace NIM
26} // namespace Service
27
diff --git a/src/core/hle/service/nim/nim_u.h b/src/core/hle/service/nim/nim_u.h
new file mode 100644
index 000000000..bc89dc0f3
--- /dev/null
+++ b/src/core/hle/service/nim/nim_u.h
@@ -0,0 +1,22 @@
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 "core/hle/service/service.h"
8
9namespace Service {
10namespace NIM {
11
12class NIM_U_Interface : public Service::Interface {
13public:
14 NIM_U_Interface();
15
16 std::string GetPortName() const override {
17 return "nim:u";
18 }
19};
20
21} // namespace NIM
22} // namespace Service
diff --git a/src/core/hle/service/nim_aoc.h b/src/core/hle/service/nim_aoc.h
deleted file mode 100644
index aeb71eed2..000000000
--- a/src/core/hle/service/nim_aoc.h
+++ /dev/null
@@ -1,23 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace NIM_AOC
11
12namespace NIM_AOC {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "nim:aoc";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/nim_u.cpp b/src/core/hle/service/nim_u.cpp
deleted file mode 100644
index 5f13bd98e..000000000
--- a/src/core/hle/service/nim_u.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
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 "common/logging/log.h"
6
7#include "core/hle/hle.h"
8#include "core/hle/service/nim_u.h"
9
10////////////////////////////////////////////////////////////////////////////////////////////////////
11// Namespace NIM_U
12
13namespace NIM_U {
14
15/**
16 * NIM_U::CheckSysUpdateAvailable service function
17 * Inputs:
18 * 1 : None
19 * Outputs:
20 * 1 : Result of function, 0 on success, otherwise error code
21 * 2 : flag, 0 = no system update available, 1 = system update available.
22 */
23static void CheckSysUpdateAvailable(Service::Interface* self) {
24 u32* cmd_buff = Kernel::GetCommandBuffer();
25
26 cmd_buff[1] = RESULT_SUCCESS.raw;
27 cmd_buff[2] = 0; // No update available
28
29 LOG_WARNING(Service_NWM, "(STUBBED) called");
30}
31
32const Interface::FunctionInfo FunctionTable[] = {
33 {0x00010000, nullptr, "StartSysUpdate"},
34 {0x00020000, nullptr, "GetUpdateDownloadProgress"},
35 {0x00040000, nullptr, "FinishTitlesInstall"},
36 {0x00050000, nullptr, "CheckForSysUpdateEvent"},
37 {0x00090000, CheckSysUpdateAvailable, "CheckSysUpdateAvailable"},
38 {0x000A0000, nullptr, "GetState"},
39};
40
41////////////////////////////////////////////////////////////////////////////////////////////////////
42// Interface class
43
44Interface::Interface() {
45 Register(FunctionTable);
46}
47
48} // namespace
diff --git a/src/core/hle/service/nim_u.h b/src/core/hle/service/nim_u.h
deleted file mode 100644
index 57a1f6acf..000000000
--- a/src/core/hle/service/nim_u.h
+++ /dev/null
@@ -1,23 +0,0 @@
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 "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace NIM_U
11
12namespace NIM_U {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "nim:u";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
index 493e6a11f..b690003cb 100644
--- a/src/core/hle/service/ptm/ptm.h
+++ b/src/core/hle/service/ptm/ptm.h
@@ -20,15 +20,15 @@ enum class ChargeLevels : u32 {
20 CompletelyFull = 5, 20 CompletelyFull = 5,
21}; 21};
22 22
23/** 23/**
24 * Represents the gamecoin file structure in the SharedExtData archive 24 * Represents the gamecoin file structure in the SharedExtData archive
25 * More information in 3dbrew (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat) 25 * More information in 3dbrew (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat)
26 */ 26 */
27struct GameCoin { 27struct GameCoin {
28 u32 magic; ///< Magic number: 0x4F00 28 u32 magic; ///< Magic number: 0x4F00
29 u16 total_coins; ///< Total Play Coins 29 u16 total_coins; ///< Total Play Coins
30 u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below. 30 u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below.
31 u32 step_count; ///< Total step count at the time a new Play Coin was obtained. 31 u32 step_count; ///< Total step count at the time a new Play Coin was obtained.
32 u32 last_step_count; ///< Step count for the day the last Play Coin was obtained 32 u32 last_step_count; ///< Step count for the day the last Play Coin was obtained
33 u16 year; 33 u16 year;
34 u8 month; 34 u8 month;
diff --git a/src/core/hle/service/ptm/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp
index 48e68a3d8..7bb990193 100644
--- a/src/core/hle/service/ptm/ptm_play.cpp
+++ b/src/core/hle/service/ptm/ptm_play.cpp
@@ -18,6 +18,6 @@ const Interface::FunctionInfo FunctionTable[] = {
18PTM_Play_Interface::PTM_Play_Interface() { 18PTM_Play_Interface::PTM_Play_Interface() {
19 Register(FunctionTable); 19 Register(FunctionTable);
20} 20}
21 21
22} // namespace PTM 22} // namespace PTM
23} // namespace Service \ No newline at end of file 23} // namespace Service \ No newline at end of file
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 64185c62e..d681cc3dc 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -8,29 +8,15 @@
8#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
9#include "core/hle/service/ac_u.h" 9#include "core/hle/service/ac_u.h"
10#include "core/hle/service/act_u.h" 10#include "core/hle/service/act_u.h"
11#include "core/hle/service/am_app.h"
12#include "core/hle/service/am_net.h"
13#include "core/hle/service/am_sys.h"
14#include "core/hle/service/boss_p.h"
15#include "core/hle/service/boss_u.h"
16#include "core/hle/service/cam_u.h"
17#include "core/hle/service/cecd_u.h"
18#include "core/hle/service/cecd_s.h"
19#include "core/hle/service/csnd_snd.h" 11#include "core/hle/service/csnd_snd.h"
20#include "core/hle/service/dsp_dsp.h" 12#include "core/hle/service/dsp_dsp.h"
21#include "core/hle/service/err_f.h" 13#include "core/hle/service/err_f.h"
22#include "core/hle/service/frd_a.h"
23#include "core/hle/service/frd_u.h"
24#include "core/hle/service/gsp_gpu.h" 14#include "core/hle/service/gsp_gpu.h"
25#include "core/hle/service/gsp_lcd.h" 15#include "core/hle/service/gsp_lcd.h"
26#include "core/hle/service/http_c.h" 16#include "core/hle/service/http_c.h"
27#include "core/hle/service/ldr_ro.h" 17#include "core/hle/service/ldr_ro.h"
28#include "core/hle/service/mic_u.h" 18#include "core/hle/service/mic_u.h"
29#include "core/hle/service/ndm_u.h" 19#include "core/hle/service/ndm_u.h"
30#include "core/hle/service/news_s.h"
31#include "core/hle/service/news_u.h"
32#include "core/hle/service/nim_aoc.h"
33#include "core/hle/service/nim_u.h"
34#include "core/hle/service/ns_s.h" 20#include "core/hle/service/ns_s.h"
35#include "core/hle/service/nwm_uds.h" 21#include "core/hle/service/nwm_uds.h"
36#include "core/hle/service/pm_app.h" 22#include "core/hle/service/pm_app.h"
@@ -39,11 +25,18 @@
39#include "core/hle/service/ssl_c.h" 25#include "core/hle/service/ssl_c.h"
40#include "core/hle/service/y2r_u.h" 26#include "core/hle/service/y2r_u.h"
41 27
28#include "core/hle/service/am/am.h"
42#include "core/hle/service/apt/apt.h" 29#include "core/hle/service/apt/apt.h"
30#include "core/hle/service/boss/boss.h"
31#include "core/hle/service/cam/cam.h"
32#include "core/hle/service/cecd/cecd.h"
33#include "core/hle/service/frd/frd.h"
43#include "core/hle/service/fs/archive.h" 34#include "core/hle/service/fs/archive.h"
44#include "core/hle/service/cfg/cfg.h" 35#include "core/hle/service/cfg/cfg.h"
45#include "core/hle/service/hid/hid.h" 36#include "core/hle/service/hid/hid.h"
46#include "core/hle/service/ir/ir.h" 37#include "core/hle/service/ir/ir.h"
38#include "core/hle/service/news/news.h"
39#include "core/hle/service/nim/nim.h"
47#include "core/hle/service/ptm/ptm.h" 40#include "core/hle/service/ptm/ptm.h"
48 41
49namespace Service { 42namespace Service {
@@ -52,7 +45,7 @@ std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_por
52std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; 45std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services;
53 46
54/** 47/**
55 * Creates a function string for logging, complete with the name (or header code, depending 48 * Creates a function string for logging, complete with the name (or header code, depending
56 * on what's passed in) the port name, and all the cmd_buff arguments. 49 * on what's passed in) the port name, and all the cmd_buff arguments.
57 */ 50 */
58static std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) { 51static std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) {
@@ -111,36 +104,29 @@ void Init() {
111 AddNamedPort(new ERR_F::Interface); 104 AddNamedPort(new ERR_F::Interface);
112 105
113 Service::FS::ArchiveInit(); 106 Service::FS::ArchiveInit();
114 Service::CFG::Init(); 107 Service::AM::Init();
115 Service::APT::Init(); 108 Service::APT::Init();
116 Service::PTM::Init(); 109 Service::BOSS::Init();
110 Service::CAM::Init();
111 Service::CECD::Init();
112 Service::CFG::Init();
113 Service::FRD::Init();
117 Service::HID::Init(); 114 Service::HID::Init();
118 Service::IR::Init(); 115 Service::IR::Init();
116 Service::NEWS::Init();
117 Service::NIM::Init();
118 Service::PTM::Init();
119 119
120 AddService(new AC_U::Interface); 120 AddService(new AC_U::Interface);
121 AddService(new ACT_U::Interface); 121 AddService(new ACT_U::Interface);
122 AddService(new AM_APP::Interface);
123 AddService(new AM_NET::Interface);
124 AddService(new AM_SYS::Interface);
125 AddService(new BOSS_P::Interface);
126 AddService(new BOSS_U::Interface);
127 AddService(new CAM_U::Interface);
128 AddService(new CECD_S::Interface);
129 AddService(new CECD_U::Interface);
130 AddService(new CSND_SND::Interface); 122 AddService(new CSND_SND::Interface);
131 AddService(new DSP_DSP::Interface); 123 AddService(new DSP_DSP::Interface);
132 AddService(new FRD_A::Interface);
133 AddService(new FRD_U::Interface);
134 AddService(new GSP_GPU::Interface); 124 AddService(new GSP_GPU::Interface);
135 AddService(new GSP_LCD::Interface); 125 AddService(new GSP_LCD::Interface);
136 AddService(new HTTP_C::Interface); 126 AddService(new HTTP_C::Interface);
137 AddService(new LDR_RO::Interface); 127 AddService(new LDR_RO::Interface);
138 AddService(new MIC_U::Interface); 128 AddService(new MIC_U::Interface);
139 AddService(new NDM_U::Interface); 129 AddService(new NDM_U::Interface);
140 AddService(new NEWS_S::Interface);
141 AddService(new NEWS_U::Interface);
142 AddService(new NIM_AOC::Interface);
143 AddService(new NIM_U::Interface);
144 AddService(new NS_S::Interface); 130 AddService(new NS_S::Interface);
145 AddService(new NWM_UDS::Interface); 131 AddService(new NWM_UDS::Interface);
146 AddService(new PM_APP::Interface); 132 AddService(new PM_APP::Interface);
@@ -153,11 +139,19 @@ void Init() {
153 139
154/// Shutdown ServiceManager 140/// Shutdown ServiceManager
155void Shutdown() { 141void Shutdown() {
142
143 Service::PTM::Shutdown();
144 Service::NIM::Shutdown();
145 Service::NEWS::Shutdown();
156 Service::IR::Shutdown(); 146 Service::IR::Shutdown();
157 Service::HID::Shutdown(); 147 Service::HID::Shutdown();
158 Service::PTM::Shutdown(); 148 Service::FRD::Shutdown();
159 Service::APT::Shutdown();
160 Service::CFG::Shutdown(); 149 Service::CFG::Shutdown();
150 Service::CECD::Shutdown();
151 Service::CAM::Shutdown();
152 Service::BOSS::Shutdown();
153 Service::APT::Shutdown();
154 Service::AM::Shutdown();
161 Service::FS::ArchiveShutdown(); 155 Service::FS::ArchiveShutdown();
162 156
163 g_srv_services.clear(); 157 g_srv_services.clear();
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index 39b8d65fd..1e0f5df9b 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -139,7 +139,7 @@ static int TranslateError(int error) {
139 auto found = error_map.find(error); 139 auto found = error_map.find(error);
140 if (found != error_map.end()) 140 if (found != error_map.end())
141 return -found->second; 141 return -found->second;
142 142
143 return error; 143 return error;
144} 144}
145 145
@@ -346,7 +346,7 @@ static void Bind(Service::Interface* self) {
346 sockaddr sock_addr = CTRSockAddr::ToPlatform(*ctr_sock_addr); 346 sockaddr sock_addr = CTRSockAddr::ToPlatform(*ctr_sock_addr);
347 347
348 int res = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len)); 348 int res = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len));
349 349
350 int result = 0; 350 int result = 0;
351 if (res != 0) 351 if (res != 0)
352 result = TranslateError(GET_ERRNO); 352 result = TranslateError(GET_ERRNO);
@@ -360,14 +360,14 @@ static void Fcntl(Service::Interface* self) {
360 u32 socket_handle = cmd_buffer[1]; 360 u32 socket_handle = cmd_buffer[1];
361 u32 ctr_cmd = cmd_buffer[2]; 361 u32 ctr_cmd = cmd_buffer[2];
362 u32 ctr_arg = cmd_buffer[3]; 362 u32 ctr_arg = cmd_buffer[3];
363 363
364 int result = 0; 364 int result = 0;
365 u32 posix_ret = 0; // TODO: Check what hardware returns for F_SETFL (unspecified by POSIX) 365 u32 posix_ret = 0; // TODO: Check what hardware returns for F_SETFL (unspecified by POSIX)
366 SCOPE_EXIT({ 366 SCOPE_EXIT({
367 cmd_buffer[1] = result; 367 cmd_buffer[1] = result;
368 cmd_buffer[2] = posix_ret; 368 cmd_buffer[2] = posix_ret;
369 }); 369 });
370 370
371 if (ctr_cmd == 3) { // F_GETFL 371 if (ctr_cmd == 3) { // F_GETFL
372#if EMU_PLATFORM == PLATFORM_WINDOWS 372#if EMU_PLATFORM == PLATFORM_WINDOWS
373 posix_ret = 0; 373 posix_ret = 0;
@@ -404,11 +404,11 @@ static void Fcntl(Service::Interface* self) {
404 posix_ret = -1; 404 posix_ret = -1;
405 return; 405 return;
406 } 406 }
407 407
408 flags &= ~O_NONBLOCK; 408 flags &= ~O_NONBLOCK;
409 if (ctr_arg & 4) // O_NONBLOCK 409 if (ctr_arg & 4) // O_NONBLOCK
410 flags |= O_NONBLOCK; 410 flags |= O_NONBLOCK;
411 411
412 int ret = ::fcntl(socket_handle, F_SETFL, flags); 412 int ret = ::fcntl(socket_handle, F_SETFL, flags);
413 if (ret == SOCKET_ERROR_VALUE) { 413 if (ret == SOCKET_ERROR_VALUE) {
414 result = TranslateError(GET_ERRNO); 414 result = TranslateError(GET_ERRNO);
@@ -439,8 +439,8 @@ static void Listen(Service::Interface* self) {
439} 439}
440 440
441static void Accept(Service::Interface* self) { 441static void Accept(Service::Interface* self) {
442 // TODO(Subv): Calling this function on a blocking socket will block the emu thread, 442 // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
443 // preventing graceful shutdown when closing the emulator, this can be fixed by always 443 // preventing graceful shutdown when closing the emulator, this can be fixed by always
444 // performing nonblocking operations and spinlock until the data is available 444 // performing nonblocking operations and spinlock until the data is available
445 u32* cmd_buffer = Kernel::GetCommandBuffer(); 445 u32* cmd_buffer = Kernel::GetCommandBuffer();
446 u32 socket_handle = cmd_buffer[1]; 446 u32 socket_handle = cmd_buffer[1];
@@ -448,7 +448,7 @@ static void Accept(Service::Interface* self) {
448 sockaddr addr; 448 sockaddr addr;
449 socklen_t addr_len = sizeof(addr); 449 socklen_t addr_len = sizeof(addr);
450 u32 ret = static_cast<u32>(::accept(socket_handle, &addr, &addr_len)); 450 u32 ret = static_cast<u32>(::accept(socket_handle, &addr, &addr_len));
451 451
452 if ((s32)ret != SOCKET_ERROR_VALUE) 452 if ((s32)ret != SOCKET_ERROR_VALUE)
453 open_sockets[ret] = { ret, true }; 453 open_sockets[ret] = { ret, true };
454 454
@@ -525,8 +525,8 @@ static void SendTo(Service::Interface* self) {
525} 525}
526 526
527static void RecvFrom(Service::Interface* self) { 527static void RecvFrom(Service::Interface* self) {
528 // TODO(Subv): Calling this function on a blocking socket will block the emu thread, 528 // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
529 // preventing graceful shutdown when closing the emulator, this can be fixed by always 529 // preventing graceful shutdown when closing the emulator, this can be fixed by always
530 // performing nonblocking operations and spinlock until the data is available 530 // performing nonblocking operations and spinlock until the data is available
531 u32* cmd_buffer = Kernel::GetCommandBuffer(); 531 u32* cmd_buffer = Kernel::GetCommandBuffer();
532 u32 socket_handle = cmd_buffer[1]; 532 u32 socket_handle = cmd_buffer[1];
@@ -568,7 +568,7 @@ static void Poll(Service::Interface* self) {
568 pollfd* platform_pollfd = new pollfd[nfds]; 568 pollfd* platform_pollfd = new pollfd[nfds];
569 for (unsigned current_fds = 0; current_fds < nfds; ++current_fds) 569 for (unsigned current_fds = 0; current_fds < nfds; ++current_fds)
570 platform_pollfd[current_fds] = CTRPollFD::ToPlatform(input_fds[current_fds]); 570 platform_pollfd[current_fds] = CTRPollFD::ToPlatform(input_fds[current_fds]);
571 571
572 int ret = ::poll(platform_pollfd, nfds, timeout); 572 int ret = ::poll(platform_pollfd, nfds, timeout);
573 573
574 // Now update the output pollfd structure 574 // Now update the output pollfd structure
@@ -630,7 +630,7 @@ static void GetPeerName(Service::Interface* self) {
630 socklen_t len = cmd_buffer[2]; 630 socklen_t len = cmd_buffer[2];
631 631
632 CTRSockAddr* ctr_dest_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[0x104 >> 2])); 632 CTRSockAddr* ctr_dest_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[0x104 >> 2]));
633 633
634 sockaddr dest_addr; 634 sockaddr dest_addr;
635 socklen_t dest_addr_len = sizeof(dest_addr); 635 socklen_t dest_addr_len = sizeof(dest_addr);
636 int ret = ::getpeername(socket_handle, &dest_addr, &dest_addr_len); 636 int ret = ::getpeername(socket_handle, &dest_addr, &dest_addr_len);
@@ -651,8 +651,8 @@ static void GetPeerName(Service::Interface* self) {
651} 651}
652 652
653static void Connect(Service::Interface* self) { 653static void Connect(Service::Interface* self) {
654 // TODO(Subv): Calling this function on a blocking socket will block the emu thread, 654 // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
655 // preventing graceful shutdown when closing the emulator, this can be fixed by always 655 // preventing graceful shutdown when closing the emulator, this can be fixed by always
656 // performing nonblocking operations and spinlock until the data is available 656 // performing nonblocking operations and spinlock until the data is available
657 u32* cmd_buffer = Kernel::GetCommandBuffer(); 657 u32* cmd_buffer = Kernel::GetCommandBuffer();
658 u32 socket_handle = cmd_buffer[1]; 658 u32 socket_handle = cmd_buffer[1];
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 347d241f9..6cde4fc87 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -40,9 +40,6 @@ const ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel,
40const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS, 40const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS,
41 ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E 41 ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E
42 42
43/// An invalid result code that is meant to be overwritten when a thread resumes from waiting
44const ResultCode RESULT_INVALID(0xDEADC0DE);
45
46enum ControlMemoryOperation { 43enum ControlMemoryOperation {
47 MEMORY_OPERATION_HEAP = 0x00000003, 44 MEMORY_OPERATION_HEAP = 0x00000003,
48 MEMORY_OPERATION_GSP_HEAP = 0x00010003, 45 MEMORY_OPERATION_GSP_HEAP = 0x00010003,
@@ -143,6 +140,10 @@ static ResultCode CloseHandle(Handle handle) {
143/// Wait for a handle to synchronize, timeout after the specified nanoseconds 140/// Wait for a handle to synchronize, timeout after the specified nanoseconds
144static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { 141static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) {
145 auto object = Kernel::g_handle_table.GetWaitObject(handle); 142 auto object = Kernel::g_handle_table.GetWaitObject(handle);
143 Kernel::Thread* thread = Kernel::GetCurrentThread();
144
145 thread->waitsynch_waited = false;
146
146 if (object == nullptr) 147 if (object == nullptr)
147 return ERR_INVALID_HANDLE; 148 return ERR_INVALID_HANDLE;
148 149
@@ -154,14 +155,14 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) {
154 // Check for next thread to schedule 155 // Check for next thread to schedule
155 if (object->ShouldWait()) { 156 if (object->ShouldWait()) {
156 157
157 object->AddWaitingThread(Kernel::GetCurrentThread()); 158 object->AddWaitingThread(thread);
158 Kernel::WaitCurrentThread_WaitSynchronization({ object }, false, false); 159 Kernel::WaitCurrentThread_WaitSynchronization({ object }, false, false);
159 160
160 // Create an event to wake the thread up after the specified nanosecond delay has passed 161 // Create an event to wake the thread up after the specified nanosecond delay has passed
161 Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds); 162 thread->WakeAfterDelay(nano_seconds);
162 163
163 // NOTE: output of this SVC will be set later depending on how the thread resumes 164 // NOTE: output of this SVC will be set later depending on how the thread resumes
164 return RESULT_INVALID; 165 return HLE::RESULT_INVALID;
165 } 166 }
166 167
167 object->Acquire(); 168 object->Acquire();
@@ -173,6 +174,9 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) {
173static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { 174static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) {
174 bool wait_thread = !wait_all; 175 bool wait_thread = !wait_all;
175 int handle_index = 0; 176 int handle_index = 0;
177 Kernel::Thread* thread = Kernel::GetCurrentThread();
178 bool was_waiting = thread->waitsynch_waited;
179 thread->waitsynch_waited = false;
176 180
177 // Check if 'handles' is invalid 181 // Check if 'handles' is invalid
178 if (handles == nullptr) 182 if (handles == nullptr)
@@ -190,6 +194,9 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
190 // necessary 194 // necessary
191 if (handle_count != 0) { 195 if (handle_count != 0) {
192 bool selected = false; // True once an object has been selected 196 bool selected = false; // True once an object has been selected
197
198 Kernel::SharedPtr<Kernel::WaitObject> wait_object;
199
193 for (int i = 0; i < handle_count; ++i) { 200 for (int i = 0; i < handle_count; ++i) {
194 auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); 201 auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
195 if (object == nullptr) 202 if (object == nullptr)
@@ -204,10 +211,11 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
204 wait_thread = true; 211 wait_thread = true;
205 } else { 212 } else {
206 // Do not wait on this object, check if this object should be selected... 213 // Do not wait on this object, check if this object should be selected...
207 if (!wait_all && !selected) { 214 if (!wait_all && (!selected || (wait_object == object && was_waiting))) {
208 // Do not wait the thread 215 // Do not wait the thread
209 wait_thread = false; 216 wait_thread = false;
210 handle_index = i; 217 handle_index = i;
218 wait_object = object;
211 selected = true; 219 selected = true;
212 } 220 }
213 } 221 }
@@ -228,7 +236,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
228 // Actually wait the current thread on each object if we decided to wait... 236 // Actually wait the current thread on each object if we decided to wait...
229 std::vector<SharedPtr<Kernel::WaitObject>> wait_objects; 237 std::vector<SharedPtr<Kernel::WaitObject>> wait_objects;
230 wait_objects.reserve(handle_count); 238 wait_objects.reserve(handle_count);
231 239
232 for (int i = 0; i < handle_count; ++i) { 240 for (int i = 0; i < handle_count; ++i) {
233 auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); 241 auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
234 object->AddWaitingThread(Kernel::GetCurrentThread()); 242 object->AddWaitingThread(Kernel::GetCurrentThread());
@@ -241,7 +249,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
241 Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds); 249 Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds);
242 250
243 // NOTE: output of this SVC will be set later depending on how the thread resumes 251 // NOTE: output of this SVC will be set later depending on how the thread resumes
244 return RESULT_INVALID; 252 return HLE::RESULT_INVALID;
245 } 253 }
246 254
247 // Acquire objects if we did not wait... 255 // Acquire objects if we did not wait...
@@ -261,7 +269,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
261 269
262 // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does 270 // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does
263 // not seem to set it to any meaningful value. 271 // not seem to set it to any meaningful value.
264 *out = wait_all ? 0 : handle_index; 272 *out = handle_count != 0 ? (wait_all ? -1 : handle_index) : 0;
265 273
266 return RESULT_SUCCESS; 274 return RESULT_SUCCESS;
267} 275}
@@ -475,7 +483,7 @@ static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
475 return ERR_INVALID_HANDLE; 483 return ERR_INVALID_HANDLE;
476 484
477 const SharedPtr<Kernel::Process> process = thread->owner_process; 485 const SharedPtr<Kernel::Process> process = thread->owner_process;
478 486
479 ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle); 487 ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle);
480 488
481 *process_id = process->process_id; 489 *process_id = process->process_id;
@@ -654,6 +662,8 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
654 using Kernel::MemoryPermission; 662 using Kernel::MemoryPermission;
655 SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(size, 663 SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(size,
656 (MemoryPermission)my_permission, (MemoryPermission)other_permission); 664 (MemoryPermission)my_permission, (MemoryPermission)other_permission);
665 // Map the SharedMemory to the specified address
666 shared_memory->base_address = addr;
657 CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); 667 CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory)));
658 668
659 LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); 669 LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr);
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index ddc5d647e..7471def57 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -2,6 +2,7 @@
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 "common/color.h"
5#include "common/common_types.h" 6#include "common/common_types.h"
6 7
7#include "core/arm/arm_interface.h" 8#include "core/arm/arm_interface.h"
@@ -22,7 +23,6 @@
22#include "video_core/command_processor.h" 23#include "video_core/command_processor.h"
23#include "video_core/utils.h" 24#include "video_core/utils.h"
24#include "video_core/video_core.h" 25#include "video_core/video_core.h"
25#include "video_core/color.h"
26 26
27namespace GPU { 27namespace GPU {
28 28
@@ -30,8 +30,8 @@ Regs g_regs;
30 30
31/// True if the current frame was skipped 31/// True if the current frame was skipped
32bool g_skip_frame; 32bool g_skip_frame;
33/// 268MHz / gpu_refresh_rate frames per second 33/// 268MHz CPU clocks / 60Hz frames per second
34static u64 frame_ticks; 34const u64 frame_ticks = 268123480ull / 60;
35/// Event id for CoreTiming 35/// Event id for CoreTiming
36static int vblank_event; 36static int vblank_event;
37/// Total number of frames drawn 37/// Total number of frames drawn
@@ -140,7 +140,7 @@ inline void Write(u32 addr, const T data) {
140 // Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions 140 // Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions
141 // TODO(Subv): Verify if raw copies perform scaling 141 // TODO(Subv): Verify if raw copies perform scaling
142 memcpy(dst_pointer, src_pointer, output_size); 142 memcpy(dst_pointer, src_pointer, output_size);
143 143
144 LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), output format: %x, flags 0x%08X, Raw copy", 144 LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), output format: %x, flags 0x%08X, Raw copy",
145 output_size, 145 output_size,
146 config.GetPhysicalInputAddress(), config.input_width.Value(), config.input_height.Value(), 146 config.GetPhysicalInputAddress(), config.input_width.Value(), config.input_height.Value(),
@@ -159,14 +159,14 @@ inline void Write(u32 addr, const T data) {
159 for (u32 x = 0; x < output_width; ++x) { 159 for (u32 x = 0; x < output_width; ++x) {
160 Math::Vec4<u8> src_color = { 0, 0, 0, 0 }; 160 Math::Vec4<u8> src_color = { 0, 0, 0, 0 };
161 161
162 // Calculate the [x,y] position of the input image 162 // Calculate the [x,y] position of the input image
163 // based on the current output position and the scale 163 // based on the current output position and the scale
164 u32 input_x = x * horizontal_scale; 164 u32 input_x = x * horizontal_scale;
165 u32 input_y = y * vertical_scale; 165 u32 input_y = y * vertical_scale;
166 166
167 if (config.flip_vertically) { 167 if (config.flip_vertically) {
168 // Flip the y value of the output data, 168 // Flip the y value of the output data,
169 // we do this after calculating the [x,y] position of the input image 169 // we do this after calculating the [x,y] position of the input image
170 // to account for the scaling options. 170 // to account for the scaling options.
171 y = output_height - y - 1; 171 y = output_height - y - 1;
172 } 172 }
@@ -302,7 +302,7 @@ static void VBlankCallback(u64 userdata, int cycles_late) {
302 // - If frameskip == 0 (disabled), always swap buffers 302 // - If frameskip == 0 (disabled), always swap buffers
303 // - If frameskip == 1, swap buffers every other frame (starting from the first frame) 303 // - If frameskip == 1, swap buffers every other frame (starting from the first frame)
304 // - If frameskip > 1, swap buffers every frameskip^n frames (starting from the second frame) 304 // - If frameskip > 1, swap buffers every frameskip^n frames (starting from the second frame)
305 if ((((Settings::values.frame_skip != 1) ^ last_skip_frame) && last_skip_frame != g_skip_frame) || 305 if ((((Settings::values.frame_skip != 1) ^ last_skip_frame) && last_skip_frame != g_skip_frame) ||
306 Settings::values.frame_skip == 0) { 306 Settings::values.frame_skip == 0) {
307 VideoCore::g_renderer->SwapBuffers(); 307 VideoCore::g_renderer->SwapBuffers();
308 } 308 }
@@ -357,7 +357,6 @@ void Init() {
357 framebuffer_sub.color_format = Regs::PixelFormat::RGB8; 357 framebuffer_sub.color_format = Regs::PixelFormat::RGB8;
358 framebuffer_sub.active_fb = 0; 358 framebuffer_sub.active_fb = 0;
359 359
360 frame_ticks = 268123480 / Settings::values.gpu_refresh_rate;
361 last_skip_frame = false; 360 last_skip_frame = false;
362 g_skip_frame = false; 361 g_skip_frame = false;
363 frame_count = 0; 362 frame_count = 0;
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp
index f4906cc7e..c7006a498 100644
--- a/src/core/hw/hw.cpp
+++ b/src/core/hw/hw.cpp
@@ -18,7 +18,7 @@ inline void Read(T &var, const u32 addr) {
18 GPU::Read(var, addr); 18 GPU::Read(var, addr);
19 break; 19 break;
20 case VADDR_LCD: 20 case VADDR_LCD:
21 LCD::Write(var, addr); 21 LCD::Read(var, addr);
22 break; 22 break;
23 default: 23 default:
24 LOG_ERROR(HW_Memory, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); 24 LOG_ERROR(HW_Memory, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp
index 09134c95b..963c8d981 100644
--- a/src/core/hw/lcd.cpp
+++ b/src/core/hw/lcd.cpp
@@ -66,5 +66,5 @@ void Init() {
66void Shutdown() { 66void Shutdown() {
67 LOG_DEBUG(HW_LCD, "shutdown OK"); 67 LOG_DEBUG(HW_LCD, "shutdown OK");
68} 68}
69 69
70} // namespace 70} // namespace
diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h
index fb14c3b21..8631eb201 100644
--- a/src/core/hw/lcd.h
+++ b/src/core/hw/lcd.h
@@ -85,5 +85,5 @@ void Init();
85 85
86/// Shutdown hardware 86/// Shutdown hardware
87void Shutdown(); 87void Shutdown();
88 88
89} // namespace 89} // namespace
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index ad5e929ce..14aeebebb 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -234,7 +234,7 @@ ResultStatus AppLoader_THREEDSX::Load() {
234 Kernel::g_current_process = Kernel::Process::Create(filename, 0); 234 Kernel::g_current_process = Kernel::Process::Create(filename, 0);
235 Kernel::g_current_process->svc_access_mask.set(); 235 Kernel::g_current_process->svc_access_mask.set();
236 Kernel::g_current_process->address_mappings = default_address_mappings; 236 Kernel::g_current_process->address_mappings = default_address_mappings;
237 237
238 // Attach the default resource limit (APPLICATION) to the process 238 // Attach the default resource limit (APPLICATION) to the process
239 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 239 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
240 240
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp
index 5ecec9566..bf814b945 100644
--- a/src/core/mem_map.cpp
+++ b/src/core/mem_map.cpp
@@ -8,6 +8,10 @@
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9 9
10#include "core/hle/config_mem.h" 10#include "core/hle/config_mem.h"
11#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/shared_memory.h"
13#include "core/hle/kernel/vm_manager.h"
14#include "core/hle/result.h"
11#include "core/hle/shared_page.h" 15#include "core/hle/shared_page.h"
12#include "core/mem_map.h" 16#include "core/mem_map.h"
13#include "core/memory.h" 17#include "core/memory.h"
@@ -17,31 +21,23 @@
17 21
18namespace Memory { 22namespace Memory {
19 23
20u8* g_exefs_code; ///< ExeFS:/.code is loaded here
21u8* g_heap; ///< Application heap (main memory)
22u8* g_shared_mem; ///< Shared memory
23u8* g_heap_linear; ///< Linear heap
24u8* g_vram; ///< Video memory (VRAM) pointer
25u8* g_dsp_mem; ///< DSP memory
26u8* g_tls_mem; ///< TLS memory
27
28namespace { 24namespace {
29 25
30struct MemoryArea { 26struct MemoryArea {
31 u8** ptr;
32 u32 base; 27 u32 base;
33 u32 size; 28 u32 size;
29 const char* name;
34}; 30};
35 31
36// We don't declare the IO regions in here since its handled by other means. 32// We don't declare the IO regions in here since its handled by other means.
37static MemoryArea memory_areas[] = { 33static MemoryArea memory_areas[] = {
38 {&g_exefs_code, PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE}, 34 {PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE, "Process Image"}, // ExeFS:/.code is loaded here
39 {&g_heap, HEAP_VADDR, HEAP_SIZE }, 35 {HEAP_VADDR, HEAP_SIZE, "Heap"}, // Application heap (main memory)
40 {&g_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE }, 36 {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory
41 {&g_heap_linear, LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE }, 37 {LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE, "Linear Heap"}, // Linear heap (main memory)
42 {&g_vram, VRAM_VADDR, VRAM_SIZE }, 38 {VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM)
43 {&g_dsp_mem, DSP_RAM_VADDR, DSP_RAM_SIZE }, 39 {DSP_RAM_VADDR, DSP_RAM_SIZE, "DSP RAM"}, // DSP memory
44 {&g_tls_mem, TLS_AREA_VADDR, TLS_AREA_SIZE }, 40 {TLS_AREA_VADDR, TLS_AREA_SIZE, "TLS Area"}, // TLS memory
45}; 41};
46 42
47/// Represents a block of memory mapped by ControlMemory/MapMemoryBlock 43/// Represents a block of memory mapped by ControlMemory/MapMemoryBlock
@@ -135,27 +131,34 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) {
135 return addr | 0x80000000; 131 return addr | 0x80000000;
136} 132}
137 133
134// TODO(yuriks): Move this into Process
135static Kernel::VMManager address_space;
136
138void Init() { 137void Init() {
138 using namespace Kernel;
139
139 InitMemoryMap(); 140 InitMemoryMap();
140 141
141 for (MemoryArea& area : memory_areas) { 142 for (MemoryArea& area : memory_areas) {
142 *area.ptr = new u8[area.size]; 143 auto block = std::make_shared<std::vector<u8>>(area.size);
143 MapMemoryRegion(area.base, area.size, *area.ptr); 144 address_space.MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private).Unwrap();
144 } 145 }
145 MapMemoryRegion(CONFIG_MEMORY_VADDR, CONFIG_MEMORY_SIZE, (u8*)&ConfigMem::config_mem);
146 MapMemoryRegion(SHARED_PAGE_VADDR, SHARED_PAGE_SIZE, (u8*)&SharedPage::shared_page);
147 146
148 LOG_DEBUG(HW_Memory, "initialized OK, RAM at %p", g_heap); 147 auto cfg_mem_vma = address_space.MapBackingMemory(CONFIG_MEMORY_VADDR,
148 (u8*)&ConfigMem::config_mem, CONFIG_MEMORY_SIZE, MemoryState::Shared).MoveFrom();
149 address_space.Reprotect(cfg_mem_vma, VMAPermission::Read);
150
151 auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR,
152 (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom();
153 address_space.Reprotect(shared_page_vma, VMAPermission::Read);
154
155 LOG_DEBUG(HW_Memory, "initialized OK");
149} 156}
150 157
151void Shutdown() { 158void Shutdown() {
152 heap_map.clear(); 159 heap_map.clear();
153 heap_linear_map.clear(); 160 heap_linear_map.clear();
154 161 address_space.Reset();
155 for (MemoryArea& area : memory_areas) {
156 delete[] *area.ptr;
157 *area.ptr = nullptr;
158 }
159 162
160 LOG_DEBUG(HW_Memory, "shutdown OK"); 163 LOG_DEBUG(HW_Memory, "shutdown OK");
161} 164}
diff --git a/src/core/mem_map.h b/src/core/mem_map.h
index 945815cd6..ba50914a8 100644
--- a/src/core/mem_map.h
+++ b/src/core/mem_map.h
@@ -8,14 +8,6 @@
8 8
9namespace Memory { 9namespace Memory {
10 10
11extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here
12extern u8* g_heap; ///< Application heap (main memory)
13extern u8* g_shared_mem; ///< Shared memory
14extern u8* g_heap_linear; ///< Linear heap (main memory)
15extern u8* g_vram; ///< Video memory (VRAM)
16extern u8* g_dsp_mem; ///< DSP memory
17extern u8* g_tls_mem; ///< TLS memory
18
19void Init(); 11void Init();
20void Shutdown(); 12void Shutdown();
21 13
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 5d8069acd..28844a915 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -14,12 +14,10 @@
14#include "core/hw/hw.h" 14#include "core/hw/hw.h"
15#include "core/mem_map.h" 15#include "core/mem_map.h"
16#include "core/memory.h" 16#include "core/memory.h"
17#include "core/memory_setup.h"
17 18
18namespace Memory { 19namespace Memory {
19 20
20const u32 PAGE_MASK = PAGE_SIZE - 1;
21const int PAGE_BITS = 12;
22
23enum class PageType { 21enum class PageType {
24 /// Page is unmapped and should cause an access error. 22 /// Page is unmapped and should cause an access error.
25 Unmapped, 23 Unmapped,
@@ -64,7 +62,7 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) {
64 while (base != end) { 62 while (base != end) {
65 ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base); 63 ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base);
66 64
67 if (current_page_table->attributes[base] != PageType::Unmapped) { 65 if (current_page_table->attributes[base] != PageType::Unmapped && type != PageType::Unmapped) {
68 LOG_ERROR(HW_Memory, "overlapping memory ranges at %08X", base * PAGE_SIZE); 66 LOG_ERROR(HW_Memory, "overlapping memory ranges at %08X", base * PAGE_SIZE);
69 } 67 }
70 current_page_table->attributes[base] = type; 68 current_page_table->attributes[base] = type;
@@ -92,6 +90,12 @@ void MapIoRegion(VAddr base, u32 size) {
92 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special); 90 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special);
93} 91}
94 92
93void UnmapRegion(VAddr base, u32 size) {
94 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size);
95 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base);
96 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped);
97}
98
95template <typename T> 99template <typename T>
96T Read(const VAddr vaddr) { 100T Read(const VAddr vaddr) {
97 const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 101 const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
diff --git a/src/core/memory.h b/src/core/memory.h
index 2d225801b..0b8ff9ec4 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -97,7 +97,7 @@ enum : VAddr {
97 SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, 97 SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
98 98
99 // TODO(yuriks): The size of this area is dynamic, the kernel grows 99 // TODO(yuriks): The size of this area is dynamic, the kernel grows
100 // it as more and more threads are created. For now we'll just use a 100 // it as more and more threads are created. For now we'll just use a
101 // hardcoded value. 101 // hardcoded value.
102 /// Area where TLS (Thread-Local Storage) buffers are allocated. 102 /// Area where TLS (Thread-Local Storage) buffers are allocated.
103 TLS_AREA_VADDR = 0x1FF82000, 103 TLS_AREA_VADDR = 0x1FF82000,
diff --git a/src/core/memory_setup.h b/src/core/memory_setup.h
index 46263495f..361bfc816 100644
--- a/src/core/memory_setup.h
+++ b/src/core/memory_setup.h
@@ -6,8 +6,13 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8 8
9#include "core/memory.h"
10
9namespace Memory { 11namespace Memory {
10 12
13const u32 PAGE_MASK = PAGE_SIZE - 1;
14const int PAGE_BITS = 12;
15
11void InitMemoryMap(); 16void InitMemoryMap();
12 17
13/** 18/**
@@ -26,4 +31,6 @@ void MapMemoryRegion(VAddr base, u32 size, u8* target);
26 */ 31 */
27void MapIoRegion(VAddr base, u32 size); 32void MapIoRegion(VAddr base, u32 size);
28 33
34void UnmapRegion(VAddr base, u32 size);
35
29} 36}
diff --git a/src/core/settings.h b/src/core/settings.h
index 54c1023b8..5a70d157a 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -35,7 +35,6 @@ struct Values {
35 int pad_cright_key; 35 int pad_cright_key;
36 36
37 // Core 37 // Core
38 int gpu_refresh_rate;
39 int frame_skip; 38 int frame_skip;
40 39
41 // Data Storage 40 // Data Storage
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 0258a3255..5c7f4ae18 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -29,11 +29,9 @@ set(HEADERS
29 renderer_opengl/pica_to_gl.h 29 renderer_opengl/pica_to_gl.h
30 renderer_opengl/renderer_opengl.h 30 renderer_opengl/renderer_opengl.h
31 clipper.h 31 clipper.h
32 color.h
33 command_processor.h 32 command_processor.h
34 gpu_debugger.h 33 gpu_debugger.h
35 hwrasterizer_base.h 34 hwrasterizer_base.h
36 math.h
37 pica.h 35 pica.h
38 primitive_assembly.h 36 primitive_assembly.h
39 rasterizer.h 37 rasterizer.h
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 100d8c7c1..b46fadd9f 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -56,7 +56,17 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
56 // Trigger IRQ 56 // Trigger IRQ
57 case PICA_REG_INDEX(trigger_irq): 57 case PICA_REG_INDEX(trigger_irq):
58 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D); 58 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D);
59 return; 59 break;
60
61 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c):
62 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d):
63 {
64 unsigned index = id - PICA_REG_INDEX(command_buffer.trigger[0]);
65 u32* head_ptr = (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index));
66 g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr;
67 g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32);
68 break;
69 }
60 70
61 // It seems like these trigger vertex rendering 71 // It seems like these trigger vertex rendering
62 case PICA_REG_INDEX(trigger_draw): 72 case PICA_REG_INDEX(trigger_draw):
@@ -136,7 +146,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
136 input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(), 146 input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(),
137 input.attr[i][2].ToFloat32(), input.attr[i][3].ToFloat32()); 147 input.attr[i][2].ToFloat32(), input.attr[i][3].ToFloat32());
138 } 148 }
139 149
140 // Load per-vertex data from the loader arrays 150 // Load per-vertex data from the loader arrays
141 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 151 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
142 const u8* srcdata = Memory::GetPhysicalPointer(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]); 152 const u8* srcdata = Memory::GetPhysicalPointer(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]);
@@ -193,7 +203,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
193 const Pica::VertexShader::OutputVertex& v2) { 203 const Pica::VertexShader::OutputVertex& v2) {
194 VideoCore::g_renderer->hw_rasterizer->AddTriangle(v0, v1, v2); 204 VideoCore::g_renderer->hw_rasterizer->AddTriangle(v0, v1, v2);
195 }; 205 };
196 206
197 primitive_assembler.SubmitVertex(output, AddHWTriangle); 207 primitive_assembler.SubmitVertex(output, AddHWTriangle);
198 } else { 208 } else {
199 // Send to triangle clipper 209 // Send to triangle clipper
@@ -282,7 +292,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
282 } 292 }
283 break; 293 break;
284 } 294 }
285 295
286 // Load default vertex input attributes 296 // Load default vertex input attributes
287 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233): 297 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233):
288 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234): 298 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234):
@@ -306,7 +316,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
306 } 316 }
307 317
308 Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index]; 318 Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index];
309 319
310 // NOTE: The destination component order indeed is "backwards" 320 // NOTE: The destination component order indeed is "backwards"
311 attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8); 321 attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8);
312 attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF)); 322 attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF));
@@ -363,38 +373,34 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
363 g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id)); 373 g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id));
364} 374}
365 375
366static std::ptrdiff_t ExecuteCommandBlock(const u32* first_command_word) {
367 const CommandHeader& header = *(const CommandHeader*)(&first_command_word[1]);
368
369 u32* read_pointer = (u32*)first_command_word;
370
371 const u32 write_mask = ((header.parameter_mask & 0x1) ? (0xFFu << 0) : 0u) |
372 ((header.parameter_mask & 0x2) ? (0xFFu << 8) : 0u) |
373 ((header.parameter_mask & 0x4) ? (0xFFu << 16) : 0u) |
374 ((header.parameter_mask & 0x8) ? (0xFFu << 24) : 0u);
375
376 WritePicaReg(header.cmd_id, *read_pointer, write_mask);
377 read_pointer += 2;
378
379 for (unsigned int i = 1; i < 1+header.extra_data_length; ++i) {
380 u32 cmd = header.cmd_id + ((header.group_commands) ? i : 0);
381 WritePicaReg(cmd, *read_pointer, write_mask);
382 ++read_pointer;
383 }
384
385 // align read pointer to 8 bytes
386 if ((first_command_word - read_pointer) % 2)
387 ++read_pointer;
388
389 return read_pointer - first_command_word;
390}
391
392void ProcessCommandList(const u32* list, u32 size) { 376void ProcessCommandList(const u32* list, u32 size) {
393 u32* read_pointer = (u32*)list; 377 g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = list;
394 u32 list_length = size / sizeof(u32); 378 g_state.cmd_list.length = size / sizeof(u32);
395 379
396 while (read_pointer < list + list_length) { 380 while (g_state.cmd_list.current_ptr < g_state.cmd_list.head_ptr + g_state.cmd_list.length) {
397 read_pointer += ExecuteCommandBlock(read_pointer); 381 // Expand a 4-bit mask to 4-byte mask, e.g. 0b0101 -> 0x00FF00FF
382 static const u32 expand_bits_to_bytes[] = {
383 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
384 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
385 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
386 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff
387 };
388
389 // Align read pointer to 8 bytes
390 if ((g_state.cmd_list.head_ptr - g_state.cmd_list.current_ptr) % 2 != 0)
391 ++g_state.cmd_list.current_ptr;
392
393 u32 value = *g_state.cmd_list.current_ptr++;
394 const CommandHeader header = { *g_state.cmd_list.current_ptr++ };
395 const u32 write_mask = expand_bits_to_bytes[header.parameter_mask];
396 u32 cmd = header.cmd_id;
397
398 WritePicaReg(cmd, value, write_mask);
399
400 for (unsigned i = 0; i < header.extra_data_length; ++i) {
401 u32 cmd = header.cmd_id + (header.group_commands ? i + 1 : 0);
402 WritePicaReg(cmd, *g_state.cmd_list.current_ptr++, write_mask);
403 }
398 } 404 }
399} 405}
400 406
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 7987b922c..7b8ab72b6 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -17,11 +17,11 @@
17#include <nihstro/shader_binary.h> 17#include <nihstro/shader_binary.h>
18 18
19#include "common/assert.h" 19#include "common/assert.h"
20#include "common/color.h"
20#include "common/file_util.h" 21#include "common/file_util.h"
21#include "common/math_util.h" 22#include "common/math_util.h"
23#include "common/vector_math.h"
22 24
23#include "video_core/color.h"
24#include "video_core/math.h"
25#include "video_core/pica.h" 25#include "video_core/pica.h"
26#include "video_core/utils.h" 26#include "video_core/utils.h"
27#include "video_core/video_core.h" 27#include "video_core/video_core.h"
@@ -319,7 +319,7 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
319 // TODO(neobrain): Fix code design to unify vertical block offsets! 319 // TODO(neobrain): Fix code design to unify vertical block offsets!
320 source += coarse_y * info.stride; 320 source += coarse_y * info.stride;
321 } 321 }
322 322
323 // TODO: Assert that width/height are multiples of block dimensions 323 // TODO: Assert that width/height are multiples of block dimensions
324 324
325 switch (info.format) { 325 switch (info.format) {
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
index f361a5385..7926d64ec 100644
--- a/src/video_core/debug_utils/debug_utils.h
+++ b/src/video_core/debug_utils/debug_utils.h
@@ -12,7 +12,8 @@
12#include <mutex> 12#include <mutex>
13#include <vector> 13#include <vector>
14 14
15#include "video_core/math.h" 15#include "common/vector_math.h"
16
16#include "video_core/pica.h" 17#include "video_core/pica.h"
17 18
18namespace Pica { 19namespace Pica {
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index b67dce1a9..9628a7589 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -15,8 +15,7 @@
15#include "common/common_funcs.h" 15#include "common/common_funcs.h"
16#include "common/common_types.h" 16#include "common/common_types.h"
17#include "common/logging/log.h" 17#include "common/logging/log.h"
18 18#include "common/vector_math.h"
19#include "math.h"
20 19
21namespace Pica { 20namespace Pica {
22 21
@@ -162,6 +161,25 @@ struct Regs {
162 ETC1A4 = 13, // compressed 161 ETC1A4 = 13, // compressed
163 }; 162 };
164 163
164 enum class LogicOp : u32 {
165 Clear = 0,
166 And = 1,
167 AndReverse = 2,
168 Copy = 3,
169 Set = 4,
170 CopyInverted = 5,
171 NoOp = 6,
172 Invert = 7,
173 Nand = 8,
174 Or = 9,
175 Nor = 10,
176 Xor = 11,
177 Equiv = 12,
178 AndInverted = 13,
179 OrReverse = 14,
180 OrInverted = 15,
181 };
182
165 static unsigned NibblesPerPixel(TextureFormat format) { 183 static unsigned NibblesPerPixel(TextureFormat format) {
166 switch (format) { 184 switch (format) {
167 case TextureFormat::RGBA8: 185 case TextureFormat::RGBA8:
@@ -221,6 +239,7 @@ struct Regs {
221 enum class Source : u32 { 239 enum class Source : u32 {
222 PrimaryColor = 0x0, 240 PrimaryColor = 0x0,
223 PrimaryFragmentColor = 0x1, 241 PrimaryFragmentColor = 0x1,
242 SecondaryFragmentColor = 0x2,
224 243
225 Texture0 = 0x3, 244 Texture0 = 0x3,
226 Texture1 = 0x4, 245 Texture1 = 0x4,
@@ -337,7 +356,7 @@ struct Regs {
337 return (stage_index < 4) && (update_mask_a & (1 << stage_index)); 356 return (stage_index < 4) && (update_mask_a & (1 << stage_index));
338 } 357 }
339 } tev_combiner_buffer_input; 358 } tev_combiner_buffer_input;
340 359
341 INSERT_PADDING_WORDS(0xf); 360 INSERT_PADDING_WORDS(0xf);
342 TevStageConfig tev_stage4; 361 TevStageConfig tev_stage4;
343 INSERT_PADDING_WORDS(0x3); 362 INSERT_PADDING_WORDS(0x3);
@@ -353,9 +372,9 @@ struct Regs {
353 INSERT_PADDING_WORDS(0x2); 372 INSERT_PADDING_WORDS(0x2);
354 373
355 const std::array<Regs::TevStageConfig,6> GetTevStages() const { 374 const std::array<Regs::TevStageConfig,6> GetTevStages() const {
356 return { tev_stage0, tev_stage1, 375 return {{ tev_stage0, tev_stage1,
357 tev_stage2, tev_stage3, 376 tev_stage2, tev_stage3,
358 tev_stage4, tev_stage5 }; 377 tev_stage4, tev_stage5 }};
359 }; 378 };
360 379
361 enum class BlendEquation : u32 { 380 enum class BlendEquation : u32 {
@@ -413,12 +432,8 @@ struct Regs {
413 } alpha_blending; 432 } alpha_blending;
414 433
415 union { 434 union {
416 enum Op { 435 BitField<0, 4, LogicOp> logic_op;
417 Set = 4, 436 };
418 };
419
420 BitField<0, 4, Op> op;
421 } logic_op;
422 437
423 union { 438 union {
424 BitField< 0, 8, u32> r; 439 BitField< 0, 8, u32> r;
@@ -703,12 +718,38 @@ struct Regs {
703 struct { 718 struct {
704 // Index of the current default attribute 719 // Index of the current default attribute
705 u32 index; 720 u32 index;
706 721
707 // Writing to these registers sets the "current" default attribute. 722 // Writing to these registers sets the "current" default attribute.
708 u32 set_value[3]; 723 u32 set_value[3];
709 } vs_default_attributes_setup; 724 } vs_default_attributes_setup;
710 725
711 INSERT_PADDING_WORDS(0x28); 726 INSERT_PADDING_WORDS(0x2);
727
728 struct {
729 // There are two channels that can be used to configure the next command buffer, which
730 // can be then executed by writing to the "trigger" registers. There are two reasons why a
731 // game might use this feature:
732 // 1) With this, an arbitrary number of additional command buffers may be executed in
733 // sequence without requiring any intervention of the CPU after the initial one is
734 // kicked off.
735 // 2) Games can configure these registers to provide a command list subroutine mechanism.
736
737 BitField< 0, 20, u32> size[2]; ///< Size (in bytes / 8) of each channel's command buffer
738 BitField< 0, 28, u32> addr[2]; ///< Physical address / 8 of each channel's command buffer
739 u32 trigger[2]; ///< Triggers execution of the channel's command buffer when written to
740
741 unsigned GetSize(unsigned index) const {
742 ASSERT(index < 2);
743 return 8 * size[index];
744 }
745
746 PAddr GetPhysicalAddress(unsigned index) const {
747 ASSERT(index < 2);
748 return (PAddr)(8 * addr[index]);
749 }
750 } command_buffer;
751
752 INSERT_PADDING_WORDS(0x20);
712 753
713 enum class TriangleTopology : u32 { 754 enum class TriangleTopology : u32 {
714 List = 0, 755 List = 0,
@@ -861,6 +902,7 @@ struct Regs {
861 ADD_FIELD(trigger_draw); 902 ADD_FIELD(trigger_draw);
862 ADD_FIELD(trigger_draw_indexed); 903 ADD_FIELD(trigger_draw_indexed);
863 ADD_FIELD(vs_default_attributes_setup); 904 ADD_FIELD(vs_default_attributes_setup);
905 ADD_FIELD(command_buffer);
864 ADD_FIELD(triangle_topology); 906 ADD_FIELD(triangle_topology);
865 ADD_FIELD(vs_bool_uniforms); 907 ADD_FIELD(vs_bool_uniforms);
866 ADD_FIELD(vs_int_uniforms); 908 ADD_FIELD(vs_int_uniforms);
@@ -938,6 +980,7 @@ ASSERT_REG_POSITION(num_vertices, 0x228);
938ASSERT_REG_POSITION(trigger_draw, 0x22e); 980ASSERT_REG_POSITION(trigger_draw, 0x22e);
939ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f); 981ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f);
940ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232); 982ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232);
983ASSERT_REG_POSITION(command_buffer, 0x238);
941ASSERT_REG_POSITION(triangle_topology, 0x25e); 984ASSERT_REG_POSITION(triangle_topology, 0x25e);
942ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0); 985ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0);
943ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1); 986ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1);
@@ -1053,21 +1096,12 @@ private:
1053 float value; 1096 float value;
1054}; 1097};
1055 1098
1056union CommandHeader {
1057 CommandHeader(u32 h) : hex(h) {}
1058
1059 u32 hex;
1060
1061 BitField< 0, 16, u32> cmd_id;
1062 BitField<16, 4, u32> parameter_mask;
1063 BitField<20, 11, u32> extra_data_length;
1064 BitField<31, 1, u32> group_commands;
1065};
1066
1067/// Struct used to describe current Pica state 1099/// Struct used to describe current Pica state
1068struct State { 1100struct State {
1101 /// Pica registers
1069 Regs regs; 1102 Regs regs;
1070 1103
1104 /// Vertex shader memory
1071 struct { 1105 struct {
1072 struct { 1106 struct {
1073 Math::Vec4<float24> f[96]; 1107 Math::Vec4<float24> f[96];
@@ -1080,6 +1114,13 @@ struct State {
1080 std::array<u32, 1024> program_code; 1114 std::array<u32, 1024> program_code;
1081 std::array<u32, 1024> swizzle_data; 1115 std::array<u32, 1024> swizzle_data;
1082 } vs; 1116 } vs;
1117
1118 /// Current Pica command list
1119 struct {
1120 const u32* head_ptr;
1121 const u32* current_ptr;
1122 u32 length;
1123 } cmd_list;
1083}; 1124};
1084 1125
1085/// Initialize Pica state 1126/// Initialize Pica state
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 767ff4205..59d156ee7 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -4,6 +4,7 @@
4 4
5#include <algorithm> 5#include <algorithm>
6 6
7#include "common/color.h"
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "common/math_util.h" 9#include "common/math_util.h"
9#include "common/profiler.h" 10#include "common/profiler.h"
@@ -13,7 +14,6 @@
13 14
14#include "debug_utils/debug_utils.h" 15#include "debug_utils/debug_utils.h"
15#include "math.h" 16#include "math.h"
16#include "color.h"
17#include "pica.h" 17#include "pica.h"
18#include "rasterizer.h" 18#include "rasterizer.h"
19#include "vertex_shader.h" 19#include "vertex_shader.h"
@@ -104,7 +104,7 @@ static u32 GetDepth(int x, int y) {
104 u8* depth_buffer = Memory::GetPhysicalPointer(addr); 104 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
105 105
106 y = framebuffer.height - y; 106 y = framebuffer.height - y;
107 107
108 const u32 coarse_y = y & ~7; 108 const u32 coarse_y = y & ~7;
109 u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format); 109 u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format);
110 u32 stride = framebuffer.width * bytes_per_pixel; 110 u32 stride = framebuffer.width * bytes_per_pixel;
@@ -402,11 +402,16 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
402 402
403 auto GetSource = [&](Source source) -> Math::Vec4<u8> { 403 auto GetSource = [&](Source source) -> Math::Vec4<u8> {
404 switch (source) { 404 switch (source) {
405 // TODO: What's the difference between these two?
406 case Source::PrimaryColor: 405 case Source::PrimaryColor:
406
407 // HACK: Until we implement fragment lighting, use primary_color
407 case Source::PrimaryFragmentColor: 408 case Source::PrimaryFragmentColor:
408 return primary_color; 409 return primary_color;
409 410
411 // HACK: Until we implement fragment lighting, use zero
412 case Source::SecondaryFragmentColor:
413 return {0, 0, 0, 0};
414
410 case Source::Texture0: 415 case Source::Texture0:
411 return texture_color[0]; 416 return texture_color[0];
412 417
@@ -570,6 +575,13 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
570 case Operation::Add: 575 case Operation::Add:
571 return std::min(255, input[0] + input[1]); 576 return std::min(255, input[0] + input[1]);
572 577
578 case Operation::AddSigned:
579 {
580 // TODO(bunnei): Verify that the color conversion from (float) 0.5f to (byte) 128 is correct
581 auto result = static_cast<int>(input[0]) + static_cast<int>(input[1]) - 128;
582 return static_cast<u8>(MathUtil::Clamp<int>(result, 0, 255));
583 }
584
573 case Operation::Lerp: 585 case Operation::Lerp:
574 return (input[0] * input[2] + input[1] * (255 - input[2])) / 255; 586 return (input[0] * input[2] + input[1] * (255 - input[2])) / 255;
575 587
@@ -808,10 +820,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
808 } 820 }
809 }; 821 };
810 822
811 using BlendEquation = Regs::BlendEquation;
812 static auto EvaluateBlendEquation = [](const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor, 823 static auto EvaluateBlendEquation = [](const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
813 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor, 824 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
814 BlendEquation equation) { 825 Regs::BlendEquation equation) {
815 Math::Vec4<int> result; 826 Math::Vec4<int> result;
816 827
817 auto src_result = (src * srcfactor).Cast<int>(); 828 auto src_result = (src * srcfactor).Cast<int>();
@@ -866,8 +877,63 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
866 blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb); 877 blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb);
867 blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a(); 878 blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a();
868 } else { 879 } else {
869 LOG_CRITICAL(HW_GPU, "logic op: %x", output_merger.logic_op); 880 static auto LogicOp = [](u8 src, u8 dest, Regs::LogicOp op) -> u8 {
870 UNIMPLEMENTED(); 881 switch (op) {
882 case Regs::LogicOp::Clear:
883 return 0;
884
885 case Regs::LogicOp::And:
886 return src & dest;
887
888 case Regs::LogicOp::AndReverse:
889 return src & ~dest;
890
891 case Regs::LogicOp::Copy:
892 return src;
893
894 case Regs::LogicOp::Set:
895 return 255;
896
897 case Regs::LogicOp::CopyInverted:
898 return ~src;
899
900 case Regs::LogicOp::NoOp:
901 return dest;
902
903 case Regs::LogicOp::Invert:
904 return ~dest;
905
906 case Regs::LogicOp::Nand:
907 return ~(src & dest);
908
909 case Regs::LogicOp::Or:
910 return src | dest;
911
912 case Regs::LogicOp::Nor:
913 return ~(src | dest);
914
915 case Regs::LogicOp::Xor:
916 return src ^ dest;
917
918 case Regs::LogicOp::Equiv:
919 return ~(src ^ dest);
920
921 case Regs::LogicOp::AndInverted:
922 return ~src & dest;
923
924 case Regs::LogicOp::OrReverse:
925 return src | ~dest;
926
927 case Regs::LogicOp::OrInverted:
928 return ~src | dest;
929 }
930 };
931
932 blend_output = Math::MakeVec(
933 LogicOp(combiner_output.r(), dest.r(), output_merger.logic_op),
934 LogicOp(combiner_output.g(), dest.g(), output_merger.logic_op),
935 LogicOp(combiner_output.b(), dest.b(), output_merger.logic_op),
936 LogicOp(combiner_output.a(), dest.a(), output_merger.logic_op));
871 } 937 }
872 938
873 const Math::Vec4<u8> result = { 939 const Math::Vec4<u8> result = {
diff --git a/src/video_core/renderer_opengl/generated/gl_3_2_core.c b/src/video_core/renderer_opengl/generated/gl_3_2_core.c
index ef29972d7..95fd29c0a 100644
--- a/src/video_core/renderer_opengl/generated/gl_3_2_core.c
+++ b/src/video_core/renderer_opengl/generated/gl_3_2_core.c
@@ -62,9 +62,9 @@ static int TestPointer(const PROC pTest)
62 ptrdiff_t iTest; 62 ptrdiff_t iTest;
63 if(!pTest) return 0; 63 if(!pTest) return 0;
64 iTest = (ptrdiff_t)pTest; 64 iTest = (ptrdiff_t)pTest;
65 65
66 if(iTest == 1 || iTest == 2 || iTest == 3 || iTest == -1) return 0; 66 if(iTest == 1 || iTest == 2 || iTest == 3 || iTest == -1) return 0;
67 67
68 return 1; 68 return 1;
69} 69}
70 70
@@ -79,7 +79,7 @@ static PROC WinGetProcAddress(const char *name)
79 glMod = GetModuleHandleA("OpenGL32.dll"); 79 glMod = GetModuleHandleA("OpenGL32.dll");
80 return (PROC)GetProcAddress(glMod, (LPCSTR)name); 80 return (PROC)GetProcAddress(glMod, (LPCSTR)name);
81} 81}
82 82
83#define IntGetProcAddress(name) WinGetProcAddress(name) 83#define IntGetProcAddress(name) WinGetProcAddress(name)
84#else 84#else
85 #if defined(__APPLE__) 85 #if defined(__APPLE__)
@@ -1083,7 +1083,7 @@ static ogl_StrToExtMap *FindExtEntry(const char *extensionName)
1083 if(strcmp(extensionName, currLoc->extensionName) == 0) 1083 if(strcmp(extensionName, currLoc->extensionName) == 0)
1084 return currLoc; 1084 return currLoc;
1085 } 1085 }
1086 1086
1087 return NULL; 1087 return NULL;
1088} 1088}
1089 1089
@@ -1135,15 +1135,15 @@ int ogl_LoadFunctions()
1135{ 1135{
1136 int numFailed = 0; 1136 int numFailed = 0;
1137 ClearExtensionVars(); 1137 ClearExtensionVars();
1138 1138
1139 _ptrc_glGetIntegerv = (void (CODEGEN_FUNCPTR *)(GLenum, GLint *))IntGetProcAddress("glGetIntegerv"); 1139 _ptrc_glGetIntegerv = (void (CODEGEN_FUNCPTR *)(GLenum, GLint *))IntGetProcAddress("glGetIntegerv");
1140 if(!_ptrc_glGetIntegerv) return ogl_LOAD_FAILED; 1140 if(!_ptrc_glGetIntegerv) return ogl_LOAD_FAILED;
1141 _ptrc_glGetStringi = (const GLubyte * (CODEGEN_FUNCPTR *)(GLenum, GLuint))IntGetProcAddress("glGetStringi"); 1141 _ptrc_glGetStringi = (const GLubyte * (CODEGEN_FUNCPTR *)(GLenum, GLuint))IntGetProcAddress("glGetStringi");
1142 if(!_ptrc_glGetStringi) return ogl_LOAD_FAILED; 1142 if(!_ptrc_glGetStringi) return ogl_LOAD_FAILED;
1143 1143
1144 ProcExtsFromExtList(); 1144 ProcExtsFromExtList();
1145 numFailed = Load_Version_3_2(); 1145 numFailed = Load_Version_3_2();
1146 1146
1147 if(numFailed == 0) 1147 if(numFailed == 0)
1148 return ogl_LOAD_SUCCEEDED; 1148 return ogl_LOAD_SUCCEEDED;
1149 else 1149 else
@@ -1177,7 +1177,7 @@ int ogl_IsVersionGEQ(int majorVersion, int minorVersion)
1177{ 1177{
1178 if(g_major_version == 0) 1178 if(g_major_version == 0)
1179 GetGLVersion(); 1179 GetGLVersion();
1180 1180
1181 if(majorVersion > g_major_version) return 1; 1181 if(majorVersion > g_major_version) return 1;
1182 if(majorVersion < g_major_version) return 0; 1182 if(majorVersion < g_major_version) return 0;
1183 if(minorVersion >= g_minor_version) return 1; 1183 if(minorVersion >= g_minor_version) return 1;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 4b7d099a5..518f79331 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -2,10 +2,11 @@
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 "common/color.h"
6
5#include "core/settings.h" 7#include "core/settings.h"
6#include "core/hw/gpu.h" 8#include "core/hw/gpu.h"
7 9
8#include "video_core/color.h"
9#include "video_core/pica.h" 10#include "video_core/pica.h"
10#include "video_core/utils.h" 11#include "video_core/utils.h"
11#include "video_core/renderer_opengl/gl_rasterizer.h" 12#include "video_core/renderer_opengl/gl_rasterizer.h"
@@ -93,14 +94,27 @@ void RasterizerOpenGL::InitObjects() {
93 // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation 94 // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation
94 fb_color_texture.texture.Create(); 95 fb_color_texture.texture.Create();
95 ReconfigureColorTexture(fb_color_texture, Pica::Regs::ColorFormat::RGBA8, 1, 1); 96 ReconfigureColorTexture(fb_color_texture, Pica::Regs::ColorFormat::RGBA8, 1, 1);
97
98 state.texture_units[0].enabled_2d = true;
99 state.texture_units[0].texture_2d = fb_color_texture.texture.handle;
100 state.Apply();
101
96 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); 102 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
97 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 103 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
98 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 104 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
99 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 105 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
100 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 106 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
101 107
108 state.texture_units[0].texture_2d = 0;
109 state.Apply();
110
102 fb_depth_texture.texture.Create(); 111 fb_depth_texture.texture.Create();
103 ReconfigureDepthTexture(fb_depth_texture, Pica::Regs::DepthFormat::D16, 1, 1); 112 ReconfigureDepthTexture(fb_depth_texture, Pica::Regs::DepthFormat::D16, 1, 1);
113
114 state.texture_units[0].enabled_2d = true;
115 state.texture_units[0].texture_2d = fb_depth_texture.texture.handle;
116 state.Apply();
117
104 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); 118 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
105 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 119 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
106 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 120 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
@@ -109,14 +123,13 @@ void RasterizerOpenGL::InitObjects() {
109 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); 123 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
110 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); 124 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
111 125
126 state.texture_units[0].texture_2d = 0;
127 state.Apply();
128
112 // Configure OpenGL framebuffer 129 // Configure OpenGL framebuffer
113 framebuffer.Create(); 130 framebuffer.Create();
114 131
115 state.draw.framebuffer = framebuffer.handle; 132 state.draw.framebuffer = framebuffer.handle;
116
117 // Unbind texture to allow binding to framebuffer
118 state.texture_units[0].enabled_2d = true;
119 state.texture_units[0].texture_2d = 0;
120 state.Apply(); 133 state.Apply();
121 134
122 glActiveTexture(GL_TEXTURE0); 135 glActiveTexture(GL_TEXTURE0);
@@ -135,6 +148,7 @@ void RasterizerOpenGL::Reset() {
135 SyncBlendFuncs(); 148 SyncBlendFuncs();
136 SyncBlendColor(); 149 SyncBlendColor();
137 SyncAlphaTest(); 150 SyncAlphaTest();
151 SyncLogicOp();
138 SyncStencilTest(); 152 SyncStencilTest();
139 SyncDepthTest(); 153 SyncDepthTest();
140 154
@@ -203,7 +217,19 @@ void RasterizerOpenGL::DrawTriangles() {
203 217
204 vertex_batch.clear(); 218 vertex_batch.clear();
205 219
206 // TODO: Flush the resource cache at the current depth and color framebuffer addresses for render-to-texture 220 // Flush the resource cache at the current depth and color framebuffer addresses for render-to-texture
221 const auto& regs = Pica::g_state.regs;
222
223 PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress();
224 u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format)
225 * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
226
227 PAddr cur_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress();
228 u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(regs.framebuffer.depth_format)
229 * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight();
230
231 res_cache.NotifyFlush(cur_fb_color_addr, cur_fb_color_size);
232 res_cache.NotifyFlush(cur_fb_depth_addr, cur_fb_depth_size);
207} 233}
208 234
209void RasterizerOpenGL::CommitFramebuffer() { 235void RasterizerOpenGL::CommitFramebuffer() {
@@ -249,6 +275,11 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
249 SyncDepthTest(); 275 SyncDepthTest();
250 break; 276 break;
251 277
278 // Logic op
279 case PICA_REG_INDEX(output_merger.logic_op):
280 SyncLogicOp();
281 break;
282
252 // TEV stage 0 283 // TEV stage 0
253 case PICA_REG_INDEX(tev_stage0.color_source1): 284 case PICA_REG_INDEX(tev_stage0.color_source1):
254 SyncTevSources(0, regs.tev_stage0); 285 SyncTevSources(0, regs.tev_stage0);
@@ -350,7 +381,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
350 case PICA_REG_INDEX(tev_stage5.color_scale): 381 case PICA_REG_INDEX(tev_stage5.color_scale):
351 SyncTevMultipliers(5, regs.tev_stage5); 382 SyncTevMultipliers(5, regs.tev_stage5);
352 break; 383 break;
353 384
354 // TEV combiner buffer color 385 // TEV combiner buffer color
355 case PICA_REG_INDEX(tev_combiner_buffer_color): 386 case PICA_REG_INDEX(tev_combiner_buffer_color):
356 SyncCombinerColor(); 387 SyncCombinerColor();
@@ -465,6 +496,9 @@ void RasterizerOpenGL::ReconfigureColorTexture(TextureInfo& texture, Pica::Regs:
465 glActiveTexture(GL_TEXTURE0); 496 glActiveTexture(GL_TEXTURE0);
466 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0, 497 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
467 texture.gl_format, texture.gl_type, nullptr); 498 texture.gl_format, texture.gl_type, nullptr);
499
500 state.texture_units[0].texture_2d = 0;
501 state.Apply();
468} 502}
469 503
470void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height) { 504void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height) {
@@ -484,7 +518,7 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::
484 case Pica::Regs::DepthFormat::D24: 518 case Pica::Regs::DepthFormat::D24:
485 internal_format = GL_DEPTH_COMPONENT24; 519 internal_format = GL_DEPTH_COMPONENT24;
486 texture.gl_format = GL_DEPTH_COMPONENT; 520 texture.gl_format = GL_DEPTH_COMPONENT;
487 texture.gl_type = GL_UNSIGNED_INT_24_8; 521 texture.gl_type = GL_UNSIGNED_INT;
488 break; 522 break;
489 523
490 case Pica::Regs::DepthFormat::D24S8: 524 case Pica::Regs::DepthFormat::D24S8:
@@ -506,6 +540,9 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::
506 glActiveTexture(GL_TEXTURE0); 540 glActiveTexture(GL_TEXTURE0);
507 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0, 541 glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
508 texture.gl_format, texture.gl_type, nullptr); 542 texture.gl_format, texture.gl_type, nullptr);
543
544 state.texture_units[0].texture_2d = 0;
545 state.Apply();
509} 546}
510 547
511void RasterizerOpenGL::SyncFramebuffer() { 548void RasterizerOpenGL::SyncFramebuffer() {
@@ -633,6 +670,10 @@ void RasterizerOpenGL::SyncAlphaTest() {
633 glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f); 670 glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f);
634} 671}
635 672
673void RasterizerOpenGL::SyncLogicOp() {
674 state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op);
675}
676
636void RasterizerOpenGL::SyncStencilTest() { 677void RasterizerOpenGL::SyncStencilTest() {
637 // TODO: Implement stencil test, mask, and op 678 // TODO: Implement stencil test, mask, and op
638} 679}
@@ -641,6 +682,10 @@ void RasterizerOpenGL::SyncDepthTest() {
641 const auto& regs = Pica::g_state.regs; 682 const auto& regs = Pica::g_state.regs;
642 state.depth.test_enabled = (regs.output_merger.depth_test_enable == 1); 683 state.depth.test_enabled = (regs.output_merger.depth_test_enable == 1);
643 state.depth.test_func = PicaToGL::CompareFunc(regs.output_merger.depth_test_func); 684 state.depth.test_func = PicaToGL::CompareFunc(regs.output_merger.depth_test_func);
685 state.color_mask.red_enabled = regs.output_merger.red_enable;
686 state.color_mask.green_enabled = regs.output_merger.green_enable;
687 state.color_mask.blue_enabled = regs.output_merger.blue_enable;
688 state.color_mask.alpha_enabled = regs.output_merger.alpha_enable;
644 state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE; 689 state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE;
645} 690}
646 691
@@ -748,10 +793,10 @@ void RasterizerOpenGL::ReloadColorBuffer() {
748 for (int x = 0; x < fb_color_texture.width; ++x) { 793 for (int x = 0; x < fb_color_texture.width; ++x) {
749 const u32 coarse_y = y & ~7; 794 const u32 coarse_y = y & ~7;
750 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel; 795 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel;
751 u32 gl_px_idx = x * bytes_per_pixel + y * fb_color_texture.width * bytes_per_pixel; 796 u32 gl_pixel_index = (x + y * fb_color_texture.width) * bytes_per_pixel;
752 797
753 u8* pixel = color_buffer + dst_offset; 798 u8* pixel = color_buffer + dst_offset;
754 memcpy(&temp_fb_color_buffer[gl_px_idx], pixel, bytes_per_pixel); 799 memcpy(&temp_fb_color_buffer[gl_pixel_index], pixel, bytes_per_pixel);
755 } 800 }
756 } 801 }
757 802
@@ -762,6 +807,9 @@ void RasterizerOpenGL::ReloadColorBuffer() {
762 glActiveTexture(GL_TEXTURE0); 807 glActiveTexture(GL_TEXTURE0);
763 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_color_texture.width, fb_color_texture.height, 808 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_color_texture.width, fb_color_texture.height,
764 fb_color_texture.gl_format, fb_color_texture.gl_type, temp_fb_color_buffer.get()); 809 fb_color_texture.gl_format, fb_color_texture.gl_type, temp_fb_color_buffer.get());
810
811 state.texture_units[0].texture_2d = 0;
812 state.Apply();
765} 813}
766 814
767void RasterizerOpenGL::ReloadDepthBuffer() { 815void RasterizerOpenGL::ReloadDepthBuffer() {
@@ -779,29 +827,29 @@ void RasterizerOpenGL::ReloadDepthBuffer() {
779 827
780 std::unique_ptr<u8[]> temp_fb_depth_buffer(new u8[fb_depth_texture.width * fb_depth_texture.height * gl_bpp]); 828 std::unique_ptr<u8[]> temp_fb_depth_buffer(new u8[fb_depth_texture.width * fb_depth_texture.height * gl_bpp]);
781 829
782 for (int y = 0; y < fb_depth_texture.height; ++y) { 830 u8* temp_fb_depth_data = bytes_per_pixel == 3 ? (temp_fb_depth_buffer.get() + 1) : temp_fb_depth_buffer.get();
783 for (int x = 0; x < fb_depth_texture.width; ++x) { 831
784 const u32 coarse_y = y & ~7; 832 if (fb_depth_texture.format == Pica::Regs::DepthFormat::D24S8) {
785 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; 833 for (int y = 0; y < fb_depth_texture.height; ++y) {
786 u32 gl_px_idx = x + y * fb_depth_texture.width; 834 for (int x = 0; x < fb_depth_texture.width; ++x) {
787 835 const u32 coarse_y = y & ~7;
788 switch (fb_depth_texture.format) { 836 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel;
789 case Pica::Regs::DepthFormat::D16: 837 u32 gl_pixel_index = (x + y * fb_depth_texture.width);
790 ((u16*)temp_fb_depth_buffer.get())[gl_px_idx] = Color::DecodeD16(depth_buffer + dst_offset); 838
791 break; 839 u8* pixel = depth_buffer + dst_offset;
792 case Pica::Regs::DepthFormat::D24: 840 u32 depth_stencil = *(u32*)pixel;
793 ((u32*)temp_fb_depth_buffer.get())[gl_px_idx] = Color::DecodeD24(depth_buffer + dst_offset); 841 ((u32*)temp_fb_depth_data)[gl_pixel_index] = (depth_stencil << 8) | (depth_stencil >> 24);
794 break;
795 case Pica::Regs::DepthFormat::D24S8:
796 {
797 Math::Vec2<u32> depth_stencil = Color::DecodeD24S8(depth_buffer + dst_offset);
798 ((u32*)temp_fb_depth_buffer.get())[gl_px_idx] = (depth_stencil.x << 8) | depth_stencil.y;
799 break;
800 } 842 }
801 default: 843 }
802 LOG_CRITICAL(Render_OpenGL, "Unknown memory framebuffer depth format %x", fb_depth_texture.format); 844 } else {
803 UNIMPLEMENTED(); 845 for (int y = 0; y < fb_depth_texture.height; ++y) {
804 break; 846 for (int x = 0; x < fb_depth_texture.width; ++x) {
847 const u32 coarse_y = y & ~7;
848 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel;
849 u32 gl_pixel_index = (x + y * fb_depth_texture.width) * gl_bpp;
850
851 u8* pixel = depth_buffer + dst_offset;
852 memcpy(&temp_fb_depth_data[gl_pixel_index], pixel, bytes_per_pixel);
805 } 853 }
806 } 854 }
807 } 855 }
@@ -813,6 +861,9 @@ void RasterizerOpenGL::ReloadDepthBuffer() {
813 glActiveTexture(GL_TEXTURE0); 861 glActiveTexture(GL_TEXTURE0);
814 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_depth_texture.width, fb_depth_texture.height, 862 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_depth_texture.width, fb_depth_texture.height,
815 fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_fb_depth_buffer.get()); 863 fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_fb_depth_buffer.get());
864
865 state.texture_units[0].texture_2d = 0;
866 state.Apply();
816} 867}
817 868
818void RasterizerOpenGL::CommitColorBuffer() { 869void RasterizerOpenGL::CommitColorBuffer() {
@@ -831,15 +882,18 @@ void RasterizerOpenGL::CommitColorBuffer() {
831 glActiveTexture(GL_TEXTURE0); 882 glActiveTexture(GL_TEXTURE0);
832 glGetTexImage(GL_TEXTURE_2D, 0, fb_color_texture.gl_format, fb_color_texture.gl_type, temp_gl_color_buffer.get()); 883 glGetTexImage(GL_TEXTURE_2D, 0, fb_color_texture.gl_format, fb_color_texture.gl_type, temp_gl_color_buffer.get());
833 884
885 state.texture_units[0].texture_2d = 0;
886 state.Apply();
887
834 // Directly copy pixels. Internal OpenGL color formats are consistent so no conversion is necessary. 888 // Directly copy pixels. Internal OpenGL color formats are consistent so no conversion is necessary.
835 for (int y = 0; y < fb_color_texture.height; ++y) { 889 for (int y = 0; y < fb_color_texture.height; ++y) {
836 for (int x = 0; x < fb_color_texture.width; ++x) { 890 for (int x = 0; x < fb_color_texture.width; ++x) {
837 const u32 coarse_y = y & ~7; 891 const u32 coarse_y = y & ~7;
838 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel; 892 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel;
839 u32 gl_px_idx = x * bytes_per_pixel + y * fb_color_texture.width * bytes_per_pixel; 893 u32 gl_pixel_index = x * bytes_per_pixel + y * fb_color_texture.width * bytes_per_pixel;
840 894
841 u8* pixel = color_buffer + dst_offset; 895 u8* pixel = color_buffer + dst_offset;
842 memcpy(pixel, &temp_gl_color_buffer[gl_px_idx], bytes_per_pixel); 896 memcpy(pixel, &temp_gl_color_buffer[gl_pixel_index], bytes_per_pixel);
843 } 897 }
844 } 898 }
845 } 899 }
@@ -866,29 +920,32 @@ void RasterizerOpenGL::CommitDepthBuffer() {
866 glActiveTexture(GL_TEXTURE0); 920 glActiveTexture(GL_TEXTURE0);
867 glGetTexImage(GL_TEXTURE_2D, 0, fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_gl_depth_buffer.get()); 921 glGetTexImage(GL_TEXTURE_2D, 0, fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_gl_depth_buffer.get());
868 922
869 for (int y = 0; y < fb_depth_texture.height; ++y) { 923 state.texture_units[0].texture_2d = 0;
870 for (int x = 0; x < fb_depth_texture.width; ++x) { 924 state.Apply();
871 const u32 coarse_y = y & ~7; 925
872 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; 926 u8* temp_gl_depth_data = bytes_per_pixel == 3 ? (temp_gl_depth_buffer.get() + 1) : temp_gl_depth_buffer.get();
873 u32 gl_px_idx = x + y * fb_depth_texture.width; 927
874 928 if (fb_depth_texture.format == Pica::Regs::DepthFormat::D24S8) {
875 switch (fb_depth_texture.format) { 929 for (int y = 0; y < fb_depth_texture.height; ++y) {
876 case Pica::Regs::DepthFormat::D16: 930 for (int x = 0; x < fb_depth_texture.width; ++x) {
877 Color::EncodeD16(((u16*)temp_gl_depth_buffer.get())[gl_px_idx], depth_buffer + dst_offset); 931 const u32 coarse_y = y & ~7;
878 break; 932 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel;
879 case Pica::Regs::DepthFormat::D24: 933 u32 gl_pixel_index = (x + y * fb_depth_texture.width);
880 Color::EncodeD24(((u32*)temp_gl_depth_buffer.get())[gl_px_idx], depth_buffer + dst_offset); 934
881 break; 935 u8* pixel = depth_buffer + dst_offset;
882 case Pica::Regs::DepthFormat::D24S8: 936 u32 depth_stencil = ((u32*)temp_gl_depth_data)[gl_pixel_index];
883 { 937 *(u32*)pixel = (depth_stencil >> 8) | (depth_stencil << 24);
884 u32 depth_stencil = ((u32*)temp_gl_depth_buffer.get())[gl_px_idx];
885 Color::EncodeD24S8((depth_stencil >> 8), depth_stencil & 0xFF, depth_buffer + dst_offset);
886 break;
887 } 938 }
888 default: 939 }
889 LOG_CRITICAL(Render_OpenGL, "Unknown framebuffer depth format %x", fb_depth_texture.format); 940 } else {
890 UNIMPLEMENTED(); 941 for (int y = 0; y < fb_depth_texture.height; ++y) {
891 break; 942 for (int x = 0; x < fb_depth_texture.width; ++x) {
943 const u32 coarse_y = y & ~7;
944 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel;
945 u32 gl_pixel_index = (x + y * fb_depth_texture.width) * gl_bpp;
946
947 u8* pixel = depth_buffer + dst_offset;
948 memcpy(pixel, &temp_gl_depth_data[gl_pixel_index], bytes_per_pixel);
892 } 949 }
893 } 950 }
894 } 951 }
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 9896f8d04..d7d422b1f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -125,6 +125,9 @@ private:
125 /// Syncs the alpha test states to match the PICA register 125 /// Syncs the alpha test states to match the PICA register
126 void SyncAlphaTest(); 126 void SyncAlphaTest();
127 127
128 /// Syncs the logic op states to match the PICA register
129 void SyncLogicOp();
130
128 /// Syncs the stencil test states to match the PICA register 131 /// Syncs the stencil test states to match the PICA register
129 void SyncStencilTest(); 132 void SyncStencilTest();
130 133
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 6f88a8b21..2e4110a88 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -4,13 +4,13 @@
4 4
5#include "common/make_unique.h" 5#include "common/make_unique.h"
6#include "common/math_util.h" 6#include "common/math_util.h"
7#include "common/vector_math.h"
7 8
8#include "core/memory.h" 9#include "core/memory.h"
9 10
10#include "video_core/renderer_opengl/gl_rasterizer_cache.h" 11#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
11#include "video_core/renderer_opengl/pica_to_gl.h" 12#include "video_core/renderer_opengl/pica_to_gl.h"
12#include "video_core/debug_utils/debug_utils.h" 13#include "video_core/debug_utils/debug_utils.h"
13#include "video_core/math.h"
14 14
15RasterizerCacheOpenGL::~RasterizerCacheOpenGL() { 15RasterizerCacheOpenGL::~RasterizerCacheOpenGL() {
16 FullFlush(); 16 FullFlush();
diff --git a/src/video_core/renderer_opengl/gl_shaders.h b/src/video_core/renderer_opengl/gl_shaders.h
index 8f0941230..a8cb2f595 100644
--- a/src/video_core/renderer_opengl/gl_shaders.h
+++ b/src/video_core/renderer_opengl/gl_shaders.h
@@ -69,15 +69,16 @@ const char g_fragment_shader_hw[] = R"(
69#define NUM_VTX_ATTR 7 69#define NUM_VTX_ATTR 7
70#define NUM_TEV_STAGES 6 70#define NUM_TEV_STAGES 6
71 71
72#define SOURCE_PRIMARYCOLOR 0x0 72#define SOURCE_PRIMARYCOLOR 0x0
73#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1 73#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1
74#define SOURCE_TEXTURE0 0x3 74#define SOURCE_SECONDARYFRAGMENTCOLOR 0x2
75#define SOURCE_TEXTURE1 0x4 75#define SOURCE_TEXTURE0 0x3
76#define SOURCE_TEXTURE2 0x5 76#define SOURCE_TEXTURE1 0x4
77#define SOURCE_TEXTURE3 0x6 77#define SOURCE_TEXTURE2 0x5
78#define SOURCE_PREVIOUSBUFFER 0xd 78#define SOURCE_TEXTURE3 0x6
79#define SOURCE_CONSTANT 0xe 79#define SOURCE_PREVIOUSBUFFER 0xd
80#define SOURCE_PREVIOUS 0xf 80#define SOURCE_CONSTANT 0xe
81#define SOURCE_PREVIOUS 0xf
81 82
82#define COLORMODIFIER_SOURCECOLOR 0x0 83#define COLORMODIFIER_SOURCECOLOR 0x0
83#define COLORMODIFIER_ONEMINUSSOURCECOLOR 0x1 84#define COLORMODIFIER_ONEMINUSSOURCECOLOR 0x1
@@ -151,8 +152,11 @@ vec4 GetSource(int source) {
151 if (source == SOURCE_PRIMARYCOLOR) { 152 if (source == SOURCE_PRIMARYCOLOR) {
152 return o[2]; 153 return o[2];
153 } else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) { 154 } else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) {
154 // HACK: Uses color value, but should really use fragment lighting output 155 // HACK: Until we implement fragment lighting, use primary_color
155 return o[2]; 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);
156 } else if (source == SOURCE_TEXTURE0) { 160 } else if (source == SOURCE_TEXTURE0) {
157 return texture(tex[0], o[3].xy); 161 return texture(tex[0], o[3].xy);
158 } else if (source == SOURCE_TEXTURE1) { 162 } else if (source == SOURCE_TEXTURE1) {
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 1afa58c99..3526e16d5 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -16,6 +16,11 @@ OpenGLState::OpenGLState() {
16 depth.test_func = GL_LESS; 16 depth.test_func = GL_LESS;
17 depth.write_mask = GL_TRUE; 17 depth.write_mask = GL_TRUE;
18 18
19 color_mask.red_enabled = GL_TRUE;
20 color_mask.green_enabled = GL_TRUE;
21 color_mask.blue_enabled = GL_TRUE;
22 color_mask.alpha_enabled = GL_TRUE;
23
19 stencil.test_enabled = false; 24 stencil.test_enabled = false;
20 stencil.test_func = GL_ALWAYS; 25 stencil.test_func = GL_ALWAYS;
21 stencil.test_ref = 0; 26 stencil.test_ref = 0;
@@ -32,6 +37,8 @@ OpenGLState::OpenGLState() {
32 blend.color.blue = 0.0f; 37 blend.color.blue = 0.0f;
33 blend.color.alpha = 0.0f; 38 blend.color.alpha = 0.0f;
34 39
40 logic_op = GL_COPY;
41
35 for (auto& texture_unit : texture_units) { 42 for (auto& texture_unit : texture_units) {
36 texture_unit.enabled_2d = false; 43 texture_unit.enabled_2d = false;
37 texture_unit.texture_2d = 0; 44 texture_unit.texture_2d = 0;
@@ -75,6 +82,15 @@ void OpenGLState::Apply() {
75 glDepthMask(depth.write_mask); 82 glDepthMask(depth.write_mask);
76 } 83 }
77 84
85 // Color mask
86 if (color_mask.red_enabled != cur_state.color_mask.red_enabled ||
87 color_mask.green_enabled != cur_state.color_mask.green_enabled ||
88 color_mask.blue_enabled != cur_state.color_mask.blue_enabled ||
89 color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) {
90 glColorMask(color_mask.red_enabled, color_mask.green_enabled,
91 color_mask.blue_enabled, color_mask.alpha_enabled);
92 }
93
78 // Stencil test 94 // Stencil test
79 if (stencil.test_enabled != cur_state.stencil.test_enabled) { 95 if (stencil.test_enabled != cur_state.stencil.test_enabled) {
80 if (stencil.test_enabled) { 96 if (stencil.test_enabled) {
@@ -82,11 +98,11 @@ void OpenGLState::Apply() {
82 } else { 98 } else {
83 glDisable(GL_STENCIL_TEST); 99 glDisable(GL_STENCIL_TEST);
84 } 100 }
85 } 101 }
86 102
87 if (stencil.test_func != cur_state.stencil.test_func || 103 if (stencil.test_func != cur_state.stencil.test_func ||
88 stencil.test_ref != cur_state.stencil.test_ref || 104 stencil.test_ref != cur_state.stencil.test_ref ||
89 stencil.test_mask != cur_state.stencil.test_mask) { 105 stencil.test_mask != cur_state.stencil.test_mask) {
90 glStencilFunc(stencil.test_func, stencil.test_ref, stencil.test_mask); 106 glStencilFunc(stencil.test_func, stencil.test_ref, stencil.test_mask);
91 } 107 }
92 108
@@ -99,23 +115,34 @@ void OpenGLState::Apply() {
99 if (blend.enabled != cur_state.blend.enabled) { 115 if (blend.enabled != cur_state.blend.enabled) {
100 if (blend.enabled) { 116 if (blend.enabled) {
101 glEnable(GL_BLEND); 117 glEnable(GL_BLEND);
118
119 cur_state.logic_op = GL_COPY;
120 glLogicOp(cur_state.logic_op);
121 glDisable(GL_COLOR_LOGIC_OP);
102 } else { 122 } else {
103 glDisable(GL_BLEND); 123 glDisable(GL_BLEND);
124 glEnable(GL_COLOR_LOGIC_OP);
104 } 125 }
105 } 126 }
106 127
107 if (blend.color.red != cur_state.blend.color.red || 128 if (blend.color.red != cur_state.blend.color.red ||
108 blend.color.green != cur_state.blend.color.green || 129 blend.color.green != cur_state.blend.color.green ||
109 blend.color.blue != cur_state.blend.color.blue || 130 blend.color.blue != cur_state.blend.color.blue ||
110 blend.color.alpha != cur_state.blend.color.alpha) { 131 blend.color.alpha != cur_state.blend.color.alpha) {
111 glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha); 132 glBlendColor(blend.color.red, blend.color.green,
133 blend.color.blue, blend.color.alpha);
112 } 134 }
113 135
114 if (blend.src_rgb_func != cur_state.blend.src_rgb_func || 136 if (blend.src_rgb_func != cur_state.blend.src_rgb_func ||
115 blend.dst_rgb_func != cur_state.blend.dst_rgb_func || 137 blend.dst_rgb_func != cur_state.blend.dst_rgb_func ||
116 blend.src_a_func != cur_state.blend.src_a_func || 138 blend.src_a_func != cur_state.blend.src_a_func ||
117 blend.dst_a_func != cur_state.blend.dst_a_func) { 139 blend.dst_a_func != cur_state.blend.dst_a_func) {
118 glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, blend.dst_a_func); 140 glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func,
141 blend.src_a_func, blend.dst_a_func);
142 }
143
144 if (logic_op != cur_state.logic_op) {
145 glLogicOp(logic_op);
119 } 146 }
120 147
121 // Textures 148 // Textures
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 281b7cad5..26b916360 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -20,6 +20,13 @@ public:
20 } depth; 20 } depth;
21 21
22 struct { 22 struct {
23 GLboolean red_enabled;
24 GLboolean green_enabled;
25 GLboolean blue_enabled;
26 GLboolean alpha_enabled;
27 } color_mask; // GL_COLOR_WRITEMASK
28
29 struct {
23 bool test_enabled; // GL_STENCIL_TEST 30 bool test_enabled; // GL_STENCIL_TEST
24 GLenum test_func; // GL_STENCIL_FUNC 31 GLenum test_func; // GL_STENCIL_FUNC
25 GLint test_ref; // GL_STENCIL_REF 32 GLint test_ref; // GL_STENCIL_REF
@@ -42,6 +49,8 @@ public:
42 } color; // GL_BLEND_COLOR 49 } color; // GL_BLEND_COLOR
43 } blend; 50 } blend;
44 51
52 GLenum logic_op; // GL_LOGIC_OP_MODE
53
45 // 3 texture units - one for each that is used in PICA fragment shader emulation 54 // 3 texture units - one for each that is used in PICA fragment shader emulation
46 struct { 55 struct {
47 bool enabled_2d; // GL_TEXTURE_2D 56 bool enabled_2d; // GL_TEXTURE_2D
@@ -61,7 +70,7 @@ public:
61 static const OpenGLState& GetCurState() { 70 static const OpenGLState& GetCurState() {
62 return cur_state; 71 return cur_state;
63 } 72 }
64 73
65 /// Apply this state as the current OpenGL state 74 /// Apply this state as the current OpenGL state
66 void Apply(); 75 void Apply();
67 76
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h
index f8763e71b..e566f9f7a 100644
--- a/src/video_core/renderer_opengl/pica_to_gl.h
+++ b/src/video_core/renderer_opengl/pica_to_gl.h
@@ -71,6 +71,37 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) {
71 return blend_func_table[(unsigned)factor]; 71 return blend_func_table[(unsigned)factor];
72} 72}
73 73
74inline GLenum LogicOp(Pica::Regs::LogicOp op) {
75 static const GLenum logic_op_table[] = {
76 GL_CLEAR, // Clear
77 GL_AND, // And
78 GL_AND_REVERSE, // AndReverse
79 GL_COPY, // Copy
80 GL_SET, // Set
81 GL_COPY_INVERTED, // CopyInverted
82 GL_NOOP, // NoOp
83 GL_INVERT, // Invert
84 GL_NAND, // Nand
85 GL_OR, // Or
86 GL_NOR, // Nor
87 GL_XOR, // Xor
88 GL_EQUIV, // Equiv
89 GL_AND_INVERTED, // AndInverted
90 GL_OR_REVERSE, // OrReverse
91 GL_OR_INVERTED, // OrInverted
92 };
93
94 // Range check table for input
95 if ((unsigned)op >= ARRAY_SIZE(logic_op_table)) {
96 LOG_CRITICAL(Render_OpenGL, "Unknown logic op %d", op);
97 UNREACHABLE();
98
99 return GL_COPY;
100 }
101
102 return logic_op_table[(unsigned)op];
103}
104
74inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { 105inline GLenum CompareFunc(Pica::Regs::CompareFunc func) {
75 static const GLenum compare_func_table[] = { 106 static const GLenum compare_func_table[] = {
76 GL_NEVER, // CompareFunc::Never 107 GL_NEVER, // CompareFunc::Never
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 16cf92e20..3399ca123 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -157,7 +157,7 @@ void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig&
157 state.texture_units[0].enabled_2d = true; 157 state.texture_units[0].enabled_2d = true;
158 state.texture_units[0].texture_2d = texture.handle; 158 state.texture_units[0].texture_2d = texture.handle;
159 state.Apply(); 159 state.Apply();
160 160
161 glActiveTexture(GL_TEXTURE0); 161 glActiveTexture(GL_TEXTURE0);
162 glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride); 162 glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride);
163 163
@@ -170,6 +170,9 @@ void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig&
170 texture.gl_format, texture.gl_type, framebuffer_data); 170 texture.gl_format, texture.gl_type, framebuffer_data);
171 171
172 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 172 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
173
174 state.texture_units[0].texture_2d = 0;
175 state.Apply();
173} 176}
174 177
175/** 178/**
@@ -239,6 +242,9 @@ void RendererOpenGL::InitOpenGLObjects() {
239 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 242 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
240 } 243 }
241 244
245 state.texture_units[0].texture_2d = 0;
246 state.Apply();
247
242 hw_rasterizer->InitObjects(); 248 hw_rasterizer->InitObjects();
243} 249}
244 250
@@ -370,6 +376,8 @@ void RendererOpenGL::Init() {
370 } 376 }
371 377
372 LOG_INFO(Render_OpenGL, "GL_VERSION: %s", glGetString(GL_VERSION)); 378 LOG_INFO(Render_OpenGL, "GL_VERSION: %s", glGetString(GL_VERSION));
379 LOG_INFO(Render_OpenGL, "GL_VENDOR: %s", glGetString(GL_VENDOR));
380 LOG_INFO(Render_OpenGL, "GL_RENDERER: %s", glGetString(GL_RENDERER));
373 InitOpenGLObjects(); 381 InitOpenGLObjects();
374} 382}
375 383
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp
index 7d68998f1..87006a832 100644
--- a/src/video_core/vertex_shader.cpp
+++ b/src/video_core/vertex_shader.cpp
@@ -119,17 +119,13 @@ static void ProcessShaderCode(VertexShaderState& state) {
119 switch (instr.opcode.Value().GetInfo().type) { 119 switch (instr.opcode.Value().GetInfo().type) {
120 case OpCode::Type::Arithmetic: 120 case OpCode::Type::Arithmetic:
121 { 121 {
122 bool is_inverted = 0 != (instr.opcode.Value().GetInfo().subtype & OpCode::Info::SrcInversed); 122 const bool is_inverted = (0 != (instr.opcode.Value().GetInfo().subtype & OpCode::Info::SrcInversed));
123 // TODO: We don't really support this properly: For instance, the address register
124 // offset needs to be applied to SRC2 instead, etc.
125 // For now, we just abort in this situation.
126 ASSERT_MSG(!is_inverted, "Bad condition...");
127 123
128 const int address_offset = (instr.common.address_register_index == 0) 124 const int address_offset = (instr.common.address_register_index == 0)
129 ? 0 : state.address_registers[instr.common.address_register_index - 1]; 125 ? 0 : state.address_registers[instr.common.address_register_index - 1];
130 126
131 const float24* src1_ = LookupSourceRegister(instr.common.GetSrc1(is_inverted) + address_offset); 127 const float24* src1_ = LookupSourceRegister(instr.common.GetSrc1(is_inverted) + (!is_inverted * address_offset));
132 const float24* src2_ = LookupSourceRegister(instr.common.GetSrc2(is_inverted)); 128 const float24* src2_ = LookupSourceRegister(instr.common.GetSrc2(is_inverted) + ( is_inverted * address_offset));
133 129
134 const bool negate_src1 = ((bool)swizzle.negate_src1 != false); 130 const bool negate_src1 = ((bool)swizzle.negate_src1 != false);
135 const bool negate_src2 = ((bool)swizzle.negate_src2 != false); 131 const bool negate_src2 = ((bool)swizzle.negate_src2 != false);
@@ -208,6 +204,15 @@ static void ProcessShaderCode(VertexShaderState& state) {
208 } 204 }
209 break; 205 break;
210 206
207 case OpCode::Id::MIN:
208 for (int i = 0; i < 4; ++i) {
209 if (!swizzle.DestComponentEnabled(i))
210 continue;
211
212 dest[i] = std::min(src1[i], src2[i]);
213 }
214 break;
215
211 case OpCode::Id::DP3: 216 case OpCode::Id::DP3:
212 case OpCode::Id::DP4: 217 case OpCode::Id::DP4:
213 { 218 {
@@ -279,6 +284,16 @@ static void ProcessShaderCode(VertexShaderState& state) {
279 break; 284 break;
280 } 285 }
281 286
287 case OpCode::Id::SLT:
288 case OpCode::Id::SLTI:
289 for (int i = 0; i < 4; ++i) {
290 if (!swizzle.DestComponentEnabled(i))
291 continue;
292
293 dest[i] = (src1[i] < src2[i]) ? float24::FromFloat32(1.0f) : float24::FromFloat32(0.0f);
294 }
295 break;
296
282 case OpCode::Id::CMP: 297 case OpCode::Id::CMP:
283 for (int i = 0; i < 2; ++i) { 298 for (int i = 0; i < 2; ++i) {
284 // TODO: Can you restrict to one compare via dest masking? 299 // TODO: Can you restrict to one compare via dest masking?
@@ -330,7 +345,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
330 345
331 case OpCode::Type::MultiplyAdd: 346 case OpCode::Type::MultiplyAdd:
332 { 347 {
333 if ((instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD) || 348 if ((instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD) ||
334 (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI)) { 349 (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI)) {
335 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.mad.operand_desc_id]; 350 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.mad.operand_desc_id];
336 351
@@ -547,7 +562,7 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes) {
547 const auto& attribute_register_map = regs.vs_input_register_map; 562 const auto& attribute_register_map = regs.vs_input_register_map;
548 float24 dummy_register; 563 float24 dummy_register;
549 boost::fill(state.input_register_table, &dummy_register); 564 boost::fill(state.input_register_table, &dummy_register);
550 565
551 if (num_attributes > 0) state.input_register_table[attribute_register_map.attribute0_register] = &input.attr[0].x; 566 if (num_attributes > 0) state.input_register_table[attribute_register_map.attribute0_register] = &input.attr[0].x;
552 if (num_attributes > 1) state.input_register_table[attribute_register_map.attribute1_register] = &input.attr[1].x; 567 if (num_attributes > 1) state.input_register_table[attribute_register_map.attribute1_register] = &input.attr[1].x;
553 if (num_attributes > 2) state.input_register_table[attribute_register_map.attribute2_register] = &input.attr[2].x; 568 if (num_attributes > 2) state.input_register_table[attribute_register_map.attribute2_register] = &input.attr[2].x;