summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/citra/citra.cpp2
-rw-r--r--src/citra/emu_window/emu_window_glfw.cpp78
-rw-r--r--src/citra/emu_window/emu_window_glfw.h18
-rw-r--r--src/citra_qt/bootmanager.cpp80
-rw-r--r--src/citra_qt/bootmanager.hxx22
-rw-r--r--src/citra_qt/config/controller_config_util.cpp4
-rw-r--r--src/citra_qt/debugger/callstack.cpp6
-rw-r--r--src/citra_qt/debugger/registers.cpp28
-rw-r--r--src/citra_qt/debugger/registers.hxx10
-rw-r--r--src/citra_qt/main.cpp3
-rw-r--r--src/common/chunk_file.h14
-rw-r--r--src/common/common_funcs.h14
-rw-r--r--src/common/common_types.h6
-rw-r--r--src/common/console_listener.cpp24
-rw-r--r--src/common/emu_window.h128
-rw-r--r--src/common/extended_trace.cpp26
-rw-r--r--src/common/fifo_queue.h2
-rw-r--r--src/common/file_search.cpp2
-rw-r--r--src/common/file_util.cpp62
-rw-r--r--src/common/file_util.h186
-rw-r--r--src/common/hash.cpp32
-rw-r--r--src/common/linear_disk_cache.h6
-rw-r--r--src/common/log.h7
-rw-r--r--src/common/log_manager.cpp12
-rw-r--r--src/common/log_manager.h4
-rw-r--r--src/common/math_util.cpp14
-rw-r--r--src/common/math_util.h9
-rw-r--r--src/common/mem_arena.cpp12
-rw-r--r--src/common/memory_util.cpp8
-rw-r--r--src/common/msg_handler.h42
-rw-r--r--src/common/string_util.cpp18
-rw-r--r--src/common/string_util.h2
-rw-r--r--src/common/symbols.cpp4
-rw-r--r--src/common/symbols.h2
-rw-r--r--src/common/thread.cpp6
-rw-r--r--src/common/thread.h10
-rw-r--r--src/common/thread_queue_list.h4
-rw-r--r--src/core/CMakeLists.txt15
-rw-r--r--src/core/arm/arm_interface.h6
-rw-r--r--src/core/arm/disassembler/load_symbol_map.cpp4
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp4
-rw-r--r--src/core/arm/dyncom/arm_dyncom.h4
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp54
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.h2
-rw-r--r--src/core/arm/interpreter/arm_interpreter.cpp4
-rw-r--r--src/core/arm/interpreter/arm_interpreter.h4
-rw-r--r--src/core/arm/skyeye_common/armcpu.h2
-rw-r--r--src/core/arm/skyeye_common/armdefs.h34
-rw-r--r--src/core/arm/skyeye_common/armemu.h18
-rw-r--r--src/core/core.cpp14
-rw-r--r--src/core/core_timing.cpp50
-rw-r--r--src/core/core_timing.h2
-rw-r--r--src/core/file_sys/archive.h53
-rw-r--r--src/core/file_sys/archive_romfs.cpp28
-rw-r--r--src/core/file_sys/archive_romfs.h24
-rw-r--r--src/core/file_sys/archive_sdmc.cpp30
-rw-r--r--src/core/file_sys/archive_sdmc.h22
-rw-r--r--src/core/file_sys/directory_sdmc.cpp6
-rw-r--r--src/core/file_sys/directory_sdmc.h2
-rw-r--r--src/core/file_sys/file_sdmc.cpp4
-rw-r--r--src/core/file_sys/file_sdmc.h2
-rw-r--r--src/core/hle/config_mem.cpp2
-rw-r--r--src/core/hle/coprocessor.cpp2
-rw-r--r--src/core/hle/function_wrappers.h4
-rw-r--r--src/core/hle/hle.cpp6
-rw-r--r--src/core/hle/hle.h2
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp15
-rw-r--r--src/core/hle/kernel/address_arbiter.h4
-rw-r--r--src/core/hle/kernel/archive.cpp229
-rw-r--r--src/core/hle/kernel/archive.h41
-rw-r--r--src/core/hle/kernel/event.cpp47
-rw-r--r--src/core/hle/kernel/event.h14
-rw-r--r--src/core/hle/kernel/kernel.cpp6
-rw-r--r--src/core/hle/kernel/kernel.h54
-rw-r--r--src/core/hle/kernel/mutex.cpp52
-rw-r--r--src/core/hle/kernel/mutex.h5
-rw-r--r--src/core/hle/kernel/shared_memory.cpp45
-rw-r--r--src/core/hle/kernel/shared_memory.h7
-rw-r--r--src/core/hle/kernel/thread.cpp154
-rw-r--r--src/core/hle/kernel/thread.h9
-rw-r--r--src/core/hle/result.h400
-rw-r--r--src/core/hle/service/ac_u.cpp6
-rw-r--r--src/core/hle/service/ac_u.h4
-rw-r--r--src/core/hle/service/am_net.cpp47
-rw-r--r--src/core/hle/service/am_net.h27
-rw-r--r--src/core/hle/service/apt_u.cpp4
-rw-r--r--src/core/hle/service/apt_u.h4
-rw-r--r--src/core/hle/service/boss_u.cpp28
-rw-r--r--src/core/hle/service/boss_u.h27
-rw-r--r--src/core/hle/service/cfg_i.cpp59
-rw-r--r--src/core/hle/service/cfg_i.h27
-rw-r--r--src/core/hle/service/cfg_u.h2
-rw-r--r--src/core/hle/service/csnd_snd.cpp39
-rw-r--r--src/core/hle/service/csnd_snd.h27
-rw-r--r--src/core/hle/service/dsp_dsp.cpp4
-rw-r--r--src/core/hle/service/dsp_dsp.h2
-rw-r--r--src/core/hle/service/err_f.cpp4
-rw-r--r--src/core/hle/service/err_f.h4
-rw-r--r--src/core/hle/service/frd_u.h2
-rw-r--r--src/core/hle/service/fs_user.cpp279
-rw-r--r--src/core/hle/service/gsp_gpu.cpp33
-rw-r--r--src/core/hle/service/hid_user.cpp9
-rw-r--r--src/core/hle/service/hid_user.h2
-rw-r--r--src/core/hle/service/ir_rst.cpp36
-rw-r--r--src/core/hle/service/ir_rst.h27
-rw-r--r--src/core/hle/service/ir_u.cpp45
-rw-r--r--src/core/hle/service/ir_u.h27
-rw-r--r--src/core/hle/service/mic_u.cpp2
-rw-r--r--src/core/hle/service/mic_u.h2
-rw-r--r--src/core/hle/service/nwm_uds.h2
-rw-r--r--src/core/hle/service/pm_app.cpp35
-rw-r--r--src/core/hle/service/pm_app.h27
-rw-r--r--src/core/hle/service/ptm_u.cpp6
-rw-r--r--src/core/hle/service/ptm_u.h2
-rw-r--r--src/core/hle/service/service.cpp18
-rw-r--r--src/core/hle/service/service.h30
-rw-r--r--src/core/hle/service/soc_u.h2
-rw-r--r--src/core/hle/service/srv.cpp14
-rw-r--r--src/core/hle/svc.cpp151
-rw-r--r--src/core/hle/svc.h2
-rw-r--r--src/core/hw/gpu.cpp6
-rw-r--r--src/core/hw/hw.cpp8
-rw-r--r--src/core/hw/ndma.cpp2
-rw-r--r--src/core/loader/elf.cpp4
-rw-r--r--src/core/loader/ncch.cpp10
-rw-r--r--src/core/loader/ncch.h2
-rw-r--r--src/core/mem_map.cpp60
-rw-r--r--src/core/mem_map.h3
-rw-r--r--src/core/mem_map_funcs.cpp22
-rw-r--r--src/core/system.h22
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp4
-rw-r--r--src/video_core/debug_utils/debug_utils.h2
-rw-r--r--src/video_core/renderer_base.h2
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp31
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h11
-rw-r--r--src/video_core/utils.cpp4
-rw-r--r--src/video_core/utils.h20
-rw-r--r--src/video_core/vertex_shader.h2
138 files changed, 2434 insertions, 1242 deletions
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp
index 41b62ac16..f2aeb510e 100644
--- a/src/citra/citra.cpp
+++ b/src/citra/citra.cpp
@@ -23,7 +23,7 @@ int __cdecl main(int argc, char **argv) {
23 } 23 }
24 24
25 Config config; 25 Config config;
26 26
27 if (!Settings::values.enable_log) 27 if (!Settings::values.enable_log)
28 LogManager::Shutdown(); 28 LogManager::Shutdown();
29 29
diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp
index 0c774bbc5..697bf4693 100644
--- a/src/citra/emu_window/emu_window_glfw.cpp
+++ b/src/citra/emu_window/emu_window_glfw.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <GLFW/glfw3.h>
6
5#include "common/common.h" 7#include "common/common.h"
6 8
7#include "video_core/video_core.h" 9#include "video_core/video_core.h"
@@ -10,22 +12,21 @@
10 12
11#include "citra/emu_window/emu_window_glfw.h" 13#include "citra/emu_window/emu_window_glfw.h"
12 14
15EmuWindow_GLFW* EmuWindow_GLFW::GetEmuWindow(GLFWwindow* win) {
16 return static_cast<EmuWindow_GLFW*>(glfwGetWindowUserPointer(win));
17}
18
13/// Called by GLFW when a key event occurs 19/// Called by GLFW when a key event occurs
14void EmuWindow_GLFW::OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods) { 20void EmuWindow_GLFW::OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods) {
15 21
16 if (!VideoCore::g_emu_window) { 22 int keyboard_id = GetEmuWindow(win)->keyboard_id;
17 return;
18 }
19
20 int keyboard_id = ((EmuWindow_GLFW*)VideoCore::g_emu_window)->keyboard_id;
21 23
22 if (action == GLFW_PRESS) { 24 if (action == GLFW_PRESS) {
23 EmuWindow::KeyPressed({key, keyboard_id}); 25 EmuWindow::KeyPressed({key, keyboard_id});
24 } 26 } else if (action == GLFW_RELEASE) {
25
26 if (action == GLFW_RELEASE) {
27 EmuWindow::KeyReleased({key, keyboard_id}); 27 EmuWindow::KeyReleased({key, keyboard_id});
28 } 28 }
29
29 HID_User::PadUpdateComplete(); 30 HID_User::PadUpdateComplete();
30} 31}
31 32
@@ -34,15 +35,36 @@ const bool EmuWindow_GLFW::IsOpen() {
34 return glfwWindowShouldClose(m_render_window) == 0; 35 return glfwWindowShouldClose(m_render_window) == 0;
35} 36}
36 37
38void EmuWindow_GLFW::OnFramebufferResizeEvent(GLFWwindow* win, int width, int height) {
39 _dbg_assert_(GUI, width > 0);
40 _dbg_assert_(GUI, height > 0);
41
42 GetEmuWindow(win)->NotifyFramebufferSizeChanged(std::pair<unsigned,unsigned>(width, height));
43}
44
45void EmuWindow_GLFW::OnClientAreaResizeEvent(GLFWwindow* win, int width, int height) {
46 _dbg_assert_(GUI, width > 0);
47 _dbg_assert_(GUI, height > 0);
48
49 // NOTE: GLFW provides no proper way to set a minimal window size.
50 // Hence, we just ignore the corresponding EmuWindow hint.
51
52 GetEmuWindow(win)->NotifyClientAreaSizeChanged(std::pair<unsigned,unsigned>(width, height));
53}
54
37/// EmuWindow_GLFW constructor 55/// EmuWindow_GLFW constructor
38EmuWindow_GLFW::EmuWindow_GLFW() { 56EmuWindow_GLFW::EmuWindow_GLFW() {
39 keyboard_id = KeyMap::NewDeviceId(); 57 keyboard_id = KeyMap::NewDeviceId();
40 58
41 ReloadSetKeymaps(); 59 ReloadSetKeymaps();
42 60
61 glfwSetErrorCallback([](int error, const char *desc){
62 ERROR_LOG(GUI, "GLFW 0x%08x: %s", error, desc);
63 });
64
43 // Initialize the window 65 // Initialize the window
44 if(glfwInit() != GL_TRUE) { 66 if(glfwInit() != GL_TRUE) {
45 printf("Failed to initialize GLFW! Exiting..."); 67 ERROR_LOG(GUI, "Failed to initialize GLFW! Exiting...");
46 exit(1); 68 exit(1);
47 } 69 }
48 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 70 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
@@ -50,19 +72,31 @@ EmuWindow_GLFW::EmuWindow_GLFW() {
50 // GLFW on OSX requires these window hints to be set to create a 3.2+ GL context. 72 // GLFW on OSX requires these window hints to be set to create a 3.2+ GL context.
51 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); 73 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
52 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 74 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
53 75
54 m_render_window = glfwCreateWindow(VideoCore::kScreenTopWidth, 76 std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc);
55 (VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight), 77 m_render_window = glfwCreateWindow(VideoCore::kScreenTopWidth,
56 m_window_title.c_str(), NULL, NULL); 78 (VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight),
79 window_title.c_str(), NULL, NULL);
57 80
58 if (m_render_window == NULL) { 81 if (m_render_window == NULL) {
59 printf("Failed to create GLFW window! Exiting..."); 82 ERROR_LOG(GUI, "Failed to create GLFW window! Exiting...");
60 exit(1); 83 exit(1);
61 } 84 }
62 85
63 // Setup callbacks
64 glfwSetWindowUserPointer(m_render_window, this); 86 glfwSetWindowUserPointer(m_render_window, this);
87
88 // Notify base interface about window state
89 int width, height;
90 glfwGetFramebufferSize(m_render_window, &width, &height);
91 OnFramebufferResizeEvent(m_render_window, width, height);
92
93 glfwGetWindowSize(m_render_window, &width, &height);
94 OnClientAreaResizeEvent(m_render_window, width, height);
95
96 // Setup callbacks
65 glfwSetKeyCallback(m_render_window, OnKeyEvent); 97 glfwSetKeyCallback(m_render_window, OnKeyEvent);
98 glfwSetFramebufferSizeCallback(m_render_window, OnFramebufferResizeEvent);
99 glfwSetWindowSizeCallback(m_render_window, OnClientAreaResizeEvent);
66 100
67 DoneCurrent(); 101 DoneCurrent();
68} 102}
@@ -110,3 +144,15 @@ void EmuWindow_GLFW::ReloadSetKeymaps() {
110 KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, HID_User::PAD_CIRCLE_UP); 144 KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, HID_User::PAD_CIRCLE_UP);
111 KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, HID_User::PAD_CIRCLE_DOWN); 145 KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, HID_User::PAD_CIRCLE_DOWN);
112} 146}
147
148void EmuWindow_GLFW::OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) {
149 std::pair<int,int> current_size;
150 glfwGetWindowSize(m_render_window, &current_size.first, &current_size.second);
151
152 _dbg_assert_(GUI, (int)minimal_size.first > 0 && (int)minimal_size.second > 0);
153 int new_width = std::max(current_size.first, (int)minimal_size.first);
154 int new_height = std::max(current_size.second, (int)minimal_size.second);
155
156 if (current_size != std::make_pair(new_width, new_height))
157 glfwSetWindowSize(m_render_window, new_width, new_height);
158}
diff --git a/src/citra/emu_window/emu_window_glfw.h b/src/citra/emu_window/emu_window_glfw.h
index 7c3072145..5b04e87bb 100644
--- a/src/citra/emu_window/emu_window_glfw.h
+++ b/src/citra/emu_window/emu_window_glfw.h
@@ -4,10 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <GLFW/glfw3.h>
8
9#include "common/emu_window.h" 7#include "common/emu_window.h"
10 8
9struct GLFWwindow;
10
11class EmuWindow_GLFW : public EmuWindow { 11class EmuWindow_GLFW : public EmuWindow {
12public: 12public:
13 EmuWindow_GLFW(); 13 EmuWindow_GLFW();
@@ -16,12 +16,12 @@ public:
16 /// Swap buffers to display the next frame 16 /// Swap buffers to display the next frame
17 void SwapBuffers() override; 17 void SwapBuffers() override;
18 18
19 /// Polls window events 19 /// Polls window events
20 void PollEvents() override; 20 void PollEvents() override;
21 21
22 /// Makes the graphics context current for the caller thread 22 /// Makes the graphics context current for the caller thread
23 void MakeCurrent() override; 23 void MakeCurrent() override;
24 24
25 /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread 25 /// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
26 void DoneCurrent() override; 26 void DoneCurrent() override;
27 27
@@ -30,9 +30,17 @@ public:
30 /// Whether the window is still open, and a close request hasn't yet been sent 30 /// Whether the window is still open, and a close request hasn't yet been sent
31 const bool IsOpen(); 31 const bool IsOpen();
32 32
33 static void OnClientAreaResizeEvent(GLFWwindow* win, int width, int height);
34
35 static void OnFramebufferResizeEvent(GLFWwindow* win, int width, int height);
36
33 void ReloadSetKeymaps() override; 37 void ReloadSetKeymaps() override;
34 38
35private: 39private:
40 void OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) override;
41
42 static EmuWindow_GLFW* GetEmuWindow(GLFWwindow* win);
43
36 GLFWwindow* m_render_window; ///< Internal GLFW render window 44 GLFWwindow* m_render_window; ///< Internal GLFW render window
37 45
38 /// Device id of keyboard for use with KeyMap 46 /// Device id of keyboard for use with KeyMap
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 20824692d..9bf079919 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -2,6 +2,12 @@
2#include <QKeyEvent> 2#include <QKeyEvent>
3#include <QApplication> 3#include <QApplication>
4 4
5#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
6// Required for screen DPI information
7#include <QScreen>
8#include <QWindow>
9#endif
10
5#include "common/common.h" 11#include "common/common.h"
6#include "bootmanager.hxx" 12#include "bootmanager.hxx"
7 13
@@ -17,7 +23,7 @@
17#define APP_TITLE APP_NAME " " APP_VERSION 23#define APP_TITLE APP_NAME " " APP_VERSION
18#define COPYRIGHT "Copyright (C) 2013-2014 Citra Team" 24#define COPYRIGHT "Copyright (C) 2013-2014 Citra Team"
19 25
20EmuThread::EmuThread(GRenderWindow* render_window) : 26EmuThread::EmuThread(GRenderWindow* render_window) :
21 filename(""), exec_cpu_step(false), cpu_running(false), 27 filename(""), exec_cpu_step(false), cpu_running(false),
22 stop_run(false), render_window(render_window) 28 stop_run(false), render_window(render_window)
23{ 29{
@@ -36,7 +42,7 @@ void EmuThread::run()
36 if (cpu_running) 42 if (cpu_running)
37 { 43 {
38 Core::RunLoop(); 44 Core::RunLoop();
39 } 45 }
40 else if (exec_cpu_step) 46 else if (exec_cpu_step)
41 { 47 {
42 exec_cpu_step = false; 48 exec_cpu_step = false;
@@ -82,20 +88,20 @@ void EmuThread::Stop()
82class GGLWidgetInternal : public QGLWidget 88class GGLWidgetInternal : public QGLWidget
83{ 89{
84public: 90public:
85 GGLWidgetInternal(QGLFormat fmt, GRenderWindow* parent) : QGLWidget(fmt, parent) 91 GGLWidgetInternal(QGLFormat fmt, GRenderWindow* parent)
86 { 92 : QGLWidget(fmt, parent), parent(parent) {
87 parent_ = parent;
88 } 93 }
89 94
90 void paintEvent(QPaintEvent* ev) override 95 void paintEvent(QPaintEvent* ev) override {
91 {
92 } 96 }
97
93 void resizeEvent(QResizeEvent* ev) override { 98 void resizeEvent(QResizeEvent* ev) override {
94 parent_->SetClientAreaWidth(size().width()); 99 parent->OnClientAreaResized(ev->size().width(), ev->size().height());
95 parent_->SetClientAreaHeight(size().height()); 100 parent->OnFramebufferSizeChanged();
96 } 101 }
102
97private: 103private:
98 GRenderWindow* parent_; 104 GRenderWindow* parent;
99}; 105};
100 106
101EmuThread& GRenderWindow::GetEmuThread() 107EmuThread& GRenderWindow::GetEmuThread()
@@ -105,6 +111,9 @@ EmuThread& GRenderWindow::GetEmuThread()
105 111
106GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this), keyboard_id(0) 112GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this), keyboard_id(0)
107{ 113{
114 std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc);
115 setWindowTitle(QString::fromStdString(window_title));
116
108 keyboard_id = KeyMap::NewDeviceId(); 117 keyboard_id = KeyMap::NewDeviceId();
109 ReloadSetKeymaps(); 118 ReloadSetKeymaps();
110 119
@@ -114,16 +123,25 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this
114 fmt.setProfile(QGLFormat::CoreProfile); 123 fmt.setProfile(QGLFormat::CoreProfile);
115 // Requests a forward-compatible context, which is required to get a 3.2+ context on OS X 124 // Requests a forward-compatible context, which is required to get a 3.2+ context on OS X
116 fmt.setOption(QGL::NoDeprecatedFunctions); 125 fmt.setOption(QGL::NoDeprecatedFunctions);
117 126
118 child = new GGLWidgetInternal(fmt, this); 127 child = new GGLWidgetInternal(fmt, this);
119 QBoxLayout* layout = new QHBoxLayout(this); 128 QBoxLayout* layout = new QHBoxLayout(this);
120 resize(VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); 129 resize(VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight);
121 layout->addWidget(child); 130 layout->addWidget(child);
122 layout->setMargin(0); 131 layout->setMargin(0);
123 setLayout(layout); 132 setLayout(layout);
124 QObject::connect(&emu_thread, SIGNAL(started()), this, SLOT(moveContext())); 133 connect(&emu_thread, SIGNAL(started()), this, SLOT(moveContext()));
134
135 OnMinimalClientAreaChangeRequest(GetActiveConfig().min_client_area_size);
136
137 OnFramebufferSizeChanged();
138 NotifyClientAreaSizeChanged(std::pair<unsigned,unsigned>(child->width(), child->height()));
125 139
126 BackupGeometry(); 140 BackupGeometry();
141
142#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
143 connect(this->windowHandle(), SIGNAL(screenChanged(QScreen*)), this, SLOT(OnFramebufferSizeChanged()));
144#endif
127} 145}
128 146
129void GRenderWindow::moveContext() 147void GRenderWindow::moveContext()
@@ -166,14 +184,28 @@ void GRenderWindow::DoneCurrent()
166} 184}
167 185
168void GRenderWindow::PollEvents() { 186void GRenderWindow::PollEvents() {
169 // TODO(ShizZy): Does this belong here? This is a reasonable place to update the window title 187}
170 // from the main thread, but this should probably be in an event handler... 188
171 /* 189// On Qt 5.0+, this correctly gets the size of the framebuffer (pixels).
172 static char title[128]; 190//
173 sprintf(title, "%s (FPS: %02.02f)", window_title_.c_str(), 191// Older versions get the window size (density independent pixels),
174 video_core::g_renderer->current_fps()); 192// and hence, do not support DPI scaling ("retina" displays).
175 setWindowTitle(title); 193// The result will be a viewport that is smaller than the extent of the window.
176 */ 194void GRenderWindow::OnFramebufferSizeChanged()
195{
196 // Screen changes potentially incur a change in screen DPI, hence we should update the framebuffer size
197#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
198 // windowHandle() might not be accessible until the window is displayed to screen.
199 auto pixel_ratio = windowHandle() ? (windowHandle()->screen()->devicePixelRatio()) : 1.0;
200
201 unsigned width = child->QPaintDevice::width() * pixel_ratio;
202 unsigned height = child->QPaintDevice::height() * pixel_ratio;
203#else
204 unsigned width = child->QPaintDevice::width();
205 unsigned height = child->QPaintDevice::height();
206#endif
207
208 NotifyFramebufferSizeChanged(std::make_pair(width, height));
177} 209}
178 210
179void GRenderWindow::BackupGeometry() 211void GRenderWindow::BackupGeometry()
@@ -236,3 +268,11 @@ void GRenderWindow::ReloadSetKeymaps()
236 KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, HID_User::PAD_CIRCLE_DOWN); 268 KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, HID_User::PAD_CIRCLE_DOWN);
237} 269}
238 270
271void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height)
272{
273 NotifyClientAreaSizeChanged(std::make_pair(width, height));
274}
275
276void GRenderWindow::OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) {
277 setMinimumSize(minimal_size.first, minimal_size.second);
278}
diff --git a/src/citra_qt/bootmanager.hxx b/src/citra_qt/bootmanager.hxx
index f8afc403e..5f69f15ea 100644
--- a/src/citra_qt/bootmanager.hxx
+++ b/src/citra_qt/bootmanager.hxx
@@ -1,12 +1,16 @@
1#include <atomic>
2
1#include <QThread> 3#include <QThread>
2#include <QGLWidget> 4#include <QGLWidget>
3#include <atomic> 5
4#include "common/common.h" 6#include "common/common.h"
5#include "common/emu_window.h" 7#include "common/emu_window.h"
6 8
7class GRenderWindow; 9class QScreen;
8class QKeyEvent; 10class QKeyEvent;
9 11
12class GRenderWindow;
13
10class EmuThread : public QThread 14class EmuThread : public QThread
11{ 15{
12 Q_OBJECT 16 Q_OBJECT
@@ -14,7 +18,7 @@ class EmuThread : public QThread
14public: 18public:
15 /** 19 /**
16 * Set image filename 20 * Set image filename
17 * 21 *
18 * @param filename 22 * @param filename
19 * @warning Only call when not running! 23 * @warning Only call when not running!
20 */ 24 */
@@ -74,7 +78,7 @@ private:
74signals: 78signals:
75 /** 79 /**
76 * Emitted when CPU when we've finished processing a single Gekko instruction 80 * Emitted when CPU when we've finished processing a single Gekko instruction
77 * 81 *
78 * @warning This will only be emitted when the CPU is not running (SetCpuRunning(false)) 82 * @warning This will only be emitted when the CPU is not running (SetCpuRunning(false))
79 * @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) 83 * @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 */ 84 */
@@ -100,7 +104,7 @@ public:
100 void BackupGeometry(); 104 void BackupGeometry();
101 void RestoreGeometry(); 105 void RestoreGeometry();
102 void restoreGeometry(const QByteArray& geometry); // overridden 106 void restoreGeometry(const QByteArray& geometry); // overridden
103 QByteArray saveGeometry(); // overridden 107 QByteArray saveGeometry(); // overridden
104 108
105 EmuThread& GetEmuThread(); 109 EmuThread& GetEmuThread();
106 110
@@ -109,10 +113,16 @@ public:
109 113
110 void ReloadSetKeymaps() override; 114 void ReloadSetKeymaps() override;
111 115
116 void OnClientAreaResized(unsigned width, unsigned height);
117
118 void OnFramebufferSizeChanged();
119
112public slots: 120public slots:
113 void moveContext(); 121 void moveContext(); // overridden
114 122
115private: 123private:
124 void OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) override;
125
116 QGLWidget* child; 126 QGLWidget* child;
117 127
118 EmuThread emu_thread; 128 EmuThread emu_thread;
diff --git a/src/citra_qt/config/controller_config_util.cpp b/src/citra_qt/config/controller_config_util.cpp
index c5426570b..aee3f8616 100644
--- a/src/citra_qt/config/controller_config_util.cpp
+++ b/src/citra_qt/config/controller_config_util.cpp
@@ -48,7 +48,7 @@ void GKeyConfigButton::OnActivePortChanged(const common::Config::ControllerPort&
48 else if (config.keys.key_code[id] == Qt::Key_Control) text = tr("Control"); 48 else if (config.keys.key_code[id] == Qt::Key_Control) text = tr("Control");
49 else if (config.keys.key_code[id] == Qt::Key_Alt) text = tr("Alt"); 49 else if (config.keys.key_code[id] == Qt::Key_Alt) text = tr("Alt");
50 else if (config.keys.key_code[id] == Qt::Key_Meta) text = tr("Meta"); 50 else if (config.keys.key_code[id] == Qt::Key_Meta) text = tr("Meta");
51 setText(text); 51 setText(text);
52} 52}
53 53
54void GKeyConfigButton::OnClicked() 54void GKeyConfigButton::OnClicked()
@@ -118,4 +118,4 @@ GButtonConfigGroup::GButtonConfigGroup(const QString& name, common::Config::Cont
118 setLayout(layout); 118 setLayout(layout);
119} 119}
120 120
121*/ \ No newline at end of file 121*/
diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp
index 77fb0c9ed..895851be3 100644
--- a/src/citra_qt/debugger/callstack.cpp
+++ b/src/citra_qt/debugger/callstack.cpp
@@ -28,7 +28,7 @@ void CallstackWidget::OnCPUStepped()
28 28
29 u32 sp = app_core->GetReg(13); //stack pointer 29 u32 sp = app_core->GetReg(13); //stack pointer
30 u32 addr, ret_addr, call_addr, func_addr; 30 u32 addr, ret_addr, call_addr, func_addr;
31 31
32 int counter = 0; 32 int counter = 0;
33 for (int addr = 0x10000000; addr >= sp; addr -= 4) 33 for (int addr = 0x10000000; addr >= sp; addr -= 4)
34 { 34 {
@@ -55,7 +55,7 @@ void CallstackWidget::OnCPUStepped()
55 callstack_model->setItem(counter, 0, new QStandardItem(QString("0x%1").arg(addr, 8, 16, QLatin1Char('0')))); 55 callstack_model->setItem(counter, 0, new QStandardItem(QString("0x%1").arg(addr, 8, 16, QLatin1Char('0'))));
56 callstack_model->setItem(counter, 1, new QStandardItem(QString("0x%1").arg(ret_addr, 8, 16, QLatin1Char('0')))); 56 callstack_model->setItem(counter, 1, new QStandardItem(QString("0x%1").arg(ret_addr, 8, 16, QLatin1Char('0'))));
57 callstack_model->setItem(counter, 2, new QStandardItem(QString("0x%1").arg(call_addr, 8, 16, QLatin1Char('0')))); 57 callstack_model->setItem(counter, 2, new QStandardItem(QString("0x%1").arg(call_addr, 8, 16, QLatin1Char('0'))));
58 58
59 name = Symbols::HasSymbol(func_addr) ? Symbols::GetSymbol(func_addr).name : "unknown"; 59 name = Symbols::HasSymbol(func_addr) ? Symbols::GetSymbol(func_addr).name : "unknown";
60 callstack_model->setItem(counter, 3, new QStandardItem(QString("%1_%2").arg(QString::fromStdString(name)) 60 callstack_model->setItem(counter, 3, new QStandardItem(QString("%1_%2").arg(QString::fromStdString(name))
61 .arg(QString("0x%1").arg(func_addr, 8, 16, QLatin1Char('0'))))); 61 .arg(QString("0x%1").arg(func_addr, 8, 16, QLatin1Char('0')))));
@@ -63,4 +63,4 @@ void CallstackWidget::OnCPUStepped()
63 counter++; 63 counter++;
64 } 64 }
65 } 65 }
66} \ No newline at end of file 66}
diff --git a/src/citra_qt/debugger/registers.cpp b/src/citra_qt/debugger/registers.cpp
index 96ceed480..ed17ee4b4 100644
--- a/src/citra_qt/debugger/registers.cpp
+++ b/src/citra_qt/debugger/registers.cpp
@@ -46,18 +46,18 @@ void RegistersWidget::OnCPUStepped()
46 46
47 CSPR->setText(1, QString("0x%1").arg(app_core->GetCPSR(), 8, 16, QLatin1Char('0'))); 47 CSPR->setText(1, QString("0x%1").arg(app_core->GetCPSR(), 8, 16, QLatin1Char('0')));
48 CSPR->child(0)->setText(1, QString("b%1").arg(app_core->GetCPSR() & 0x1F, 5, 2, QLatin1Char('0'))); // M - Mode 48 CSPR->child(0)->setText(1, QString("b%1").arg(app_core->GetCPSR() & 0x1F, 5, 2, QLatin1Char('0'))); // M - Mode
49 CSPR->child(1)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 5) & 0x1)); // T - State 49 CSPR->child(1)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 5) & 0x1)); // T - State
50 CSPR->child(2)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 6) & 0x1)); // F - FIQ disable 50 CSPR->child(2)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 6) & 0x1)); // F - FIQ disable
51 CSPR->child(3)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 7) & 0x1)); // I - IRQ disable 51 CSPR->child(3)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 7) & 0x1)); // I - IRQ disable
52 CSPR->child(4)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 8) & 0x1)); // A - Imprecise abort 52 CSPR->child(4)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 8) & 0x1)); // A - Imprecise abort
53 CSPR->child(5)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 9) & 0x1)); // E - Data endianess 53 CSPR->child(5)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 9) & 0x1)); // E - Data endianess
54 CSPR->child(6)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 10) & 0x3F)); // IT - If-Then state (DNM) 54 CSPR->child(6)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 10) & 0x3F)); // IT - If-Then state (DNM)
55 CSPR->child(7)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 16) & 0xF)); // GE - Greater-than-or-Equal 55 CSPR->child(7)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 16) & 0xF)); // GE - Greater-than-or-Equal
56 CSPR->child(8)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 20) & 0xF)); // DNM - Do not modify 56 CSPR->child(8)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 20) & 0xF)); // DNM - Do not modify
57 CSPR->child(9)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 24) & 0x1)); // J - Java state 57 CSPR->child(9)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 24) & 0x1)); // J - Java state
58 CSPR->child(10)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 27) & 0x1)); // Q - Sticky overflow 58 CSPR->child(10)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 27) & 0x1)); // Q - Sticky overflow
59 CSPR->child(11)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 28) & 0x1)); // V - Overflow 59 CSPR->child(11)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 28) & 0x1)); // V - Overflow
60 CSPR->child(12)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 29) & 0x1)); // C - Carry/Borrow/Extend 60 CSPR->child(12)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 29) & 0x1)); // C - Carry/Borrow/Extend
61 CSPR->child(13)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 30) & 0x1)); // Z - Zero 61 CSPR->child(13)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 30) & 0x1)); // Z - Zero
62 CSPR->child(14)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 31) & 0x1)); // N - Negative/Less than 62 CSPR->child(14)->setText(1, QString("%1").arg((app_core->GetCPSR() >> 31) & 0x1)); // N - Negative/Less than
63} 63}
diff --git a/src/citra_qt/debugger/registers.hxx b/src/citra_qt/debugger/registers.hxx
index 9645feb2a..4cca957ce 100644
--- a/src/citra_qt/debugger/registers.hxx
+++ b/src/citra_qt/debugger/registers.hxx
@@ -16,10 +16,10 @@ public slots:
16 void OnCPUStepped(); 16 void OnCPUStepped();
17 17
18private: 18private:
19 Ui::ARMRegisters cpu_regs_ui; 19 Ui::ARMRegisters cpu_regs_ui;
20 20
21 QTreeWidget* tree; 21 QTreeWidget* tree;
22 22
23 QTreeWidgetItem* registers; 23 QTreeWidgetItem* registers;
24 QTreeWidgetItem* CSPR; 24 QTreeWidgetItem* CSPR;
25}; 25};
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 9a4e36adf..d5554d917 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -117,7 +117,8 @@ GMainWindow::GMainWindow()
117 connect(GetHotkey("Main Window", "Load File", this), SIGNAL(activated()), this, SLOT(OnMenuLoadFile())); 117 connect(GetHotkey("Main Window", "Load File", this), SIGNAL(activated()), this, SLOT(OnMenuLoadFile()));
118 connect(GetHotkey("Main Window", "Start Emulation", this), SIGNAL(activated()), this, SLOT(OnStartGame())); 118 connect(GetHotkey("Main Window", "Start Emulation", this), SIGNAL(activated()), this, SLOT(OnStartGame()));
119 119
120 setWindowTitle(render_window->GetWindowTitle().c_str()); 120 std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc);
121 setWindowTitle(window_title.c_str());
121 122
122 show(); 123 show();
123 124
diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h
index dc8ac1fd9..609784076 100644
--- a/src/common/chunk_file.h
+++ b/src/common/chunk_file.h
@@ -51,7 +51,7 @@ public:
51 PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) { 51 PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) {
52 } 52 }
53 ~PointerWrapSection(); 53 ~PointerWrapSection();
54 54
55 bool operator == (const int &v) const { return ver_ == v; } 55 bool operator == (const int &v) const { return ver_ == v; }
56 bool operator != (const int &v) const { return ver_ != v; } 56 bool operator != (const int &v) const { return ver_ != v; }
57 bool operator <= (const int &v) const { return ver_ <= v; } 57 bool operator <= (const int &v) const { return ver_ <= v; }
@@ -196,7 +196,7 @@ public:
196 } 196 }
197 (*ptr) += size; 197 (*ptr) += size;
198 } 198 }
199 199
200 template<class K, class T> 200 template<class K, class T>
201 void Do(std::map<K, T *> &x) 201 void Do(std::map<K, T *> &x)
202 { 202 {
@@ -364,7 +364,7 @@ public:
364 if (vec_size > 0) 364 if (vec_size > 0)
365 DoArray(&x[0], vec_size); 365 DoArray(&x[0], vec_size);
366 } 366 }
367 367
368 // Store deques. 368 // Store deques.
369 template<class T> 369 template<class T>
370 void Do(std::deque<T *> &x) 370 void Do(std::deque<T *> &x)
@@ -481,11 +481,11 @@ public:
481 } 481 }
482 482
483 // Store strings. 483 // Store strings.
484 void Do(std::string &x) 484 void Do(std::string &x)
485 { 485 {
486 int stringLen = (int)x.length() + 1; 486 int stringLen = (int)x.length() + 1;
487 Do(stringLen); 487 Do(stringLen);
488 488
489 switch (mode) { 489 switch (mode) {
490 case MODE_READ: x = (char*)*ptr; break; 490 case MODE_READ: x = (char*)*ptr; break;
491 case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; 491 case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
@@ -495,7 +495,7 @@ public:
495 (*ptr) += stringLen; 495 (*ptr) += stringLen;
496 } 496 }
497 497
498 void Do(std::wstring &x) 498 void Do(std::wstring &x)
499 { 499 {
500 int stringLen = sizeof(wchar_t)*((int)x.length() + 1); 500 int stringLen = sizeof(wchar_t)*((int)x.length() + 1);
501 Do(stringLen); 501 Do(stringLen);
@@ -534,7 +534,7 @@ public:
534 void Do(T &x) { 534 void Do(T &x) {
535 DoHelper<T>::Do(this, x); 535 DoHelper<T>::Do(this, x);
536 } 536 }
537 537
538 template<class T> 538 template<class T>
539 void DoPOD(T &x) { 539 void DoPOD(T &x) {
540 DoHelper<T>::Do(this, x); 540 DoHelper<T>::Do(this, x);
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index c18afe119..d84ec4c42 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -17,7 +17,7 @@ template<> struct CompileTimeAssert<true> {};
17#define b2(x) ( (x) | ( (x) >> 1) ) 17#define b2(x) ( (x) | ( (x) >> 1) )
18#define b4(x) ( b2(x) | ( b2(x) >> 2) ) 18#define b4(x) ( b2(x) | ( b2(x) >> 2) )
19#define b8(x) ( b4(x) | ( b4(x) >> 4) ) 19#define b8(x) ( b4(x) | ( b4(x) >> 4) )
20#define b16(x) ( b8(x) | ( b8(x) >> 8) ) 20#define b16(x) ( b8(x) | ( b8(x) >> 8) )
21#define b32(x) (b16(x) | (b16(x) >>16) ) 21#define b32(x) (b16(x) | (b16(x) >>16) )
22#define ROUND_UP_POW2(x) (b32(x - 1) + 1) 22#define ROUND_UP_POW2(x) (b32(x - 1) + 1)
23 23
@@ -79,12 +79,12 @@ inline u64 _rotr64(u64 x, unsigned int shift){
79 #define unlink _unlink 79 #define unlink _unlink
80 #define snprintf _snprintf 80 #define snprintf _snprintf
81 #define vscprintf _vscprintf 81 #define vscprintf _vscprintf
82 82
83// Locale Cross-Compatibility 83// Locale Cross-Compatibility
84 #define locale_t _locale_t 84 #define locale_t _locale_t
85 #define freelocale _free_locale 85 #define freelocale _free_locale
86 #define newlocale(mask, locale, base) _create_locale(mask, locale) 86 #define newlocale(mask, locale, base) _create_locale(mask, locale)
87 87
88 #define LC_GLOBAL_LOCALE ((locale_t)-1) 88 #define LC_GLOBAL_LOCALE ((locale_t)-1)
89 #define LC_ALL_MASK LC_ALL 89 #define LC_ALL_MASK LC_ALL
90 #define LC_COLLATE_MASK LC_COLLATE 90 #define LC_COLLATE_MASK LC_COLLATE
@@ -92,7 +92,7 @@ inline u64 _rotr64(u64 x, unsigned int shift){
92 #define LC_MONETARY_MASK LC_MONETARY 92 #define LC_MONETARY_MASK LC_MONETARY
93 #define LC_NUMERIC_MASK LC_NUMERIC 93 #define LC_NUMERIC_MASK LC_NUMERIC
94 #define LC_TIME_MASK LC_TIME 94 #define LC_TIME_MASK LC_TIME
95 95
96 inline locale_t uselocale(locale_t new_locale) 96 inline locale_t uselocale(locale_t new_locale)
97 { 97 {
98 // Retrieve the current per thread locale setting 98 // Retrieve the current per thread locale setting
@@ -168,8 +168,8 @@ inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);}
168inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);} 168inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);}
169inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);} 169inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);}
170#elif _M_ARM 170#elif _M_ARM
171inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;} 171inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;}
172inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;} 172inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;}
173inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);} 173inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);}
174#elif __linux__ 174#elif __linux__
175inline u16 swap16(u16 _data) {return bswap_16(_data);} 175inline u16 swap16(u16 _data) {return bswap_16(_data);}
@@ -226,7 +226,7 @@ template <typename T>
226inline T FromBigEndian(T data) 226inline T FromBigEndian(T data)
227{ 227{
228 //static_assert(std::is_arithmetic<T>::value, "function only makes sense with arithmetic types"); 228 //static_assert(std::is_arithmetic<T>::value, "function only makes sense with arithmetic types");
229 229
230 swap<sizeof(data)>(reinterpret_cast<u8*>(&data)); 230 swap<sizeof(data)>(reinterpret_cast<u8*>(&data));
231 return data; 231 return data;
232} 232}
diff --git a/src/common/common_types.h b/src/common/common_types.h
index 7ce6b2240..fcc8b9a4e 100644
--- a/src/common/common_types.h
+++ b/src/common/common_types.h
@@ -22,7 +22,7 @@
22 * http://code.google.com/p/gekko-gc-emu/ 22 * http://code.google.com/p/gekko-gc-emu/
23 */ 23 */
24 24
25#pragma once 25#pragma once
26 26
27#include <cmath> 27#include <cmath>
28#include <cstdint> 28#include <cstdint>
@@ -45,8 +45,8 @@ typedef double f64; ///< 64-bit floating point
45 45
46/// Union for fast 16-bit type casting 46/// Union for fast 16-bit type casting
47union t16 { 47union t16 {
48 u8 _u8[2]; ///< 8-bit unsigned char(s) 48 u8 _u8[2]; ///< 8-bit unsigned char(s)
49 u16 _u16; ///< 16-bit unsigned shorts(s) 49 u16 _u16; ///< 16-bit unsigned shorts(s)
50}; 50};
51 51
52/// Union for fast 32-bit type casting 52/// Union for fast 32-bit type casting
diff --git a/src/common/console_listener.cpp b/src/common/console_listener.cpp
index 53f20d754..d7f27c358 100644
--- a/src/common/console_listener.cpp
+++ b/src/common/console_listener.cpp
@@ -86,7 +86,7 @@ bool ConsoleListener::IsOpen()
86 86
87/* 87/*
88 LetterSpace: SetConsoleScreenBufferSize and SetConsoleWindowInfo are 88 LetterSpace: SetConsoleScreenBufferSize and SetConsoleWindowInfo are
89 dependent on each other, that's the reason for the additional checks. 89 dependent on each other, that's the reason for the additional checks.
90*/ 90*/
91void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst) 91void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst)
92{ 92{
@@ -225,7 +225,7 @@ void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool
225 225
226 BytesWritten += cAttrWritten; 226 BytesWritten += cAttrWritten;
227 coordScreen = GetCoordinates(BytesWritten, LBufWidth); 227 coordScreen = GetCoordinates(BytesWritten, LBufWidth);
228 } 228 }
229 229
230 const int OldCursor = ConInfo.dwCursorPosition.Y * ConInfo.dwSize.X + ConInfo.dwCursorPosition.X; 230 const int OldCursor = ConInfo.dwCursorPosition.Y * ConInfo.dwSize.X + ConInfo.dwCursorPosition.X;
231 COORD Coo = GetCoordinates(OldCursor, LBufWidth); 231 COORD Coo = GetCoordinates(OldCursor, LBufWidth);
@@ -296,23 +296,23 @@ void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text)
296} 296}
297// Clear console screen 297// Clear console screen
298void ConsoleListener::ClearScreen(bool Cursor) 298void ConsoleListener::ClearScreen(bool Cursor)
299{ 299{
300#if defined(_WIN32) 300#if defined(_WIN32)
301 COORD coordScreen = { 0, 0 }; 301 COORD coordScreen = { 0, 0 };
302 DWORD cCharsWritten; 302 DWORD cCharsWritten;
303 CONSOLE_SCREEN_BUFFER_INFO csbi; 303 CONSOLE_SCREEN_BUFFER_INFO csbi;
304 DWORD dwConSize; 304 DWORD dwConSize;
305 305
306 HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); 306 HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
307 307
308 GetConsoleScreenBufferInfo(hConsole, &csbi); 308 GetConsoleScreenBufferInfo(hConsole, &csbi);
309 dwConSize = csbi.dwSize.X * csbi.dwSize.Y; 309 dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
310 // Write space to the entire console 310 // Write space to the entire console
311 FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten); 311 FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten);
312 GetConsoleScreenBufferInfo(hConsole, &csbi); 312 GetConsoleScreenBufferInfo(hConsole, &csbi);
313 FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten); 313 FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten);
314 // Reset cursor 314 // Reset cursor
315 if (Cursor) SetConsoleCursorPosition(hConsole, coordScreen); 315 if (Cursor) SetConsoleCursorPosition(hConsole, coordScreen);
316#endif 316#endif
317} 317}
318 318
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index 4d09acb8b..4cb94fed1 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -9,17 +9,33 @@
9#include "common/string_util.h" 9#include "common/string_util.h"
10#include "common/key_map.h" 10#include "common/key_map.h"
11 11
12// Abstraction class used to provide an interface between emulation code and the frontend (e.g. SDL, 12/**
13// QGLWidget, GLFW, etc...) 13 * Abstraction class used to provide an interface between emulation code and the frontend
14 * (e.g. SDL, QGLWidget, GLFW, etc...).
15 *
16 * Design notes on the interaction between EmuWindow and the emulation core:
17 * - Generally, decisions on anything visible to the user should be left up to the GUI.
18 * For example, the emulation core should not try to dictate some window title or size.
19 * This stuff is not the core's business and only causes problems with regards to thread-safety
20 * anyway.
21 * - Under certain circumstances, it may be desirable for the core to politely request the GUI
22 * to set e.g. a minimum window size. However, the GUI should always be free to ignore any
23 * such hints.
24 * - EmuWindow may expose some of its state as read-only to the emulation core, however care
25 * should be taken to make sure the provided information is self-consistent. This requires
26 * some sort of synchronization (most of this is still a TODO).
27 * - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please
28 * re-read the upper points again and think about it if you don't see this.
29 */
14class EmuWindow 30class EmuWindow
15{ 31{
16
17public: 32public:
18 /// Data structure to store an emuwindow configuration 33 /// Data structure to store emuwindow configuration
19 struct WindowConfig { 34 struct WindowConfig {
20 bool fullscreen; 35 bool fullscreen;
21 int res_width; 36 int res_width;
22 int res_height; 37 int res_height;
38 std::pair<unsigned,unsigned> min_client_area_size;
23 }; 39 };
24 40
25 /// Swap buffers to display the next frame 41 /// Swap buffers to display the next frame
@@ -42,52 +58,96 @@ public:
42 /// Signals a key release action to the HID module 58 /// Signals a key release action to the HID module
43 static void KeyReleased(KeyMap::HostDeviceKey key); 59 static void KeyReleased(KeyMap::HostDeviceKey key);
44 60
45 WindowConfig GetConfig() const { 61 /**
46 return m_config; 62 * Returns currently active configuration.
63 * @note Accesses to the returned object need not be consistent because it may be modified in another thread
64 */
65 const WindowConfig& GetActiveConfig() const {
66 return active_config;
47 } 67 }
48 68
69 /**
70 * Requests the internal configuration to be replaced by the specified argument at some point in the future.
71 * @note This method is thread-safe, because it delays configuration changes to the GUI event loop. Hence there is no guarantee on when the requested configuration will be active.
72 */
49 void SetConfig(const WindowConfig& val) { 73 void SetConfig(const WindowConfig& val) {
50 m_config = val; 74 config = val;
51 }
52
53 int GetClientAreaWidth() const {
54 return m_client_area_width;
55 } 75 }
56 76
57 void SetClientAreaWidth(const int val) { 77 /**
58 m_client_area_width = val; 78 * Gets the framebuffer size in pixels.
79 * @note This method is thread-safe
80 */
81 const std::pair<unsigned,unsigned> GetFramebufferSize() const {
82 return framebuffer_size;
59 } 83 }
60 84
61 int GetClientAreaHeight() const { 85 /**
62 return m_client_area_height; 86 * Gets window client area width in logical coordinates.
87 * @note For high-DPI systems, this is smaller than the framebuffer size.
88 * @note This method is thread-safe
89 */
90 std::pair<unsigned,unsigned> GetClientAreaSize() const {
91 return std::make_pair(client_area_width, client_area_height);
63 } 92 }
64 93
65 void SetClientAreaHeight(const int val) { 94protected:
66 m_client_area_height = val; 95 EmuWindow()
96 {
97 // TODO: Find a better place to set this.
98 config.min_client_area_size = std::make_pair(400u, 480u);
99 active_config = config;
67 } 100 }
101 virtual ~EmuWindow() {}
68 102
69 std::string GetWindowTitle() const { 103 /**
70 return m_window_title; 104 * Processes any pending configuration changes from the last SetConfig call.
105 * This method invokes OnMinimalClientAreaChangeRequest if the corresponding configuration
106 * field changed.
107 * @note Implementations will usually want to call this from the GUI thread.
108 * @todo Actually call this in existing implementations.
109 */
110 void ProcessConfigurationChanges() {
111 // TODO: For proper thread safety, we should eventually implement a proper
112 // multiple-writer/single-reader queue...
113
114 if (config.min_client_area_size != active_config.min_client_area_size) {
115 OnMinimalClientAreaChangeRequest(config.min_client_area_size);
116 config.min_client_area_size = active_config.min_client_area_size;
117 }
71 } 118 }
72 119
73 void SetWindowTitle(std::string val) { 120 /**
74 m_window_title = val; 121 * Update internal framebuffer size with the given parameter.
122 * @note EmuWindow implementations will usually use this in window resize event handlers.
123 */
124 void NotifyFramebufferSizeChanged(const std::pair<unsigned,unsigned>& size) {
125 framebuffer_size = size;
75 } 126 }
76 127
77protected: 128 /**
78 EmuWindow(): 129 * Update internal client area size with the given parameter.
79 m_client_area_width(640), 130 * @note EmuWindow implementations will usually use this in window resize event handlers.
80 m_client_area_height(480), 131 */
81 m_window_title(Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc)) 132 void NotifyClientAreaSizeChanged(const std::pair<unsigned,unsigned>& size) {
82 {} 133 client_area_width = size.first;
83 virtual ~EmuWindow() {} 134 client_area_height = size.second;
135 }
84 136
85 std::string m_window_title; ///< Current window title, should be used by window impl. 137private:
138 /**
139 * Handler called when the minimal client area was requested to be changed via SetConfig.
140 * For the request to be honored, EmuWindow implementations will usually reimplement this function.
141 */
142 virtual void OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) {
143 // By default, ignore this request and do nothing.
144 }
86 145
87 int m_client_area_width; ///< Current client width, should be set by window impl. 146 std::pair<unsigned,unsigned> framebuffer_size;
88 int m_client_area_height; ///< Current client height, should be set by window impl.
89 147
90private: 148 unsigned client_area_width; ///< Current client width, should be set by window impl.
91 WindowConfig m_config; ///< Internal configuration 149 unsigned client_area_height; ///< Current client height, should be set by window impl.
92 150
151 WindowConfig config; ///< Internal configuration (changes pending for being applied in ProcessConfigurationChanges)
152 WindowConfig active_config; ///< Internal active configuration
93}; 153};
diff --git a/src/common/extended_trace.cpp b/src/common/extended_trace.cpp
index 9cd0398ed..bf61ac1d1 100644
--- a/src/common/extended_trace.cpp
+++ b/src/common/extended_trace.cpp
@@ -29,7 +29,7 @@ using namespace std;
29void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut ) 29void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut )
30{ 30{
31#if defined(UNICODE)||defined(_UNICODE) 31#if defined(UNICODE)||defined(_UNICODE)
32 ULONG index = 0; 32 ULONG index = 0;
33 PCSTR lpAct = lpszIn; 33 PCSTR lpAct = lpszIn;
34 34
35 for( ; ; lpAct++ ) 35 for( ; ; lpAct++ )
@@ -37,7 +37,7 @@ void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut )
37 lpszOut[index++] = (TCHAR)(*lpAct); 37 lpszOut[index++] = (TCHAR)(*lpAct);
38 if ( *lpAct == 0 ) 38 if ( *lpAct == 0 )
39 break; 39 break;
40 } 40 }
41#else 41#else
42 // This is trivial :) 42 // This is trivial :)
43 strcpy( lpszOut, lpszIn ); 43 strcpy( lpszOut, lpszIn );
@@ -101,7 +101,7 @@ BOOL InitSymInfo( PCSTR lpszInitialSymbolPath )
101 CHAR lpszSymbolPath[BUFFERSIZE]; 101 CHAR lpszSymbolPath[BUFFERSIZE];
102 DWORD symOptions = SymGetOptions(); 102 DWORD symOptions = SymGetOptions();
103 103
104 symOptions |= SYMOPT_LOAD_LINES; 104 symOptions |= SYMOPT_LOAD_LINES;
105 symOptions &= ~SYMOPT_UNDNAME; 105 symOptions &= ~SYMOPT_UNDNAME;
106 SymSetOptions( symOptions ); 106 SymSetOptions( symOptions );
107 InitSymbolPath( lpszSymbolPath, lpszInitialSymbolPath ); 107 InitSymbolPath( lpszSymbolPath, lpszInitialSymbolPath );
@@ -153,15 +153,15 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L
153#ifndef _M_X64 153#ifndef _M_X64
154 DWORD dwDisp = 0; 154 DWORD dwDisp = 0;
155 if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) ) 155 if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) )
156#else 156#else
157 //makes it compile but hell im not sure if this works... 157 //makes it compile but hell im not sure if this works...
158 DWORD64 dwDisp = 0; 158 DWORD64 dwDisp = 0;
159 if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, (PDWORD64)&dwDisp, pSym ) ) 159 if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, (PDWORD64)&dwDisp, pSym ) )
160#endif 160#endif
161 { 161 {
162 // Make the symbol readable for humans 162 // Make the symbol readable for humans
163 UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE, 163 UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE,
164 UNDNAME_COMPLETE | 164 UNDNAME_COMPLETE |
165 UNDNAME_NO_THISTYPE | 165 UNDNAME_NO_THISTYPE |
166 UNDNAME_NO_SPECIAL_SYMS | 166 UNDNAME_NO_SPECIAL_SYMS |
167 UNDNAME_NO_MEMBER_TYPE | 167 UNDNAME_NO_MEMBER_TYPE |
@@ -219,7 +219,7 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L
219 _tcscat( lpszSymbol, lpszParsed ); 219 _tcscat( lpszSymbol, lpszParsed );
220 220
221 ret = TRUE; 221 ret = TRUE;
222 } 222 }
223 GlobalFree( pSym ); 223 GlobalFree( pSym );
224 224
225 return ret; 225 return ret;
@@ -325,14 +325,14 @@ void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file )
325 325
326 PrintFunctionAndSourceInfo(file, callStack); 326 PrintFunctionAndSourceInfo(file, callStack);
327 327
328 for( ULONG index = 0; ; index++ ) 328 for( ULONG index = 0; ; index++ )
329 { 329 {
330 bResult = StackWalk( 330 bResult = StackWalk(
331 IMAGE_FILE_MACHINE_I386, 331 IMAGE_FILE_MACHINE_I386,
332 hProcess, 332 hProcess,
333 hThread, 333 hThread,
334 &callStack, 334 &callStack,
335 NULL, 335 NULL,
336 NULL, 336 NULL,
337 SymFunctionTableAccess, 337 SymFunctionTableAccess,
338 SymGetModuleBase, 338 SymGetModuleBase,
@@ -341,7 +341,7 @@ void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file )
341 if ( index == 0 ) 341 if ( index == 0 )
342 continue; 342 continue;
343 343
344 if( !bResult || callStack.AddrFrame.Offset == 0 ) 344 if( !bResult || callStack.AddrFrame.Offset == 0 )
345 break; 345 break;
346 346
347 PrintFunctionAndSourceInfo(file, callStack); 347 PrintFunctionAndSourceInfo(file, callStack);
@@ -382,14 +382,14 @@ void StackTrace(HANDLE hThread, const char* lpszMessage, FILE *file, DWORD eip,
382 382
383 PrintFunctionAndSourceInfo(file, callStack); 383 PrintFunctionAndSourceInfo(file, callStack);
384 384
385 for( ULONG index = 0; ; index++ ) 385 for( ULONG index = 0; ; index++ )
386 { 386 {
387 bResult = StackWalk( 387 bResult = StackWalk(
388 IMAGE_FILE_MACHINE_I386, 388 IMAGE_FILE_MACHINE_I386,
389 hProcess, 389 hProcess,
390 hThread, 390 hThread,
391 &callStack, 391 &callStack,
392 NULL, 392 NULL,
393 NULL, 393 NULL,
394 SymFunctionTableAccess, 394 SymFunctionTableAccess,
395 SymGetModuleBase, 395 SymGetModuleBase,
@@ -398,7 +398,7 @@ void StackTrace(HANDLE hThread, const char* lpszMessage, FILE *file, DWORD eip,
398 if ( index == 0 ) 398 if ( index == 0 )
399 continue; 399 continue;
400 400
401 if( !bResult || callStack.AddrFrame.Offset == 0 ) 401 if( !bResult || callStack.AddrFrame.Offset == 0 )
402 break; 402 break;
403 403
404 PrintFunctionAndSourceInfo(file, callStack); 404 PrintFunctionAndSourceInfo(file, callStack);
diff --git a/src/common/fifo_queue.h b/src/common/fifo_queue.h
index 78a8f561d..2c18285d4 100644
--- a/src/common/fifo_queue.h
+++ b/src/common/fifo_queue.h
@@ -45,7 +45,7 @@ public:
45 // create the element, add it to the queue 45 // create the element, add it to the queue
46 m_write_ptr->current = new T(std::forward<Arg>(t)); 46 m_write_ptr->current = new T(std::forward<Arg>(t));
47 // set the next pointer to a new element ptr 47 // set the next pointer to a new element ptr
48 // then advance the write pointer 48 // then advance the write pointer
49 m_write_ptr = m_write_ptr->next = new ElementPtr(); 49 m_write_ptr = m_write_ptr->next = new ElementPtr();
50 Common::AtomicIncrement(m_size); 50 Common::AtomicIncrement(m_size);
51 } 51 }
diff --git a/src/common/file_search.cpp b/src/common/file_search.cpp
index 63580f688..bfb54ce72 100644
--- a/src/common/file_search.cpp
+++ b/src/common/file_search.cpp
@@ -43,7 +43,7 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string&
43 bool bkeepLooping = true; 43 bool bkeepLooping = true;
44 44
45 while (bkeepLooping) 45 while (bkeepLooping)
46 { 46 {
47 if (findData.cFileName[0] != '.') 47 if (findData.cFileName[0] != '.')
48 { 48 {
49 std::string strFilename; 49 std::string strFilename;
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 35da07306..b6dec838c 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -88,7 +88,7 @@ bool IsDirectory(const std::string &filename)
88#endif 88#endif
89 89
90 if (result < 0) { 90 if (result < 0) {
91 WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s", 91 WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s",
92 filename.c_str(), GetLastErrorMsg()); 92 filename.c_str(), GetLastErrorMsg());
93 return false; 93 return false;
94 } 94 }
@@ -102,7 +102,7 @@ bool Delete(const std::string &filename)
102{ 102{
103 INFO_LOG(COMMON, "Delete: file %s", filename.c_str()); 103 INFO_LOG(COMMON, "Delete: file %s", filename.c_str());
104 104
105 // Return true because we care about the file no 105 // Return true because we care about the file no
106 // being there, not the actual delete. 106 // being there, not the actual delete.
107 if (!Exists(filename)) 107 if (!Exists(filename))
108 { 108 {
@@ -120,13 +120,13 @@ bool Delete(const std::string &filename)
120#ifdef _WIN32 120#ifdef _WIN32
121 if (!DeleteFile(Common::UTF8ToTStr(filename).c_str())) 121 if (!DeleteFile(Common::UTF8ToTStr(filename).c_str()))
122 { 122 {
123 WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", 123 WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s",
124 filename.c_str(), GetLastErrorMsg()); 124 filename.c_str(), GetLastErrorMsg());
125 return false; 125 return false;
126 } 126 }
127#else 127#else
128 if (unlink(filename.c_str()) == -1) { 128 if (unlink(filename.c_str()) == -1) {
129 WARN_LOG(COMMON, "Delete: unlink failed on %s: %s", 129 WARN_LOG(COMMON, "Delete: unlink failed on %s: %s",
130 filename.c_str(), GetLastErrorMsg()); 130 filename.c_str(), GetLastErrorMsg());
131 return false; 131 return false;
132 } 132 }
@@ -232,28 +232,28 @@ bool DeleteDir(const std::string &filename)
232 return false; 232 return false;
233} 233}
234 234
235// renames file srcFilename to destFilename, returns true on success 235// renames file srcFilename to destFilename, returns true on success
236bool Rename(const std::string &srcFilename, const std::string &destFilename) 236bool Rename(const std::string &srcFilename, const std::string &destFilename)
237{ 237{
238 INFO_LOG(COMMON, "Rename: %s --> %s", 238 INFO_LOG(COMMON, "Rename: %s --> %s",
239 srcFilename.c_str(), destFilename.c_str()); 239 srcFilename.c_str(), destFilename.c_str());
240 if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) 240 if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
241 return true; 241 return true;
242 ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s", 242 ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s",
243 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); 243 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
244 return false; 244 return false;
245} 245}
246 246
247// copies file srcFilename to destFilename, returns true on success 247// copies file srcFilename to destFilename, returns true on success
248bool Copy(const std::string &srcFilename, const std::string &destFilename) 248bool Copy(const std::string &srcFilename, const std::string &destFilename)
249{ 249{
250 INFO_LOG(COMMON, "Copy: %s --> %s", 250 INFO_LOG(COMMON, "Copy: %s --> %s",
251 srcFilename.c_str(), destFilename.c_str()); 251 srcFilename.c_str(), destFilename.c_str());
252#ifdef _WIN32 252#ifdef _WIN32
253 if (CopyFile(Common::UTF8ToTStr(srcFilename).c_str(), Common::UTF8ToTStr(destFilename).c_str(), FALSE)) 253 if (CopyFile(Common::UTF8ToTStr(srcFilename).c_str(), Common::UTF8ToTStr(destFilename).c_str(), FALSE))
254 return true; 254 return true;
255 255
256 ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", 256 ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s",
257 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); 257 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
258 return false; 258 return false;
259#else 259#else
@@ -267,7 +267,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
267 FILE *input = fopen(srcFilename.c_str(), "rb"); 267 FILE *input = fopen(srcFilename.c_str(), "rb");
268 if (!input) 268 if (!input)
269 { 269 {
270 ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s", 270 ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s",
271 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); 271 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
272 return false; 272 return false;
273 } 273 }
@@ -277,7 +277,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
277 if (!output) 277 if (!output)
278 { 278 {
279 fclose(input); 279 fclose(input);
280 ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s", 280 ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s",
281 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); 281 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
282 return false; 282 return false;
283 } 283 }
@@ -291,8 +291,8 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
291 { 291 {
292 if (ferror(input) != 0) 292 if (ferror(input) != 0)
293 { 293 {
294 ERROR_LOG(COMMON, 294 ERROR_LOG(COMMON,
295 "Copy: failed reading from source, %s --> %s: %s", 295 "Copy: failed reading from source, %s --> %s: %s",
296 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); 296 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
297 goto bail; 297 goto bail;
298 } 298 }
@@ -302,8 +302,8 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
302 int wnum = fwrite(buffer, sizeof(char), rnum, output); 302 int wnum = fwrite(buffer, sizeof(char), rnum, output);
303 if (wnum != rnum) 303 if (wnum != rnum)
304 { 304 {
305 ERROR_LOG(COMMON, 305 ERROR_LOG(COMMON,
306 "Copy: failed writing to output, %s --> %s: %s", 306 "Copy: failed writing to output, %s --> %s: %s",
307 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); 307 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
308 goto bail; 308 goto bail;
309 } 309 }
@@ -335,7 +335,7 @@ u64 GetSize(const std::string &filename)
335 WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.c_str()); 335 WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.c_str());
336 return 0; 336 return 0;
337 } 337 }
338 338
339 struct stat64 buf; 339 struct stat64 buf;
340#ifdef _WIN32 340#ifdef _WIN32
341 if (_tstat64(Common::UTF8ToTStr(filename).c_str(), &buf) == 0) 341 if (_tstat64(Common::UTF8ToTStr(filename).c_str(), &buf) == 0)
@@ -384,10 +384,10 @@ u64 GetSize(FILE *f)
384 return size; 384 return size;
385} 385}
386 386
387// creates an empty file filename, returns true on success 387// creates an empty file filename, returns true on success
388bool CreateEmptyFile(const std::string &filename) 388bool CreateEmptyFile(const std::string &filename)
389{ 389{
390 INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); 390 INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str());
391 391
392 if (!FileUtil::IOFile(filename, "wb")) 392 if (!FileUtil::IOFile(filename, "wb"))
393 { 393 {
@@ -437,7 +437,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
437#endif 437#endif
438 // check for "." and ".." 438 // check for "." and ".."
439 if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || 439 if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
440 ((virtualName[0] == '.') && (virtualName[1] == '.') && 440 ((virtualName[0] == '.') && (virtualName[1] == '.') &&
441 (virtualName[2] == '\0'))) 441 (virtualName[2] == '\0')))
442 continue; 442 continue;
443 entry.virtualName = virtualName; 443 entry.virtualName = virtualName;
@@ -452,14 +452,14 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
452 foundEntries += (u32)entry.size; 452 foundEntries += (u32)entry.size;
453 } 453 }
454 else 454 else
455 { // is a file 455 { // is a file
456 entry.isDirectory = false; 456 entry.isDirectory = false;
457 entry.size = GetSize(entry.physicalName.c_str()); 457 entry.size = GetSize(entry.physicalName.c_str());
458 } 458 }
459 ++foundEntries; 459 ++foundEntries;
460 // Push into the tree 460 // Push into the tree
461 parentEntry.children.push_back(entry); 461 parentEntry.children.push_back(entry);
462#ifdef _WIN32 462#ifdef _WIN32
463 } while (FindNextFile(hFind, &ffd) != 0); 463 } while (FindNextFile(hFind, &ffd) != 0);
464 FindClose(hFind); 464 FindClose(hFind);
465#else 465#else
@@ -504,7 +504,7 @@ bool DeleteDirRecursively(const std::string &directory)
504 504
505 // check for "." and ".." 505 // check for "." and ".."
506 if (((virtualName[0] == '.') && (virtualName[1] == '\0')) || 506 if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
507 ((virtualName[0] == '.') && (virtualName[1] == '.') && 507 ((virtualName[0] == '.') && (virtualName[1] == '.') &&
508 (virtualName[2] == '\0'))) 508 (virtualName[2] == '\0')))
509 continue; 509 continue;
510 510
@@ -540,7 +540,7 @@ bool DeleteDirRecursively(const std::string &directory)
540 closedir(dirp); 540 closedir(dirp);
541#endif 541#endif
542 FileUtil::DeleteDir(directory); 542 FileUtil::DeleteDir(directory);
543 543
544 return true; 544 return true;
545} 545}
546 546
@@ -585,7 +585,7 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
585std::string GetCurrentDir() 585std::string GetCurrentDir()
586{ 586{
587 char *dir; 587 char *dir;
588 // Get the current working directory (getcwd uses malloc) 588 // Get the current working directory (getcwd uses malloc)
589 if (!(dir = __getcwd(NULL, 0))) { 589 if (!(dir = __getcwd(NULL, 0))) {
590 590
591 ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s", 591 ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s",
@@ -604,7 +604,7 @@ bool SetCurrentDir(const std::string &directory)
604} 604}
605 605
606#if defined(__APPLE__) 606#if defined(__APPLE__)
607std::string GetBundleDirectory() 607std::string GetBundleDirectory()
608{ 608{
609 CFURLRef BundleRef; 609 CFURLRef BundleRef;
610 char AppBundlePath[MAXPATHLEN]; 610 char AppBundlePath[MAXPATHLEN];
@@ -666,8 +666,8 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
666 if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR)) 666 if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR))
667 paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP; 667 paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
668 else 668 else
669 paths[D_USER_IDX] = std::string(getenv("HOME") ? 669 paths[D_USER_IDX] = std::string(getenv("HOME") ?
670 getenv("HOME") : getenv("PWD") ? 670 getenv("HOME") : getenv("PWD") ?
671 getenv("PWD") : "") + DIR_SEP EMU_DATA_DIR DIR_SEP; 671 getenv("PWD") : "") + DIR_SEP EMU_DATA_DIR DIR_SEP;
672#endif 672#endif
673 673
@@ -749,7 +749,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
749 paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG; 749 paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
750 } 750 }
751 } 751 }
752 752
753 return paths[DirIDX]; 753 return paths[DirIDX];
754} 754}
755 755
@@ -762,7 +762,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
762// if (!FileUtil::Exists(dir)) 762// if (!FileUtil::Exists(dir))
763// dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/"; 763// dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/";
764//#endif 764//#endif
765// 765//
766// return dir; 766// return dir;
767//} 767//}
768 768
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 173ce6623..72b80be8a 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -16,33 +16,33 @@
16 16
17// User directory indices for GetUserPath 17// User directory indices for GetUserPath
18enum { 18enum {
19 D_USER_IDX, 19 D_USER_IDX,
20 D_ROOT_IDX, 20 D_ROOT_IDX,
21 D_CONFIG_IDX, 21 D_CONFIG_IDX,
22 D_GAMECONFIG_IDX, 22 D_GAMECONFIG_IDX,
23 D_MAPS_IDX, 23 D_MAPS_IDX,
24 D_CACHE_IDX, 24 D_CACHE_IDX,
25 D_SHADERCACHE_IDX, 25 D_SHADERCACHE_IDX,
26 D_SHADERS_IDX, 26 D_SHADERS_IDX,
27 D_STATESAVES_IDX, 27 D_STATESAVES_IDX,
28 D_SCREENSHOTS_IDX, 28 D_SCREENSHOTS_IDX,
29 D_SDMC_IDX, 29 D_SDMC_IDX,
30 D_HIRESTEXTURES_IDX, 30 D_HIRESTEXTURES_IDX,
31 D_DUMP_IDX, 31 D_DUMP_IDX,
32 D_DUMPFRAMES_IDX, 32 D_DUMPFRAMES_IDX,
33 D_DUMPAUDIO_IDX, 33 D_DUMPAUDIO_IDX,
34 D_DUMPTEXTURES_IDX, 34 D_DUMPTEXTURES_IDX,
35 D_DUMPDSP_IDX, 35 D_DUMPDSP_IDX,
36 D_LOGS_IDX, 36 D_LOGS_IDX,
37 D_SYSCONF_IDX, 37 D_SYSCONF_IDX,
38 F_EMUCONFIG_IDX, 38 F_EMUCONFIG_IDX,
39 F_DEBUGGERCONFIG_IDX, 39 F_DEBUGGERCONFIG_IDX,
40 F_LOGGERCONFIG_IDX, 40 F_LOGGERCONFIG_IDX,
41 F_MAINLOG_IDX, 41 F_MAINLOG_IDX,
42 F_RAMDUMP_IDX, 42 F_RAMDUMP_IDX,
43 F_ARAMDUMP_IDX, 43 F_ARAMDUMP_IDX,
44 F_SYSCONF_IDX, 44 F_SYSCONF_IDX,
45 NUM_PATH_INDICES 45 NUM_PATH_INDICES
46}; 46};
47 47
48namespace FileUtil 48namespace FileUtil
@@ -51,11 +51,11 @@ namespace FileUtil
51// FileSystem tree node/ 51// FileSystem tree node/
52struct FSTEntry 52struct FSTEntry
53{ 53{
54 bool isDirectory; 54 bool isDirectory;
55 u64 size; // file length or number of entries from children 55 u64 size; // file length or number of entries from children
56 std::string physicalName; // name on disk 56 std::string physicalName; // name on disk
57 std::string virtualName; // name in FST names table 57 std::string virtualName; // name in FST names table
58 std::vector<FSTEntry> children; 58 std::vector<FSTEntry> children;
59}; 59};
60 60
61// Returns true if file filename exists 61// Returns true if file filename exists
@@ -148,86 +148,86 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
148class IOFile : public NonCopyable 148class IOFile : public NonCopyable
149{ 149{
150public: 150public:
151 IOFile(); 151 IOFile();
152 IOFile(std::FILE* file); 152 IOFile(std::FILE* file);
153 IOFile(const std::string& filename, const char openmode[]); 153 IOFile(const std::string& filename, const char openmode[]);
154 154
155 ~IOFile(); 155 ~IOFile();
156 156
157 IOFile(IOFile&& other); 157 IOFile(IOFile&& other);
158 IOFile& operator=(IOFile&& other); 158 IOFile& operator=(IOFile&& other);
159 159
160 void Swap(IOFile& other); 160 void Swap(IOFile& other);
161 161
162 bool Open(const std::string& filename, const char openmode[]); 162 bool Open(const std::string& filename, const char openmode[]);
163 bool Close(); 163 bool Close();
164 164
165 template <typename T> 165 template <typename T>
166 size_t ReadArray(T* data, size_t length) 166 size_t ReadArray(T* data, size_t length)
167 { 167 {
168 if (!IsOpen()) { 168 if (!IsOpen()) {
169 m_good = false; 169 m_good = false;
170 return -1; 170 return -1;
171 } 171 }
172 172
173 size_t items_read = std::fread(data, sizeof(T), length, m_file); 173 size_t items_read = std::fread(data, sizeof(T), length, m_file);
174 if (items_read != length) 174 if (items_read != length)
175 m_good = false; 175 m_good = false;
176 176
177 return items_read; 177 return items_read;
178 } 178 }
179 179
180 template <typename T> 180 template <typename T>
181 size_t WriteArray(const T* data, size_t length) 181 size_t WriteArray(const T* data, size_t length)
182 { 182 {
183 if (!IsOpen()) { 183 if (!IsOpen()) {
184 m_good = false; 184 m_good = false;
185 return -1; 185 return -1;
186 } 186 }
187 187
188 size_t items_written = std::fwrite(data, sizeof(T), length, m_file); 188 size_t items_written = std::fwrite(data, sizeof(T), length, m_file);
189 if (items_written != length) 189 if (items_written != length)
190 m_good = false; 190 m_good = false;
191 191
192 return items_written; 192 return items_written;
193 } 193 }
194 194
195 size_t ReadBytes(void* data, size_t length) 195 size_t ReadBytes(void* data, size_t length)
196 { 196 {
197 return ReadArray(reinterpret_cast<char*>(data), length); 197 return ReadArray(reinterpret_cast<char*>(data), length);
198 } 198 }
199 199
200 size_t WriteBytes(const void* data, size_t length) 200 size_t WriteBytes(const void* data, size_t length)
201 { 201 {
202 return WriteArray(reinterpret_cast<const char*>(data), length); 202 return WriteArray(reinterpret_cast<const char*>(data), length);
203 } 203 }
204 204
205 bool IsOpen() { return NULL != m_file; } 205 bool IsOpen() { return NULL != m_file; }
206 206
207 // m_good is set to false when a read, write or other function fails 207 // m_good is set to false when a read, write or other function fails
208 bool IsGood() { return m_good; } 208 bool IsGood() { return m_good; }
209 operator void*() { return m_good ? m_file : NULL; } 209 operator void*() { return m_good ? m_file : NULL; }
210 210
211 std::FILE* ReleaseHandle(); 211 std::FILE* ReleaseHandle();
212 212
213 std::FILE* GetHandle() { return m_file; } 213 std::FILE* GetHandle() { return m_file; }
214 214
215 void SetHandle(std::FILE* file); 215 void SetHandle(std::FILE* file);
216 216
217 bool Seek(s64 off, int origin); 217 bool Seek(s64 off, int origin);
218 u64 Tell(); 218 u64 Tell();
219 u64 GetSize(); 219 u64 GetSize();
220 bool Resize(u64 size); 220 bool Resize(u64 size);
221 bool Flush(); 221 bool Flush();
222 222
223 // clear error state 223 // clear error state
224 void Clear() { m_good = true; std::clearerr(m_file); } 224 void Clear() { m_good = true; std::clearerr(m_file); }
225 225
226 std::FILE* m_file; 226 std::FILE* m_file;
227 bool m_good; 227 bool m_good;
228private: 228private:
229 IOFile(IOFile&); 229 IOFile(IOFile&);
230 IOFile& operator=(IOFile& other); 230 IOFile& operator=(IOFile& other);
231}; 231};
232 232
233} // namespace 233} // namespace
@@ -237,8 +237,8 @@ template <typename T>
237void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode) 237void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode)
238{ 238{
239#ifdef _WIN32 239#ifdef _WIN32
240 fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode); 240 fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode);
241#else 241#else
242 fstream.open(filename.c_str(), openmode); 242 fstream.open(filename.c_str(), openmode);
243#endif 243#endif
244} 244}
diff --git a/src/common/hash.cpp b/src/common/hash.cpp
index d2ebc7341..2ddcfe6b7 100644
--- a/src/common/hash.cpp
+++ b/src/common/hash.cpp
@@ -115,15 +115,15 @@ inline u64 getblock(const u64 * p, int i)
115 115
116inline void bmix64(u64 & h1, u64 & h2, u64 & k1, u64 & k2, u64 & c1, u64 & c2) 116inline void bmix64(u64 & h1, u64 & h2, u64 & k1, u64 & k2, u64 & c1, u64 & c2)
117{ 117{
118 k1 *= c1; 118 k1 *= c1;
119 k1 = _rotl64(k1,23); 119 k1 = _rotl64(k1,23);
120 k1 *= c2; 120 k1 *= c2;
121 h1 ^= k1; 121 h1 ^= k1;
122 h1 += h2; 122 h1 += h2;
123 123
124 h2 = _rotl64(h2,41); 124 h2 = _rotl64(h2,41);
125 125
126 k2 *= c2; 126 k2 *= c2;
127 k2 = _rotl64(k2,23); 127 k2 = _rotl64(k2,23);
128 k2 *= c1; 128 k2 *= c1;
129 h2 ^= k2; 129 h2 ^= k2;
@@ -250,7 +250,7 @@ u64 GetCRC32(const u8 *src, int len, u32 samples)
250} 250}
251 251
252 252
253/* 253/*
254 * NOTE: This hash function is used for custom texture loading/dumping, so 254 * NOTE: This hash function is used for custom texture loading/dumping, so
255 * it should not be changed, which would require all custom textures to be 255 * it should not be changed, which would require all custom textures to be
256 * recalculated for their new hash values. If the hashing function is 256 * recalculated for their new hash values. If the hashing function is
@@ -273,7 +273,7 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples)
273 u64 k = data[0]; 273 u64 k = data[0];
274 data+=Step; 274 data+=Step;
275 k *= m; 275 k *= m;
276 k ^= k >> r; 276 k ^= k >> r;
277 k *= m; 277 k *= m;
278 h ^= k; 278 h ^= k;
279 h *= m; 279 h *= m;
@@ -292,13 +292,13 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples)
292 case 1: h ^= u64(data2[0]); 292 case 1: h ^= u64(data2[0]);
293 h *= m; 293 h *= m;
294 }; 294 };
295 295
296 h ^= h >> r; 296 h ^= h >> r;
297 h *= m; 297 h *= m;
298 h ^= h >> r; 298 h ^= h >> r;
299 299
300 return h; 300 return h;
301} 301}
302#else 302#else
303// CRC32 hash using the SSE4.2 instruction 303// CRC32 hash using the SSE4.2 instruction
304u64 GetCRC32(const u8 *src, int len, u32 samples) 304u64 GetCRC32(const u8 *src, int len, u32 samples)
@@ -351,15 +351,15 @@ inline u32 fmix32(u32 h)
351 351
352inline void bmix32(u32 & h1, u32 & h2, u32 & k1, u32 & k2, u32 & c1, u32 & c2) 352inline void bmix32(u32 & h1, u32 & h2, u32 & k1, u32 & k2, u32 & c1, u32 & c2)
353{ 353{
354 k1 *= c1; 354 k1 *= c1;
355 k1 = _rotl(k1,11); 355 k1 = _rotl(k1,11);
356 k1 *= c2; 356 k1 *= c2;
357 h1 ^= k1; 357 h1 ^= k1;
358 h1 += h2; 358 h1 += h2;
359 359
360 h2 = _rotl(h2,17); 360 h2 = _rotl(h2,17);
361 361
362 k2 *= c2; 362 k2 *= c2;
363 k2 = _rotl(k2,11); 363 k2 = _rotl(k2,11);
364 k2 *= c1; 364 k2 *= c1;
365 h2 ^= k2; 365 h2 ^= k2;
@@ -405,7 +405,7 @@ u64 GetMurmurHash3(const u8* src, int len, u32 samples)
405 405
406 //---------- 406 //----------
407 // tail 407 // tail
408 408
409 const u8 * tail = (const u8*)(data + nblocks*8); 409 const u8 * tail = (const u8*)(data + nblocks*8);
410 410
411 u32 k1 = 0; 411 u32 k1 = 0;
@@ -439,7 +439,7 @@ u64 GetMurmurHash3(const u8* src, int len, u32 samples)
439 439
440 out[0] = h1; 440 out[0] = h1;
441 out[1] = h2; 441 out[1] = h2;
442 442
443 return *((u64 *)&out); 443 return *((u64 *)&out);
444} 444}
445 445
@@ -463,11 +463,11 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples)
463 { 463 {
464 u64 k = data[0]; 464 u64 k = data[0];
465 data+=Step; 465 data+=Step;
466 k *= m; 466 k *= m;
467 k ^= k >> r; 467 k ^= k >> r;
468 k *= m; 468 k *= m;
469 h ^= k; 469 h ^= k;
470 h *= m; 470 h *= m;
471 } 471 }
472 472
473 const u8 * data2 = (const u8*)end; 473 const u8 * data2 = (const u8*)end;
@@ -483,7 +483,7 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples)
483 case 1: h ^= u64(data2[0]); 483 case 1: h ^= u64(data2[0]);
484 h *= m; 484 h *= m;
485 }; 485 };
486 486
487 h ^= h >> r; 487 h ^= h >> r;
488 h *= m; 488 h *= m;
489 h ^= h >> r; 489 h ^= h >> r;
diff --git a/src/common/linear_disk_cache.h b/src/common/linear_disk_cache.h
index 96dce3155..f4263f72a 100644
--- a/src/common/linear_disk_cache.h
+++ b/src/common/linear_disk_cache.h
@@ -64,7 +64,7 @@ public:
64 m_file.seekg(0, std::ios::beg); 64 m_file.seekg(0, std::ios::beg);
65 std::fstream::pos_type start_pos = m_file.tellg(); 65 std::fstream::pos_type start_pos = m_file.tellg();
66 std::streamoff file_size = end_pos - start_pos; 66 std::streamoff file_size = end_pos - start_pos;
67 67
68 if (m_file.is_open() && ValidateHeader()) 68 if (m_file.is_open() && ValidateHeader())
69 { 69 {
70 // good header, read some key/value pairs 70 // good header, read some key/value pairs
@@ -87,7 +87,7 @@ public:
87 87
88 // read key/value and pass to reader 88 // read key/value and pass to reader
89 if (Read(&key) && 89 if (Read(&key) &&
90 Read(value, value_size) && 90 Read(value, value_size) &&
91 Read(&entry_number) && 91 Read(&entry_number) &&
92 entry_number == m_num_entries+1) 92 entry_number == m_num_entries+1)
93 { 93 {
@@ -115,7 +115,7 @@ public:
115 WriteHeader(); 115 WriteHeader();
116 return 0; 116 return 0;
117 } 117 }
118 118
119 void Sync() 119 void Sync()
120 { 120 {
121 m_file.flush(); 121 m_file.flush();
diff --git a/src/common/log.h b/src/common/log.h
index bfd73f8a5..14ad98c08 100644
--- a/src/common/log.h
+++ b/src/common/log.h
@@ -11,7 +11,7 @@
11enum { 11enum {
12 OS_LEVEL, // Printed by the emulated operating system 12 OS_LEVEL, // Printed by the emulated operating system
13 NOTICE_LEVEL, // VERY important information that is NOT errors. Like startup and OSReports. 13 NOTICE_LEVEL, // VERY important information that is NOT errors. Like startup and OSReports.
14 ERROR_LEVEL, // Critical errors 14 ERROR_LEVEL, // Critical errors
15 WARNING_LEVEL, // Something is suspicious. 15 WARNING_LEVEL, // Something is suspicious.
16 INFO_LEVEL, // General information. 16 INFO_LEVEL, // General information.
17 DEBUG_LEVEL, // Detailed debugging - might make things slow. 17 DEBUG_LEVEL, // Detailed debugging - might make things slow.
@@ -46,7 +46,7 @@ enum LOG_TYPE {
46 MEMMAP, 46 MEMMAP,
47 MEMCARD_MANAGER, 47 MEMCARD_MANAGER,
48 OSREPORT, 48 OSREPORT,
49 PAD, 49 PAD,
50 PROCESSORINTERFACE, 50 PROCESSORINTERFACE,
51 PIXELENGINE, 51 PIXELENGINE,
52 SERIALINTERFACE, 52 SERIALINTERFACE,
@@ -69,6 +69,7 @@ enum LOG_TYPE {
69 HW, 69 HW,
70 TIME, 70 TIME,
71 NETPLAY, 71 NETPLAY,
72 GUI,
72 73
73 NUMBER_OF_LOGS // Must be last 74 NUMBER_OF_LOGS // Must be last
74}; 75};
@@ -88,7 +89,7 @@ enum LOG_LEVELS {
88 89
89} // namespace 90} // namespace
90 91
91void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int line, 92void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int line,
92 const char* function, const char* fmt, ...) 93 const char* function, const char* fmt, ...)
93#ifdef __GNUC__ 94#ifdef __GNUC__
94 __attribute__((format(printf, 6, 7))) 95 __attribute__((format(printf, 6, 7)))
diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp
index 4d590d98f..2ef7d98c0 100644
--- a/src/common/log_manager.cpp
+++ b/src/common/log_manager.cpp
@@ -7,9 +7,8 @@
7#include "common/log_manager.h" 7#include "common/log_manager.h"
8#include "common/console_listener.h" 8#include "common/console_listener.h"
9#include "common/timer.h" 9#include "common/timer.h"
10#include "common/thread.h"
11 10
12void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, 11void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,
13 const char* function, const char* fmt, ...) 12 const char* function, const char* fmt, ...)
14{ 13{
15 va_list args; 14 va_list args;
@@ -75,6 +74,7 @@ LogManager::LogManager()
75 m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay"); 74 m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay");
76 m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager"); 75 m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager");
77 m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay"); 76 m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay");
77 m_Log[LogTypes::GUI] = new LogContainer("GUI", "GUI");
78 78
79 m_fileLog = new FileLogListener(FileUtil::GetUserPath(F_MAINLOG_IDX).c_str()); 79 m_fileLog = new FileLogListener(FileUtil::GetUserPath(F_MAINLOG_IDX).c_str());
80 m_consoleLog = new ConsoleListener(); 80 m_consoleLog = new ConsoleListener();
@@ -111,7 +111,7 @@ LogManager::~LogManager()
111 delete m_debuggerLog; 111 delete m_debuggerLog;
112} 112}
113 113
114void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, 114void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file,
115 int line, const char* function, const char *fmt, va_list args) 115 int line, const char* function, const char *fmt, va_list args)
116{ 116{
117 char temp[MAX_MSGLEN]; 117 char temp[MAX_MSGLEN];
@@ -124,11 +124,11 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const
124 Common::CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args); 124 Common::CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args);
125 125
126 static const char level_to_char[7] = "ONEWID"; 126 static const char level_to_char[7] = "ONEWID";
127 sprintf(msg, "%s %s:%u %c[%s] %s: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line, 127 sprintf(msg, "%s %s:%u %c[%s] %s: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line,
128 level_to_char[(int)level], log->GetShortName(), function, temp); 128 level_to_char[(int)level], log->GetShortName(), function, temp);
129 129
130#ifdef ANDROID 130#ifdef ANDROID
131 Host_SysMessage(msg); 131 Host_SysMessage(msg);
132#endif 132#endif
133 log->Trigger(level, msg); 133 log->Trigger(level, msg);
134} 134}
diff --git a/src/common/log_manager.h b/src/common/log_manager.h
index de1d16ee5..baefc4ba8 100644
--- a/src/common/log_manager.h
+++ b/src/common/log_manager.h
@@ -54,7 +54,7 @@ class LogContainer
54{ 54{
55public: 55public:
56 LogContainer(const char* shortName, const char* fullName, bool enable = false); 56 LogContainer(const char* shortName, const char* fullName, bool enable = false);
57 57
58 const char* GetShortName() const { return m_shortName; } 58 const char* GetShortName() const { return m_shortName; }
59 const char* GetFullName() const { return m_fullName; } 59 const char* GetFullName() const { return m_fullName; }
60 60
@@ -98,7 +98,7 @@ public:
98 98
99 static u32 GetMaxLevel() { return LogTypes::MAX_LOGLEVEL; } 99 static u32 GetMaxLevel() { return LogTypes::MAX_LOGLEVEL; }
100 100
101 void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line, 101 void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,
102 const char* function, const char *fmt, va_list args); 102 const char* function, const char *fmt, va_list args);
103 103
104 void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level) 104 void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level)
diff --git a/src/common/math_util.cpp b/src/common/math_util.cpp
index ab0e6b75c..3613e82a6 100644
--- a/src/common/math_util.cpp
+++ b/src/common/math_util.cpp
@@ -18,7 +18,7 @@ u32 ClassifyDouble(double dvalue)
18 value.d = dvalue; 18 value.d = dvalue;
19 u64 sign = value.i & DOUBLE_SIGN; 19 u64 sign = value.i & DOUBLE_SIGN;
20 u64 exp = value.i & DOUBLE_EXP; 20 u64 exp = value.i & DOUBLE_EXP;
21 if (exp > DOUBLE_ZERO && exp < DOUBLE_EXP) 21 if (exp > DOUBLE_ZERO && exp < DOUBLE_EXP)
22 { 22 {
23 // Nice normalized number. 23 // Nice normalized number.
24 return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN; 24 return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN;
@@ -58,7 +58,7 @@ u32 ClassifyFloat(float fvalue)
58 value.f = fvalue; 58 value.f = fvalue;
59 u32 sign = value.i & FLOAT_SIGN; 59 u32 sign = value.i & FLOAT_SIGN;
60 u32 exp = value.i & FLOAT_EXP; 60 u32 exp = value.i & FLOAT_EXP;
61 if (exp > FLOAT_ZERO && exp < FLOAT_EXP) 61 if (exp > FLOAT_ZERO && exp < FLOAT_EXP)
62 { 62 {
63 // Nice normalized number. 63 // Nice normalized number.
64 return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN; 64 return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN;
@@ -77,13 +77,13 @@ u32 ClassifyFloat(float fvalue)
77 // Denormalized number. 77 // Denormalized number.
78 return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD; 78 return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD;
79 } 79 }
80 } 80 }
81 else if (exp) 81 else if (exp)
82 { 82 {
83 // Infinite 83 // Infinite
84 return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF; 84 return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF;
85 } 85 }
86 else 86 else
87 { 87 {
88 //Zero 88 //Zero
89 return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ; 89 return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ;
@@ -143,7 +143,7 @@ void Matrix33::RotateY(Matrix33 &mtx, float rad)
143 mtx.data[0] = c; 143 mtx.data[0] = c;
144 mtx.data[2] = s; 144 mtx.data[2] = s;
145 mtx.data[4] = 1; 145 mtx.data[4] = 1;
146 mtx.data[6] = -s; 146 mtx.data[6] = -s;
147 mtx.data[8] = c; 147 mtx.data[8] = c;
148} 148}
149 149
diff --git a/src/common/math_util.h b/src/common/math_util.h
index b32e7bb14..b10a25c13 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -7,6 +7,7 @@
7#include "common/common.h" 7#include "common/common.h"
8 8
9#include <algorithm> 9#include <algorithm>
10#include <type_traits>
10#include <vector> 11#include <vector>
11 12
12namespace MathUtil 13namespace MathUtil
@@ -109,11 +110,11 @@ struct Rectangle
109 Rectangle(T theLeft, T theTop, T theRight, T theBottom) 110 Rectangle(T theLeft, T theTop, T theRight, T theBottom)
110 : left(theLeft), top(theTop), right(theRight), bottom(theBottom) 111 : left(theLeft), top(theTop), right(theRight), bottom(theBottom)
111 { } 112 { }
112 113
113 bool operator==(const Rectangle& r) { return left==r.left && top==r.top && right==r.right && bottom==r.bottom; } 114 bool operator==(const Rectangle& r) { return left==r.left && top==r.top && right==r.right && bottom==r.bottom; }
114 115
115 T GetWidth() const { return abs(right - left); } 116 T GetWidth() const { return std::abs(static_cast<typename std::make_signed<T>::type>(right - left)); }
116 T GetHeight() const { return abs(bottom - top); } 117 T GetHeight() const { return std::abs(static_cast<typename std::make_signed<T>::type>(bottom - top)); }
117 118
118 // If the rectangle is in a coordinate system with a lower-left origin, use 119 // If the rectangle is in a coordinate system with a lower-left origin, use
119 // this Clamp. 120 // this Clamp.
@@ -127,7 +128,7 @@ struct Rectangle
127 128
128 // If the rectangle is in a coordinate system with an upper-left origin, 129 // If the rectangle is in a coordinate system with an upper-left origin,
129 // use this Clamp. 130 // use this Clamp.
130 void ClampUL(T x1, T y1, T x2, T y2) 131 void ClampUL(T x1, T y1, T x2, T y2)
131 { 132 {
132 if (left < x1) left = x1; 133 if (left < x1) left = x1;
133 if (right > x2) right = x2; 134 if (right > x2) right = x2;
diff --git a/src/common/mem_arena.cpp b/src/common/mem_arena.cpp
index 40d9c03a2..67dbaf509 100644
--- a/src/common/mem_arena.cpp
+++ b/src/common/mem_arena.cpp
@@ -38,7 +38,7 @@ void* globalbase = NULL;
38// Hopefully this ABI will never change... 38// Hopefully this ABI will never change...
39 39
40 40
41#define ASHMEM_DEVICE "/dev/ashmem" 41#define ASHMEM_DEVICE "/dev/ashmem"
42 42
43/* 43/*
44* ashmem_create_region - creates a new ashmem region and returns the file 44* ashmem_create_region - creates a new ashmem region and returns the file
@@ -272,11 +272,11 @@ u8* MemArena::Find4GBBase()
272 272
273 273
274// yeah, this could also be done in like two bitwise ops... 274// yeah, this could also be done in like two bitwise ops...
275#define SKIP(a_flags, b_flags) 275#define SKIP(a_flags, b_flags)
276// if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY)) 276//if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY))
277// continue; 277// continue;
278// if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM)) 278//if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM))
279// continue; 279// continue;
280 280
281static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 flags, MemArena *arena) { 281static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 flags, MemArena *arena) {
282 // OK, we know where to find free space. Now grab it! 282 // OK, we know where to find free space. Now grab it!
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp
index bab7d9f7a..b6f66e4e1 100644
--- a/src/common/memory_util.cpp
+++ b/src/common/memory_util.cpp
@@ -47,7 +47,7 @@ void* AllocateExecutableMemory(size_t size, bool low)
47 47
48 // printf("Mapped executable memory at %p (size %ld)\n", ptr, 48 // printf("Mapped executable memory at %p (size %ld)\n", ptr,
49 // (unsigned long)size); 49 // (unsigned long)size);
50 50
51#ifdef _WIN32 51#ifdef _WIN32
52 if (ptr == nullptr) 52 if (ptr == nullptr)
53 { 53 {
@@ -55,7 +55,7 @@ void* AllocateExecutableMemory(size_t size, bool low)
55 if (ptr == MAP_FAILED) 55 if (ptr == MAP_FAILED)
56 { 56 {
57 ptr = nullptr; 57 ptr = nullptr;
58#endif 58#endif
59 PanicAlert("Failed to allocate executable memory"); 59 PanicAlert("Failed to allocate executable memory");
60 } 60 }
61#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) 61#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
@@ -127,11 +127,11 @@ void FreeMemoryPages(void* ptr, size_t size)
127 if (ptr) 127 if (ptr)
128 { 128 {
129#ifdef _WIN32 129#ifdef _WIN32
130 130
131 if (!VirtualFree(ptr, 0, MEM_RELEASE)) 131 if (!VirtualFree(ptr, 0, MEM_RELEASE))
132 PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg()); 132 PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg());
133 ptr = NULL; // Is this our responsibility? 133 ptr = NULL; // Is this our responsibility?
134 134
135#else 135#else
136 munmap(ptr, size); 136 munmap(ptr, size);
137#endif 137#endif
diff --git a/src/common/msg_handler.h b/src/common/msg_handler.h
index 7c5319ec3..9bfdf950e 100644
--- a/src/common/msg_handler.h
+++ b/src/common/msg_handler.h
@@ -15,7 +15,7 @@ enum MSG_TYPE
15 CRITICAL 15 CRITICAL
16}; 16};
17 17
18typedef bool (*MsgAlertHandler)(const char* caption, const char* text, 18typedef bool (*MsgAlertHandler)(const char* caption, const char* text,
19 bool yes_no, int Style); 19 bool yes_no, int Style);
20typedef std::string (*StringTranslator)(const char* text); 20typedef std::string (*StringTranslator)(const char* text);
21 21
@@ -31,29 +31,29 @@ void SetEnableAlert(bool enable);
31 31
32#ifndef GEKKO 32#ifndef GEKKO
33#ifdef _WIN32 33#ifdef _WIN32
34 #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) 34 #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__)
35 #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) 35 #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__)
36 #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) 36 #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__)
37 #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) 37 #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__)
38 #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) 38 #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__)
39 // Use these macros (that do the same thing) if the message should be translated. 39 // Use these macros (that do the same thing) if the message should be translated.
40 #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__) 40 #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__)
41 #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__) 41 #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__)
42 #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__) 42 #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__)
43 #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__) 43 #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__)
44 #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__) 44 #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__)
45#else 45#else
46 #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) 46 #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__)
47 #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) 47 #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__)
48 #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) 48 #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__)
49 #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) 49 #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__)
50 #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) 50 #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__)
51 // Use these macros (that do the same thing) if the message should be translated. 51 // Use these macros (that do the same thing) if the message should be translated.
52 #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__) 52 #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__)
53 #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__) 53 #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__)
54 #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__) 54 #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__)
55 #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__) 55 #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__)
56 #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__) 56 #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__)
57#endif 57#endif
58#else 58#else
59// GEKKO 59// GEKKO
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 54943d306..dcec9275f 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -121,11 +121,11 @@ std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces)
121{ 121{
122 std::ostringstream oss; 122 std::ostringstream oss;
123 oss << std::setfill('0') << std::hex; 123 oss << std::setfill('0') << std::hex;
124 124
125 for (int line = 0; size; ++data, --size) 125 for (int line = 0; size; ++data, --size)
126 { 126 {
127 oss << std::setw(2) << (int)*data; 127 oss << std::setw(2) << (int)*data;
128 128
129 if (line_len == ++line) 129 if (line_len == ++line)
130 { 130 {
131 oss << '\n'; 131 oss << '\n';
@@ -168,7 +168,7 @@ bool TryParse(const std::string &str, u32 *const output)
168 errno = 0; 168 errno = 0;
169 169
170 unsigned long value = strtoul(str.c_str(), &endptr, 0); 170 unsigned long value = strtoul(str.c_str(), &endptr, 0);
171 171
172 if (!endptr || *endptr) 172 if (!endptr || *endptr)
173 return false; 173 return false;
174 174
@@ -294,7 +294,7 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
294//#include <string> 294//#include <string>
295//#include <assert.h> 295//#include <assert.h>
296 296
297const char HEX2DEC[256] = 297const char HEX2DEC[256] =
298{ 298{
299 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ 299 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
300 /* 0 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16, 300 /* 0 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
@@ -327,7 +327,7 @@ std::string UriDecode(const std::string & sSrc)
327 const unsigned char * pSrc = (const unsigned char *)sSrc.c_str(); 327 const unsigned char * pSrc = (const unsigned char *)sSrc.c_str();
328 const size_t SRC_LEN = sSrc.length(); 328 const size_t SRC_LEN = sSrc.length();
329 const unsigned char * const SRC_END = pSrc + SRC_LEN; 329 const unsigned char * const SRC_END = pSrc + SRC_LEN;
330 const unsigned char * const SRC_LAST_DEC = SRC_END - 2; // last decodable '%' 330 const unsigned char * const SRC_LAST_DEC = SRC_END - 2; // last decodable '%'
331 331
332 char * const pStart = new char[SRC_LEN]; 332 char * const pStart = new char[SRC_LEN];
333 char * pEnd = pStart; 333 char * pEnd = pStart;
@@ -394,7 +394,7 @@ std::string UriEncode(const std::string & sSrc)
394 394
395 for (; pSrc < SRC_END; ++pSrc) 395 for (; pSrc < SRC_END; ++pSrc)
396 { 396 {
397 if (SAFE[*pSrc]) 397 if (SAFE[*pSrc])
398 *pEnd++ = *pSrc; 398 *pEnd++ = *pSrc;
399 else 399 else
400 { 400 {
@@ -518,9 +518,9 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>&
518 518
519 out_buffer.resize(out_buffer_size - dst_bytes); 519 out_buffer.resize(out_buffer_size - dst_bytes);
520 out_buffer.swap(result); 520 out_buffer.swap(result);
521 521
522 iconv_close(conv_desc); 522 iconv_close(conv_desc);
523 523
524 return result; 524 return result;
525} 525}
526 526
@@ -576,7 +576,7 @@ std::u16string UTF8ToUTF16(const std::string& input)
576 out_buffer.swap(result); 576 out_buffer.swap(result);
577 577
578 iconv_close(conv_desc); 578 iconv_close(conv_desc);
579 579
580 return result; 580 return result;
581} 581}
582 582
diff --git a/src/common/string_util.h b/src/common/string_util.h
index 787a5663f..ae5bbadad 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -63,7 +63,7 @@ template <typename N>
63static bool TryParse(const std::string &str, N *const output) 63static bool TryParse(const std::string &str, N *const output)
64{ 64{
65 std::istringstream iss(str); 65 std::istringstream iss(str);
66 66
67 N tmp = 0; 67 N tmp = 0;
68 if (iss >> tmp) 68 if (iss >> tmp)
69 { 69 {
diff --git a/src/common/symbols.cpp b/src/common/symbols.cpp
index d61f4c0c6..63ad6218b 100644
--- a/src/common/symbols.cpp
+++ b/src/common/symbols.cpp
@@ -31,7 +31,7 @@ namespace Symbols
31 { 31 {
32 TSymbolsMap::iterator foundSymbolItr; 32 TSymbolsMap::iterator foundSymbolItr;
33 TSymbol symbol; 33 TSymbol symbol;
34 34
35 foundSymbolItr = g_symbols.find(_address); 35 foundSymbolItr = g_symbols.find(_address);
36 if (foundSymbolItr != g_symbols.end()) 36 if (foundSymbolItr != g_symbols.end())
37 { 37 {
@@ -44,7 +44,7 @@ namespace Symbols
44 { 44 {
45 return GetSymbol(_address).name; 45 return GetSymbol(_address).name;
46 } 46 }
47 47
48 void Remove(u32 _address) 48 void Remove(u32 _address)
49 { 49 {
50 g_symbols.erase(_address); 50 g_symbols.erase(_address);
diff --git a/src/common/symbols.h b/src/common/symbols.h
index b13a8001a..4560f5240 100644
--- a/src/common/symbols.h
+++ b/src/common/symbols.h
@@ -33,5 +33,5 @@ namespace Symbols
33 const std::string GetName(u32 _address); 33 const std::string GetName(u32 _address);
34 void Remove(u32 _address); 34 void Remove(u32 _address);
35 void Clear(); 35 void Clear();
36}; 36}
37 37
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 60d8ed075..dc153ba71 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -25,7 +25,7 @@ int CurrentThreadId()
25 return 0; 25 return 0;
26#endif 26#endif
27} 27}
28 28
29#ifdef _WIN32 29#ifdef _WIN32
30 30
31void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) 31void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
@@ -52,7 +52,7 @@ void SwitchCurrentThread()
52// Sets the debugger-visible name of the current thread. 52// Sets the debugger-visible name of the current thread.
53// Uses undocumented (actually, it is now documented) trick. 53// Uses undocumented (actually, it is now documented) trick.
54// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp 54// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp
55 55
56// This is implemented much nicer in upcoming msvc++, see: 56// This is implemented much nicer in upcoming msvc++, see:
57// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx 57// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx
58void SetCurrentThreadName(const char* szThreadName) 58void SetCurrentThreadName(const char* szThreadName)
@@ -81,7 +81,7 @@ void SetCurrentThreadName(const char* szThreadName)
81 __except(EXCEPTION_CONTINUE_EXECUTION) 81 __except(EXCEPTION_CONTINUE_EXECUTION)
82 {} 82 {}
83} 83}
84 84
85#else // !WIN32, so must be POSIX threads 85#else // !WIN32, so must be POSIX threads
86 86
87void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) 87void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
diff --git a/src/common/thread.h b/src/common/thread.h
index f7ace21b4..be9b5cbe2 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -30,13 +30,13 @@ int CurrentThreadId();
30 30
31void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask); 31void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
32void SetCurrentThreadAffinity(u32 mask); 32void SetCurrentThreadAffinity(u32 mask);
33 33
34class Event 34class Event
35{ 35{
36public: 36public:
37 Event() 37 Event()
38 : is_set(false) 38 : is_set(false)
39 {}; 39 {}
40 40
41 void Set() 41 void Set()
42 { 42 {
@@ -135,7 +135,7 @@ private:
135 const size_t m_count; 135 const size_t m_count;
136 volatile size_t m_waiting; 136 volatile size_t m_waiting;
137}; 137};
138 138
139void SleepCurrentThread(int ms); 139void SleepCurrentThread(int ms);
140void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms 140void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
141 141
@@ -146,7 +146,7 @@ inline void YieldCPU()
146{ 146{
147 std::this_thread::yield(); 147 std::this_thread::yield();
148} 148}
149 149
150void SetCurrentThreadName(const char *name); 150void SetCurrentThreadName(const char *name);
151 151
152} // namespace Common 152} // namespace Common
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
index 4a89572f6..59efbce4c 100644
--- a/src/common/thread_queue_list.h
+++ b/src/common/thread_queue_list.h
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project / PPSSPP Project 1// Copyright 2014 Citra Emulator Project / PPSSPP Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
@@ -12,7 +12,7 @@ template<class IdType>
12struct ThreadQueueList { 12struct ThreadQueueList {
13 // Number of queues (number of priority levels starting at 0.) 13 // Number of queues (number of priority levels starting at 0.)
14 static const int NUM_QUEUES = 128; 14 static const int NUM_QUEUES = 128;
15 15
16 // Initial number of threads a single queue can handle. 16 // Initial number of threads a single queue can handle.
17 static const int INITIAL_CAPACITY = 32; 17 static const int INITIAL_CAPACITY = 32;
18 18
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index f41d52e80..48241c3d4 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -31,17 +31,24 @@ set(SRCS
31 hle/kernel/shared_memory.cpp 31 hle/kernel/shared_memory.cpp
32 hle/kernel/thread.cpp 32 hle/kernel/thread.cpp
33 hle/service/ac_u.cpp 33 hle/service/ac_u.cpp
34 hle/service/am_net.cpp
34 hle/service/apt_u.cpp 35 hle/service/apt_u.cpp
36 hle/service/boss_u.cpp
37 hle/service/cfg_i.cpp
35 hle/service/cfg_u.cpp 38 hle/service/cfg_u.cpp
39 hle/service/csnd_snd.cpp
36 hle/service/dsp_dsp.cpp 40 hle/service/dsp_dsp.cpp
37 hle/service/err_f.cpp 41 hle/service/err_f.cpp
38 hle/service/fs_user.cpp 42 hle/service/fs_user.cpp
39 hle/service/frd_u.cpp 43 hle/service/frd_u.cpp
40 hle/service/gsp_gpu.cpp 44 hle/service/gsp_gpu.cpp
41 hle/service/hid_user.cpp 45 hle/service/hid_user.cpp
46 hle/service/ir_rst.cpp
47 hle/service/ir_u.cpp
42 hle/service/mic_u.cpp 48 hle/service/mic_u.cpp
43 hle/service/ndm_u.cpp 49 hle/service/ndm_u.cpp
44 hle/service/nwm_uds.cpp 50 hle/service/nwm_uds.cpp
51 hle/service/pm_app.cpp
45 hle/service/ptm_u.cpp 52 hle/service/ptm_u.cpp
46 hle/service/service.cpp 53 hle/service/service.cpp
47 hle/service/soc_u.cpp 54 hle/service/soc_u.cpp
@@ -102,23 +109,31 @@ set(HEADERS
102 hle/kernel/shared_memory.h 109 hle/kernel/shared_memory.h
103 hle/kernel/thread.h 110 hle/kernel/thread.h
104 hle/service/ac_u.h 111 hle/service/ac_u.h
112 hle/service/am_net.h
105 hle/service/apt_u.h 113 hle/service/apt_u.h
114 hle/service/boss_u.h
115 hle/service/cfg_i.h
106 hle/service/cfg_u.h 116 hle/service/cfg_u.h
117 hle/service/csnd_snd.h
107 hle/service/dsp_dsp.h 118 hle/service/dsp_dsp.h
108 hle/service/err_f.h 119 hle/service/err_f.h
109 hle/service/fs_user.h 120 hle/service/fs_user.h
110 hle/service/frd_u.h 121 hle/service/frd_u.h
111 hle/service/gsp_gpu.h 122 hle/service/gsp_gpu.h
112 hle/service/hid_user.h 123 hle/service/hid_user.h
124 hle/service/ir_rst.h
125 hle/service/ir_u.h
113 hle/service/mic_u.h 126 hle/service/mic_u.h
114 hle/service/ndm_u.h 127 hle/service/ndm_u.h
115 hle/service/nwm_uds.h 128 hle/service/nwm_uds.h
129 hle/service/pm_app.h
116 hle/service/ptm_u.h 130 hle/service/ptm_u.h
117 hle/service/service.h 131 hle/service/service.h
118 hle/service/soc_u.h 132 hle/service/soc_u.h
119 hle/service/srv.h 133 hle/service/srv.h
120 hle/service/ssl_c.h 134 hle/service/ssl_c.h
121 hle/config_mem.h 135 hle/config_mem.h
136 hle/result.h
122 hle/function_wrappers.h 137 hle/function_wrappers.h
123 hle/hle.h 138 hle/hle.h
124 hle/svc.h 139 hle/svc.h
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 4b93d3313..3ae528562 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
@@ -63,7 +63,7 @@ public:
63 * Get the current CPSR register 63 * Get the current CPSR register
64 * @return Returns the value of the CPSR register 64 * @return Returns the value of the CPSR register
65 */ 65 */
66 virtual u32 GetCPSR() const = 0; 66 virtual u32 GetCPSR() const = 0;
67 67
68 /** 68 /**
69 * Set the current CPSR register 69 * Set the current CPSR register
@@ -98,7 +98,7 @@ public:
98 } 98 }
99 99
100protected: 100protected:
101 101
102 /** 102 /**
103 * Executes the given number of instructions 103 * Executes the given number of instructions
104 * @param num_instructions Number of instructions to executes 104 * @param num_instructions Number of instructions to executes
diff --git a/src/core/arm/disassembler/load_symbol_map.cpp b/src/core/arm/disassembler/load_symbol_map.cpp
index 0f384ad3e..55278474b 100644
--- a/src/core/arm/disassembler/load_symbol_map.cpp
+++ b/src/core/arm/disassembler/load_symbol_map.cpp
@@ -22,8 +22,8 @@ void LoadSymbolMap(std::string filename) {
22 22
23 while (std::getline(infile, line)) { 23 while (std::getline(infile, line)) {
24 std::istringstream iss(line); 24 std::istringstream iss(line);
25 if (!(iss >> address_str >> size >> function_name)) { 25 if (!(iss >> address_str >> size >> function_name)) {
26 break; // Error parsing 26 break; // Error parsing
27 } 27 }
28 u32 address = std::stoul(address_str, nullptr, 16); 28 u32 address = std::stoul(address_str, nullptr, 16);
29 29
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index a3ed3e31e..6c8ea211e 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/arm/skyeye_common/armcpu.h" 5#include "core/arm/skyeye_common/armcpu.h"
6#include "core/arm/skyeye_common/armemu.h" 6#include "core/arm/skyeye_common/armemu.h"
@@ -113,7 +113,7 @@ void ARM_DynCom::ExecuteInstructions(int num_instructions) {
113 state->NumInstrsToExecute = num_instructions; 113 state->NumInstrsToExecute = num_instructions;
114 114
115 // Dyncom only breaks on instruction dispatch. This only happens on every instruction when 115 // Dyncom only breaks on instruction dispatch. This only happens on every instruction when
116 // executing one instruction at a time. Otherwise, if a block is being executed, more 116 // executing one instruction at a time. Otherwise, if a block is being executed, more
117 // instructions may actually be executed than specified. 117 // instructions may actually be executed than specified.
118 ticks += InterpreterMainLoop(state.get()); 118 ticks += InterpreterMainLoop(state.get());
119} 119}
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index 1f8cd3a3a..51eea41ed 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
@@ -19,7 +19,7 @@ public:
19 19
20 /** 20 /**
21 * Set the Program Counter to an address 21 * Set the Program Counter to an address
22 * @param addr Address to set PC to 22 * @param pc Address to set PC to
23 */ 23 */
24 void SetPC(u32 pc) override; 24 void SetPC(u32 pc) override;
25 25
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index f899e2e8a..233cd3e3a 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -26,7 +26,7 @@
26#define CITRA_IGNORE_EXIT(x) 26#define CITRA_IGNORE_EXIT(x)
27 27
28#include <algorithm> 28#include <algorithm>
29#include <map> 29#include <unordered_map>
30#include <stdio.h> 30#include <stdio.h>
31#include <assert.h> 31#include <assert.h>
32#include <cstdio> 32#include <cstdio>
@@ -94,9 +94,8 @@ typedef unsigned int (*shtop_fp_t)(arm_processor *cpu, unsigned int sht_oper);
94 94
95/* exclusive memory access */ 95/* exclusive memory access */
96static int exclusive_detect(ARMul_State* state, ARMword addr){ 96static int exclusive_detect(ARMul_State* state, ARMword addr){
97 int i;
98 #if 0 97 #if 0
99 for(i = 0; i < 128; i++){ 98 for(int i = 0; i < 128; i++){
100 if(state->exclusive_tag_array[i] == addr) 99 if(state->exclusive_tag_array[i] == addr)
101 return 0; 100 return 0;
102 } 101 }
@@ -108,9 +107,8 @@ static int exclusive_detect(ARMul_State* state, ARMword addr){
108} 107}
109 108
110static void add_exclusive_addr(ARMul_State* state, ARMword addr){ 109static void add_exclusive_addr(ARMul_State* state, ARMword addr){
111 int i;
112 #if 0 110 #if 0
113 for(i = 0; i < 128; i++){ 111 for(int i = 0; i < 128; i++){
114 if(state->exclusive_tag_array[i] == 0xffffffff){ 112 if(state->exclusive_tag_array[i] == 0xffffffff){
115 state->exclusive_tag_array[i] = addr; 113 state->exclusive_tag_array[i] = addr;
116 //DEBUG_LOG(ARM11, "In %s, add addr 0x%x\n", __func__, addr); 114 //DEBUG_LOG(ARM11, "In %s, add addr 0x%x\n", __func__, addr);
@@ -3309,9 +3307,8 @@ const transop_fp_t arm_instruction_trans[] = {
3309 INTERPRETER_TRANSLATE(blx_1_thumb) 3307 INTERPRETER_TRANSLATE(blx_1_thumb)
3310}; 3308};
3311 3309
3312typedef map<unsigned int, int> bb_map; 3310typedef std::unordered_map<u32, int> bb_map;
3313bb_map CreamCache[65536]; 3311bb_map CreamCache;
3314bb_map ProfileCache[65536];
3315 3312
3316//#define USE_DUMMY_CACHE 3313//#define USE_DUMMY_CACHE
3317 3314
@@ -3319,14 +3316,12 @@ bb_map ProfileCache[65536];
3319unsigned int DummyCache[0x100000]; 3316unsigned int DummyCache[0x100000];
3320#endif 3317#endif
3321 3318
3322#define HASH(x) ((x + (x << 3) + (x >> 6)) % 65536)
3323void insert_bb(unsigned int addr, int start) 3319void insert_bb(unsigned int addr, int start)
3324{ 3320{
3325#ifdef USE_DUMMY_CACHE 3321#ifdef USE_DUMMY_CACHE
3326 DummyCache[addr] = start; 3322 DummyCache[addr] = start;
3327#else 3323#else
3328// CreamCache[addr] = start; 3324 CreamCache[addr] = start;
3329 CreamCache[HASH(addr)][addr] = start;
3330#endif 3325#endif
3331} 3326}
3332 3327
@@ -3341,8 +3336,8 @@ int find_bb(unsigned int addr, int &start)
3341 } else 3336 } else
3342 ret = -1; 3337 ret = -1;
3343#else 3338#else
3344 bb_map::const_iterator it = CreamCache[HASH(addr)].find(addr); 3339 bb_map::const_iterator it = CreamCache.find(addr);
3345 if (it != CreamCache[HASH(addr)].end()) { 3340 if (it != CreamCache.end()) {
3346 start = static_cast<int>(it->second); 3341 start = static_cast<int>(it->second);
3347 ret = 0; 3342 ret = 0;
3348#if HYBRID_MODE 3343#if HYBRID_MODE
@@ -3473,30 +3468,15 @@ void flush_bb(uint32_t addr)
3473 uint32_t start; 3468 uint32_t start;
3474 3469
3475 addr &= 0xfffff000; 3470 addr &= 0xfffff000;
3476 for (int i = 0; i < 65536; i ++) { 3471 for (it = CreamCache.begin(); it != CreamCache.end(); ) {
3477 for (it = CreamCache[i].begin(); it != CreamCache[i].end(); ) { 3472 start = static_cast<uint32_t>(it->first);
3478 start = static_cast<uint32_t>(it->first); 3473 //start = (start >> 12) << 12;
3479 //start = (start >> 12) << 12; 3474 start &= 0xfffff000;
3480 start &= 0xfffff000; 3475 if (start == addr) {
3481 if (start == addr) { 3476 //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first));
3482 //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first)); 3477 CreamCache.erase(it++);
3483 CreamCache[i].erase(it ++); 3478 } else
3484 } else 3479 ++it;
3485 ++it;
3486 }
3487 }
3488
3489 for (int i = 0; i < 65536; i ++) {
3490 for (it = ProfileCache[i].begin(); it != ProfileCache[i].end(); ) {
3491 start = static_cast<uint32_t>(it->first);
3492 //start = (start >> 12) << 12;
3493 start &= 0xfffff000;
3494 if (start == addr) {
3495 //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first));
3496 ProfileCache[i].erase(it ++);
3497 } else
3498 ++it;
3499 }
3500 } 3480 }
3501 3481
3502 //DEBUG_LOG(ARM11, "flush bb @ %x\n", addr); 3482 //DEBUG_LOG(ARM11, "flush bb @ %x\n", addr);
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.h b/src/core/arm/dyncom/arm_dyncom_interpreter.h
index c65eb23f7..3a2462f55 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.h
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.h
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp
index ed4415082..e2aa5ce92 100644
--- a/src/core/arm/interpreter/arm_interpreter.cpp
+++ b/src/core/arm/interpreter/arm_interpreter.cpp
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/arm/interpreter/arm_interpreter.h" 5#include "core/arm/interpreter/arm_interpreter.h"
6 6
@@ -24,7 +24,7 @@ ARM_Interpreter::ARM_Interpreter() {
24 state->lateabtSig = LOW; 24 state->lateabtSig = LOW;
25 25
26 // Reset the core to initial state 26 // Reset the core to initial state
27 ARMul_CoProInit(state); 27 ARMul_CoProInit(state);
28 ARMul_Reset(state); 28 ARMul_Reset(state);
29 state->NextInstr = RESUME; // NOTE: This will be overwritten by LoadContext 29 state->NextInstr = RESUME; // NOTE: This will be overwritten by LoadContext
30 state->Emulate = 3; 30 state->Emulate = 3;
diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h
index ceb1be438..ed53d997c 100644
--- a/src/core/arm/interpreter/arm_interpreter.h
+++ b/src/core/arm/interpreter/arm_interpreter.h
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
@@ -18,7 +18,7 @@ public:
18 18
19 /** 19 /**
20 * Set the Program Counter to an address 20 * Set the Program Counter to an address
21 * @param addr Address to set PC to 21 * @param pc Address to set PC to
22 */ 22 */
23 void SetPC(u32 pc) override; 23 void SetPC(u32 pc) override;
24 24
diff --git a/src/core/arm/skyeye_common/armcpu.h b/src/core/arm/skyeye_common/armcpu.h
index 3a029f0e7..2b756c5bc 100644
--- a/src/core/arm/skyeye_common/armcpu.h
+++ b/src/core/arm/skyeye_common/armcpu.h
@@ -24,8 +24,6 @@
24#include <stddef.h> 24#include <stddef.h>
25#include <stdio.h> 25#include <stdio.h>
26 26
27#include "common/thread.h"
28
29#include "core/arm/skyeye_common/armdefs.h" 27#include "core/arm/skyeye_common/armdefs.h"
30 28
31typedef struct ARM_CPU_State_s { 29typedef struct ARM_CPU_State_s {
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h
index 8e71948c6..8343aaa01 100644
--- a/src/core/arm/skyeye_common/armdefs.h
+++ b/src/core/arm/skyeye_common/armdefs.h
@@ -799,22 +799,24 @@ pascal void SpinCursor (short increment); /* copied from CursorCtl.h */
799#include "list.h" 799#include "list.h"
800#include "tb.h" 800#include "tb.h"
801*/ 801*/
802#define EQ 0 802enum ConditionCode {
803#define NE 1 803 EQ = 0,
804#define CS 2 804 NE = 1,
805#define CC 3 805 CS = 2,
806#define MI 4 806 CC = 3,
807#define PL 5 807 MI = 4,
808#define VS 6 808 PL = 5,
809#define VC 7 809 VS = 6,
810#define HI 8 810 VC = 7,
811#define LS 9 811 HI = 8,
812#define GE 10 812 LS = 9,
813#define LT 11 813 GE = 10,
814#define GT 12 814 LT = 11,
815#define LE 13 815 GT = 12,
816#define AL 14 816 LE = 13,
817#define NV 15 817 AL = 14,
818 NV = 15,
819};
818 820
819#ifndef NFLAG 821#ifndef NFLAG
820#define NFLAG state->NFlag 822#define NFLAG state->NFlag
diff --git a/src/core/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h
index c0f0270fe..075fc7e9e 100644
--- a/src/core/arm/skyeye_common/armemu.h
+++ b/src/core/arm/skyeye_common/armemu.h
@@ -25,24 +25,6 @@
25 25
26#define DEBUG(...) DEBUG_LOG(ARM11, __VA_ARGS__) 26#define DEBUG(...) DEBUG_LOG(ARM11, __VA_ARGS__)
27 27
28/* Condition code values. */
29#define EQ 0
30#define NE 1
31#define CS 2
32#define CC 3
33#define MI 4
34#define PL 5
35#define VS 6
36#define VC 7
37#define HI 8
38#define LS 9
39#define GE 10
40#define LT 11
41#define GT 12
42#define LE 13
43#define AL 14
44#define NV 15
45
46/* Shift Opcodes. */ 28/* Shift Opcodes. */
47#define LSL 0 29#define LSL 0
48#define LSR 1 30#define LSR 1
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 25c78d33c..865898b24 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -16,10 +16,10 @@
16 16
17namespace Core { 17namespace Core {
18 18
19u64 g_last_ticks = 0; ///< Last CPU ticks 19static u64 last_ticks = 0; ///< Last CPU ticks
20ARM_Disasm* g_disasm = nullptr; ///< ARM disassembler 20static ARM_Disasm* disasm = nullptr; ///< ARM disassembler
21ARM_Interface* g_app_core = nullptr; ///< ARM11 application core 21ARM_Interface* g_app_core = nullptr; ///< ARM11 application core
22ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core 22ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core
23 23
24/// Run the core CPU loop 24/// Run the core CPU loop
25void RunLoop(int tight_loop) { 25void RunLoop(int tight_loop) {
@@ -49,7 +49,7 @@ void Stop() {
49int Init() { 49int Init() {
50 NOTICE_LOG(MASTER_LOG, "initialized OK"); 50 NOTICE_LOG(MASTER_LOG, "initialized OK");
51 51
52 g_disasm = new ARM_Disasm(); 52 disasm = new ARM_Disasm();
53 g_sys_core = new ARM_Interpreter(); 53 g_sys_core = new ARM_Interpreter();
54 54
55 switch (Settings::values.cpu_core) { 55 switch (Settings::values.cpu_core) {
@@ -62,13 +62,13 @@ int Init() {
62 break; 62 break;
63 } 63 }
64 64
65 g_last_ticks = Core::g_app_core->GetTicks(); 65 last_ticks = Core::g_app_core->GetTicks();
66 66
67 return 0; 67 return 0;
68} 68}
69 69
70void Shutdown() { 70void Shutdown() {
71 delete g_disasm; 71 delete disasm;
72 delete g_app_core; 72 delete g_app_core;
73 delete g_sys_core; 73 delete g_sys_core;
74 74
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 0116cb376..558c6cbf7 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -41,7 +41,7 @@ struct BaseEvent
41 s64 time; 41 s64 time;
42 u64 userdata; 42 u64 userdata;
43 int type; 43 int type;
44 // Event *next; 44 // Event *next;
45}; 45};
46 46
47typedef LinkedListItem<BaseEvent> Event; 47typedef LinkedListItem<BaseEvent> Event;
@@ -249,7 +249,7 @@ void AddEventToQueue(Event* ne)
249 249
250// This must be run ONLY from within the cpu thread 250// This must be run ONLY from within the cpu thread
251// cyclesIntoFuture may be VERY inaccurate if called from anything else 251// cyclesIntoFuture may be VERY inaccurate if called from anything else
252// than Advance 252// than Advance
253void ScheduleEvent(s64 cyclesIntoFuture, int event_type, u64 userdata) 253void ScheduleEvent(s64 cyclesIntoFuture, int event_type, u64 userdata)
254{ 254{
255 Event *ne = GetNewEvent(); 255 Event *ne = GetNewEvent();
@@ -469,8 +469,8 @@ void ProcessFifoWaitEvents()
469 { 469 {
470 if (first->time <= globalTimer) 470 if (first->time <= globalTimer)
471 { 471 {
472 // LOG(TIMER, "[Scheduler] %s (%lld, %lld) ", 472 //LOG(TIMER, "[Scheduler] %s (%lld, %lld) ",
473 // first->name ? first->name : "?", (u64)globalTimer, (u64)first->time); 473 // first->name ? first->name : "?", (u64)globalTimer, (u64)first->time);
474 Event* evt = first; 474 Event* evt = first;
475 first = first->next; 475 first = first->next;
476 event_types[evt->type].callback(evt->userdata, (int)(globalTimer - evt->time)); 476 event_types[evt->type].callback(evt->userdata, (int)(globalTimer - evt->time));
@@ -516,23 +516,23 @@ void Advance()
516 //currentMIPS->downcount = slicelength; 516 //currentMIPS->downcount = slicelength;
517 517
518 //if (Common::AtomicLoadAcquire(hasTsEvents)) 518 //if (Common::AtomicLoadAcquire(hasTsEvents))
519 // MoveEvents(); 519 // MoveEvents();
520 //ProcessFifoWaitEvents(); 520 //ProcessFifoWaitEvents();
521 521
522 //if (!first) 522 //if (!first)
523 //{ 523 //{
524 // // WARN_LOG(TIMER, "WARNING - no events in queue. Setting currentMIPS->downcount to 10000"); 524 // // WARN_LOG(TIMER, "WARNING - no events in queue. Setting currentMIPS->downcount to 10000");
525 // currentMIPS->downcount += 10000; 525 // currentMIPS->downcount += 10000;
526 //} 526 //}
527 //else 527 //else
528 //{ 528 //{
529 // slicelength = (int)(first->time - globalTimer); 529 // slicelength = (int)(first->time - globalTimer);
530 // if (slicelength > MAX_SLICE_LENGTH) 530 // if (slicelength > MAX_SLICE_LENGTH)
531 // slicelength = MAX_SLICE_LENGTH; 531 // slicelength = MAX_SLICE_LENGTH;
532 // currentMIPS->downcount = slicelength; 532 // currentMIPS->downcount = slicelength;
533 //} 533 //}
534 //if (advanceCallback) 534 //if (advanceCallback)
535 // advanceCallback(cyclesExecuted); 535 // advanceCallback(cyclesExecuted);
536} 536}
537 537
538void LogPendingEvents() 538void LogPendingEvents()
@@ -550,20 +550,20 @@ void Idle(int maxIdle)
550 ERROR_LOG(TIME, "Unimplemented function!"); 550 ERROR_LOG(TIME, "Unimplemented function!");
551 //int cyclesDown = currentMIPS->downcount; 551 //int cyclesDown = currentMIPS->downcount;
552 //if (maxIdle != 0 && cyclesDown > maxIdle) 552 //if (maxIdle != 0 && cyclesDown > maxIdle)
553 // cyclesDown = maxIdle; 553 // cyclesDown = maxIdle;
554 554
555 //if (first && cyclesDown > 0) 555 //if (first && cyclesDown > 0)
556 //{ 556 //{
557 // int cyclesExecuted = slicelength - currentMIPS->downcount; 557 // int cyclesExecuted = slicelength - currentMIPS->downcount;
558 // int cyclesNextEvent = (int) (first->time - globalTimer); 558 // int cyclesNextEvent = (int) (first->time - globalTimer);
559 559
560 // if (cyclesNextEvent < cyclesExecuted + cyclesDown) 560 // if (cyclesNextEvent < cyclesExecuted + cyclesDown)
561 // { 561 // {
562 // cyclesDown = cyclesNextEvent - cyclesExecuted; 562 // cyclesDown = cyclesNextEvent - cyclesExecuted;
563 // // Now, now... no time machines, please. 563 // // Now, now... no time machines, please.
564 // if (cyclesDown < 0) 564 // if (cyclesDown < 0)
565 // cyclesDown = 0; 565 // cyclesDown = 0;
566 // } 566 // }
567 //} 567 //}
568 568
569 //INFO_LOG(TIME, "Idle for %i cycles! (%f ms)", cyclesDown, cyclesDown / (float)(g_clock_rate_arm11 * 0.001f)); 569 //INFO_LOG(TIME, "Idle for %i cycles! (%f ms)", cyclesDown, cyclesDown / (float)(g_clock_rate_arm11 * 0.001f));
@@ -571,7 +571,7 @@ void Idle(int maxIdle)
571 //idledCycles += cyclesDown; 571 //idledCycles += cyclesDown;
572 //currentMIPS->downcount -= cyclesDown; 572 //currentMIPS->downcount -= cyclesDown;
573 //if (currentMIPS->downcount == 0) 573 //if (currentMIPS->downcount == 0)
574 // currentMIPS->downcount = -1; 574 // currentMIPS->downcount = -1;
575} 575}
576 576
577std::string GetScheduledEventsSummary() 577std::string GetScheduledEventsSummary()
@@ -623,4 +623,4 @@ void DoState(PointerWrap &p)
623 p.Do(idledCycles); 623 p.Do(idledCycles);
624} 624}
625 625
626} // namespace 626} // namespace
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 09fdf7a90..b197cf40c 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -106,4 +106,4 @@ void SetClockFrequencyMHz(int cpuMhz);
106int GetClockFrequencyMHz(); 106int GetClockFrequencyMHz();
107extern int slicelength; 107extern int slicelength;
108 108
109}; // namespace 109} // namespace
diff --git a/src/core/file_sys/archive.h b/src/core/file_sys/archive.h
index 38145eed8..c2426a153 100644
--- a/src/core/file_sys/archive.h
+++ b/src/core/file_sys/archive.h
@@ -67,6 +67,8 @@ public:
67 u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated. 67 u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated.
68 break; 68 break;
69 } 69 }
70 default:
71 break;
70 } 72 }
71 } 73 }
72 74
@@ -74,6 +76,35 @@ public:
74 return type; 76 return type;
75 } 77 }
76 78
79 /**
80 * Gets the string representation of the path for debugging
81 * @return String representation of the path for debugging
82 */
83 const std::string DebugStr() const {
84 switch (GetType()) {
85 case Invalid:
86 return "[Invalid]";
87 case Empty:
88 return "[Empty]";
89 case Binary:
90 {
91 std::stringstream res;
92 res << "[Binary: ";
93 for (unsigned byte : binary)
94 res << std::hex << std::setw(2) << std::setfill('0') << byte;
95 res << ']';
96 return res.str();
97 }
98 case Char:
99 return "[Char: " + AsString() + ']';
100 case Wchar:
101 return "[Wchar: " + AsString() + ']';
102 default:
103 ERROR_LOG(KERNEL, "LowPathType cannot be converted to string!");
104 return {};
105 }
106 }
107
77 const std::string AsString() const { 108 const std::string AsString() const {
78 switch (GetType()) { 109 switch (GetType()) {
79 case Char: 110 case Char:
@@ -153,21 +184,35 @@ public:
153 * @param mode Mode to open the file with 184 * @param mode Mode to open the file with
154 * @return Opened file, or nullptr 185 * @return Opened file, or nullptr
155 */ 186 */
156 virtual std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const = 0; 187 virtual std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const = 0;
188
189 /**
190 * Delete a file specified by its path
191 * @param path Path relative to the archive
192 * @return Whether the file could be deleted
193 */
194 virtual bool DeleteFile(const FileSys::Path& path) const = 0;
195
196 /**
197 * Delete a directory specified by its path
198 * @param path Path relative to the archive
199 * @return Whether the directory could be deleted
200 */
201 virtual bool DeleteDirectory(const FileSys::Path& path) const = 0;
157 202
158 /** 203 /**
159 * Create a directory specified by its path 204 * Create a directory specified by its path
160 * @param path Path relative to the archive 205 * @param path Path relative to the archive
161 * @return Whether the directory could be created 206 * @return Whether the directory could be created
162 */ 207 */
163 virtual bool CreateDirectory(const std::string& path) const = 0; 208 virtual bool CreateDirectory(const Path& path) const = 0;
164 209
165 /** 210 /**
166 * Open a directory specified by its path 211 * Open a directory specified by its path
167 * @param path Path relative to the archive 212 * @param path Path relative to the archive
168 * @return Opened directory, or nullptr 213 * @return Opened directory, or nullptr
169 */ 214 */
170 virtual std::unique_ptr<Directory> OpenDirectory(const std::string& path) const = 0; 215 virtual std::unique_ptr<Directory> OpenDirectory(const Path& path) const = 0;
171 216
172 /** 217 /**
173 * Read data from the archive 218 * Read data from the archive
@@ -193,7 +238,7 @@ public:
193 * @return Size of the archive in bytes 238 * @return Size of the archive in bytes
194 */ 239 */
195 virtual size_t GetSize() const = 0; 240 virtual size_t GetSize() const = 0;
196 241
197 /** 242 /**
198 * Set the size of the archive in bytes 243 * Set the size of the archive in bytes
199 */ 244 */
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp
index cc759faa8..53dc57954 100644
--- a/src/core/file_sys/archive_romfs.cpp
+++ b/src/core/file_sys/archive_romfs.cpp
@@ -29,26 +29,46 @@ Archive_RomFS::~Archive_RomFS() {
29 * @param mode Mode to open the file with 29 * @param mode Mode to open the file with
30 * @return Opened file, or nullptr 30 * @return Opened file, or nullptr
31 */ 31 */
32std::unique_ptr<File> Archive_RomFS::OpenFile(const std::string& path, const Mode mode) const { 32std::unique_ptr<File> Archive_RomFS::OpenFile(const Path& path, const Mode mode) const {
33 return std::unique_ptr<File>(new File_RomFS); 33 return std::unique_ptr<File>(new File_RomFS);
34} 34}
35 35
36/** 36/**
37 * Delete a file specified by its path
38 * @param path Path relative to the archive
39 * @return Whether the file could be deleted
40 */
41bool Archive_RomFS::DeleteFile(const FileSys::Path& path) const {
42 ERROR_LOG(FILESYS, "Attempted to delete a file from ROMFS.");
43 return false;
44}
45
46/**
47 * Delete a directory specified by its path
48 * @param path Path relative to the archive
49 * @return Whether the directory could be deleted
50 */
51bool Archive_RomFS::DeleteDirectory(const FileSys::Path& path) const {
52 ERROR_LOG(FILESYS, "Attempted to delete a directory from ROMFS.");
53 return false;
54}
55
56/**
37 * Create a directory specified by its path 57 * Create a directory specified by its path
38 * @param path Path relative to the archive 58 * @param path Path relative to the archive
39 * @return Whether the directory could be created 59 * @return Whether the directory could be created
40 */ 60 */
41bool Archive_RomFS::CreateDirectory(const std::string& path) const { 61bool Archive_RomFS::CreateDirectory(const Path& path) const {
42 ERROR_LOG(FILESYS, "Attempted to create a directory in ROMFS."); 62 ERROR_LOG(FILESYS, "Attempted to create a directory in ROMFS.");
43 return false; 63 return false;
44}; 64}
45 65
46/** 66/**
47 * Open a directory specified by its path 67 * Open a directory specified by its path
48 * @param path Path relative to the archive 68 * @param path Path relative to the archive
49 * @return Opened directory, or nullptr 69 * @return Opened directory, or nullptr
50 */ 70 */
51std::unique_ptr<Directory> Archive_RomFS::OpenDirectory(const std::string& path) const { 71std::unique_ptr<Directory> Archive_RomFS::OpenDirectory(const Path& path) const {
52 return std::unique_ptr<Directory>(new Directory_RomFS); 72 return std::unique_ptr<Directory>(new Directory_RomFS);
53} 73}
54 74
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h
index ae2344e82..0649dde99 100644
--- a/src/core/file_sys/archive_romfs.h
+++ b/src/core/file_sys/archive_romfs.h
@@ -26,7 +26,7 @@ public:
26 * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.) 26 * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.)
27 * @return IdCode of the archive 27 * @return IdCode of the archive
28 */ 28 */
29 IdCode GetIdCode() const override { return IdCode::RomFS; }; 29 IdCode GetIdCode() const override { return IdCode::RomFS; }
30 30
31 /** 31 /**
32 * Open a file specified by its path, using the specified mode 32 * Open a file specified by its path, using the specified mode
@@ -34,21 +34,35 @@ public:
34 * @param mode Mode to open the file with 34 * @param mode Mode to open the file with
35 * @return Opened file, or nullptr 35 * @return Opened file, or nullptr
36 */ 36 */
37 std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override; 37 std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const override;
38
39 /**
40 * Delete a file specified by its path
41 * @param path Path relative to the archive
42 * @return Whether the file could be deleted
43 */
44 bool DeleteFile(const FileSys::Path& path) const override;
45
46 /**
47 * Delete a directory specified by its path
48 * @param path Path relative to the archive
49 * @return Whether the directory could be deleted
50 */
51 bool DeleteDirectory(const FileSys::Path& path) const override;
38 52
39 /** 53 /**
40 * Create a directory specified by its path 54 * Create a directory specified by its path
41 * @param path Path relative to the archive 55 * @param path Path relative to the archive
42 * @return Whether the directory could be created 56 * @return Whether the directory could be created
43 */ 57 */
44 bool CreateDirectory(const std::string& path) const override; 58 bool CreateDirectory(const Path& path) const override;
45 59
46 /** 60 /**
47 * Open a directory specified by its path 61 * Open a directory specified by its path
48 * @param path Path relative to the archive 62 * @param path Path relative to the archive
49 * @return Opened directory, or nullptr 63 * @return Opened directory, or nullptr
50 */ 64 */
51 std::unique_ptr<Directory> OpenDirectory(const std::string& path) const override; 65 std::unique_ptr<Directory> OpenDirectory(const Path& path) const override;
52 66
53 /** 67 /**
54 * Read data from the archive 68 * Read data from the archive
@@ -74,7 +88,7 @@ public:
74 * @return Size of the archive in bytes 88 * @return Size of the archive in bytes
75 */ 89 */
76 size_t GetSize() const override; 90 size_t GetSize() const override;
77 91
78 /** 92 /**
79 * Set the size of the archive in bytes 93 * Set the size of the archive in bytes
80 */ 94 */
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index 66931e93e..789212b17 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -49,8 +49,8 @@ bool Archive_SDMC::Initialize() {
49 * @param mode Mode to open the file with 49 * @param mode Mode to open the file with
50 * @return Opened file, or nullptr 50 * @return Opened file, or nullptr
51 */ 51 */
52std::unique_ptr<File> Archive_SDMC::OpenFile(const std::string& path, const Mode mode) const { 52std::unique_ptr<File> Archive_SDMC::OpenFile(const Path& path, const Mode mode) const {
53 DEBUG_LOG(FILESYS, "called path=%s mode=%d", path.c_str(), mode); 53 DEBUG_LOG(FILESYS, "called path=%s mode=%u", path.DebugStr().c_str(), mode.hex);
54 File_SDMC* file = new File_SDMC(this, path, mode); 54 File_SDMC* file = new File_SDMC(this, path, mode);
55 if (!file->Open()) 55 if (!file->Open())
56 return nullptr; 56 return nullptr;
@@ -58,12 +58,30 @@ std::unique_ptr<File> Archive_SDMC::OpenFile(const std::string& path, const Mode
58} 58}
59 59
60/** 60/**
61 * Delete a file specified by its path
62 * @param path Path relative to the archive
63 * @return Whether the file could be deleted
64 */
65bool Archive_SDMC::DeleteFile(const FileSys::Path& path) const {
66 return FileUtil::Delete(GetMountPoint() + path.AsString());
67}
68
69/**
70 * Delete a directory specified by its path
71 * @param path Path relative to the archive
72 * @return Whether the directory could be deleted
73 */
74bool Archive_SDMC::DeleteDirectory(const FileSys::Path& path) const {
75 return FileUtil::DeleteDir(GetMountPoint() + path.AsString());
76}
77
78/**
61 * Create a directory specified by its path 79 * Create a directory specified by its path
62 * @param path Path relative to the archive 80 * @param path Path relative to the archive
63 * @return Whether the directory could be created 81 * @return Whether the directory could be created
64 */ 82 */
65bool Archive_SDMC::CreateDirectory(const std::string& path) const { 83bool Archive_SDMC::CreateDirectory(const Path& path) const {
66 return FileUtil::CreateDir(GetMountPoint() + path); 84 return FileUtil::CreateDir(GetMountPoint() + path.AsString());
67} 85}
68 86
69/** 87/**
@@ -71,8 +89,8 @@ bool Archive_SDMC::CreateDirectory(const std::string& path) const {
71 * @param path Path relative to the archive 89 * @param path Path relative to the archive
72 * @return Opened directory, or nullptr 90 * @return Opened directory, or nullptr
73 */ 91 */
74std::unique_ptr<Directory> Archive_SDMC::OpenDirectory(const std::string& path) const { 92std::unique_ptr<Directory> Archive_SDMC::OpenDirectory(const Path& path) const {
75 DEBUG_LOG(FILESYS, "called path=%s", path.c_str()); 93 DEBUG_LOG(FILESYS, "called path=%s", path.DebugStr().c_str());
76 Directory_SDMC* directory = new Directory_SDMC(this, path); 94 Directory_SDMC* directory = new Directory_SDMC(this, path);
77 return std::unique_ptr<Directory>(directory); 95 return std::unique_ptr<Directory>(directory);
78} 96}
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index 0e059b635..74ce29c0d 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -30,7 +30,7 @@ public:
30 * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.) 30 * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.)
31 * @return IdCode of the archive 31 * @return IdCode of the archive
32 */ 32 */
33 IdCode GetIdCode() const override { return IdCode::SDMC; }; 33 IdCode GetIdCode() const override { return IdCode::SDMC; }
34 34
35 /** 35 /**
36 * Open a file specified by its path, using the specified mode 36 * Open a file specified by its path, using the specified mode
@@ -38,21 +38,35 @@ public:
38 * @param mode Mode to open the file with 38 * @param mode Mode to open the file with
39 * @return Opened file, or nullptr 39 * @return Opened file, or nullptr
40 */ 40 */
41 std::unique_ptr<File> OpenFile(const std::string& path, const Mode mode) const override; 41 std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const override;
42
43 /**
44 * Delete a file specified by its path
45 * @param path Path relative to the archive
46 * @return Whether the file could be deleted
47 */
48 bool DeleteFile(const FileSys::Path& path) const override;
49
50 /**
51 * Delete a directory specified by its path
52 * @param path Path relative to the archive
53 * @return Whether the directory could be deleted
54 */
55 bool DeleteDirectory(const FileSys::Path& path) const override;
42 56
43 /** 57 /**
44 * Create a directory specified by its path 58 * Create a directory specified by its path
45 * @param path Path relative to the archive 59 * @param path Path relative to the archive
46 * @return Whether the directory could be created 60 * @return Whether the directory could be created
47 */ 61 */
48 bool CreateDirectory(const std::string& path) const override; 62 bool CreateDirectory(const Path& path) const override;
49 63
50 /** 64 /**
51 * Open a directory specified by its path 65 * Open a directory specified by its path
52 * @param path Path relative to the archive 66 * @param path Path relative to the archive
53 * @return Opened directory, or nullptr 67 * @return Opened directory, or nullptr
54 */ 68 */
55 std::unique_ptr<Directory> OpenDirectory(const std::string& path) const override; 69 std::unique_ptr<Directory> OpenDirectory(const Path& path) const override;
56 70
57 /** 71 /**
58 * Read data from the archive 72 * Read data from the archive
diff --git a/src/core/file_sys/directory_sdmc.cpp b/src/core/file_sys/directory_sdmc.cpp
index fd558def9..60a197ce9 100644
--- a/src/core/file_sys/directory_sdmc.cpp
+++ b/src/core/file_sys/directory_sdmc.cpp
@@ -15,11 +15,11 @@
15 15
16namespace FileSys { 16namespace FileSys {
17 17
18Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const std::string& path) { 18Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const Path& path) {
19 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass 19 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
20 // the root directory we set while opening the archive. 20 // the root directory we set while opening the archive.
21 // For example, opening /../../usr/bin can give the emulated program your installed programs. 21 // For example, opening /../../usr/bin can give the emulated program your installed programs.
22 std::string absolute_path = archive->GetMountPoint() + path; 22 std::string absolute_path = archive->GetMountPoint() + path.AsString();
23 FileUtil::ScanDirectoryTree(absolute_path, directory); 23 FileUtil::ScanDirectoryTree(absolute_path, directory);
24 children_iterator = directory.children.begin(); 24 children_iterator = directory.children.begin();
25} 25}
@@ -45,7 +45,7 @@ u32 Directory_SDMC::Read(const u32 count, Entry* entries) {
45 WARN_LOG(FILESYS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory); 45 WARN_LOG(FILESYS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory);
46 46
47 // TODO(Link Mauve): use a proper conversion to UTF-16. 47 // TODO(Link Mauve): use a proper conversion to UTF-16.
48 for (int j = 0; j < FILENAME_LENGTH; ++j) { 48 for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
49 entry.filename[j] = filename[j]; 49 entry.filename[j] = filename[j];
50 if (!filename[j]) 50 if (!filename[j])
51 break; 51 break;
diff --git a/src/core/file_sys/directory_sdmc.h b/src/core/file_sys/directory_sdmc.h
index cb8d32fda..4520d0401 100644
--- a/src/core/file_sys/directory_sdmc.h
+++ b/src/core/file_sys/directory_sdmc.h
@@ -19,7 +19,7 @@ namespace FileSys {
19class Directory_SDMC final : public Directory { 19class Directory_SDMC final : public Directory {
20public: 20public:
21 Directory_SDMC(); 21 Directory_SDMC();
22 Directory_SDMC(const Archive_SDMC* archive, const std::string& path); 22 Directory_SDMC(const Archive_SDMC* archive, const Path& path);
23 ~Directory_SDMC() override; 23 ~Directory_SDMC() override;
24 24
25 /** 25 /**
diff --git a/src/core/file_sys/file_sdmc.cpp b/src/core/file_sys/file_sdmc.cpp
index 26204392c..a4b90670a 100644
--- a/src/core/file_sys/file_sdmc.cpp
+++ b/src/core/file_sys/file_sdmc.cpp
@@ -15,11 +15,11 @@
15 15
16namespace FileSys { 16namespace FileSys {
17 17
18File_SDMC::File_SDMC(const Archive_SDMC* archive, const std::string& path, const Mode mode) { 18File_SDMC::File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode) {
19 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass 19 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
20 // the root directory we set while opening the archive. 20 // the root directory we set while opening the archive.
21 // For example, opening /../../etc/passwd can give the emulated program your users list. 21 // For example, opening /../../etc/passwd can give the emulated program your users list.
22 this->path = archive->GetMountPoint() + path; 22 this->path = archive->GetMountPoint() + path.AsString();
23 this->mode.hex = mode.hex; 23 this->mode.hex = mode.hex;
24} 24}
25 25
diff --git a/src/core/file_sys/file_sdmc.h b/src/core/file_sys/file_sdmc.h
index df032f7c0..80b445968 100644
--- a/src/core/file_sys/file_sdmc.h
+++ b/src/core/file_sys/file_sdmc.h
@@ -19,7 +19,7 @@ namespace FileSys {
19class File_SDMC final : public File { 19class File_SDMC final : public File {
20public: 20public:
21 File_SDMC(); 21 File_SDMC();
22 File_SDMC(const Archive_SDMC* archive, const std::string& path, const Mode mode); 22 File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode);
23 ~File_SDMC() override; 23 ~File_SDMC() override;
24 24
25 /** 25 /**
diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp
index a45e61427..c7cf5b1d3 100644
--- a/src/core/hle/config_mem.cpp
+++ b/src/core/hle/config_mem.cpp
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
6 6
diff --git a/src/core/hle/coprocessor.cpp b/src/core/hle/coprocessor.cpp
index 1eb33eb86..e34229a57 100644
--- a/src/core/hle/coprocessor.cpp
+++ b/src/core/hle/coprocessor.cpp
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/coprocessor.h" 5#include "core/hle/coprocessor.h"
6#include "core/hle/hle.h" 6#include "core/hle/hle.h"
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 55eaf0621..3dbe25037 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -50,7 +50,7 @@ template<s32 func(u32*, u32, u32, u32, u32, u32)> void Wrap(){
50 50
51template<s32 func(s32*, u32*, s32, bool, s64)> void Wrap() { 51template<s32 func(s32*, u32*, s32, bool, s64)> void Wrap() {
52 s32 param_1 = 0; 52 s32 param_1 = 0;
53 s32 retval = func(&param_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), 53 s32 retval = func(&param_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2),
54 (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))); 54 (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0)));
55 Core::g_app_core->SetReg(1, (u32)param_1); 55 Core::g_app_core->SetReg(1, (u32)param_1);
56 FuncReturn(retval); 56 FuncReturn(retval);
@@ -103,7 +103,7 @@ template<s32 func(void*)> void Wrap() {
103} 103}
104 104
105template<s32 func(s64*, u32, void*, s32)> void Wrap(){ 105template<s32 func(s64*, u32, void*, s32)> void Wrap(){
106 FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), 106 FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)),
107 (s32)PARAM(3))); 107 (s32)PARAM(3)));
108} 108}
109 109
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
index b03894ad7..b8ac186f6 100644
--- a/src/core/hle/hle.cpp
+++ b/src/core/hle/hle.cpp
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <vector> 5#include <vector>
6 6
@@ -20,7 +20,7 @@ bool g_reschedule = false; ///< If true, immediately reschedules the CPU to a n
20const FunctionDef* GetSVCInfo(u32 opcode) { 20const FunctionDef* GetSVCInfo(u32 opcode) {
21 u32 func_num = opcode & 0xFFFFFF; // 8 bits 21 u32 func_num = opcode & 0xFFFFFF; // 8 bits
22 if (func_num > 0xFF) { 22 if (func_num > 0xFF) {
23 ERROR_LOG(HLE,"unknown svc=0x%02X", func_num); 23 ERROR_LOG(HLE,"unknown svc=0x%02X", func_num);
24 return nullptr; 24 return nullptr;
25 } 25 }
26 return &g_module_db[0].func_table[func_num]; 26 return &g_module_db[0].func_table[func_num];
@@ -58,7 +58,7 @@ void RegisterAllModules() {
58 58
59void Init() { 59void Init() {
60 Service::Init(); 60 Service::Init();
61 61
62 RegisterAllModules(); 62 RegisterAllModules();
63 63
64 NOTICE_LOG(HLE, "initialized OK"); 64 NOTICE_LOG(HLE, "initialized OK");
diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h
index bf4d84575..4ab258c69 100644
--- a/src/core/hle/hle.h
+++ b/src/core/hle/hle.h
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 2b21657da..db571b895 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -25,22 +25,17 @@ public:
25 25
26 std::string name; ///< Name of address arbiter object (optional) 26 std::string name; ///< Name of address arbiter object (optional)
27 27
28 /** 28 ResultVal<bool> WaitSynchronization() override {
29 * Wait for kernel object to synchronize
30 * @param wait Boolean wait set if current thread should wait as a result of sync operation
31 * @return Result of operation, 0 on success, otherwise error code
32 */
33 Result WaitSynchronization(bool* wait) override {
34 // TODO(bunnei): ImplementMe 29 // TODO(bunnei): ImplementMe
35 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 30 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
36 return 0; 31 return UnimplementedFunction(ErrorModule::OS);
37 } 32 }
38}; 33};
39 34
40//////////////////////////////////////////////////////////////////////////////////////////////////// 35////////////////////////////////////////////////////////////////////////////////////////////////////
41 36
42/// Arbitrate an address 37/// Arbitrate an address
43Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) { 38ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value) {
44 switch (type) { 39 switch (type) {
45 40
46 // Signal thread(s) waiting for arbitrate address... 41 // Signal thread(s) waiting for arbitrate address...
@@ -65,9 +60,9 @@ Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 va
65 60
66 default: 61 default:
67 ERROR_LOG(KERNEL, "unknown type=%d", type); 62 ERROR_LOG(KERNEL, "unknown type=%d", type);
68 return -1; 63 return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, ErrorSummary::WrongArgument, ErrorLevel::Usage);
69 } 64 }
70 return 0; 65 return RESULT_SUCCESS;
71} 66}
72 67
73/// Create an address arbiter 68/// Create an address arbiter
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index a483fe466..8a5fb10b4 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -11,7 +11,7 @@
11// Address arbiters are an underlying kernel synchronization object that can be created/used via 11// Address arbiters are an underlying kernel synchronization object that can be created/used via
12// supervisor calls (SVCs). They function as sort of a global lock. Typically, games/other CTR 12// supervisor calls (SVCs). They function as sort of a global lock. Typically, games/other CTR
13// applications use them as an underlying mechanism to implement thread-safe barriers, events, and 13// applications use them as an underlying mechanism to implement thread-safe barriers, events, and
14// semphores. 14// semphores.
15 15
16//////////////////////////////////////////////////////////////////////////////////////////////////// 16////////////////////////////////////////////////////////////////////////////////////////////////////
17// Kernel namespace 17// Kernel namespace
@@ -28,7 +28,7 @@ enum class ArbitrationType : u32 {
28}; 28};
29 29
30/// Arbitrate an address 30/// Arbitrate an address
31Result ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value); 31ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s32 value);
32 32
33/// Create an address arbiter 33/// Create an address arbiter
34Handle CreateAddressArbiter(const std::string& name = "Unknown"); 34Handle CreateAddressArbiter(const std::string& name = "Unknown");
diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp
index 764082d71..e273444c9 100644
--- a/src/core/hle/kernel/archive.cpp
+++ b/src/core/hle/kernel/archive.cpp
@@ -9,8 +9,9 @@
9#include "core/file_sys/archive.h" 9#include "core/file_sys/archive.h"
10#include "core/file_sys/archive_sdmc.h" 10#include "core/file_sys/archive_sdmc.h"
11#include "core/file_sys/directory.h" 11#include "core/file_sys/directory.h"
12#include "core/hle/service/service.h"
13#include "core/hle/kernel/archive.h" 12#include "core/hle/kernel/archive.h"
13#include "core/hle/result.h"
14#include "core/hle/service/service.h"
14 15
15//////////////////////////////////////////////////////////////////////////////////////////////////// 16////////////////////////////////////////////////////////////////////////////////////////////////////
16// Kernel namespace 17// Kernel namespace
@@ -51,15 +52,10 @@ public:
51 std::string name; ///< Name of archive (optional) 52 std::string name; ///< Name of archive (optional)
52 FileSys::Archive* backend; ///< Archive backend interface 53 FileSys::Archive* backend; ///< Archive backend interface
53 54
54 /** 55 ResultVal<bool> SyncRequest() override {
55 * Synchronize kernel object
56 * @param wait Boolean wait set if current thread should wait as a result of sync operation
57 * @return Result of operation, 0 on success, otherwise error code
58 */
59 Result SyncRequest(bool* wait) override {
60 u32* cmd_buff = Service::GetCommandBuffer(); 56 u32* cmd_buff = Service::GetCommandBuffer();
61 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); 57 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
62 58
63 switch (cmd) { 59 switch (cmd) {
64 // Read from archive... 60 // Read from archive...
65 case FileCommand::Read: 61 case FileCommand::Read:
@@ -99,7 +95,6 @@ public:
99 case FileCommand::Close: 95 case FileCommand::Close:
100 { 96 {
101 DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); 97 DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
102 Kernel::g_object_pool.Destroy<Archive>(GetHandle());
103 CloseArchive(backend->GetIdCode()); 98 CloseArchive(backend->GetIdCode());
104 break; 99 break;
105 } 100 }
@@ -107,42 +102,32 @@ public:
107 default: 102 default:
108 { 103 {
109 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); 104 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
110 return -1; 105 return UnimplementedFunction(ErrorModule::FS);
111 } 106 }
112 } 107 }
113 cmd_buff[1] = 0; // No error 108 cmd_buff[1] = 0; // No error
114 return 0; 109 return MakeResult<bool>(false);
115 } 110 }
116 111
117 /** 112 ResultVal<bool> WaitSynchronization() override {
118 * Wait for kernel object to synchronize
119 * @param wait Boolean wait set if current thread should wait as a result of sync operation
120 * @return Result of operation, 0 on success, otherwise error code
121 */
122 Result WaitSynchronization(bool* wait) override {
123 // TODO(bunnei): ImplementMe 113 // TODO(bunnei): ImplementMe
124 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 114 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
125 return 0; 115 return UnimplementedFunction(ErrorModule::FS);
126 } 116 }
127}; 117};
128 118
129class File : public Object { 119class File : public Object {
130public: 120public:
131 std::string GetTypeName() const override { return "File"; } 121 std::string GetTypeName() const override { return "File"; }
132 std::string GetName() const override { return path; } 122 std::string GetName() const override { return path.DebugStr(); }
133 123
134 static Kernel::HandleType GetStaticHandleType() { return HandleType::File; } 124 static Kernel::HandleType GetStaticHandleType() { return HandleType::File; }
135 Kernel::HandleType GetHandleType() const override { return HandleType::File; } 125 Kernel::HandleType GetHandleType() const override { return HandleType::File; }
136 126
137 std::string path; ///< Path of the file 127 FileSys::Path path; ///< Path of the file
138 std::unique_ptr<FileSys::File> backend; ///< File backend interface 128 std::unique_ptr<FileSys::File> backend; ///< File backend interface
139 129
140 /** 130 ResultVal<bool> SyncRequest() override {
141 * Synchronize kernel object
142 * @param wait Boolean wait set if current thread should wait as a result of sync operation
143 * @return Result of operation, 0 on success, otherwise error code
144 */
145 Result SyncRequest(bool* wait) override {
146 u32* cmd_buff = Service::GetCommandBuffer(); 131 u32* cmd_buff = Service::GetCommandBuffer();
147 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]); 132 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
148 switch (cmd) { 133 switch (cmd) {
@@ -184,7 +169,8 @@ public:
184 case FileCommand::SetSize: 169 case FileCommand::SetSize:
185 { 170 {
186 u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); 171 u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
187 DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(), size); 172 DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu",
173 GetTypeName().c_str(), GetName().c_str(), size);
188 backend->SetSize(size); 174 backend->SetSize(size);
189 break; 175 break;
190 } 176 }
@@ -199,42 +185,33 @@ public:
199 // Unknown command... 185 // Unknown command...
200 default: 186 default:
201 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); 187 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
202 cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. 188 ResultCode error = UnimplementedFunction(ErrorModule::FS);
203 return -1; 189 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
190 return error;
204 } 191 }
205 cmd_buff[1] = 0; // No error 192 cmd_buff[1] = 0; // No error
206 return 0; 193 return MakeResult<bool>(false);
207 } 194 }
208 195
209 /** 196 ResultVal<bool> WaitSynchronization() override {
210 * Wait for kernel object to synchronize
211 * @param wait Boolean wait set if current thread should wait as a result of sync operation
212 * @return Result of operation, 0 on success, otherwise error code
213 */
214 Result WaitSynchronization(bool* wait) override {
215 // TODO(bunnei): ImplementMe 197 // TODO(bunnei): ImplementMe
216 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 198 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
217 return 0; 199 return UnimplementedFunction(ErrorModule::FS);
218 } 200 }
219}; 201};
220 202
221class Directory : public Object { 203class Directory : public Object {
222public: 204public:
223 std::string GetTypeName() const override { return "Directory"; } 205 std::string GetTypeName() const override { return "Directory"; }
224 std::string GetName() const override { return path; } 206 std::string GetName() const override { return path.DebugStr(); }
225 207
226 static Kernel::HandleType GetStaticHandleType() { return HandleType::Directory; } 208 static Kernel::HandleType GetStaticHandleType() { return HandleType::Directory; }
227 Kernel::HandleType GetHandleType() const override { return HandleType::Directory; } 209 Kernel::HandleType GetHandleType() const override { return HandleType::Directory; }
228 210
229 std::string path; ///< Path of the directory 211 FileSys::Path path; ///< Path of the directory
230 std::unique_ptr<FileSys::Directory> backend; ///< File backend interface 212 std::unique_ptr<FileSys::Directory> backend; ///< File backend interface
231 213
232 /** 214 ResultVal<bool> SyncRequest() override {
233 * Synchronize kernel object
234 * @param wait Boolean wait set if current thread should wait as a result of sync operation
235 * @return Result of operation, 0 on success, otherwise error code
236 */
237 Result SyncRequest(bool* wait) override {
238 u32* cmd_buff = Service::GetCommandBuffer(); 215 u32* cmd_buff = Service::GetCommandBuffer();
239 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]); 216 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
240 switch (cmd) { 217 switch (cmd) {
@@ -244,8 +221,9 @@ public:
244 { 221 {
245 u32 count = cmd_buff[1]; 222 u32 count = cmd_buff[1];
246 u32 address = cmd_buff[3]; 223 u32 address = cmd_buff[3];
247 FileSys::Entry* entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address)); 224 auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address));
248 DEBUG_LOG(KERNEL, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(), count); 225 DEBUG_LOG(KERNEL, "Read %s %s: count=%d",
226 GetTypeName().c_str(), GetName().c_str(), count);
249 227
250 // Number of entries actually read 228 // Number of entries actually read
251 cmd_buff[2] = backend->Read(count, entries); 229 cmd_buff[2] = backend->Read(count, entries);
@@ -262,22 +240,18 @@ public:
262 // Unknown command... 240 // Unknown command...
263 default: 241 default:
264 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd); 242 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
265 cmd_buff[1] = -1; // TODO(Link Mauve): use the correct error code for that. 243 ResultCode error = UnimplementedFunction(ErrorModule::FS);
266 return -1; 244 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
245 return error;
267 } 246 }
268 cmd_buff[1] = 0; // No error 247 cmd_buff[1] = 0; // No error
269 return 0; 248 return MakeResult<bool>(false);
270 } 249 }
271 250
272 /** 251 ResultVal<bool> WaitSynchronization() override {
273 * Wait for kernel object to synchronize
274 * @param wait Boolean wait set if current thread should wait as a result of sync operation
275 * @return Result of operation, 0 on success, otherwise error code
276 */
277 Result WaitSynchronization(bool* wait) override {
278 // TODO(bunnei): ImplementMe 252 // TODO(bunnei): ImplementMe
279 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 253 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
280 return 0; 254 return UnimplementedFunction(ErrorModule::FS);
281 } 255 }
282}; 256};
283 257
@@ -285,108 +259,124 @@ public:
285 259
286std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode 260std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode
287 261
288/** 262ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code) {
289 * Opens an archive
290 * @param id_code IdCode of the archive to open
291 * @return Handle to archive if it exists, otherwise a null handle (0)
292 */
293Handle OpenArchive(FileSys::Archive::IdCode id_code) {
294 auto itr = g_archive_map.find(id_code); 263 auto itr = g_archive_map.find(id_code);
295 if (itr == g_archive_map.end()) { 264 if (itr == g_archive_map.end()) {
296 return 0; 265 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
266 ErrorSummary::NotFound, ErrorLevel::Permanent);
297 } 267 }
298 return itr->second; 268
269 return MakeResult<Handle>(itr->second);
299} 270}
300 271
301/** 272ResultCode CloseArchive(FileSys::Archive::IdCode id_code) {
302 * Closes an archive 273 auto itr = g_archive_map.find(id_code);
303 * @param id_code IdCode of the archive to open 274 if (itr == g_archive_map.end()) {
304 * @return Result of operation, 0 on success, otherwise error code 275 ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code);
305 */ 276 return InvalidHandle(ErrorModule::FS);
306Result CloseArchive(FileSys::Archive::IdCode id_code) {
307 if (1 != g_archive_map.erase(id_code)) {
308 ERROR_LOG(KERNEL, "Cannot close archive %d", (int) id_code);
309 return -1;
310 } 277 }
311 278
312 INFO_LOG(KERNEL, "Closed archive %d", (int) id_code); 279 INFO_LOG(KERNEL, "Closed archive %d", (int) id_code);
313 return 0; 280 return RESULT_SUCCESS;
314} 281}
315 282
316/** 283/**
317 * Mounts an archive 284 * Mounts an archive
318 * @param archive Pointer to the archive to mount 285 * @param archive Pointer to the archive to mount
319 * @return Result of operation, 0 on success, otherwise error code
320 */ 286 */
321Result MountArchive(Archive* archive) { 287ResultCode MountArchive(Archive* archive) {
322 FileSys::Archive::IdCode id_code = archive->backend->GetIdCode(); 288 FileSys::Archive::IdCode id_code = archive->backend->GetIdCode();
323 if (0 != OpenArchive(id_code)) { 289 ResultVal<Handle> archive_handle = OpenArchive(id_code);
290 if (archive_handle.Succeeded()) {
324 ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); 291 ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code);
325 return -1; 292 return archive_handle.Code();
326 } 293 }
327 g_archive_map[id_code] = archive->GetHandle(); 294 g_archive_map[id_code] = archive->GetHandle();
328 INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str()); 295 INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str());
329 return 0; 296 return RESULT_SUCCESS;
330} 297}
331 298
332/** 299ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) {
333 * Creates an Archive
334 * @param handle Handle to newly created archive object
335 * @param backend File system backend interface to the archive
336 * @param name Optional name of Archive
337 * @return Newly created Archive object
338 */
339Archive* CreateArchive(Handle& handle, FileSys::Archive* backend, const std::string& name) {
340 Archive* archive = new Archive; 300 Archive* archive = new Archive;
341 handle = Kernel::g_object_pool.Create(archive); 301 Handle handle = Kernel::g_object_pool.Create(archive);
342 archive->name = name; 302 archive->name = name;
343 archive->backend = backend; 303 archive->backend = backend;
344 304
345 MountArchive(archive); 305 ResultCode result = MountArchive(archive);
306 if (result.IsError()) {
307 return result;
308 }
346 309
347 return archive; 310 return RESULT_SUCCESS;
348} 311}
349 312
350/** 313ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) {
351 * Creates an Archive 314 // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create
352 * @param backend File system backend interface to the archive 315 // the archive file handles at app loading, and then keep them persistent throughout execution.
353 * @param name Optional name of Archive 316 // Archives file handles are just reused and not actually freed until emulation shut down.
354 * @return Handle to newly created Archive object 317 // Verify if real hardware works this way, or if new handles are created each time
355 */ 318 if (path.GetType() == FileSys::Binary)
356Handle CreateArchive(FileSys::Archive* backend, const std::string& name) { 319 // TODO(bunnei): FixMe - this is a hack to compensate for an incorrect FileSys backend
357 Handle handle; 320 // design. While the functionally of this is OK, our implementation decision to separate
358 CreateArchive(handle, backend, name); 321 // normal files from archive file pointers is very likely wrong.
359 return handle; 322 // See https://github.com/citra-emu/citra/issues/205
360} 323 return MakeResult<Handle>(archive_handle);
361 324
362/**
363 * Open a File from an Archive
364 * @param archive_handle Handle to an open Archive object
365 * @param path Path to the File inside of the Archive
366 * @param mode Mode under which to open the File
367 * @return Opened File object
368 */
369Handle OpenFileFromArchive(Handle archive_handle, const std::string& path, const FileSys::Mode mode) {
370 File* file = new File; 325 File* file = new File;
371 Handle handle = Kernel::g_object_pool.Create(file); 326 Handle handle = Kernel::g_object_pool.Create(file);
372 327
373 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); 328 Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle);
329 if (archive == nullptr) {
330 return InvalidHandle(ErrorModule::FS);
331 }
374 file->path = path; 332 file->path = path;
375 file->backend = archive->backend->OpenFile(path, mode); 333 file->backend = archive->backend->OpenFile(path, mode);
376 334
377 if (!file->backend) 335 if (!file->backend) {
336 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
337 ErrorSummary::NotFound, ErrorLevel::Permanent);
338 }
339
340 return MakeResult<Handle>(handle);
341}
342
343/**
344 * Delete a File from an Archive
345 * @param archive_handle Handle to an open Archive object
346 * @param path Path to the File inside of the Archive
347 * @return Whether deletion succeeded
348 */
349Result DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path) {
350 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
351 if (archive == nullptr)
352 return -1;
353 if (archive->backend->DeleteFile(path))
378 return 0; 354 return 0;
355 return -1;
356}
379 357
380 return handle; 358/**
359 * Delete a Directory from an Archive
360 * @param archive_handle Handle to an open Archive object
361 * @param path Path to the Directory inside of the Archive
362 * @return Whether deletion succeeded
363 */
364Result DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
365 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
366 if (archive == nullptr)
367 return -1;
368 if (archive->backend->DeleteDirectory(path))
369 return 0;
370 return -1;
381} 371}
382 372
383/** 373/**
384 * Create a Directory from an Archive 374 * Create a Directory from an Archive
385 * @param archive_handle Handle to an open Archive object 375 * @param archive_handle Handle to an open Archive object
386 * @param path Path to the Directory inside of the Archive 376 * @param path Path to the Directory inside of the Archive
387 * @return Opened Directory object 377 * @return Whether creation succeeded
388 */ 378 */
389Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& path) { 379Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
390 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); 380 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
391 if (archive == nullptr) 381 if (archive == nullptr)
392 return -1; 382 return -1;
@@ -401,15 +391,18 @@ Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& path
401 * @param path Path to the Directory inside of the Archive 391 * @param path Path to the Directory inside of the Archive
402 * @return Opened Directory object 392 * @return Opened Directory object
403 */ 393 */
404Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& path) { 394ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
405 Directory* directory = new Directory; 395 Directory* directory = new Directory;
406 Handle handle = Kernel::g_object_pool.Create(directory); 396 Handle handle = Kernel::g_object_pool.Create(directory);
407 397
408 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle); 398 Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle);
399 if (archive == nullptr) {
400 return InvalidHandle(ErrorModule::FS);
401 }
409 directory->path = path; 402 directory->path = path;
410 directory->backend = archive->backend->OpenDirectory(path); 403 directory->backend = archive->backend->OpenDirectory(path);
411 404
412 return handle; 405 return MakeResult<Handle>(handle);
413} 406}
414 407
415/// Initialize archives 408/// Initialize archives
diff --git a/src/core/hle/kernel/archive.h b/src/core/hle/kernel/archive.h
index 0230996b6..6fc4f0f25 100644
--- a/src/core/hle/kernel/archive.h
+++ b/src/core/hle/kernel/archive.h
@@ -6,8 +6,9 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8 8
9#include "core/hle/kernel/kernel.h"
10#include "core/file_sys/archive.h" 9#include "core/file_sys/archive.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/result.h"
11 12
12//////////////////////////////////////////////////////////////////////////////////////////////////// 13////////////////////////////////////////////////////////////////////////////////////////////////////
13// Kernel namespace 14// Kernel namespace
@@ -17,33 +18,47 @@ namespace Kernel {
17/** 18/**
18 * Opens an archive 19 * Opens an archive
19 * @param id_code IdCode of the archive to open 20 * @param id_code IdCode of the archive to open
20 * @return Handle to archive if it exists, otherwise a null handle (0) 21 * @return Handle to the opened archive
21 */ 22 */
22Handle OpenArchive(FileSys::Archive::IdCode id_code); 23ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code);
23 24
24/** 25/**
25 * Closes an archive 26 * Closes an archive
26 * @param id_code IdCode of the archive to open 27 * @param id_code IdCode of the archive to open
27 * @return true if it worked fine
28 */ 28 */
29Result CloseArchive(FileSys::Archive::IdCode id_code); 29ResultCode CloseArchive(FileSys::Archive::IdCode id_code);
30 30
31/** 31/**
32 * Creates an Archive 32 * Creates an Archive
33 * @param backend File system backend interface to the archive 33 * @param backend File system backend interface to the archive
34 * @param name Optional name of Archive 34 * @param name Name of Archive
35 * @return Handle to newly created Archive object
36 */ 35 */
37Handle CreateArchive(FileSys::Archive* backend, const std::string& name); 36ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name);
38 37
39/** 38/**
40 * Open a File from an Archive 39 * Open a File from an Archive
41 * @param archive_handle Handle to an open Archive object 40 * @param archive_handle Handle to an open Archive object
42 * @param path Path to the File inside of the Archive 41 * @param path Path to the File inside of the Archive
43 * @param mode Mode under which to open the File 42 * @param mode Mode under which to open the File
44 * @return Opened File object 43 * @return Handle to the opened File object
44 */
45ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode);
46
47/**
48 * Delete a File from an Archive
49 * @param archive_handle Handle to an open Archive object
50 * @param path Path to the File inside of the Archive
51 * @return Whether deletion succeeded
52 */
53Result DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path);
54
55/**
56 * Delete a Directory from an Archive
57 * @param archive_handle Handle to an open Archive object
58 * @param path Path to the Directory inside of the Archive
59 * @return Whether deletion succeeded
45 */ 60 */
46Handle OpenFileFromArchive(Handle archive_handle, const std::string& name, const FileSys::Mode mode); 61Result DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path);
47 62
48/** 63/**
49 * Create a Directory from an Archive 64 * Create a Directory from an Archive
@@ -51,15 +66,15 @@ Handle OpenFileFromArchive(Handle archive_handle, const std::string& name, const
51 * @param path Path to the Directory inside of the Archive 66 * @param path Path to the Directory inside of the Archive
52 * @return Whether creation of directory succeeded 67 * @return Whether creation of directory succeeded
53 */ 68 */
54Result CreateDirectoryFromArchive(Handle archive_handle, const std::string& name); 69Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path);
55 70
56/** 71/**
57 * Open a Directory from an Archive 72 * Open a Directory from an Archive
58 * @param archive_handle Handle to an open Archive object 73 * @param archive_handle Handle to an open Archive object
59 * @param path Path to the Directory inside of the Archive 74 * @param path Path to the Directory inside of the Archive
60 * @return Opened Directory object 75 * @return Handle to the opened File object
61 */ 76 */
62Handle OpenDirectoryFromArchive(Handle archive_handle, const std::string& name); 77ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path);
63 78
64/// Initialize archives 79/// Initialize archives
65void ArchiveInit(); 80void ArchiveInit();
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index 45ed79be8..288080209 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map> 5#include <map>
6#include <algorithm> 6#include <algorithm>
@@ -30,13 +30,8 @@ public:
30 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event 30 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the event
31 std::string name; ///< Name of event (optional) 31 std::string name; ///< Name of event (optional)
32 32
33 /** 33 ResultVal<bool> WaitSynchronization() override {
34 * Wait for kernel object to synchronize 34 bool wait = locked;
35 * @param wait Boolean wait set if current thread should wait as a result of sync operation
36 * @return Result of operation, 0 on success, otherwise error code
37 */
38 Result WaitSynchronization(bool* wait) override {
39 *wait = locked;
40 if (locked) { 35 if (locked) {
41 Handle thread = GetCurrentThreadHandle(); 36 Handle thread = GetCurrentThreadHandle();
42 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { 37 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
@@ -47,7 +42,7 @@ public:
47 if (reset_type != RESETTYPE_STICKY && !permanent_locked) { 42 if (reset_type != RESETTYPE_STICKY && !permanent_locked) {
48 locked = true; 43 locked = true;
49 } 44 }
50 return 0; 45 return MakeResult<bool>(wait);
51 } 46 }
52}; 47};
53 48
@@ -57,12 +52,12 @@ public:
57 * @param permanent_locked Boolean permanent locked value to set event 52 * @param permanent_locked Boolean permanent locked value to set event
58 * @return Result of operation, 0 on success, otherwise error code 53 * @return Result of operation, 0 on success, otherwise error code
59 */ 54 */
60Result SetPermanentLock(Handle handle, const bool permanent_locked) { 55ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) {
61 Event* evt = g_object_pool.GetFast<Event>(handle); 56 Event* evt = g_object_pool.Get<Event>(handle);
62 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); 57 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
63 58
64 evt->permanent_locked = permanent_locked; 59 evt->permanent_locked = permanent_locked;
65 return 0; 60 return RESULT_SUCCESS;
66} 61}
67 62
68/** 63/**
@@ -71,14 +66,14 @@ Result SetPermanentLock(Handle handle, const bool permanent_locked) {
71 * @param locked Boolean locked value to set event 66 * @param locked Boolean locked value to set event
72 * @return Result of operation, 0 on success, otherwise error code 67 * @return Result of operation, 0 on success, otherwise error code
73 */ 68 */
74Result SetEventLocked(const Handle handle, const bool locked) { 69ResultCode SetEventLocked(const Handle handle, const bool locked) {
75 Event* evt = g_object_pool.GetFast<Event>(handle); 70 Event* evt = g_object_pool.Get<Event>(handle);
76 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); 71 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
77 72
78 if (!evt->permanent_locked) { 73 if (!evt->permanent_locked) {
79 evt->locked = locked; 74 evt->locked = locked;
80 } 75 }
81 return 0; 76 return RESULT_SUCCESS;
82} 77}
83 78
84/** 79/**
@@ -86,16 +81,16 @@ Result SetEventLocked(const Handle handle, const bool locked) {
86 * @param handle Handle to event to signal 81 * @param handle Handle to event to signal
87 * @return Result of operation, 0 on success, otherwise error code 82 * @return Result of operation, 0 on success, otherwise error code
88 */ 83 */
89Result SignalEvent(const Handle handle) { 84ResultCode SignalEvent(const Handle handle) {
90 Event* evt = g_object_pool.GetFast<Event>(handle); 85 Event* evt = g_object_pool.Get<Event>(handle);
91 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); 86 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
92 87
93 // Resume threads waiting for event to signal 88 // Resume threads waiting for event to signal
94 bool event_caught = false; 89 bool event_caught = false;
95 for (size_t i = 0; i < evt->waiting_threads.size(); ++i) { 90 for (size_t i = 0; i < evt->waiting_threads.size(); ++i) {
96 ResumeThreadFromWait( evt->waiting_threads[i]); 91 ResumeThreadFromWait( evt->waiting_threads[i]);
97 92
98 // If any thread is signalled awake by this event, assume the event was "caught" and reset 93 // If any thread is signalled awake by this event, assume the event was "caught" and reset
99 // the event. This will result in the next thread waiting on the event to block. Otherwise, 94 // the event. This will result in the next thread waiting on the event to block. Otherwise,
100 // the event will not be reset, and the next thread to call WaitSynchronization on it will 95 // the event will not be reset, and the next thread to call WaitSynchronization on it will
101 // not block. Not sure if this is correct behavior, but it seems to work. 96 // not block. Not sure if this is correct behavior, but it seems to work.
@@ -106,7 +101,7 @@ Result SignalEvent(const Handle handle) {
106 if (!evt->permanent_locked) { 101 if (!evt->permanent_locked) {
107 evt->locked = event_caught; 102 evt->locked = event_caught;
108 } 103 }
109 return 0; 104 return RESULT_SUCCESS;
110} 105}
111 106
112/** 107/**
@@ -114,14 +109,14 @@ Result SignalEvent(const Handle handle) {
114 * @param handle Handle to event to clear 109 * @param handle Handle to event to clear
115 * @return Result of operation, 0 on success, otherwise error code 110 * @return Result of operation, 0 on success, otherwise error code
116 */ 111 */
117Result ClearEvent(Handle handle) { 112ResultCode ClearEvent(Handle handle) {
118 Event* evt = g_object_pool.GetFast<Event>(handle); 113 Event* evt = g_object_pool.Get<Event>(handle);
119 _assert_msg_(KERNEL, (evt != nullptr), "called, but event is nullptr!"); 114 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
120 115
121 if (!evt->permanent_locked) { 116 if (!evt->permanent_locked) {
122 evt->locked = true; 117 evt->locked = true;
123 } 118 }
124 return 0; 119 return RESULT_SUCCESS;
125} 120}
126 121
127/** 122/**
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index c39b33180..73aec4e79 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
@@ -15,31 +15,27 @@ namespace Kernel {
15 * Changes whether an event is locked or not 15 * Changes whether an event is locked or not
16 * @param handle Handle to event to change 16 * @param handle Handle to event to change
17 * @param locked Boolean locked value to set event 17 * @param locked Boolean locked value to set event
18 * @return Result of operation, 0 on success, otherwise error code
19 */ 18 */
20Result SetEventLocked(const Handle handle, const bool locked); 19ResultCode SetEventLocked(const Handle handle, const bool locked);
21 20
22/** 21/**
23 * Hackish function to set an events permanent lock state, used to pass through synch blocks 22 * Hackish function to set an events permanent lock state, used to pass through synch blocks
24 * @param handle Handle to event to change 23 * @param handle Handle to event to change
25 * @param permanent_locked Boolean permanent locked value to set event 24 * @param permanent_locked Boolean permanent locked value to set event
26 * @return Result of operation, 0 on success, otherwise error code
27 */ 25 */
28Result SetPermanentLock(Handle handle, const bool permanent_locked); 26ResultCode SetPermanentLock(Handle handle, const bool permanent_locked);
29 27
30/** 28/**
31 * Signals an event 29 * Signals an event
32 * @param handle Handle to event to signal 30 * @param handle Handle to event to signal
33 * @return Result of operation, 0 on success, otherwise error code
34 */ 31 */
35Result SignalEvent(const Handle handle); 32ResultCode SignalEvent(const Handle handle);
36 33
37/** 34/**
38 * Clears an event 35 * Clears an event
39 * @param handle Handle to event to clear 36 * @param handle Handle to event to clear
40 * @return Result of operation, 0 on success, otherwise error code
41 */ 37 */
42Result ClearEvent(Handle handle); 38ResultCode ClearEvent(Handle handle);
43 39
44/** 40/**
45 * Creates an event 41 * Creates an event
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 88cbc1af5..018000abd 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project / PPSSPP Project 1// Copyright 2014 Citra Emulator Project / PPSSPP Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common.h" 5#include "common/common.h"
6 6
@@ -68,7 +68,7 @@ void ObjectPool::List() {
68 for (int i = 0; i < MAX_COUNT; i++) { 68 for (int i = 0; i < MAX_COUNT; i++) {
69 if (occupied[i]) { 69 if (occupied[i]) {
70 if (pool[i]) { 70 if (pool[i]) {
71 INFO_LOG(KERNEL, "KO %i: %s \"%s\"", i + HANDLE_OFFSET, pool[i]->GetTypeName().c_str(), 71 INFO_LOG(KERNEL, "KO %i: %s \"%s\"", i + HANDLE_OFFSET, pool[i]->GetTypeName().c_str(),
72 pool[i]->GetName().c_str()); 72 pool[i]->GetName().c_str());
73 } 73 }
74 } 74 }
@@ -110,7 +110,7 @@ void Shutdown() {
110 */ 110 */
111bool LoadExec(u32 entry_point) { 111bool LoadExec(u32 entry_point) {
112 Init(); 112 Init();
113 113
114 Core::g_app_core->SetPC(entry_point); 114 Core::g_app_core->SetPC(entry_point);
115 115
116 // 0x30 is the typical main thread priority I've seen used so far 116 // 0x30 is the typical main thread priority I've seen used so far
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 867d1b89c..8d3937ce8 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -1,12 +1,13 @@
1// Copyright 2014 Citra Emulator Project / PPSSPP Project 1// Copyright 2014 Citra Emulator Project / PPSSPP Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <string> 8#include <string>
9#include "common/common.h" 9#include "common/common.h"
10#include "core/hle/result.h"
10 11
11typedef u32 Handle; 12typedef u32 Handle;
12typedef s32 Result; 13typedef s32 Result;
@@ -34,7 +35,7 @@ enum class HandleType : u32 {
34 Archive = 12, 35 Archive = 12,
35 Directory = 13, 36 Directory = 13,
36}; 37};
37 38
38enum { 39enum {
39 DEFAULT_STACK_SIZE = 0x4000, 40 DEFAULT_STACK_SIZE = 0x4000,
40}; 41};
@@ -52,21 +53,19 @@ public:
52 virtual Kernel::HandleType GetHandleType() const = 0; 53 virtual Kernel::HandleType GetHandleType() const = 0;
53 54
54 /** 55 /**
55 * Synchronize kernel object 56 * Synchronize kernel object.
56 * @param wait Boolean wait set if current thread should wait as a result of sync operation 57 * @return True if the current thread should wait as a result of the sync
57 * @return Result of operation, 0 on success, otherwise error code
58 */ 58 */
59 virtual Result SyncRequest(bool* wait) { 59 virtual ResultVal<bool> SyncRequest() {
60 ERROR_LOG(KERNEL, "(UNIMPLEMENTED)"); 60 ERROR_LOG(KERNEL, "(UNIMPLEMENTED)");
61 return -1; 61 return UnimplementedFunction(ErrorModule::Kernel);
62 } 62 }
63 63
64 /** 64 /**
65 * Wait for kernel object to synchronize 65 * Wait for kernel object to synchronize.
66 * @param wait Boolean wait set if current thread should wait as a result of sync operation 66 * @return True if the current thread should wait as a result of the wait
67 * @return Result of operation, 0 on success, otherwise error code
68 */ 67 */
69 virtual Result WaitSynchronization(bool* wait) = 0; 68 virtual ResultVal<bool> WaitSynchronization() = 0;
70}; 69};
71 70
72class ObjectPool : NonCopyable { 71class ObjectPool : NonCopyable {
@@ -80,38 +79,29 @@ public:
80 static Object* CreateByIDType(int type); 79 static Object* CreateByIDType(int type);
81 80
82 template <class T> 81 template <class T>
83 u32 Destroy(Handle handle) { 82 void Destroy(Handle handle) {
84 u32 error; 83 if (Get<T>(handle)) {
85 if (Get<T>(handle, error)) {
86 occupied[handle - HANDLE_OFFSET] = false; 84 occupied[handle - HANDLE_OFFSET] = false;
87 delete pool[handle - HANDLE_OFFSET]; 85 delete pool[handle - HANDLE_OFFSET];
88 } 86 }
89 return error; 87 }
90 };
91 88
92 bool IsValid(Handle handle); 89 bool IsValid(Handle handle);
93 90
94 template <class T> 91 template <class T>
95 T* Get(Handle handle, u32& outError) { 92 T* Get(Handle handle) {
96 if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) { 93 if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) {
97 // Tekken 6 spams 0x80020001 gets wrong with no ill effects, also on the real PSP 94 if (handle != 0) {
98 if (handle != 0 && (u32)handle != 0x80020001) {
99 WARN_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); 95 WARN_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle);
100 } 96 }
101 outError = 0;//T::GetMissingErrorCode(); 97 return nullptr;
102 return 0;
103 } else { 98 } else {
104 // Previously we had a dynamic_cast here, but since RTTI was disabled traditionally, 99 Object* t = pool[handle - HANDLE_OFFSET];
105 // it just acted as a static case and everything worked. This means that we will never 100 if (t->GetHandleType() != T::GetStaticHandleType()) {
106 // see the Wrong type object error below, but we'll just have to live with that danger.
107 T* t = static_cast<T*>(pool[handle - HANDLE_OFFSET]);
108 if (t == 0 || t->GetHandleType() != T::GetStaticHandleType()) {
109 WARN_LOG(KERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle); 101 WARN_LOG(KERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle);
110 outError = 0;//T::GetMissingErrorCode(); 102 return nullptr;
111 return 0;
112 } 103 }
113 outError = 0;//SCE_KERNEL_ERROR_OK; 104 return static_cast<T*>(t);
114 return t;
115 } 105 }
116 } 106 }
117 107
@@ -139,7 +129,7 @@ public:
139 } 129 }
140 130
141 bool GetIDType(Handle handle, HandleType* type) const { 131 bool GetIDType(Handle handle, HandleType* type) const {
142 if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) || 132 if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) ||
143 !occupied[handle - HANDLE_OFFSET]) { 133 !occupied[handle - HANDLE_OFFSET]) {
144 ERROR_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); 134 ERROR_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle);
145 return false; 135 return false;
@@ -155,7 +145,7 @@ public:
155 int GetCount(); 145 int GetCount();
156 146
157private: 147private:
158 148
159 enum { 149 enum {
160 MAX_COUNT = 0x1000, 150 MAX_COUNT = 0x1000,
161 HANDLE_OFFSET = 0x100, 151 HANDLE_OFFSET = 0x100,
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index fcfd061ac..d07e9761b 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map> 5#include <map>
6#include <vector> 6#include <vector>
@@ -27,31 +27,20 @@ public:
27 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex 27 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex
28 std::string name; ///< Name of mutex (optional) 28 std::string name; ///< Name of mutex (optional)
29 29
30 /** 30 ResultVal<bool> SyncRequest() override {
31 * Synchronize kernel object
32 * @param wait Boolean wait set if current thread should wait as a result of sync operation
33 * @return Result of operation, 0 on success, otherwise error code
34 */
35 Result SyncRequest(bool* wait) override {
36 // TODO(bunnei): ImplementMe 31 // TODO(bunnei): ImplementMe
37 locked = true; 32 locked = true;
38 return 0; 33 return MakeResult<bool>(false);
39 } 34 }
40 35
41 /** 36 ResultVal<bool> WaitSynchronization() override {
42 * Wait for kernel object to synchronize
43 * @param wait Boolean wait set if current thread should wait as a result of sync operation
44 * @return Result of operation, 0 on success, otherwise error code
45 */
46 Result WaitSynchronization(bool* wait) override {
47 // TODO(bunnei): ImplementMe 37 // TODO(bunnei): ImplementMe
48 *wait = locked; 38 bool wait = locked;
49
50 if (locked) { 39 if (locked) {
51 Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle()); 40 Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle());
52 } 41 }
53 42
54 return 0; 43 return MakeResult<bool>(wait);
55 } 44 }
56}; 45};
57 46
@@ -99,35 +88,36 @@ bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
99 88
100bool ReleaseMutex(Mutex* mutex) { 89bool ReleaseMutex(Mutex* mutex) {
101 MutexEraseLock(mutex); 90 MutexEraseLock(mutex);
102 bool woke_threads = false;
103 91
104 // Find the next waiting thread for the mutex... 92 // Find the next waiting thread for the mutex...
105 while (!woke_threads && !mutex->waiting_threads.empty()) { 93 while (!mutex->waiting_threads.empty()) {
106 std::vector<Handle>::iterator iter = mutex->waiting_threads.begin(); 94 std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
107 woke_threads |= ReleaseMutexForThread(mutex, *iter); 95 ReleaseMutexForThread(mutex, *iter);
108 mutex->waiting_threads.erase(iter); 96 mutex->waiting_threads.erase(iter);
109 } 97 }
98
110 // Reset mutex lock thread handle, nothing is waiting 99 // Reset mutex lock thread handle, nothing is waiting
111 if (!woke_threads) { 100 mutex->locked = false;
112 mutex->locked = false; 101 mutex->lock_thread = -1;
113 mutex->lock_thread = -1; 102
114 } 103 return true;
115 return woke_threads;
116} 104}
117 105
118/** 106/**
119 * Releases a mutex 107 * Releases a mutex
120 * @param handle Handle to mutex to release 108 * @param handle Handle to mutex to release
121 */ 109 */
122Result ReleaseMutex(Handle handle) { 110ResultCode ReleaseMutex(Handle handle) {
123 Mutex* mutex = Kernel::g_object_pool.GetFast<Mutex>(handle); 111 Mutex* mutex = Kernel::g_object_pool.Get<Mutex>(handle);
124 112 if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel);
125 _assert_msg_(KERNEL, (mutex != nullptr), "ReleaseMutex tried to release a nullptr mutex!");
126 113
127 if (!ReleaseMutex(mutex)) { 114 if (!ReleaseMutex(mutex)) {
128 return -1; 115 // TODO(yuriks): Verify error code, this one was pulled out of thin air. I'm not even sure
116 // what error condition this is supposed to be signaling.
117 return ResultCode(ErrorDescription::AlreadyDone, ErrorModule::Kernel,
118 ErrorSummary::NothingHappened, ErrorLevel::Temporary);
129 } 119 }
130 return 0; 120 return RESULT_SUCCESS;
131} 121}
132 122
133/** 123/**
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 7d7b5137e..155449f95 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
@@ -13,9 +13,8 @@ namespace Kernel {
13/** 13/**
14 * Releases a mutex 14 * Releases a mutex
15 * @param handle Handle to mutex to release 15 * @param handle Handle to mutex to release
16 * @return Result of operation, 0 on success, otherwise error code
17 */ 16 */
18Result ReleaseMutex(Handle handle); 17ResultCode ReleaseMutex(Handle handle);
19 18
20/** 19/**
21 * Creates a mutex 20 * Creates a mutex
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index f538c6550..cfcc0e0b7 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common.h" 5#include "common/common.h"
6 6
@@ -16,15 +16,10 @@ public:
16 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; } 16 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; }
17 Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; } 17 Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; }
18 18
19 /** 19 ResultVal<bool> WaitSynchronization() override {
20 * Wait for kernel object to synchronize
21 * @param wait Boolean wait set if current thread should wait as a result of sync operation
22 * @return Result of operation, 0 on success, otherwise error code
23 */
24 Result WaitSynchronization(bool* wait) override {
25 // TODO(bunnei): ImplementMe 20 // TODO(bunnei): ImplementMe
26 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)"); 21 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
27 return 0; 22 return UnimplementedFunction(ErrorModule::OS);
28 } 23 }
29 24
30 u32 base_address; ///< Address of shared memory block in RAM 25 u32 base_address; ///< Address of shared memory block in RAM
@@ -48,11 +43,6 @@ SharedMemory* CreateSharedMemory(Handle& handle, const std::string& name) {
48 return shared_memory; 43 return shared_memory;
49} 44}
50 45
51/**
52 * Creates a shared memory object
53 * @param name Optional name of shared memory object
54 * @return Handle of newly created shared memory object
55 */
56Handle CreateSharedMemory(const std::string& name) { 46Handle CreateSharedMemory(const std::string& name) {
57 Handle handle; 47 Handle handle;
58 CreateSharedMemory(handle, name); 48 CreateSharedMemory(handle, name);
@@ -67,39 +57,36 @@ Handle CreateSharedMemory(const std::string& name) {
67 * @param other_permissions Memory block map other permissions (specified by SVC field) 57 * @param other_permissions Memory block map other permissions (specified by SVC field)
68 * @return Result of operation, 0 on success, otherwise error code 58 * @return Result of operation, 0 on success, otherwise error code
69 */ 59 */
70Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, 60ResultCode MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions,
71 MemoryPermission other_permissions) { 61 MemoryPermission other_permissions) {
72 62
73 if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { 63 if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) {
74 ERROR_LOG(KERNEL, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", 64 ERROR_LOG(KERNEL, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!",
75 handle, address); 65 handle, address);
76 return -1; 66 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
67 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
77 } 68 }
78 SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle); 69 SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle);
79 _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle); 70 if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel);
80 71
81 shared_memory->base_address = address; 72 shared_memory->base_address = address;
82 shared_memory->permissions = permissions; 73 shared_memory->permissions = permissions;
83 shared_memory->other_permissions = other_permissions; 74 shared_memory->other_permissions = other_permissions;
84 75
85 return 0; 76 return RESULT_SUCCESS;
86} 77}
87 78
88/** 79ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) {
89 * Gets a pointer to the shared memory block 80 SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle);
90 * @param handle Shared memory block handle 81 if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel);
91 * @param offset Offset from the start of the shared memory block to get pointer
92 * @return Pointer to the shared memory block from the specified offset
93 */
94u8* GetSharedMemoryPointer(Handle handle, u32 offset) {
95 SharedMemory* shared_memory = Kernel::g_object_pool.GetFast<SharedMemory>(handle);
96 _assert_msg_(KERNEL, (shared_memory != nullptr), "handle 0x%08X is not valid!", handle);
97 82
98 if (0 != shared_memory->base_address) 83 if (0 != shared_memory->base_address)
99 return Memory::GetPointer(shared_memory->base_address + offset); 84 return MakeResult<u8*>(Memory::GetPointer(shared_memory->base_address + offset));
100 85
101 ERROR_LOG(KERNEL, "memory block handle=0x%08X not mapped!", handle); 86 ERROR_LOG(KERNEL, "memory block handle=0x%08X not mapped!", handle);
102 return nullptr; 87 // TODO(yuriks): Verify error code.
88 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
89 ErrorSummary::InvalidState, ErrorLevel::Permanent);
103} 90}
104 91
105} // namespace 92} // namespace
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 5312b8854..304cf5b67 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
@@ -32,9 +32,8 @@ Handle CreateSharedMemory(const std::string& name="Unknown");
32 * @param address Address in system memory to map shared memory block to 32 * @param address Address in system memory to map shared memory block to
33 * @param permissions Memory block map permissions (specified by SVC field) 33 * @param permissions Memory block map permissions (specified by SVC field)
34 * @param other_permissions Memory block map other permissions (specified by SVC field) 34 * @param other_permissions Memory block map other permissions (specified by SVC field)
35 * @return Result of operation, 0 on success, otherwise error code
36 */ 35 */
37Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions, 36ResultCode MapSharedMemory(Handle handle, u32 address, MemoryPermission permissions,
38 MemoryPermission other_permissions); 37 MemoryPermission other_permissions);
39 38
40/** 39/**
@@ -43,6 +42,6 @@ Result MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions,
43 * @param offset Offset from the start of the shared memory block to get pointer 42 * @param offset Offset from the start of the shared memory block to get pointer
44 * @return Pointer to the shared memory block from the specified offset 43 * @return Pointer to the shared memory block from the specified offset
45 */ 44 */
46u8* GetSharedMemoryPointer(Handle handle, u32 offset); 45ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset);
47 46
48} // namespace 47} // namespace
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index e15590c49..f59795901 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project / PPSSPP Project 1// Copyright 2014 Citra Emulator Project / PPSSPP Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <list> 6#include <list>
@@ -11,10 +11,11 @@
11#include "common/thread_queue_list.h" 11#include "common/thread_queue_list.h"
12 12
13#include "core/core.h" 13#include "core/core.h"
14#include "core/mem_map.h"
15#include "core/hle/hle.h" 14#include "core/hle/hle.h"
16#include "core/hle/kernel/kernel.h" 15#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/thread.h" 16#include "core/hle/kernel/thread.h"
17#include "core/hle/result.h"
18#include "core/mem_map.h"
18 19
19namespace Kernel { 20namespace Kernel {
20 21
@@ -33,21 +34,17 @@ public:
33 inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; } 34 inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; }
34 inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; } 35 inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
35 36
36 /** 37 ResultVal<bool> WaitSynchronization() override {
37 * Wait for kernel object to synchronize 38 const bool wait = status != THREADSTATUS_DORMANT;
38 * @param wait Boolean wait set if current thread should wait as a result of sync operation 39 if (wait) {
39 * @return Result of operation, 0 on success, otherwise error code
40 */
41 Result WaitSynchronization(bool* wait) override {
42 if (status != THREADSTATUS_DORMANT) {
43 Handle thread = GetCurrentThreadHandle(); 40 Handle thread = GetCurrentThreadHandle();
44 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) { 41 if (std::find(waiting_threads.begin(), waiting_threads.end(), thread) == waiting_threads.end()) {
45 waiting_threads.push_back(thread); 42 waiting_threads.push_back(thread);
46 } 43 }
47 WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle()); 44 WaitCurrentThread(WAITTYPE_THREADEND, this->GetHandle());
48 *wait = true;
49 } 45 }
50 return 0; 46
47 return MakeResult<bool>(wait);
51 } 48 }
52 49
53 ThreadContext context; 50 ThreadContext context;
@@ -71,17 +68,17 @@ public:
71}; 68};
72 69
73// Lists all thread ids that aren't deleted/etc. 70// Lists all thread ids that aren't deleted/etc.
74std::vector<Handle> g_thread_queue; 71static std::vector<Handle> thread_queue;
75 72
76// Lists only ready thread ids. 73// Lists only ready thread ids.
77Common::ThreadQueueList<Handle> g_thread_ready_queue; 74static Common::ThreadQueueList<Handle> thread_ready_queue;
78 75
79Handle g_current_thread_handle; 76static Handle current_thread_handle;
80Thread* g_current_thread; 77static Thread* current_thread;
81 78
82/// Gets the current thread 79/// Gets the current thread
83inline Thread* GetCurrentThread() { 80inline Thread* GetCurrentThread() {
84 return g_current_thread; 81 return current_thread;
85} 82}
86 83
87/// Gets the current thread handle 84/// Gets the current thread handle
@@ -91,8 +88,8 @@ Handle GetCurrentThreadHandle() {
91 88
92/// Sets the current thread 89/// Sets the current thread
93inline void SetCurrentThread(Thread* t) { 90inline void SetCurrentThread(Thread* t) {
94 g_current_thread = t; 91 current_thread = t;
95 g_current_thread_handle = t->GetHandle(); 92 current_thread_handle = t->GetHandle();
96} 93}
97 94
98/// Saves the current CPU context 95/// Saves the current CPU context
@@ -113,7 +110,7 @@ void ResetThread(Thread* t, u32 arg, s32 lowest_priority) {
113 t->context.pc = t->context.reg_15 = t->entry_point; 110 t->context.pc = t->context.reg_15 = t->entry_point;
114 t->context.sp = t->stack_top; 111 t->context.sp = t->stack_top;
115 t->context.cpsr = 0x1F; // Usermode 112 t->context.cpsr = 0x1F; // Usermode
116 113
117 // TODO(bunnei): This instructs the CPU core to start the execution as if it is "resuming" a 114 // TODO(bunnei): This instructs the CPU core to start the execution as if it is "resuming" a
118 // thread. This is somewhat Sky-Eye specific, and should be re-architected in the future to be 115 // thread. This is somewhat Sky-Eye specific, and should be re-architected in the future to be
119 // agnostic of the CPU core. 116 // agnostic of the CPU core.
@@ -131,40 +128,35 @@ void ChangeReadyState(Thread* t, bool ready) {
131 Handle handle = t->GetHandle(); 128 Handle handle = t->GetHandle();
132 if (t->IsReady()) { 129 if (t->IsReady()) {
133 if (!ready) { 130 if (!ready) {
134 g_thread_ready_queue.remove(t->current_priority, handle); 131 thread_ready_queue.remove(t->current_priority, handle);
135 } 132 }
136 } else if (ready) { 133 } else if (ready) {
137 if (t->IsRunning()) { 134 if (t->IsRunning()) {
138 g_thread_ready_queue.push_front(t->current_priority, handle); 135 thread_ready_queue.push_front(t->current_priority, handle);
139 } else { 136 } else {
140 g_thread_ready_queue.push_back(t->current_priority, handle); 137 thread_ready_queue.push_back(t->current_priority, handle);
141 } 138 }
142 t->status = THREADSTATUS_READY; 139 t->status = THREADSTATUS_READY;
143 } 140 }
144} 141}
145 142
146/// Verify that a thread has not been released from waiting 143/// Verify that a thread has not been released from waiting
147inline bool VerifyWait(const Handle& handle, WaitType type, Handle wait_handle) { 144inline bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) {
148 Thread* thread = g_object_pool.GetFast<Thread>(handle); 145 _dbg_assert_(KERNEL, thread != nullptr);
149 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 146 return (type == thread->wait_type) && (wait_handle == thread->wait_handle) && (thread->IsWaiting());
150
151 if (type != thread->wait_type || wait_handle != thread->wait_handle)
152 return false;
153
154 return true;
155} 147}
156 148
157/// Stops the current thread 149/// Stops the current thread
158void StopThread(Handle handle, const char* reason) { 150ResultCode StopThread(Handle handle, const char* reason) {
159 Thread* thread = g_object_pool.GetFast<Thread>(handle); 151 Thread* thread = g_object_pool.Get<Thread>(handle);
160 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 152 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
161 153
162 ChangeReadyState(thread, false); 154 ChangeReadyState(thread, false);
163 thread->status = THREADSTATUS_DORMANT; 155 thread->status = THREADSTATUS_DORMANT;
164 for (size_t i = 0; i < thread->waiting_threads.size(); ++i) { 156 for (Handle waiting_handle : thread->waiting_threads) {
165 const Handle waiting_thread = thread->waiting_threads[i]; 157 Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle);
166 if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { 158 if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) {
167 ResumeThreadFromWait(waiting_thread); 159 ResumeThreadFromWait(waiting_handle);
168 } 160 }
169 } 161 }
170 thread->waiting_threads.clear(); 162 thread->waiting_threads.clear();
@@ -172,6 +164,8 @@ void StopThread(Handle handle, const char* reason) {
172 // Stopped threads are never waiting. 164 // Stopped threads are never waiting.
173 thread->wait_type = WAITTYPE_NONE; 165 thread->wait_type = WAITTYPE_NONE;
174 thread->wait_handle = 0; 166 thread->wait_handle = 0;
167
168 return RESULT_SUCCESS;
175} 169}
176 170
177/// Changes a threads state 171/// Changes a threads state
@@ -181,7 +175,7 @@ void ChangeThreadState(Thread* t, ThreadStatus new_status) {
181 } 175 }
182 ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0); 176 ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0);
183 t->status = new_status; 177 t->status = new_status;
184 178
185 if (new_status == THREADSTATUS_WAIT) { 179 if (new_status == THREADSTATUS_WAIT) {
186 if (t->wait_type == WAITTYPE_NONE) { 180 if (t->wait_type == WAITTYPE_NONE) {
187 ERROR_LOG(KERNEL, "Waittype none not allowed"); 181 ERROR_LOG(KERNEL, "Waittype none not allowed");
@@ -195,13 +189,15 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
195 s32 priority = THREADPRIO_LOWEST; 189 s32 priority = THREADPRIO_LOWEST;
196 190
197 // Iterate through threads, find highest priority thread that is waiting to be arbitrated... 191 // Iterate through threads, find highest priority thread that is waiting to be arbitrated...
198 for (const auto& handle : g_thread_queue) { 192 for (Handle handle : thread_queue) {
193 Thread* thread = g_object_pool.Get<Thread>(handle);
199 194
200 // TODO(bunnei): Verify arbiter address... 195 // TODO(bunnei): Verify arbiter address...
201 if (!VerifyWait(handle, WAITTYPE_ARB, arbiter)) 196 if (!VerifyWait(thread, WAITTYPE_ARB, arbiter))
202 continue; 197 continue;
203 198
204 Thread* thread = g_object_pool.GetFast<Thread>(handle); 199 if (thread == nullptr)
200 continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up.
205 if(thread->current_priority <= priority) { 201 if(thread->current_priority <= priority) {
206 highest_priority_thread = handle; 202 highest_priority_thread = handle;
207 priority = thread->current_priority; 203 priority = thread->current_priority;
@@ -216,12 +212,13 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
216 212
217/// Arbitrate all threads currently waiting 213/// Arbitrate all threads currently waiting
218void ArbitrateAllThreads(u32 arbiter, u32 address) { 214void ArbitrateAllThreads(u32 arbiter, u32 address) {
219 215
220 // Iterate through threads, find highest priority thread that is waiting to be arbitrated... 216 // Iterate through threads, find highest priority thread that is waiting to be arbitrated...
221 for (const auto& handle : g_thread_queue) { 217 for (Handle handle : thread_queue) {
218 Thread* thread = g_object_pool.Get<Thread>(handle);
222 219
223 // TODO(bunnei): Verify arbiter address... 220 // TODO(bunnei): Verify arbiter address...
224 if (VerifyWait(handle, WAITTYPE_ARB, arbiter)) 221 if (VerifyWait(thread, WAITTYPE_ARB, arbiter))
225 ResumeThreadFromWait(handle); 222 ResumeThreadFromWait(handle);
226 } 223 }
227} 224}
@@ -238,11 +235,11 @@ void CallThread(Thread* t) {
238/// Switches CPU context to that of the specified thread 235/// Switches CPU context to that of the specified thread
239void SwitchContext(Thread* t) { 236void SwitchContext(Thread* t) {
240 Thread* cur = GetCurrentThread(); 237 Thread* cur = GetCurrentThread();
241 238
242 // Save context for current thread 239 // Save context for current thread
243 if (cur) { 240 if (cur) {
244 SaveContext(cur->context); 241 SaveContext(cur->context);
245 242
246 if (cur->IsRunning()) { 243 if (cur->IsRunning()) {
247 ChangeReadyState(cur, true); 244 ChangeReadyState(cur, true);
248 } 245 }
@@ -263,16 +260,16 @@ void SwitchContext(Thread* t) {
263Thread* NextThread() { 260Thread* NextThread() {
264 Handle next; 261 Handle next;
265 Thread* cur = GetCurrentThread(); 262 Thread* cur = GetCurrentThread();
266 263
267 if (cur && cur->IsRunning()) { 264 if (cur && cur->IsRunning()) {
268 next = g_thread_ready_queue.pop_first_better(cur->current_priority); 265 next = thread_ready_queue.pop_first_better(cur->current_priority);
269 } else { 266 } else {
270 next = g_thread_ready_queue.pop_first(); 267 next = thread_ready_queue.pop_first();
271 } 268 }
272 if (next == 0) { 269 if (next == 0) {
273 return nullptr; 270 return nullptr;
274 } 271 }
275 return Kernel::g_object_pool.GetFast<Thread>(next); 272 return Kernel::g_object_pool.Get<Thread>(next);
276} 273}
277 274
278/** 275/**
@@ -289,8 +286,7 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
289 286
290/// Resumes a thread from waiting by marking it as "ready" 287/// Resumes a thread from waiting by marking it as "ready"
291void ResumeThreadFromWait(Handle handle) { 288void ResumeThreadFromWait(Handle handle) {
292 u32 error; 289 Thread* thread = Kernel::g_object_pool.Get<Thread>(handle);
293 Thread* thread = Kernel::g_object_pool.Get<Thread>(handle, error);
294 if (thread) { 290 if (thread) {
295 thread->status &= ~THREADSTATUS_WAIT; 291 thread->status &= ~THREADSTATUS_WAIT;
296 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { 292 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
@@ -306,9 +302,9 @@ void DebugThreadQueue() {
306 return; 302 return;
307 } 303 }
308 INFO_LOG(KERNEL, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThreadHandle()); 304 INFO_LOG(KERNEL, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThreadHandle());
309 for (u32 i = 0; i < g_thread_queue.size(); i++) { 305 for (u32 i = 0; i < thread_queue.size(); i++) {
310 Handle handle = g_thread_queue[i]; 306 Handle handle = thread_queue[i];
311 s32 priority = g_thread_ready_queue.contains(handle); 307 s32 priority = thread_ready_queue.contains(handle);
312 if (priority != -1) { 308 if (priority != -1) {
313 INFO_LOG(KERNEL, "0x%02X 0x%08X", priority, handle); 309 INFO_LOG(KERNEL, "0x%02X 0x%08X", priority, handle);
314 } 310 }
@@ -319,15 +315,15 @@ void DebugThreadQueue() {
319Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority, 315Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority,
320 s32 processor_id, u32 stack_top, int stack_size) { 316 s32 processor_id, u32 stack_top, int stack_size) {
321 317
322 _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST), 318 _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST),
323 "CreateThread priority=%d, outside of allowable range!", priority) 319 "CreateThread priority=%d, outside of allowable range!", priority)
324 320
325 Thread* thread = new Thread; 321 Thread* thread = new Thread;
326 322
327 handle = Kernel::g_object_pool.Create(thread); 323 handle = Kernel::g_object_pool.Create(thread);
328 324
329 g_thread_queue.push_back(handle); 325 thread_queue.push_back(handle);
330 g_thread_ready_queue.prepare(priority); 326 thread_ready_queue.prepare(priority);
331 327
332 thread->status = THREADSTATUS_DORMANT; 328 thread->status = THREADSTATUS_DORMANT;
333 thread->entry_point = entry_point; 329 thread->entry_point = entry_point;
@@ -351,7 +347,7 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3
351 return -1; 347 return -1;
352 } 348 }
353 if ((u32)stack_size < 0x200) { 349 if ((u32)stack_size < 0x200) {
354 ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid stack_size=0x%08X", name, 350 ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid stack_size=0x%08X", name,
355 stack_size); 351 stack_size);
356 return -1; 352 return -1;
357 } 353 }
@@ -368,7 +364,7 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3
368 return -1; 364 return -1;
369 } 365 }
370 Handle handle; 366 Handle handle;
371 Thread* thread = CreateThread(handle, name, entry_point, priority, processor_id, stack_top, 367 Thread* thread = CreateThread(handle, name, entry_point, priority, processor_id, stack_top,
372 stack_size); 368 stack_size);
373 369
374 ResetThread(thread, arg, 0); 370 ResetThread(thread, arg, 0);
@@ -378,19 +374,23 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3
378} 374}
379 375
380/// Get the priority of the thread specified by handle 376/// Get the priority of the thread specified by handle
381u32 GetThreadPriority(const Handle handle) { 377ResultVal<u32> GetThreadPriority(const Handle handle) {
382 Thread* thread = g_object_pool.GetFast<Thread>(handle); 378 Thread* thread = g_object_pool.Get<Thread>(handle);
383 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 379 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
384 return thread->current_priority; 380
381 return MakeResult<u32>(thread->current_priority);
385} 382}
386 383
387/// Set the priority of the thread specified by handle 384/// Set the priority of the thread specified by handle
388Result SetThreadPriority(Handle handle, s32 priority) { 385ResultCode SetThreadPriority(Handle handle, s32 priority) {
389 Thread* thread = nullptr; 386 Thread* thread = nullptr;
390 if (!handle) { 387 if (!handle) {
391 thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? 388 thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior?
392 } else { 389 } else {
393 thread = g_object_pool.GetFast<Thread>(handle); 390 thread = g_object_pool.Get<Thread>(handle);
391 if (thread == nullptr) {
392 return InvalidHandle(ErrorModule::Kernel);
393 }
394 } 394 }
395 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!"); 395 _assert_msg_(KERNEL, (thread != nullptr), "called, but thread is nullptr!");
396 396
@@ -405,37 +405,37 @@ Result SetThreadPriority(Handle handle, s32 priority) {
405 405
406 // Change thread priority 406 // Change thread priority
407 s32 old = thread->current_priority; 407 s32 old = thread->current_priority;
408 g_thread_ready_queue.remove(old, handle); 408 thread_ready_queue.remove(old, handle);
409 thread->current_priority = priority; 409 thread->current_priority = priority;
410 g_thread_ready_queue.prepare(thread->current_priority); 410 thread_ready_queue.prepare(thread->current_priority);
411 411
412 // Change thread status to "ready" and push to ready queue 412 // Change thread status to "ready" and push to ready queue
413 if (thread->IsRunning()) { 413 if (thread->IsRunning()) {
414 thread->status = (thread->status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY; 414 thread->status = (thread->status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY;
415 } 415 }
416 if (thread->IsReady()) { 416 if (thread->IsReady()) {
417 g_thread_ready_queue.push_back(thread->current_priority, handle); 417 thread_ready_queue.push_back(thread->current_priority, handle);
418 } 418 }
419 419
420 return 0; 420 return RESULT_SUCCESS;
421} 421}
422 422
423/// Sets up the primary application thread 423/// Sets up the primary application thread
424Handle SetupMainThread(s32 priority, int stack_size) { 424Handle SetupMainThread(s32 priority, int stack_size) {
425 Handle handle; 425 Handle handle;
426 426
427 // Initialize new "main" thread 427 // Initialize new "main" thread
428 Thread* thread = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority, 428 Thread* thread = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority,
429 THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size); 429 THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size);
430 430
431 ResetThread(thread, 0, 0); 431 ResetThread(thread, 0, 0);
432 432
433 // If running another thread already, set it to "ready" state 433 // If running another thread already, set it to "ready" state
434 Thread* cur = GetCurrentThread(); 434 Thread* cur = GetCurrentThread();
435 if (cur && cur->IsRunning()) { 435 if (cur && cur->IsRunning()) {
436 ChangeReadyState(cur, true); 436 ChangeReadyState(cur, true);
437 } 437 }
438 438
439 // Run new "main" thread 439 // Run new "main" thread
440 SetCurrentThread(thread); 440 SetCurrentThread(thread);
441 thread->status = THREADSTATUS_RUNNING; 441 thread->status = THREADSTATUS_RUNNING;
@@ -452,12 +452,12 @@ void Reschedule() {
452 HLE::g_reschedule = false; 452 HLE::g_reschedule = false;
453 if (next > 0) { 453 if (next > 0) {
454 INFO_LOG(KERNEL, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle()); 454 INFO_LOG(KERNEL, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle());
455 455
456 SwitchContext(next); 456 SwitchContext(next);
457 457
458 // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep 458 // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep
459 // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again. 459 // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again.
460 // This results in the current thread yielding on a VBLANK once, and then it will be 460 // This results in the current thread yielding on a VBLANK once, and then it will be
461 // immediately placed back in the queue for execution. 461 // immediately placed back in the queue for execution.
462 if (prev->wait_type == WAITTYPE_VBLANK) { 462 if (prev->wait_type == WAITTYPE_VBLANK) {
463 ResumeThreadFromWait(prev->GetHandle()); 463 ResumeThreadFromWait(prev->GetHandle());
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 39fa38b75..ce63a70d3 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -1,11 +1,12 @@
1// Copyright 2014 Citra Emulator Project / PPSSPP Project 1// Copyright 2014 Citra Emulator Project / PPSSPP Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/hle/kernel/kernel.h" 8#include "core/hle/kernel/kernel.h"
9#include "core/hle/result.h"
9 10
10enum ThreadPriority { 11enum ThreadPriority {
11 THREADPRIO_HIGHEST = 0, ///< Highest thread priority 12 THREADPRIO_HIGHEST = 0, ///< Highest thread priority
@@ -55,7 +56,7 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE);
55void Reschedule(); 56void Reschedule();
56 57
57/// Stops the current thread 58/// Stops the current thread
58void StopThread(Handle thread, const char* reason); 59ResultCode StopThread(Handle thread, const char* reason);
59 60
60/// Resumes a thread from waiting by marking it as "ready" 61/// Resumes a thread from waiting by marking it as "ready"
61void ResumeThreadFromWait(Handle handle); 62void ResumeThreadFromWait(Handle handle);
@@ -80,10 +81,10 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHa
80void WaitThread_Synchronization(); 81void WaitThread_Synchronization();
81 82
82/// Get the priority of the thread specified by handle 83/// Get the priority of the thread specified by handle
83u32 GetThreadPriority(const Handle handle); 84ResultVal<u32> GetThreadPriority(const Handle handle);
84 85
85/// Set the priority of the thread specified by handle 86/// Set the priority of the thread specified by handle
86Result SetThreadPriority(Handle handle, s32 priority); 87ResultCode SetThreadPriority(Handle handle, s32 priority);
87 88
88/// Initialize threading 89/// Initialize threading
89void ThreadingInit(); 90void ThreadingInit();
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
new file mode 100644
index 000000000..15c4a2677
--- /dev/null
+++ b/src/core/hle/result.h
@@ -0,0 +1,400 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cassert>
8#include <cstddef>
9#include <type_traits>
10#include <utility>
11
12#include "common/common_types.h"
13#include "common/bit_field.h"
14
15// All the constants in this file come from http://3dbrew.org/wiki/Error_codes
16
17/// Detailed description of the error. This listing is likely incomplete.
18enum class ErrorDescription : u32 {
19 Success = 0,
20 InvalidSection = 1000,
21 TooLarge = 1001,
22 NotAuthorized = 1002,
23 AlreadyDone = 1003,
24 InvalidSize = 1004,
25 InvalidEnumValue = 1005,
26 InvalidCombination = 1006,
27 NoData = 1007,
28 Busy = 1008,
29 MisalignedAddress = 1009,
30 MisalignedSize = 1010,
31 OutOfMemory = 1011,
32 NotImplemented = 1012,
33 InvalidAddress = 1013,
34 InvalidPointer = 1014,
35 InvalidHandle = 1015,
36 NotInitialized = 1016,
37 AlreadyInitialized = 1017,
38 NotFound = 1018,
39 CancelRequested = 1019,
40 AlreadyExists = 1020,
41 OutOfRange = 1021,
42 Timeout = 1022,
43 InvalidResultValue = 1023,
44};
45
46/**
47 * Identifies the module which caused the error. Error codes can be propagated through a call
48 * chain, meaning that this doesn't always correspond to the module where the API call made is
49 * contained.
50 */
51enum class ErrorModule : u32 {
52 Common = 0,
53 Kernel = 1,
54 Util = 2,
55 FileServer = 3,
56 LoaderServer = 4,
57 TCB = 5,
58 OS = 6,
59 DBG = 7,
60 DMNT = 8,
61 PDN = 9,
62 GX = 10,
63 I2C = 11,
64 GPIO = 12,
65 DD = 13,
66 CODEC = 14,
67 SPI = 15,
68 PXI = 16,
69 FS = 17,
70 DI = 18,
71 HID = 19,
72 CAM = 20,
73 PI = 21,
74 PM = 22,
75 PM_LOW = 23,
76 FSI = 24,
77 SRV = 25,
78 NDM = 26,
79 NWM = 27,
80 SOC = 28,
81 LDR = 29,
82 ACC = 30,
83 RomFS = 31,
84 AM = 32,
85 HIO = 33,
86 Updater = 34,
87 MIC = 35,
88 FND = 36,
89 MP = 37,
90 MPWL = 38,
91 AC = 39,
92 HTTP = 40,
93 DSP = 41,
94 SND = 42,
95 DLP = 43,
96 HIO_LOW = 44,
97 CSND = 45,
98 SSL = 46,
99 AM_LOW = 47,
100 NEX = 48,
101 Friends = 49,
102 RDT = 50,
103 Applet = 51,
104 NIM = 52,
105 PTM = 53,
106 MIDI = 54,
107 MC = 55,
108 SWC = 56,
109 FatFS = 57,
110 NGC = 58,
111 CARD = 59,
112 CARDNOR = 60,
113 SDMC = 61,
114 BOSS = 62,
115 DBM = 63,
116 Config = 64,
117 PS = 65,
118 CEC = 66,
119 IR = 67,
120 UDS = 68,
121 PL = 69,
122 CUP = 70,
123 Gyroscope = 71,
124 MCU = 72,
125 NS = 73,
126 News = 74,
127 RO_1 = 75,
128 GD = 76,
129 CardSPI = 77,
130 EC = 78,
131 RO_2 = 79,
132 WebBrowser = 80,
133 Test = 81,
134 ENC = 82,
135 PIA = 83,
136
137 Application = 254,
138 InvalidResult = 255
139};
140
141/// A less specific error cause.
142enum class ErrorSummary : u32 {
143 Success = 0,
144 NothingHappened = 1,
145 WouldBlock = 2,
146 OutOfResource = 3, ///< There are no more kernel resources (memory, table slots) to
147 ///< execute the operation.
148 NotFound = 4, ///< A file or resource was not found.
149 InvalidState = 5,
150 NotSupported = 6, ///< The operation is not supported or not implemented.
151 InvalidArgument = 7, ///< Returned when a passed argument is invalid in the current runtime
152 ///< context. (Invalid handle, out-of-bounds pointer or size, etc.)
153 WrongArgument = 8, ///< Returned when a passed argument is in an incorrect format for use
154 ///< with the function. (E.g. Invalid enum value)
155 Canceled = 9,
156 StatusChanged = 10,
157 Internal = 11,
158
159 InvalidResult = 63
160};
161
162/// The severity of the error.
163enum class ErrorLevel : u32 {
164 Success = 0,
165 Info = 1,
166
167 Status = 25,
168 Temporary = 26,
169 Permanent = 27,
170 Usage = 28,
171 Reinitialize = 29,
172 Reset = 30,
173 Fatal = 31
174};
175
176/// Encapsulates a CTR-OS error code, allowing it to be separated into its constituent fields.
177union ResultCode {
178 u32 raw;
179
180 BitField<0, 10, ErrorDescription> description;
181 BitField<10, 8, ErrorModule> module;
182
183 BitField<21, 6, ErrorSummary> summary;
184 BitField<27, 5, ErrorLevel> level;
185
186 // The last bit of `level` is checked by apps and the kernel to determine if a result code is an error
187 BitField<31, 1, u32> is_error;
188
189 explicit ResultCode(u32 raw) : raw(raw) {}
190 ResultCode(ErrorDescription description_, ErrorModule module_,
191 ErrorSummary summary_, ErrorLevel level_) : raw(0) {
192 description = description_;
193 module = module_;
194 summary = summary_;
195 level = level_;
196 }
197
198 ResultCode& operator=(const ResultCode& o) { raw = o.raw; return *this; }
199
200 bool IsSuccess() const {
201 return is_error == 0;
202 }
203
204 bool IsError() const {
205 return is_error == 1;
206 }
207};
208
209inline bool operator==(const ResultCode a, const ResultCode b) {
210 return a.raw == b.raw;
211}
212
213inline bool operator!=(const ResultCode a, const ResultCode b) {
214 return a.raw != b.raw;
215}
216
217// Convenience functions for creating some common kinds of errors:
218
219/// The default success `ResultCode`.
220const ResultCode RESULT_SUCCESS(0);
221
222/// Might be returned instead of a dummy success for unimplemented APIs.
223inline ResultCode UnimplementedFunction(ErrorModule module) {
224 return ResultCode(ErrorDescription::NotImplemented, module,
225 ErrorSummary::NotSupported, ErrorLevel::Permanent);
226}
227/// Returned when a function is passed an invalid handle.
228inline ResultCode InvalidHandle(ErrorModule module) {
229 return ResultCode(ErrorDescription::InvalidHandle, module,
230 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
231}
232
233/**
234 * This is an optional value type. It holds a `ResultCode` and, if that code is a success code,
235 * also holds a result of type `T`. If the code is an error code then trying to access the inner
236 * value fails, thus ensuring that the ResultCode of functions is always checked properly before
237 * their return value is used. It is similar in concept to the `std::optional` type
238 * (http://en.cppreference.com/w/cpp/experimental/optional) originally proposed for inclusion in
239 * C++14, or the `Result` type in Rust (http://doc.rust-lang.org/std/result/index.html).
240 *
241 * An example of how it could be used:
242 * \code
243 * ResultVal<int> Frobnicate(float strength) {
244 * if (strength < 0.f || strength > 1.0f) {
245 * // Can't frobnicate too weakly or too strongly
246 * return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Common,
247 * ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
248 * } else {
249 * // Frobnicated! Give caller a cookie
250 * return MakeResult<int>(42);
251 * }
252 * }
253 * \endcode
254 *
255 * \code
256 * ResultVal<int> frob_result = Frobnicate(0.75f);
257 * if (frob_result) {
258 * // Frobbed ok
259 * printf("My cookie is %d\n", *frob_result);
260 * } else {
261 * printf("Guess I overdid it. :( Error code: %ux\n", frob_result.code().hex);
262 * }
263 * \endcode
264 */
265template <typename T>
266class ResultVal {
267public:
268 /// Constructs an empty `ResultVal` with the given error code. The code must not be a success code.
269 ResultVal(ResultCode error_code = ResultCode(-1))
270 : result_code(error_code)
271 {
272 assert(error_code.IsError());
273 UpdateDebugPtr();
274 }
275
276 /**
277 * Similar to the non-member function `MakeResult`, with the exception that you can manually
278 * specify the success code. `success_code` must not be an error code.
279 */
280 template <typename... Args>
281 static ResultVal WithCode(ResultCode success_code, Args&&... args) {
282 ResultVal<T> result;
283 result.emplace(success_code, std::forward<Args>(args)...);
284 return result;
285 }
286
287 ResultVal(const ResultVal& o)
288 : result_code(o.result_code)
289 {
290 if (!o.empty()) {
291 new (&storage) T(*o.GetPointer());
292 }
293 UpdateDebugPtr();
294 }
295
296 ResultVal(ResultVal&& o)
297 : result_code(o.result_code)
298 {
299 if (!o.empty()) {
300 new (&storage) T(std::move(*o.GetPointer()));
301 }
302 UpdateDebugPtr();
303 }
304
305 ~ResultVal() {
306 if (!empty()) {
307 GetPointer()->~T();
308 }
309 }
310
311 ResultVal& operator=(const ResultVal& o) {
312 if (*this) {
313 if (o) {
314 *GetPointer() = *o.GetPointer();
315 } else {
316 GetPointer()->~T();
317 }
318 } else {
319 if (o) {
320 new (&storage) T(*o.GetPointer());
321 }
322 }
323 result_code = o.result_code;
324 UpdateDebugPtr();
325
326 return *this;
327 }
328
329 /**
330 * Replaces the current result with a new constructed result value in-place. The code must not
331 * be an error code.
332 */
333 template <typename... Args>
334 void emplace(ResultCode success_code, Args&&... args) {
335 assert(success_code.IsSuccess());
336 if (!empty()) {
337 GetPointer()->~T();
338 }
339 new (&storage) T(std::forward<Args>(args)...);
340 result_code = success_code;
341 UpdateDebugPtr();
342 }
343
344 /// Returns true if the `ResultVal` contains an error code and no value.
345 bool empty() const { return result_code.IsError(); }
346
347 /// Returns true if the `ResultVal` contains a return value.
348 bool Succeeded() const { return result_code.IsSuccess(); }
349 /// Returns true if the `ResultVal` contains an error code and no value.
350 bool Failed() const { return empty(); }
351
352 ResultCode Code() const { return result_code; }
353
354 const T& operator* () const { return *GetPointer(); }
355 T& operator* () { return *GetPointer(); }
356 const T* operator->() const { return GetPointer(); }
357 T* operator->() { return GetPointer(); }
358
359 /// Returns the value contained in this `ResultVal`, or the supplied default if it is missing.
360 template <typename U>
361 T ValueOr(U&& value) const {
362 return !empty() ? *GetPointer() : std::move(value);
363 }
364
365private:
366 typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type StorageType;
367
368 StorageType storage;
369 ResultCode result_code;
370#if _DEBUG
371 // The purpose of this pointer is to aid inspecting the type with a debugger, eliminating the
372 // need to cast `storage` to a pointer or pay attention to `result_code`.
373 const T* debug_ptr;
374#endif
375
376 void UpdateDebugPtr() {
377#if _DEBUG
378 debug_ptr = empty() ? nullptr : static_cast<const T*>(static_cast<const void*>(&storage));
379#endif
380 }
381
382 const T* GetPointer() const {
383 assert(!empty());
384 return static_cast<const T*>(static_cast<const void*>(&storage));
385 }
386
387 T* GetPointer() {
388 assert(!empty());
389 return static_cast<T*>(static_cast<void*>(&storage));
390 }
391};
392
393/**
394 * This function is a helper used to construct `ResultVal`s. It receives the arguments to construct
395 * `T` with and creates a success `ResultVal` contained the constructed value.
396 */
397template <typename T, typename... Args>
398ResultVal<T> MakeResult(Args&&... args) {
399 return ResultVal<T>::WithCode(RESULT_SUCCESS, std::forward<Args>(args)...);
400}
diff --git a/src/core/hle/service/ac_u.cpp b/src/core/hle/service/ac_u.cpp
index b39603bdf..9af96f6b8 100644
--- a/src/core/hle/service/ac_u.cpp
+++ b/src/core/hle/service/ac_u.cpp
@@ -22,12 +22,12 @@ const Interface::FunctionInfo FunctionTable[] = {
22 {0x000E0042, nullptr, "GetCurrentAPInfo"}, 22 {0x000E0042, nullptr, "GetCurrentAPInfo"},
23 {0x00100042, nullptr, "GetCurrentNZoneInfo"}, 23 {0x00100042, nullptr, "GetCurrentNZoneInfo"},
24 {0x00110042, nullptr, "GetNZoneApNumService"}, 24 {0x00110042, nullptr, "GetNZoneApNumService"},
25 {0x00240042, nullptr, "AddDenyApType "}, 25 {0x00240042, nullptr, "AddDenyApType"},
26 {0x00270002, nullptr, "GetInfraPriority "}, 26 {0x00270002, nullptr, "GetInfraPriority"},
27 {0x002D0082, nullptr, "SetRequestEulaVersion"}, 27 {0x002D0082, nullptr, "SetRequestEulaVersion"},
28 {0x00300004, nullptr, "RegisterDisconnectEvent"}, 28 {0x00300004, nullptr, "RegisterDisconnectEvent"},
29 {0x003C0042, nullptr, "GetAPSSIDList"}, 29 {0x003C0042, nullptr, "GetAPSSIDList"},
30 {0x003E0042, nullptr, "IsConnected "}, 30 {0x003E0042, nullptr, "IsConnected"},
31 {0x00400042, nullptr, "SetClientVersion"}, 31 {0x00400042, nullptr, "SetClientVersion"},
32}; 32};
33 33
diff --git a/src/core/hle/service/ac_u.h b/src/core/hle/service/ac_u.h
index 3c5958d27..c91b28353 100644
--- a/src/core/hle/service/ac_u.h
+++ b/src/core/hle/service/ac_u.h
@@ -9,7 +9,7 @@
9//////////////////////////////////////////////////////////////////////////////////////////////////// 9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace AC_U 10// Namespace AC_U
11 11
12// socket service "ac:u" 12// socket service "ac:u"
13 13
14namespace AC_U { 14namespace AC_U {
15 15
@@ -21,7 +21,7 @@ public:
21 * Gets the string port name used by CTROS for the service 21 * Gets the string port name used by CTROS for the service
22 * @return Port name of service 22 * @return Port name of service
23 */ 23 */
24 std::string GetPortName() const { 24 std::string GetPortName() const override {
25 return "ac:u"; 25 return "ac:u";
26 } 26 }
27}; 27};
diff --git a/src/core/hle/service/am_net.cpp b/src/core/hle/service/am_net.cpp
new file mode 100644
index 000000000..403cac353
--- /dev/null
+++ b/src/core/hle/service/am_net.cpp
@@ -0,0 +1,47 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/am_net.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace AM_NET
11
12namespace AM_NET {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x08010000, nullptr, "OpenTicket"},
16 {0x08020002, nullptr, "TicketAbortInstall"},
17 {0x08030002, nullptr, "TicketFinalizeInstall"},
18 {0x08040100, nullptr, "InstallTitleBegin"},
19 {0x08050000, nullptr, "InstallTitleAbort"},
20 {0x080600C0, nullptr, "InstallTitleResume"},
21 {0x08070000, nullptr, "InstallTitleAbortTMD"},
22 {0x08080000, nullptr, "InstallTitleFinish"},
23 {0x080A0000, nullptr, "OpenTMD"},
24 {0x080B0002, nullptr, "TMDAbortInstall"},
25 {0x080C0042, nullptr, "TMDFinalizeInstall"},
26 {0x080E0040, nullptr, "OpenContentCreate"},
27 {0x080F0002, nullptr, "ContentAbortInstall"},
28 {0x08100040, nullptr, "OpenContentResume"},
29 {0x08120002, nullptr, "ContentFinalizeInstall"},
30 {0x08130000, nullptr, "GetTotalContents"},
31 {0x08140042, nullptr, "GetContentIndexes"},
32 {0x08150044, nullptr, "GetContentsInfo"},
33 {0x08190108, nullptr, "Unknown"},
34 {0x081B00C2, nullptr, "InstallTitlesFinish"},
35};
36
37////////////////////////////////////////////////////////////////////////////////////////////////////
38// Interface class
39
40Interface::Interface() {
41 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
42}
43
44Interface::~Interface() {
45}
46
47} // namespace
diff --git a/src/core/hle/service/am_net.h b/src/core/hle/service/am_net.h
new file mode 100644
index 000000000..4816e1697
--- /dev/null
+++ b/src/core/hle/service/am_net.h
@@ -0,0 +1,27 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
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 ~Interface();
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const override {
23 return "am:net";
24 }
25};
26
27} // namespace
diff --git a/src/core/hle/service/apt_u.cpp b/src/core/hle/service/apt_u.cpp
index 4f41ec5f4..4bb05ce40 100644
--- a/src/core/hle/service/apt_u.cpp
+++ b/src/core/hle/service/apt_u.cpp
@@ -27,7 +27,7 @@ enum class SignalType : u32 {
27 27
28void Initialize(Service::Interface* self) { 28void Initialize(Service::Interface* self) {
29 u32* cmd_buff = Service::GetCommandBuffer(); 29 u32* cmd_buff = Service::GetCommandBuffer();
30 30
31 cmd_buff[3] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Menu"); // APT menu event handle 31 cmd_buff[3] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Menu"); // APT menu event handle
32 cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Pause"); // APT pause event handle 32 cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Pause"); // APT pause event handle
33 33
@@ -168,7 +168,7 @@ void AppletUtility(Service::Interface* self) {
168 cmd_buff[1] = 0; // No error 168 cmd_buff[1] = 0; // No error
169 169
170 WARN_LOG(KERNEL, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, " 170 WARN_LOG(KERNEL, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, "
171 "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size, 171 "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size,
172 buffer1_addr, buffer2_addr); 172 buffer1_addr, buffer2_addr);
173} 173}
174 174
diff --git a/src/core/hle/service/apt_u.h b/src/core/hle/service/apt_u.h
index 5af39e085..306730400 100644
--- a/src/core/hle/service/apt_u.h
+++ b/src/core/hle/service/apt_u.h
@@ -13,8 +13,8 @@ namespace APT_U {
13 13
14// Application and title launching service. These services handle signaling for home/power button as 14// Application and title launching service. These services handle signaling for home/power button as
15// well. Only one session for either APT service can be open at a time, normally processes close the 15// well. Only one session for either APT service can be open at a time, normally processes close the
16// service handle immediately once finished using the service. The commands for APT:U and APT:S are 16// service handle immediately once finished using the service. The commands for APT:U and APT:S are
17// exactly the same, however certain commands are only accessible with APT:S(NS module will call 17// exactly the same, however certain commands are only accessible with APT:S(NS module will call
18// svcBreak when the command isn't accessible). See http://3dbrew.org/wiki/NS#APT_Services. 18// svcBreak when the command isn't accessible). See http://3dbrew.org/wiki/NS#APT_Services.
19 19
20/// Interface to "APT:U" service 20/// Interface to "APT:U" service
diff --git a/src/core/hle/service/boss_u.cpp b/src/core/hle/service/boss_u.cpp
new file mode 100644
index 000000000..b2ff4a756
--- /dev/null
+++ b/src/core/hle/service/boss_u.cpp
@@ -0,0 +1,28 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/boss_u.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace BOSS_U
11
12namespace BOSS_U {
13
14 const Interface::FunctionInfo FunctionTable[] = {
15 {0x00020100, nullptr, "GetStorageInfo"},
16 };
17
18 ////////////////////////////////////////////////////////////////////////////////////////////////////
19 // Interface class
20
21 Interface::Interface() {
22 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
23 }
24
25 Interface::~Interface() {
26 }
27
28} // namespace
diff --git a/src/core/hle/service/boss_u.h b/src/core/hle/service/boss_u.h
new file mode 100644
index 000000000..af39b8e65
--- /dev/null
+++ b/src/core/hle/service/boss_u.h
@@ -0,0 +1,27 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
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
14 class Interface : public Service::Interface {
15 public:
16 Interface();
17 ~Interface();
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const {
23 return "boss:U";
24 }
25 };
26
27} // namespace
diff --git a/src/core/hle/service/cfg_i.cpp b/src/core/hle/service/cfg_i.cpp
new file mode 100644
index 000000000..88d13d459
--- /dev/null
+++ b/src/core/hle/service/cfg_i.cpp
@@ -0,0 +1,59 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/cfg_i.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace CFG_I
11
12namespace CFG_I {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x04010082, nullptr, "GetConfigInfoBlk8"},
16 {0x04020082, nullptr, "GetConfigInfoBlk4"},
17 {0x04030000, nullptr, "UpdateConfigNANDSavegame"},
18 {0x04040042, nullptr, "GetLocalFriendCodeSeedData"},
19 {0x04050000, nullptr, "GetLocalFriendCodeSeed"},
20 {0x04060000, nullptr, "SecureInfoGetRegion"},
21 {0x04070000, nullptr, "SecureInfoGetByte101"},
22 {0x04080042, nullptr, "SecureInfoGetSerialNo"},
23 {0x04090000, nullptr, "UpdateConfigBlk00040003"},
24 {0x08010082, nullptr, "GetConfigInfoBlk8"},
25 {0x08020082, nullptr, "GetConfigInfoBlk4"},
26 {0x08030000, nullptr, "UpdateConfigNANDSavegame"},
27 {0x080400C2, nullptr, "CreateConfigInfoBlk"},
28 {0x08050000, nullptr, "DeleteConfigNANDSavefile"},
29 {0x08060000, nullptr, "FormatConfig"},
30 {0x08070000, nullptr, "Unknown"},
31 {0x08080000, nullptr, "UpdateConfigBlk1"},
32 {0x08090000, nullptr, "UpdateConfigBlk2"},
33 {0x080A0000, nullptr, "UpdateConfigBlk3"},
34 {0x080B0082, nullptr, "SetGetLocalFriendCodeSeedData"},
35 {0x080C0042, nullptr, "SetLocalFriendCodeSeedSignature"},
36 {0x080D0000, nullptr, "DeleteCreateNANDLocalFriendCodeSeed"},
37 {0x080E0000, nullptr, "VerifySigLocalFriendCodeSeed"},
38 {0x080F0042, nullptr, "GetLocalFriendCodeSeedData"},
39 {0x08100000, nullptr, "GetLocalFriendCodeSeed"},
40 {0x08110084, nullptr, "SetSecureInfo"},
41 {0x08120000, nullptr, "DeleteCreateNANDSecureInfo"},
42 {0x08130000, nullptr, "VerifySigSecureInfo"},
43 {0x08140042, nullptr, "SecureInfoGetData"},
44 {0x08150042, nullptr, "SecureInfoGetSignature"},
45 {0x08160000, nullptr, "SecureInfoGetRegion"},
46 {0x08170000, nullptr, "SecureInfoGetByte101"},
47 {0x08180042, nullptr, "SecureInfoGetSerialNo"},
48};
49////////////////////////////////////////////////////////////////////////////////////////////////////
50// Interface class
51
52Interface::Interface() {
53 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
54}
55
56Interface::~Interface() {
57}
58
59} // namespace
diff --git a/src/core/hle/service/cfg_i.h b/src/core/hle/service/cfg_i.h
new file mode 100644
index 000000000..fe343c968
--- /dev/null
+++ b/src/core/hle/service/cfg_i.h
@@ -0,0 +1,27 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace CFG_I
11
12namespace CFG_I {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17 ~Interface();
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const override {
23 return "cfg:i";
24 }
25};
26
27} // namespace
diff --git a/src/core/hle/service/cfg_u.h b/src/core/hle/service/cfg_u.h
index 7525bd7c6..8075d19a8 100644
--- a/src/core/hle/service/cfg_u.h
+++ b/src/core/hle/service/cfg_u.h
@@ -19,7 +19,7 @@ public:
19 * Gets the string port name used by CTROS for the service 19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service 20 * @return Port name of service
21 */ 21 */
22 std::string GetPortName() const { 22 std::string GetPortName() const override {
23 return "cfg:u"; 23 return "cfg:u";
24 } 24 }
25}; 25};
diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp
new file mode 100644
index 000000000..6e59a9bf3
--- /dev/null
+++ b/src/core/hle/service/csnd_snd.cpp
@@ -0,0 +1,39 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/csnd_snd.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace CSND_SND
11
12namespace CSND_SND {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010140, nullptr, "Initialize"},
16 {0x00020000, nullptr, "Shutdown"},
17 {0x00030040, nullptr, "Unknown"},
18 {0x00040080, nullptr, "Unknown"},
19 {0x00050000, nullptr, "Unknown"},
20 {0x00060000, nullptr, "Unknown"},
21 {0x00070000, nullptr, "Unknown"},
22 {0x00080040, nullptr, "Unknown"},
23 {0x00090082, nullptr, "FlushDCache"},
24 {0x000A0082, nullptr, "StoreDCache"},
25 {0x000B0082, nullptr, "InvalidateDCache"},
26 {0x000C0000, nullptr, "Unknown"},
27};
28
29////////////////////////////////////////////////////////////////////////////////////////////////////
30// Interface class
31
32Interface::Interface() {
33 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
34}
35
36Interface::~Interface() {
37}
38
39} // namespace
diff --git a/src/core/hle/service/csnd_snd.h b/src/core/hle/service/csnd_snd.h
new file mode 100644
index 000000000..31cc85b07
--- /dev/null
+++ b/src/core/hle/service/csnd_snd.h
@@ -0,0 +1,27 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace CSND_SND
11
12namespace CSND_SND {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17 ~Interface();
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const override {
23 return "csnd:SND";
24 }
25};
26
27} // namespace
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index 9e84ac938..bbcf26f61 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -26,12 +26,12 @@ const Interface::FunctionInfo FunctionTable[] = {
26 {0x001100C2, nullptr, "LoadComponent"}, 26 {0x001100C2, nullptr, "LoadComponent"},
27 {0x00120000, nullptr, "UnloadComponent"}, 27 {0x00120000, nullptr, "UnloadComponent"},
28 {0x00130082, nullptr, "FlushDataCache"}, 28 {0x00130082, nullptr, "FlushDataCache"},
29 {0x00140082, nullptr, "InvalidateDCache "}, 29 {0x00140082, nullptr, "InvalidateDCache"},
30 {0x00150082, nullptr, "RegisterInterruptEvents"}, 30 {0x00150082, nullptr, "RegisterInterruptEvents"},
31 {0x00160000, nullptr, "GetSemaphoreEventHandle"}, 31 {0x00160000, nullptr, "GetSemaphoreEventHandle"},
32 {0x00170040, nullptr, "SetSemaphoreMask"}, 32 {0x00170040, nullptr, "SetSemaphoreMask"},
33 {0x00180040, nullptr, "GetPhysicalAddress"}, 33 {0x00180040, nullptr, "GetPhysicalAddress"},
34 {0x00190040, nullptr, "GetVirtualAddress" }, 34 {0x00190040, nullptr, "GetVirtualAddress"},
35 {0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"}, 35 {0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"},
36 {0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"}, 36 {0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"},
37 {0x001C0082, nullptr, "SetIirFilterEQ"}, 37 {0x001C0082, nullptr, "SetIirFilterEQ"},
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h
index c439ed266..c4ce44245 100644
--- a/src/core/hle/service/dsp_dsp.h
+++ b/src/core/hle/service/dsp_dsp.h
@@ -19,7 +19,7 @@ public:
19 * Gets the string port name used by CTROS for the service 19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service 20 * @return Port name of service
21 */ 21 */
22 std::string GetPortName() const { 22 std::string GetPortName() const override {
23 return "dsp:DSP"; 23 return "dsp:DSP";
24 } 24 }
25}; 25};
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp
index 917b2f8ca..785c351e9 100644
--- a/src/core/hle/service/err_f.cpp
+++ b/src/core/hle/service/err_f.cpp
@@ -20,8 +20,8 @@ namespace ERR_F {
20 Interface::Interface() { 20 Interface::Interface() {
21 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 21 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
22 } 22 }
23 23
24 Interface::~Interface() { 24 Interface::~Interface() {
25 } 25 }
26 26
27} // namespace 27} // namespace
diff --git a/src/core/hle/service/err_f.h b/src/core/hle/service/err_f.h
index 5da663267..6d7141c1b 100644
--- a/src/core/hle/service/err_f.h
+++ b/src/core/hle/service/err_f.h
@@ -19,9 +19,9 @@ namespace ERR_F {
19 * Gets the string port name used by CTROS for the service 19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service 20 * @return Port name of service
21 */ 21 */
22 std::string GetPortName() const { 22 std::string GetPortName() const override {
23 return "err:f"; 23 return "err:f";
24 } 24 }
25 }; 25 };
26 26
27} // namespace 27} // namespace
diff --git a/src/core/hle/service/frd_u.h b/src/core/hle/service/frd_u.h
index 9df8a815a..4020c6664 100644
--- a/src/core/hle/service/frd_u.h
+++ b/src/core/hle/service/frd_u.h
@@ -19,7 +19,7 @@ namespace FRD_U {
19 * Gets the string port name used by CTROS for the service 19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service 20 * @return Port name of service
21 */ 21 */
22 std::string GetPortName() const { 22 std::string GetPortName() const override {
23 return "frd:u"; 23 return "frd:u";
24 } 24 }
25 }; 25 };
diff --git a/src/core/hle/service/fs_user.cpp b/src/core/hle/service/fs_user.cpp
index 9dc83291d..34af78cb9 100644
--- a/src/core/hle/service/fs_user.cpp
+++ b/src/core/hle/service/fs_user.cpp
@@ -4,31 +4,45 @@
4 4
5#include "common/common.h" 5#include "common/common.h"
6 6
7#include "fs_user.h"
8#include "common/string_util.h" 7#include "common/string_util.h"
9#include "core/settings.h"
10#include "core/hle/kernel/archive.h" 8#include "core/hle/kernel/archive.h"
9#include "core/hle/kernel/archive.h"
10#include "core/hle/result.h"
11#include "core/hle/service/fs_user.h"
12#include "core/settings.h"
11 13
12//////////////////////////////////////////////////////////////////////////////////////////////////// 14////////////////////////////////////////////////////////////////////////////////////////////////////
13// Namespace FS_User 15// Namespace FS_User
14 16
15namespace FS_User { 17namespace FS_User {
16 18
17// We currently return 0 for success and -1 for failure in cmd_buff[1]. -1 was chosen because it 19static void Initialize(Service::Interface* self) {
18// puts all the sections of the http://3dbrew.org/wiki/Error_codes to something non-zero, to make
19// sure we don't mislead the application into thinking something worked.
20
21void Initialize(Service::Interface* self) {
22 u32* cmd_buff = Service::GetCommandBuffer(); 20 u32* cmd_buff = Service::GetCommandBuffer();
23 21
24 // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per 22 // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per
25 // http://3dbrew.org/wiki/FS:Initialize#Request 23 // http://3dbrew.org/wiki/FS:Initialize#Request
26 cmd_buff[1] = 0; 24 cmd_buff[1] = RESULT_SUCCESS.raw;
27 25
28 DEBUG_LOG(KERNEL, "called"); 26 DEBUG_LOG(KERNEL, "called");
29} 27}
30 28
31void OpenFile(Service::Interface* self) { 29/**
30 * FS_User::OpenFile service function
31 * Inputs:
32 * 1 : Transaction
33 * 2 : Archive handle lower word
34 * 3 : Archive handle upper word
35 * 4 : Low path type
36 * 5 : Low path size
37 * 6 : Open flags
38 * 7 : Attributes
39 * 8 : (LowPathSize << 14) | 2
40 * 9 : Low path data pointer
41 * Outputs:
42 * 1 : Result of function, 0 on success, otherwise error code
43 * 3 : File handle
44 */
45static void OpenFile(Service::Interface* self) {
32 u32* cmd_buff = Service::GetCommandBuffer(); 46 u32* cmd_buff = Service::GetCommandBuffer();
33 47
34 // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to 48 // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
@@ -39,36 +53,41 @@ void OpenFile(Service::Interface* self) {
39 FileSys::Mode mode; mode.hex = cmd_buff[6]; 53 FileSys::Mode mode; mode.hex = cmd_buff[6];
40 u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes. 54 u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes.
41 u32 filename_ptr = cmd_buff[9]; 55 u32 filename_ptr = cmd_buff[9];
42
43 FileSys::Path file_path(filename_type, filename_size, filename_ptr); 56 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
44 std::string file_string;
45 switch (file_path.GetType()) {
46 case FileSys::Char:
47 case FileSys::Wchar:
48 file_string = file_path.AsString();
49 break;
50 default:
51 WARN_LOG(KERNEL, "file LowPath type is currently unsupported; returning archive handle instead");
52 return;
53 }
54 57
55 DEBUG_LOG(KERNEL, "type=%d size=%d mode=%d attrs=%d data=%s", 58 DEBUG_LOG(KERNEL, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes);
56 filename_type, filename_size, mode, attributes, file_string.c_str());
57 59
58 Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_string, mode); 60 ResultVal<Handle> handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode);
59 if (handle) { 61 cmd_buff[1] = handle.Code().raw;
60 cmd_buff[1] = 0; 62 if (handle.Succeeded()) {
61 cmd_buff[3] = handle; 63 cmd_buff[3] = *handle;
62 } else { 64 } else {
63 ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_string.c_str()); 65 ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str());
64 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
65 cmd_buff[1] = -1;
66 } 66 }
67 67
68 DEBUG_LOG(KERNEL, "called"); 68 DEBUG_LOG(KERNEL, "called");
69} 69}
70 70
71void OpenFileDirectly(Service::Interface* self) { 71/**
72 * FS_User::OpenFileDirectly service function
73 * Inputs:
74 * 1 : Transaction
75 * 2 : Archive ID
76 * 3 : Archive low path type
77 * 4 : Archive low path size
78 * 5 : File low path type
79 * 6 : File low path size
80 * 7 : Flags
81 * 8 : Attributes
82 * 9 : (ArchiveLowPathSize << 14) | 0x802
83 * 10 : Archive low path
84 * 11 : (FileLowPathSize << 14) | 2
85 * 12 : File low path
86 * Outputs:
87 * 1 : Result of function, 0 on success, otherwise error code
88 * 3 : File handle
89 */
90static void OpenFileDirectly(Service::Interface* self) {
72 u32* cmd_buff = Service::GetCommandBuffer(); 91 u32* cmd_buff = Service::GetCommandBuffer();
73 92
74 auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]); 93 auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]);
@@ -80,55 +99,103 @@ void OpenFileDirectly(Service::Interface* self) {
80 u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes. 99 u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes.
81 u32 archivename_ptr = cmd_buff[10]; 100 u32 archivename_ptr = cmd_buff[10];
82 u32 filename_ptr = cmd_buff[12]; 101 u32 filename_ptr = cmd_buff[12];
102 FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
103 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
83 104
84 DEBUG_LOG(KERNEL, "archive_type=%d archive_size=%d file_type=%d file_size=%d file_mode=%d file_attrs=%d", 105 DEBUG_LOG(KERNEL, "archive_path=%s file_path=%s, mode=%u attributes=%d",
85 archivename_type, archivename_size, filename_type, filename_size, mode, attributes); 106 archive_path.DebugStr().c_str(), file_path.DebugStr().c_str(), mode.hex, attributes);
86 107
87 if (archivename_type != FileSys::Empty) { 108 if (archive_path.GetType() != FileSys::Empty) {
88 ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); 109 ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
89 cmd_buff[1] = -1; 110 cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
90 return; 111 return;
91 } 112 }
92 113
93 // TODO(Link Mauve): check if we should even get a handle for the archive, and don't leak it. 114 // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it
94 Handle archive_handle = Kernel::OpenArchive(archive_id); 115 // TODO(yuriks): Why is there all this duplicate (and seemingly useless) code up here?
95 if (archive_handle) { 116 ResultVal<Handle> archive_handle = Kernel::OpenArchive(archive_id);
96 cmd_buff[1] = 0; 117 cmd_buff[1] = archive_handle.Code().raw;
97 // cmd_buff[2] isn't used according to 3dmoo's implementation. 118 if (archive_handle.Failed()) {
98 cmd_buff[3] = archive_handle;
99 } else {
100 ERROR_LOG(KERNEL, "failed to get a handle for archive"); 119 ERROR_LOG(KERNEL, "failed to get a handle for archive");
101 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
102 cmd_buff[1] = -1;
103 return;
104 }
105
106 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
107 std::string file_string;
108 switch (file_path.GetType()) {
109 case FileSys::Char:
110 case FileSys::Wchar:
111 file_string = file_path.AsString();
112 break;
113 default:
114 WARN_LOG(KERNEL, "file LowPath type is currently unsupported; returning archive handle instead");
115 return; 120 return;
116 } 121 }
122 // cmd_buff[2] isn't used according to 3dmoo's implementation.
123 cmd_buff[3] = *archive_handle;
117 124
118 Handle handle = Kernel::OpenFileFromArchive(archive_handle, file_string, mode); 125 ResultVal<Handle> handle = Kernel::OpenFileFromArchive(*archive_handle, file_path, mode);
119 if (handle) { 126 cmd_buff[1] = handle.Code().raw;
120 cmd_buff[1] = 0; 127 if (handle.Succeeded()) {
121 cmd_buff[3] = handle; 128 cmd_buff[3] = *handle;
122 } else { 129 } else {
123 ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_string.c_str()); 130 ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str());
124 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
125 cmd_buff[1] = -1;
126 } 131 }
127 132
128 DEBUG_LOG(KERNEL, "called"); 133 DEBUG_LOG(KERNEL, "called");
129} 134}
130 135
131/* 136/*
137 * FS_User::DeleteFile service function
138 * Inputs:
139 * 2 : Archive handle lower word
140 * 3 : Archive handle upper word
141 * 4 : File path string type
142 * 5 : File path string size
143 * 7 : File path string data
144 * Outputs:
145 * 1 : Result of function, 0 on success, otherwise error code
146 */
147void DeleteFile(Service::Interface* self) {
148 u32* cmd_buff = Service::GetCommandBuffer();
149
150 // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
151 // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
152 Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
153 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
154 u32 filename_size = cmd_buff[5];
155 u32 filename_ptr = cmd_buff[7];
156
157 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
158
159 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s",
160 filename_type, filename_size, file_path.DebugStr().c_str());
161
162 cmd_buff[1] = Kernel::DeleteFileFromArchive(archive_handle, file_path);
163
164 DEBUG_LOG(KERNEL, "called");
165}
166
167/*
168 * FS_User::DeleteDirectory service function
169 * Inputs:
170 * 2 : Archive handle lower word
171 * 3 : Archive handle upper word
172 * 4 : Directory path string type
173 * 5 : Directory path string size
174 * 7 : Directory path string data
175 * Outputs:
176 * 1 : Result of function, 0 on success, otherwise error code
177 */
178void DeleteDirectory(Service::Interface* self) {
179 u32* cmd_buff = Service::GetCommandBuffer();
180
181 // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
182 // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
183 Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
184 auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
185 u32 dirname_size = cmd_buff[5];
186 u32 dirname_ptr = cmd_buff[7];
187
188 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
189
190 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s",
191 dirname_type, dirname_size, dir_path.DebugStr().c_str());
192
193 cmd_buff[1] = Kernel::DeleteDirectoryFromArchive(archive_handle, dir_path);
194
195 DEBUG_LOG(KERNEL, "called");
196}
197
198/*
132 * FS_User::CreateDirectory service function 199 * FS_User::CreateDirectory service function
133 * Inputs: 200 * Inputs:
134 * 2 : Archive handle lower word 201 * 2 : Archive handle lower word
@@ -139,7 +206,7 @@ void OpenFileDirectly(Service::Interface* self) {
139 * Outputs: 206 * Outputs:
140 * 1 : Result of function, 0 on success, otherwise error code 207 * 1 : Result of function, 0 on success, otherwise error code
141 */ 208 */
142void CreateDirectory(Service::Interface* self) { 209static void CreateDirectory(Service::Interface* self) {
143 u32* cmd_buff = Service::GetCommandBuffer(); 210 u32* cmd_buff = Service::GetCommandBuffer();
144 211
145 // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to 212 // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to
@@ -150,25 +217,15 @@ void CreateDirectory(Service::Interface* self) {
150 u32 dirname_ptr = cmd_buff[8]; 217 u32 dirname_ptr = cmd_buff[8];
151 218
152 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); 219 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
153 std::string dir_string;
154 switch (dir_path.GetType()) {
155 case FileSys::Char:
156 case FileSys::Wchar:
157 dir_string = dir_path.AsString();
158 break;
159 default:
160 cmd_buff[1] = -1;
161 return;
162 }
163 220
164 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str()); 221 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str());
165 222
166 cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_string); 223 cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_path);
167 224
168 DEBUG_LOG(KERNEL, "called"); 225 DEBUG_LOG(KERNEL, "called");
169} 226}
170 227
171void OpenDirectory(Service::Interface* self) { 228static void OpenDirectory(Service::Interface* self) {
172 u32* cmd_buff = Service::GetCommandBuffer(); 229 u32* cmd_buff = Service::GetCommandBuffer();
173 230
174 // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to 231 // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
@@ -179,57 +236,57 @@ void OpenDirectory(Service::Interface* self) {
179 u32 dirname_ptr = cmd_buff[6]; 236 u32 dirname_ptr = cmd_buff[6];
180 237
181 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); 238 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
182 std::string dir_string;
183 switch (dir_path.GetType()) {
184 case FileSys::Char:
185 case FileSys::Wchar:
186 dir_string = dir_path.AsString();
187 break;
188 default:
189 cmd_buff[1] = -1;
190 return;
191 }
192 239
193 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_string.c_str()); 240 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str());
194 241
195 Handle handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_string); 242 ResultVal<Handle> handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_path);
196 if (handle) { 243 cmd_buff[1] = handle.Code().raw;
197 cmd_buff[1] = 0; 244 if (handle.Succeeded()) {
198 cmd_buff[3] = handle; 245 cmd_buff[3] = *handle;
199 } else { 246 } else {
200 ERROR_LOG(KERNEL, "failed to get a handle for directory %s", dir_string.c_str()); 247 ERROR_LOG(KERNEL, "failed to get a handle for directory");
201 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
202 cmd_buff[1] = -1;
203 } 248 }
204 249
205 DEBUG_LOG(KERNEL, "called"); 250 DEBUG_LOG(KERNEL, "called");
206} 251}
207 252
208void OpenArchive(Service::Interface* self) { 253/**
254 * FS_User::OpenArchive service function
255 * Inputs:
256 * 1 : Archive ID
257 * 2 : Archive low path type
258 * 3 : Archive low path size
259 * 4 : (LowPathSize << 14) | 2
260 * 5 : Archive low path
261 * Outputs:
262 * 1 : Result of function, 0 on success, otherwise error code
263 * 2 : Archive handle lower word (unused)
264 * 3 : Archive handle upper word (same as file handle)
265 */
266static void OpenArchive(Service::Interface* self) {
209 u32* cmd_buff = Service::GetCommandBuffer(); 267 u32* cmd_buff = Service::GetCommandBuffer();
210 268
211 auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]); 269 auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]);
212 auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]); 270 auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
213 u32 archivename_size = cmd_buff[3]; 271 u32 archivename_size = cmd_buff[3];
214 u32 archivename_ptr = cmd_buff[5]; 272 u32 archivename_ptr = cmd_buff[5];
273 FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
215 274
216 DEBUG_LOG(KERNEL, "type=%d size=%d", archivename_type, archivename_size); 275 DEBUG_LOG(KERNEL, "archive_path=%s", archive_path.DebugStr().c_str());
217 276
218 if (archivename_type != FileSys::Empty) { 277 if (archive_path.GetType() != FileSys::Empty) {
219 ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported"); 278 ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
220 cmd_buff[1] = -1; 279 cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
221 return; 280 return;
222 } 281 }
223 282
224 Handle handle = Kernel::OpenArchive(archive_id); 283 ResultVal<Handle> handle = Kernel::OpenArchive(archive_id);
225 if (handle) { 284 cmd_buff[1] = handle.Code().raw;
226 cmd_buff[1] = 0; 285 if (handle.Succeeded()) {
227 // cmd_buff[2] isn't used according to 3dmoo's implementation. 286 // cmd_buff[2] isn't used according to 3dmoo's implementation.
228 cmd_buff[3] = handle; 287 cmd_buff[3] = *handle;
229 } else { 288 } else {
230 ERROR_LOG(KERNEL, "failed to get a handle for archive"); 289 ERROR_LOG(KERNEL, "failed to get a handle for archive");
231 // TODO(Link Mauve): check for the actual error values, this one was just chosen arbitrarily.
232 cmd_buff[1] = -1;
233 } 290 }
234 291
235 DEBUG_LOG(KERNEL, "called"); 292 DEBUG_LOG(KERNEL, "called");
@@ -241,12 +298,12 @@ void OpenArchive(Service::Interface* self) {
241* 1 : Result of function, 0 on success, otherwise error code 298* 1 : Result of function, 0 on success, otherwise error code
242* 2 : Whether the Sdmc could be detected 299* 2 : Whether the Sdmc could be detected
243*/ 300*/
244void IsSdmcDetected(Service::Interface* self) { 301static void IsSdmcDetected(Service::Interface* self) {
245 u32* cmd_buff = Service::GetCommandBuffer(); 302 u32* cmd_buff = Service::GetCommandBuffer();
246 303
247 cmd_buff[1] = 0; 304 cmd_buff[1] = 0;
248 cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0; 305 cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0;
249 306
250 DEBUG_LOG(KERNEL, "called"); 307 DEBUG_LOG(KERNEL, "called");
251} 308}
252 309
@@ -256,9 +313,9 @@ const Interface::FunctionInfo FunctionTable[] = {
256 {0x08010002, Initialize, "Initialize"}, 313 {0x08010002, Initialize, "Initialize"},
257 {0x080201C2, OpenFile, "OpenFile"}, 314 {0x080201C2, OpenFile, "OpenFile"},
258 {0x08030204, OpenFileDirectly, "OpenFileDirectly"}, 315 {0x08030204, OpenFileDirectly, "OpenFileDirectly"},
259 {0x08040142, nullptr, "DeleteFile"}, 316 {0x08040142, DeleteFile, "DeleteFile"},
260 {0x08050244, nullptr, "RenameFile"}, 317 {0x08050244, nullptr, "RenameFile"},
261 {0x08060142, nullptr, "DeleteDirectory"}, 318 {0x08060142, DeleteDirectory, "DeleteDirectory"},
262 {0x08070142, nullptr, "DeleteDirectoryRecursively"}, 319 {0x08070142, nullptr, "DeleteDirectoryRecursively"},
263 {0x08080202, nullptr, "CreateFile"}, 320 {0x08080202, nullptr, "CreateFile"},
264 {0x08090182, CreateDirectory, "CreateDirectory"}, 321 {0x08090182, CreateDirectory, "CreateDirectory"},
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 6119e6300..de1bd3f61 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -28,31 +28,26 @@ u32 g_thread_id = 1; ///< Thread index into interrupt relay queue, 1
28 28
29/// Gets a pointer to a thread command buffer in GSP shared memory 29/// Gets a pointer to a thread command buffer in GSP shared memory
30static inline u8* GetCommandBuffer(u32 thread_id) { 30static inline u8* GetCommandBuffer(u32 thread_id) {
31 if (0 == g_shared_memory) 31 ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, 0x800 + (thread_id * sizeof(CommandBuffer)));
32 return nullptr; 32 return ptr.ValueOr(nullptr);
33
34 return Kernel::GetSharedMemoryPointer(g_shared_memory,
35 0x800 + (thread_id * sizeof(CommandBuffer)));
36} 33}
37 34
38static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { 35static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) {
39 if (0 == g_shared_memory)
40 return nullptr;
41
42 _dbg_assert_msg_(GSP, screen_index < 2, "Invalid screen index"); 36 _dbg_assert_msg_(GSP, screen_index < 2, "Invalid screen index");
43 37
44 // For each thread there are two FrameBufferUpdate fields 38 // For each thread there are two FrameBufferUpdate fields
45 u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate); 39 u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate);
46 return (FrameBufferUpdate*)Kernel::GetSharedMemoryPointer(g_shared_memory, offset); 40 ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, offset);
41 return reinterpret_cast<FrameBufferUpdate*>(ptr.ValueOr(nullptr));
47} 42}
48 43
49/// Gets a pointer to the interrupt relay queue for a given thread index 44/// Gets a pointer to the interrupt relay queue for a given thread index
50static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) { 45static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
51 return (InterruptRelayQueue*)Kernel::GetSharedMemoryPointer(g_shared_memory, 46 ResultVal<u8*> ptr = Kernel::GetSharedMemoryPointer(g_shared_memory, sizeof(InterruptRelayQueue) * thread_id);
52 sizeof(InterruptRelayQueue) * thread_id); 47 return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr));
53} 48}
54 49
55void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { 50static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
56 // TODO: Return proper error codes 51 // TODO: Return proper error codes
57 if (base_address + size_in_bytes >= 0x420000) { 52 if (base_address + size_in_bytes >= 0x420000) {
58 ERROR_LOG(GPU, "Write address out of range! (address=0x%08x, size=0x%08x)", 53 ERROR_LOG(GPU, "Write address out of range! (address=0x%08x, size=0x%08x)",
@@ -76,7 +71,7 @@ void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
76} 71}
77 72
78/// Write a GSP GPU hardware register 73/// Write a GSP GPU hardware register
79void WriteHWRegs(Service::Interface* self) { 74static void WriteHWRegs(Service::Interface* self) {
80 u32* cmd_buff = Service::GetCommandBuffer(); 75 u32* cmd_buff = Service::GetCommandBuffer();
81 u32 reg_addr = cmd_buff[1]; 76 u32 reg_addr = cmd_buff[1];
82 u32 size = cmd_buff[2]; 77 u32 size = cmd_buff[2];
@@ -87,7 +82,7 @@ void WriteHWRegs(Service::Interface* self) {
87} 82}
88 83
89/// Read a GSP GPU hardware register 84/// Read a GSP GPU hardware register
90void ReadHWRegs(Service::Interface* self) { 85static void ReadHWRegs(Service::Interface* self) {
91 u32* cmd_buff = Service::GetCommandBuffer(); 86 u32* cmd_buff = Service::GetCommandBuffer();
92 u32 reg_addr = cmd_buff[1]; 87 u32 reg_addr = cmd_buff[1];
93 u32 size = cmd_buff[2]; 88 u32 size = cmd_buff[2];
@@ -115,7 +110,7 @@ void ReadHWRegs(Service::Interface* self) {
115 } 110 }
116} 111}
117 112
118void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { 113static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
119 u32 base_address = 0x400000; 114 u32 base_address = 0x400000;
120 if (info.active_fb == 0) { 115 if (info.active_fb == 0) {
121 WriteHWRegs(base_address + 4 * GPU_REG_INDEX(framebuffer_config[screen_id].address_left1), 4, &info.address_left); 116 WriteHWRegs(base_address + 4 * GPU_REG_INDEX(framebuffer_config[screen_id].address_left1), 4, &info.address_left);
@@ -140,7 +135,7 @@ void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
140 * Outputs: 135 * Outputs:
141 * 1: Result code 136 * 1: Result code
142 */ 137 */
143void SetBufferSwap(Service::Interface* self) { 138static void SetBufferSwap(Service::Interface* self) {
144 u32* cmd_buff = Service::GetCommandBuffer(); 139 u32* cmd_buff = Service::GetCommandBuffer();
145 u32 screen_id = cmd_buff[1]; 140 u32 screen_id = cmd_buff[1];
146 FrameBufferInfo* fb_info = (FrameBufferInfo*)&cmd_buff[2]; 141 FrameBufferInfo* fb_info = (FrameBufferInfo*)&cmd_buff[2];
@@ -159,7 +154,7 @@ void SetBufferSwap(Service::Interface* self) {
159 * 2 : Thread index into GSP command buffer 154 * 2 : Thread index into GSP command buffer
160 * 4 : Handle to GSP shared memory 155 * 4 : Handle to GSP shared memory
161 */ 156 */
162void RegisterInterruptRelayQueue(Service::Interface* self) { 157static void RegisterInterruptRelayQueue(Service::Interface* self) {
163 u32* cmd_buff = Service::GetCommandBuffer(); 158 u32* cmd_buff = Service::GetCommandBuffer();
164 u32 flags = cmd_buff[1]; 159 u32 flags = cmd_buff[1];
165 g_interrupt_event = cmd_buff[3]; 160 g_interrupt_event = cmd_buff[3];
@@ -202,7 +197,7 @@ void SignalInterrupt(InterruptId interrupt_id) {
202} 197}
203 198
204/// Executes the next GSP command 199/// Executes the next GSP command
205void ExecuteCommand(const Command& command, u32 thread_id) { 200static void ExecuteCommand(const Command& command, u32 thread_id) {
206 // Utility function to convert register ID to address 201 // Utility function to convert register ID to address
207 auto WriteGPURegister = [](u32 id, u32 data) { 202 auto WriteGPURegister = [](u32 id, u32 data) {
208 GPU::Write<u32>(0x1EF00000 + 4 * id, data); 203 GPU::Write<u32>(0x1EF00000 + 4 * id, data);
@@ -308,7 +303,7 @@ void ExecuteCommand(const Command& command, u32 thread_id) {
308} 303}
309 304
310/// This triggers handling of the GX command written to the command buffer in shared memory. 305/// This triggers handling of the GX command written to the command buffer in shared memory.
311void TriggerCmdReqQueue(Service::Interface* self) { 306static void TriggerCmdReqQueue(Service::Interface* self) {
312 307
313 // Iterate through each thread's command queue... 308 // Iterate through each thread's command queue...
314 for (unsigned thread_id = 0; thread_id < 0x4; ++thread_id) { 309 for (unsigned thread_id = 0; thread_id < 0x4; ++thread_id) {
diff --git a/src/core/hle/service/hid_user.cpp b/src/core/hle/service/hid_user.cpp
index 0eb32ba4a..d29de1a52 100644
--- a/src/core/hle/service/hid_user.cpp
+++ b/src/core/hle/service/hid_user.cpp
@@ -34,10 +34,7 @@ static s16 next_circle_y = 0;
34 * Gets a pointer to the PadData structure inside HID shared memory 34 * Gets a pointer to the PadData structure inside HID shared memory
35 */ 35 */
36static inline PadData* GetPadData() { 36static inline PadData* GetPadData() {
37 if (0 == shared_mem) 37 return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0).ValueOr(nullptr));
38 return nullptr;
39
40 return reinterpret_cast<PadData*>(Kernel::GetSharedMemoryPointer(shared_mem, 0));
41} 38}
42 39
43/** 40/**
@@ -47,7 +44,7 @@ static inline PadData* GetPadData() {
47 * 44 *
48 * Indicate the circle pad is pushed completely to the edge in 1 of 8 directions. 45 * Indicate the circle pad is pushed completely to the edge in 1 of 8 directions.
49 */ 46 */
50void UpdateNextCirclePadState() { 47static void UpdateNextCirclePadState() {
51 static const s16 max_value = 0x9C; 48 static const s16 max_value = 0x9C;
52 next_circle_x = next_state.circle_left ? -max_value : 0x0; 49 next_circle_x = next_state.circle_left ? -max_value : 0x0;
53 next_circle_x += next_state.circle_right ? max_value : 0x0; 50 next_circle_x += next_state.circle_right ? max_value : 0x0;
@@ -155,7 +152,7 @@ void PadUpdateComplete() {
155 * 7 : Gyroscope event 152 * 7 : Gyroscope event
156 * 8 : Event signaled by HID_User 153 * 8 : Event signaled by HID_User
157 */ 154 */
158void GetIPCHandles(Service::Interface* self) { 155static void GetIPCHandles(Service::Interface* self) {
159 u32* cmd_buff = Service::GetCommandBuffer(); 156 u32* cmd_buff = Service::GetCommandBuffer();
160 157
161 cmd_buff[1] = 0; // No error 158 cmd_buff[1] = 0; // No error
diff --git a/src/core/hle/service/hid_user.h b/src/core/hle/service/hid_user.h
index 9f6c4d5ed..5ed97085d 100644
--- a/src/core/hle/service/hid_user.h
+++ b/src/core/hle/service/hid_user.h
@@ -15,7 +15,7 @@
15 15
16namespace HID_User { 16namespace HID_User {
17 17
18/** 18/**
19 * Structure of a Pad controller state. 19 * Structure of a Pad controller state.
20 */ 20 */
21struct PadState { 21struct PadState {
diff --git a/src/core/hle/service/ir_rst.cpp b/src/core/hle/service/ir_rst.cpp
new file mode 100644
index 000000000..be15db231
--- /dev/null
+++ b/src/core/hle/service/ir_rst.cpp
@@ -0,0 +1,36 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/ir_rst.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace IR_RST
11
12namespace IR_RST {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010000, nullptr, "GetHandles"},
16 {0x00020080, nullptr, "Initialize"},
17 {0x00030000, nullptr, "Shutdown"},
18 {0x00040000, nullptr, "Unknown"},
19 {0x00050000, nullptr, "Unknown"},
20 {0x00060000, nullptr, "Unknown"},
21 {0x00070080, nullptr, "Unknown"},
22 {0x00080000, nullptr, "Unknown"},
23 {0x00090000, nullptr, "Unknown"},
24};
25
26////////////////////////////////////////////////////////////////////////////////////////////////////
27// Interface class
28
29Interface::Interface() {
30 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
31}
32
33Interface::~Interface() {
34}
35
36} // namespace
diff --git a/src/core/hle/service/ir_rst.h b/src/core/hle/service/ir_rst.h
new file mode 100644
index 000000000..73effd7e3
--- /dev/null
+++ b/src/core/hle/service/ir_rst.h
@@ -0,0 +1,27 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace IR_RST
11
12namespace IR_RST {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17 ~Interface();
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const override {
23 return "ir:rst";
24 }
25};
26
27} // namespace
diff --git a/src/core/hle/service/ir_u.cpp b/src/core/hle/service/ir_u.cpp
new file mode 100644
index 000000000..aa9db6f6d
--- /dev/null
+++ b/src/core/hle/service/ir_u.cpp
@@ -0,0 +1,45 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/ir_u.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace IR_U
11
12namespace IR_U {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010000, nullptr, "Initialize"},
16 {0x00020000, nullptr, "Shutdown"},
17 {0x00030042, nullptr, "StartSendTransfer"},
18 {0x00040000, nullptr, "WaitSendTransfer"},
19 {0x000500C2, nullptr, "StartRecvTransfer"},
20 {0x00060000, nullptr, "WaitRecvTransfer"},
21 {0x00070080, nullptr, "GetRecvTransferCount"},
22 {0x00080000, nullptr, "GetSendState"},
23 {0x00090040, nullptr, "SetBitRate"},
24 {0x000A0000, nullptr, "GetBitRate"},
25 {0x000B0040, nullptr, "SetIRLEDState"},
26 {0x000C0000, nullptr, "GetIRLEDRecvState"},
27 {0x000D0000, nullptr, "GetSendFinishedEvent"},
28 {0x000E0000, nullptr, "GetRecvFinishedEvent"},
29 {0x000F0000, nullptr, "GetTransferState"},
30 {0x00100000, nullptr, "GetErrorStatus"},
31 {0x00110040, nullptr, "SetSleepModeActive"},
32 {0x00120040, nullptr, "SetSleepModeState"},
33};
34
35////////////////////////////////////////////////////////////////////////////////////////////////////
36// Interface class
37
38Interface::Interface() {
39 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
40}
41
42Interface::~Interface() {
43}
44
45} // namespace
diff --git a/src/core/hle/service/ir_u.h b/src/core/hle/service/ir_u.h
new file mode 100644
index 000000000..86d98d079
--- /dev/null
+++ b/src/core/hle/service/ir_u.h
@@ -0,0 +1,27 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace IR_U
11
12namespace IR_U {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17 ~Interface();
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const override {
23 return "ir:u";
24 }
25};
26
27} // namespace
diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp
index 58051f133..d6f30e9ae 100644
--- a/src/core/hle/service/mic_u.cpp
+++ b/src/core/hle/service/mic_u.cpp
@@ -27,7 +27,7 @@ const Interface::FunctionInfo FunctionTable[] = {
27 {0x000D0040, nullptr, "SetClamp"}, 27 {0x000D0040, nullptr, "SetClamp"},
28 {0x000E0000, nullptr, "GetClamp"}, 28 {0x000E0000, nullptr, "GetClamp"},
29 {0x000F0040, nullptr, "unknown_input1"}, 29 {0x000F0040, nullptr, "unknown_input1"},
30 {0x00100040, nullptr, "unknown_input2"}, 30 {0x00100040, nullptr, "unknown_input2"},
31}; 31};
32 32
33//////////////////////////////////////////////////////////////////////////////////////////////////// 33////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/mic_u.h b/src/core/hle/service/mic_u.h
index 72ba048ef..2a495f3a9 100644
--- a/src/core/hle/service/mic_u.h
+++ b/src/core/hle/service/mic_u.h
@@ -21,7 +21,7 @@ public:
21 * Gets the string port name used by CTROS for the service 21 * Gets the string port name used by CTROS for the service
22 * @return Port name of service 22 * @return Port name of service
23 */ 23 */
24 std::string GetPortName() const { 24 std::string GetPortName() const override {
25 return "mic:u"; 25 return "mic:u";
26 } 26 }
27}; 27};
diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h
index a956ca812..69d2c2002 100644
--- a/src/core/hle/service/nwm_uds.h
+++ b/src/core/hle/service/nwm_uds.h
@@ -21,7 +21,7 @@ public:
21 * Gets the string port name used by CTROS for the service 21 * Gets the string port name used by CTROS for the service
22 * @return Port name of service 22 * @return Port name of service
23 */ 23 */
24 std::string GetPortName() const { 24 std::string GetPortName() const override {
25 return "nwm:UDS"; 25 return "nwm:UDS";
26 } 26 }
27}; 27};
diff --git a/src/core/hle/service/pm_app.cpp b/src/core/hle/service/pm_app.cpp
new file mode 100644
index 000000000..90e9b1bfa
--- /dev/null
+++ b/src/core/hle/service/pm_app.cpp
@@ -0,0 +1,35 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/pm_app.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace PM_APP
11
12namespace PM_APP {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010140, nullptr, "LaunchTitle"},
16 {0x00020082, nullptr, "LaunchFIRMSetParams"},
17 {0x00030080, nullptr, "TerminateProcesse"},
18 {0x00040100, nullptr, "TerminateProcessTID"},
19 {0x000500C0, nullptr, "TerminateProcessTID_unknown"},
20 {0x00070042, nullptr, "GetFIRMLaunchParams"},
21 {0x00080100, nullptr, "GetTitleExheaderFlags"},
22 {0x00090042, nullptr, "SetFIRMLaunchParams"},
23};
24
25////////////////////////////////////////////////////////////////////////////////////////////////////
26// Interface class
27
28Interface::Interface() {
29 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
30}
31
32Interface::~Interface() {
33}
34
35} // namespace
diff --git a/src/core/hle/service/pm_app.h b/src/core/hle/service/pm_app.h
new file mode 100644
index 000000000..28c38f582
--- /dev/null
+++ b/src/core/hle/service/pm_app.h
@@ -0,0 +1,27 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace PM_APP
11
12namespace PM_APP {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17 ~Interface();
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const override {
23 return "pm:app";
24 }
25};
26
27} // namespace
diff --git a/src/core/hle/service/ptm_u.cpp b/src/core/hle/service/ptm_u.cpp
index f6a14d509..d9122dbbc 100644
--- a/src/core/hle/service/ptm_u.cpp
+++ b/src/core/hle/service/ptm_u.cpp
@@ -17,13 +17,13 @@ const Interface::FunctionInfo FunctionTable[] = {
17 {0x00030000, nullptr, "GetRtcAlarm"}, 17 {0x00030000, nullptr, "GetRtcAlarm"},
18 {0x00040000, nullptr, "CancelRtcAlarm"}, 18 {0x00040000, nullptr, "CancelRtcAlarm"},
19 {0x00050000, nullptr, "GetAdapterState"}, 19 {0x00050000, nullptr, "GetAdapterState"},
20 {0x00060000, nullptr, "GetShellState "}, 20 {0x00060000, nullptr, "GetShellState"},
21 {0x00070000, nullptr, "GetBatteryLevel"}, 21 {0x00070000, nullptr, "GetBatteryLevel"},
22 {0x00080000, nullptr, "GetBatteryChargeState"}, 22 {0x00080000, nullptr, "GetBatteryChargeState"},
23 {0x00090000, nullptr, "GetPedometerState"}, 23 {0x00090000, nullptr, "GetPedometerState"},
24 {0x000A0042, nullptr, "GetStepHistoryEntry"}, 24 {0x000A0042, nullptr, "GetStepHistoryEntry"},
25 {0x000B00C2, nullptr, "GetStepHistory "}, 25 {0x000B00C2, nullptr, "GetStepHistory"},
26 {0x000C0000, nullptr, "GetTotalStepCount "}, 26 {0x000C0000, nullptr, "GetTotalStepCount"},
27 {0x000D0040, nullptr, "SetPedometerRecordingMode"}, 27 {0x000D0040, nullptr, "SetPedometerRecordingMode"},
28 {0x000E0000, nullptr, "GetPedometerRecordingMode"}, 28 {0x000E0000, nullptr, "GetPedometerRecordingMode"},
29 {0x000F0084, nullptr, "GetStepHistoryAll"}, 29 {0x000F0084, nullptr, "GetStepHistoryAll"},
diff --git a/src/core/hle/service/ptm_u.h b/src/core/hle/service/ptm_u.h
index 82749fa39..f8d9f57be 100644
--- a/src/core/hle/service/ptm_u.h
+++ b/src/core/hle/service/ptm_u.h
@@ -21,7 +21,7 @@ public:
21 * Gets the string port name used by CTROS for the service 21 * Gets the string port name used by CTROS for the service
22 * @return Port name of service 22 * @return Port name of service
23 */ 23 */
24 std::string GetPortName() const { 24 std::string GetPortName() const override {
25 return "ptm:u"; 25 return "ptm:u";
26 } 26 }
27}; 27};
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index bb0f80e98..fed2268a0 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -7,17 +7,24 @@
7 7
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/am_net.h"
10#include "core/hle/service/apt_u.h" 11#include "core/hle/service/apt_u.h"
12#include "core/hle/service/boss_u.h"
13#include "core/hle/service/cfg_i.h"
11#include "core/hle/service/cfg_u.h" 14#include "core/hle/service/cfg_u.h"
15#include "core/hle/service/csnd_snd.h"
12#include "core/hle/service/dsp_dsp.h" 16#include "core/hle/service/dsp_dsp.h"
13#include "core/hle/service/err_f.h" 17#include "core/hle/service/err_f.h"
14#include "core/hle/service/fs_user.h" 18#include "core/hle/service/fs_user.h"
15#include "core/hle/service/frd_u.h" 19#include "core/hle/service/frd_u.h"
16#include "core/hle/service/gsp_gpu.h" 20#include "core/hle/service/gsp_gpu.h"
17#include "core/hle/service/hid_user.h" 21#include "core/hle/service/hid_user.h"
22#include "core/hle/service/ir_rst.h"
23#include "core/hle/service/ir_u.h"
18#include "core/hle/service/mic_u.h" 24#include "core/hle/service/mic_u.h"
19#include "core/hle/service/ndm_u.h" 25#include "core/hle/service/ndm_u.h"
20#include "core/hle/service/nwm_uds.h" 26#include "core/hle/service/nwm_uds.h"
27#include "core/hle/service/pm_app.h"
21#include "core/hle/service/ptm_u.h" 28#include "core/hle/service/ptm_u.h"
22#include "core/hle/service/soc_u.h" 29#include "core/hle/service/soc_u.h"
23#include "core/hle/service/srv.h" 30#include "core/hle/service/srv.h"
@@ -55,7 +62,7 @@ void Manager::DeleteService(const std::string& port_name) {
55 62
56/// Get a Service Interface from its Handle 63/// Get a Service Interface from its Handle
57Interface* Manager::FetchFromHandle(Handle handle) { 64Interface* Manager::FetchFromHandle(Handle handle) {
58 return Kernel::g_object_pool.GetFast<Interface>(handle); 65 return Kernel::g_object_pool.Get<Interface>(handle);
59} 66}
60 67
61/// Get a Service Interface from its port 68/// Get a Service Interface from its port
@@ -74,20 +81,27 @@ Interface* Manager::FetchFromPortName(const std::string& port_name) {
74/// Initialize ServiceManager 81/// Initialize ServiceManager
75void Init() { 82void Init() {
76 g_manager = new Manager; 83 g_manager = new Manager;
77 84
78 g_manager->AddService(new SRV::Interface); 85 g_manager->AddService(new SRV::Interface);
79 g_manager->AddService(new AC_U::Interface); 86 g_manager->AddService(new AC_U::Interface);
87 g_manager->AddService(new AM_NET::Interface);
80 g_manager->AddService(new APT_U::Interface); 88 g_manager->AddService(new APT_U::Interface);
89 g_manager->AddService(new BOSS_U::Interface);
90 g_manager->AddService(new CFG_I::Interface);
81 g_manager->AddService(new CFG_U::Interface); 91 g_manager->AddService(new CFG_U::Interface);
92 g_manager->AddService(new CSND_SND::Interface);
82 g_manager->AddService(new DSP_DSP::Interface); 93 g_manager->AddService(new DSP_DSP::Interface);
83 g_manager->AddService(new ERR_F::Interface); 94 g_manager->AddService(new ERR_F::Interface);
84 g_manager->AddService(new FRD_U::Interface); 95 g_manager->AddService(new FRD_U::Interface);
85 g_manager->AddService(new FS_User::Interface); 96 g_manager->AddService(new FS_User::Interface);
86 g_manager->AddService(new GSP_GPU::Interface); 97 g_manager->AddService(new GSP_GPU::Interface);
87 g_manager->AddService(new HID_User::Interface); 98 g_manager->AddService(new HID_User::Interface);
99 g_manager->AddService(new IR_RST::Interface);
100 g_manager->AddService(new IR_U::Interface);
88 g_manager->AddService(new MIC_U::Interface); 101 g_manager->AddService(new MIC_U::Interface);
89 g_manager->AddService(new NDM_U::Interface); 102 g_manager->AddService(new NDM_U::Interface);
90 g_manager->AddService(new NWM_UDS::Interface); 103 g_manager->AddService(new NWM_UDS::Interface);
104 g_manager->AddService(new PM_APP::Interface);
91 g_manager->AddService(new PTM_U::Interface); 105 g_manager->AddService(new PTM_U::Interface);
92 g_manager->AddService(new SOC_U::Interface); 106 g_manager->AddService(new SOC_U::Interface);
93 g_manager->AddService(new SSL_C::Interface); 107 g_manager->AddService(new SSL_C::Interface);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 2f5a866c9..20e7fb4d3 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -38,7 +38,7 @@ class Manager;
38class Interface : public Kernel::Object { 38class Interface : public Kernel::Object {
39 friend class Manager; 39 friend class Manager;
40public: 40public:
41 41
42 std::string GetName() const override { return GetPortName(); } 42 std::string GetName() const override { return GetPortName(); }
43 std::string GetTypeName() const override { return GetPortName(); } 43 std::string GetTypeName() const override { return GetPortName(); }
44 44
@@ -75,48 +75,38 @@ public:
75 m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end()); 75 m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end());
76 } 76 }
77 77
78 /** 78 ResultVal<bool> SyncRequest() override {
79 * Synchronize kernel object
80 * @param wait Boolean wait set if current thread should wait as a result of sync operation
81 * @return Result of operation, 0 on success, otherwise error code
82 */
83 Result SyncRequest(bool* wait) override {
84 u32* cmd_buff = GetCommandBuffer(); 79 u32* cmd_buff = GetCommandBuffer();
85 auto itr = m_functions.find(cmd_buff[0]); 80 auto itr = m_functions.find(cmd_buff[0]);
86 81
87 if (itr == m_functions.end()) { 82 if (itr == m_functions.end()) {
88 ERROR_LOG(OSHLE, "unknown/unimplemented function: port=%s, command=0x%08X", 83 ERROR_LOG(OSHLE, "unknown/unimplemented function: port=%s, command=0x%08X",
89 GetPortName().c_str(), cmd_buff[0]); 84 GetPortName().c_str(), cmd_buff[0]);
90 85
91 // TODO(bunnei): Hack - ignore error 86 // TODO(bunnei): Hack - ignore error
92 u32* cmd_buff = Service::GetCommandBuffer(); 87 u32* cmd_buff = Service::GetCommandBuffer();
93 cmd_buff[1] = 0; 88 cmd_buff[1] = 0;
94 return 0; 89 return MakeResult<bool>(false);
95 } 90 }
96 if (itr->second.func == nullptr) { 91 if (itr->second.func == nullptr) {
97 ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s", 92 ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s",
98 GetPortName().c_str(), itr->second.name.c_str()); 93 GetPortName().c_str(), itr->second.name.c_str());
99 94
100 // TODO(bunnei): Hack - ignore error 95 // TODO(bunnei): Hack - ignore error
101 u32* cmd_buff = Service::GetCommandBuffer(); 96 u32* cmd_buff = Service::GetCommandBuffer();
102 cmd_buff[1] = 0; 97 cmd_buff[1] = 0;
103 return 0; 98 return MakeResult<bool>(false);
104 } 99 }
105 100
106 itr->second.func(this); 101 itr->second.func(this);
107 102
108 return 0; // TODO: Implement return from actual function 103 return MakeResult<bool>(false); // TODO: Implement return from actual function
109 } 104 }
110 105
111 /** 106 ResultVal<bool> WaitSynchronization() override {
112 * Wait for kernel object to synchronize
113 * @param wait Boolean wait set if current thread should wait as a result of sync operation
114 * @return Result of operation, 0 on success, otherwise error code
115 */
116 Result WaitSynchronization(bool* wait) override {
117 // TODO(bunnei): ImplementMe 107 // TODO(bunnei): ImplementMe
118 ERROR_LOG(OSHLE, "unimplemented function"); 108 ERROR_LOG(OSHLE, "unimplemented function");
119 return 0; 109 return UnimplementedFunction(ErrorModule::OS);
120 } 110 }
121 111
122protected: 112protected:
diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h
index e27a2b1fe..d5590a683 100644
--- a/src/core/hle/service/soc_u.h
+++ b/src/core/hle/service/soc_u.h
@@ -19,7 +19,7 @@ public:
19 * Gets the string port name used by CTROS for the service 19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service 20 * @return Port name of service
21 */ 21 */
22 std::string GetPortName() const { 22 std::string GetPortName() const override {
23 return "soc:U"; 23 return "soc:U";
24 } 24 }
25}; 25};
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index 6c02a43d9..0e7fa9e3b 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -11,9 +11,9 @@
11 11
12namespace SRV { 12namespace SRV {
13 13
14Handle g_event_handle = 0; 14static Handle g_event_handle = 0;
15 15
16void Initialize(Service::Interface* self) { 16static void Initialize(Service::Interface* self) {
17 DEBUG_LOG(OSHLE, "called"); 17 DEBUG_LOG(OSHLE, "called");
18 18
19 u32* cmd_buff = Service::GetCommandBuffer(); 19 u32* cmd_buff = Service::GetCommandBuffer();
@@ -21,7 +21,7 @@ void Initialize(Service::Interface* self) {
21 cmd_buff[1] = 0; // No error 21 cmd_buff[1] = 0; // No error
22} 22}
23 23
24void GetProcSemaphore(Service::Interface* self) { 24static void GetProcSemaphore(Service::Interface* self) {
25 DEBUG_LOG(OSHLE, "called"); 25 DEBUG_LOG(OSHLE, "called");
26 26
27 u32* cmd_buff = Service::GetCommandBuffer(); 27 u32* cmd_buff = Service::GetCommandBuffer();
@@ -34,8 +34,8 @@ void GetProcSemaphore(Service::Interface* self) {
34 cmd_buff[3] = g_event_handle; 34 cmd_buff[3] = g_event_handle;
35} 35}
36 36
37void GetServiceHandle(Service::Interface* self) { 37static void GetServiceHandle(Service::Interface* self) {
38 Result res = 0; 38 ResultCode res = RESULT_SUCCESS;
39 u32* cmd_buff = Service::GetCommandBuffer(); 39 u32* cmd_buff = Service::GetCommandBuffer();
40 40
41 std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); 41 std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize);
@@ -46,9 +46,9 @@ void GetServiceHandle(Service::Interface* self) {
46 DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); 46 DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]);
47 } else { 47 } else {
48 ERROR_LOG(OSHLE, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); 48 ERROR_LOG(OSHLE, "(UNIMPLEMENTED) called port=%s", port_name.c_str());
49 res = -1; 49 res = UnimplementedFunction(ErrorModule::SRV);
50 } 50 }
51 cmd_buff[1] = res; 51 cmd_buff[1] = res.raw;
52} 52}
53 53
54const Interface::FunctionInfo FunctionTable[] = { 54const Interface::FunctionInfo FunctionTable[] = {
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 1eda36c53..43a3cbe03 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map> 5#include <map>
6 6
@@ -16,6 +16,7 @@
16#include "core/hle/kernel/thread.h" 16#include "core/hle/kernel/thread.h"
17 17
18#include "core/hle/function_wrappers.h" 18#include "core/hle/function_wrappers.h"
19#include "core/hle/result.h"
19#include "core/hle/service/service.h" 20#include "core/hle/service/service.h"
20 21
21//////////////////////////////////////////////////////////////////////////////////////////////////// 22////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -29,8 +30,8 @@ enum ControlMemoryOperation {
29}; 30};
30 31
31/// Map application or GSP heap memory 32/// Map application or GSP heap memory
32Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { 33static Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) {
33 DEBUG_LOG(SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", 34 DEBUG_LOG(SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",
34 operation, addr0, addr1, size, permissions); 35 operation, addr0, addr1, size, permissions);
35 36
36 switch (operation) { 37 switch (operation) {
@@ -53,8 +54,8 @@ Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 siz
53} 54}
54 55
55/// Maps a memory block to specified address 56/// Maps a memory block to specified address
56Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) { 57static Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) {
57 DEBUG_LOG(SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", 58 DEBUG_LOG(SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",
58 handle, addr, permissions, other_permissions); 59 handle, addr, permissions, other_permissions);
59 60
60 Kernel::MemoryPermission permissions_type = static_cast<Kernel::MemoryPermission>(permissions); 61 Kernel::MemoryPermission permissions_type = static_cast<Kernel::MemoryPermission>(permissions);
@@ -63,7 +64,7 @@ Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permis
63 case Kernel::MemoryPermission::Write: 64 case Kernel::MemoryPermission::Write:
64 case Kernel::MemoryPermission::ReadWrite: 65 case Kernel::MemoryPermission::ReadWrite:
65 case Kernel::MemoryPermission::DontCare: 66 case Kernel::MemoryPermission::DontCare:
66 Kernel::MapSharedMemory(handle, addr, permissions_type, 67 Kernel::MapSharedMemory(handle, addr, permissions_type,
67 static_cast<Kernel::MemoryPermission>(other_permissions)); 68 static_cast<Kernel::MemoryPermission>(other_permissions));
68 break; 69 break;
69 default: 70 default:
@@ -73,7 +74,7 @@ Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permis
73} 74}
74 75
75/// Connect to an OS service given the port name, returns the handle to the port to out 76/// Connect to an OS service given the port name, returns the handle to the port to out
76Result ConnectToPort(Handle* out, const char* port_name) { 77static Result ConnectToPort(Handle* out, const char* port_name) {
77 Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); 78 Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
78 79
79 DEBUG_LOG(SVC, "called port_name=%s", port_name); 80 DEBUG_LOG(SVC, "called port_name=%s", port_name);
@@ -85,78 +86,83 @@ Result ConnectToPort(Handle* out, const char* port_name) {
85} 86}
86 87
87/// Synchronize to an OS service 88/// Synchronize to an OS service
88Result SendSyncRequest(Handle handle) { 89static Result SendSyncRequest(Handle handle) {
90 // TODO(yuriks): ObjectPool::Get tries to check the Object type, which fails since this is a generic base Object,
91 // so we are forced to use GetFast and manually verify the handle.
92 if (!Kernel::g_object_pool.IsValid(handle)) {
93 return InvalidHandle(ErrorModule::Kernel).raw;
94 }
89 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); 95 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
90 96
91 _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); 97 _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!");
92 DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName().c_str()); 98 DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName().c_str());
93 99
94 bool wait = false; 100 ResultVal<bool> wait = object->SyncRequest();
95 Result res = object->SyncRequest(&wait); 101 if (wait.Succeeded() && *wait) {
96 if (wait) {
97 Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? 102 Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
98 } 103 }
99 104
100 return res; 105 return wait.Code().raw;
101} 106}
102 107
103/// Close a handle 108/// Close a handle
104Result CloseHandle(Handle handle) { 109static Result CloseHandle(Handle handle) {
105 // ImplementMe 110 // ImplementMe
106 ERROR_LOG(SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle); 111 ERROR_LOG(SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle);
107 return 0; 112 return 0;
108} 113}
109 114
110/// Wait for a handle to synchronize, timeout after the specified nanoseconds 115/// Wait for a handle to synchronize, timeout after the specified nanoseconds
111Result WaitSynchronization1(Handle handle, s64 nano_seconds) { 116static Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
112 // TODO(bunnei): Do something with nano_seconds, currently ignoring this 117 // TODO(bunnei): Do something with nano_seconds, currently ignoring this
113 bool wait = false;
114 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated 118 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
115 119
120 if (!Kernel::g_object_pool.IsValid(handle)) {
121 return InvalidHandle(ErrorModule::Kernel).raw;
122 }
116 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle); 123 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
124 _dbg_assert_(KERNEL, object != nullptr);
117 125
118 DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), 126 DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(),
119 object->GetName().c_str(), nano_seconds); 127 object->GetName().c_str(), nano_seconds);
120 128
121 _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); 129 ResultVal<bool> wait = object->WaitSynchronization();
122
123 Result res = object->WaitSynchronization(&wait);
124 130
125 // Check for next thread to schedule 131 // Check for next thread to schedule
126 if (wait) { 132 if (wait.Succeeded() && *wait) {
127 HLE::Reschedule(__func__); 133 HLE::Reschedule(__func__);
128 return 0;
129 } 134 }
130 135
131 return res; 136 return wait.Code().raw;
132} 137}
133 138
134/// Wait for the given handles to synchronize, timeout after the specified nanoseconds 139/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
135Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, 140static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all,
136 s64 nano_seconds) { 141 s64 nano_seconds) {
137 // TODO(bunnei): Do something with nano_seconds, currently ignoring this 142 // TODO(bunnei): Do something with nano_seconds, currently ignoring this
138 bool unlock_all = true; 143 bool unlock_all = true;
139 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated 144 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
140 145
141 DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld", 146 DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld",
142 handle_count, (wait_all ? "true" : "false"), nano_seconds); 147 handle_count, (wait_all ? "true" : "false"), nano_seconds);
143 148
144 // Iterate through each handle, synchronize kernel object 149 // Iterate through each handle, synchronize kernel object
145 for (s32 i = 0; i < handle_count; i++) { 150 for (s32 i = 0; i < handle_count; i++) {
146 bool wait = false; 151 if (!Kernel::g_object_pool.IsValid(handles[i])) {
152 return InvalidHandle(ErrorModule::Kernel).raw;
153 }
147 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]); 154 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]);
148 155
149 _assert_msg_(KERNEL, (object != nullptr), "called handle=0x%08X, but kernel object " 156 DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName().c_str(),
150 "is nullptr!", handles[i]);
151
152 DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName().c_str(),
153 object->GetName().c_str()); 157 object->GetName().c_str());
154 158
155 Result res = object->WaitSynchronization(&wait); 159 // TODO(yuriks): Verify how the real function behaves when an error happens here
160 ResultVal<bool> wait_result = object->WaitSynchronization();
161 bool wait = wait_result.Succeeded() && *wait_result;
156 162
157 if (!wait && !wait_all) { 163 if (!wait && !wait_all) {
158 *out = i; 164 *out = i;
159 return 0; 165 return RESULT_SUCCESS.raw;
160 } else { 166 } else {
161 unlock_all = false; 167 unlock_all = false;
162 } 168 }
@@ -164,17 +170,17 @@ Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wa
164 170
165 if (wait_all && unlock_all) { 171 if (wait_all && unlock_all) {
166 *out = handle_count; 172 *out = handle_count;
167 return 0; 173 return RESULT_SUCCESS.raw;
168 } 174 }
169 175
170 // Check for next thread to schedule 176 // Check for next thread to schedule
171 HLE::Reschedule(__func__); 177 HLE::Reschedule(__func__);
172 178
173 return 0; 179 return RESULT_SUCCESS.raw;
174} 180}
175 181
176/// Create an address arbiter (to allocate access to shared resources) 182/// Create an address arbiter (to allocate access to shared resources)
177Result CreateAddressArbiter(u32* arbiter) { 183static Result CreateAddressArbiter(u32* arbiter) {
178 DEBUG_LOG(SVC, "called"); 184 DEBUG_LOG(SVC, "called");
179 Handle handle = Kernel::CreateAddressArbiter(); 185 Handle handle = Kernel::CreateAddressArbiter();
180 *arbiter = handle; 186 *arbiter = handle;
@@ -182,20 +188,22 @@ Result CreateAddressArbiter(u32* arbiter) {
182} 188}
183 189
184/// Arbitrate address 190/// Arbitrate address
185Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) { 191static Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) {
186 return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type), address, 192 DEBUG_LOG(SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", arbiter,
187 value); 193 address, type, value);
194 return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type),
195 address, value).raw;
188} 196}
189 197
190/// Used to output a message on a debug hardware unit - does nothing on a retail unit 198/// Used to output a message on a debug hardware unit - does nothing on a retail unit
191void OutputDebugString(const char* string) { 199static void OutputDebugString(const char* string) {
192 OS_LOG(SVC, "%s", string); 200 OS_LOG(SVC, "%s", string);
193} 201}
194 202
195/// Get resource limit 203/// Get resource limit
196Result GetResourceLimit(Handle* resource_limit, Handle process) { 204static Result GetResourceLimit(Handle* resource_limit, Handle process) {
197 // With regards to proceess values: 205 // With regards to proceess values:
198 // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for 206 // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for
199 // the current KThread. 207 // the current KThread.
200 *resource_limit = 0xDEADBEEF; 208 *resource_limit = 0xDEADBEEF;
201 ERROR_LOG(SVC, "(UNIMPLEMENTED) called process=0x%08X", process); 209 ERROR_LOG(SVC, "(UNIMPLEMENTED) called process=0x%08X", process);
@@ -203,7 +211,7 @@ Result GetResourceLimit(Handle* resource_limit, Handle process) {
203} 211}
204 212
205/// Get resource limit current values 213/// Get resource limit current values
206Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names, 214static Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names,
207 s32 name_count) { 215 s32 name_count) {
208 ERROR_LOG(SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d", 216 ERROR_LOG(SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d",
209 resource_limit, names, name_count); 217 resource_limit, names, name_count);
@@ -212,7 +220,7 @@ Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* n
212} 220}
213 221
214/// Creates a new thread 222/// Creates a new thread
215Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) { 223static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) {
216 std::string name; 224 std::string name;
217 if (Symbols::HasSymbol(entry_point)) { 225 if (Symbols::HasSymbol(entry_point)) {
218 TSymbol symbol = Symbols::GetSymbol(entry_point); 226 TSymbol symbol = Symbols::GetSymbol(entry_point);
@@ -227,14 +235,14 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p
227 Core::g_app_core->SetReg(1, thread); 235 Core::g_app_core->SetReg(1, thread);
228 236
229 DEBUG_LOG(SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " 237 DEBUG_LOG(SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
230 "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, 238 "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point,
231 name.c_str(), arg, stack_top, priority, processor_id, thread); 239 name.c_str(), arg, stack_top, priority, processor_id, thread);
232 240
233 return 0; 241 return 0;
234} 242}
235 243
236/// Called when a thread exits 244/// Called when a thread exits
237u32 ExitThread() { 245static u32 ExitThread() {
238 Handle thread = Kernel::GetCurrentThreadHandle(); 246 Handle thread = Kernel::GetCurrentThreadHandle();
239 247
240 DEBUG_LOG(SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); // PC = 0x0010545C 248 DEBUG_LOG(SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); // PC = 0x0010545C
@@ -245,54 +253,56 @@ u32 ExitThread() {
245} 253}
246 254
247/// Gets the priority for the specified thread 255/// Gets the priority for the specified thread
248Result GetThreadPriority(s32* priority, Handle handle) { 256static Result GetThreadPriority(s32* priority, Handle handle) {
249 *priority = Kernel::GetThreadPriority(handle); 257 ResultVal<u32> priority_result = Kernel::GetThreadPriority(handle);
250 return 0; 258 if (priority_result.Succeeded()) {
259 *priority = *priority_result;
260 }
261 return priority_result.Code().raw;
251} 262}
252 263
253/// Sets the priority for the specified thread 264/// Sets the priority for the specified thread
254Result SetThreadPriority(Handle handle, s32 priority) { 265static Result SetThreadPriority(Handle handle, s32 priority) {
255 return Kernel::SetThreadPriority(handle, priority); 266 return Kernel::SetThreadPriority(handle, priority).raw;
256} 267}
257 268
258/// Create a mutex 269/// Create a mutex
259Result CreateMutex(Handle* mutex, u32 initial_locked) { 270static Result CreateMutex(Handle* mutex, u32 initial_locked) {
260 *mutex = Kernel::CreateMutex((initial_locked != 0)); 271 *mutex = Kernel::CreateMutex((initial_locked != 0));
261 DEBUG_LOG(SVC, "called initial_locked=%s : created handle=0x%08X", 272 DEBUG_LOG(SVC, "called initial_locked=%s : created handle=0x%08X",
262 initial_locked ? "true" : "false", *mutex); 273 initial_locked ? "true" : "false", *mutex);
263 return 0; 274 return 0;
264} 275}
265 276
266/// Release a mutex 277/// Release a mutex
267Result ReleaseMutex(Handle handle) { 278static Result ReleaseMutex(Handle handle) {
268 DEBUG_LOG(SVC, "called handle=0x%08X", handle); 279 DEBUG_LOG(SVC, "called handle=0x%08X", handle);
269 _assert_msg_(KERNEL, (handle != 0), "called, but handle is nullptr!"); 280 ResultCode res = Kernel::ReleaseMutex(handle);
270 Kernel::ReleaseMutex(handle); 281 return res.raw;
271 return 0;
272} 282}
273 283
274/// Get current thread ID 284/// Get current thread ID
275Result GetThreadId(u32* thread_id, Handle thread) { 285static Result GetThreadId(u32* thread_id, Handle thread) {
276 ERROR_LOG(SVC, "(UNIMPLEMENTED) called thread=0x%08X", thread); 286 ERROR_LOG(SVC, "(UNIMPLEMENTED) called thread=0x%08X", thread);
277 return 0; 287 return 0;
278} 288}
279 289
280/// Query memory 290/// Query memory
281Result QueryMemory(void* info, void* out, u32 addr) { 291static Result QueryMemory(void* info, void* out, u32 addr) {
282 ERROR_LOG(SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr); 292 ERROR_LOG(SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr);
283 return 0; 293 return 0;
284} 294}
285 295
286/// Create an event 296/// Create an event
287Result CreateEvent(Handle* evt, u32 reset_type) { 297static Result CreateEvent(Handle* evt, u32 reset_type) {
288 *evt = Kernel::CreateEvent((ResetType)reset_type); 298 *evt = Kernel::CreateEvent((ResetType)reset_type);
289 DEBUG_LOG(SVC, "called reset_type=0x%08X : created handle=0x%08X", 299 DEBUG_LOG(SVC, "called reset_type=0x%08X : created handle=0x%08X",
290 reset_type, *evt); 300 reset_type, *evt);
291 return 0; 301 return 0;
292} 302}
293 303
294/// Duplicates a kernel handle 304/// Duplicates a kernel handle
295Result DuplicateHandle(Handle* out, Handle handle) { 305static Result DuplicateHandle(Handle* out, Handle handle) {
296 DEBUG_LOG(SVC, "called handle=0x%08X", handle); 306 DEBUG_LOG(SVC, "called handle=0x%08X", handle);
297 307
298 // Translate kernel handles -> real handles 308 // Translate kernel handles -> real handles
@@ -301,7 +311,7 @@ Result DuplicateHandle(Handle* out, Handle handle) {
301 } 311 }
302 _assert_msg_(KERNEL, (handle != Kernel::CurrentProcess), 312 _assert_msg_(KERNEL, (handle != Kernel::CurrentProcess),
303 "(UNIMPLEMENTED) process handle duplication!"); 313 "(UNIMPLEMENTED) process handle duplication!");
304 314
305 // TODO(bunnei): FixMe - This is a hack to return the handle that we were asked to duplicate. 315 // TODO(bunnei): FixMe - This is a hack to return the handle that we were asked to duplicate.
306 *out = handle; 316 *out = handle;
307 317
@@ -309,26 +319,27 @@ Result DuplicateHandle(Handle* out, Handle handle) {
309} 319}
310 320
311/// Signals an event 321/// Signals an event
312Result SignalEvent(Handle evt) { 322static Result SignalEvent(Handle evt) {
313 Result res = Kernel::SignalEvent(evt);
314 DEBUG_LOG(SVC, "called event=0x%08X", evt); 323 DEBUG_LOG(SVC, "called event=0x%08X", evt);
315 return res; 324 return Kernel::SignalEvent(evt).raw;
316} 325}
317 326
318/// Clears an event 327/// Clears an event
319Result ClearEvent(Handle evt) { 328static Result ClearEvent(Handle evt) {
320 Result res = Kernel::ClearEvent(evt);
321 DEBUG_LOG(SVC, "called event=0x%08X", evt); 329 DEBUG_LOG(SVC, "called event=0x%08X", evt);
322 return res; 330 return Kernel::ClearEvent(evt).raw;
323} 331}
324 332
325/// Sleep the current thread 333/// Sleep the current thread
326void SleepThread(s64 nanoseconds) { 334static void SleepThread(s64 nanoseconds) {
327 DEBUG_LOG(SVC, "called nanoseconds=%lld", nanoseconds); 335 DEBUG_LOG(SVC, "called nanoseconds=%lld", nanoseconds);
336
337 // Check for next thread to schedule
338 HLE::Reschedule(__func__);
328} 339}
329 340
330/// This returns the total CPU ticks elapsed since the CPU was powered-on 341/// This returns the total CPU ticks elapsed since the CPU was powered-on
331s64 GetSystemTick() { 342static s64 GetSystemTick() {
332 return (s64)Core::g_app_core->GetTicks(); 343 return (s64)Core::g_app_core->GetTicks();
333} 344}
334 345
diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h
index 1d125faf6..6be393d0b 100644
--- a/src/core/hle/svc.h
+++ b/src/core/hle/svc.h
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 3ad801c63..af5e1b39b 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -49,7 +49,7 @@ inline void Write(u32 addr, const T data) {
49 49
50 // Writes other than u32 are untested, so I'd rather have them abort than silently fail 50 // Writes other than u32 are untested, so I'd rather have them abort than silently fail
51 if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { 51 if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) {
52 ERROR_LOG(GPU, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); 52 ERROR_LOG(GPU, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr);
53 return; 53 return;
54 } 54 }
55 55
@@ -140,8 +140,8 @@ inline void Write(u32 addr, const T data) {
140 140
141 DEBUG_LOG(GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x", 141 DEBUG_LOG(GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x",
142 config.output_height * config.output_width * 4, 142 config.output_height * config.output_width * 4,
143 config.GetPhysicalInputAddress(), config.input_width, config.input_height, 143 config.GetPhysicalInputAddress(), (u32)config.input_width, (u32)config.input_height,
144 config.GetPhysicalOutputAddress(), config.output_width, config.output_height, 144 config.GetPhysicalOutputAddress(), (u32)config.output_width, (u32)config.output_height,
145 config.output_format.Value()); 145 config.output_format.Value());
146 } 146 }
147 break; 147 break;
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp
index 33f75c50a..ea001673a 100644
--- a/src/core/hw/hw.cpp
+++ b/src/core/hw/hw.cpp
@@ -39,7 +39,7 @@ enum {
39template <typename T> 39template <typename T>
40inline void Read(T &var, const u32 addr) { 40inline void Read(T &var, const u32 addr) {
41 switch (addr & 0xFFFFF000) { 41 switch (addr & 0xFFFFF000) {
42 42
43 // TODO(bunnei): What is the virtual address of NDMA? 43 // TODO(bunnei): What is the virtual address of NDMA?
44 // case VADDR_NDMA: 44 // case VADDR_NDMA:
45 // NDMA::Read(var, addr); 45 // NDMA::Read(var, addr);
@@ -57,9 +57,9 @@ inline void Read(T &var, const u32 addr) {
57template <typename T> 57template <typename T>
58inline void Write(u32 addr, const T data) { 58inline void Write(u32 addr, const T data) {
59 switch (addr & 0xFFFFF000) { 59 switch (addr & 0xFFFFF000) {
60 60
61 // TODO(bunnei): What is the virtual address of NDMA? 61 // TODO(bunnei): What is the virtual address of NDMA?
62 // case VADDR_NDMA 62 // case VADDR_NDMA
63 // NDMA::Write(addr, data); 63 // NDMA::Write(addr, data);
64 // break; 64 // break;
65 65
@@ -68,7 +68,7 @@ inline void Write(u32 addr, const T data) {
68 break; 68 break;
69 69
70 default: 70 default:
71 ERROR_LOG(HW, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); 71 ERROR_LOG(HW, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr);
72 } 72 }
73} 73}
74 74
diff --git a/src/core/hw/ndma.cpp b/src/core/hw/ndma.cpp
index e29a773f1..593e5de30 100644
--- a/src/core/hw/ndma.cpp
+++ b/src/core/hw/ndma.cpp
@@ -15,7 +15,7 @@ inline void Read(T &var, const u32 addr) {
15 15
16template <typename T> 16template <typename T>
17inline void Write(u32 addr, const T data) { 17inline void Write(u32 addr, const T data) {
18 ERROR_LOG(NDMA, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); 18 ERROR_LOG(NDMA, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr);
19} 19}
20 20
21// Explicitly instantiate template functions because we aren't defining this in the header: 21// Explicitly instantiate template functions because we aren't defining this in the header:
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 389d5a8c9..63d2496ed 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -273,13 +273,13 @@ bool ElfReader::LoadInto(u32 vaddr) {
273 273
274 for (int i = 0; i < header->e_phnum; i++) { 274 for (int i = 0; i < header->e_phnum; i++) {
275 Elf32_Phdr *p = segments + i; 275 Elf32_Phdr *p = segments + i;
276 INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, 276 INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr,
277 p->p_filesz, p->p_memsz); 277 p->p_filesz, p->p_memsz);
278 278
279 if (p->p_type == PT_LOAD) { 279 if (p->p_type == PT_LOAD) {
280 segment_addr[i] = base_addr + p->p_vaddr; 280 segment_addr[i] = base_addr + p->p_vaddr;
281 memcpy(Memory::GetPointer(segment_addr[i]), GetSegmentPtr(i), p->p_filesz); 281 memcpy(Memory::GetPointer(segment_addr[i]), GetSegmentPtr(i), p->p_filesz);
282 INFO_LOG(MASTER_LOG, "Loadable Segment Copied to %08x, size %08x", segment_addr[i], 282 INFO_LOG(MASTER_LOG, "Loadable Segment Copied to %08x, size %08x", segment_addr[i],
283 p->p_memsz); 283 p->p_memsz);
284 } 284 }
285 } 285 }
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 1e5501e6d..343bb7523 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -24,7 +24,7 @@ static const int kBlockSize = 0x200; ///< Size of ExeFS blocks (in bytes)
24 * @param size Size of compressed buffer 24 * @param size Size of compressed buffer
25 * @return Size of decompressed buffer 25 * @return Size of decompressed buffer
26 */ 26 */
27u32 LZSS_GetDecompressedSize(u8* buffer, u32 size) { 27static u32 LZSS_GetDecompressedSize(u8* buffer, u32 size) {
28 u32 offset_size = *(u32*)(buffer + size - 4); 28 u32 offset_size = *(u32*)(buffer + size - 4);
29 return offset_size + size; 29 return offset_size + size;
30} 30}
@@ -37,7 +37,7 @@ u32 LZSS_GetDecompressedSize(u8* buffer, u32 size) {
37 * @param decompressed_size Size of decompressed buffer 37 * @param decompressed_size Size of decompressed buffer
38 * @return True on success, otherwise false 38 * @return True on success, otherwise false
39 */ 39 */
40bool LZSS_Decompress(u8* compressed, u32 compressed_size, u8* decompressed, u32 decompressed_size) { 40static bool LZSS_Decompress(u8* compressed, u32 compressed_size, u8* decompressed, u32 decompressed_size) {
41 u8* footer = compressed + compressed_size - 8; 41 u8* footer = compressed + compressed_size - 8;
42 u32 buffer_top_and_bottom = *(u32*)footer; 42 u32 buffer_top_and_bottom = *(u32*)footer;
43 u32 out = decompressed_size; 43 u32 out = decompressed_size;
@@ -118,7 +118,7 @@ AppLoader_NCCH::~AppLoader_NCCH() {
118 * @return ResultStatus result of function 118 * @return ResultStatus result of function
119 */ 119 */
120ResultStatus AppLoader_NCCH::LoadExec() const { 120ResultStatus AppLoader_NCCH::LoadExec() const {
121 if (!is_loaded) 121 if (!is_loaded)
122 return ResultStatus::ErrorNotLoaded; 122 return ResultStatus::ErrorNotLoaded;
123 123
124 std::vector<u8> code; 124 std::vector<u8> code;
@@ -185,7 +185,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>&
185 return ResultStatus::Error; 185 return ResultStatus::Error;
186 } 186 }
187 return ResultStatus::ErrorNotUsed; 187 return ResultStatus::ErrorNotUsed;
188} 188}
189 189
190/** 190/**
191 * Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI) 191 * Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI)
@@ -210,7 +210,7 @@ ResultStatus AppLoader_NCCH::Load() {
210 file.Seek(ncch_offset, 0); 210 file.Seek(ncch_offset, 0);
211 file.ReadBytes(&ncch_header, sizeof(NCCH_Header)); 211 file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
212 } 212 }
213 213
214 // Verify we are loading the correct file type... 214 // Verify we are loading the correct file type...
215 if (0 != memcmp(&ncch_header.magic, "NCCH", 4)) 215 if (0 != memcmp(&ncch_header.magic, "NCCH", 4))
216 return ResultStatus::ErrorInvalidFormat; 216 return ResultStatus::ErrorInvalidFormat;
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index f40a258b7..03116add8 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -215,7 +215,7 @@ private:
215 u32 entry_point; 215 u32 entry_point;
216 u32 ncch_offset; // Offset to NCCH header, can be 0 or after NCSD header 216 u32 ncch_offset; // Offset to NCCH header, can be 0 or after NCSD header
217 u32 exefs_offset; 217 u32 exefs_offset;
218 218
219 NCCH_Header ncch_header; 219 NCCH_Header ncch_header;
220 ExeFs_Header exefs_header; 220 ExeFs_Header exefs_header;
221 ExHeader_Header exheader_header; 221 ExHeader_Header exheader_header;
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp
index cf12f24d9..74a93b1d9 100644
--- a/src/core/mem_map.cpp
+++ b/src/core/mem_map.cpp
@@ -11,38 +11,38 @@
11 11
12namespace Memory { 12namespace Memory {
13 13
14u8* g_base = NULL; ///< The base pointer to the auto-mirrored arena. 14u8* g_base = nullptr; ///< The base pointer to the auto-mirrored arena.
15 15
16MemArena g_arena; ///< The MemArena class 16static MemArena arena; ///< The MemArena class
17 17
18u8* g_exefs_code = NULL; ///< ExeFS:/.code is loaded here 18u8* g_exefs_code = nullptr; ///< ExeFS:/.code is loaded here
19u8* g_system_mem = NULL; ///< System memory 19u8* g_system_mem = nullptr; ///< System memory
20u8* g_heap = NULL; ///< Application heap (main memory) 20u8* g_heap = nullptr; ///< Application heap (main memory)
21u8* g_heap_gsp = NULL; ///< GSP heap (main memory) 21u8* g_heap_gsp = nullptr; ///< GSP heap (main memory)
22u8* g_vram = NULL; ///< Video memory (VRAM) pointer 22u8* g_vram = nullptr; ///< Video memory (VRAM) pointer
23u8* g_shared_mem = NULL; ///< Shared memory 23u8* g_shared_mem = nullptr; ///< Shared memory
24u8* g_kernel_mem; ///< Kernel memory 24u8* g_kernel_mem; ///< Kernel memory
25 25
26u8* g_physical_bootrom = NULL; ///< Bootrom physical memory 26static u8* physical_bootrom = nullptr; ///< Bootrom physical memory
27u8* g_uncached_bootrom = NULL; 27static u8* uncached_bootrom = nullptr;
28 28
29u8* g_physical_exefs_code = NULL; ///< Phsical ExeFS:/.code is loaded here 29static u8* physical_exefs_code = nullptr; ///< Phsical ExeFS:/.code is loaded here
30u8* g_physical_system_mem = NULL; ///< System physical memory 30static u8* physical_system_mem = nullptr; ///< System physical memory
31u8* g_physical_fcram = NULL; ///< Main physical memory (FCRAM) 31static u8* physical_fcram = nullptr; ///< Main physical memory (FCRAM)
32u8* g_physical_heap_gsp = NULL; ///< GSP heap physical memory 32static u8* physical_heap_gsp = nullptr; ///< GSP heap physical memory
33u8* g_physical_vram = NULL; ///< Video physical memory (VRAM) 33static u8* physical_vram = nullptr; ///< Video physical memory (VRAM)
34u8* g_physical_shared_mem = NULL; ///< Physical shared memory 34static u8* physical_shared_mem = nullptr; ///< Physical shared memory
35u8* g_physical_kernel_mem; ///< Kernel memory 35static u8* physical_kernel_mem; ///< Kernel memory
36 36
37// We don't declare the IO region in here since its handled by other means. 37// We don't declare the IO region in here since its handled by other means.
38static MemoryView g_views[] = { 38static MemoryView g_views[] = {
39 {&g_exefs_code, &g_physical_exefs_code, EXEFS_CODE_VADDR, EXEFS_CODE_SIZE, 0}, 39 {&g_exefs_code, &physical_exefs_code, EXEFS_CODE_VADDR, EXEFS_CODE_SIZE, 0},
40 {&g_vram, &g_physical_vram, VRAM_VADDR, VRAM_SIZE, 0}, 40 {&g_vram, &physical_vram, VRAM_VADDR, VRAM_SIZE, 0},
41 {&g_heap, &g_physical_fcram, HEAP_VADDR, HEAP_SIZE, MV_IS_PRIMARY_RAM}, 41 {&g_heap, &physical_fcram, HEAP_VADDR, HEAP_SIZE, MV_IS_PRIMARY_RAM},
42 {&g_shared_mem, &g_physical_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, 0}, 42 {&g_shared_mem, &physical_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, 0},
43 {&g_system_mem, &g_physical_system_mem, SYSTEM_MEMORY_VADDR, SYSTEM_MEMORY_SIZE, 0}, 43 {&g_system_mem, &physical_system_mem, SYSTEM_MEMORY_VADDR, SYSTEM_MEMORY_SIZE, 0},
44 {&g_kernel_mem, &g_physical_kernel_mem, KERNEL_MEMORY_VADDR, KERNEL_MEMORY_SIZE, 0}, 44 {&g_kernel_mem, &physical_kernel_mem, KERNEL_MEMORY_VADDR, KERNEL_MEMORY_SIZE, 0},
45 {&g_heap_gsp, &g_physical_heap_gsp, HEAP_GSP_VADDR, HEAP_GSP_SIZE, 0}, 45 {&g_heap_gsp, &physical_heap_gsp, HEAP_GSP_VADDR, HEAP_GSP_SIZE, 0},
46}; 46};
47 47
48/*static MemoryView views[] = 48/*static MemoryView views[] =
@@ -69,18 +69,18 @@ void Init() {
69 g_views[i].size = FCRAM_SIZE; 69 g_views[i].size = FCRAM_SIZE;
70 } 70 }
71 71
72 g_base = MemoryMap_Setup(g_views, kNumMemViews, flags, &g_arena); 72 g_base = MemoryMap_Setup(g_views, kNumMemViews, flags, &arena);
73 73
74 NOTICE_LOG(MEMMAP, "initialized OK, RAM at %p (mirror at 0 @ %p)", g_heap, 74 NOTICE_LOG(MEMMAP, "initialized OK, RAM at %p (mirror at 0 @ %p)", g_heap,
75 g_physical_fcram); 75 physical_fcram);
76} 76}
77 77
78void Shutdown() { 78void Shutdown() {
79 u32 flags = 0; 79 u32 flags = 0;
80 MemoryMap_Shutdown(g_views, kNumMemViews, flags, &g_arena); 80 MemoryMap_Shutdown(g_views, kNumMemViews, flags, &arena);
81 81
82 g_arena.ReleaseSpace(); 82 arena.ReleaseSpace();
83 g_base = NULL; 83 g_base = nullptr;
84 84
85 NOTICE_LOG(MEMMAP, "shutdown OK"); 85 NOTICE_LOG(MEMMAP, "shutdown OK");
86} 86}
diff --git a/src/core/mem_map.h b/src/core/mem_map.h
index eed445046..a58c59244 100644
--- a/src/core/mem_map.h
+++ b/src/core/mem_map.h
@@ -147,6 +147,7 @@ u32 Read16_ZX(VAddr addr);
147void Write8(VAddr addr, u8 data); 147void Write8(VAddr addr, u8 data);
148void Write16(VAddr addr, u16 data); 148void Write16(VAddr addr, u16 data);
149void Write32(VAddr addr, u32 data); 149void Write32(VAddr addr, u32 data);
150void Write64(VAddr addr, u64 data);
150 151
151void WriteBlock(VAddr addr, const u8* data, size_t size); 152void WriteBlock(VAddr addr, const u8* data, size_t size);
152 153
@@ -156,7 +157,7 @@ u8* GetPointer(VAddr virtual_address);
156 * Maps a block of memory on the heap 157 * Maps a block of memory on the heap
157 * @param size Size of block in bytes 158 * @param size Size of block in bytes
158 * @param operation Memory map operation type 159 * @param operation Memory map operation type
159 * @param flags Memory allocation flags 160 * @param permissions Memory allocation permissions
160 */ 161 */
161u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions); 162u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions);
162 163
diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp
index 90951812b..e8747840c 100644
--- a/src/core/mem_map_funcs.cpp
+++ b/src/core/mem_map_funcs.cpp
@@ -12,9 +12,9 @@
12 12
13namespace Memory { 13namespace Memory {
14 14
15std::map<u32, MemoryBlock> g_heap_map; 15static std::map<u32, MemoryBlock> heap_map;
16std::map<u32, MemoryBlock> g_heap_gsp_map; 16static std::map<u32, MemoryBlock> heap_gsp_map;
17std::map<u32, MemoryBlock> g_shared_map; 17static std::map<u32, MemoryBlock> shared_map;
18 18
19/// Convert a physical address to virtual address 19/// Convert a physical address to virtual address
20VAddr PhysicalToVirtualAddress(const PAddr addr) { 20VAddr PhysicalToVirtualAddress(const PAddr addr) {
@@ -92,7 +92,7 @@ inline void Read(T &var, const VAddr vaddr) {
92 var = *((const T*)&g_vram[vaddr & VRAM_MASK]); 92 var = *((const T*)&g_vram[vaddr & VRAM_MASK]);
93 93
94 } else { 94 } else {
95 ERROR_LOG(MEMMAP, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr); 95 ERROR_LOG(MEMMAP, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, vaddr);
96 } 96 }
97} 97}
98 98
@@ -141,7 +141,7 @@ inline void Write(const VAddr vaddr, const T data) {
141 141
142 // Error out... 142 // Error out...
143 } else { 143 } else {
144 ERROR_LOG(MEMMAP, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, vaddr); 144 ERROR_LOG(MEMMAP, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, vaddr);
145 } 145 }
146} 146}
147 147
@@ -194,11 +194,11 @@ u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) {
194 block.operation = operation; 194 block.operation = operation;
195 block.permissions = permissions; 195 block.permissions = permissions;
196 196
197 if (g_heap_map.size() > 0) { 197 if (heap_map.size() > 0) {
198 const MemoryBlock last_block = g_heap_map.rbegin()->second; 198 const MemoryBlock last_block = heap_map.rbegin()->second;
199 block.address = last_block.address + last_block.size; 199 block.address = last_block.address + last_block.size;
200 } 200 }
201 g_heap_map[block.GetVirtualAddress()] = block; 201 heap_map[block.GetVirtualAddress()] = block;
202 202
203 return block.GetVirtualAddress(); 203 return block.GetVirtualAddress();
204} 204}
@@ -217,11 +217,11 @@ u32 MapBlock_HeapGSP(u32 size, u32 operation, u32 permissions) {
217 block.operation = operation; 217 block.operation = operation;
218 block.permissions = permissions; 218 block.permissions = permissions;
219 219
220 if (g_heap_gsp_map.size() > 0) { 220 if (heap_gsp_map.size() > 0) {
221 const MemoryBlock last_block = g_heap_gsp_map.rbegin()->second; 221 const MemoryBlock last_block = heap_gsp_map.rbegin()->second;
222 block.address = last_block.address + last_block.size; 222 block.address = last_block.address + last_block.size;
223 } 223 }
224 g_heap_gsp_map[block.GetVirtualAddress()] = block; 224 heap_gsp_map[block.GetVirtualAddress()] = block;
225 225
226 return block.GetVirtualAddress(); 226 return block.GetVirtualAddress();
227} 227}
diff --git a/src/core/system.h b/src/core/system.h
index 8f8ddf87b..2bc2edc75 100644
--- a/src/core/system.h
+++ b/src/core/system.h
@@ -11,16 +11,16 @@
11namespace System { 11namespace System {
12 12
13// State of the full emulator 13// State of the full emulator
14typedef enum { 14enum State {
15 STATE_NULL = 0, ///< System is in null state, nothing initialized 15 STATE_NULL = 0, ///< System is in null state, nothing initialized
16 STATE_IDLE, ///< System is in an initialized state, but not running 16 STATE_IDLE, ///< System is in an initialized state, but not running
17 STATE_RUNNING, ///< System is running 17 STATE_RUNNING, ///< System is running
18 STATE_LOADING, ///< System is loading a ROM 18 STATE_LOADING, ///< System is loading a ROM
19 STATE_HALTED, ///< System is halted (error) 19 STATE_HALTED, ///< System is halted (error)
20 STATE_STALLED, ///< System is stalled (unused) 20 STATE_STALLED, ///< System is stalled (unused)
21 STATE_DEBUG, ///< System is in a special debug mode (unused) 21 STATE_DEBUG, ///< System is in a special debug mode (unused)
22 STATE_DIE ///< System is shutting down 22 STATE_DIE ///< System is shutting down
23} State; 23};
24 24
25extern volatile State g_state; 25extern volatile State g_state;
26 26
@@ -30,4 +30,4 @@ void RunLoopFor(int cycles);
30void RunLoopUntil(u64 global_cycles); 30void RunLoopUntil(u64 global_cycles);
31void Shutdown(); 31void Shutdown();
32 32
33}; 33}
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 22b8e9950..275b06b7c 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -318,9 +318,9 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
318 return; 318 return;
319 319
320#ifndef HAVE_PNG 320#ifndef HAVE_PNG
321 return; 321 return;
322#else 322#else
323 if (!data) 323 if (!data)
324 return; 324 return;
325 325
326 // Write data to file 326 // Write data to file
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
index 8b1499bf2..b1558cfae 100644
--- a/src/video_core/debug_utils/debug_utils.h
+++ b/src/video_core/debug_utils/debug_utils.h
@@ -41,7 +41,7 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data
41// Utility class to log Pica commands. 41// Utility class to log Pica commands.
42struct PicaTrace { 42struct PicaTrace {
43 struct Write : public std::pair<u32,u32> { 43 struct Write : public std::pair<u32,u32> {
44 Write(u32 id, u32 value) : std::pair<u32,u32>(id, value) {} 44 Write(u32 id, u32 value) : std::pair<u32,u32>(id, value) {}
45 45
46 u32& Id() { return first; } 46 u32& Id() { return first; }
47 const u32& Id() const { return first; } 47 const u32& Id() const { return first; }
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index f1dbc9d17..bce402b88 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -25,7 +25,7 @@ public:
25 /// Swap buffers (render frame) 25 /// Swap buffers (render frame)
26 virtual void SwapBuffers() = 0; 26 virtual void SwapBuffers() = 0;
27 27
28 /** 28 /**
29 * Set the emulator window to use for renderer 29 * Set the emulator window to use for renderer
30 * @param window EmuWindow handle to emulator window to use for rendering 30 * @param window EmuWindow handle to emulator window to use for rendering
31 */ 31 */
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 8483f79be..abbb4c2cb 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -191,7 +191,8 @@ void RendererOpenGL::DrawSingleScreenRotated(const TextureInfo& texture, float x
191 * Draws the emulated screens to the emulator window. 191 * Draws the emulated screens to the emulator window.
192 */ 192 */
193void RendererOpenGL::DrawScreens() { 193void RendererOpenGL::DrawScreens() {
194 glViewport(0, 0, resolution_width, resolution_height); 194 auto viewport_extent = GetViewportExtent();
195 glViewport(viewport_extent.left, viewport_extent.top, viewport_extent.GetWidth(), viewport_extent.GetHeight()); // TODO: Or bottom?
195 glClear(GL_COLOR_BUFFER_BIT); 196 glClear(GL_COLOR_BUFFER_BIT);
196 197
197 glUseProgram(program_id); 198 glUseProgram(program_id);
@@ -228,6 +229,34 @@ void RendererOpenGL::SetWindow(EmuWindow* window) {
228 render_window = window; 229 render_window = window;
229} 230}
230 231
232MathUtil::Rectangle<unsigned> RendererOpenGL::GetViewportExtent() {
233 unsigned framebuffer_width;
234 unsigned framebuffer_height;
235 std::tie(framebuffer_width, framebuffer_height) = render_window->GetFramebufferSize();
236
237 float window_aspect_ratio = static_cast<float>(framebuffer_height) / framebuffer_width;
238 float emulation_aspect_ratio = static_cast<float>(resolution_height) / resolution_width;
239
240 MathUtil::Rectangle<unsigned> viewport_extent;
241 if (window_aspect_ratio > emulation_aspect_ratio) {
242 // Window is narrower than the emulation content => apply borders to the top and bottom
243 unsigned viewport_height = emulation_aspect_ratio * framebuffer_width;
244 viewport_extent.left = 0;
245 viewport_extent.top = (framebuffer_height - viewport_height) / 2;
246 viewport_extent.right = viewport_extent.left + framebuffer_width;
247 viewport_extent.bottom = viewport_extent.top + viewport_height;
248 } else {
249 // Otherwise, apply borders to the left and right sides of the window.
250 unsigned viewport_width = framebuffer_height / emulation_aspect_ratio;
251 viewport_extent.left = (framebuffer_width - viewport_width) / 2;
252 viewport_extent.top = 0;
253 viewport_extent.right = viewport_extent.left + viewport_width;
254 viewport_extent.bottom = viewport_extent.top + framebuffer_height;
255 }
256
257 return viewport_extent;
258}
259
231/// Initialize the renderer 260/// Initialize the renderer
232void RendererOpenGL::Init() { 261void RendererOpenGL::Init() {
233 render_window->MakeCurrent(); 262 render_window->MakeCurrent();
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index eed201a95..7fdcec731 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -4,13 +4,15 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array>
8
7#include "generated/gl_3_2_core.h" 9#include "generated/gl_3_2_core.h"
8 10
9#include "common/common.h" 11#include "common/math_util.h"
12
10#include "core/hw/gpu.h" 13#include "core/hw/gpu.h"
11#include "video_core/renderer_base.h"
12 14
13#include <array> 15#include "video_core/renderer_base.h"
14 16
15class EmuWindow; 17class EmuWindow;
16 18
@@ -52,6 +54,9 @@ private:
52 static void LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer, 54 static void LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& framebuffer,
53 const TextureInfo& texture); 55 const TextureInfo& texture);
54 56
57 /// Computes the viewport rectangle
58 MathUtil::Rectangle<unsigned> GetViewportExtent();
59
55 EmuWindow* render_window; ///< Handle to render window 60 EmuWindow* render_window; ///< Handle to render window
56 u32 last_mode; ///< Last render mode 61 u32 last_mode; ///< Last render mode
57 62
diff --git a/src/video_core/utils.cpp b/src/video_core/utils.cpp
index c1848f923..f1156a493 100644
--- a/src/video_core/utils.cpp
+++ b/src/video_core/utils.cpp
@@ -20,7 +20,7 @@ namespace VideoCore {
20void DumpTGA(std::string filename, short width, short height, u8* raw_data) { 20void DumpTGA(std::string filename, short width, short height, u8* raw_data) {
21 TGAHeader hdr = {0, 0, 2, 0, 0, 0, 0, width, height, 24, 0}; 21 TGAHeader hdr = {0, 0, 2, 0, 0, 0, 0, width, height, 24, 0};
22 FILE* fout = fopen(filename.c_str(), "wb"); 22 FILE* fout = fopen(filename.c_str(), "wb");
23 23
24 fwrite(&hdr, sizeof(TGAHeader), 1, fout); 24 fwrite(&hdr, sizeof(TGAHeader), 1, fout);
25 25
26 for (int y = 0; y < height; y++) { 26 for (int y = 0; y < height; y++) {
@@ -30,7 +30,7 @@ void DumpTGA(std::string filename, short width, short height, u8* raw_data) {
30 putc(raw_data[(3 * (y * width)) + (3 * x) + 2], fout); // r 30 putc(raw_data[(3 * (y * width)) + (3 * x) + 2], fout); // r
31 } 31 }
32 } 32 }
33 33
34 fclose(fout); 34 fclose(fout);
35} 35}
36} // namespace 36} // namespace
diff --git a/src/video_core/utils.h b/src/video_core/utils.h
index 9cb3d4d43..21380a908 100644
--- a/src/video_core/utils.h
+++ b/src/video_core/utils.h
@@ -12,24 +12,24 @@ namespace FormatPrecision {
12 12
13/// Adjust RGBA8 color with RGBA6 precision 13/// Adjust RGBA8 color with RGBA6 precision
14static inline u32 rgba8_with_rgba6(u32 src) { 14static inline u32 rgba8_with_rgba6(u32 src) {
15 u32 color = src; 15 u32 color = src;
16 color &= 0xFCFCFCFC; 16 color &= 0xFCFCFCFC;
17 color |= (color >> 6) & 0x03030303; 17 color |= (color >> 6) & 0x03030303;
18 return color; 18 return color;
19} 19}
20 20
21/// Adjust RGBA8 color with RGB565 precision 21/// Adjust RGBA8 color with RGB565 precision
22static inline u32 rgba8_with_rgb565(u32 src) { 22static inline u32 rgba8_with_rgb565(u32 src) {
23 u32 color = (src & 0xF8FCF8); 23 u32 color = (src & 0xF8FCF8);
24 color |= (color >> 5) & 0x070007; 24 color |= (color >> 5) & 0x070007;
25 color |= (color >> 6) & 0x000300; 25 color |= (color >> 6) & 0x000300;
26 color |= 0xFF000000; 26 color |= 0xFF000000;
27 return color; 27 return color;
28} 28}
29 29
30/// Adjust Z24 depth value with Z16 precision 30/// Adjust Z24 depth value with Z16 precision
31static inline u32 z24_with_z16(u32 src) { 31static inline u32 z24_with_z16(u32 src) {
32 return (src & 0xFFFF00) | (src >> 16); 32 return (src & 0xFFFF00) | (src >> 16);
33} 33}
34 34
35} // namespace 35} // namespace
diff --git a/src/video_core/vertex_shader.h b/src/video_core/vertex_shader.h
index 607a8e803..bfb6fb6e3 100644
--- a/src/video_core/vertex_shader.h
+++ b/src/video_core/vertex_shader.h
@@ -141,7 +141,7 @@ union Instruction {
141 return BitFieldType::Value(); 141 return BitFieldType::Value();
142 else if (GetRegisterType() == Temporary) 142 else if (GetRegisterType() == Temporary)
143 return BitFieldType::Value() - 0x10; 143 return BitFieldType::Value() - 0x10;
144 else if (GetRegisterType() == FloatUniform) 144 else // if (GetRegisterType() == FloatUniform)
145 return BitFieldType::Value() - 0x20; 145 return BitFieldType::Value() - 0x20;
146 } 146 }
147 147