summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.gitmodules3
-rw-r--r--CMakeLists.txt21
-rw-r--r--CMakeModules/CopyCitraQt5Deps.cmake17
-rw-r--r--CMakeModules/CopyCitraSDLDeps.cmake5
-rw-r--r--dist/citra-qt.640
-rw-r--r--dist/citra.649
-rw-r--r--externals/CMakeLists.txt8
m---------externals/dynarmic0
m---------externals/xbyak0
-rw-r--r--src/audio_core/audio_core.cpp23
-rw-r--r--src/audio_core/hle/pipe.cpp2
-rw-r--r--src/audio_core/time_stretch.h2
-rw-r--r--src/citra/CMakeLists.txt11
-rw-r--r--src/citra/citra.cpp40
-rw-r--r--src/citra/citra.rc2
-rw-r--r--src/citra/emu_window/emu_window_sdl2.cpp2
-rw-r--r--src/citra/emu_window/emu_window_sdl2.h2
-rw-r--r--src/citra_qt/CMakeLists.txt59
-rw-r--r--src/citra_qt/bootmanager.cpp15
-rw-r--r--src/citra_qt/bootmanager.h6
-rw-r--r--src/citra_qt/citra-qt.rc2
-rw-r--r--src/citra_qt/configure_general.cpp4
-rw-r--r--src/citra_qt/configure_graphics.cpp4
-rw-r--r--src/citra_qt/configure_input.cpp169
-rw-r--r--src/citra_qt/configure_input.h47
-rw-r--r--src/citra_qt/configure_system.cpp3
-rw-r--r--src/citra_qt/debugger/callstack.cpp2
-rw-r--r--src/citra_qt/debugger/callstack.h4
-rw-r--r--src/citra_qt/debugger/disassembler.cpp10
-rw-r--r--src/citra_qt/debugger/disassembler.h6
-rw-r--r--src/citra_qt/debugger/graphics/graphics.cpp (renamed from src/citra_qt/debugger/graphics.cpp)18
-rw-r--r--src/citra_qt/debugger/graphics/graphics.h (renamed from src/citra_qt/debugger/graphics.h)2
-rw-r--r--src/citra_qt/debugger/graphics/graphics_breakpoint_observer.cpp (renamed from src/citra_qt/debugger/graphics_breakpoint_observer.cpp)2
-rw-r--r--src/citra_qt/debugger/graphics/graphics_breakpoint_observer.h (renamed from src/citra_qt/debugger/graphics_breakpoint_observer.h)0
-rw-r--r--src/citra_qt/debugger/graphics/graphics_breakpoints.cpp (renamed from src/citra_qt/debugger/graphics_breakpoints.cpp)4
-rw-r--r--src/citra_qt/debugger/graphics/graphics_breakpoints.h (renamed from src/citra_qt/debugger/graphics_breakpoints.h)4
-rw-r--r--src/citra_qt/debugger/graphics/graphics_breakpoints_p.h (renamed from src/citra_qt/debugger/graphics_breakpoints_p.h)0
-rw-r--r--src/citra_qt/debugger/graphics/graphics_cmdlists.cpp (renamed from src/citra_qt/debugger/graphics_cmdlists.cpp)44
-rw-r--r--src/citra_qt/debugger/graphics/graphics_cmdlists.h (renamed from src/citra_qt/debugger/graphics_cmdlists.h)4
-rw-r--r--src/citra_qt/debugger/graphics/graphics_surface.cpp (renamed from src/citra_qt/debugger/graphics_surface.cpp)2
-rw-r--r--src/citra_qt/debugger/graphics/graphics_surface.h (renamed from src/citra_qt/debugger/graphics_surface.h)9
-rw-r--r--src/citra_qt/debugger/graphics/graphics_tracing.cpp (renamed from src/citra_qt/debugger/graphics_tracing.cpp)2
-rw-r--r--src/citra_qt/debugger/graphics/graphics_tracing.h (renamed from src/citra_qt/debugger/graphics_tracing.h)6
-rw-r--r--src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp (renamed from src/citra_qt/debugger/graphics_vertex_shader.cpp)2
-rw-r--r--src/citra_qt/debugger/graphics/graphics_vertex_shader.h (renamed from src/citra_qt/debugger/graphics_vertex_shader.h)4
-rw-r--r--src/citra_qt/debugger/profiler.h6
-rw-r--r--src/citra_qt/debugger/ramview.h4
-rw-r--r--src/citra_qt/debugger/registers.cpp16
-rw-r--r--src/citra_qt/debugger/registers.h4
-rw-r--r--src/citra_qt/debugger/wait_tree.cpp6
-rw-r--r--src/citra_qt/debugger/wait_tree.h26
-rw-r--r--src/citra_qt/game_list.cpp46
-rw-r--r--src/citra_qt/game_list.h16
-rw-r--r--src/citra_qt/game_list_p.h5
-rw-r--r--src/citra_qt/hotkeys.h2
-rw-r--r--src/citra_qt/main.cpp236
-rw-r--r--src/citra_qt/main.h29
-rw-r--r--src/citra_qt/util/spinbox.h2
-rw-r--r--src/common/CMakeLists.txt12
-rw-r--r--src/common/bit_set.h2
-rw-r--r--src/common/common_paths.h18
-rw-r--r--src/common/file_util.cpp59
-rw-r--r--src/common/file_util.h20
-rw-r--r--src/common/logging/backend.cpp1
-rw-r--r--src/common/logging/log.h1
-rw-r--r--src/common/logging/text_formatter.cpp2
-rw-r--r--src/common/scm_rev.cpp.in2
-rw-r--r--src/common/string_util.cpp2
-rw-r--r--src/common/thread.cpp2
-rw-r--r--src/common/timer.cpp3
-rw-r--r--src/common/x64/xbyak_abi.h178
-rw-r--r--src/common/x64/xbyak_util.h49
-rw-r--r--src/core/CMakeLists.txt69
-rw-r--r--src/core/arm/arm_interface.h19
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp6
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.h8
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp4
-rw-r--r--src/core/arm/dyncom/arm_dyncom.h8
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp4
-rw-r--r--src/core/arm/dyncom/arm_dyncom_trans.h2
-rw-r--r--src/core/arm/skyeye_common/armstate.cpp2
-rw-r--r--src/core/core.cpp135
-rw-r--r--src/core/core.h148
-rw-r--r--src/core/core_timing.cpp27
-rw-r--r--src/core/file_sys/archive_extsavedata.cpp9
-rw-r--r--src/core/file_sys/archive_ncch.cpp2
-rw-r--r--src/core/file_sys/archive_ncch.h2
-rw-r--r--src/core/file_sys/archive_romfs.h2
-rw-r--r--src/core/file_sys/archive_sdmc.h4
-rw-r--r--src/core/file_sys/archive_sdmcwriteonly.h4
-rw-r--r--src/core/file_sys/archive_source_sd_savedata.cpp7
-rw-r--r--src/core/file_sys/archive_source_sd_savedata.h2
-rw-r--r--src/core/file_sys/archive_systemsavedata.cpp2
-rw-r--r--src/core/file_sys/archive_systemsavedata.h2
-rw-r--r--src/core/file_sys/path_parser.h2
-rw-r--r--src/core/file_sys/savedata_archive.h2
-rw-r--r--src/core/frontend/emu_window.cpp (renamed from src/common/emu_window.cpp)4
-rw-r--r--src/core/frontend/emu_window.h (renamed from src/common/emu_window.h)0
-rw-r--r--src/core/frontend/key_map.cpp (renamed from src/common/key_map.cpp)4
-rw-r--r--src/core/frontend/key_map.h (renamed from src/common/key_map.h)0
-rw-r--r--src/core/gdbstub/gdbstub.cpp83
-rw-r--r--src/core/gdbstub/gdbstub.h11
-rw-r--r--src/core/hle/applets/applet.cpp4
-rw-r--r--src/core/hle/applets/applet.h10
-rw-r--r--src/core/hle/applets/erreula.cpp4
-rw-r--r--src/core/hle/applets/erreula.h8
-rw-r--r--src/core/hle/applets/mii_selector.cpp4
-rw-r--r--src/core/hle/applets/mii_selector.h9
-rw-r--r--src/core/hle/applets/swkbd.cpp8
-rw-r--r--src/core/hle/applets/swkbd.h9
-rw-r--r--src/core/hle/function_wrappers.h76
-rw-r--r--src/core/hle/hle.cpp58
-rw-r--r--src/core/hle/hle.h23
-rw-r--r--src/core/hle/ipc.h (renamed from src/core/hle/kernel/session.h)96
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp3
-rw-r--r--src/core/hle/kernel/client_port.cpp32
-rw-r--r--src/core/hle/kernel/client_port.h13
-rw-r--r--src/core/hle/kernel/client_session.cpp40
-rw-r--r--src/core/hle/kernel/client_session.h65
-rw-r--r--src/core/hle/kernel/kernel.cpp59
-rw-r--r--src/core/hle/kernel/kernel.h48
-rw-r--r--src/core/hle/kernel/server_port.cpp4
-rw-r--r--src/core/hle/kernel/server_port.h14
-rw-r--r--src/core/hle/kernel/server_session.cpp79
-rw-r--r--src/core/hle/kernel/server_session.h94
-rw-r--r--src/core/hle/kernel/thread.cpp127
-rw-r--r--src/core/hle/kernel/thread.h53
-rw-r--r--src/core/hle/kernel/timer.cpp4
-rw-r--r--src/core/hle/result.h1
-rw-r--r--src/core/hle/service/ac_u.cpp40
-rw-r--r--src/core/hle/service/ac_u.h17
-rw-r--r--src/core/hle/service/act/act.cpp18
-rw-r--r--src/core/hle/service/act/act.h14
-rw-r--r--src/core/hle/service/act/act_a.cpp30
-rw-r--r--src/core/hle/service/act/act_a.h (renamed from src/core/hle/service/act_a.h)13
-rw-r--r--src/core/hle/service/act/act_u.cpp (renamed from src/core/hle/service/act_u.cpp)20
-rw-r--r--src/core/hle/service/act/act_u.h (renamed from src/core/hle/service/act_u.h)13
-rw-r--r--src/core/hle/service/act_a.cpp26
-rw-r--r--src/core/hle/service/am/am.cpp10
-rw-r--r--src/core/hle/service/am/am.h20
-rw-r--r--src/core/hle/service/am/am_app.cpp5
-rw-r--r--src/core/hle/service/am/am_net.cpp157
-rw-r--r--src/core/hle/service/am/am_sys.cpp71
-rw-r--r--src/core/hle/service/am/am_u.cpp96
-rw-r--r--src/core/hle/service/apt/apt.cpp12
-rw-r--r--src/core/hle/service/apt/apt.h7
-rw-r--r--src/core/hle/service/apt/apt_a.cpp79
-rw-r--r--src/core/hle/service/apt/apt_s.cpp5
-rw-r--r--src/core/hle/service/apt/apt_u.cpp2
-rw-r--r--src/core/hle/service/boss/boss_p.cpp71
-rw-r--r--src/core/hle/service/cecd/cecd.cpp10
-rw-r--r--src/core/hle/service/cecd/cecd_ndm.cpp23
-rw-r--r--src/core/hle/service/cecd/cecd_ndm.h22
-rw-r--r--src/core/hle/service/cecd/cecd_s.cpp26
-rw-r--r--src/core/hle/service/cecd/cecd_s.h4
-rw-r--r--src/core/hle/service/cecd/cecd_u.cpp17
-rw-r--r--src/core/hle/service/cecd/cecd_u.h4
-rw-r--r--src/core/hle/service/cfg/cfg.cpp8
-rw-r--r--src/core/hle/service/cfg/cfg_i.cpp3
-rw-r--r--src/core/hle/service/cfg/cfg_i.h4
-rw-r--r--src/core/hle/service/cfg/cfg_nor.cpp23
-rw-r--r--src/core/hle/service/cfg/cfg_nor.h22
-rw-r--r--src/core/hle/service/cfg/cfg_s.cpp3
-rw-r--r--src/core/hle/service/cfg/cfg_s.h4
-rw-r--r--src/core/hle/service/cfg/cfg_u.cpp3
-rw-r--r--src/core/hle/service/cfg/cfg_u.h4
-rw-r--r--src/core/hle/service/csnd_snd.cpp140
-rw-r--r--src/core/hle/service/csnd_snd.h26
-rw-r--r--src/core/hle/service/dlp/dlp.h2
-rw-r--r--src/core/hle/service/dlp/dlp_srvr.cpp7
-rw-r--r--src/core/hle/service/dsp_dsp.cpp7
-rw-r--r--src/core/hle/service/dsp_dsp.h7
-rw-r--r--src/core/hle/service/err_f.cpp16
-rw-r--r--src/core/hle/service/err_f.h13
-rw-r--r--src/core/hle/service/fs/archive.cpp65
-rw-r--r--src/core/hle/service/fs/archive.h36
-rw-r--r--src/core/hle/service/fs/fs_user.cpp35
-rw-r--r--src/core/hle/service/gsp_gpu.cpp54
-rw-r--r--src/core/hle/service/gsp_gpu.h17
-rw-r--r--src/core/hle/service/gsp_lcd.cpp18
-rw-r--r--src/core/hle/service/gsp_lcd.h14
-rw-r--r--src/core/hle/service/hid/hid.cpp5
-rw-r--r--src/core/hle/service/http_c.cpp18
-rw-r--r--src/core/hle/service/http_c.h13
-rw-r--r--src/core/hle/service/ir/ir.cpp3
-rw-r--r--src/core/hle/service/ldr_ro/cro_helper.cpp9
-rw-r--r--src/core/hle/service/ldr_ro/cro_helper.h9
-rw-r--r--src/core/hle/service/ldr_ro/ldr_ro.cpp40
-rw-r--r--src/core/hle/service/ldr_ro/ldr_ro.h13
-rw-r--r--src/core/hle/service/ldr_ro/memory_synchronizer.cpp9
-rw-r--r--src/core/hle/service/ldr_ro/memory_synchronizer.h9
-rw-r--r--src/core/hle/service/mic_u.cpp51
-rw-r--r--src/core/hle/service/mic_u.h17
-rw-r--r--src/core/hle/service/mvd/mvd.cpp17
-rw-r--r--src/core/hle/service/mvd/mvd.h14
-rw-r--r--src/core/hle/service/mvd/mvd_std.cpp32
-rw-r--r--src/core/hle/service/mvd/mvd_std.h22
-rw-r--r--src/core/hle/service/nfc/nfc.cpp18
-rw-r--r--src/core/hle/service/nfc/nfc.h14
-rw-r--r--src/core/hle/service/nfc/nfc_m.cpp44
-rw-r--r--src/core/hle/service/nfc/nfc_m.h22
-rw-r--r--src/core/hle/service/nfc/nfc_u.cpp41
-rw-r--r--src/core/hle/service/nfc/nfc_u.h22
-rw-r--r--src/core/hle/service/nim/nim_s.cpp1
-rw-r--r--src/core/hle/service/nim/nim_u.cpp1
-rw-r--r--src/core/hle/service/ns_s.cpp14
-rw-r--r--src/core/hle/service/ns_s.h14
-rw-r--r--src/core/hle/service/nwm/nwm.cpp28
-rw-r--r--src/core/hle/service/nwm/nwm.h14
-rw-r--r--src/core/hle/service/nwm/nwm_cec.cpp19
-rw-r--r--src/core/hle/service/nwm/nwm_cec.h22
-rw-r--r--src/core/hle/service/nwm/nwm_ext.cpp19
-rw-r--r--src/core/hle/service/nwm/nwm_ext.h22
-rw-r--r--src/core/hle/service/nwm/nwm_inf.cpp21
-rw-r--r--src/core/hle/service/nwm/nwm_inf.h22
-rw-r--r--src/core/hle/service/nwm/nwm_sap.cpp20
-rw-r--r--src/core/hle/service/nwm/nwm_sap.h22
-rw-r--r--src/core/hle/service/nwm/nwm_soc.cpp20
-rw-r--r--src/core/hle/service/nwm/nwm_soc.h22
-rw-r--r--src/core/hle/service/nwm/nwm_tst.cpp20
-rw-r--r--src/core/hle/service/nwm/nwm_tst.h22
-rw-r--r--src/core/hle/service/nwm/nwm_uds.cpp (renamed from src/core/hle/service/nwm_uds.cpp)43
-rw-r--r--src/core/hle/service/nwm/nwm_uds.h (renamed from src/core/hle/service/nwm_uds.h)17
-rw-r--r--src/core/hle/service/pm_app.cpp29
-rw-r--r--src/core/hle/service/pm_app.h13
-rw-r--r--src/core/hle/service/ptm/ptm.cpp15
-rw-r--r--src/core/hle/service/ptm/ptm.h7
-rw-r--r--src/core/hle/service/ptm/ptm_gets.cpp37
-rw-r--r--src/core/hle/service/ptm/ptm_gets.h22
-rw-r--r--src/core/hle/service/ptm/ptm_play.cpp20
-rw-r--r--src/core/hle/service/ptm/ptm_play.h4
-rw-r--r--src/core/hle/service/ptm/ptm_sets.cpp20
-rw-r--r--src/core/hle/service/ptm/ptm_sets.h22
-rw-r--r--src/core/hle/service/ptm/ptm_sysm.cpp27
-rw-r--r--src/core/hle/service/ptm/ptm_sysm.h13
-rw-r--r--src/core/hle/service/ptm/ptm_u.cpp2
-rw-r--r--src/core/hle/service/ptm/ptm_u.h4
-rw-r--r--src/core/hle/service/qtm/qtm.cpp21
-rw-r--r--src/core/hle/service/qtm/qtm.h14
-rw-r--r--src/core/hle/service/qtm/qtm_s.cpp23
-rw-r--r--src/core/hle/service/qtm/qtm_s.h22
-rw-r--r--src/core/hle/service/qtm/qtm_sp.cpp23
-rw-r--r--src/core/hle/service/qtm/qtm_sp.h22
-rw-r--r--src/core/hle/service/qtm/qtm_u.cpp23
-rw-r--r--src/core/hle/service/qtm/qtm_u.h22
-rw-r--r--src/core/hle/service/service.cpp151
-rw-r--r--src/core/hle/service/service.h88
-rw-r--r--src/core/hle/service/soc_u.cpp56
-rw-r--r--src/core/hle/service/soc_u.h15
-rw-r--r--src/core/hle/service/srv.cpp38
-rw-r--r--src/core/hle/service/srv.h15
-rw-r--r--src/core/hle/service/ssl_c.cpp21
-rw-r--r--src/core/hle/service/ssl_c.h13
-rw-r--r--src/core/hle/service/y2r_u.cpp106
-rw-r--r--src/core/hle/service/y2r_u.h15
-rw-r--r--src/core/hle/svc.cpp298
-rw-r--r--src/core/hw/gpu.cpp14
-rw-r--r--src/core/hw/y2r.cpp2
-rw-r--r--src/core/hw/y2r.h9
-rw-r--r--src/core/loader/3dsx.h20
-rw-r--r--src/core/loader/elf.h8
-rw-r--r--src/core/loader/loader.h9
-rw-r--r--src/core/loader/ncch.cpp12
-rw-r--r--src/core/loader/ncch.h31
-rw-r--r--src/core/settings.cpp2
-rw-r--r--src/core/system.cpp55
-rw-r--r--src/core/system.h21
-rw-r--r--src/tests/CMakeLists.txt2
-rw-r--r--src/video_core/CMakeLists.txt4
-rw-r--r--src/video_core/command_processor.cpp18
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp20
-rw-r--r--src/video_core/debug_utils/debug_utils.h6
-rw-r--r--src/video_core/gpu_debugger.h11
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp36
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp23
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp19
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp13
-rw-r--r--src/video_core/renderer_opengl/gl_state.h3
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp2
-rw-r--r--src/video_core/shader/debug_data.h186
-rw-r--r--src/video_core/shader/shader.cpp28
-rw-r--r--src/video_core/shader/shader.h201
-rw-r--r--src/video_core/shader/shader_interpreter.cpp235
-rw-r--r--src/video_core/shader/shader_interpreter.h7
-rw-r--r--src/video_core/shader/shader_jit_x64.cpp442
-rw-r--r--src/video_core/shader/shader_jit_x64.h18
287 files changed, 4909 insertions, 2888 deletions
diff --git a/.gitmodules b/.gitmodules
index f498a60de..dbb1b0dd3 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -16,3 +16,6 @@
[submodule "dynarmic"]
path = externals/dynarmic
url = https://github.com/MerryMage/dynarmic.git
+[submodule "xbyak"]
+ path = externals/xbyak
+ url = https://github.com/herumi/xbyak.git
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 25631b32e..52a1fd492 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,6 @@
# CMake 3.2 required for cmake to know the right flags for CXX standard on OSX
cmake_minimum_required(VERSION 3.2)
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules)
function(download_bundled_external remote_path lib_name prefix_var)
set(prefix "${CMAKE_BINARY_DIR}/externals/${lib_name}")
@@ -183,8 +184,10 @@ IF (APPLE)
FIND_LIBRARY(COCOA_LIBRARY Cocoa) # Umbrella framework for everything GUI-related
set(PLATFORM_LIBRARIES ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY})
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
- set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++")
+ if (CMAKE_CXX_COMPILER_ID STREQUAL Clang)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++")
+ endif()
ELSEIF (WIN32)
# WSAPoll and SHGetKnownFolderPath (AppData/Roaming) didn't exist before WinNT 6.x (Vista)
add_definitions(-D_WIN32_WINNT=0x0600 -DWINVER=0x0600)
@@ -254,6 +257,8 @@ set(INI_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/externals/inih")
include_directories(${INI_PREFIX})
add_subdirectory(${INI_PREFIX})
+add_subdirectory(externals)
+
option(DYNARMIC_TESTS OFF)
add_subdirectory(externals/dynarmic)
@@ -289,3 +294,15 @@ if(ENABLE_QT AND UNIX AND NOT APPLE)
install(FILES "${CMAKE_SOURCE_DIR}/dist/citra.xml"
DESTINATION "${CMAKE_INSTALL_PREFIX}/share/mime/packages")
endif()
+
+if(UNIX)
+ if(ENABLE_SDL2)
+ install(FILES "${CMAKE_SOURCE_DIR}/dist/citra.6"
+ DESTINATION "${CMAKE_INSTALL_PREFIX}/share/man/man6")
+ endif()
+
+ if (ENABLE_QT)
+ install(FILES "${CMAKE_SOURCE_DIR}/dist/citra-qt.6"
+ DESTINATION "${CMAKE_INSTALL_PREFIX}/share/man/man6")
+ endif()
+endif()
diff --git a/CMakeModules/CopyCitraQt5Deps.cmake b/CMakeModules/CopyCitraQt5Deps.cmake
new file mode 100644
index 000000000..05f58cf9a
--- /dev/null
+++ b/CMakeModules/CopyCitraQt5Deps.cmake
@@ -0,0 +1,17 @@
+function(copy_citra_Qt5_deps target_dir)
+ include(WindowsCopyFiles)
+ set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
+ set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin")
+ set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/")
+ set(PLATFORMS ${DLL_DEST}platforms/)
+ windows_copy_files(${target_dir} ${Qt5_DLL_DIR} ${DLL_DEST}
+ icudt*.dll
+ icuin*.dll
+ icuuc*.dll
+ Qt5Core$<$<CONFIG:Debug>:d>.*
+ Qt5Gui$<$<CONFIG:Debug>:d>.*
+ Qt5OpenGL$<$<CONFIG:Debug>:d>.*
+ Qt5Widgets$<$<CONFIG:Debug>:d>.*
+ )
+ windows_copy_files(citra-qt ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)
+endfunction(copy_citra_Qt5_deps)
diff --git a/CMakeModules/CopyCitraSDLDeps.cmake b/CMakeModules/CopyCitraSDLDeps.cmake
new file mode 100644
index 000000000..4f9e4aeb9
--- /dev/null
+++ b/CMakeModules/CopyCitraSDLDeps.cmake
@@ -0,0 +1,5 @@
+function(copy_citra_SDL_deps target_dir)
+ include(WindowsCopyFiles)
+ set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
+ windows_copy_files(${target_dir} ${SDL2_DLL_DIR} ${DLL_DEST} SDL2.dll)
+endfunction(copy_citra_SDL_deps)
diff --git a/dist/citra-qt.6 b/dist/citra-qt.6
new file mode 100644
index 000000000..d09e96b5d
--- /dev/null
+++ b/dist/citra-qt.6
@@ -0,0 +1,40 @@
+.Dd November 22 2016
+.Dt citra-qt 6
+.Os
+.Sh NAME
+.Nm Citra-Qt
+.Nd Nintendo 3DS Emulator/Debugger (Qt)
+.Sh SYNOPSIS
+.Nm citra-qt
+.Op Ar file
+.Sh DESCRIPTION
+Citra is an experimental open-source Nintendo 3DS emulator/debugger.
+.Pp
+.Nm citra-qt
+is the Qt implementation.
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa $XDG_DATA_HOME/citra-emu
+Emulator storage.
+.It Pa $XDG_CONFIG_HOME/citra-emu
+Configuration files.
+.El
+.Sh AUTHORS
+This document is made available to you under the CC-BY license.
+.Pp
+Citra is made by a team of volunteers. These contributors are listed
+ at <\fBhttps://github.com/citra-emu/citra/contributors\fR>.
+.Pp
+.Sh SEE ALSO
+.Bl -tag -width Ds
+.It Xr citra 6
+The SDL frontend of the application
+.El
+.Pp
+Resources are available for this project:
+.Bl -tag -width Ds
+.It <\fBhttps://citra-emu.org\fR>
+The main homepage of the project.
+.It <\fBhttps://github.com/citra-emu/citra\fR>
+The main source code repository for the Citra emulator.
+.Pp
diff --git a/dist/citra.6 b/dist/citra.6
new file mode 100644
index 000000000..72483b1dd
--- /dev/null
+++ b/dist/citra.6
@@ -0,0 +1,49 @@
+.Dd November 22 2016
+.Dt citra 6
+.Os
+.Sh NAME
+.Nm Citra
+.Nd Nintendo 3DS Emulator/Debugger (SDL)
+.Sh SYNOPSIS
+.Nm citra
+.Op Ar options
+.Op Ar file
+.Sh OPTIONS
+.Bl -tag -width Ds
+.It Fl g Ar port , Fl Fl gdbport Ar port
+Starts the GDB stub on the specified port
+.It Fl h , Fl Fl help
+Shows syntax help and exits
+.It Fl v , Fl Fl version
+Describes the installed version and exits
+.Sh DESCRIPTION
+Citra is an experimental open-source Nintendo 3DS emulator/debugger.
+.Pp
+.Nm citra
+is the Simple DirectMedia Layer (SDL) implementation.
+.Sh FILES
+.Bl -tag -width Ds
+.It Pa $XDG_DATA_HOME/citra-emu
+Emulator storage.
+.It Pa $XDG_CONFIG_HOME/citra-emu
+Configuration files.
+.El
+.Sh AUTHORS
+This document is made available to you under the CC-BY license.
+.Pp
+Citra is made by a team of volunteers. These contributors are listed
+ at <\fBhttps://github.com/citra-emu/citra/contributors\fR>.
+.Pp
+.Sh SEE ALSO
+.Bl -tag -width Ds
+.It Xr citra-qt 6
+The Qt frontend of the application
+.El
+.Pp
+Resources are available for this project:
+.Bl -tag -width Ds
+.It <\fBhttps://citra-emu.org\fR>
+The main homepage of the project.
+.It <\fBhttps://github.com/citra-emu/citra\fR>
+The main source code repository for the Citra emulator.
+.Pp
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
new file mode 100644
index 000000000..7e4b05ffc
--- /dev/null
+++ b/externals/CMakeLists.txt
@@ -0,0 +1,8 @@
+# Xbyak
+if (ARCHITECTURE_x86_64)
+ add_library(xbyak INTERFACE)
+ target_include_directories(xbyak INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/xbyak/xbyak)
+ if (NOT MSVC)
+ target_compile_options(xbyak INTERFACE -fno-operator-names)
+ endif()
+endif()
diff --git a/externals/dynarmic b/externals/dynarmic
-Subproject 54d051977f7a6af9c7596ba6a4e6eb467bd1e0b
+Subproject 36082087ded632079b16d24137fdd0c450ce82e
diff --git a/externals/xbyak b/externals/xbyak
new file mode 160000
+Subproject fe4765d2fed4e990ea5e9661b6bc5fc9bf48ec1
diff --git a/src/audio_core/audio_core.cpp b/src/audio_core/audio_core.cpp
index 49260de7c..ba6acf28e 100644
--- a/src/audio_core/audio_core.cpp
+++ b/src/audio_core/audio_core.cpp
@@ -23,9 +23,9 @@ static constexpr u64 audio_frame_ticks = 1310252ull; ///< Units: ARM11 cycles
static void AudioTickCallback(u64 /*userdata*/, int cycles_late) {
if (DSP::HLE::Tick()) {
// TODO(merry): Signal all the other interrupts as appropriate.
- DSP_DSP::SignalPipeInterrupt(DSP::HLE::DspPipe::Audio);
+ Service::DSP_DSP::SignalPipeInterrupt(DSP::HLE::DspPipe::Audio);
// HACK(merry): Added to prevent regressions. Will remove soon.
- DSP_DSP::SignalPipeInterrupt(DSP::HLE::DspPipe::Binary);
+ Service::DSP_DSP::SignalPipeInterrupt(DSP::HLE::DspPipe::Binary);
}
// Reschedule recurrent event
@@ -56,22 +56,17 @@ void AddAddressSpace(Kernel::VMManager& address_space) {
}
void SelectSink(std::string sink_id) {
- if (sink_id == "auto") {
- // Auto-select.
- // g_sink_details is ordered in terms of desirability, with the best choice at the front.
- const auto& sink_detail = g_sink_details.front();
- DSP::HLE::SetSink(sink_detail.factory());
- return;
- }
-
auto iter =
std::find_if(g_sink_details.begin(), g_sink_details.end(),
[sink_id](const auto& sink_detail) { return sink_detail.id == sink_id; });
- if (iter == g_sink_details.end()) {
- LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id");
- DSP::HLE::SetSink(std::make_unique<NullSink>());
- return;
+ if (sink_id == "auto" || iter == g_sink_details.end()) {
+ if (sink_id != "auto") {
+ LOG_ERROR(Audio, "AudioCore::SelectSink given invalid sink_id %s", sink_id.c_str());
+ }
+ // Auto-select.
+ // g_sink_details is ordered in terms of desirability, with the best choice at the front.
+ iter = g_sink_details.begin();
}
DSP::HLE::SetSink(iter->factory());
diff --git a/src/audio_core/hle/pipe.cpp b/src/audio_core/hle/pipe.cpp
index bc69acbc2..24074a514 100644
--- a/src/audio_core/hle/pipe.cpp
+++ b/src/audio_core/hle/pipe.cpp
@@ -104,7 +104,7 @@ static void AudioPipeWriteStructAddresses() {
WriteU16(DspPipe::Audio, addr);
}
// Signal that we have data on this pipe.
- DSP_DSP::SignalPipeInterrupt(DspPipe::Audio);
+ Service::DSP_DSP::SignalPipeInterrupt(DspPipe::Audio);
}
void PipeWrite(DspPipe pipe_number, const std::vector<u8>& buffer) {
diff --git a/src/audio_core/time_stretch.h b/src/audio_core/time_stretch.h
index fa81718ed..e3e4dc353 100644
--- a/src/audio_core/time_stretch.h
+++ b/src/audio_core/time_stretch.h
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
#include <cstddef>
#include <memory>
#include <vector>
diff --git a/src/citra/CMakeLists.txt b/src/citra/CMakeLists.txt
index f9c488a1a..ecb5d2dfe 100644
--- a/src/citra/CMakeLists.txt
+++ b/src/citra/CMakeLists.txt
@@ -1,3 +1,5 @@
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules)
+
set(SRCS
emu_window/emu_window_sdl2.cpp
citra.cpp
@@ -28,11 +30,6 @@ if(UNIX AND NOT APPLE)
endif()
if (MSVC)
- include(WindowsCopyFiles)
-
- set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
-
- windows_copy_files(citra ${SDL2_DLL_DIR} ${DLL_DEST} SDL2.dll)
-
- unset(DLL_DEST)
+ include(CopyCitraSDLDeps)
+ copy_citra_SDL_deps(citra)
endif()
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp
index f9387e61c..99c096ac7 100644
--- a/src/citra/citra.cpp
+++ b/src/citra/citra.cpp
@@ -18,7 +18,7 @@
#endif
#ifdef _WIN32
-#include <Windows.h>
+#include <windows.h>
#endif
#include "citra/config.h"
@@ -33,7 +33,6 @@
#include "core/gdbstub/gdbstub.h"
#include "core/loader/loader.h"
#include "core/settings.h"
-#include "core/system.h"
#include "video_core/video_core.h"
static void PrintHelp(const char* argv0) {
@@ -64,7 +63,7 @@ int main(int argc, char** argv) {
return -1;
}
#endif
- std::string boot_filename;
+ std::string filepath;
static struct option long_options[] = {
{"gdbport", required_argument, 0, 'g'},
@@ -97,9 +96,9 @@ int main(int argc, char** argv) {
}
} else {
#ifdef _WIN32
- boot_filename = Common::UTF16ToUTF8(argv_w[optind]);
+ filepath = Common::UTF16ToUTF8(argv_w[optind]);
#else
- boot_filename = argv[optind];
+ filepath = argv[optind];
#endif
optind++;
}
@@ -115,7 +114,7 @@ int main(int argc, char** argv) {
MicroProfileOnThreadCreate("EmuThread");
SCOPE_EXIT({ MicroProfileShutdown(); });
- if (boot_filename.empty()) {
+ if (filepath.empty()) {
LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified");
return -1;
}
@@ -127,32 +126,25 @@ int main(int argc, char** argv) {
Settings::values.use_gdbstub = use_gdbstub;
Settings::Apply();
- std::unique_ptr<EmuWindow_SDL2> emu_window = std::make_unique<EmuWindow_SDL2>();
+ std::unique_ptr<EmuWindow_SDL2> emu_window{std::make_unique<EmuWindow_SDL2>()};
- std::unique_ptr<Loader::AppLoader> loader = Loader::GetLoader(boot_filename);
- if (!loader) {
- LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", boot_filename.c_str());
- return -1;
- }
-
- boost::optional<u32> system_mode = loader->LoadKernelSystemMode();
+ Core::System& system{Core::System::GetInstance()};
- if (!system_mode) {
- LOG_CRITICAL(Frontend, "Failed to load ROM (Could not determine system mode)!");
- return -1;
- }
+ SCOPE_EXIT({ system.Shutdown(); });
- System::Init(emu_window.get(), system_mode.get());
- SCOPE_EXIT({ System::Shutdown(); });
+ const Core::System::ResultStatus load_result{system.Load(emu_window.get(), filepath)};
- Loader::ResultStatus load_result = loader->Load();
- if (Loader::ResultStatus::Success != load_result) {
- LOG_CRITICAL(Frontend, "Failed to load ROM (Error %i)!", load_result);
+ switch (load_result) {
+ case Core::System::ResultStatus::ErrorGetLoader:
+ LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", filepath.c_str());
+ return -1;
+ case Core::System::ResultStatus::ErrorLoader:
+ LOG_CRITICAL(Frontend, "Failed to load ROM!");
return -1;
}
while (emu_window->IsOpen()) {
- Core::RunLoop();
+ system.RunLoop();
}
return 0;
diff --git a/src/citra/citra.rc b/src/citra/citra.rc
index b0edb2e6b..fea603004 100644
--- a/src/citra/citra.rc
+++ b/src/citra/citra.rc
@@ -5,5 +5,5 @@
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
-GLFW_ICON ICON "..\\..\\dist\\citra.ico"
+CITRA_ICON ICON "../../dist/citra.ico"
diff --git a/src/citra/emu_window/emu_window_sdl2.cpp b/src/citra/emu_window/emu_window_sdl2.cpp
index 8abe48984..b0d82b670 100644
--- a/src/citra/emu_window/emu_window_sdl2.cpp
+++ b/src/citra/emu_window/emu_window_sdl2.cpp
@@ -9,10 +9,10 @@
#include <SDL.h>
#include <glad/glad.h>
#include "citra/emu_window/emu_window_sdl2.h"
-#include "common/key_map.h"
#include "common/logging/log.h"
#include "common/scm_rev.h"
#include "common/string_util.h"
+#include "core/frontend/key_map.h"
#include "core/hle/service/hid/hid.h"
#include "core/settings.h"
#include "video_core/video_core.h"
diff --git a/src/citra/emu_window/emu_window_sdl2.h b/src/citra/emu_window/emu_window_sdl2.h
index e4d14ef12..c8cd919c6 100644
--- a/src/citra/emu_window/emu_window_sdl2.h
+++ b/src/citra/emu_window/emu_window_sdl2.h
@@ -5,7 +5,7 @@
#pragma once
#include <utility>
-#include "common/emu_window.h"
+#include "core/frontend/emu_window.h"
struct SDL_Window;
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index a9dacd5f1..93f1c339d 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -1,17 +1,18 @@
set(CMAKE_AUTOMOC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules)
set(SRCS
config.cpp
debugger/callstack.cpp
debugger/disassembler.cpp
- debugger/graphics.cpp
- debugger/graphics_breakpoint_observer.cpp
- debugger/graphics_breakpoints.cpp
- debugger/graphics_cmdlists.cpp
- debugger/graphics_surface.cpp
- debugger/graphics_tracing.cpp
- debugger/graphics_vertex_shader.cpp
+ debugger/graphics/graphics.cpp
+ debugger/graphics/graphics_breakpoint_observer.cpp
+ debugger/graphics/graphics_breakpoints.cpp
+ debugger/graphics/graphics_cmdlists.cpp
+ debugger/graphics/graphics_surface.cpp
+ debugger/graphics/graphics_tracing.cpp
+ debugger/graphics/graphics_vertex_shader.cpp
debugger/profiler.cpp
debugger/ramview.cpp
debugger/registers.cpp
@@ -38,14 +39,14 @@ set(HEADERS
config.h
debugger/callstack.h
debugger/disassembler.h
- debugger/graphics.h
- debugger/graphics_breakpoint_observer.h
- debugger/graphics_breakpoints.h
- debugger/graphics_breakpoints_p.h
- debugger/graphics_cmdlists.h
- debugger/graphics_surface.h
- debugger/graphics_tracing.h
- debugger/graphics_vertex_shader.h
+ debugger/graphics/graphics.h
+ debugger/graphics/graphics_breakpoint_observer.h
+ debugger/graphics/graphics_breakpoints.h
+ debugger/graphics/graphics_breakpoints_p.h
+ debugger/graphics/graphics_cmdlists.h
+ debugger/graphics/graphics_surface.h
+ debugger/graphics/graphics_tracing.h
+ debugger/graphics/graphics_vertex_shader.h
debugger/profiler.h
debugger/ramview.h
debugger/registers.h
@@ -107,27 +108,9 @@ if(UNIX AND NOT APPLE)
install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
endif()
-if (Qt5_FOUND AND MSVC)
- include(WindowsCopyFiles)
-
- set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin")
- set(Qt5_PLATFORMS_DIR "${Qt5_DIR}/../../../plugins/platforms/")
- set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
- set(PLATFORMS ${DLL_DEST}platforms/)
-
- windows_copy_files(citra-qt ${Qt5_DLL_DIR} ${DLL_DEST}
- icudt*.dll
- icuin*.dll
- icuuc*.dll
- Qt5Core$<$<CONFIG:Debug>:d>.*
- Qt5Gui$<$<CONFIG:Debug>:d>.*
- Qt5OpenGL$<$<CONFIG:Debug>:d>.*
- Qt5Widgets$<$<CONFIG:Debug>:d>.*
- )
- windows_copy_files(citra-qt ${Qt5_PLATFORMS_DIR} ${PLATFORMS} qwindows$<$<CONFIG:Debug>:d>.*)
-
- unset(Qt5_DLL_DIR)
- unset(Qt5_PLATFORMS_DIR)
- unset(DLL_DEST)
- unset(PLATFORMS)
+if (MSVC)
+ include(CopyCitraQt5Deps)
+ include(CopyCitraSDLDeps)
+ copy_citra_Qt5_deps(citra-qt)
+ copy_citra_SDL_deps(citra-qt)
endif()
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 7699ca8d0..57fde6caa 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -9,21 +9,14 @@
#endif
#include "citra_qt/bootmanager.h"
-#include "common/key_map.h"
#include "common/microprofile.h"
#include "common/scm_rev.h"
#include "common/string_util.h"
#include "core/core.h"
-#include "core/settings.h"
-#include "core/system.h"
+#include "core/frontend/key_map.h"
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/video_core.h"
-#define APP_NAME "citra"
-#define APP_VERSION "0.1-" VERSION
-#define APP_TITLE APP_NAME " " APP_VERSION
-#define COPYRIGHT "Copyright (C) 2013-2014 Citra Team"
-
EmuThread::EmuThread(GRenderWindow* render_window)
: exec_step(false), running(false), stop_run(false), render_window(render_window) {}
@@ -43,7 +36,7 @@ void EmuThread::run() {
if (!was_active)
emit DebugModeLeft();
- Core::RunLoop();
+ Core::System::GetInstance().RunLoop();
was_active = running || exec_step;
if (!was_active && !stop_run)
@@ -53,7 +46,7 @@ void EmuThread::run() {
emit DebugModeLeft();
exec_step = false;
- Core::SingleStep();
+ Core::System::GetInstance().SingleStep();
emit DebugModeEntered();
yieldCurrentThread();
@@ -65,7 +58,7 @@ void EmuThread::run() {
}
// Shutdown the core emulation
- System::Shutdown();
+ Core::System::GetInstance().Shutdown();
#if MICROPROFILE_ENABLED
MicroProfileOnThreadExit();
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h
index 67228b94f..43015390b 100644
--- a/src/citra_qt/bootmanager.h
+++ b/src/citra_qt/bootmanager.h
@@ -2,13 +2,15 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <QGLWidget>
#include <QThread>
-#include "common/emu_window.h"
#include "common/thread.h"
+#include "core/frontend/emu_window.h"
class QKeyEvent;
class QScreen;
@@ -21,7 +23,7 @@ class EmuThread : public QThread {
Q_OBJECT
public:
- EmuThread(GRenderWindow* render_window);
+ explicit EmuThread(GRenderWindow* render_window);
/**
* Start emulation (on new thread)
diff --git a/src/citra_qt/citra-qt.rc b/src/citra_qt/citra-qt.rc
index 3c7239853..fea603004 100644
--- a/src/citra_qt/citra-qt.rc
+++ b/src/citra_qt/citra-qt.rc
@@ -5,5 +5,5 @@
// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
-IDI_ICON1 ICON "..\\..\\dist\\citra.ico"
+CITRA_ICON ICON "../../dist/citra.ico"
diff --git a/src/citra_qt/configure_general.cpp b/src/citra_qt/configure_general.cpp
index 0b802d081..ac90a6df4 100644
--- a/src/citra_qt/configure_general.cpp
+++ b/src/citra_qt/configure_general.cpp
@@ -4,8 +4,8 @@
#include "citra_qt/configure_general.h"
#include "citra_qt/ui_settings.h"
+#include "core/core.h"
#include "core/settings.h"
-#include "core/system.h"
#include "ui_configure_general.h"
ConfigureGeneral::ConfigureGeneral(QWidget* parent)
@@ -14,7 +14,7 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
ui->setupUi(this);
this->setConfiguration();
- ui->toggle_cpu_jit->setEnabled(!System::IsPoweredOn());
+ ui->toggle_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
}
ConfigureGeneral::~ConfigureGeneral() {}
diff --git a/src/citra_qt/configure_graphics.cpp b/src/citra_qt/configure_graphics.cpp
index 36f10c8d7..cea7db388 100644
--- a/src/citra_qt/configure_graphics.cpp
+++ b/src/citra_qt/configure_graphics.cpp
@@ -3,8 +3,8 @@
// Refer to the license.txt file included.
#include "citra_qt/configure_graphics.h"
+#include "core/core.h"
#include "core/settings.h"
-#include "core/system.h"
#include "ui_configure_graphics.h"
ConfigureGraphics::ConfigureGraphics(QWidget* parent)
@@ -13,7 +13,7 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
ui->setupUi(this);
this->setConfiguration();
- ui->toggle_vsync->setEnabled(!System::IsPoweredOn());
+ ui->toggle_vsync->setEnabled(!Core::System::GetInstance().IsPoweredOn());
}
ConfigureGraphics::~ConfigureGraphics() {}
diff --git a/src/citra_qt/configure_input.cpp b/src/citra_qt/configure_input.cpp
index d321db71f..3e6803b8a 100644
--- a/src/citra_qt/configure_input.cpp
+++ b/src/citra_qt/configure_input.cpp
@@ -5,15 +5,33 @@
#include <memory>
#include <utility>
#include <QTimer>
+#include "citra_qt/config.h"
#include "citra_qt/configure_input.h"
+static QString getKeyName(Qt::Key key_code) {
+ switch (key_code) {
+ case Qt::Key_Shift:
+ return QObject::tr("Shift");
+ case Qt::Key_Control:
+ return QObject::tr("Ctrl");
+ case Qt::Key_Alt:
+ return QObject::tr("Alt");
+ case Qt::Key_Meta:
+ case -1:
+ return "";
+ default:
+ return QKeySequence(key_code).toString();
+ }
+}
+
ConfigureInput::ConfigureInput(QWidget* parent)
- : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) {
+ : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()),
+ timer(std::make_unique<QTimer>()) {
ui->setupUi(this);
+ setFocusPolicy(Qt::ClickFocus);
- // Initialize mapping of input enum to UI button.
- input_mapping = {
+ button_map = {
{Settings::NativeInput::Values::A, ui->buttonA},
{Settings::NativeInput::Values::B, ui->buttonB},
{Settings::NativeInput::Values::X, ui->buttonX},
@@ -40,114 +58,89 @@ ConfigureInput::ConfigureInput(QWidget* parent)
{Settings::NativeInput::Values::CIRCLE_MODIFIER, ui->buttonCircleMod},
};
- // Attach handle click method to each button click.
- for (const auto& entry : input_mapping) {
- connect(entry.second, SIGNAL(released()), this, SLOT(handleClick()));
+ for (const auto& entry : button_map) {
+ const Settings::NativeInput::Values input_id = entry.first;
+ connect(entry.second, &QPushButton::released,
+ [this, input_id]() { handleClick(input_id); });
}
- connect(ui->buttonRestoreDefaults, SIGNAL(released()), this, SLOT(restoreDefaults()));
- setFocusPolicy(Qt::ClickFocus);
- timer = new QTimer(this);
+
+ connect(ui->buttonRestoreDefaults, &QPushButton::released, [this]() { restoreDefaults(); });
+
timer->setSingleShot(true);
- connect(timer, &QTimer::timeout, this, [&]() {
- key_pressed = Qt::Key_Escape;
- setKey();
+ connect(timer.get(), &QTimer::timeout, [this]() {
+ releaseKeyboard();
+ releaseMouse();
+ current_input_id = boost::none;
+ updateButtonLabels();
});
- this->setConfiguration();
-}
-void ConfigureInput::handleClick() {
- QPushButton* sender = qobject_cast<QPushButton*>(QObject::sender());
- previous_mapping = sender->text();
- sender->setText(tr("[waiting]"));
- sender->setFocus();
- grabKeyboard();
- grabMouse();
- changing_button = sender;
- timer->start(5000); // Cancel after 5 seconds
+ this->loadConfiguration();
}
void ConfigureInput::applyConfiguration() {
- for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
- int value = getKeyValue(input_mapping[Settings::NativeInput::Values(i)]->text());
- Settings::values.input_mappings[Settings::NativeInput::All[i]] = value;
+ for (const auto& input_id : Settings::NativeInput::All) {
+ const size_t index = static_cast<size_t>(input_id);
+ Settings::values.input_mappings[index] = static_cast<int>(key_map[input_id]);
}
Settings::Apply();
}
-void ConfigureInput::setConfiguration() {
- for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
- QString keyValue = getKeyName(Settings::values.input_mappings[i]);
- input_mapping[Settings::NativeInput::Values(i)]->setText(keyValue);
+void ConfigureInput::loadConfiguration() {
+ for (const auto& input_id : Settings::NativeInput::All) {
+ const size_t index = static_cast<size_t>(input_id);
+ key_map[input_id] = static_cast<Qt::Key>(Settings::values.input_mappings[index]);
}
+ updateButtonLabels();
}
-void ConfigureInput::keyPressEvent(QKeyEvent* event) {
- if (!changing_button)
- return;
- if (!event || event->key() == Qt::Key_unknown)
- return;
- key_pressed = event->key();
- timer->stop();
- setKey();
+void ConfigureInput::restoreDefaults() {
+ for (const auto& input_id : Settings::NativeInput::All) {
+ const size_t index = static_cast<size_t>(input_id);
+ key_map[input_id] = static_cast<Qt::Key>(Config::defaults[index].toInt());
+ }
+ updateButtonLabels();
+ applyConfiguration();
}
-void ConfigureInput::setKey() {
- const QString key_value = getKeyName(key_pressed);
- if (key_pressed == Qt::Key_Escape)
- changing_button->setText(previous_mapping);
- else
- changing_button->setText(key_value);
- removeDuplicates(key_value);
- key_pressed = Qt::Key_unknown;
- releaseKeyboard();
- releaseMouse();
- changing_button = nullptr;
- previous_mapping = nullptr;
+void ConfigureInput::updateButtonLabels() {
+ for (const auto& input_id : Settings::NativeInput::All) {
+ button_map[input_id]->setText(getKeyName(key_map[input_id]));
+ }
}
-QString ConfigureInput::getKeyName(int key_code) const {
- if (key_code == Qt::Key_Shift)
- return tr("Shift");
- if (key_code == Qt::Key_Control)
- return tr("Ctrl");
- if (key_code == Qt::Key_Alt)
- return tr("Alt");
- if (key_code == Qt::Key_Meta)
- return "";
- if (key_code == -1)
- return "";
+void ConfigureInput::handleClick(Settings::NativeInput::Values input_id) {
+ QPushButton* button = button_map[input_id];
+ button->setText(tr("[press key]"));
+ button->setFocus();
- return QKeySequence(key_code).toString();
-}
+ current_input_id = input_id;
-Qt::Key ConfigureInput::getKeyValue(const QString& text) const {
- if (text == "Shift")
- return Qt::Key_Shift;
- if (text == "Ctrl")
- return Qt::Key_Control;
- if (text == "Alt")
- return Qt::Key_Alt;
- if (text == "Meta")
- return Qt::Key_unknown;
- if (text == "")
- return Qt::Key_unknown;
-
- return Qt::Key(QKeySequence(text)[0]);
+ grabKeyboard();
+ grabMouse();
+ timer->start(5000); // Cancel after 5 seconds
}
-void ConfigureInput::removeDuplicates(const QString& newValue) {
- for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
- if (changing_button != input_mapping[Settings::NativeInput::Values(i)]) {
- const QString oldValue = input_mapping[Settings::NativeInput::Values(i)]->text();
- if (newValue == oldValue)
- input_mapping[Settings::NativeInput::Values(i)]->setText("");
- }
- }
+void ConfigureInput::keyPressEvent(QKeyEvent* event) {
+ releaseKeyboard();
+ releaseMouse();
+
+ if (!current_input_id || !event)
+ return;
+
+ if (event->key() != Qt::Key_Escape)
+ setInput(*current_input_id, static_cast<Qt::Key>(event->key()));
+
+ updateButtonLabels();
+ current_input_id = boost::none;
+ timer->stop();
}
-void ConfigureInput::restoreDefaults() {
- for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
- const QString keyValue = getKeyName(Config::defaults[i].toInt());
- input_mapping[Settings::NativeInput::Values(i)]->setText(keyValue);
+void ConfigureInput::setInput(Settings::NativeInput::Values input_id, Qt::Key key_pressed) {
+ // Remove duplicates
+ for (auto& pair : key_map) {
+ if (pair.second == key_pressed)
+ pair.second = Qt::Key_unknown;
}
+
+ key_map[input_id] = key_pressed;
}
diff --git a/src/citra_qt/configure_input.h b/src/citra_qt/configure_input.h
index 5183b904d..bc343db83 100644
--- a/src/citra_qt/configure_input.h
+++ b/src/citra_qt/configure_input.h
@@ -7,7 +7,7 @@
#include <memory>
#include <QKeyEvent>
#include <QWidget>
-#include "citra_qt/config.h"
+#include <boost/optional.hpp>
#include "core/settings.h"
#include "ui_configure_input.h"
@@ -30,35 +30,28 @@ public:
private:
std::unique_ptr<Ui::ConfigureInput> ui;
- std::map<Settings::NativeInput::Values, QPushButton*> input_mapping;
- int key_pressed;
- QPushButton* changing_button = nullptr; ///< button currently waiting for key press.
- QString previous_mapping;
- QTimer* timer;
- /// Load configuration settings into button text
- void setConfiguration();
+ /// This input is currently awaiting configuration.
+ /// (i.e.: its corresponding QPushButton has been pressed.)
+ boost::optional<Settings::NativeInput::Values> current_input_id;
+ std::unique_ptr<QTimer> timer;
- /// Check all inputs for duplicate keys. Clears out any other button with the same value as this
- /// button's new value.
- void removeDuplicates(const QString& newValue);
-
- /// Handle key press event for input tab when a button is 'waiting'.
- void keyPressEvent(QKeyEvent* event) override;
-
- /// Convert key ASCII value to its' letter/name
- QString getKeyName(int key_code) const;
-
- /// Convert letter/name of key to its ASCII value.
- Qt::Key getKeyValue(const QString& text) const;
-
- /// Set button text to name of key pressed.
- void setKey();
-
-private slots:
- /// Event handler for all button released() event.
- void handleClick();
+ /// Each input is represented by a QPushButton.
+ std::map<Settings::NativeInput::Values, QPushButton*> button_map;
+ /// Each input is configured to respond to the press of a Qt::Key.
+ std::map<Settings::NativeInput::Values, Qt::Key> key_map;
+ /// Load configuration settings.
+ void loadConfiguration();
/// Restore all buttons to their default values.
void restoreDefaults();
+ /// Update UI to reflect current configuration.
+ void updateButtonLabels();
+
+ /// Called when the button corresponding to input_id was pressed.
+ void handleClick(Settings::NativeInput::Values input_id);
+ /// Handle key press events.
+ void keyPressEvent(QKeyEvent* event) override;
+ /// Configure input input_id to respond to key key_pressed.
+ void setInput(Settings::NativeInput::Values input_id, Qt::Key key_pressed);
};
diff --git a/src/citra_qt/configure_system.cpp b/src/citra_qt/configure_system.cpp
index 873d314ec..eb1276ef3 100644
--- a/src/citra_qt/configure_system.cpp
+++ b/src/citra_qt/configure_system.cpp
@@ -6,7 +6,6 @@
#include "citra_qt/ui_settings.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/fs/archive.h"
-#include "core/system.h"
#include "ui_configure_system.h"
static const std::array<int, 12> days_in_month = {{
@@ -24,7 +23,7 @@ ConfigureSystem::ConfigureSystem(QWidget* parent) : QWidget(parent), ui(new Ui::
ConfigureSystem::~ConfigureSystem() {}
void ConfigureSystem::setConfiguration() {
- enabled = !System::IsPoweredOn();
+ enabled = !Core::System::GetInstance().IsPoweredOn();
if (!enabled) {
ReadSystemSettings();
diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp
index c66f2b96a..c1db93583 100644
--- a/src/citra_qt/debugger/callstack.cpp
+++ b/src/citra_qt/debugger/callstack.cpp
@@ -25,7 +25,7 @@ CallstackWidget::CallstackWidget(QWidget* parent) : QDockWidget(parent) {
void CallstackWidget::OnDebugModeEntered() {
// Stack pointer
- const u32 sp = Core::g_app_core->GetReg(13);
+ const u32 sp = Core::CPU().GetReg(13);
Clear();
diff --git a/src/citra_qt/debugger/callstack.h b/src/citra_qt/debugger/callstack.h
index 765757986..f04ab9c7e 100644
--- a/src/citra_qt/debugger/callstack.h
+++ b/src/citra_qt/debugger/callstack.h
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
#include <QDockWidget>
#include "ui_callstack.h"
@@ -11,7 +13,7 @@ class CallstackWidget : public QDockWidget {
Q_OBJECT
public:
- CallstackWidget(QWidget* parent = nullptr);
+ explicit CallstackWidget(QWidget* parent = nullptr);
public slots:
void OnDebugModeEntered();
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp
index 1ee6bbd6a..e9c8ad858 100644
--- a/src/citra_qt/debugger/disassembler.cpp
+++ b/src/citra_qt/debugger/disassembler.cpp
@@ -185,13 +185,13 @@ DisassemblerWidget::DisassemblerWidget(QWidget* parent, EmuThread* emu_thread)
}
void DisassemblerWidget::Init() {
- model->ParseFromAddress(Core::g_app_core->GetPC());
+ model->ParseFromAddress(Core::CPU().GetPC());
disasm_ui.treeView->resizeColumnToContents(0);
disasm_ui.treeView->resizeColumnToContents(1);
disasm_ui.treeView->resizeColumnToContents(2);
- QModelIndex model_index = model->IndexFromAbsoluteAddress(Core::g_app_core->GetPC());
+ QModelIndex model_index = model->IndexFromAbsoluteAddress(Core::CPU().GetPC());
disasm_ui.treeView->scrollTo(model_index);
disasm_ui.treeView->selectionModel()->setCurrentIndex(
model_index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
@@ -214,8 +214,8 @@ void DisassemblerWidget::OnPause() {
emu_thread->SetRunning(false);
// TODO: By now, the CPU might not have actually stopped...
- if (Core::g_app_core) {
- model->SetNextInstruction(Core::g_app_core->GetPC());
+ if (Core::System::GetInstance().IsPoweredOn()) {
+ model->SetNextInstruction(Core::CPU().GetPC());
}
}
@@ -224,7 +224,7 @@ void DisassemblerWidget::OnToggleStartStop() {
}
void DisassemblerWidget::OnDebugModeEntered() {
- u32 next_instr = Core::g_app_core->GetPC();
+ u32 next_instr = Core::CPU().GetPC();
if (model->GetBreakPoints().IsAddressBreakPoint(next_instr))
emu_thread->SetRunning(false);
diff --git a/src/citra_qt/debugger/disassembler.h b/src/citra_qt/debugger/disassembler.h
index 2ca6c2bd4..a6e59515c 100644
--- a/src/citra_qt/debugger/disassembler.h
+++ b/src/citra_qt/debugger/disassembler.h
@@ -17,7 +17,7 @@ class DisassemblerModel : public QAbstractListModel {
Q_OBJECT
public:
- DisassemblerModel(QObject* parent);
+ explicit DisassemblerModel(QObject* parent);
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
@@ -38,9 +38,7 @@ private:
unsigned int program_counter;
QModelIndex selection;
-
- // TODO: Make BreakPoints less crappy (i.e. const-correct) so that this needn't be mutable.
- mutable BreakPoints breakpoints;
+ BreakPoints breakpoints;
};
class DisassemblerWidget : public QDockWidget {
diff --git a/src/citra_qt/debugger/graphics.cpp b/src/citra_qt/debugger/graphics/graphics.cpp
index ef6712bfa..6a76adeae 100644
--- a/src/citra_qt/debugger/graphics.cpp
+++ b/src/citra_qt/debugger/graphics/graphics.cpp
@@ -3,7 +3,7 @@
// Refer to the license.txt file included.
#include <QListView>
-#include "citra_qt/debugger/graphics.h"
+#include "citra_qt/debugger/graphics/graphics.h"
#include "citra_qt/util/util.h"
extern GraphicsDebugger g_debugger;
@@ -22,15 +22,15 @@ QVariant GPUCommandStreamItemModel::data(const QModelIndex& index, int role) con
return QVariant();
int command_index = index.row();
- const GSP_GPU::Command& command = GetDebugger()->ReadGXCommandHistory(command_index);
+ const Service::GSP::Command& command = GetDebugger()->ReadGXCommandHistory(command_index);
if (role == Qt::DisplayRole) {
- std::map<GSP_GPU::CommandId, const char*> command_names = {
- {GSP_GPU::CommandId::REQUEST_DMA, "REQUEST_DMA"},
- {GSP_GPU::CommandId::SUBMIT_GPU_CMDLIST, "SUBMIT_GPU_CMDLIST"},
- {GSP_GPU::CommandId::SET_MEMORY_FILL, "SET_MEMORY_FILL"},
- {GSP_GPU::CommandId::SET_DISPLAY_TRANSFER, "SET_DISPLAY_TRANSFER"},
- {GSP_GPU::CommandId::SET_TEXTURE_COPY, "SET_TEXTURE_COPY"},
- {GSP_GPU::CommandId::CACHE_FLUSH, "CACHE_FLUSH"},
+ std::map<Service::GSP::CommandId, const char*> command_names = {
+ {Service::GSP::CommandId::REQUEST_DMA, "REQUEST_DMA"},
+ {Service::GSP::CommandId::SUBMIT_GPU_CMDLIST, "SUBMIT_GPU_CMDLIST"},
+ {Service::GSP::CommandId::SET_MEMORY_FILL, "SET_MEMORY_FILL"},
+ {Service::GSP::CommandId::SET_DISPLAY_TRANSFER, "SET_DISPLAY_TRANSFER"},
+ {Service::GSP::CommandId::SET_TEXTURE_COPY, "SET_TEXTURE_COPY"},
+ {Service::GSP::CommandId::CACHE_FLUSH, "CACHE_FLUSH"},
};
const u32* command_data = reinterpret_cast<const u32*>(&command);
QString str = QString("%1 %2 %3 %4 %5 %6 %7 %8 %9")
diff --git a/src/citra_qt/debugger/graphics.h b/src/citra_qt/debugger/graphics/graphics.h
index bedf3e596..8837fb792 100644
--- a/src/citra_qt/debugger/graphics.h
+++ b/src/citra_qt/debugger/graphics/graphics.h
@@ -13,7 +13,7 @@ class GPUCommandStreamItemModel : public QAbstractListModel,
Q_OBJECT
public:
- GPUCommandStreamItemModel(QObject* parent);
+ explicit GPUCommandStreamItemModel(QObject* parent);
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
diff --git a/src/citra_qt/debugger/graphics_breakpoint_observer.cpp b/src/citra_qt/debugger/graphics/graphics_breakpoint_observer.cpp
index e01d3440e..dc6070dea 100644
--- a/src/citra_qt/debugger/graphics_breakpoint_observer.cpp
+++ b/src/citra_qt/debugger/graphics/graphics_breakpoint_observer.cpp
@@ -3,7 +3,7 @@
// Refer to the license.txt file included.
#include <QMetaType>
-#include "citra_qt/debugger/graphics_breakpoint_observer.h"
+#include "citra_qt/debugger/graphics/graphics_breakpoint_observer.h"
BreakPointObserverDock::BreakPointObserverDock(std::shared_ptr<Pica::DebugContext> debug_context,
const QString& title, QWidget* parent)
diff --git a/src/citra_qt/debugger/graphics_breakpoint_observer.h b/src/citra_qt/debugger/graphics/graphics_breakpoint_observer.h
index e77df4f5b..e77df4f5b 100644
--- a/src/citra_qt/debugger/graphics_breakpoint_observer.h
+++ b/src/citra_qt/debugger/graphics/graphics_breakpoint_observer.h
diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics/graphics_breakpoints.cpp
index d2a036dfa..030828ba8 100644
--- a/src/citra_qt/debugger/graphics_breakpoints.cpp
+++ b/src/citra_qt/debugger/graphics/graphics_breakpoints.cpp
@@ -7,8 +7,8 @@
#include <QPushButton>
#include <QTreeView>
#include <QVBoxLayout>
-#include "citra_qt/debugger/graphics_breakpoints.h"
-#include "citra_qt/debugger/graphics_breakpoints_p.h"
+#include "citra_qt/debugger/graphics/graphics_breakpoints.h"
+#include "citra_qt/debugger/graphics/graphics_breakpoints_p.h"
#include "common/assert.h"
BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_context, QObject* parent)
diff --git a/src/citra_qt/debugger/graphics_breakpoints.h b/src/citra_qt/debugger/graphics/graphics_breakpoints.h
index 5fc40c916..bec72a2db 100644
--- a/src/citra_qt/debugger/graphics_breakpoints.h
+++ b/src/citra_qt/debugger/graphics/graphics_breakpoints.h
@@ -20,8 +20,8 @@ class GraphicsBreakPointsWidget : public QDockWidget, Pica::DebugContext::BreakP
using Event = Pica::DebugContext::Event;
public:
- GraphicsBreakPointsWidget(std::shared_ptr<Pica::DebugContext> debug_context,
- QWidget* parent = nullptr);
+ explicit GraphicsBreakPointsWidget(std::shared_ptr<Pica::DebugContext> debug_context,
+ QWidget* parent = nullptr);
void OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) override;
void OnPicaResume() override;
diff --git a/src/citra_qt/debugger/graphics_breakpoints_p.h b/src/citra_qt/debugger/graphics/graphics_breakpoints_p.h
index dc64706bd..dc64706bd 100644
--- a/src/citra_qt/debugger/graphics_breakpoints_p.h
+++ b/src/citra_qt/debugger/graphics/graphics_breakpoints_p.h
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics/graphics_cmdlists.cpp
index 8a784d108..dab529e3a 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.cpp
+++ b/src/citra_qt/debugger/graphics/graphics_cmdlists.cpp
@@ -13,7 +13,7 @@
#include <QSpinBox>
#include <QTreeView>
#include <QVBoxLayout>
-#include "citra_qt/debugger/graphics_cmdlists.h"
+#include "citra_qt/debugger/graphics/graphics_cmdlists.h"
#include "citra_qt/util/spinbox.h"
#include "citra_qt/util/util.h"
#include "common/vector_math.h"
@@ -21,7 +21,8 @@
#include "video_core/pica.h"
#include "video_core/pica_state.h"
-QImage LoadTexture(u8* src, const Pica::DebugUtils::TextureInfo& info) {
+namespace {
+QImage LoadTexture(const u8* src, const Pica::DebugUtils::TextureInfo& info) {
QImage decoded_image(info.width, info.height, QImage::Format_ARGB32);
for (int y = 0; y < info.height; ++y) {
for (int x = 0; x < info.width; ++x) {
@@ -35,7 +36,8 @@ QImage LoadTexture(u8* src, const Pica::DebugUtils::TextureInfo& info) {
class TextureInfoWidget : public QWidget {
public:
- TextureInfoWidget(u8* src, const Pica::DebugUtils::TextureInfo& info, QWidget* parent = nullptr)
+ TextureInfoWidget(const u8* src, const Pica::DebugUtils::TextureInfo& info,
+ QWidget* parent = nullptr)
: QWidget(parent) {
QLabel* image_widget = new QLabel;
QPixmap image_pixmap = QPixmap::fromImage(LoadTexture(src, info));
@@ -47,6 +49,7 @@ public:
setLayout(layout);
}
};
+} // Anonymous namespace
GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent) {}
@@ -65,7 +68,6 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const {
const auto& write = pica_trace.writes[index.row()];
if (role == Qt::DisplayRole) {
- QString content;
switch (index.column()) {
case 0:
return QString::fromLatin1(Pica::Regs::GetCommandName(write.cmd_id).c_str());
@@ -122,19 +124,21 @@ void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) ||
COMMAND_IN_RANGE(command_id, texture2)) {
- unsigned index;
+ unsigned texture_index;
if (COMMAND_IN_RANGE(command_id, texture0)) {
- index = 0;
+ texture_index = 0;
} else if (COMMAND_IN_RANGE(command_id, texture1)) {
- index = 1;
+ texture_index = 1;
} else if (COMMAND_IN_RANGE(command_id, texture2)) {
- index = 2;
+ texture_index = 2;
} else {
UNREACHABLE_MSG("Unknown texture command");
}
- auto config = Pica::g_state.regs.GetTextures()[index].config;
- auto format = Pica::g_state.regs.GetTextures()[index].format;
- auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format);
+
+ const auto texture = Pica::g_state.regs.GetTextures()[texture_index];
+ const auto config = texture.config;
+ const auto format = texture.format;
+ const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format);
// TODO: Open a surface debugger
}
@@ -148,19 +152,21 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
if (COMMAND_IN_RANGE(command_id, texture0) || COMMAND_IN_RANGE(command_id, texture1) ||
COMMAND_IN_RANGE(command_id, texture2)) {
- unsigned index;
+ unsigned texture_index;
if (COMMAND_IN_RANGE(command_id, texture0)) {
- index = 0;
+ texture_index = 0;
} else if (COMMAND_IN_RANGE(command_id, texture1)) {
- index = 1;
+ texture_index = 1;
} else {
- index = 2;
+ texture_index = 2;
}
- auto config = Pica::g_state.regs.GetTextures()[index].config;
- auto format = Pica::g_state.regs.GetTextures()[index].format;
- auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format);
- u8* src = Memory::GetPhysicalPointer(config.GetPhysicalAddress());
+ const auto texture = Pica::g_state.regs.GetTextures()[texture_index];
+ const auto config = texture.config;
+ const auto format = texture.format;
+
+ const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format);
+ const u8* src = Memory::GetPhysicalPointer(config.GetPhysicalAddress());
new_info_widget = new TextureInfoWidget(src, info);
}
if (command_info_widget) {
diff --git a/src/citra_qt/debugger/graphics_cmdlists.h b/src/citra_qt/debugger/graphics/graphics_cmdlists.h
index fa2b9122b..8f40b94c5 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.h
+++ b/src/citra_qt/debugger/graphics/graphics_cmdlists.h
@@ -20,7 +20,7 @@ public:
CommandIdRole = Qt::UserRole,
};
- GPUCommandListModel(QObject* parent);
+ explicit GPUCommandListModel(QObject* parent);
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
@@ -39,7 +39,7 @@ class GPUCommandListWidget : public QDockWidget {
Q_OBJECT
public:
- GPUCommandListWidget(QWidget* parent = nullptr);
+ explicit GPUCommandListWidget(QWidget* parent = nullptr);
public slots:
void OnToggleTracing();
diff --git a/src/citra_qt/debugger/graphics_surface.cpp b/src/citra_qt/debugger/graphics/graphics_surface.cpp
index 906daaa50..4efd95d3c 100644
--- a/src/citra_qt/debugger/graphics_surface.cpp
+++ b/src/citra_qt/debugger/graphics/graphics_surface.cpp
@@ -11,7 +11,7 @@
#include <QPushButton>
#include <QScrollArea>
#include <QSpinBox>
-#include "citra_qt/debugger/graphics_surface.h"
+#include "citra_qt/debugger/graphics/graphics_surface.h"
#include "citra_qt/util/spinbox.h"
#include "common/color.h"
#include "core/hw/gpu.h"
diff --git a/src/citra_qt/debugger/graphics_surface.h b/src/citra_qt/debugger/graphics/graphics_surface.h
index 21e6b5b8b..28f5650a7 100644
--- a/src/citra_qt/debugger/graphics_surface.h
+++ b/src/citra_qt/debugger/graphics/graphics_surface.h
@@ -6,7 +6,7 @@
#include <QLabel>
#include <QPushButton>
-#include "citra_qt/debugger/graphics_breakpoint_observer.h"
+#include "citra_qt/debugger/graphics/graphics_breakpoint_observer.h"
class QComboBox;
class QSpinBox;
@@ -18,7 +18,8 @@ class SurfacePicture : public QLabel {
Q_OBJECT
public:
- SurfacePicture(QWidget* parent = 0, GraphicsSurfaceWidget* surface_widget = nullptr);
+ explicit SurfacePicture(QWidget* parent = nullptr,
+ GraphicsSurfaceWidget* surface_widget = nullptr);
~SurfacePicture();
protected slots:
@@ -71,8 +72,8 @@ class GraphicsSurfaceWidget : public BreakPointObserverDock {
static unsigned int NibblesPerPixel(Format format);
public:
- GraphicsSurfaceWidget(std::shared_ptr<Pica::DebugContext> debug_context,
- QWidget* parent = nullptr);
+ explicit GraphicsSurfaceWidget(std::shared_ptr<Pica::DebugContext> debug_context,
+ QWidget* parent = nullptr);
void Pick(int x, int y);
public slots:
diff --git a/src/citra_qt/debugger/graphics_tracing.cpp b/src/citra_qt/debugger/graphics/graphics_tracing.cpp
index 5c6b74034..716ed50b8 100644
--- a/src/citra_qt/debugger/graphics_tracing.cpp
+++ b/src/citra_qt/debugger/graphics/graphics_tracing.cpp
@@ -12,7 +12,7 @@
#include <QMessageBox>
#include <QPushButton>
#include <boost/range/algorithm/copy.hpp>
-#include "citra_qt/debugger/graphics_tracing.h"
+#include "citra_qt/debugger/graphics/graphics_tracing.h"
#include "common/common_types.h"
#include "core/hw/gpu.h"
#include "core/hw/lcd.h"
diff --git a/src/citra_qt/debugger/graphics_tracing.h b/src/citra_qt/debugger/graphics/graphics_tracing.h
index e04a3dac3..3f73bcd2e 100644
--- a/src/citra_qt/debugger/graphics_tracing.h
+++ b/src/citra_qt/debugger/graphics/graphics_tracing.h
@@ -4,7 +4,7 @@
#pragma once
-#include "citra_qt/debugger/graphics_breakpoint_observer.h"
+#include "citra_qt/debugger/graphics/graphics_breakpoint_observer.h"
class EmuThread;
@@ -12,8 +12,8 @@ class GraphicsTracingWidget : public BreakPointObserverDock {
Q_OBJECT
public:
- GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context,
- QWidget* parent = nullptr);
+ explicit GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context,
+ QWidget* parent = nullptr);
private slots:
void StartRecording();
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp
index 96b40db1e..b75b94ef8 100644
--- a/src/citra_qt/debugger/graphics_vertex_shader.cpp
+++ b/src/citra_qt/debugger/graphics/graphics_vertex_shader.cpp
@@ -14,7 +14,7 @@
#include <QSignalMapper>
#include <QSpinBox>
#include <QTreeView>
-#include "citra_qt/debugger/graphics_vertex_shader.h"
+#include "citra_qt/debugger/graphics/graphics_vertex_shader.h"
#include "citra_qt/util/util.h"
#include "video_core/pica.h"
#include "video_core/pica_state.h"
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.h b/src/citra_qt/debugger/graphics/graphics_vertex_shader.h
index ec42f24bb..bedea0bed 100644
--- a/src/citra_qt/debugger/graphics_vertex_shader.h
+++ b/src/citra_qt/debugger/graphics/graphics_vertex_shader.h
@@ -6,7 +6,7 @@
#include <QAbstractTableModel>
#include <QTreeView>
-#include "citra_qt/debugger/graphics_breakpoint_observer.h"
+#include "citra_qt/debugger/graphics/graphics_breakpoint_observer.h"
#include "nihstro/parser_shbin.h"
#include "video_core/shader/shader.h"
@@ -19,7 +19,7 @@ class GraphicsVertexShaderModel : public QAbstractTableModel {
Q_OBJECT
public:
- GraphicsVertexShaderModel(GraphicsVertexShaderWidget* parent);
+ explicit GraphicsVertexShaderModel(GraphicsVertexShaderWidget* parent);
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
diff --git a/src/citra_qt/debugger/profiler.h b/src/citra_qt/debugger/profiler.h
index d8c6487aa..c8912fd5a 100644
--- a/src/citra_qt/debugger/profiler.h
+++ b/src/citra_qt/debugger/profiler.h
@@ -15,7 +15,7 @@ class ProfilerModel : public QAbstractItemModel {
Q_OBJECT
public:
- ProfilerModel(QObject* parent);
+ explicit ProfilerModel(QObject* parent);
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
@@ -37,7 +37,7 @@ class ProfilerWidget : public QDockWidget {
Q_OBJECT
public:
- ProfilerWidget(QWidget* parent = nullptr);
+ explicit ProfilerWidget(QWidget* parent = nullptr);
private slots:
void setProfilingInfoUpdateEnabled(bool enable);
@@ -53,7 +53,7 @@ class MicroProfileDialog : public QWidget {
Q_OBJECT
public:
- MicroProfileDialog(QWidget* parent = nullptr);
+ explicit MicroProfileDialog(QWidget* parent = nullptr);
/// Returns a QAction that can be used to toggle visibility of this dialog.
QAction* toggleViewAction();
diff --git a/src/citra_qt/debugger/ramview.h b/src/citra_qt/debugger/ramview.h
index 8043c59e8..d01cea93b 100644
--- a/src/citra_qt/debugger/ramview.h
+++ b/src/citra_qt/debugger/ramview.h
@@ -2,13 +2,15 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
#include "qhexedit.h"
class GRamView : public QHexEdit {
Q_OBJECT
public:
- GRamView(QWidget* parent = nullptr);
+ explicit GRamView(QWidget* parent = nullptr);
public slots:
void OnCPUStepped();
diff --git a/src/citra_qt/debugger/registers.cpp b/src/citra_qt/debugger/registers.cpp
index 4c529d3c3..b982bc58b 100644
--- a/src/citra_qt/debugger/registers.cpp
+++ b/src/citra_qt/debugger/registers.cpp
@@ -58,16 +58,16 @@ RegistersWidget::RegistersWidget(QWidget* parent) : QDockWidget(parent) {
}
void RegistersWidget::OnDebugModeEntered() {
- if (!Core::g_app_core)
+ if (!Core::System::GetInstance().IsPoweredOn())
return;
for (int i = 0; i < core_registers->childCount(); ++i)
core_registers->child(i)->setText(
- 1, QString("0x%1").arg(Core::g_app_core->GetReg(i), 8, 16, QLatin1Char('0')));
+ 1, QString("0x%1").arg(Core::CPU().GetReg(i), 8, 16, QLatin1Char('0')));
for (int i = 0; i < vfp_registers->childCount(); ++i)
vfp_registers->child(i)->setText(
- 1, QString("0x%1").arg(Core::g_app_core->GetVFPReg(i), 8, 16, QLatin1Char('0')));
+ 1, QString("0x%1").arg(Core::CPU().GetVFPReg(i), 8, 16, QLatin1Char('0')));
UpdateCPSRValues();
UpdateVFPSystemRegisterValues();
@@ -127,7 +127,7 @@ void RegistersWidget::CreateCPSRChildren() {
}
void RegistersWidget::UpdateCPSRValues() {
- const u32 cpsr_val = Core::g_app_core->GetCPSR();
+ const u32 cpsr_val = Core::CPU().GetCPSR();
cpsr->setText(1, QString("0x%1").arg(cpsr_val, 8, 16, QLatin1Char('0')));
cpsr->child(0)->setText(
@@ -191,10 +191,10 @@ void RegistersWidget::CreateVFPSystemRegisterChildren() {
}
void RegistersWidget::UpdateVFPSystemRegisterValues() {
- const u32 fpscr_val = Core::g_app_core->GetVFPSystemReg(VFP_FPSCR);
- const u32 fpexc_val = Core::g_app_core->GetVFPSystemReg(VFP_FPEXC);
- const u32 fpinst_val = Core::g_app_core->GetVFPSystemReg(VFP_FPINST);
- const u32 fpinst2_val = Core::g_app_core->GetVFPSystemReg(VFP_FPINST2);
+ const u32 fpscr_val = Core::CPU().GetVFPSystemReg(VFP_FPSCR);
+ const u32 fpexc_val = Core::CPU().GetVFPSystemReg(VFP_FPEXC);
+ const u32 fpinst_val = Core::CPU().GetVFPSystemReg(VFP_FPINST);
+ const u32 fpinst2_val = Core::CPU().GetVFPSystemReg(VFP_FPINST2);
QTreeWidgetItem* const fpscr = vfp_system_registers->child(0);
fpscr->setText(1, QString("0x%1").arg(fpscr_val, 8, 16, QLatin1Char('0')));
diff --git a/src/citra_qt/debugger/registers.h b/src/citra_qt/debugger/registers.h
index 54c9a8155..55bda5b59 100644
--- a/src/citra_qt/debugger/registers.h
+++ b/src/citra_qt/debugger/registers.h
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
#include <QDockWidget>
#include "ui_registers.h"
@@ -13,7 +15,7 @@ class RegistersWidget : public QDockWidget {
Q_OBJECT
public:
- RegistersWidget(QWidget* parent = nullptr);
+ explicit RegistersWidget(QWidget* parent = nullptr);
public slots:
void OnDebugModeEntered();
diff --git a/src/citra_qt/debugger/wait_tree.cpp b/src/citra_qt/debugger/wait_tree.cpp
index be5a51e52..1d2de5185 100644
--- a/src/citra_qt/debugger/wait_tree.cpp
+++ b/src/citra_qt/debugger/wait_tree.cpp
@@ -8,7 +8,6 @@
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/semaphore.h"
-#include "core/hle/kernel/session.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h"
@@ -230,7 +229,8 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeThread::GetChildren() const {
list.push_back(std::make_unique<WaitTreeMutexList>(thread.held_mutexes));
}
if (thread.status == THREADSTATUS_WAIT_SYNCH) {
- list.push_back(std::make_unique<WaitTreeObjectList>(thread.wait_objects, thread.wait_all));
+ list.push_back(std::make_unique<WaitTreeObjectList>(thread.wait_objects,
+ thread.IsSleepingOnWaitAll()));
}
return list;
@@ -391,7 +391,7 @@ WaitTreeWidget::WaitTreeWidget(QWidget* parent) : QDockWidget(tr("Wait Tree"), p
}
void WaitTreeWidget::OnDebugModeEntered() {
- if (!Core::g_app_core)
+ if (!Core::System::GetInstance().IsPoweredOn())
return;
model->InitItems();
view->setModel(model);
diff --git a/src/citra_qt/debugger/wait_tree.h b/src/citra_qt/debugger/wait_tree.h
index 5d1d964d1..ee9708fc1 100644
--- a/src/citra_qt/debugger/wait_tree.h
+++ b/src/citra_qt/debugger/wait_tree.h
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
#include <boost/container/flat_set.hpp>
#include <QAbstractItemModel>
@@ -49,7 +51,7 @@ private:
class WaitTreeText : public WaitTreeItem {
Q_OBJECT
public:
- WaitTreeText(const QString& text);
+ explicit WaitTreeText(const QString& text);
QString GetText() const override;
private:
@@ -65,7 +67,7 @@ public:
class WaitTreeWaitObject : public WaitTreeExpandableItem {
Q_OBJECT
public:
- WaitTreeWaitObject(const Kernel::WaitObject& object);
+ explicit WaitTreeWaitObject(const Kernel::WaitObject& object);
static std::unique_ptr<WaitTreeWaitObject> make(const Kernel::WaitObject& object);
QString GetText() const override;
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
@@ -92,7 +94,7 @@ private:
class WaitTreeThread : public WaitTreeWaitObject {
Q_OBJECT
public:
- WaitTreeThread(const Kernel::Thread& thread);
+ explicit WaitTreeThread(const Kernel::Thread& thread);
QString GetText() const override;
QColor GetColor() const override;
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
@@ -101,35 +103,37 @@ public:
class WaitTreeEvent : public WaitTreeWaitObject {
Q_OBJECT
public:
- WaitTreeEvent(const Kernel::Event& object);
+ explicit WaitTreeEvent(const Kernel::Event& object);
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
};
class WaitTreeMutex : public WaitTreeWaitObject {
Q_OBJECT
public:
- WaitTreeMutex(const Kernel::Mutex& object);
+ explicit WaitTreeMutex(const Kernel::Mutex& object);
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
};
class WaitTreeSemaphore : public WaitTreeWaitObject {
Q_OBJECT
public:
- WaitTreeSemaphore(const Kernel::Semaphore& object);
+ explicit WaitTreeSemaphore(const Kernel::Semaphore& object);
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
};
class WaitTreeTimer : public WaitTreeWaitObject {
Q_OBJECT
public:
- WaitTreeTimer(const Kernel::Timer& object);
+ explicit WaitTreeTimer(const Kernel::Timer& object);
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
};
class WaitTreeMutexList : public WaitTreeExpandableItem {
Q_OBJECT
public:
- WaitTreeMutexList(const boost::container::flat_set<Kernel::SharedPtr<Kernel::Mutex>>& list);
+ explicit WaitTreeMutexList(
+ const boost::container::flat_set<Kernel::SharedPtr<Kernel::Mutex>>& list);
+
QString GetText() const override;
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
@@ -140,7 +144,7 @@ private:
class WaitTreeThreadList : public WaitTreeExpandableItem {
Q_OBJECT
public:
- WaitTreeThreadList(const std::vector<Kernel::SharedPtr<Kernel::Thread>>& list);
+ explicit WaitTreeThreadList(const std::vector<Kernel::SharedPtr<Kernel::Thread>>& list);
QString GetText() const override;
std::vector<std::unique_ptr<WaitTreeItem>> GetChildren() const override;
@@ -152,7 +156,7 @@ class WaitTreeModel : public QAbstractItemModel {
Q_OBJECT
public:
- WaitTreeModel(QObject* parent = nullptr);
+ explicit WaitTreeModel(QObject* parent = nullptr);
QVariant data(const QModelIndex& index, int role) const override;
QModelIndex index(int row, int column, const QModelIndex& parent) const override;
@@ -171,7 +175,7 @@ class WaitTreeWidget : public QDockWidget {
Q_OBJECT
public:
- WaitTreeWidget(QWidget* parent = nullptr);
+ explicit WaitTreeWidget(QWidget* parent = nullptr);
public slots:
void OnDebugModeEntered();
diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp
index 07bc35308..09469f3c5 100644
--- a/src/citra_qt/game_list.cpp
+++ b/src/citra_qt/game_list.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <QHeaderView>
+#include <QMenu>
#include <QThreadPool>
#include <QVBoxLayout>
#include "common/common_paths.h"
@@ -13,7 +14,7 @@
#include "game_list_p.h"
#include "ui_settings.h"
-GameList::GameList(QWidget* parent) {
+GameList::GameList(QWidget* parent) : QWidget{parent} {
QVBoxLayout* layout = new QVBoxLayout;
tree_view = new QTreeView;
@@ -28,18 +29,18 @@ GameList::GameList(QWidget* parent) {
tree_view->setSortingEnabled(true);
tree_view->setEditTriggers(QHeaderView::NoEditTriggers);
tree_view->setUniformRowHeights(true);
+ tree_view->setContextMenuPolicy(Qt::CustomContextMenu);
item_model->insertColumns(0, COLUMN_COUNT);
item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, "Name");
item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, "File type");
item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, "Size");
- connect(tree_view, SIGNAL(activated(const QModelIndex&)), this,
- SLOT(ValidateEntry(const QModelIndex&)));
+ connect(tree_view, &QTreeView::activated, this, &GameList::ValidateEntry);
+ connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu);
// We must register all custom types with the Qt Automoc system so that we are able to use it
- // with
- // signals/slots. In this case, QList falls under the umbrells of custom types.
+ // with signals/slots. In this case, QList falls under the umbrells of custom types.
qRegisterMetaType<QList<QStandardItem*>>("QList<QStandardItem*>");
layout->addWidget(tree_view);
@@ -50,7 +51,7 @@ GameList::~GameList() {
emit ShouldCancelWorker();
}
-void GameList::AddEntry(QList<QStandardItem*> entry_items) {
+void GameList::AddEntry(const QList<QStandardItem*>& entry_items) {
item_model->invisibleRootItem()->appendRow(entry_items);
}
@@ -72,6 +73,23 @@ void GameList::DonePopulating() {
tree_view->setEnabled(true);
}
+void GameList::PopupContextMenu(const QPoint& menu_location) {
+ QModelIndex item = tree_view->indexAt(menu_location);
+ if (!item.isValid())
+ return;
+
+ int row = item_model->itemFromIndex(item)->row();
+ QStandardItem* child_file = item_model->invisibleRootItem()->child(row, COLUMN_NAME);
+ u64 program_id = child_file->data(GameListItemPath::ProgramIdRole).toULongLong();
+
+ QMenu context_menu;
+ QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location"));
+ open_save_location->setEnabled(program_id != 0);
+ connect(open_save_location, &QAction::triggered,
+ [&]() { emit OpenSaveFolderRequested(program_id); });
+ context_menu.exec(tree_view->viewport()->mapToGlobal(menu_location));
+}
+
void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) {
if (!FileUtil::Exists(dir_path.toStdString()) ||
!FileUtil::IsDirectory(dir_path.toStdString())) {
@@ -86,12 +104,13 @@ void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) {
emit ShouldCancelWorker();
GameListWorker* worker = new GameListWorker(dir_path, deep_scan);
- connect(worker, SIGNAL(EntryReady(QList<QStandardItem*>)), this,
- SLOT(AddEntry(QList<QStandardItem*>)), Qt::QueuedConnection);
- connect(worker, SIGNAL(Finished()), this, SLOT(DonePopulating()), Qt::QueuedConnection);
+ connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection);
+ connect(worker, &GameListWorker::Finished, this, &GameList::DonePopulating,
+ Qt::QueuedConnection);
// Use DirectConnection here because worker->Cancel() is thread-safe and we want it to cancel
// without delay.
- connect(this, SIGNAL(ShouldCancelWorker()), worker, SLOT(Cancel()), Qt::DirectConnection);
+ connect(this, &GameList::ShouldCancelWorker, worker, &GameListWorker::Cancel,
+ Qt::DirectConnection);
QThreadPool::globalInstance()->start(worker);
current_worker = std::move(worker);
@@ -128,8 +147,11 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
std::vector<u8> smdh;
loader->ReadIcon(smdh);
+ u64 program_id = 0;
+ loader->ReadProgramId(program_id);
+
emit EntryReady({
- new GameListItemPath(QString::fromStdString(physical_name), smdh),
+ new GameListItemPath(QString::fromStdString(physical_name), smdh, program_id),
new GameListItem(
QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
new GameListItemSize(FileUtil::GetSize(physical_name)),
@@ -151,6 +173,6 @@ void GameListWorker::run() {
}
void GameListWorker::Cancel() {
- disconnect(this, 0, 0, 0);
+ disconnect(this, nullptr, nullptr, nullptr);
stop_processing = true;
}
diff --git a/src/citra_qt/game_list.h b/src/citra_qt/game_list.h
index a22e9bc60..1abf10051 100644
--- a/src/citra_qt/game_list.h
+++ b/src/citra_qt/game_list.h
@@ -25,7 +25,7 @@ public:
COLUMN_COUNT, // Number of columns
};
- GameList(QWidget* parent = nullptr);
+ explicit GameList(QWidget* parent = nullptr);
~GameList() override;
void PopulateAsync(const QString& dir_path, bool deep_scan);
@@ -33,18 +33,18 @@ public:
void SaveInterfaceLayout();
void LoadInterfaceLayout();
-public slots:
- void AddEntry(QList<QStandardItem*> entry_items);
-
-private slots:
- void ValidateEntry(const QModelIndex& item);
- void DonePopulating();
-
signals:
void GameChosen(QString game_path);
void ShouldCancelWorker();
+ void OpenSaveFolderRequested(u64 program_id);
private:
+ void AddEntry(const QList<QStandardItem*>& entry_items);
+ void ValidateEntry(const QModelIndex& item);
+ void DonePopulating();
+
+ void PopupContextMenu(const QPoint& menu_location);
+
QTreeView* tree_view = nullptr;
QStandardItemModel* item_model = nullptr;
GameListWorker* current_worker = nullptr;
diff --git a/src/citra_qt/game_list_p.h b/src/citra_qt/game_list_p.h
index 5ca3fe991..a15f06c5f 100644
--- a/src/citra_qt/game_list_p.h
+++ b/src/citra_qt/game_list_p.h
@@ -71,10 +71,13 @@ class GameListItemPath : public GameListItem {
public:
static const int FullPathRole = Qt::UserRole + 1;
static const int TitleRole = Qt::UserRole + 2;
+ static const int ProgramIdRole = Qt::UserRole + 3;
GameListItemPath() : GameListItem() {}
- GameListItemPath(const QString& game_path, const std::vector<u8>& smdh_data) : GameListItem() {
+ GameListItemPath(const QString& game_path, const std::vector<u8>& smdh_data, u64 program_id)
+ : GameListItem() {
setData(game_path, FullPathRole);
+ setData(qulonglong(program_id), ProgramIdRole);
if (!Loader::IsValidSMDH(smdh_data)) {
// SMDH is not valid, set a default icon
diff --git a/src/citra_qt/hotkeys.h b/src/citra_qt/hotkeys.h
index 350103c6f..46f48c2d8 100644
--- a/src/citra_qt/hotkeys.h
+++ b/src/citra_qt/hotkeys.h
@@ -55,7 +55,7 @@ class GHotkeysDialog : public QWidget {
Q_OBJECT
public:
- GHotkeysDialog(QWidget* parent = nullptr);
+ explicit GHotkeysDialog(QWidget* parent = nullptr);
private:
Ui::hotkeys ui;
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index a3887f9ab..6d59cf640 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cinttypes>
#include <clocale>
#include <memory>
#include <thread>
@@ -16,12 +17,12 @@
#include "citra_qt/configure_dialog.h"
#include "citra_qt/debugger/callstack.h"
#include "citra_qt/debugger/disassembler.h"
-#include "citra_qt/debugger/graphics.h"
-#include "citra_qt/debugger/graphics_breakpoints.h"
-#include "citra_qt/debugger/graphics_cmdlists.h"
-#include "citra_qt/debugger/graphics_surface.h"
-#include "citra_qt/debugger/graphics_tracing.h"
-#include "citra_qt/debugger/graphics_vertex_shader.h"
+#include "citra_qt/debugger/graphics/graphics.h"
+#include "citra_qt/debugger/graphics/graphics_breakpoints.h"
+#include "citra_qt/debugger/graphics/graphics_cmdlists.h"
+#include "citra_qt/debugger/graphics/graphics_surface.h"
+#include "citra_qt/debugger/graphics/graphics_tracing.h"
+#include "citra_qt/debugger/graphics/graphics_vertex_shader.h"
#include "citra_qt/debugger/profiler.h"
#include "citra_qt/debugger/ramview.h"
#include "citra_qt/debugger/registers.h"
@@ -41,10 +42,10 @@
#include "common/string_util.h"
#include "core/arm/disassembler/load_symbol_map.h"
#include "core/core.h"
+#include "core/file_sys/archive_source_sd_savedata.h"
#include "core/gdbstub/gdbstub.h"
#include "core/loader/loader.h"
#include "core/settings.h"
-#include "core/system.h"
#include "qhexedit.h"
#include "video_core/video_core.h"
@@ -58,6 +59,36 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) {
ui.setupUi(this);
statusBar()->hide();
+ InitializeWidgets();
+ InitializeDebugMenuActions();
+ InitializeRecentFileMenuActions();
+ InitializeHotkeys();
+
+ SetDefaultUIGeometry();
+ RestoreUIState();
+
+ ConnectWidgetEvents();
+
+ setWindowTitle(QString("Citra | %1-%2").arg(Common::g_scm_branch, Common::g_scm_desc));
+ show();
+
+ game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan);
+
+ QStringList args = QApplication::arguments();
+ if (args.length() >= 2) {
+ BootGame(args[1].toStdString());
+ }
+}
+
+GMainWindow::~GMainWindow() {
+ // will get automatically deleted otherwise
+ if (render_window->parent() == nullptr)
+ delete render_window;
+
+ Pica::g_debug_context.reset();
+}
+
+void GMainWindow::InitializeWidgets() {
render_window = new GRenderWindow(this, emu_thread.get());
render_window->hide();
@@ -93,25 +124,27 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) {
addDockWidget(Qt::RightDockWidgetArea, graphicsCommandsWidget);
graphicsCommandsWidget->hide();
- auto graphicsBreakpointsWidget = new GraphicsBreakPointsWidget(Pica::g_debug_context, this);
+ graphicsBreakpointsWidget = new GraphicsBreakPointsWidget(Pica::g_debug_context, this);
addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget);
graphicsBreakpointsWidget->hide();
- auto graphicsVertexShaderWidget = new GraphicsVertexShaderWidget(Pica::g_debug_context, this);
+ graphicsVertexShaderWidget = new GraphicsVertexShaderWidget(Pica::g_debug_context, this);
addDockWidget(Qt::RightDockWidgetArea, graphicsVertexShaderWidget);
graphicsVertexShaderWidget->hide();
- auto graphicsTracingWidget = new GraphicsTracingWidget(Pica::g_debug_context, this);
+ graphicsTracingWidget = new GraphicsTracingWidget(Pica::g_debug_context, this);
addDockWidget(Qt::RightDockWidgetArea, graphicsTracingWidget);
graphicsTracingWidget->hide();
- auto graphicsSurfaceViewerAction = new QAction(tr("Create Pica Surface Viewer"), this);
- connect(graphicsSurfaceViewerAction, SIGNAL(triggered()), this,
- SLOT(OnCreateGraphicsSurfaceViewer()));
-
waitTreeWidget = new WaitTreeWidget(this);
addDockWidget(Qt::LeftDockWidgetArea, waitTreeWidget);
waitTreeWidget->hide();
+}
+
+void GMainWindow::InitializeDebugMenuActions() {
+ auto graphicsSurfaceViewerAction = new QAction(tr("Create Pica Surface Viewer"), this);
+ connect(graphicsSurfaceViewerAction, SIGNAL(triggered()), this,
+ SLOT(OnCreateGraphicsSurfaceViewer()));
QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging"));
debug_menu->addAction(graphicsSurfaceViewerAction);
@@ -129,19 +162,47 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) {
debug_menu->addAction(graphicsVertexShaderWidget->toggleViewAction());
debug_menu->addAction(graphicsTracingWidget->toggleViewAction());
debug_menu->addAction(waitTreeWidget->toggleViewAction());
+}
- // Set default UI state
+void GMainWindow::InitializeRecentFileMenuActions() {
+ for (int i = 0; i < max_recent_files_item; ++i) {
+ actions_recent_files[i] = new QAction(this);
+ actions_recent_files[i]->setVisible(false);
+ connect(actions_recent_files[i], SIGNAL(triggered()), this, SLOT(OnMenuRecentFile()));
+
+ ui.menu_recent_files->addAction(actions_recent_files[i]);
+ }
+
+ UpdateRecentFiles();
+}
+
+void GMainWindow::InitializeHotkeys() {
+ RegisterHotkey("Main Window", "Load File", QKeySequence::Open);
+ RegisterHotkey("Main Window", "Swap Screens", QKeySequence::NextChild);
+ RegisterHotkey("Main Window", "Start Emulation");
+ LoadHotkeys();
+
+ connect(GetHotkey("Main Window", "Load File", this), SIGNAL(activated()), this,
+ SLOT(OnMenuLoadFile()));
+ connect(GetHotkey("Main Window", "Start Emulation", this), SIGNAL(activated()), this,
+ SLOT(OnStartGame()));
+ connect(GetHotkey("Main Window", "Swap Screens", render_window), SIGNAL(activated()), this,
+ SLOT(OnSwapScreens()));
+}
+
+void GMainWindow::SetDefaultUIGeometry() {
// geometry: 55% of the window contents are in the upper screen half, 45% in the lower half
- QDesktopWidget* desktop = ((QApplication*)QApplication::instance())->desktop();
- QRect screenRect = desktop->screenGeometry(this);
- int x, y, w, h;
- w = screenRect.width() * 2 / 3;
- h = screenRect.height() / 2;
- x = (screenRect.x() + screenRect.width()) / 2 - w / 2;
- y = (screenRect.y() + screenRect.height()) / 2 - h * 55 / 100;
+ const QRect screenRect = QApplication::desktop()->screenGeometry(this);
+
+ const int w = screenRect.width() * 2 / 3;
+ const int h = screenRect.height() / 2;
+ const int x = (screenRect.x() + screenRect.width()) / 2 - w / 2;
+ const int y = (screenRect.y() + screenRect.height()) / 2 - h * 55 / 100;
+
setGeometry(x, y, w, h);
+}
- // Restore UI state
+void GMainWindow::RestoreUIState() {
restoreGeometry(UISettings::values.geometry);
restoreState(UISettings::values.state);
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
@@ -157,20 +218,13 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) {
ui.actionDisplay_widget_title_bars->setChecked(UISettings::values.display_titlebar);
OnDisplayTitleBars(ui.actionDisplay_widget_title_bars->isChecked());
+}
- // Prepare actions for recent files
- for (int i = 0; i < max_recent_files_item; ++i) {
- actions_recent_files[i] = new QAction(this);
- actions_recent_files[i]->setVisible(false);
- connect(actions_recent_files[i], SIGNAL(triggered()), this, SLOT(OnMenuRecentFile()));
-
- ui.menu_recent_files->addAction(actions_recent_files[i]);
- }
- UpdateRecentFiles();
-
- // Setup connections
+void GMainWindow::ConnectWidgetEvents() {
connect(game_list, SIGNAL(GameChosen(QString)), this, SLOT(OnGameListLoadFile(QString)),
Qt::DirectConnection);
+ connect(game_list, SIGNAL(OpenSaveFolderRequested(u64)), this,
+ SLOT(OnGameListOpenSaveFolder(u64)), Qt::DirectConnection);
connect(ui.action_Configure, SIGNAL(triggered()), this, SLOT(OnConfigure()));
connect(ui.action_Load_File, SIGNAL(triggered()), this, SLOT(OnMenuLoadFile()),
Qt::DirectConnection);
@@ -197,40 +251,6 @@ GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) {
connect(this, SIGNAL(EmulationStarting(EmuThread*)), waitTreeWidget,
SLOT(OnEmulationStarting(EmuThread*)));
connect(this, SIGNAL(EmulationStopping()), waitTreeWidget, SLOT(OnEmulationStopping()));
-
- // Setup hotkeys
- RegisterHotkey("Main Window", "Load File", QKeySequence::Open);
- RegisterHotkey("Main Window", "Swap Screens", QKeySequence::NextChild);
- RegisterHotkey("Main Window", "Start Emulation");
- LoadHotkeys();
-
- connect(GetHotkey("Main Window", "Load File", this), SIGNAL(activated()), this,
- SLOT(OnMenuLoadFile()));
- connect(GetHotkey("Main Window", "Start Emulation", this), SIGNAL(activated()), this,
- SLOT(OnStartGame()));
- connect(GetHotkey("Main Window", "Swap Screens", this), SIGNAL(activated()), this,
- SLOT(OnSwapScreens()));
-
- std::string window_title =
- Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc);
- setWindowTitle(window_title.c_str());
-
- show();
-
- game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan);
-
- QStringList args = QApplication::arguments();
- if (args.length() >= 2) {
- BootGame(args[1].toStdString());
- }
-}
-
-GMainWindow::~GMainWindow() {
- // will get automatically deleted otherwise
- if (render_window->parent() == nullptr)
- delete render_window;
-
- Pica::g_debug_context.reset();
}
void GMainWindow::OnDisplayTitleBars(bool show) {
@@ -253,7 +273,7 @@ void GMainWindow::OnDisplayTitleBars(bool show) {
}
}
-bool GMainWindow::InitializeSystem(u32 system_mode) {
+bool GMainWindow::LoadROM(const std::string& filename) {
// Shutdown previous session if the emu thread is still active...
if (emu_thread != nullptr)
ShutdownGame();
@@ -269,54 +289,25 @@ bool GMainWindow::InitializeSystem(u32 system_mode) {
return false;
}
- // Initialize the core emulation
- System::Result system_result = System::Init(render_window, system_mode);
- if (System::Result::Success != system_result) {
- switch (system_result) {
- case System::Result::ErrorInitVideoCore:
- QMessageBox::critical(this, tr("Error while starting Citra!"),
- tr("Failed to initialize the video core!\n\n"
- "Please ensure that your GPU supports OpenGL 3.3 and that you "
- "have the latest graphics driver."));
- break;
-
- default:
- QMessageBox::critical(this, tr("Error while starting Citra!"),
- tr("Unknown error (please check the log)!"));
- break;
- }
- return false;
- }
- return true;
-}
+ Core::System& system{Core::System::GetInstance()};
-bool GMainWindow::LoadROM(const std::string& filename) {
- std::unique_ptr<Loader::AppLoader> app_loader = Loader::GetLoader(filename);
- if (!app_loader) {
- LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", filename.c_str());
- QMessageBox::critical(this, tr("Error while loading ROM!"),
- tr("The ROM format is not supported."));
- return false;
- }
+ const Core::System::ResultStatus result{system.Load(render_window, filename)};
- boost::optional<u32> system_mode = app_loader->LoadKernelSystemMode();
- if (!system_mode) {
- LOG_CRITICAL(Frontend, "Failed to load ROM!");
- QMessageBox::critical(this, tr("Error while loading ROM!"),
- tr("Could not determine the system mode."));
- return false;
- }
-
- if (!InitializeSystem(system_mode.get()))
- return false;
+ if (result != Core::System::ResultStatus::Success) {
+ switch (result) {
+ case Core::System::ResultStatus::ErrorGetLoader:
+ LOG_CRITICAL(Frontend, "Failed to obtain loader for %s!", filename.c_str());
+ QMessageBox::critical(this, tr("Error while loading ROM!"),
+ tr("The ROM format is not supported."));
+ break;
- Loader::ResultStatus result = app_loader->Load();
- if (Loader::ResultStatus::Success != result) {
- System::Shutdown();
- LOG_CRITICAL(Frontend, "Failed to load ROM!");
+ case Core::System::ResultStatus::ErrorSystemMode:
+ LOG_CRITICAL(Frontend, "Failed to load ROM!");
+ QMessageBox::critical(this, tr("Error while loading ROM!"),
+ tr("Could not determine the system mode."));
+ break;
- switch (result) {
- case Loader::ResultStatus::ErrorEncrypted: {
+ case Core::System::ResultStatus::ErrorLoader_ErrorEncrypted: {
// Build the MessageBox ourselves to have clickable link
QMessageBox popup_error;
popup_error.setTextFormat(Qt::RichText);
@@ -331,11 +322,10 @@ bool GMainWindow::LoadROM(const std::string& filename) {
popup_error.exec();
break;
}
- case Loader::ResultStatus::ErrorInvalidFormat:
+ case Core::System::ResultStatus::ErrorLoader_ErrorInvalidFormat:
QMessageBox::critical(this, tr("Error while loading ROM!"),
tr("The ROM format is not supported."));
break;
- case Loader::ResultStatus::Error:
default:
QMessageBox::critical(this, tr("Error while loading ROM!"), tr("Unknown error!"));
@@ -386,6 +376,7 @@ void GMainWindow::BootGame(const std::string& filename) {
game_list->hide();
}
render_window->show();
+ render_window->setFocus();
emulation_running = true;
OnStartGame();
@@ -460,6 +451,21 @@ void GMainWindow::OnGameListLoadFile(QString game_path) {
BootGame(game_path.toStdString());
}
+void GMainWindow::OnGameListOpenSaveFolder(u64 program_id) {
+ std::string sdmc_dir = FileUtil::GetUserPath(D_SDMC_IDX);
+ std::string path = FileSys::ArchiveSource_SDSaveData::GetSaveDataPathFor(sdmc_dir, program_id);
+ QString qpath = QString::fromStdString(path);
+
+ QDir dir(qpath);
+ if (!dir.exists()) {
+ QMessageBox::critical(this, tr("Error Opening Save Folder"), tr("Folder does not exist!"));
+ return;
+ }
+
+ LOG_INFO(Frontend, "Opening save data path for program_id=%" PRIu64, program_id);
+ QDesktopServices::openUrl(QUrl::fromLocalFile(qpath));
+}
+
void GMainWindow::OnMenuLoadFile() {
QString filename =
QFileDialog::getOpenFileName(this, tr("Load File"), UISettings::values.roms_path,
diff --git a/src/citra_qt/main.h b/src/citra_qt/main.h
index f87178227..a2fd45c47 100644
--- a/src/citra_qt/main.h
+++ b/src/citra_qt/main.h
@@ -9,18 +9,21 @@
#include <QMainWindow>
#include "ui_main.h"
+class CallstackWidget;
class Config;
+class DisassemblerWidget;
+class EmuThread;
class GameList;
class GImageInfo;
+class GPUCommandStreamWidget;
+class GPUCommandListWidget;
+class GraphicsBreakPointsWidget;
+class GraphicsTracingWidget;
+class GraphicsVertexShaderWidget;
class GRenderWindow;
-class EmuThread;
-class ProfilerWidget;
class MicroProfileDialog;
-class DisassemblerWidget;
+class ProfilerWidget;
class RegistersWidget;
-class CallstackWidget;
-class GPUCommandStreamWidget;
-class GPUCommandListWidget;
class WaitTreeWidget;
class GMainWindow : public QMainWindow {
@@ -60,6 +63,16 @@ signals:
void EmulationStopping();
private:
+ void InitializeWidgets();
+ void InitializeDebugMenuActions();
+ void InitializeRecentFileMenuActions();
+ void InitializeHotkeys();
+
+ void SetDefaultUIGeometry();
+ void RestoreUIState();
+
+ void ConnectWidgetEvents();
+
/**
* Initializes the emulation system.
* @param system_mode The system mode with which to intialize the kernel.
@@ -105,6 +118,7 @@ private slots:
void OnStopGame();
/// Called whenever a user selects a game in the game list widget.
void OnGameListLoadFile(QString game_path);
+ void OnGameListOpenSaveFolder(u64 program_id);
void OnMenuLoadFile();
void OnMenuLoadSymbolMap();
/// Called whenever a user selects the "File->Select Game List Root" menu item
@@ -135,6 +149,9 @@ private:
CallstackWidget* callstackWidget;
GPUCommandStreamWidget* graphicsWidget;
GPUCommandListWidget* graphicsCommandsWidget;
+ GraphicsBreakPointsWidget* graphicsBreakpointsWidget;
+ GraphicsVertexShaderWidget* graphicsVertexShaderWidget;
+ GraphicsTracingWidget* graphicsTracingWidget;
WaitTreeWidget* waitTreeWidget;
QAction* actions_recent_files[max_recent_files_item];
diff --git a/src/citra_qt/util/spinbox.h b/src/citra_qt/util/spinbox.h
index a57355cd6..2fa1db3a4 100644
--- a/src/citra_qt/util/spinbox.h
+++ b/src/citra_qt/util/spinbox.h
@@ -42,7 +42,7 @@ class CSpinBox : public QAbstractSpinBox {
Q_OBJECT
public:
- CSpinBox(QWidget* parent = nullptr);
+ explicit CSpinBox(QWidget* parent = nullptr);
void stepBy(int steps) override;
StepEnabled stepEnabled() const override;
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 74a271f08..5aecf6e6e 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -3,11 +3,9 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" "${CMAKE_CURRENT_SOU
set(SRCS
break_points.cpp
- emu_window.cpp
file_util.cpp
framebuffer_layout.cpp
hash.cpp
- key_map.cpp
logging/filter.cpp
logging/text_formatter.cpp
logging/backend.cpp
@@ -34,11 +32,9 @@ set(HEADERS
common_funcs.h
common_paths.h
common_types.h
- emu_window.h
file_util.h
framebuffer_layout.h
hash.h
- key_map.h
linear_disk_cache.h
logging/text_formatter.h
logging/filter.h
@@ -71,9 +67,15 @@ if(ARCHITECTURE_x86_64)
set(HEADERS ${HEADERS}
x64/abi.h
x64/cpu_detect.h
- x64/emitter.h)
+ x64/emitter.h
+ x64/xbyak_abi.h
+ x64/xbyak_util.h
+ )
endif()
create_directory_groups(${SRCS} ${HEADERS})
add_library(common STATIC ${SRCS} ${HEADERS})
+if (ARCHITECTURE_x86_64)
+ target_link_libraries(common xbyak)
+endif()
diff --git a/src/common/bit_set.h b/src/common/bit_set.h
index c48b3b769..3059d0cb0 100644
--- a/src/common/bit_set.h
+++ b/src/common/bit_set.h
@@ -16,7 +16,7 @@ namespace Common {
// Helper functions:
-#ifdef _WIN32
+#ifdef _MSC_VER
template <typename T>
static inline int CountSetBits(T v) {
// from https://graphics.stanford.edu/~seander/bithacks.html
diff --git a/src/common/common_paths.h b/src/common/common_paths.h
index 37304d236..b56105306 100644
--- a/src/common/common_paths.h
+++ b/src/common/common_paths.h
@@ -32,22 +32,10 @@
// Subdirs in the User dir returned by GetUserPath(D_USER_IDX)
#define CONFIG_DIR "config"
-#define GAMECONFIG_DIR "game_config"
-#define MAPS_DIR "maps"
#define CACHE_DIR "cache"
#define SDMC_DIR "sdmc"
#define NAND_DIR "nand"
#define SYSDATA_DIR "sysdata"
-#define SHADERCACHE_DIR "shader_cache"
-#define STATESAVES_DIR "state_saves"
-#define SCREENSHOTS_DIR "screenShots"
-#define DUMP_DIR "dump"
-#define DUMP_TEXTURES_DIR "textures"
-#define DUMP_FRAMES_DIR "frames"
-#define DUMP_AUDIO_DIR "audio"
-#define LOGS_DIR "logs"
-#define SHADERS_DIR "shaders"
-#define SYSCONF_DIR "sysconf"
// Filenames
// Files in the directory returned by GetUserPath(D_CONFIG_IDX)
@@ -57,9 +45,3 @@
// Sys files
#define SHARED_FONT "shared_font.bin"
-
-// Files in the directory returned by GetUserPath(D_LOGS_IDX)
-#define MAIN_LOG "emu.log"
-
-// Files in the directory returned by GetUserPath(D_SYSCONF_IDX)
-#define SYSCONF "SYSCONF"
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index b6161f2dc..1a1f5d9b5 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -40,9 +40,20 @@
#endif
#if defined(__APPLE__)
+// CFURL contains __attribute__ directives that gcc does not know how to parse, so we need to just
+// ignore them if we're not using clang. The macro is only used to prevent linking against
+// functions that don't exist on older versions of macOS, and the worst case scenario is a linker
+// error, so this is perfectly safe, just inconvenient.
+#ifndef __clang__
+#define availability(...)
+#endif
#include <CoreFoundation/CFBundle.h>
#include <CoreFoundation/CFString.h>
#include <CoreFoundation/CFURL.h>
+#ifdef availability
+#undef availability
+#endif
+
#endif
#include <algorithm>
@@ -701,24 +712,9 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string& new
paths[D_CACHE_IDX] = cache_dir + DIR_SEP EMU_DATA_DIR DIR_SEP;
}
#endif
-
- paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
- paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP;
paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP;
- paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
- paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
- paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
- paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
- paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
- paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
- paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
- paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
- paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
- paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
- paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
- paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
}
if (!newPath.empty()) {
@@ -732,48 +728,15 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string& new
switch (DirIDX) {
case D_ROOT_IDX:
paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
- paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR + DIR_SEP;
- paths[F_SYSCONF_IDX] = paths[D_SYSCONF_IDX] + SYSCONF;
break;
case D_USER_IDX:
paths[D_USER_IDX] = paths[D_ROOT_IDX] + DIR_SEP;
paths[D_CONFIG_IDX] = paths[D_USER_IDX] + CONFIG_DIR DIR_SEP;
- paths[D_GAMECONFIG_IDX] = paths[D_USER_IDX] + GAMECONFIG_DIR DIR_SEP;
- paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
paths[D_NAND_IDX] = paths[D_USER_IDX] + NAND_DIR DIR_SEP;
- paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
- paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
- paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
- paths[D_SCREENSHOTS_IDX] = paths[D_USER_IDX] + SCREENSHOTS_DIR DIR_SEP;
- paths[D_DUMP_IDX] = paths[D_USER_IDX] + DUMP_DIR DIR_SEP;
- paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
- paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
- paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
- paths[D_LOGS_IDX] = paths[D_USER_IDX] + LOGS_DIR DIR_SEP;
- paths[D_SYSCONF_IDX] = paths[D_USER_IDX] + SYSCONF_DIR DIR_SEP;
- paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG;
- paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
- paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
- paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
break;
-
- case D_CONFIG_IDX:
- paths[F_EMUCONFIG_IDX] = paths[D_CONFIG_IDX] + EMU_CONFIG;
- paths[F_DEBUGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + DEBUGGER_CONFIG;
- paths[F_LOGGERCONFIG_IDX] = paths[D_CONFIG_IDX] + LOGGER_CONFIG;
- break;
-
- case D_DUMP_IDX:
- paths[D_DUMPFRAMES_IDX] = paths[D_DUMP_IDX] + DUMP_FRAMES_DIR DIR_SEP;
- paths[D_DUMPAUDIO_IDX] = paths[D_DUMP_IDX] + DUMP_AUDIO_DIR DIR_SEP;
- paths[D_DUMPTEXTURES_IDX] = paths[D_DUMP_IDX] + DUMP_TEXTURES_DIR DIR_SEP;
- break;
-
- case D_LOGS_IDX:
- paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
}
}
diff --git a/src/common/file_util.h b/src/common/file_util.h
index ac58607c5..94adfcd7e 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -21,31 +21,11 @@ enum {
D_USER_IDX,
D_ROOT_IDX,
D_CONFIG_IDX,
- D_GAMECONFIG_IDX,
- D_MAPS_IDX,
D_CACHE_IDX,
- D_SHADERCACHE_IDX,
- D_SHADERS_IDX,
- D_STATESAVES_IDX,
- D_SCREENSHOTS_IDX,
D_SDMC_IDX,
D_NAND_IDX,
D_SYSDATA_IDX,
- D_HIRESTEXTURES_IDX,
- D_DUMP_IDX,
- D_DUMPFRAMES_IDX,
- D_DUMPAUDIO_IDX,
- D_DUMPTEXTURES_IDX,
- D_DUMPDSP_IDX,
D_LOGS_IDX,
- D_SYSCONF_IDX,
- F_EMUCONFIG_IDX,
- F_DEBUGGERCONFIG_IDX,
- F_LOGGERCONFIG_IDX,
- F_MAINLOG_IDX,
- F_RAMDUMP_IDX,
- F_ARAMDUMP_IDX,
- F_SYSCONF_IDX,
NUM_PATH_INDICES
};
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 7fd397fe5..3ea102229 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -50,6 +50,7 @@ namespace Log {
SUB(Service, CAM) \
SUB(Service, CECD) \
SUB(Service, CFG) \
+ SUB(Service, CSND) \
SUB(Service, DSP) \
SUB(Service, DLP) \
SUB(Service, HID) \
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 96d0dfb8c..9d8c18d8e 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -67,6 +67,7 @@ enum class Class : ClassType {
Service_CAM, ///< The CAM (Camera) service
Service_CECD, ///< The CECD (StreetPass) service
Service_CFG, ///< The CFG (Configuration) service
+ Service_CSND, ///< The CSND (CWAV format process) service
Service_DSP, ///< The DSP (DSP control) service
Service_DLP, ///< The DLP (Download Play) service
Service_HID, ///< The HID (Human interface device) service
diff --git a/src/common/logging/text_formatter.cpp b/src/common/logging/text_formatter.cpp
index d61c1696b..9d423766f 100644
--- a/src/common/logging/text_formatter.cpp
+++ b/src/common/logging/text_formatter.cpp
@@ -7,7 +7,7 @@
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
-#include <Windows.h>
+#include <windows.h>
#endif
#include "common/assert.h"
diff --git a/src/common/scm_rev.cpp.in b/src/common/scm_rev.cpp.in
index 09366e801..79b404bb8 100644
--- a/src/common/scm_rev.cpp.in
+++ b/src/common/scm_rev.cpp.in
@@ -1,5 +1,5 @@
// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2
+// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/scm_rev.h"
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index df1008180..bad311793 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -14,7 +14,7 @@
#ifdef _WIN32
#include <codecvt>
-#include <Windows.h>
+#include <windows.h>
#include "common/common_funcs.h"
#else
#include <iconv.h>
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 9bb2f4e1d..9e207118f 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -6,7 +6,7 @@
#ifdef __APPLE__
#include <mach/mach.h>
#elif defined(_WIN32)
-#include <Windows.h>
+#include <windows.h>
#else
#if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
#include <pthread_np.h>
diff --git a/src/common/timer.cpp b/src/common/timer.cpp
index e843cbd9c..c9803109e 100644
--- a/src/common/timer.cpp
+++ b/src/common/timer.cpp
@@ -4,7 +4,8 @@
#include <time.h>
#ifdef _WIN32
-#include <Windows.h>
+#include <windows.h>
+// windows.h needs to be included before other windows headers
#include <mmsystem.h>
#include <sys/timeb.h>
#else
diff --git a/src/common/x64/xbyak_abi.h b/src/common/x64/xbyak_abi.h
new file mode 100644
index 000000000..6090d93e1
--- /dev/null
+++ b/src/common/x64/xbyak_abi.h
@@ -0,0 +1,178 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <initializer_list>
+#include <xbyak.h>
+#include "common/assert.h"
+#include "common/bit_set.h"
+
+namespace Common {
+namespace X64 {
+
+int RegToIndex(const Xbyak::Reg& reg) {
+ using Kind = Xbyak::Reg::Kind;
+ ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0,
+ "RegSet only support GPRs and XMM registers.");
+ ASSERT_MSG(reg.getIdx() < 16, "RegSet only supports XXM0-15.");
+ return reg.getIdx() + (reg.getKind() == Kind::REG ? 0 : 16);
+}
+
+inline Xbyak::Reg64 IndexToReg64(int reg_index) {
+ ASSERT(reg_index < 16);
+ return Xbyak::Reg64(reg_index);
+}
+
+inline Xbyak::Xmm IndexToXmm(int reg_index) {
+ ASSERT(reg_index >= 16 && reg_index < 32);
+ return Xbyak::Xmm(reg_index - 16);
+}
+
+inline Xbyak::Reg IndexToReg(int reg_index) {
+ if (reg_index < 16) {
+ return IndexToReg64(reg_index);
+ } else {
+ return IndexToXmm(reg_index);
+ }
+}
+
+inline BitSet32 BuildRegSet(std::initializer_list<Xbyak::Reg> regs) {
+ BitSet32 bits;
+ for (const Xbyak::Reg& reg : regs) {
+ bits[RegToIndex(reg)] = true;
+ }
+ return bits;
+}
+
+const BitSet32 ABI_ALL_GPRS(0x0000FFFF);
+const BitSet32 ABI_ALL_XMMS(0xFFFF0000);
+
+#ifdef _WIN32
+
+// Microsoft x64 ABI
+const Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
+const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rcx;
+const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rdx;
+const Xbyak::Reg ABI_PARAM3 = Xbyak::util::r8;
+const Xbyak::Reg ABI_PARAM4 = Xbyak::util::r9;
+
+const BitSet32 ABI_ALL_CALLER_SAVED = BuildRegSet({
+ // GPRs
+ Xbyak::util::rcx, Xbyak::util::rdx, Xbyak::util::r8, Xbyak::util::r9, Xbyak::util::r10,
+ Xbyak::util::r11,
+ // XMMs
+ Xbyak::util::xmm0, Xbyak::util::xmm1, Xbyak::util::xmm2, Xbyak::util::xmm3, Xbyak::util::xmm4,
+ Xbyak::util::xmm5,
+});
+
+const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
+ // GPRs
+ Xbyak::util::rbx, Xbyak::util::rsi, Xbyak::util::rdi, Xbyak::util::rbp, Xbyak::util::r12,
+ Xbyak::util::r13, Xbyak::util::r14, Xbyak::util::r15,
+ // XMMs
+ Xbyak::util::xmm6, Xbyak::util::xmm7, Xbyak::util::xmm8, Xbyak::util::xmm9, Xbyak::util::xmm10,
+ Xbyak::util::xmm11, Xbyak::util::xmm12, Xbyak::util::xmm13, Xbyak::util::xmm14,
+ Xbyak::util::xmm15,
+});
+
+constexpr size_t ABI_SHADOW_SPACE = 0x20;
+
+#else
+
+// System V x86-64 ABI
+const Xbyak::Reg ABI_RETURN = Xbyak::util::rax;
+const Xbyak::Reg ABI_PARAM1 = Xbyak::util::rdi;
+const Xbyak::Reg ABI_PARAM2 = Xbyak::util::rsi;
+const Xbyak::Reg ABI_PARAM3 = Xbyak::util::rdx;
+const Xbyak::Reg ABI_PARAM4 = Xbyak::util::rcx;
+
+const BitSet32 ABI_ALL_CALLER_SAVED = BuildRegSet({
+ // GPRs
+ Xbyak::util::rcx, Xbyak::util::rdx, Xbyak::util::rdi, Xbyak::util::rsi, Xbyak::util::r8,
+ Xbyak::util::r9, Xbyak::util::r10, Xbyak::util::r11,
+ // XMMs
+ Xbyak::util::xmm0, Xbyak::util::xmm1, Xbyak::util::xmm2, Xbyak::util::xmm3, Xbyak::util::xmm4,
+ Xbyak::util::xmm5, Xbyak::util::xmm6, Xbyak::util::xmm7, Xbyak::util::xmm8, Xbyak::util::xmm9,
+ Xbyak::util::xmm10, Xbyak::util::xmm11, Xbyak::util::xmm12, Xbyak::util::xmm13,
+ Xbyak::util::xmm14, Xbyak::util::xmm15,
+});
+
+const BitSet32 ABI_ALL_CALLEE_SAVED = BuildRegSet({
+ // GPRs
+ Xbyak::util::rbx, Xbyak::util::rbp, Xbyak::util::r12, Xbyak::util::r13, Xbyak::util::r14,
+ Xbyak::util::r15,
+});
+
+constexpr size_t ABI_SHADOW_SPACE = 0;
+
+#endif
+
+void ABI_CalculateFrameSize(BitSet32 regs, size_t rsp_alignment, size_t needed_frame_size,
+ s32* out_subtraction, s32* out_xmm_offset) {
+ int count = (regs & ABI_ALL_GPRS).Count();
+ rsp_alignment -= count * 8;
+ size_t subtraction = 0;
+ int xmm_count = (regs & ABI_ALL_XMMS).Count();
+ if (xmm_count) {
+ // If we have any XMMs to save, we must align the stack here.
+ subtraction = rsp_alignment & 0xF;
+ }
+ subtraction += 0x10 * xmm_count;
+ size_t xmm_base_subtraction = subtraction;
+ subtraction += needed_frame_size;
+ subtraction += ABI_SHADOW_SPACE;
+ // Final alignment.
+ rsp_alignment -= subtraction;
+ subtraction += rsp_alignment & 0xF;
+
+ *out_subtraction = (s32)subtraction;
+ *out_xmm_offset = (s32)(subtraction - xmm_base_subtraction);
+}
+
+size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs,
+ size_t rsp_alignment, size_t needed_frame_size = 0) {
+ s32 subtraction, xmm_offset;
+ ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
+
+ for (int reg_index : (regs & ABI_ALL_GPRS)) {
+ code.push(IndexToReg64(reg_index));
+ }
+
+ if (subtraction != 0) {
+ code.sub(code.rsp, subtraction);
+ }
+
+ for (int reg_index : (regs & ABI_ALL_XMMS)) {
+ code.movaps(code.xword[code.rsp + xmm_offset], IndexToXmm(reg_index));
+ xmm_offset += 0x10;
+ }
+
+ return ABI_SHADOW_SPACE;
+}
+
+void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, BitSet32 regs, size_t rsp_alignment,
+ size_t needed_frame_size = 0) {
+ s32 subtraction, xmm_offset;
+ ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size, &subtraction, &xmm_offset);
+
+ for (int reg_index : (regs & ABI_ALL_XMMS)) {
+ code.movaps(IndexToXmm(reg_index), code.xword[code.rsp + xmm_offset]);
+ xmm_offset += 0x10;
+ }
+
+ if (subtraction != 0) {
+ code.add(code.rsp, subtraction);
+ }
+
+ // GPRs need to be popped in reverse order
+ for (int reg_index = 15; reg_index >= 0; reg_index--) {
+ if (regs[reg_index]) {
+ code.pop(IndexToReg64(reg_index));
+ }
+ }
+}
+
+} // namespace X64
+} // namespace Common
diff --git a/src/common/x64/xbyak_util.h b/src/common/x64/xbyak_util.h
new file mode 100644
index 000000000..0f52f704b
--- /dev/null
+++ b/src/common/x64/xbyak_util.h
@@ -0,0 +1,49 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <type_traits>
+#include <xbyak.h>
+#include "common/x64/xbyak_abi.h"
+
+namespace Common {
+namespace X64 {
+
+// Constants for use with cmpps/cmpss
+enum {
+ CMP_EQ = 0,
+ CMP_LT = 1,
+ CMP_LE = 2,
+ CMP_UNORD = 3,
+ CMP_NEQ = 4,
+ CMP_NLT = 5,
+ CMP_NLE = 6,
+ CMP_ORD = 7,
+};
+
+inline bool IsWithin2G(uintptr_t ref, uintptr_t target) {
+ u64 distance = target - (ref + 5);
+ return !(distance >= 0x8000'0000ULL && distance <= ~0x8000'0000ULL);
+}
+
+inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) {
+ return IsWithin2G(reinterpret_cast<uintptr_t>(code.getCurr()), target);
+}
+
+template <typename T>
+inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) {
+ static_assert(std::is_pointer<T>(), "Argument must be a (function) pointer.");
+ size_t addr = reinterpret_cast<size_t>(f);
+ if (IsWithin2G(code, addr)) {
+ code.call(f);
+ } else {
+ // ABI_RETURN is a safe temp register to use before a call
+ code.mov(ABI_RETURN, addr);
+ code.call(ABI_RETURN);
+ }
+}
+
+} // namespace X64
+} // namespace Common
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 8ce141e6a..3621449b3 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -29,15 +29,17 @@ set(SRCS
file_sys/ivfc_archive.cpp
file_sys/path_parser.cpp
file_sys/savedata_archive.cpp
+ frontend/emu_window.cpp
+ frontend/key_map.cpp
gdbstub/gdbstub.cpp
hle/config_mem.cpp
- hle/hle.cpp
hle/applets/applet.cpp
hle/applets/erreula.cpp
hle/applets/mii_selector.cpp
hle/applets/swkbd.cpp
hle/kernel/address_arbiter.cpp
hle/kernel/client_port.cpp
+ hle/kernel/client_session.cpp
hle/kernel/event.cpp
hle/kernel/kernel.cpp
hle/kernel/memory.cpp
@@ -46,14 +48,15 @@ set(SRCS
hle/kernel/resource_limit.cpp
hle/kernel/semaphore.cpp
hle/kernel/server_port.cpp
- hle/kernel/session.cpp
+ hle/kernel/server_session.cpp
hle/kernel/shared_memory.cpp
hle/kernel/thread.cpp
hle/kernel/timer.cpp
hle/kernel/vm_manager.cpp
hle/service/ac_u.cpp
- hle/service/act_a.cpp
- hle/service/act_u.cpp
+ hle/service/act/act.cpp
+ hle/service/act/act_a.cpp
+ hle/service/act/act_u.cpp
hle/service/am/am.cpp
hle/service/am/am_app.cpp
hle/service/am/am_net.cpp
@@ -73,10 +76,12 @@ set(SRCS
hle/service/cam/cam_s.cpp
hle/service/cam/cam_u.cpp
hle/service/cecd/cecd.cpp
+ hle/service/cecd/cecd_ndm.cpp
hle/service/cecd/cecd_s.cpp
hle/service/cecd/cecd_u.cpp
hle/service/cfg/cfg.cpp
hle/service/cfg/cfg_i.cpp
+ hle/service/cfg/cfg_nor.cpp
hle/service/cfg/cfg_s.cpp
hle/service/cfg/cfg_u.cpp
hle/service/csnd_snd.cpp
@@ -105,8 +110,13 @@ set(SRCS
hle/service/ldr_ro/ldr_ro.cpp
hle/service/ldr_ro/memory_synchronizer.cpp
hle/service/mic_u.cpp
+ hle/service/mvd/mvd.cpp
+ hle/service/mvd/mvd_std.cpp
hle/service/ndm/ndm.cpp
hle/service/ndm/ndm_u.cpp
+ hle/service/nfc/nfc.cpp
+ hle/service/nfc/nfc_m.cpp
+ hle/service/nfc/nfc_u.cpp
hle/service/news/news.cpp
hle/service/news/news_s.cpp
hle/service/news/news_u.cpp
@@ -115,12 +125,25 @@ set(SRCS
hle/service/nim/nim_s.cpp
hle/service/nim/nim_u.cpp
hle/service/ns_s.cpp
- hle/service/nwm_uds.cpp
+ hle/service/nwm/nwm.cpp
+ hle/service/nwm/nwm_cec.cpp
+ hle/service/nwm/nwm_ext.cpp
+ hle/service/nwm/nwm_inf.cpp
+ hle/service/nwm/nwm_sap.cpp
+ hle/service/nwm/nwm_soc.cpp
+ hle/service/nwm/nwm_tst.cpp
+ hle/service/nwm/nwm_uds.cpp
hle/service/pm_app.cpp
hle/service/ptm/ptm.cpp
+ hle/service/ptm/ptm_gets.cpp
hle/service/ptm/ptm_play.cpp
+ hle/service/ptm/ptm_sets.cpp
hle/service/ptm/ptm_sysm.cpp
hle/service/ptm/ptm_u.cpp
+ hle/service/qtm/qtm.cpp
+ hle/service/qtm/qtm_s.cpp
+ hle/service/qtm/qtm_sp.cpp
+ hle/service/qtm/qtm_u.cpp
hle/service/service.cpp
hle/service/soc_u.cpp
hle/service/srv.cpp
@@ -140,7 +163,6 @@ set(SRCS
tracer/recorder.cpp
memory.cpp
settings.cpp
- system.cpp
)
set(HEADERS
@@ -178,16 +200,19 @@ set(HEADERS
file_sys/ivfc_archive.h
file_sys/path_parser.h
file_sys/savedata_archive.h
+ frontend/emu_window.h
+ frontend/key_map.h
gdbstub/gdbstub.h
hle/config_mem.h
hle/function_wrappers.h
- hle/hle.h
+ hle/ipc.h
hle/applets/applet.h
hle/applets/erreula.h
hle/applets/mii_selector.h
hle/applets/swkbd.h
hle/kernel/address_arbiter.h
hle/kernel/client_port.h
+ hle/kernel/client_session.h
hle/kernel/event.h
hle/kernel/kernel.h
hle/kernel/memory.h
@@ -196,15 +221,16 @@ set(HEADERS
hle/kernel/resource_limit.h
hle/kernel/semaphore.h
hle/kernel/server_port.h
- hle/kernel/session.h
+ hle/kernel/server_session.h
hle/kernel/shared_memory.h
hle/kernel/thread.h
hle/kernel/timer.h
hle/kernel/vm_manager.h
hle/result.h
hle/service/ac_u.h
- hle/service/act_a.h
- hle/service/act_u.h
+ hle/service/act/act.h
+ hle/service/act/act_a.h
+ hle/service/act/act_u.h
hle/service/am/am.h
hle/service/am/am_app.h
hle/service/am/am_net.h
@@ -224,10 +250,12 @@ set(HEADERS
hle/service/cam/cam_s.h
hle/service/cam/cam_u.h
hle/service/cecd/cecd.h
+ hle/service/cecd/cecd_ndm.h
hle/service/cecd/cecd_s.h
hle/service/cecd/cecd_u.h
hle/service/cfg/cfg.h
hle/service/cfg/cfg_i.h
+ hle/service/cfg/cfg_nor.h
hle/service/cfg/cfg_s.h
hle/service/cfg/cfg_u.h
hle/service/csnd_snd.h
@@ -256,8 +284,13 @@ set(HEADERS
hle/service/ldr_ro/ldr_ro.h
hle/service/ldr_ro/memory_synchronizer.h
hle/service/mic_u.h
+ hle/service/mvd/mvd.h
+ hle/service/mvd/mvd_std.h
hle/service/ndm/ndm.h
hle/service/ndm/ndm_u.h
+ hle/service/nfc/nfc.h
+ hle/service/nfc/nfc_m.h
+ hle/service/nfc/nfc_u.h
hle/service/news/news.h
hle/service/news/news_s.h
hle/service/news/news_u.h
@@ -266,12 +299,25 @@ set(HEADERS
hle/service/nim/nim_s.h
hle/service/nim/nim_u.h
hle/service/ns_s.h
- hle/service/nwm_uds.h
+ hle/service/nwm/nwm.h
+ hle/service/nwm/nwm_cec.h
+ hle/service/nwm/nwm_ext.h
+ hle/service/nwm/nwm_inf.h
+ hle/service/nwm/nwm_sap.h
+ hle/service/nwm/nwm_soc.h
+ hle/service/nwm/nwm_tst.h
+ hle/service/nwm/nwm_uds.h
hle/service/pm_app.h
hle/service/ptm/ptm.h
+ hle/service/ptm/ptm_gets.h
hle/service/ptm/ptm_play.h
+ hle/service/ptm/ptm_sets.h
hle/service/ptm/ptm_sysm.h
hle/service/ptm/ptm_u.h
+ hle/service/qtm/qtm.h
+ hle/service/qtm/qtm_s.h
+ hle/service/qtm/qtm_sp.h
+ hle/service/qtm/qtm_u.h
hle/service/service.h
hle/service/soc_u.h
hle/service/srv.h
@@ -294,7 +340,6 @@ set(HEADERS
memory_setup.h
mmio.h
settings.h
- system.h
)
include_directories(../../externals/dynarmic/include)
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index e466b21b2..ccd43f431 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -8,15 +8,22 @@
#include "core/arm/skyeye_common/arm_regformat.h"
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
-namespace Core {
-struct ThreadContext;
-}
-
/// Generic ARM11 CPU interface
class ARM_Interface : NonCopyable {
public:
virtual ~ARM_Interface() {}
+ struct ThreadContext {
+ u32 cpu_registers[13];
+ u32 sp;
+ u32 lr;
+ u32 pc;
+ u32 cpsr;
+ u32 fpu_registers[64];
+ u32 fpscr;
+ u32 fpexc;
+ };
+
/**
* Runs the CPU for the given number of instructions
* @param num_instructions Number of instructions to run
@@ -124,13 +131,13 @@ public:
* Saves the current CPU context
* @param ctx Thread context to save
*/
- virtual void SaveContext(Core::ThreadContext& ctx) = 0;
+ virtual void SaveContext(ThreadContext& ctx) = 0;
/**
* Loads a CPU context
* @param ctx Thread context to load
*/
- virtual void LoadContext(const Core::ThreadContext& ctx) = 0;
+ virtual void LoadContext(const ThreadContext& ctx) = 0;
/// Prepare core for thread reschedule (if needed to correctly handle state)
virtual void PrepareReschedule() = 0;
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index ca8a94ee9..9f25e3b00 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
#include <dynarmic/dynarmic.h>
#include "common/assert.h"
#include "common/microprofile.h"
@@ -44,6 +45,7 @@ static Dynarmic::UserCallbacks GetUserCallbacks(ARMul_State* interpeter_state) {
user_callbacks.user_arg = static_cast<void*>(interpeter_state);
user_callbacks.CallSVC = &SVC::CallSVC;
user_callbacks.IsReadOnlyMemory = &IsReadOnlyMemory;
+ user_callbacks.MemoryReadCode = &Memory::Read32;
user_callbacks.MemoryRead8 = &Memory::Read8;
user_callbacks.MemoryRead16 = &Memory::Read16;
user_callbacks.MemoryRead32 = &Memory::Read32;
@@ -136,7 +138,7 @@ void ARM_Dynarmic::ExecuteInstructions(int num_instructions) {
AddTicks(ticks_executed);
}
-void ARM_Dynarmic::SaveContext(Core::ThreadContext& ctx) {
+void ARM_Dynarmic::SaveContext(ARM_Interface::ThreadContext& ctx) {
memcpy(ctx.cpu_registers, jit->Regs().data(), sizeof(ctx.cpu_registers));
memcpy(ctx.fpu_registers, jit->ExtRegs().data(), sizeof(ctx.fpu_registers));
@@ -149,7 +151,7 @@ void ARM_Dynarmic::SaveContext(Core::ThreadContext& ctx) {
ctx.fpexc = interpreter_state->VFP[VFP_FPEXC];
}
-void ARM_Dynarmic::LoadContext(const Core::ThreadContext& ctx) {
+void ARM_Dynarmic::LoadContext(const ARM_Interface::ThreadContext& ctx) {
memcpy(jit->Regs().data(), ctx.cpu_registers, sizeof(ctx.cpu_registers));
memcpy(jit->ExtRegs().data(), ctx.fpu_registers, sizeof(ctx.fpu_registers));
diff --git a/src/core/arm/dynarmic/arm_dynarmic.h b/src/core/arm/dynarmic/arm_dynarmic.h
index ced86d29b..87ab53d81 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.h
+++ b/src/core/arm/dynarmic/arm_dynarmic.h
@@ -10,10 +10,6 @@
#include "core/arm/arm_interface.h"
#include "core/arm/skyeye_common/armstate.h"
-namespace Core {
-struct ThreadContext;
-}
-
class ARM_Dynarmic final : public ARM_Interface {
public:
ARM_Dynarmic(PrivilegeMode initial_mode);
@@ -33,8 +29,8 @@ public:
void AddTicks(u64 ticks) override;
- void SaveContext(Core::ThreadContext& ctx) override;
- void LoadContext(const Core::ThreadContext& ctx) override;
+ void SaveContext(ThreadContext& ctx) override;
+ void LoadContext(const ThreadContext& ctx) override;
void PrepareReschedule() override;
void ExecuteInstructions(int num_instructions) override;
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index 34c7f945e..81f9bf99e 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -89,7 +89,7 @@ void ARM_DynCom::ExecuteInstructions(int num_instructions) {
AddTicks(ticks_executed);
}
-void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) {
+void ARM_DynCom::SaveContext(ThreadContext& ctx) {
memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers));
memcpy(ctx.fpu_registers, state->ExtReg.data(), sizeof(ctx.fpu_registers));
@@ -102,7 +102,7 @@ void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) {
ctx.fpexc = state->VFP[VFP_FPEXC];
}
-void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) {
+void ARM_DynCom::LoadContext(const ThreadContext& ctx) {
memcpy(state->Reg.data(), ctx.cpu_registers, sizeof(ctx.cpu_registers));
memcpy(state->ExtReg.data(), ctx.fpu_registers, sizeof(ctx.fpu_registers));
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index 65db1f0f9..62c174f3c 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -10,10 +10,6 @@
#include "core/arm/skyeye_common/arm_regformat.h"
#include "core/arm/skyeye_common/armstate.h"
-namespace Core {
-struct ThreadContext;
-}
-
class ARM_DynCom final : public ARM_Interface {
public:
ARM_DynCom(PrivilegeMode initial_mode);
@@ -36,8 +32,8 @@ public:
void AddTicks(u64 ticks) override;
- void SaveContext(Core::ThreadContext& ctx) override;
- void LoadContext(const Core::ThreadContext& ctx) override;
+ void SaveContext(ThreadContext& ctx) override;
+ void LoadContext(const ThreadContext& ctx) override;
void PrepareReschedule() override;
void ExecuteInstructions(int num_instructions) override;
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index 7b8616702..67c45640a 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -953,7 +953,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
#define GDB_BP_CHECK \
cpu->Cpsr &= ~(1 << 5); \
cpu->Cpsr |= cpu->TFlag << 5; \
- if (GDBStub::g_server_enabled) { \
+ if (GDBStub::IsServerEnabled()) { \
if (GDBStub::IsMemoryBreak() || (breakpoint_data.type != GDBStub::BreakpointType::None && \
PC == breakpoint_data.address)) { \
GDBStub::Break(); \
@@ -1649,7 +1649,7 @@ DISPATCH : {
}
// Find breakpoint if one exists within the block
- if (GDBStub::g_server_enabled && GDBStub::IsConnected()) {
+ if (GDBStub::IsConnected()) {
breakpoint_data =
GDBStub::GetNextBreakpointFromAddress(cpu->Reg[15], GDBStub::BreakpointType::Execute);
}
diff --git a/src/core/arm/dyncom/arm_dyncom_trans.h b/src/core/arm/dyncom/arm_dyncom_trans.h
index b1ec90662..632ff2cd6 100644
--- a/src/core/arm/dyncom/arm_dyncom_trans.h
+++ b/src/core/arm/dyncom/arm_dyncom_trans.h
@@ -1,3 +1,5 @@
+#pragma once
+
#include <cstddef>
#include "common/common_types.h"
diff --git a/src/core/arm/skyeye_common/armstate.cpp b/src/core/arm/skyeye_common/armstate.cpp
index 1465b074e..c36b0208f 100644
--- a/src/core/arm/skyeye_common/armstate.cpp
+++ b/src/core/arm/skyeye_common/armstate.cpp
@@ -182,7 +182,7 @@ void ARMul_State::ResetMPCoreCP15Registers() {
}
static void CheckMemoryBreakpoint(u32 address, GDBStub::BreakpointType type) {
- if (GDBStub::g_server_enabled && GDBStub::CheckBreakpoint(address, type)) {
+ if (GDBStub::IsServerEnabled() && GDBStub::CheckBreakpoint(address, type)) {
LOG_DEBUG(Debug, "Found memory breakpoint @ %08x", address);
GDBStub::Break(true);
}
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 49ac8be6e..202cd332b 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -3,6 +3,8 @@
// Refer to the license.txt file included.
#include <memory>
+
+#include "audio_core/audio_core.h"
#include "common/logging/log.h"
#include "core/arm/arm_interface.h"
#include "core/arm/dynarmic/arm_dynarmic.h"
@@ -10,19 +12,25 @@
#include "core/core.h"
#include "core/core_timing.h"
#include "core/gdbstub/gdbstub.h"
-#include "core/hle/hle.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/thread.h"
+#include "core/hle/service/service.h"
#include "core/hw/hw.h"
+#include "core/loader/loader.h"
#include "core/settings.h"
+#include "video_core/video_core.h"
namespace Core {
-std::unique_ptr<ARM_Interface> g_app_core; ///< ARM11 application core
-std::unique_ptr<ARM_Interface> g_sys_core; ///< ARM11 system (OS) core
+/*static*/ System System::s_instance;
+
+System::ResultStatus System::RunLoop(int tight_loop) {
+ if (!cpu_core) {
+ return ResultStatus::ErrorNotInitialized;
+ }
-/// Run the core CPU loop
-void RunLoop(int tight_loop) {
- if (GDBStub::g_server_enabled) {
+ if (GDBStub::IsServerEnabled()) {
GDBStub::HandlePacket();
// If the loop is halted and we want to step, use a tiny (1) number of instructions to
@@ -32,7 +40,7 @@ void RunLoop(int tight_loop) {
GDBStub::SetCpuStepFlag(false);
tight_loop = 1;
} else {
- return;
+ return ResultStatus::Success;
}
}
}
@@ -43,48 +51,115 @@ void RunLoop(int tight_loop) {
LOG_TRACE(Core_ARM11, "Idling");
CoreTiming::Idle();
CoreTiming::Advance();
- HLE::Reschedule(__func__);
+ PrepareReschedule();
} else {
- g_app_core->Run(tight_loop);
+ cpu_core->Run(tight_loop);
}
HW::Update();
- if (HLE::IsReschedulePending()) {
- Kernel::Reschedule();
- }
+ Reschedule();
+
+ return ResultStatus::Success;
+}
+
+System::ResultStatus System::SingleStep() {
+ return RunLoop(1);
}
-/// Step the CPU one instruction
-void SingleStep() {
- RunLoop(1);
+System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& filepath) {
+ if (app_loader) {
+ app_loader.reset();
+ }
+
+ app_loader = Loader::GetLoader(filepath);
+
+ if (!app_loader) {
+ LOG_CRITICAL(Core, "Failed to obtain loader for %s!", filepath.c_str());
+ return ResultStatus::ErrorGetLoader;
+ }
+
+ boost::optional<u32> system_mode{app_loader->LoadKernelSystemMode()};
+ if (!system_mode) {
+ LOG_CRITICAL(Core, "Failed to determine system mode!");
+ return ResultStatus::ErrorSystemMode;
+ }
+
+ ResultStatus init_result{Init(emu_window, system_mode.get())};
+ if (init_result != ResultStatus::Success) {
+ LOG_CRITICAL(Core, "Failed to initialize system (Error %i)!", init_result);
+ System::Shutdown();
+ return init_result;
+ }
+
+ const Loader::ResultStatus load_result{app_loader->Load()};
+ if (Loader::ResultStatus::Success != load_result) {
+ LOG_CRITICAL(Core, "Failed to load ROM (Error %i)!", load_result);
+ System::Shutdown();
+
+ switch (load_result) {
+ case Loader::ResultStatus::ErrorEncrypted:
+ return ResultStatus::ErrorLoader_ErrorEncrypted;
+ case Loader::ResultStatus::ErrorInvalidFormat:
+ return ResultStatus::ErrorLoader_ErrorInvalidFormat;
+ default:
+ return ResultStatus::ErrorLoader;
+ }
+ }
+ return ResultStatus::Success;
}
-/// Halt the core
-void Halt(const char* msg) {
- // TODO(ShizZy): ImplementMe
+void System::PrepareReschedule() {
+ cpu_core->PrepareReschedule();
+ reschedule_pending = true;
}
-/// Kill the core
-void Stop() {
- // TODO(ShizZy): ImplementMe
+void System::Reschedule() {
+ if (!reschedule_pending) {
+ return;
+ }
+
+ reschedule_pending = false;
+ Kernel::Reschedule();
}
-/// Initialize the core
-void Init() {
+System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
+ if (cpu_core) {
+ cpu_core.reset();
+ }
+
+ Memory::Init();
+
if (Settings::values.use_cpu_jit) {
- g_sys_core = std::make_unique<ARM_Dynarmic>(USER32MODE);
- g_app_core = std::make_unique<ARM_Dynarmic>(USER32MODE);
+ cpu_core = std::make_unique<ARM_Dynarmic>(USER32MODE);
} else {
- g_sys_core = std::make_unique<ARM_DynCom>(USER32MODE);
- g_app_core = std::make_unique<ARM_DynCom>(USER32MODE);
+ cpu_core = std::make_unique<ARM_DynCom>(USER32MODE);
+ }
+
+ CoreTiming::Init();
+ HW::Init();
+ Kernel::Init(system_mode);
+ Service::Init();
+ AudioCore::Init();
+ GDBStub::Init();
+
+ if (!VideoCore::Init(emu_window)) {
+ return ResultStatus::ErrorVideoCore;
}
LOG_DEBUG(Core, "Initialized OK");
+
+ return ResultStatus::Success;
}
-void Shutdown() {
- g_app_core.reset();
- g_sys_core.reset();
+void System::Shutdown() {
+ GDBStub::Shutdown();
+ AudioCore::Shutdown();
+ VideoCore::Shutdown();
+ Service::Shutdown();
+ Kernel::Shutdown();
+ HW::Shutdown();
+ CoreTiming::Shutdown();
+ cpu_core.reset();
LOG_DEBUG(Core, "Shutdown OK");
}
diff --git a/src/core/core.h b/src/core/core.h
index ffbfa91c3..1015e8847 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -5,56 +5,118 @@
#pragma once
#include <memory>
+#include <string>
+
#include "common/common_types.h"
+#include "core/memory.h"
+class EmuWindow;
class ARM_Interface;
-////////////////////////////////////////////////////////////////////////////////////////////////////
+namespace Loader {
+class AppLoader;
+}
namespace Core {
-struct ThreadContext {
- u32 cpu_registers[13];
- u32 sp;
- u32 lr;
- u32 pc;
- u32 cpsr;
- u32 fpu_registers[64];
- u32 fpscr;
- u32 fpexc;
+class System {
+public:
+ /**
+ * Gets the instance of the System singleton class.
+ * @returns Reference to the instance of the System singleton class.
+ */
+ static System& GetInstance() {
+ return s_instance;
+ }
+
+ /// Enumeration representing the return values of the System Initialize and Load process.
+ enum class ResultStatus : u32 {
+ Success, ///< Succeeded
+ ErrorNotInitialized, ///< Error trying to use core prior to initialization
+ ErrorGetLoader, ///< Error finding the correct application loader
+ ErrorSystemMode, ///< Error determining the system mode
+ ErrorLoader, ///< Error loading the specified application
+ ErrorLoader_ErrorEncrypted, ///< Error loading the specified application due to encryption
+ ErrorLoader_ErrorInvalidFormat, ///< Error loading the specified application due to an
+ /// invalid format
+ ErrorVideoCore, ///< Error in the video core
+ };
+
+ /**
+ * Run the core CPU loop
+ * This function runs the core for the specified number of CPU instructions before trying to
+ * update hardware. This is much faster than SingleStep (and should be equivalent), as the CPU
+ * is not required to do a full dispatch with each instruction. NOTE: the number of instructions
+ * requested is not guaranteed to run, as this will be interrupted preemptively if a hardware
+ * update is requested (e.g. on a thread switch).
+ * @param tight_loop Number of instructions to execute.
+ * @return Result status, indicating whethor or not the operation succeeded.
+ */
+ ResultStatus RunLoop(int tight_loop = 1000);
+
+ /**
+ * Step the CPU one instruction
+ * @return Result status, indicating whethor or not the operation succeeded.
+ */
+ ResultStatus SingleStep();
+
+ /// Shutdown the emulated system.
+ void Shutdown();
+
+ /**
+ * Load an executable application.
+ * @param emu_window Pointer to the host-system window used for video output and keyboard input.
+ * @param filepath String path to the executable application to load on the host file system.
+ * @returns ResultStatus code, indicating if the operation succeeded.
+ */
+ ResultStatus Load(EmuWindow* emu_window, const std::string& filepath);
+
+ /**
+ * Indicates if the emulated system is powered on (all subsystems initialized and able to run an
+ * application).
+ * @returns True if the emulated system is powered on, otherwise false.
+ */
+ bool IsPoweredOn() const {
+ return cpu_core != nullptr;
+ }
+
+ /// Prepare the core emulation for a reschedule
+ void PrepareReschedule();
+
+ /**
+ * Gets a reference to the emulated CPU.
+ * @returns A reference to the emulated CPU.
+ */
+ ARM_Interface& CPU() {
+ return *cpu_core;
+ }
+
+private:
+ /**
+ * Initialize the emulated system.
+ * @param emu_window Pointer to the host-system window used for video output and keyboard input.
+ * @param system_mode The system mode.
+ * @return ResultStatus code, indicating if the operation succeeded.
+ */
+ ResultStatus Init(EmuWindow* emu_window, u32 system_mode);
+
+ /// Reschedule the core emulation
+ void Reschedule();
+
+ /// AppLoader used to load the current executing application
+ std::unique_ptr<Loader::AppLoader> app_loader;
+
+ ///< ARM11 CPU core
+ std::unique_ptr<ARM_Interface> cpu_core;
+
+ /// When true, signals that a reschedule should happen
+ bool reschedule_pending{};
+
+ static System s_instance;
};
-extern std::unique_ptr<ARM_Interface> g_app_core; ///< ARM11 application core
-extern std::unique_ptr<ARM_Interface> g_sys_core; ///< ARM11 system (OS) core
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/// Start the core
-void Start();
-
-/**
- * Run the core CPU loop
- * This function runs the core for the specified number of CPU instructions before trying to update
- * hardware. This is much faster than SingleStep (and should be equivalent), as the CPU is not
- * required to do a full dispatch with each instruction. NOTE: the number of instructions requested
- * is not guaranteed to run, as this will be interrupted preemptively if a hardware update is
- * requested (e.g. on a thread switch).
- */
-void RunLoop(int tight_loop = 1000);
-
-/// Step the CPU one instruction
-void SingleStep();
-
-/// Halt the core
-void Halt(const char* msg);
-
-/// Kill the core
-void Stop();
-
-/// Initialize the core
-void Init();
-
-/// Shutdown the core
-void Shutdown();
+static ARM_Interface& CPU() {
+ return System::GetInstance().CPU();
+}
-} // namespace
+} // namespace Core
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 5220b55ea..a437d0823 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -130,7 +130,6 @@ int RegisterEvent(const char* name, TimedCallback callback) {
static void AntiCrashCallback(u64 userdata, int cycles_late) {
LOG_CRITICAL(Core_Timing, "Savestate broken: an unregistered event was called.");
- Core::Halt("invalid timing events");
}
void RestoreRegisterEvent(int event_type, const char* name, TimedCallback callback) {
@@ -147,7 +146,7 @@ void UnregisterAllEvents() {
}
void Init() {
- Core::g_app_core->down_count = INITIAL_SLICE_LENGTH;
+ Core::CPU().down_count = INITIAL_SLICE_LENGTH;
g_slice_length = INITIAL_SLICE_LENGTH;
global_timer = 0;
idled_cycles = 0;
@@ -187,7 +186,7 @@ void Shutdown() {
}
u64 GetTicks() {
- return (u64)global_timer + g_slice_length - Core::g_app_core->down_count;
+ return (u64)global_timer + g_slice_length - Core::CPU().down_count;
}
u64 GetIdleTicks() {
@@ -461,18 +460,18 @@ void MoveEvents() {
}
void ForceCheck() {
- s64 cycles_executed = g_slice_length - Core::g_app_core->down_count;
+ s64 cycles_executed = g_slice_length - Core::CPU().down_count;
global_timer += cycles_executed;
// This will cause us to check for new events immediately.
- Core::g_app_core->down_count = 0;
+ Core::CPU().down_count = 0;
// But let's not eat a bunch more time in Advance() because of this.
g_slice_length = 0;
}
void Advance() {
- s64 cycles_executed = g_slice_length - Core::g_app_core->down_count;
+ s64 cycles_executed = g_slice_length - Core::CPU().down_count;
global_timer += cycles_executed;
- Core::g_app_core->down_count = g_slice_length;
+ Core::CPU().down_count = g_slice_length;
if (has_ts_events)
MoveEvents();
@@ -481,7 +480,7 @@ void Advance() {
if (!first) {
if (g_slice_length < 10000) {
g_slice_length += 10000;
- Core::g_app_core->down_count += g_slice_length;
+ Core::CPU().down_count += g_slice_length;
}
} else {
// Note that events can eat cycles as well.
@@ -491,7 +490,7 @@ void Advance() {
const int diff = target - g_slice_length;
g_slice_length += diff;
- Core::g_app_core->down_count += diff;
+ Core::CPU().down_count += diff;
}
if (advance_callback)
advance_callback(static_cast<int>(cycles_executed));
@@ -507,12 +506,12 @@ void LogPendingEvents() {
}
void Idle(int max_idle) {
- s64 cycles_down = Core::g_app_core->down_count;
+ s64 cycles_down = Core::CPU().down_count;
if (max_idle != 0 && cycles_down > max_idle)
cycles_down = max_idle;
if (first && cycles_down > 0) {
- s64 cycles_executed = g_slice_length - Core::g_app_core->down_count;
+ s64 cycles_executed = g_slice_length - Core::CPU().down_count;
s64 cycles_next_event = first->time - global_timer;
if (cycles_next_event < cycles_executed + cycles_down) {
@@ -527,9 +526,9 @@ void Idle(int max_idle) {
cycles_down / (float)(g_clock_rate_arm11 * 0.001f));
idled_cycles += cycles_down;
- Core::g_app_core->down_count -= cycles_down;
- if (Core::g_app_core->down_count == 0)
- Core::g_app_core->down_count = -1;
+ Core::CPU().down_count -= cycles_down;
+ if (Core::CPU().down_count == 0)
+ Core::CPU().down_count = -1;
}
std::string GetScheduledEventsSummary() {
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index e1c4931ec..51ce78435 100644
--- a/src/core/file_sys/archive_extsavedata.cpp
+++ b/src/core/file_sys/archive_extsavedata.cpp
@@ -64,7 +64,7 @@ private:
*/
class ExtSaveDataArchive : public SaveDataArchive {
public:
- ExtSaveDataArchive(const std::string& mount_point) : SaveDataArchive(mount_point) {}
+ explicit ExtSaveDataArchive(const std::string& mount_point) : SaveDataArchive(mount_point) {}
std::string GetName() const override {
return "ExtSaveDataArchive: " + mount_point;
@@ -141,11 +141,10 @@ std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path)
std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) {
if (shared)
- return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(),
- SYSTEM_ID.c_str());
+ return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(), SYSTEM_ID);
- return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(),
- SYSTEM_ID.c_str(), SDCARD_ID.c_str());
+ return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(), SYSTEM_ID,
+ SDCARD_ID);
}
Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low) {
diff --git a/src/core/file_sys/archive_ncch.cpp b/src/core/file_sys/archive_ncch.cpp
index 6f1aadfc3..89455e39c 100644
--- a/src/core/file_sys/archive_ncch.cpp
+++ b/src/core/file_sys/archive_ncch.cpp
@@ -19,7 +19,7 @@
namespace FileSys {
static std::string GetNCCHContainerPath(const std::string& nand_directory) {
- return Common::StringFromFormat("%s%s/title/", nand_directory.c_str(), SYSTEM_ID.c_str());
+ return Common::StringFromFormat("%s%s/title/", nand_directory.c_str(), SYSTEM_ID);
}
static std::string GetNCCHPath(const std::string& mount_point, u32 high, u32 low) {
diff --git a/src/core/file_sys/archive_ncch.h b/src/core/file_sys/archive_ncch.h
index 66b8ce75d..753b91f96 100644
--- a/src/core/file_sys/archive_ncch.h
+++ b/src/core/file_sys/archive_ncch.h
@@ -17,7 +17,7 @@ namespace FileSys {
/// File system interface to the NCCH archive
class ArchiveFactory_NCCH final : public ArchiveFactory {
public:
- ArchiveFactory_NCCH(const std::string& mount_point);
+ explicit ArchiveFactory_NCCH(const std::string& mount_point);
std::string GetName() const override {
return "NCCH";
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h
index 8a8082a05..1eaf99b54 100644
--- a/src/core/file_sys/archive_romfs.h
+++ b/src/core/file_sys/archive_romfs.h
@@ -20,7 +20,7 @@ namespace FileSys {
/// File system interface to the RomFS archive
class ArchiveFactory_RomFS final : public ArchiveFactory {
public:
- ArchiveFactory_RomFS(Loader::AppLoader& app_loader);
+ explicit ArchiveFactory_RomFS(Loader::AppLoader& app_loader);
std::string GetName() const override {
return "RomFS";
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index 9d99b110c..f6c70bfcc 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -17,7 +17,7 @@ namespace FileSys {
/// Archive backend for SDMC archive
class SDMCArchive : public ArchiveBackend {
public:
- SDMCArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
+ explicit SDMCArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
std::string GetName() const override {
return "SDMCArchive: " + mount_point;
@@ -43,7 +43,7 @@ protected:
/// File system interface to the SDMC archive
class ArchiveFactory_SDMC final : public ArchiveFactory {
public:
- ArchiveFactory_SDMC(const std::string& mount_point);
+ explicit ArchiveFactory_SDMC(const std::string& mount_point);
/**
* Initialize the archive.
diff --git a/src/core/file_sys/archive_sdmcwriteonly.h b/src/core/file_sys/archive_sdmcwriteonly.h
index ed977485a..9cd38d96f 100644
--- a/src/core/file_sys/archive_sdmcwriteonly.h
+++ b/src/core/file_sys/archive_sdmcwriteonly.h
@@ -19,7 +19,7 @@ namespace FileSys {
*/
class SDMCWriteOnlyArchive : public SDMCArchive {
public:
- SDMCWriteOnlyArchive(const std::string& mount_point) : SDMCArchive(mount_point) {}
+ explicit SDMCWriteOnlyArchive(const std::string& mount_point) : SDMCArchive(mount_point) {}
std::string GetName() const override {
return "SDMCWriteOnlyArchive: " + mount_point;
@@ -34,7 +34,7 @@ public:
/// File system interface to the SDMC write-only archive
class ArchiveFactory_SDMCWriteOnly final : public ArchiveFactory {
public:
- ArchiveFactory_SDMCWriteOnly(const std::string& mount_point);
+ explicit ArchiveFactory_SDMCWriteOnly(const std::string& mount_point);
/**
* Initialize the archive.
diff --git a/src/core/file_sys/archive_source_sd_savedata.cpp b/src/core/file_sys/archive_source_sd_savedata.cpp
index 2d8a950a3..e01357891 100644
--- a/src/core/file_sys/archive_source_sd_savedata.cpp
+++ b/src/core/file_sys/archive_source_sd_savedata.cpp
@@ -18,7 +18,7 @@ namespace {
std::string GetSaveDataContainerPath(const std::string& sdmc_directory) {
return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(),
- SYSTEM_ID.c_str(), SDCARD_ID.c_str());
+ SYSTEM_ID, SDCARD_ID);
}
std::string GetSaveDataPath(const std::string& mount_location, u64 program_id) {
@@ -90,4 +90,9 @@ ResultVal<ArchiveFormatInfo> ArchiveSource_SDSaveData::GetFormatInfo(u64 program
return MakeResult<ArchiveFormatInfo>(info);
}
+std::string ArchiveSource_SDSaveData::GetSaveDataPathFor(const std::string& mount_point,
+ u64 program_id) {
+ return GetSaveDataPath(GetSaveDataContainerPath(mount_point), program_id);
+}
+
} // namespace FileSys
diff --git a/src/core/file_sys/archive_source_sd_savedata.h b/src/core/file_sys/archive_source_sd_savedata.h
index b33126c31..b5fe43cc1 100644
--- a/src/core/file_sys/archive_source_sd_savedata.h
+++ b/src/core/file_sys/archive_source_sd_savedata.h
@@ -23,6 +23,8 @@ public:
ResultCode Format(u64 program_id, const FileSys::ArchiveFormatInfo& format_info);
ResultVal<ArchiveFormatInfo> GetFormatInfo(u64 program_id) const;
+ static std::string GetSaveDataPathFor(const std::string& mount_point, u64 program_id);
+
private:
std::string mount_point;
};
diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp
index 54e7793e0..8986b5c0e 100644
--- a/src/core/file_sys/archive_systemsavedata.cpp
+++ b/src/core/file_sys/archive_systemsavedata.cpp
@@ -26,7 +26,7 @@ std::string GetSystemSaveDataPath(const std::string& mount_point, const Path& pa
}
std::string GetSystemSaveDataContainerPath(const std::string& mount_point) {
- return Common::StringFromFormat("%sdata/%s/sysdata/", mount_point.c_str(), SYSTEM_ID.c_str());
+ return Common::StringFromFormat("%sdata/%s/sysdata/", mount_point.c_str(), SYSTEM_ID);
}
Path ConstructSystemSaveDataBinaryPath(u32 high, u32 low) {
diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h
index a24b89f2b..52eb6c630 100644
--- a/src/core/file_sys/archive_systemsavedata.h
+++ b/src/core/file_sys/archive_systemsavedata.h
@@ -18,7 +18,7 @@ namespace FileSys {
/// File system interface to the SystemSaveData archive
class ArchiveFactory_SystemSaveData final : public ArchiveFactory {
public:
- ArchiveFactory_SystemSaveData(const std::string& mount_point);
+ explicit ArchiveFactory_SystemSaveData(const std::string& mount_point);
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override;
diff --git a/src/core/file_sys/path_parser.h b/src/core/file_sys/path_parser.h
index 990802579..b9f52f65d 100644
--- a/src/core/file_sys/path_parser.h
+++ b/src/core/file_sys/path_parser.h
@@ -17,7 +17,7 @@ namespace FileSys {
*/
class PathParser {
public:
- PathParser(const Path& path);
+ explicit PathParser(const Path& path);
/**
* Checks if the Path is valid.
diff --git a/src/core/file_sys/savedata_archive.h b/src/core/file_sys/savedata_archive.h
index 2fb6c452a..176d35710 100644
--- a/src/core/file_sys/savedata_archive.h
+++ b/src/core/file_sys/savedata_archive.h
@@ -18,7 +18,7 @@ namespace FileSys {
/// Archive backend for general save data archive type (SaveData and SystemSaveData)
class SaveDataArchive : public ArchiveBackend {
public:
- SaveDataArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
+ explicit SaveDataArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
std::string GetName() const override {
return "SaveDataArchive: " + mount_point;
diff --git a/src/common/emu_window.cpp b/src/core/frontend/emu_window.cpp
index e3a9e08e6..f6f90f9e1 100644
--- a/src/common/emu_window.cpp
+++ b/src/core/frontend/emu_window.cpp
@@ -5,8 +5,8 @@
#include <algorithm>
#include <cmath>
#include "common/assert.h"
-#include "common/key_map.h"
-#include "emu_window.h"
+#include "core/frontend/emu_window.h"
+#include "core/frontend/key_map.h"
#include "video_core/video_core.h"
void EmuWindow::ButtonPressed(Service::HID::PadState pad) {
diff --git a/src/common/emu_window.h b/src/core/frontend/emu_window.h
index 835c4d500..835c4d500 100644
--- a/src/common/emu_window.h
+++ b/src/core/frontend/emu_window.h
diff --git a/src/common/key_map.cpp b/src/core/frontend/key_map.cpp
index 97cafe9c9..15f0e079c 100644
--- a/src/common/key_map.cpp
+++ b/src/core/frontend/key_map.cpp
@@ -3,8 +3,8 @@
// Refer to the license.txt file included.
#include <map>
-#include "common/emu_window.h"
-#include "common/key_map.h"
+#include "core/frontend/emu_window.h"
+#include "core/frontend/key_map.h"
namespace KeyMap {
diff --git a/src/common/key_map.h b/src/core/frontend/key_map.h
index 040794578..040794578 100644
--- a/src/common/key_map.h
+++ b/src/core/frontend/key_map.h
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index aea43e92b..d88e25073 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -5,6 +5,7 @@
// Originally written by Sven Peter <sven@fail0verflow.com> for anergistic.
#include <algorithm>
+#include <atomic>
#include <climits>
#include <csignal>
#include <cstdarg>
@@ -15,8 +16,8 @@
#include <fcntl.h>
#ifdef _WIN32
-#include <WinSock2.h>
-#include <common/x64/abi.h>
+#include <winsock2.h>
+// winsock2.h needs to be included first to prevent winsock.h being included by other includes
#include <io.h>
#include <iphlpapi.h>
#include <ws2tcpip.h>
@@ -34,6 +35,7 @@
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/gdbstub/gdbstub.h"
+#include "core/loader/loader.h"
#include "core/memory.h"
const int GDB_BUFFER_SIZE = 10000;
@@ -130,7 +132,10 @@ static u16 gdbstub_port = 24689;
static bool halt_loop = true;
static bool step_loop = false;
-std::atomic<bool> g_server_enabled(false);
+
+// If set to false, the server will never be started and no
+// gdbstub-related functions will be executed.
+static std::atomic<bool> server_enabled(false);
#ifdef _WIN32
WSADATA InitData;
@@ -181,11 +186,10 @@ static u8 NibbleToHex(u8 n) {
/**
* Converts input hex string characters into an array of equivalent of u8 bytes.
*
-* @param dest Pointer to buffer to store u8 bytes.
* @param src Pointer to array of output hex string characters.
* @param len Length of src array.
*/
-static u32 HexToInt(u8* src, u32 len) {
+static u32 HexToInt(const u8* src, size_t len) {
u32 output = 0;
while (len-- > 0) {
output = (output << 4) | HexCharToValue(src[0]);
@@ -201,7 +205,7 @@ static u32 HexToInt(u8* src, u32 len) {
* @param src Pointer to array of u8 bytes.
* @param len Length of src array.
*/
-static void MemToGdbHex(u8* dest, u8* src, u32 len) {
+static void MemToGdbHex(u8* dest, const u8* src, size_t len) {
while (len-- > 0) {
u8 tmp = *src++;
*dest++ = NibbleToHex(tmp >> 4);
@@ -216,7 +220,7 @@ static void MemToGdbHex(u8* dest, u8* src, u32 len) {
* @param src Pointer to array of output hex string characters.
* @param len Length of src array.
*/
-static void GdbHexToMem(u8* dest, u8* src, u32 len) {
+static void GdbHexToMem(u8* dest, const u8* src, size_t len) {
while (len-- > 0) {
*dest++ = (HexCharToValue(src[0]) << 4) | HexCharToValue(src[1]);
src += 2;
@@ -240,7 +244,7 @@ static void IntToGdbHex(u8* dest, u32 v) {
*
* @param src Pointer to hex string.
*/
-static u32 GdbHexToInt(u8* src) {
+static u32 GdbHexToInt(const u8* src) {
u32 output = 0;
for (int i = 0; i < 8; i += 2) {
@@ -264,7 +268,7 @@ static u8 ReadByte() {
}
/// Calculate the checksum of the current command buffer.
-static u8 CalculateChecksum(u8* buffer, u32 length) {
+static u8 CalculateChecksum(const u8* buffer, size_t length) {
return static_cast<u8>(std::accumulate(buffer, buffer + length, 0, std::plus<u8>()));
}
@@ -446,9 +450,9 @@ static void SendSignal(u32 signal) {
latest_signal = signal;
- std::string buffer = Common::StringFromFormat("T%02x%02x:%08x;%02x:%08x;", latest_signal, 15,
- htonl(Core::g_app_core->GetPC()), 13,
- htonl(Core::g_app_core->GetReg(13)));
+ std::string buffer =
+ Common::StringFromFormat("T%02x%02x:%08x;%02x:%08x;", latest_signal, 15,
+ htonl(Core::CPU().GetPC()), 13, htonl(Core::CPU().GetReg(13)));
LOG_DEBUG(Debug_GDBStub, "Response: %s", buffer.c_str());
SendReply(buffer.c_str());
}
@@ -535,15 +539,15 @@ static void ReadRegister() {
}
if (id <= R15_REGISTER) {
- IntToGdbHex(reply, Core::g_app_core->GetReg(id));
+ IntToGdbHex(reply, Core::CPU().GetReg(id));
} else if (id == CPSR_REGISTER) {
- IntToGdbHex(reply, Core::g_app_core->GetCPSR());
+ IntToGdbHex(reply, Core::CPU().GetCPSR());
} else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) {
- IntToGdbHex(reply, Core::g_app_core->GetVFPReg(
+ IntToGdbHex(reply, Core::CPU().GetVFPReg(
id - CPSR_REGISTER -
1)); // VFP registers should start at 26, so one after CSPR_REGISTER
} else if (id == FPSCR_REGISTER) {
- IntToGdbHex(reply, Core::g_app_core->GetVFPSystemReg(VFP_FPSCR)); // Get FPSCR
+ IntToGdbHex(reply, Core::CPU().GetVFPSystemReg(VFP_FPSCR)); // Get FPSCR
IntToGdbHex(reply + 8, 0);
} else {
return SendReply("E01");
@@ -560,29 +564,29 @@ static void ReadRegisters() {
u8* bufptr = buffer;
for (int reg = 0; reg <= R15_REGISTER; reg++) {
- IntToGdbHex(bufptr + reg * CHAR_BIT, Core::g_app_core->GetReg(reg));
+ IntToGdbHex(bufptr + reg * CHAR_BIT, Core::CPU().GetReg(reg));
}
bufptr += (16 * CHAR_BIT);
- IntToGdbHex(bufptr, Core::g_app_core->GetCPSR());
+ IntToGdbHex(bufptr, Core::CPU().GetCPSR());
bufptr += CHAR_BIT;
for (int reg = 0; reg <= 31; reg++) {
- IntToGdbHex(bufptr + reg * CHAR_BIT, Core::g_app_core->GetVFPReg(reg));
+ IntToGdbHex(bufptr + reg * CHAR_BIT, Core::CPU().GetVFPReg(reg));
}
bufptr += (32 * CHAR_BIT);
- IntToGdbHex(bufptr, Core::g_app_core->GetVFPSystemReg(VFP_FPSCR));
+ IntToGdbHex(bufptr, Core::CPU().GetVFPSystemReg(VFP_FPSCR));
SendReply(reinterpret_cast<char*>(buffer));
}
/// Modify data of register specified by gdb client.
static void WriteRegister() {
- u8* buffer_ptr = command_buffer + 3;
+ const u8* buffer_ptr = command_buffer + 3;
u32 id = HexCharToValue(command_buffer[1]);
if (command_buffer[2] != '=') {
@@ -592,13 +596,13 @@ static void WriteRegister() {
}
if (id <= R15_REGISTER) {
- Core::g_app_core->SetReg(id, GdbHexToInt(buffer_ptr));
+ Core::CPU().SetReg(id, GdbHexToInt(buffer_ptr));
} else if (id == CPSR_REGISTER) {
- Core::g_app_core->SetCPSR(GdbHexToInt(buffer_ptr));
+ Core::CPU().SetCPSR(GdbHexToInt(buffer_ptr));
} else if (id > CPSR_REGISTER && id < FPSCR_REGISTER) {
- Core::g_app_core->SetVFPReg(id - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr));
+ Core::CPU().SetVFPReg(id - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr));
} else if (id == FPSCR_REGISTER) {
- Core::g_app_core->SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr));
+ Core::CPU().SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr));
} else {
return SendReply("E01");
}
@@ -608,27 +612,26 @@ static void WriteRegister() {
/// Modify all registers with data received from the client.
static void WriteRegisters() {
- u8* buffer_ptr = command_buffer + 1;
+ const u8* buffer_ptr = command_buffer + 1;
if (command_buffer[0] != 'G')
return SendReply("E01");
for (int i = 0, reg = 0; reg <= FPSCR_REGISTER; i++, reg++) {
if (reg <= R15_REGISTER) {
- Core::g_app_core->SetReg(reg, GdbHexToInt(buffer_ptr + i * CHAR_BIT));
+ Core::CPU().SetReg(reg, GdbHexToInt(buffer_ptr + i * CHAR_BIT));
} else if (reg == CPSR_REGISTER) {
- Core::g_app_core->SetCPSR(GdbHexToInt(buffer_ptr + i * CHAR_BIT));
+ Core::CPU().SetCPSR(GdbHexToInt(buffer_ptr + i * CHAR_BIT));
} else if (reg == CPSR_REGISTER - 1) {
// Dummy FPA register, ignore
} else if (reg < CPSR_REGISTER) {
// Dummy FPA registers, ignore
i += 2;
} else if (reg > CPSR_REGISTER && reg < FPSCR_REGISTER) {
- Core::g_app_core->SetVFPReg(reg - CPSR_REGISTER - 1,
- GdbHexToInt(buffer_ptr + i * CHAR_BIT));
+ Core::CPU().SetVFPReg(reg - CPSR_REGISTER - 1, GdbHexToInt(buffer_ptr + i * CHAR_BIT));
i++; // Skip padding
} else if (reg == FPSCR_REGISTER) {
- Core::g_app_core->SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr + i * CHAR_BIT));
+ Core::CPU().SetVFPSystemReg(VFP_FPSCR, GdbHexToInt(buffer_ptr + i * CHAR_BIT));
}
}
@@ -653,7 +656,7 @@ static void ReadMemory() {
SendReply("E01");
}
- u8* data = Memory::GetPointer(addr);
+ const u8* data = Memory::GetPointer(addr);
if (!data) {
return SendReply("E00");
}
@@ -902,10 +905,10 @@ void SetServerPort(u16 port) {
void ToggleServer(bool status) {
if (status) {
- g_server_enabled = status;
+ server_enabled = status;
// Start server
- if (!IsConnected() && Core::g_sys_core != nullptr) {
+ if (!IsConnected() && Core::System().GetInstance().IsPoweredOn()) {
Init();
}
} else {
@@ -914,12 +917,12 @@ void ToggleServer(bool status) {
Shutdown();
}
- g_server_enabled = status;
+ server_enabled = status;
}
}
static void Init(u16 port) {
- if (!g_server_enabled) {
+ if (!server_enabled) {
// Set the halt loop to false in case the user enabled the gdbstub mid-execution.
// This way the CPU can still execute normally.
halt_loop = false;
@@ -998,7 +1001,7 @@ void Init() {
}
void Shutdown() {
- if (!g_server_enabled) {
+ if (!server_enabled) {
return;
}
@@ -1015,8 +1018,12 @@ void Shutdown() {
LOG_INFO(Debug_GDBStub, "GDB stopped.");
}
+bool IsServerEnabled() {
+ return server_enabled;
+}
+
bool IsConnected() {
- return g_server_enabled && gdbserver_socket != -1;
+ return IsServerEnabled() && gdbserver_socket != -1;
}
bool GetCpuHaltFlag() {
diff --git a/src/core/gdbstub/gdbstub.h b/src/core/gdbstub/gdbstub.h
index a7483bb10..38177e32c 100644
--- a/src/core/gdbstub/gdbstub.h
+++ b/src/core/gdbstub/gdbstub.h
@@ -5,7 +5,7 @@
// Originally written by Sven Peter <sven@fail0verflow.com> for anergistic.
#pragma once
-#include <atomic>
+
#include "common/common_types.h"
namespace GDBStub {
@@ -24,10 +24,6 @@ struct BreakpointAddress {
BreakpointType type;
};
-/// If set to false, the server will never be started and no gdbstub-related functions will be
-/// executed.
-extern std::atomic<bool> g_server_enabled;
-
/**
* Set the port the gdbstub should use to listen for connections.
*
@@ -36,7 +32,7 @@ extern std::atomic<bool> g_server_enabled;
void SetServerPort(u16 port);
/**
- * Set the g_server_enabled flag and start or stop the server if possible.
+ * Starts or stops the server if possible.
*
* @param status Set the server to enabled or disabled.
*/
@@ -48,6 +44,9 @@ void Init();
/// Stop gdbstub server.
void Shutdown();
+/// Checks if the gdbstub server is enabled.
+bool IsServerEnabled();
+
/// Returns true if there is an active socket connection.
bool IsConnected();
diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp
index 4311d9897..645b2d5fe 100644
--- a/src/core/hle/applets/applet.cpp
+++ b/src/core/hle/applets/applet.cpp
@@ -101,6 +101,10 @@ ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter)
return result;
}
+bool Applet::IsRunning() const {
+ return is_running;
+}
+
bool IsLibraryAppletRunning() {
// Check the applets map for instances of any applet
for (auto itr = applets.begin(); itr != applets.end(); ++itr)
diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h
index bfdcad126..ebeed9813 100644
--- a/src/core/hle/applets/applet.h
+++ b/src/core/hle/applets/applet.h
@@ -13,8 +13,7 @@ namespace Applets {
class Applet {
public:
- virtual ~Applet() {}
- Applet(Service::APT::AppletId id) : id(id) {}
+ virtual ~Applet() = default;
/**
* Creates an instance of the Applet subclass identified by the parameter.
@@ -48,7 +47,7 @@ public:
/**
* Whether the applet is currently executing instead of the host application or not.
*/
- virtual bool IsRunning() const = 0;
+ bool IsRunning() const;
/**
* Handles an update tick for the Applet, lets it update the screen, send commands, etc.
@@ -56,6 +55,8 @@ public:
virtual void Update() = 0;
protected:
+ explicit Applet(Service::APT::AppletId id) : id(id) {}
+
/**
* Handles the Applet start event, triggered from the application.
* @param parameter Parameter data to handle.
@@ -65,6 +66,9 @@ protected:
Service::APT::AppletId id; ///< Id of this Applet
std::shared_ptr<std::vector<u8>> heap_memory; ///< Heap memory for this Applet
+
+ /// Whether this applet is currently running instead of the host application or not.
+ bool is_running = false;
};
/// Returns whether a library applet is currently running
diff --git a/src/core/hle/applets/erreula.cpp b/src/core/hle/applets/erreula.cpp
index e1379ac4d..75d7fd9fc 100644
--- a/src/core/hle/applets/erreula.cpp
+++ b/src/core/hle/applets/erreula.cpp
@@ -47,7 +47,7 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param
}
ResultCode ErrEula::StartImpl(const Service::APT::AppletStartupParameter& parameter) {
- started = true;
+ is_running = true;
// TODO(Subv): Set the expected fields in the response buffer before resending it to the
// application.
@@ -62,7 +62,7 @@ ResultCode ErrEula::StartImpl(const Service::APT::AppletStartupParameter& parame
message.sender_id = static_cast<u32>(id);
Service::APT::SendParameter(message);
- started = false;
+ is_running = false;
return RESULT_SUCCESS;
}
diff --git a/src/core/hle/applets/erreula.h b/src/core/hle/applets/erreula.h
index a7ec7ec01..681bbea0c 100644
--- a/src/core/hle/applets/erreula.h
+++ b/src/core/hle/applets/erreula.h
@@ -17,18 +17,12 @@ public:
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
void Update() override;
- bool IsRunning() const override {
- return started;
- }
+private:
/// This SharedMemory will be created when we receive the LibAppJustStarted message.
/// It holds the framebuffer info retrieved by the application with
/// GSPGPU::ImportDisplayCaptureInfo
Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
-
-private:
- /// Whether this applet is currently running instead of the host application or not.
- bool started = false;
};
} // namespace Applets
diff --git a/src/core/hle/applets/mii_selector.cpp b/src/core/hle/applets/mii_selector.cpp
index 3455b9201..07c7f5b99 100644
--- a/src/core/hle/applets/mii_selector.cpp
+++ b/src/core/hle/applets/mii_selector.cpp
@@ -55,7 +55,7 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
}
ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& parameter) {
- started = true;
+ is_running = true;
// TODO(Subv): Set the expected fields in the response buffer before resending it to the
// application.
@@ -78,7 +78,7 @@ ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& pa
message.sender_id = static_cast<u32>(id);
Service::APT::SendParameter(message);
- started = false;
+ is_running = false;
return RESULT_SUCCESS;
}
diff --git a/src/core/hle/applets/mii_selector.h b/src/core/hle/applets/mii_selector.h
index e3ab9f0cd..ec00e29d2 100644
--- a/src/core/hle/applets/mii_selector.h
+++ b/src/core/hle/applets/mii_selector.h
@@ -65,23 +65,18 @@ ASSERT_REG_POSITION(unk_6C, 0x6C);
class MiiSelector final : public Applet {
public:
- MiiSelector(Service::APT::AppletId id) : Applet(id), started(false) {}
+ MiiSelector(Service::APT::AppletId id) : Applet(id) {}
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
void Update() override;
- bool IsRunning() const override {
- return started;
- }
+private:
/// This SharedMemory will be created when we receive the LibAppJustStarted message.
/// It holds the framebuffer info retrieved by the application with
/// GSPGPU::ImportDisplayCaptureInfo
Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
- /// Whether this applet is currently running instead of the host application or not.
- bool started;
-
MiiConfig config;
};
}
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp
index 1e21337f5..059297fbc 100644
--- a/src/core/hle/applets/swkbd.cpp
+++ b/src/core/hle/applets/swkbd.cpp
@@ -70,7 +70,7 @@ ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter cons
DrawScreenKeyboard();
- started = true;
+ is_running = true;
return RESULT_SUCCESS;
}
@@ -94,13 +94,13 @@ void SoftwareKeyboard::Update() {
}
void SoftwareKeyboard::DrawScreenKeyboard() {
- auto bottom_screen = GSP_GPU::GetFrameBufferInfo(0, 1);
+ auto bottom_screen = Service::GSP::GetFrameBufferInfo(0, 1);
auto info = bottom_screen->framebuffer_info[bottom_screen->index];
// TODO(Subv): Draw the HLE keyboard, for now just zero-fill the framebuffer
Memory::ZeroBlock(info.address_left, info.stride * 320);
- GSP_GPU::SetBufferSwap(1, info);
+ Service::GSP::SetBufferSwap(1, info);
}
void SoftwareKeyboard::Finalize() {
@@ -113,7 +113,7 @@ void SoftwareKeyboard::Finalize() {
message.sender_id = static_cast<u32>(id);
Service::APT::SendParameter(message);
- started = false;
+ is_running = false;
}
}
} // namespace
diff --git a/src/core/hle/applets/swkbd.h b/src/core/hle/applets/swkbd.h
index ea0b1fba9..cc92a8f19 100644
--- a/src/core/hle/applets/swkbd.h
+++ b/src/core/hle/applets/swkbd.h
@@ -52,14 +52,11 @@ static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config
class SoftwareKeyboard final : public Applet {
public:
- SoftwareKeyboard(Service::APT::AppletId id) : Applet(id), started(false) {}
+ SoftwareKeyboard(Service::APT::AppletId id) : Applet(id) {}
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
void Update() override;
- bool IsRunning() const override {
- return started;
- }
/**
* Draws a keyboard to the current bottom screen framebuffer.
@@ -72,6 +69,7 @@ public:
*/
void Finalize();
+private:
/// This SharedMemory will be created when we receive the LibAppJustStarted message.
/// It holds the framebuffer info retrieved by the application with
/// GSPGPU::ImportDisplayCaptureInfo
@@ -82,9 +80,6 @@ public:
/// Configuration of this instance of the SoftwareKeyboard, as received from the application
SoftwareKeyboardConfig config;
-
- /// Whether this applet is currently running instead of the host application or not.
- bool started;
};
}
} // namespace
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 8ce0f6d2b..7875971ce 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -7,14 +7,14 @@
#include "common/common_types.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
-#include "core/hle/hle.h"
+#include "core/hle/kernel/kernel.h"
#include "core/hle/result.h"
#include "core/hle/svc.h"
#include "core/memory.h"
namespace HLE {
-#define PARAM(n) Core::g_app_core->GetReg(n)
+#define PARAM(n) Core::CPU().GetReg(n)
/// An invalid result code that is meant to be overwritten when a thread resumes from waiting
static const ResultCode RESULT_INVALID(0xDEADC0DE);
@@ -24,7 +24,7 @@ static const ResultCode RESULT_INVALID(0xDEADC0DE);
* @param res Result to return
*/
static inline void FuncReturn(u32 res) {
- Core::g_app_core->SetReg(0, res);
+ Core::CPU().SetReg(0, res);
}
/**
@@ -33,8 +33,8 @@ static inline void FuncReturn(u32 res) {
* @todo Verify that this function is correct
*/
static inline void FuncReturn64(u64 res) {
- Core::g_app_core->SetReg(0, (u32)(res & 0xFFFFFFFF));
- Core::g_app_core->SetReg(1, (u32)((res >> 32) & 0xFFFFFFFF));
+ Core::CPU().SetReg(0, (u32)(res & 0xFFFFFFFF));
+ Core::CPU().SetReg(1, (u32)((res >> 32) & 0xFFFFFFFF));
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -49,7 +49,7 @@ template <ResultCode func(u32*, u32, u32, u32, u32, u32)>
void Wrap() {
u32 param_1 = 0;
u32 retval = func(&param_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -57,19 +57,19 @@ template <ResultCode func(u32*, s32, u32, u32, u32, s32)>
void Wrap() {
u32 param_1 = 0;
u32 retval = func(&param_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
template <ResultCode func(s32*, u32*, s32, bool, s64)>
void Wrap() {
s32 param_1 = 0;
- s32 retval = func(&param_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2),
+ s32 retval = func(&param_1, (Kernel::Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2),
(PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0)))
.raw;
if (retval != RESULT_INVALID.raw) {
- Core::g_app_core->SetReg(1, (u32)param_1);
+ Core::CPU().SetReg(1, (u32)param_1);
FuncReturn(retval);
}
}
@@ -84,7 +84,7 @@ template <ResultCode func(u32*)>
void Wrap() {
u32 param_1 = 0;
u32 retval = func(&param_1).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -102,24 +102,24 @@ void Wrap() {
MemoryInfo memory_info = {};
PageInfo page_info = {};
u32 retval = func(&memory_info, &page_info, PARAM(2)).raw;
- Core::g_app_core->SetReg(1, memory_info.base_address);
- Core::g_app_core->SetReg(2, memory_info.size);
- Core::g_app_core->SetReg(3, memory_info.permission);
- Core::g_app_core->SetReg(4, memory_info.state);
- Core::g_app_core->SetReg(5, page_info.flags);
+ Core::CPU().SetReg(1, memory_info.base_address);
+ Core::CPU().SetReg(2, memory_info.size);
+ Core::CPU().SetReg(3, memory_info.permission);
+ Core::CPU().SetReg(4, memory_info.state);
+ Core::CPU().SetReg(5, page_info.flags);
FuncReturn(retval);
}
-template <ResultCode func(MemoryInfo*, PageInfo*, Handle, u32)>
+template <ResultCode func(MemoryInfo*, PageInfo*, Kernel::Handle, u32)>
void Wrap() {
MemoryInfo memory_info = {};
PageInfo page_info = {};
u32 retval = func(&memory_info, &page_info, PARAM(2), PARAM(3)).raw;
- Core::g_app_core->SetReg(1, memory_info.base_address);
- Core::g_app_core->SetReg(2, memory_info.size);
- Core::g_app_core->SetReg(3, memory_info.permission);
- Core::g_app_core->SetReg(4, memory_info.state);
- Core::g_app_core->SetReg(5, page_info.flags);
+ Core::CPU().SetReg(1, memory_info.base_address);
+ Core::CPU().SetReg(2, memory_info.size);
+ Core::CPU().SetReg(3, memory_info.permission);
+ Core::CPU().SetReg(4, memory_info.state);
+ Core::CPU().SetReg(5, page_info.flags);
FuncReturn(retval);
}
@@ -127,7 +127,7 @@ template <ResultCode func(s32*, u32)>
void Wrap() {
s32 param_1 = 0;
u32 retval = func(&param_1, PARAM(1)).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -140,7 +140,7 @@ template <ResultCode func(u32*, u32)>
void Wrap() {
u32 param_1 = 0;
u32 retval = func(&param_1, PARAM(1)).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -160,7 +160,7 @@ template <ResultCode func(u32*, const char*)>
void Wrap() {
u32 param_1 = 0;
u32 retval = func(&param_1, (char*)Memory::GetPointer(PARAM(1))).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -168,7 +168,7 @@ template <ResultCode func(u32*, s32, s32)>
void Wrap() {
u32 param_1 = 0;
u32 retval = func(&param_1, PARAM(1), PARAM(2)).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -176,7 +176,7 @@ template <ResultCode func(s32*, u32, s32)>
void Wrap() {
s32 param_1 = 0;
u32 retval = func(&param_1, PARAM(1), PARAM(2)).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -184,8 +184,8 @@ template <ResultCode func(s64*, u32, s32)>
void Wrap() {
s64 param_1 = 0;
u32 retval = func(&param_1, PARAM(1), PARAM(2)).raw;
- Core::g_app_core->SetReg(1, (u32)param_1);
- Core::g_app_core->SetReg(2, (u32)(param_1 >> 32));
+ Core::CPU().SetReg(1, (u32)param_1);
+ Core::CPU().SetReg(2, (u32)(param_1 >> 32));
FuncReturn(retval);
}
@@ -194,7 +194,7 @@ void Wrap() {
u32 param_1 = 0;
// The last parameter is passed in R0 instead of R4
u32 retval = func(&param_1, PARAM(1), PARAM(2), PARAM(3), PARAM(0)).raw;
- Core::g_app_core->SetReg(1, param_1);
+ Core::CPU().SetReg(1, param_1);
FuncReturn(retval);
}
@@ -205,30 +205,30 @@ void Wrap() {
FuncReturn(func(PARAM(0), param1, param2).raw);
}
-template <ResultCode func(s64*, Handle, u32)>
+template <ResultCode func(s64*, Kernel::Handle, u32)>
void Wrap() {
s64 param_1 = 0;
u32 retval = func(&param_1, PARAM(1), PARAM(2)).raw;
- Core::g_app_core->SetReg(1, (u32)param_1);
- Core::g_app_core->SetReg(2, (u32)(param_1 >> 32));
+ Core::CPU().SetReg(1, (u32)param_1);
+ Core::CPU().SetReg(2, (u32)(param_1 >> 32));
FuncReturn(retval);
}
-template <ResultCode func(Handle, u32)>
+template <ResultCode func(Kernel::Handle, u32)>
void Wrap() {
FuncReturn(func(PARAM(0), PARAM(1)).raw);
}
-template <ResultCode func(Handle*, Handle*, const char*, u32)>
+template <ResultCode func(Kernel::Handle*, Kernel::Handle*, const char*, u32)>
void Wrap() {
- Handle param_1 = 0;
- Handle param_2 = 0;
+ Kernel::Handle param_1 = 0;
+ Kernel::Handle param_2 = 0;
u32 retval = func(&param_1, &param_2,
reinterpret_cast<const char*>(Memory::GetPointer(PARAM(2))), PARAM(3))
.raw;
// The first out parameter is moved into R2 and the second is moved into R1.
- Core::g_app_core->SetReg(1, param_2);
- Core::g_app_core->SetReg(2, param_1);
+ Core::CPU().SetReg(1, param_2);
+ Core::CPU().SetReg(2, param_1);
FuncReturn(retval);
}
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
deleted file mode 100644
index 41b772163..000000000
--- a/src/core/hle/hle.cpp
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "common/assert.h"
-#include "common/logging/log.h"
-#include "core/arm/arm_interface.h"
-#include "core/core.h"
-#include "core/hle/hle.h"
-#include "core/hle/service/service.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-namespace {
-
-bool reschedule; ///< If true, immediately reschedules the CPU to a new thread
-}
-
-namespace HLE {
-
-void Reschedule(const char* reason) {
- DEBUG_ASSERT_MSG(reason != nullptr && strlen(reason) < 256,
- "Reschedule: Invalid or too long reason.");
-
- // TODO(bunnei): It seems that games depend on some CPU execution time elapsing during HLE
- // routines. This simulates that time by artificially advancing the number of CPU "ticks".
- // The value was chosen empirically, it seems to work well enough for everything tested, but
- // is likely not ideal. We should find a more accurate way to simulate timing with HLE.
- Core::g_app_core->AddTicks(4000);
-
- Core::g_app_core->PrepareReschedule();
-
- reschedule = true;
-}
-
-bool IsReschedulePending() {
- return reschedule;
-}
-
-void DoneRescheduling() {
- reschedule = false;
-}
-
-void Init() {
- Service::Init();
-
- reschedule = false;
-
- LOG_DEBUG(Kernel, "initialized OK");
-}
-
-void Shutdown() {
- Service::Shutdown();
-
- LOG_DEBUG(Kernel, "shutdown OK");
-}
-
-} // namespace
diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h
deleted file mode 100644
index 23859e129..000000000
--- a/src/core/hle/hle.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "common/common_types.h"
-
-typedef u32 Handle;
-typedef s32 Result;
-
-const Handle INVALID_HANDLE = 0;
-
-namespace HLE {
-
-void Reschedule(const char* reason);
-bool IsReschedulePending();
-void DoneRescheduling();
-
-void Init();
-void Shutdown();
-
-} // namespace
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/ipc.h
index ec025f732..4e094faa7 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/ipc.h
@@ -1,17 +1,31 @@
-// Copyright 2014 Citra Emulator Project
+// Copyright 2016 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
-#include <string>
-#include "common/assert.h"
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/thread.h"
-#include "core/hle/result.h"
#include "core/memory.h"
+namespace Kernel {
+
+static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header
+
+/**
+ * Returns a pointer to the command buffer in the current thread's TLS
+ * TODO(Subv): This is not entirely correct, the command buffer should be copied from
+ * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to
+ * the service handler process' memory.
+ * @param offset Optional offset into command buffer
+ * @return Pointer to command buffer
+ */
+inline u32* GetCommandBuffer(const int offset = 0) {
+ return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset +
+ offset);
+}
+}
+
namespace IPC {
enum DescriptorType : u32 {
@@ -144,75 +158,3 @@ inline DescriptorType GetDescriptorType(u32 descriptor) {
}
} // namespace IPC
-
-namespace Kernel {
-
-static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header
-
-/**
- * Returns a pointer to the command buffer in the current thread's TLS
- * TODO(Subv): This is not entirely correct, the command buffer should be copied from
- * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to
- * the service handler process' memory.
- * @param offset Optional offset into command buffer
- * @return Pointer to command buffer
- */
-inline u32* GetCommandBuffer(const int offset = 0) {
- return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset +
- offset);
-}
-
-/**
- * Kernel object representing the client endpoint of an IPC session. Sessions are the basic CTR-OS
- * primitive for communication between different processes, and are used to implement service calls
- * to the various system services.
- *
- * To make a service call, the client must write the command header and parameters to the buffer
- * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest
- * SVC call with its Session handle. The kernel will read the command header, using it to marshall
- * the parameters to the process at the server endpoint of the session. After the server replies to
- * the request, the response is marshalled back to the caller's TLS buffer and control is
- * transferred back to it.
- *
- * In Citra, only the client endpoint is currently implemented and only HLE calls, where the IPC
- * request is answered by C++ code in the emulator, are supported. When SendSyncRequest is called
- * with the session handle, this class's SyncRequest method is called, which should read the TLS
- * buffer and emulate the call accordingly. Since the code can directly read the emulated memory,
- * no parameter marshalling is done.
- *
- * In the long term, this should be turned into the full-fledged IPC mechanism implemented by
- * CTR-OS so that IPC calls can be optionally handled by the real implementations of processes, as
- * opposed to HLE simulations.
- */
-class Session : public WaitObject {
-public:
- Session();
- ~Session() override;
-
- std::string GetTypeName() const override {
- return "Session";
- }
-
- static const HandleType HANDLE_TYPE = HandleType::Session;
- HandleType GetHandleType() const override {
- return HANDLE_TYPE;
- }
-
- /**
- * Handles a synchronous call to this session using HLE emulation. Emulated <-> emulated calls
- * aren't supported yet.
- */
- virtual ResultVal<bool> SyncRequest() = 0;
-
- // TODO(bunnei): These functions exist to satisfy a hardware test with a Session object
- // passed into WaitSynchronization. Figure out the meaning of them.
-
- bool ShouldWait() override {
- return true;
- }
-
- void Acquire() override {
- ASSERT_MSG(!ShouldWait(), "object unavailable!");
- }
-};
-}
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 37eec4c84..01fab123e 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -4,7 +4,6 @@
#include "common/common_types.h"
#include "common/logging/log.h"
-#include "core/hle/hle.h"
#include "core/hle/kernel/address_arbiter.h"
#include "core/hle/kernel/thread.h"
#include "core/memory.h"
@@ -79,8 +78,6 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
ErrorSummary::WrongArgument, ErrorLevel::Usage);
}
- HLE::Reschedule(__func__);
-
// The calls that use a timeout seem to always return a Timeout error even if they did not put
// the thread to sleep
if (type == ArbitrationType::WaitIfLessThanWithTimeout ||
diff --git a/src/core/hle/kernel/client_port.cpp b/src/core/hle/kernel/client_port.cpp
index aedc6f989..22645f4ec 100644
--- a/src/core/hle/kernel/client_port.cpp
+++ b/src/core/hle/kernel/client_port.cpp
@@ -4,12 +4,44 @@
#include "common/assert.h"
#include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/server_port.h"
+#include "core/hle/kernel/server_session.h"
namespace Kernel {
ClientPort::ClientPort() {}
ClientPort::~ClientPort() {}
+ResultVal<SharedPtr<ClientSession>> ClientPort::Connect() {
+ // Note: Threads do not wait for the server endpoint to call
+ // AcceptSession before returning from this call.
+
+ if (active_sessions >= max_sessions) {
+ // TODO(Subv): Return an error code in this situation after session disconnection is
+ // implemented.
+ /*return ResultCode(ErrorDescription::MaxConnectionsReached,
+ ErrorModule::OS, ErrorSummary::WouldBlock,
+ ErrorLevel::Temporary);*/
+ }
+ active_sessions++;
+
+ // Create a new session pair, let the created sessions inherit the parent port's HLE handler.
+ auto sessions =
+ ServerSession::CreateSessionPair(server_port->GetName(), server_port->hle_handler);
+ auto client_session = std::get<SharedPtr<ClientSession>>(sessions);
+ auto server_session = std::get<SharedPtr<ServerSession>>(sessions);
+
+ if (server_port->hle_handler)
+ server_port->hle_handler->ClientConnected(server_session);
+
+ server_port->pending_sessions.push_back(std::move(server_session));
+
+ // Wake the threads waiting on the ServerPort
+ server_port->WakeupAllWaitingThreads();
+
+ return MakeResult<SharedPtr<ClientSession>>(std::move(client_session));
+}
+
} // namespace
diff --git a/src/core/hle/kernel/client_port.h b/src/core/hle/kernel/client_port.h
index d28147718..511490c7c 100644
--- a/src/core/hle/kernel/client_port.h
+++ b/src/core/hle/kernel/client_port.h
@@ -11,8 +11,9 @@
namespace Kernel {
class ServerPort;
+class ClientSession;
-class ClientPort : public Object {
+class ClientPort final : public Object {
public:
friend class ServerPort;
std::string GetTypeName() const override {
@@ -27,12 +28,20 @@ public:
return HANDLE_TYPE;
}
+ /**
+ * Creates a new Session pair, adds the created ServerSession to the associated ServerPort's
+ * list of pending sessions, and signals the ServerPort, causing any threads
+ * waiting on it to awake.
+ * @returns ClientSession The client endpoint of the created Session pair, or error code.
+ */
+ ResultVal<SharedPtr<ClientSession>> Connect();
+
SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port.
u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have
u32 active_sessions; ///< Number of currently open sessions to this port
std::string name; ///< Name of client port (optional)
-protected:
+private:
ClientPort();
~ClientPort() override;
};
diff --git a/src/core/hle/kernel/client_session.cpp b/src/core/hle/kernel/client_session.cpp
new file mode 100644
index 000000000..0331386ec
--- /dev/null
+++ b/src/core/hle/kernel/client_session.cpp
@@ -0,0 +1,40 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+
+#include "core/hle/kernel/client_session.h"
+#include "core/hle/kernel/server_session.h"
+
+namespace Kernel {
+
+ClientSession::ClientSession() = default;
+ClientSession::~ClientSession() {
+ // This destructor will be called automatically when the last ClientSession handle is closed by
+ // the emulated application.
+
+ if (server_session->hle_handler)
+ server_session->hle_handler->ClientDisconnected(server_session);
+
+ // TODO(Subv): If the session is still open, set the connection status to 2 (Closed by client),
+ // wake up all the ServerSession's waiting threads and set the WaitSynchronization result to
+ // 0xC920181A.
+}
+
+ResultVal<SharedPtr<ClientSession>> ClientSession::Create(ServerSession* server_session,
+ std::string name) {
+ SharedPtr<ClientSession> client_session(new ClientSession);
+
+ client_session->name = std::move(name);
+ client_session->server_session = server_session;
+ client_session->session_status = SessionStatus::Open;
+ return MakeResult<SharedPtr<ClientSession>>(std::move(client_session));
+}
+
+ResultCode ClientSession::SendSyncRequest() {
+ // Signal the server session that new data is available
+ return server_session->HandleSyncRequest();
+}
+
+} // namespace
diff --git a/src/core/hle/kernel/client_session.h b/src/core/hle/kernel/client_session.h
new file mode 100644
index 000000000..ed468dec6
--- /dev/null
+++ b/src/core/hle/kernel/client_session.h
@@ -0,0 +1,65 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "common/common_types.h"
+
+#include "core/hle/kernel/kernel.h"
+
+namespace Kernel {
+
+class ServerSession;
+
+enum class SessionStatus {
+ Open = 1,
+ ClosedByClient = 2,
+ ClosedBYServer = 3,
+};
+
+class ClientSession final : public Object {
+public:
+ friend class ServerSession;
+
+ std::string GetTypeName() const override {
+ return "ClientSession";
+ }
+
+ std::string GetName() const override {
+ return name;
+ }
+
+ static const HandleType HANDLE_TYPE = HandleType::ClientSession;
+ HandleType GetHandleType() const override {
+ return HANDLE_TYPE;
+ }
+
+ /**
+ * Sends an SyncRequest from the current emulated thread.
+ * @return ResultCode of the operation.
+ */
+ ResultCode SendSyncRequest();
+
+ std::string name; ///< Name of client port (optional)
+ ServerSession* server_session; ///< The server session associated with this client session.
+ SessionStatus session_status; ///< The session's current status.
+
+private:
+ ClientSession();
+ ~ClientSession() override;
+
+ /**
+ * Creates a client session.
+ * @param server_session The server session associated with this client session
+ * @param name Optional name of client session
+ * @return The created client session
+ */
+ static ResultVal<SharedPtr<ClientSession>> Create(ServerSession* server_session,
+ std::string name = "Unknown");
+};
+
+} // namespace
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 0c8752670..1db8e102f 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <algorithm>
+#include <boost/range/algorithm_ext/erase.hpp>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/hle/config_mem.h"
@@ -31,13 +32,61 @@ void WaitObject::RemoveWaitingThread(Thread* thread) {
waiting_threads.erase(itr);
}
-void WaitObject::WakeupAllWaitingThreads() {
- for (auto thread : waiting_threads)
- thread->ResumeFromWait();
+SharedPtr<Thread> WaitObject::GetHighestPriorityReadyThread() {
+ // Remove the threads that are ready or already running from our waitlist
+ boost::range::remove_erase_if(waiting_threads, [](const SharedPtr<Thread>& thread) {
+ return thread->status == THREADSTATUS_RUNNING || thread->status == THREADSTATUS_READY ||
+ thread->status == THREADSTATUS_DEAD;
+ });
+
+ // TODO(Subv): This call should be performed inside the loop below to check if an object can be
+ // acquired by a particular thread. This is useful for things like recursive locking of Mutexes.
+ if (ShouldWait())
+ return nullptr;
+
+ Thread* candidate = nullptr;
+ s32 candidate_priority = THREADPRIO_LOWEST + 1;
+
+ for (const auto& thread : waiting_threads) {
+ if (thread->current_priority >= candidate_priority)
+ continue;
- waiting_threads.clear();
+ bool ready_to_run =
+ std::none_of(thread->wait_objects.begin(), thread->wait_objects.end(),
+ [](const SharedPtr<WaitObject>& object) { return object->ShouldWait(); });
+ if (ready_to_run) {
+ candidate = thread.get();
+ candidate_priority = thread->current_priority;
+ }
+ }
+
+ return candidate;
+}
- HLE::Reschedule(__func__);
+void WaitObject::WakeupAllWaitingThreads() {
+ while (auto thread = GetHighestPriorityReadyThread()) {
+ if (!thread->IsSleepingOnWaitAll()) {
+ Acquire();
+ // Set the output index of the WaitSynchronizationN call to the index of this object.
+ if (thread->wait_set_output) {
+ thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(this));
+ thread->wait_set_output = false;
+ }
+ } else {
+ for (auto& object : thread->wait_objects) {
+ object->Acquire();
+ object->RemoveWaitingThread(thread.get());
+ }
+ // Note: This case doesn't update the output index of WaitSynchronizationN.
+ // Clear the thread's waitlist
+ thread->wait_objects.clear();
+ }
+
+ thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
+ thread->ResumeFromWait();
+ // Note: Removing the thread from the object's waitlist will be
+ // done by GetHighestPriorityReadyThread.
+ }
}
const std::vector<SharedPtr<Thread>>& WaitObject::GetWaitingThreads() const {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 231cf7b75..9503e7d04 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -11,11 +11,12 @@
#include <vector>
#include <boost/smart_ptr/intrusive_ptr.hpp>
#include "common/common_types.h"
-#include "core/hle/hle.h"
#include "core/hle/result.h"
namespace Kernel {
+using Handle = u32;
+
class Thread;
// TODO: Verify code
@@ -31,22 +32,21 @@ enum KernelHandle : Handle {
};
enum class HandleType : u32 {
- Unknown = 0,
-
- Session = 2,
- Event = 3,
- Mutex = 4,
- SharedMemory = 5,
- Redirection = 6,
- Thread = 7,
- Process = 8,
- AddressArbiter = 9,
- Semaphore = 10,
- Timer = 11,
- ResourceLimit = 12,
- CodeSet = 13,
- ClientPort = 14,
- ServerPort = 15,
+ Unknown,
+ Event,
+ Mutex,
+ SharedMemory,
+ Thread,
+ Process,
+ AddressArbiter,
+ Semaphore,
+ Timer,
+ ResourceLimit,
+ CodeSet,
+ ClientPort,
+ ServerPort,
+ ClientSession,
+ ServerSession,
};
enum {
@@ -82,23 +82,23 @@ public:
*/
bool IsWaitable() const {
switch (GetHandleType()) {
- case HandleType::Session:
- case HandleType::ServerPort:
case HandleType::Event:
case HandleType::Mutex:
case HandleType::Thread:
case HandleType::Semaphore:
case HandleType::Timer:
+ case HandleType::ServerPort:
+ case HandleType::ServerSession:
return true;
case HandleType::Unknown:
case HandleType::SharedMemory:
- case HandleType::Redirection:
case HandleType::Process:
case HandleType::AddressArbiter:
case HandleType::ResourceLimit:
case HandleType::CodeSet:
case HandleType::ClientPort:
+ case HandleType::ClientSession:
return false;
}
}
@@ -152,9 +152,15 @@ public:
*/
void RemoveWaitingThread(Thread* thread);
- /// Wake up all threads waiting on this object
+ /**
+ * Wake up all threads waiting on this object that can be awoken, in priority order,
+ * and set the synchronization result and output of the thread.
+ */
void WakeupAllWaitingThreads();
+ /// Obtains the highest priority thread that is ready to run from this object's waiting list.
+ SharedPtr<Thread> GetHighestPriorityReadyThread();
+
/// Get a const reference to the waiting threads list for debug use
const std::vector<SharedPtr<Thread>>& GetWaitingThreads() const;
diff --git a/src/core/hle/kernel/server_port.cpp b/src/core/hle/kernel/server_port.cpp
index 8e3ec8a14..6c19aa7c0 100644
--- a/src/core/hle/kernel/server_port.cpp
+++ b/src/core/hle/kernel/server_port.cpp
@@ -24,12 +24,14 @@ void ServerPort::Acquire() {
}
std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair(
- u32 max_sessions, std::string name) {
+ u32 max_sessions, std::string name,
+ std::shared_ptr<Service::SessionRequestHandler> hle_handler) {
SharedPtr<ServerPort> server_port(new ServerPort);
SharedPtr<ClientPort> client_port(new ClientPort);
server_port->name = name + "_Server";
+ server_port->hle_handler = std::move(hle_handler);
client_port->name = name + "_Client";
client_port->server_port = server_port;
client_port->max_sessions = max_sessions;
diff --git a/src/core/hle/kernel/server_port.h b/src/core/hle/kernel/server_port.h
index fa9448ca0..b0f8df62c 100644
--- a/src/core/hle/kernel/server_port.h
+++ b/src/core/hle/kernel/server_port.h
@@ -4,11 +4,16 @@
#pragma once
+#include <memory>
#include <string>
#include <tuple>
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
+namespace Service {
+class SessionRequestHandler;
+}
+
namespace Kernel {
class ClientPort;
@@ -19,10 +24,13 @@ public:
* Creates a pair of ServerPort and an associated ClientPort.
* @param max_sessions Maximum number of sessions to the port
* @param name Optional name of the ports
+ * @param hle_handler Optional HLE handler template for the port,
+ * ServerSessions crated from this port will inherit a reference to this handler.
* @return The created port tuple
*/
static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair(
- u32 max_sessions, std::string name = "UnknownPort");
+ u32 max_sessions, std::string name = "UnknownPort",
+ std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr);
std::string GetTypeName() const override {
return "ServerPort";
@@ -41,6 +49,10 @@ public:
std::vector<SharedPtr<WaitObject>>
pending_sessions; ///< ServerSessions waiting to be accepted by the port
+ /// This session's HLE request handler template (optional)
+ /// ServerSessions created from this port inherit a reference to this handler.
+ std::shared_ptr<Service::SessionRequestHandler> hle_handler;
+
bool ShouldWait() override;
void Acquire() override;
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
new file mode 100644
index 000000000..146458c1c
--- /dev/null
+++ b/src/core/hle/kernel/server_session.cpp
@@ -0,0 +1,79 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <tuple>
+
+#include "core/hle/kernel/client_session.h"
+#include "core/hle/kernel/server_session.h"
+#include "core/hle/kernel/thread.h"
+
+namespace Kernel {
+
+ServerSession::ServerSession() = default;
+ServerSession::~ServerSession() {
+ // This destructor will be called automatically when the last ServerSession handle is closed by
+ // the emulated application.
+ // TODO(Subv): Reduce the ClientPort's connection count,
+ // if the session is still open, set the connection status to 3 (Closed by server),
+}
+
+ResultVal<SharedPtr<ServerSession>> ServerSession::Create(
+ std::string name, std::shared_ptr<Service::SessionRequestHandler> hle_handler) {
+ SharedPtr<ServerSession> server_session(new ServerSession);
+
+ server_session->name = std::move(name);
+ server_session->signaled = false;
+ server_session->hle_handler = std::move(hle_handler);
+
+ return MakeResult<SharedPtr<ServerSession>>(std::move(server_session));
+}
+
+bool ServerSession::ShouldWait() {
+ return !signaled;
+}
+
+void ServerSession::Acquire() {
+ ASSERT_MSG(!ShouldWait(), "object unavailable!");
+ signaled = false;
+}
+
+ResultCode ServerSession::HandleSyncRequest() {
+ // The ServerSession received a sync request, this means that there's new data available
+ // from its ClientSession, so wake up any threads that may be waiting on a svcReplyAndReceive or
+ // similar.
+
+ // If this ServerSession has an associated HLE handler, forward the request to it.
+ if (hle_handler != nullptr) {
+ // Attempt to translate the incoming request's command buffer.
+ ResultCode result = TranslateHLERequest(this);
+ if (result.IsError())
+ return result;
+ hle_handler->HandleSyncRequest(SharedPtr<ServerSession>(this));
+ // TODO(Subv): Translate the response command buffer.
+ }
+
+ // If this ServerSession does not have an HLE implementation, just wake up the threads waiting
+ // on it.
+ signaled = true;
+ WakeupAllWaitingThreads();
+ return RESULT_SUCCESS;
+}
+
+ServerSession::SessionPair ServerSession::CreateSessionPair(
+ const std::string& name, std::shared_ptr<Service::SessionRequestHandler> hle_handler) {
+ auto server_session =
+ ServerSession::Create(name + "_Server", std::move(hle_handler)).MoveFrom();
+ // We keep a non-owning pointer to the ServerSession in the ClientSession because we don't want
+ // to prevent the ServerSession's destructor from being called when the emulated
+ // application closes the last ServerSession handle.
+ auto client_session = ClientSession::Create(server_session.get(), name + "_Client").MoveFrom();
+
+ return std::make_tuple(std::move(server_session), std::move(client_session));
+}
+
+ResultCode TranslateHLERequest(ServerSession* server_session) {
+ // TODO(Subv): Implement this function once multiple concurrent processes are supported.
+ return RESULT_SUCCESS;
+}
+}
diff --git a/src/core/hle/kernel/server_session.h b/src/core/hle/kernel/server_session.h
new file mode 100644
index 000000000..458284a5d
--- /dev/null
+++ b/src/core/hle/kernel/server_session.h
@@ -0,0 +1,94 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <string>
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/thread.h"
+#include "core/hle/result.h"
+#include "core/hle/service/service.h"
+#include "core/memory.h"
+
+namespace Kernel {
+
+class ClientSession;
+
+/**
+ * Kernel object representing the server endpoint of an IPC session. Sessions are the basic CTR-OS
+ * primitive for communication between different processes, and are used to implement service calls
+ * to the various system services.
+ *
+ * To make a service call, the client must write the command header and parameters to the buffer
+ * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest
+ * SVC call with its ClientSession handle. The kernel will read the command header, using it to
+ * marshall the parameters to the process at the server endpoint of the session.
+ * After the server replies to the request, the response is marshalled back to the caller's
+ * TLS buffer and control is transferred back to it.
+ */
+class ServerSession final : public WaitObject {
+public:
+ std::string GetTypeName() const override {
+ return "ServerSession";
+ }
+
+ static const HandleType HANDLE_TYPE = HandleType::ServerSession;
+ HandleType GetHandleType() const override {
+ return HANDLE_TYPE;
+ }
+
+ using SessionPair = std::tuple<SharedPtr<ServerSession>, SharedPtr<ClientSession>>;
+
+ /**
+ * Creates a pair of ServerSession and an associated ClientSession.
+ * @param name Optional name of the ports
+ * @return The created session tuple
+ */
+ static SessionPair CreateSessionPair(
+ const std::string& name = "Unknown",
+ std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr);
+
+ /**
+ * Handle a sync request from the emulated application.
+ * @returns ResultCode from the operation.
+ */
+ ResultCode HandleSyncRequest();
+
+ bool ShouldWait() override;
+
+ void Acquire() override;
+
+ std::string name; ///< The name of this session (optional)
+ bool signaled; ///< Whether there's new data available to this ServerSession
+ std::shared_ptr<Service::SessionRequestHandler>
+ hle_handler; ///< This session's HLE request handler (optional)
+
+private:
+ ServerSession();
+ ~ServerSession() override;
+
+ /**
+ * Creates a server session. The server session can have an optional HLE handler,
+ * which will be invoked to handle the IPC requests that this session receives.
+ * @param name Optional name of the server session.
+ * @param hle_handler Optional HLE handler for this server session.
+ * @return The created server session
+ */
+ static ResultVal<SharedPtr<ServerSession>> Create(
+ std::string name = "Unknown",
+ std::shared_ptr<Service::SessionRequestHandler> hle_handler = nullptr);
+};
+
+/**
+ * Performs command buffer translation for an HLE IPC request.
+ * The command buffer from the ServerSession thread's TLS is copied into a
+ * buffer and all descriptors in the buffer are processed.
+ * TODO(Subv): Implement this function, currently we do not support multiple processes running at
+ * once, but once that is implemented we'll need to properly translate all descriptors
+ * in the command buffer.
+ */
+ResultCode TranslateHLERequest(ServerSession* server_session);
+}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 84d6d24c6..5fb95dada 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -14,7 +14,6 @@
#include "core/arm/skyeye_common/armstate.h"
#include "core/core.h"
#include "core/core_timing.h"
-#include "core/hle/hle.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/mutex.h"
@@ -46,7 +45,7 @@ static std::vector<SharedPtr<Thread>> thread_list;
// Lists only ready thread ids.
static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST + 1> ready_queue;
-static Thread* current_thread;
+static SharedPtr<Thread> current_thread;
// The first available thread id at startup
static u32 next_thread_id;
@@ -63,7 +62,7 @@ Thread::Thread() {}
Thread::~Thread() {}
Thread* GetCurrentThread() {
- return current_thread;
+ return current_thread.get();
}
/**
@@ -120,8 +119,6 @@ void Thread::Stop() {
u32 tls_slot =
((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot);
-
- HLE::Reschedule(__func__);
}
Thread* ArbitrateHighestPriorityThread(u32 address) {
@@ -181,50 +178,6 @@ static void PriorityBoostStarvedThreads() {
}
/**
- * Gets the registers for timeout parameter of the next WaitSynchronization call.
- * @param thread a pointer to the thread that is ready to call WaitSynchronization
- * @returns a tuple of two register pointers to low and high part of the timeout parameter
- */
-static std::tuple<u32*, u32*> GetWaitSynchTimeoutParameterRegister(Thread* thread) {
- bool thumb_mode = (thread->context.cpsr & TBIT) != 0;
- u16 thumb_inst = Memory::Read16(thread->context.pc & 0xFFFFFFFE);
- u32 inst = Memory::Read32(thread->context.pc & 0xFFFFFFFC) & 0x0FFFFFFF;
-
- if ((thumb_mode && thumb_inst == 0xDF24) || (!thumb_mode && inst == 0x0F000024)) {
- // svc #0x24 (WaitSynchronization1)
- return std::make_tuple(&thread->context.cpu_registers[2],
- &thread->context.cpu_registers[3]);
- } else if ((thumb_mode && thumb_inst == 0xDF25) || (!thumb_mode && inst == 0x0F000025)) {
- // svc #0x25 (WaitSynchronizationN)
- return std::make_tuple(&thread->context.cpu_registers[0],
- &thread->context.cpu_registers[4]);
- }
-
- UNREACHABLE();
-}
-
-/**
- * Updates the WaitSynchronization timeout parameter according to the difference
- * between ticks of the last WaitSynchronization call and the incoming one.
- * @param timeout_low a pointer to the register for the low part of the timeout parameter
- * @param timeout_high a pointer to the register for the high part of the timeout parameter
- * @param last_tick tick of the last WaitSynchronization call
- */
-static void UpdateTimeoutParameter(u32* timeout_low, u32* timeout_high, u64 last_tick) {
- s64 timeout = ((s64)*timeout_high << 32) | *timeout_low;
-
- if (timeout != -1) {
- timeout -= cyclesToUs(CoreTiming::GetTicks() - last_tick) * 1000; // in nanoseconds
-
- if (timeout < 0)
- timeout = 0;
-
- *timeout_low = timeout & 0xFFFFFFFF;
- *timeout_high = timeout >> 32;
- }
-}
-
-/**
* Switches the CPU's active thread context to that of the specified thread
* @param new_thread The thread to switch to
*/
@@ -234,7 +187,7 @@ static void SwitchContext(Thread* new_thread) {
// Save context for previous thread
if (previous_thread) {
previous_thread->last_running_ticks = CoreTiming::GetTicks();
- Core::g_app_core->SaveContext(previous_thread->context);
+ Core::CPU().SaveContext(previous_thread->context);
if (previous_thread->status == THREADSTATUS_RUNNING) {
// This is only the case when a reschedule is triggered without the current thread
@@ -254,40 +207,14 @@ static void SwitchContext(Thread* new_thread) {
current_thread = new_thread;
- // If the thread was waited by a svcWaitSynch call, step back PC by one instruction to rerun
- // the SVC when the thread wakes up. This is necessary to ensure that the thread can acquire
- // the requested wait object(s) before continuing.
- if (new_thread->waitsynch_waited) {
- // CPSR flag indicates CPU mode
- bool thumb_mode = (new_thread->context.cpsr & TBIT) != 0;
-
- // SVC instruction is 2 bytes for THUMB, 4 bytes for ARM
- new_thread->context.pc -= thumb_mode ? 2 : 4;
-
- // Get the register for timeout parameter
- u32 *timeout_low, *timeout_high;
- std::tie(timeout_low, timeout_high) = GetWaitSynchTimeoutParameterRegister(new_thread);
-
- // Update the timeout parameter
- UpdateTimeoutParameter(timeout_low, timeout_high, new_thread->last_running_ticks);
- }
-
- // Clean up the thread's wait_objects, they'll be restored if needed during
- // the svcWaitSynchronization call
- for (size_t i = 0; i < new_thread->wait_objects.size(); ++i) {
- SharedPtr<WaitObject> object = new_thread->wait_objects[i];
- object->RemoveWaitingThread(new_thread);
- }
- new_thread->wait_objects.clear();
-
ready_queue.remove(new_thread->current_priority, new_thread);
new_thread->status = THREADSTATUS_RUNNING;
// Restores thread to its nominal priority if it has been temporarily changed
new_thread->current_priority = new_thread->nominal_priority;
- Core::g_app_core->LoadContext(new_thread->context);
- Core::g_app_core->SetCP15Register(CP15_THREAD_URO, new_thread->GetTLSAddress());
+ Core::CPU().LoadContext(new_thread->context);
+ Core::CPU().SetCP15Register(CP15_THREAD_URO, new_thread->GetTLSAddress());
} else {
current_thread = nullptr;
}
@@ -319,17 +246,13 @@ static Thread* PopNextReadyThread() {
void WaitCurrentThread_Sleep() {
Thread* thread = GetCurrentThread();
thread->status = THREADSTATUS_WAIT_SLEEP;
-
- HLE::Reschedule(__func__);
}
void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects,
- bool wait_set_output, bool wait_all) {
+ bool wait_set_output) {
Thread* thread = GetCurrentThread();
thread->wait_set_output = wait_set_output;
- thread->wait_all = wait_all;
thread->wait_objects = std::move(wait_objects);
- thread->waitsynch_waited = true;
thread->status = THREADSTATUS_WAIT_SYNCH;
}
@@ -339,6 +262,13 @@ void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) {
thread->status = THREADSTATUS_WAIT_ARB;
}
+void ExitCurrentThread() {
+ Thread* thread = GetCurrentThread();
+ thread->Stop();
+ thread_list.erase(std::remove(thread_list.begin(), thread_list.end(), thread),
+ thread_list.end());
+}
+
/**
* Callback that will wake up the thread it was scheduled for
* @param thread_handle The handle of the thread that's been awoken
@@ -351,15 +281,15 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
return;
}
- thread->waitsynch_waited = false;
-
if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) {
+ thread->wait_set_output = false;
+ // Remove the thread from each of its waiting objects' waitlists
+ for (auto& object : thread->wait_objects)
+ object->RemoveWaitingThread(thread.get());
+ thread->wait_objects.clear();
thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
ErrorSummary::StatusChanged,
ErrorLevel::Info));
-
- if (thread->wait_set_output)
- thread->SetWaitSynchronizationOutput(-1);
}
thread->ResumeFromWait();
@@ -399,6 +329,7 @@ void Thread::ResumeFromWait() {
ready_queue.push_back(current_priority, this);
status = THREADSTATUS_READY;
+ Core::System::GetInstance().PrepareReschedule();
}
/**
@@ -453,9 +384,9 @@ std::tuple<u32, u32, bool> GetFreeThreadLocalSlot(std::vector<std::bitset<8>>& t
* @param entry_point Address of entry point for execution
* @param arg User argument for thread
*/
-static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point,
- u32 arg) {
- memset(&context, 0, sizeof(Core::ThreadContext));
+static void ResetThreadContext(ARM_Interface::ThreadContext& context, u32 stack_top,
+ u32 entry_point, u32 arg) {
+ memset(&context, 0, sizeof(ARM_Interface::ThreadContext));
context.cpu_registers[0] = arg;
context.pc = entry_point;
@@ -494,13 +425,11 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
thread->last_running_ticks = CoreTiming::GetTicks();
thread->processor_id = processor_id;
thread->wait_set_output = false;
- thread->wait_all = false;
thread->wait_objects.clear();
thread->wait_address = 0;
thread->name = std::move(name);
thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom();
thread->owner_process = g_current_process;
- thread->waitsynch_waited = false;
// Find the next available TLS index, and mark it as used
auto& tls_slots = Kernel::g_current_process->tls_slots;
@@ -555,8 +484,6 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
ready_queue.push_back(thread->current_priority, thread.get());
thread->status = THREADSTATUS_READY;
- HLE::Reschedule(__func__);
-
return MakeResult<SharedPtr<Thread>>(std::move(thread));
}
@@ -617,16 +544,6 @@ void Reschedule() {
Thread* cur = GetCurrentThread();
Thread* next = PopNextReadyThread();
- HLE::DoneRescheduling();
-
- // Don't bother switching to the same thread.
- // But if the thread was waiting on objects, we still need to switch it
- // to perform PC modification, change state to RUNNING, etc.
- // This occurs in the case when an object the thread is waiting on immediately wakes up
- // the current thread before Reschedule() is called.
- if (next == cur && (next == nullptr || next->waitsynch_waited == false))
- return;
-
if (cur && next) {
LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId());
} else if (cur) {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index e0ffcea8a..c77ac644d 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -5,11 +5,13 @@
#pragma once
#include <string>
+#include <unordered_map>
#include <vector>
+#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>
#include "common/common_types.h"
+#include "core/arm/arm_interface.h"
#include "core/core.h"
-#include "core/hle/hle.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/result.h"
@@ -125,6 +127,16 @@ public:
void SetWaitSynchronizationOutput(s32 output);
/**
+ * Retrieves the index that this particular object occupies in the list of objects
+ * that the thread passed to WaitSynchronizationN.
+ * It is used to set the output value of WaitSynchronizationN when the thread is awakened.
+ * @param object Object to query the index of.
+ */
+ s32 GetWaitObjectIndex(const WaitObject* object) const {
+ return wait_objects_index.at(object->GetObjectId());
+ }
+
+ /**
* Stops a thread, invalidating it from further use
*/
void Stop();
@@ -137,7 +149,16 @@ public:
return tls_address;
}
- Core::ThreadContext context;
+ /**
+ * Returns whether this thread is waiting for all the objects in
+ * its wait list to become ready, as a result of a WaitSynchronizationN call
+ * with wait_all = true, or a ReplyAndReceive call.
+ */
+ bool IsSleepingOnWaitAll() const {
+ return !wait_objects.empty();
+ }
+
+ ARM_Interface::ThreadContext context;
u32 thread_id;
@@ -154,16 +175,22 @@ public:
VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread
- bool waitsynch_waited; ///< Set to true if the last svcWaitSynch call caused the thread to wait
-
/// Mutexes currently held by this thread, which will be released when it exits.
boost::container::flat_set<SharedPtr<Mutex>> held_mutexes;
- SharedPtr<Process> owner_process; ///< Process that owns this thread
- std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on
- VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
- bool wait_all; ///< True if the thread is waiting on all objects before resuming
- bool wait_set_output; ///< True if the output parameter should be set on thread wakeup
+ SharedPtr<Process> owner_process; ///< Process that owns this thread
+
+ /// Objects that the thread is waiting on.
+ /// This is only populated when the thread should wait for all the objects to become ready.
+ std::vector<SharedPtr<WaitObject>> wait_objects;
+
+ /// Mapping of Object ids to their position in the last waitlist that this object waited on.
+ boost::container::flat_map<int, s32> wait_objects_index;
+
+ VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
+
+ /// True if the WaitSynchronizationN output parameter should be set on thread wakeup.
+ bool wait_set_output;
std::string name;
@@ -215,10 +242,9 @@ void WaitCurrentThread_Sleep();
* @param wait_objects Kernel objects that we are waiting on
* @param wait_set_output If true, set the output parameter on thread wakeup (for
* WaitSynchronizationN only)
- * @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only)
*/
void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects,
- bool wait_set_output, bool wait_all);
+ bool wait_set_output);
/**
* Waits the current thread from an ArbitrateAddress call
@@ -227,6 +253,11 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa
void WaitCurrentThread_ArbitrateAddress(VAddr wait_address);
/**
+ * Stops the current thread and removes it from the thread_list
+ */
+void ExitCurrentThread();
+
+/**
* Initialize threading
*/
void ThreadingInit();
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index eac181f4e..b50cf520d 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -60,14 +60,10 @@ void Timer::Set(s64 initial, s64 interval) {
u64 initial_microseconds = initial / 1000;
CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type,
callback_handle);
-
- HLE::Reschedule(__func__);
}
void Timer::Cancel() {
CoreTiming::UnscheduleEvent(timer_callback_event_type, callback_handle);
-
- HLE::Reschedule(__func__);
}
void Timer::Clear() {
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 8d29117a8..53864a3a7 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -18,6 +18,7 @@ enum class ErrorDescription : u32 {
Success = 0,
WrongPermission = 46,
OS_InvalidBufferDescriptor = 48,
+ MaxConnectionsReached = 52,
WrongAddress = 53,
FS_ArchiveNotMounted = 101,
FS_FileNotFound = 112,
diff --git a/src/core/hle/service/ac_u.cpp b/src/core/hle/service/ac_u.cpp
index fe367aca5..36204db4d 100644
--- a/src/core/hle/service/ac_u.cpp
+++ b/src/core/hle/service/ac_u.cpp
@@ -2,14 +2,14 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <array>
+
#include "common/logging/log.h"
#include "core/hle/kernel/event.h"
#include "core/hle/service/ac_u.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace AC_U
-
-namespace AC_U {
+namespace Service {
+namespace AC {
struct ACConfig {
std::array<u8, 0x200> data;
@@ -31,7 +31,7 @@ static Kernel::SharedPtr<Kernel::Event> disconnect_event;
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void CreateDefaultConfig(Service::Interface* self) {
+static void CreateDefaultConfig(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 ac_config_addr = cmd_buff[65];
@@ -56,7 +56,7 @@ static void CreateDefaultConfig(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void ConnectAsync(Service::Interface* self) {
+static void ConnectAsync(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
connect_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]);
@@ -77,7 +77,7 @@ static void ConnectAsync(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void GetConnectResult(Service::Interface* self) {
+static void GetConnectResult(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -94,7 +94,7 @@ static void GetConnectResult(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void CloseAsync(Service::Interface* self) {
+static void CloseAsync(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
if (ac_connected && disconnect_event) {
@@ -120,7 +120,7 @@ static void CloseAsync(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void GetCloseResult(Service::Interface* self) {
+static void GetCloseResult(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -134,7 +134,7 @@ static void GetCloseResult(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Output connection type, 0 = none, 1 = Old3DS Internet, 2 = New3DS Internet.
*/
-static void GetWifiStatus(Service::Interface* self) {
+static void GetWifiStatus(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
// TODO(purpasmart96): This function is only a stub,
@@ -155,7 +155,7 @@ static void GetWifiStatus(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Infra Priority
*/
-static void GetInfraPriority(Service::Interface* self) {
+static void GetInfraPriority(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -177,7 +177,7 @@ static void GetInfraPriority(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Infra Priority
*/
-static void SetRequestEulaVersion(Service::Interface* self) {
+static void SetRequestEulaVersion(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 major = cmd_buff[1] & 0xFF;
@@ -203,7 +203,7 @@ static void SetRequestEulaVersion(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void RegisterDisconnectEvent(Service::Interface* self) {
+static void RegisterDisconnectEvent(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
disconnect_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]);
@@ -221,7 +221,7 @@ static void RegisterDisconnectEvent(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : bool, is connected
*/
-static void IsConnected(Service::Interface* self) {
+static void IsConnected(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -237,7 +237,7 @@ static void IsConnected(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetClientVersion(Service::Interface* self) {
+static void SetClientVersion(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
const u32 version = cmd_buff[1];
@@ -271,10 +271,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00400042, SetClientVersion, "SetClientVersion"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+AC_U::AC_U() {
Register(FunctionTable);
ac_connected = false;
@@ -284,10 +281,11 @@ Interface::Interface() {
disconnect_event = nullptr;
}
-Interface::~Interface() {
+AC_U::~AC_U() {
close_event = nullptr;
connect_event = nullptr;
disconnect_event = nullptr;
}
-} // namespace
+} // namespace AC
+} // namespace Service
diff --git a/src/core/hle/service/ac_u.h b/src/core/hle/service/ac_u.h
index 6592b21c9..573c32d7e 100644
--- a/src/core/hle/service/ac_u.h
+++ b/src/core/hle/service/ac_u.h
@@ -6,21 +6,18 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace AC_U
+namespace Service {
+namespace AC {
-// socket service "ac:u"
-
-namespace AC_U {
-
-class Interface : public Service::Interface {
+class AC_U final : public Interface {
public:
- Interface();
- ~Interface();
+ AC_U();
+ ~AC_U();
std::string GetPortName() const override {
return "ac:u";
}
};
-} // namespace
+} // namespace AC
+} // namespace Service
diff --git a/src/core/hle/service/act/act.cpp b/src/core/hle/service/act/act.cpp
new file mode 100644
index 000000000..9600036c0
--- /dev/null
+++ b/src/core/hle/service/act/act.cpp
@@ -0,0 +1,18 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/act/act.h"
+#include "core/hle/service/act/act_a.h"
+#include "core/hle/service/act/act_u.h"
+
+namespace Service {
+namespace ACT {
+
+void Init() {
+ AddService(new ACT_A);
+ AddService(new ACT_U);
+}
+
+} // namespace ACT
+} // namespace Service
diff --git a/src/core/hle/service/act/act.h b/src/core/hle/service/act/act.h
new file mode 100644
index 000000000..1425291aa
--- /dev/null
+++ b/src/core/hle/service/act/act.h
@@ -0,0 +1,14 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service {
+namespace ACT {
+
+/// Initializes all ACT services
+void Init();
+
+} // namespace ACT
+} // namespace Service
diff --git a/src/core/hle/service/act/act_a.cpp b/src/core/hle/service/act/act_a.cpp
new file mode 100644
index 000000000..5c523368f
--- /dev/null
+++ b/src/core/hle/service/act/act_a.cpp
@@ -0,0 +1,30 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/act/act.h"
+#include "core/hle/service/act/act_a.h"
+
+namespace Service {
+namespace ACT {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // act:u shared commands
+ {0x00010084, nullptr, "Initialize"},
+ {0x00020040, nullptr, "GetErrorCode"},
+ {0x000600C2, nullptr, "GetAccountDataBlock"},
+ {0x000B0042, nullptr, "AcquireEulaList"},
+ {0x000D0040, nullptr, "GenerateUuid"},
+ // act:a
+ {0x041300C2, nullptr, "UpdateMiiImage"},
+ {0x041B0142, nullptr, "AgreeEula"},
+ {0x04210042, nullptr, "UploadMii"},
+ {0x04230082, nullptr, "ValidateMailAddress"},
+};
+
+ACT_A::ACT_A() {
+ Register(FunctionTable);
+}
+
+} // namespace ACT
+} // namespace Service
diff --git a/src/core/hle/service/act_a.h b/src/core/hle/service/act/act_a.h
index 765cae644..e3adb03e5 100644
--- a/src/core/hle/service/act_a.h
+++ b/src/core/hle/service/act/act_a.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace ACT_A
+namespace Service {
+namespace ACT {
-namespace ACT_A {
-
-class Interface : public Service::Interface {
+class ACT_A final : public Service::Interface {
public:
- Interface();
+ ACT_A();
std::string GetPortName() const override {
return "act:a";
}
};
-} // namespace
+} // namespace ACT
+} // namespace Service
diff --git a/src/core/hle/service/act_u.cpp b/src/core/hle/service/act/act_u.cpp
index 05de4d002..cf98aa1d6 100644
--- a/src/core/hle/service/act_u.cpp
+++ b/src/core/hle/service/act/act_u.cpp
@@ -2,25 +2,25 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "core/hle/service/act_u.h"
+#include "core/hle/service/act/act.h"
+#include "core/hle/service/act/act_u.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace ACT_U
-
-namespace ACT_U {
+namespace Service {
+namespace ACT {
const Interface::FunctionInfo FunctionTable[] = {
+ // clang-format off
{0x00010084, nullptr, "Initialize"},
{0x00020040, nullptr, "GetErrorCode"},
{0x000600C2, nullptr, "GetAccountDataBlock"},
+ {0x000B0042, nullptr, "AcquireEulaList"},
{0x000D0040, nullptr, "GenerateUuid"},
+ // clang-format on
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+ACT_U::ACT_U() {
Register(FunctionTable);
}
-} // namespace
+} // namespace ACT
+} // namespace Service
diff --git a/src/core/hle/service/act_u.h b/src/core/hle/service/act/act_u.h
index be41454a4..9d8538fbf 100644
--- a/src/core/hle/service/act_u.h
+++ b/src/core/hle/service/act/act_u.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace ACT_U
+namespace Service {
+namespace ACT {
-namespace ACT_U {
-
-class Interface : public Service::Interface {
+class ACT_U final : public Interface {
public:
- Interface();
+ ACT_U();
std::string GetPortName() const override {
return "act:u";
}
};
-} // namespace
+} // namespace ACT
+} // namespace Service
diff --git a/src/core/hle/service/act_a.cpp b/src/core/hle/service/act_a.cpp
deleted file mode 100644
index 3a775fa90..000000000
--- a/src/core/hle/service/act_a.cpp
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2016 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/service/act_a.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace ACT_A
-
-namespace ACT_A {
-
-const Interface::FunctionInfo FunctionTable[] = {
- {0x041300C2, nullptr, "UpdateMiiImage"},
- {0x041B0142, nullptr, "AgreeEula"},
- {0x04210042, nullptr, "UploadMii"},
- {0x04230082, nullptr, "ValidateMailAddress"},
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- Register(FunctionTable);
-}
-
-} // namespace
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index f7a990d69..d344a622f 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -20,7 +20,7 @@ static std::array<u32, 3> am_titles_list_count = {0, 0, 0};
static u32 am_ticket_count = 0;
static u32 am_ticket_list_count = 0;
-void GetTitleCount(Service::Interface* self) {
+void GetNumPrograms(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 media_type = cmd_buff[1] & 0xFF;
@@ -81,7 +81,7 @@ void DeleteContents(Service::Interface* self) {
media_type, title_id, am_content_count[media_type], content_ids_pointer);
}
-void GetTitleList(Service::Interface* self) {
+void GetProgramList(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 media_type = cmd_buff[2] & 0xFF;
@@ -97,7 +97,7 @@ void GetTitleList(Service::Interface* self) {
media_type, am_titles_list_count[media_type], title_ids_output_pointer);
}
-void GetTitleInfo(Service::Interface* self) {
+void GetProgramInfos(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 media_type = cmd_buff[1] & 0xFF;
@@ -113,7 +113,7 @@ void GetTitleInfo(Service::Interface* self) {
}
void GetDataTitleInfos(Service::Interface* self) {
- GetTitleInfo(self);
+ GetProgramInfos(self);
LOG_WARNING(Service_AM, "(STUBBED) called");
}
@@ -151,7 +151,7 @@ void DeleteTicket(Service::Interface* self) {
LOG_WARNING(Service_AM, "(STUBBED) called title_id=0x%016" PRIx64 "", title_id);
}
-void GetTicketCount(Service::Interface* self) {
+void GetNumTickets(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw;
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 5676cdd5f..9bc2ca305 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -11,7 +11,7 @@ class Interface;
namespace AM {
/**
- * AM::GetTitleCount service function
+ * AM::GetNumPrograms service function
* Gets the number of installed titles in the requested media type
* Inputs:
* 0 : Command header (0x00010040)
@@ -20,7 +20,7 @@ namespace AM {
* 1 : Result, 0 on success, otherwise error code
* 2 : The number of titles in the requested media type
*/
-void GetTitleCount(Service::Interface* self);
+void GetNumPrograms(Service::Interface* self);
/**
* AM::FindContentInfos service function
@@ -62,7 +62,7 @@ void ListContentInfos(Service::Interface* self);
void DeleteContents(Service::Interface* self);
/**
- * AM::GetTitleList service function
+ * AM::GetProgramList service function
* Loads information about the desired number of titles from the desired media type into an array
* Inputs:
* 1 : Title count
@@ -72,10 +72,10 @@ void DeleteContents(Service::Interface* self);
* 1 : Result, 0 on success, otherwise error code
* 2 : The number of titles loaded from the requested media type
*/
-void GetTitleList(Service::Interface* self);
+void GetProgramList(Service::Interface* self);
/**
- * AM::GetTitleInfo service function
+ * AM::GetProgramInfos service function
* Inputs:
* 1 : u8 Mediatype
* 2 : Total titles
@@ -84,11 +84,11 @@ void GetTitleList(Service::Interface* self);
* Outputs:
* 1 : Result, 0 on success, otherwise error code
*/
-void GetTitleInfo(Service::Interface* self);
+void GetProgramInfos(Service::Interface* self);
/**
* AM::GetDataTitleInfos service function
- * Wrapper for AM::GetTitleInfo
+ * Wrapper for AM::GetProgramInfos
* Inputs:
* 1 : u8 Mediatype
* 2 : Total titles
@@ -135,12 +135,12 @@ void GetNumContentInfos(Service::Interface* self);
void DeleteTicket(Service::Interface* self);
/**
- * AM::GetTicketCount service function
+ * AM::GetNumTickets service function
* Outputs:
* 1 : Result, 0 on success, otherwise error code
- * 2 : Total titles
+ * 2 : Number of tickets
*/
-void GetTicketCount(Service::Interface* self);
+void GetNumTickets(Service::Interface* self);
/**
* AM::GetTicketList service function
diff --git a/src/core/hle/service/am/am_app.cpp b/src/core/hle/service/am/am_app.cpp
index bfc1ca6bd..218375c8f 100644
--- a/src/core/hle/service/am/am_app.cpp
+++ b/src/core/hle/service/am/am_app.cpp
@@ -14,9 +14,14 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x10030142, ListContentInfos, "ListContentInfos"},
{0x10040102, DeleteContents, "DeleteContents"},
{0x10050084, GetDataTitleInfos, "GetDataTitleInfos"},
+ {0x10060080, nullptr, "GetNumDataTitleTickets"},
{0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"},
+ {0x100801C2, nullptr, "GetItemRights"},
{0x100900C0, nullptr, "IsDataTitleInUse"},
{0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"},
+ {0x100B00C0, nullptr, "GetNumExistingContentInfos"},
+ {0x100C0142, nullptr, "ListExistingContentInfos"},
+ {0x100D0084, nullptr, "GetPatchTitleInfos"},
};
AM_APP_Interface::AM_APP_Interface() {
diff --git a/src/core/hle/service/am/am_net.cpp b/src/core/hle/service/am/am_net.cpp
index 3a597a34c..f3cd1d23f 100644
--- a/src/core/hle/service/am/am_net.cpp
+++ b/src/core/hle/service/am/am_net.cpp
@@ -9,61 +9,116 @@ namespace Service {
namespace AM {
const Interface::FunctionInfo FunctionTable[] = {
- {0x00010040, GetTitleCount, "GetTitleCount"},
- {0x00020082, GetTitleList, "GetTitleList"},
- {0x00030084, GetTitleInfo, "GetTitleInfo"},
- {0x000400C0, nullptr, "DeleteApplicationTitle"},
- {0x000500C0, nullptr, "GetTitleProductCode"},
- {0x000600C0, nullptr, "GetTitleExtDataId"},
+ {0x00010040, GetNumPrograms, "GetNumPrograms"},
+ {0x00020082, GetProgramList, "GetProgramList"},
+ {0x00030084, GetProgramInfos, "GetProgramInfos"},
+ {0x000400C0, nullptr, "DeleteUserProgram"},
+ {0x000500C0, nullptr, "GetProductCode"},
+ {0x000600C0, nullptr, "GetStorageId"},
{0x00070080, DeleteTicket, "DeleteTicket"},
- {0x00080000, GetTicketCount, "GetTicketCount"},
+ {0x00080000, GetNumTickets, "GetNumTickets"},
{0x00090082, GetTicketList, "GetTicketList"},
{0x000A0000, nullptr, "GetDeviceID"},
- {0x000D0084, nullptr, "GetPendingTitleInfo"},
- {0x000E00C0, nullptr, "DeletePendingTitle"},
- {0x00140040, nullptr, "FinalizePendingTitles"},
- {0x00150040, nullptr, "DeleteAllPendingTitles"},
+ {0x000B0040, nullptr, "GetNumImportTitleContexts"},
+ {0x000C0082, nullptr, "GetImportTitleContextList"},
+ {0x000D0084, nullptr, "GetImportTitleContexts"},
+ {0x000E00C0, nullptr, "DeleteImportTitleContext"},
+ {0x000F00C0, nullptr, "GetNumImportContentContexts"},
+ {0x00100102, nullptr, "GetImportContentContextList"},
+ {0x00110104, nullptr, "GetImportContentContexts"},
+ {0x00120102, nullptr, "DeleteImportContentContexts"},
+ {0x00130040, nullptr, "NeedsCleanup"},
+ {0x00140040, nullptr, "DoCleanup"},
+ {0x00150040, nullptr, "DeleteAllImportContexts"},
+ {0x00160000, nullptr, "DeleteAllTemporaryPrograms"},
+ {0x00170044, nullptr, "ImportTwlBackupLegacy"},
{0x00180080, nullptr, "InitializeTitleDatabase"},
- {0x00190040, nullptr, "ReloadDBS"},
- {0x001A00C0, nullptr, "GetDSiWareExportSize"},
- {0x001B0144, nullptr, "ExportDSiWare"},
- {0x001C0084, nullptr, "ImportDSiWare"},
- {0x00230080, nullptr, "TitleIDListGetTotal2"},
- {0x002400C2, nullptr, "GetTitleIDList2"},
- {0x04010080, nullptr, "InstallFIRM"},
- {0x04020040, nullptr, "StartInstallCIADB0"},
- {0x04030000, nullptr, "StartInstallCIADB1"},
- {0x04040002, nullptr, "AbortCIAInstall"},
- {0x04050002, nullptr, "CloseCIAFinalizeInstall"},
- {0x04060002, nullptr, "CloseCIA"},
- {0x040700C2, nullptr, "FinalizeTitlesInstall"},
- {0x04080042, nullptr, "GetCiaFileInfo"},
- {0x040E00C2, nullptr, "InstallTitlesFinish"},
- {0x040F0000, nullptr, "InstallNATIVEFIRM"},
- {0x041000C0, nullptr, "DeleteTitle"},
- {0x04120000, nullptr, "Initialize"},
- {0x041700C0, nullptr, "MigrateAGBtoSAV"},
- {0x08010000, nullptr, "OpenTicket"},
- {0x08020002, nullptr, "TicketAbortInstall"},
- {0x08030002, nullptr, "TicketFinalizeInstall"},
- {0x08040100, nullptr, "InstallTitleBegin"},
- {0x08050000, nullptr, "InstallTitleAbort"},
- {0x080600C0, nullptr, "InstallTitleResume"},
- {0x08070000, nullptr, "InstallTitleAbortTMD"},
- {0x08080000, nullptr, "InstallTitleFinish"},
- {0x080A0000, nullptr, "OpenTMD"},
- {0x080B0002, nullptr, "TMDAbortInstall"},
- {0x080C0042, nullptr, "TMDFinalizeInstall"},
- {0x080E0040, nullptr, "OpenContentCreate"},
- {0x080F0002, nullptr, "ContentAbortInstall"},
- {0x08100040, nullptr, "OpenContentResume"},
- {0x08120002, nullptr, "ContentFinalizeInstall"},
- {0x08130000, nullptr, "GetTotalContents"},
- {0x08140042, nullptr, "GetContentIndexes"},
- {0x08150044, nullptr, "GetContentsInfo"},
- {0x08180042, nullptr, "GetCTCert"},
- {0x08190108, nullptr, "SetCertificates"},
- {0x081B00C2, nullptr, "InstallTitlesFinish"},
+ {0x00190040, nullptr, "QueryAvailableTitleDatabase"},
+ {0x001A00C0, nullptr, "CalcTwlBackupSize"},
+ {0x001B0144, nullptr, "ExportTwlBackup"},
+ {0x001C0084, nullptr, "ImportTwlBackup"},
+ {0x001D0000, nullptr, "DeleteAllTwlUserPrograms"},
+ {0x001E00C8, nullptr, "ReadTwlBackupInfo"},
+ {0x001F0040, nullptr, "DeleteAllExpiredUserPrograms"},
+ {0x00200000, nullptr, "GetTwlArchiveResourceInfo"},
+ {0x00210042, nullptr, "GetPersonalizedTicketInfoList"},
+ {0x00220080, nullptr, "DeleteAllImportContextsFiltered"},
+ {0x00230080, nullptr, "GetNumImportTitleContextsFiltered"},
+ {0x002400C2, nullptr, "GetImportTitleContextListFiltered"},
+ {0x002500C0, nullptr, "CheckContentRights"},
+ {0x00260044, nullptr, "GetTicketLimitInfos"},
+ {0x00270044, nullptr, "GetDemoLaunchInfos"},
+ {0x00280108, nullptr, "ReadTwlBackupInfoEx"},
+ {0x00290082, nullptr, "DeleteUserProgramsAtomically"},
+ {0x002A00C0, nullptr, "GetNumExistingContentInfosSystem"},
+ {0x002B0142, nullptr, "ListExistingContentInfosSystem"},
+ {0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"},
+ {0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"},
+ {0x04010080, nullptr, "UpdateFirmwareTo"},
+ {0x04020040, nullptr, "BeginImportProgram"},
+ {0x04030000, nullptr, "BeginImportProgramTemporarily"},
+ {0x04040002, nullptr, "CancelImportProgram"},
+ {0x04050002, nullptr, "EndImportProgram"},
+ {0x04060002, nullptr, "EndImportProgramWithoutCommit"},
+ {0x040700C2, nullptr, "CommitImportPrograms"},
+ {0x04080042, nullptr, "GetProgramInfoFromCia"},
+ {0x04090004, nullptr, "GetSystemMenuDataFromCia"},
+ {0x040A0002, nullptr, "GetDependencyListFromCia"},
+ {0x040B0002, nullptr, "GetTransferSizeFromCia"},
+ {0x040C0002, nullptr, "GetCoreVersionFromCia"},
+ {0x040D0042, nullptr, "GetRequiredSizeFromCia"},
+ {0x040E00C2, nullptr, "CommitImportProgramsAndUpdateFirmwareAuto"},
+ {0x040F0000, nullptr, "UpdateFirmwareAuto"},
+ {0x041000C0, nullptr, "DeleteProgram"},
+ {0x04110044, nullptr, "GetTwlProgramListForReboot"},
+ {0x04120000, nullptr, "GetSystemUpdaterMutex"},
+ {0x04130002, nullptr, "GetMetaSizeFromCia"},
+ {0x04140044, nullptr, "GetMetaDataFromCia"},
+ {0x04150080, nullptr, "CheckDemoLaunchRights"},
+ {0x041600C0, nullptr, "GetInternalTitleLocationInfo"},
+ {0x041700C0, nullptr, "PerpetuateAgbSaveData"},
+ {0x04180040, nullptr, "BeginImportProgramForOverWrite"},
+ {0x04190000, nullptr, "BeginImportSystemProgram"},
+ {0x08010000, nullptr, "BeginImportTicket"},
+ {0x08020002, nullptr, "CancelImportTicket"},
+ {0x08030002, nullptr, "EndImportTicket"},
+ {0x08040100, nullptr, "BeginImportTitle"},
+ {0x08050000, nullptr, "StopImportTitle"},
+ {0x080600C0, nullptr, "ResumeImportTitle"},
+ {0x08070000, nullptr, "CancelImportTitle"},
+ {0x08080000, nullptr, "EndImportTitle"},
+ {0x080900C2, nullptr, "CommitImportTitles"},
+ {0x080A0000, nullptr, "BeginImportTmd"},
+ {0x080B0002, nullptr, "CancelImportTmd"},
+ {0x080C0042, nullptr, "EndImportTmd"},
+ {0x080D0042, nullptr, "CreateImportContentContexts"},
+ {0x080E0040, nullptr, "BeginImportContent"},
+ {0x080F0002, nullptr, "StopImportContent"},
+ {0x08100040, nullptr, "ResumeImportContent"},
+ {0x08110002, nullptr, "CancelImportContent"},
+ {0x08120002, nullptr, "EndImportContent"},
+ {0x08130000, nullptr, "GetNumCurrentImportContentContexts"},
+ {0x08140042, nullptr, "GetCurrentImportContentContextList"},
+ {0x08150044, nullptr, "GetCurrentImportContentContexts"},
+ {0x08160146, nullptr, "Sign"},
+ {0x08170146, nullptr, "Verify"},
+ {0x08180042, nullptr, "GetDeviceCert"},
+ {0x08190108, nullptr, "ImportCertificates"},
+ {0x081A0042, nullptr, "ImportCertificate"},
+ {0x081B00C2, nullptr, "CommitImportTitlesAndUpdateFirmwareAuto"},
+ {0x081C0100, nullptr, "DeleteTicketId"},
+ {0x081D0080, nullptr, "GetNumTicketIds"},
+ {0x081E0102, nullptr, "GetTicketIdList"},
+ {0x081F0080, nullptr, "GetNumTicketsOfProgram"},
+ {0x08200102, nullptr, "ListTicketInfos"},
+ {0x08210142, nullptr, "GetRightsOnlyTicketData"},
+ {0x08220000, nullptr, "GetNumCurrentContentInfos"},
+ {0x08230044, nullptr, "FindCurrentContentInfos"},
+ {0x08240082, nullptr, "ListCurrentContentInfos"},
+ {0x08250102, nullptr, "CalculateContextRequiredSize"},
+ {0x08260042, nullptr, "UpdateImportContentContexts"},
+ {0x08270000, nullptr, "DeleteAllDemoLaunchInfos"},
+ {0x082800C0, nullptr, "BeginImportTitleForOverWrite"},
};
AM_NET_Interface::AM_NET_Interface() {
diff --git a/src/core/hle/service/am/am_sys.cpp b/src/core/hle/service/am/am_sys.cpp
index a2268303c..949b3591d 100644
--- a/src/core/hle/service/am/am_sys.cpp
+++ b/src/core/hle/service/am/am_sys.cpp
@@ -9,27 +9,64 @@ namespace Service {
namespace AM {
const Interface::FunctionInfo FunctionTable[] = {
- {0x00010040, GetTitleCount, "GetTitleCount"},
- {0x00020082, GetTitleList, "GetTitleList"},
- {0x00030084, GetTitleInfo, "GetTitleInfo"},
- {0x000400C0, nullptr, "DeleteApplicationTitle"},
- {0x000500C0, nullptr, "GetTitleProductCode"},
- {0x000600C0, nullptr, "GetTitleExtDataId"},
+ {0x00010040, GetNumPrograms, "GetNumPrograms"},
+ {0x00020082, GetProgramList, "GetProgramList"},
+ {0x00030084, GetProgramInfos, "GetProgramInfos"},
+ {0x000400C0, nullptr, "DeleteUserProgram"},
+ {0x000500C0, nullptr, "GetProductCode"},
+ {0x000600C0, nullptr, "GetStorageId"},
{0x00070080, DeleteTicket, "DeleteTicket"},
- {0x00080000, GetTicketCount, "GetTicketCount"},
+ {0x00080000, GetNumTickets, "GetNumTickets"},
{0x00090082, GetTicketList, "GetTicketList"},
{0x000A0000, nullptr, "GetDeviceID"},
- {0x000D0084, nullptr, "GetPendingTitleInfo"},
- {0x000E00C0, nullptr, "DeletePendingTitle"},
- {0x00140040, nullptr, "FinalizePendingTitles"},
- {0x00150040, nullptr, "DeleteAllPendingTitles"},
+ {0x000B0040, nullptr, "GetNumImportTitleContexts"},
+ {0x000C0082, nullptr, "GetImportTitleContextList"},
+ {0x000D0084, nullptr, "GetImportTitleContexts"},
+ {0x000E00C0, nullptr, "DeleteImportTitleContext"},
+ {0x000F00C0, nullptr, "GetNumImportContentContexts"},
+ {0x00100102, nullptr, "GetImportContentContextList"},
+ {0x00110104, nullptr, "GetImportContentContexts"},
+ {0x00120102, nullptr, "DeleteImportContentContexts"},
+ {0x00130040, nullptr, "NeedsCleanup"},
+ {0x00140040, nullptr, "DoCleanup"},
+ {0x00150040, nullptr, "DeleteAllImportContexts"},
+ {0x00160000, nullptr, "DeleteAllTemporaryPrograms"},
+ {0x00170044, nullptr, "ImportTwlBackupLegacy"},
{0x00180080, nullptr, "InitializeTitleDatabase"},
- {0x00190040, nullptr, "ReloadDBS"},
- {0x001A00C0, nullptr, "GetDSiWareExportSize"},
- {0x001B0144, nullptr, "ExportDSiWare"},
- {0x001C0084, nullptr, "ImportDSiWare"},
- {0x00230080, nullptr, "GetPendingTitleCount"},
- {0x002400C2, nullptr, "GetPendingTitleList"},
+ {0x00190040, nullptr, "QueryAvailableTitleDatabase"},
+ {0x001A00C0, nullptr, "CalcTwlBackupSize"},
+ {0x001B0144, nullptr, "ExportTwlBackup"},
+ {0x001C0084, nullptr, "ImportTwlBackup"},
+ {0x001D0000, nullptr, "DeleteAllTwlUserPrograms"},
+ {0x001E00C8, nullptr, "ReadTwlBackupInfo"},
+ {0x001F0040, nullptr, "DeleteAllExpiredUserPrograms"},
+ {0x00200000, nullptr, "GetTwlArchiveResourceInfo"},
+ {0x00210042, nullptr, "GetPersonalizedTicketInfoList"},
+ {0x00220080, nullptr, "DeleteAllImportContextsFiltered"},
+ {0x00230080, nullptr, "GetNumImportTitleContextsFiltered"},
+ {0x002400C2, nullptr, "GetImportTitleContextListFiltered"},
+ {0x002500C0, nullptr, "CheckContentRights"},
+ {0x00260044, nullptr, "GetTicketLimitInfos"},
+ {0x00270044, nullptr, "GetDemoLaunchInfos"},
+ {0x00280108, nullptr, "ReadTwlBackupInfoEx"},
+ {0x00290082, nullptr, "DeleteUserProgramsAtomically"},
+ {0x002A00C0, nullptr, "GetNumExistingContentInfosSystem"},
+ {0x002B0142, nullptr, "ListExistingContentInfosSystem"},
+ {0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"},
+ {0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"},
+ {0x100100C0, GetNumContentInfos, "GetNumContentInfos"},
+ {0x10020104, FindContentInfos, "FindContentInfos"},
+ {0x10030142, ListContentInfos, "ListContentInfos"},
+ {0x10040102, DeleteContents, "DeleteContents"},
+ {0x10050084, GetDataTitleInfos, "GetDataTitleInfos"},
+ {0x10060080, nullptr, "GetNumDataTitleTickets"},
+ {0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"},
+ {0x100801C2, nullptr, "GetItemRights"},
+ {0x100900C0, nullptr, "IsDataTitleInUse"},
+ {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"},
+ {0x100B00C0, nullptr, "GetNumExistingContentInfos"},
+ {0x100C0142, nullptr, "ListExistingContentInfos"},
+ {0x100D0084, nullptr, "GetPatchTitleInfos"},
};
AM_SYS_Interface::AM_SYS_Interface() {
diff --git a/src/core/hle/service/am/am_u.cpp b/src/core/hle/service/am/am_u.cpp
index 151b5e42b..354d51610 100644
--- a/src/core/hle/service/am/am_u.cpp
+++ b/src/core/hle/service/am/am_u.cpp
@@ -9,40 +9,76 @@ namespace Service {
namespace AM {
const Interface::FunctionInfo FunctionTable[] = {
- {0x00010040, GetTitleCount, "GetTitleCount"},
- {0x00020082, GetTitleList, "GetTitleList"},
- {0x00030084, GetTitleInfo, "GetTitleInfo"},
- {0x000400C0, nullptr, "DeleteApplicationTitle"},
- {0x000500C0, nullptr, "GetTitleProductCode"},
- {0x000600C0, nullptr, "GetTitleExtDataId"},
+ {0x00010040, GetNumPrograms, "GetNumPrograms"},
+ {0x00020082, GetProgramList, "GetProgramList"},
+ {0x00030084, GetProgramInfos, "GetProgramInfos"},
+ {0x000400C0, nullptr, "DeleteUserProgram"},
+ {0x000500C0, nullptr, "GetProductCode"},
+ {0x000600C0, nullptr, "GetStorageId"},
{0x00070080, DeleteTicket, "DeleteTicket"},
- {0x00080000, GetTicketCount, "GetTicketCount"},
+ {0x00080000, GetNumTickets, "GetNumTickets"},
{0x00090082, GetTicketList, "GetTicketList"},
{0x000A0000, nullptr, "GetDeviceID"},
- {0x000D0084, nullptr, "GetPendingTitleInfo"},
- {0x000E00C0, nullptr, "DeletePendingTitle"},
- {0x00140040, nullptr, "FinalizePendingTitles"},
- {0x00150040, nullptr, "DeleteAllPendingTitles"},
+ {0x000B0040, nullptr, "GetNumImportTitleContexts"},
+ {0x000C0082, nullptr, "GetImportTitleContextList"},
+ {0x000D0084, nullptr, "GetImportTitleContexts"},
+ {0x000E00C0, nullptr, "DeleteImportTitleContext"},
+ {0x000F00C0, nullptr, "GetNumImportContentContexts"},
+ {0x00100102, nullptr, "GetImportContentContextList"},
+ {0x00110104, nullptr, "GetImportContentContexts"},
+ {0x00120102, nullptr, "DeleteImportContentContexts"},
+ {0x00130040, nullptr, "NeedsCleanup"},
+ {0x00140040, nullptr, "DoCleanup"},
+ {0x00150040, nullptr, "DeleteAllImportContexts"},
+ {0x00160000, nullptr, "DeleteAllTemporaryPrograms"},
+ {0x00170044, nullptr, "ImportTwlBackupLegacy"},
{0x00180080, nullptr, "InitializeTitleDatabase"},
- {0x00190040, nullptr, "ReloadDBS"},
- {0x001A00C0, nullptr, "GetDSiWareExportSize"},
- {0x001B0144, nullptr, "ExportDSiWare"},
- {0x001C0084, nullptr, "ImportDSiWare"},
- {0x00230080, nullptr, "TitleIDListGetTotal2"},
- {0x002400C2, nullptr, "GetTitleIDList2"},
- {0x04010080, nullptr, "InstallFIRM"},
- {0x04020040, nullptr, "StartInstallCIADB0"},
- {0x04030000, nullptr, "StartInstallCIADB1"},
- {0x04040002, nullptr, "AbortCIAInstall"},
- {0x04050002, nullptr, "CloseCIAFinalizeInstall"},
- {0x04060002, nullptr, "CloseCIA"},
- {0x040700C2, nullptr, "FinalizeTitlesInstall"},
- {0x04080042, nullptr, "GetCiaFileInfo"},
- {0x040E00C2, nullptr, "InstallTitlesFinish"},
- {0x040F0000, nullptr, "InstallNATIVEFIRM"},
- {0x041000C0, nullptr, "DeleteTitle"},
- {0x04120000, nullptr, "Initialize"},
- {0x041700C0, nullptr, "MigrateAGBtoSAV"},
+ {0x00190040, nullptr, "QueryAvailableTitleDatabase"},
+ {0x001A00C0, nullptr, "CalcTwlBackupSize"},
+ {0x001B0144, nullptr, "ExportTwlBackup"},
+ {0x001C0084, nullptr, "ImportTwlBackup"},
+ {0x001D0000, nullptr, "DeleteAllTwlUserPrograms"},
+ {0x001E00C8, nullptr, "ReadTwlBackupInfo"},
+ {0x001F0040, nullptr, "DeleteAllExpiredUserPrograms"},
+ {0x00200000, nullptr, "GetTwlArchiveResourceInfo"},
+ {0x00210042, nullptr, "GetPersonalizedTicketInfoList"},
+ {0x00220080, nullptr, "DeleteAllImportContextsFiltered"},
+ {0x00230080, nullptr, "GetNumImportTitleContextsFiltered"},
+ {0x002400C2, nullptr, "GetImportTitleContextListFiltered"},
+ {0x002500C0, nullptr, "CheckContentRights"},
+ {0x00260044, nullptr, "GetTicketLimitInfos"},
+ {0x00270044, nullptr, "GetDemoLaunchInfos"},
+ {0x00280108, nullptr, "ReadTwlBackupInfoEx"},
+ {0x00290082, nullptr, "DeleteUserProgramsAtomically"},
+ {0x002A00C0, nullptr, "GetNumExistingContentInfosSystem"},
+ {0x002B0142, nullptr, "ListExistingContentInfosSystem"},
+ {0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"},
+ {0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"},
+ {0x04010080, nullptr, "UpdateFirmwareTo"},
+ {0x04020040, nullptr, "BeginImportProgram"},
+ {0x04030000, nullptr, "BeginImportProgramTemporarily"},
+ {0x04040002, nullptr, "CancelImportProgram"},
+ {0x04050002, nullptr, "EndImportProgram"},
+ {0x04060002, nullptr, "EndImportProgramWithoutCommit"},
+ {0x040700C2, nullptr, "CommitImportPrograms"},
+ {0x04080042, nullptr, "GetProgramInfoFromCia"},
+ {0x04090004, nullptr, "GetSystemMenuDataFromCia"},
+ {0x040A0002, nullptr, "GetDependencyListFromCia"},
+ {0x040B0002, nullptr, "GetTransferSizeFromCia"},
+ {0x040C0002, nullptr, "GetCoreVersionFromCia"},
+ {0x040D0042, nullptr, "GetRequiredSizeFromCia"},
+ {0x040E00C2, nullptr, "CommitImportProgramsAndUpdateFirmwareAuto"},
+ {0x040F0000, nullptr, "UpdateFirmwareAuto"},
+ {0x041000C0, nullptr, "DeleteProgram"},
+ {0x04110044, nullptr, "GetTwlProgramListForReboot"},
+ {0x04120000, nullptr, "GetSystemUpdaterMutex"},
+ {0x04130002, nullptr, "GetMetaSizeFromCia"},
+ {0x04140044, nullptr, "GetMetaDataFromCia"},
+ {0x04150080, nullptr, "CheckDemoLaunchRights"},
+ {0x041600C0, nullptr, "GetInternalTitleLocationInfo"},
+ {0x041700C0, nullptr, "PerpetuateAgbSaveData"},
+ {0x04180040, nullptr, "BeginImportProgramForOverWrite"},
+ {0x04190000, nullptr, "BeginImportSystemProgram"},
};
AM_U_Interface::AM_U_Interface() {
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 31e5e07b2..615fe31ea 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -458,12 +458,16 @@ void GetStartupArgument(Service::Interface* self) {
return;
}
- LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x , "
- "parameter_value=0x%08x",
- startup_argument_type, parameter_size, Memory::Read32(cmd_buff[41]));
+ u32 addr = cmd_buff[65];
+ if (addr && parameter_size) {
+ Memory::ZeroBlock(addr, parameter_size);
+ }
+
+ LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x",
+ startup_argument_type, parameter_size);
cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = (parameter_size > 0) ? 1 : 0;
+ cmd_buff[2] = 0;
}
void CheckNew3DSApp(Service::Interface* self) {
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index 44dbd8757..80325361f 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -14,6 +14,9 @@ class Interface;
namespace APT {
+/// Each APT service can only have up to 2 sessions connected at the same time.
+static const u32 MaxAPTSessions = 2;
+
/// Holds information about the parameters used in Send/Glance/ReceiveParameter
struct MessageParameter {
u32 sender_id = 0;
@@ -407,9 +410,11 @@ void CancelLibraryApplet(Service::Interface* self);
* Inputs:
* 1 : Parameter Size (capped to 0x300)
* 2 : StartupArgumentType
+ * 65 : Output buffer for startup argument
* Outputs:
* 0 : Return header
- * 1 : u8, Exists (0 = does not exist, 1 = exists)
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : u8, Exists (0 = does not exist, 1 = exists)
*/
void GetStartupArgument(Service::Interface* self);
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp
index a7a0c8a41..62dc2d61d 100644
--- a/src/core/hle/service/apt/apt_a.cpp
+++ b/src/core/hle/service/apt/apt_a.cpp
@@ -9,37 +9,100 @@ namespace Service {
namespace APT {
const Interface::FunctionInfo FunctionTable[] = {
- {0x00010040, GetLockHandle, "GetLockHandle?"},
- {0x00020080, Initialize, "Initialize?"},
- {0x00030040, Enable, "Enable?"},
- {0x00040040, nullptr, "Finalize?"},
+ {0x00010040, GetLockHandle, "GetLockHandle"},
+ {0x00020080, Initialize, "Initialize"},
+ {0x00030040, Enable, "Enable"},
+ {0x00040040, nullptr, "Finalize"},
{0x00050040, GetAppletManInfo, "GetAppletManInfo"},
{0x00060040, GetAppletInfo, "GetAppletInfo"},
+ {0x00070000, nullptr, "GetLastSignaledAppletId"},
+ {0x00080000, nullptr, "CountRegisteredApplet"},
{0x00090040, IsRegistered, "IsRegistered"},
+ {0x000A0040, nullptr, "GetAttribute"},
{0x000B0040, InquireNotification, "InquireNotification"},
{0x000C0104, SendParameter, "SendParameter"},
{0x000D0080, ReceiveParameter, "ReceiveParameter"},
{0x000E0080, GlanceParameter, "GlanceParameter"},
{0x000F0100, CancelParameter, "CancelParameter"},
+ {0x001000C2, nullptr, "DebugFunc"},
+ {0x001100C0, nullptr, "MapProgramIdForDebug"},
+ {0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"},
+ {0x00130000, nullptr, "GetPreparationState"},
+ {0x00140040, nullptr, "SetPreparationState"},
{0x00150140, PrepareToStartApplication, "PrepareToStartApplication"},
{0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"},
+ {0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
{0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
+ {0x00190040, nullptr, "PrepareToStartSystemApplet"},
+ {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
+ {0x001B00C4, nullptr, "StartApplication"},
+ {0x001C0000, nullptr, "WakeupApplication"},
+ {0x001D0000, nullptr, "CancelApplication"},
{0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
+ {0x001F0084, nullptr, "StartSystemApplet"},
+ {0x00200044, nullptr, "StartNewestHomeMenu"},
+ {0x00210000, nullptr, "OrderToCloseApplication"},
+ {0x00220040, nullptr, "PrepareToCloseApplication"},
+ {0x00230040, nullptr, "PrepareToJumpToApplication"},
+ {0x00240044, nullptr, "JumpToApplication"},
+ {0x002500C0, nullptr, "PrepareToCloseLibraryApplet"},
+ {0x00260000, nullptr, "PrepareToCloseSystemApplet"},
+ {0x00270044, nullptr, "CloseApplication"},
+ {0x00280044, nullptr, "CloseLibraryApplet"},
+ {0x00290044, nullptr, "CloseSystemApplet"},
+ {0x002A0000, nullptr, "OrderToCloseSystemApplet"},
+ {0x002B0000, nullptr, "PrepareToJumpToHomeMenu"},
+ {0x002C0044, nullptr, "JumpToHomeMenu"},
+ {0x002D0000, nullptr, "PrepareToLeaveHomeMenu"},
+ {0x002E0044, nullptr, "LeaveHomeMenu"},
+ {0x002F0040, nullptr, "PrepareToLeaveResidentApplet"},
+ {0x00300044, nullptr, "LeaveResidentApplet"},
+ {0x00310100, nullptr, "PrepareToDoApplicationJump"},
+ {0x00320084, nullptr, "DoApplicationJump"},
+ {0x00330000, nullptr, "GetProgramIdOnApplicationJump"},
+ {0x00340084, nullptr, "SendDeliverArg"},
+ {0x00350080, nullptr, "ReceiveDeliverArg"},
+ {0x00360040, nullptr, "LoadSysMenuArg"},
+ {0x00370042, nullptr, "StoreSysMenuArg"},
+ {0x00380040, nullptr, "PreloadResidentApplet"},
+ {0x00390040, nullptr, "PrepareToStartResidentApplet"},
+ {0x003A0044, nullptr, "StartResidentApplet"},
{0x003B0040, CancelLibraryApplet, "CancelLibraryApplet"},
+ {0x003C0042, nullptr, "SendDspSleep"},
+ {0x003D0042, nullptr, "SendDspWakeUp"},
{0x003E0080, nullptr, "ReplySleepQuery"},
- {0x00430040, NotifyToWait, "NotifyToWait?"},
- {0x00440000, GetSharedFont, "GetSharedFont?"},
- {0x004B00C2, AppletUtility, "AppletUtility?"},
+ {0x003F0040, nullptr, "ReplySleepNotificationComplete"},
+ {0x00400042, nullptr, "SendCaptureBufferInfo"},
+ {0x00410040, nullptr, "ReceiveCaptureBufferInfo"},
+ {0x00420080, nullptr, "SleepSystem"},
+ {0x00430040, NotifyToWait, "NotifyToWait"},
+ {0x00440000, GetSharedFont, "GetSharedFont"},
+ {0x00450040, nullptr, "GetWirelessRebootInfo"},
+ {0x00460104, nullptr, "Wrap"},
+ {0x00470104, nullptr, "Unwrap"},
+ {0x00480100, nullptr, "GetProgramInfo"},
+ {0x00490180, nullptr, "Reboot"},
+ {0x004A0040, nullptr, "GetCaptureInfo"},
+ {0x004B00C2, AppletUtility, "AppletUtility"},
+ {0x004C0000, nullptr, "SetFatalErrDispMode"},
+ {0x004D0080, nullptr, "GetAppletProgramInfo"},
+ {0x004E0000, nullptr, "HardwareResetAsync"},
{0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
{0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
{0x00510080, GetStartupArgument, "GetStartupArgument"},
+ {0x00520104, nullptr, "Wrap1"},
+ {0x00530104, nullptr, "Unwrap1"},
{0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"},
{0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"},
+ {0x00570044, nullptr, "WakeupApplication2"},
+ {0x00580002, nullptr, "GetProgramID"},
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
{0x01020000, CheckNew3DS, "CheckNew3DS"},
+ {0x01040000, nullptr, "IsStandardMemoryLayout"},
+ {0x01050100, nullptr, "IsTitleAllowed"},
};
-APT_A_Interface::APT_A_Interface() {
+APT_A_Interface::APT_A_Interface() : Interface(MaxAPTSessions) {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp
index c4556a5de..effd23dce 100644
--- a/src/core/hle/service/apt/apt_s.cpp
+++ b/src/core/hle/service/apt/apt_s.cpp
@@ -94,12 +94,15 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00530104, nullptr, "Unwrap1"},
{0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"},
{0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"},
+ {0x00570044, nullptr, "WakeupApplication2"},
{0x00580002, nullptr, "GetProgramID"},
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
{0x01020000, CheckNew3DS, "CheckNew3DS"},
+ {0x01040000, nullptr, "IsStandardMemoryLayout"},
+ {0x01050100, nullptr, "IsTitleAllowed"},
};
-APT_S_Interface::APT_S_Interface() {
+APT_S_Interface::APT_S_Interface() : Interface(MaxAPTSessions) {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp
index a731c39f6..e06084a1e 100644
--- a/src/core/hle/service/apt/apt_u.cpp
+++ b/src/core/hle/service/apt/apt_u.cpp
@@ -99,7 +99,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x01020000, CheckNew3DS, "CheckNew3DS"},
};
-APT_U_Interface::APT_U_Interface() {
+APT_U_Interface::APT_U_Interface() : Interface(MaxAPTSessions) {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/boss/boss_p.cpp b/src/core/hle/service/boss/boss_p.cpp
index dfee8d055..ee941e228 100644
--- a/src/core/hle/service/boss/boss_p.cpp
+++ b/src/core/hle/service/boss/boss_p.cpp
@@ -2,16 +2,81 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "core/hle/service/boss/boss.h"
#include "core/hle/service/boss/boss_p.h"
namespace Service {
namespace BOSS {
-// Empty arrays are illegal -- commented out until an entry is added.
-// const Interface::FunctionInfo FunctionTable[] = { };
+const Interface::FunctionInfo FunctionTable[] = {
+ // boss:u shared commands
+ {0x00010082, InitializeSession, "InitializeSession"},
+ {0x00020100, RegisterStorage, "RegisterStorage"},
+ {0x00030000, UnregisterStorage, "UnregisterStorage"},
+ {0x00040000, GetStorageInfo, "GetStorageInfo"},
+ {0x00050042, RegisterPrivateRootCa, "RegisterPrivateRootCa"},
+ {0x00060084, RegisterPrivateClientCert, "RegisterPrivateClientCert"},
+ {0x00070000, GetNewArrivalFlag, "GetNewArrivalFlag"},
+ {0x00080002, RegisterNewArrivalEvent, "RegisterNewArrivalEvent"},
+ {0x00090040, SetOptoutFlag, "SetOptoutFlag"},
+ {0x000A0000, GetOptoutFlag, "GetOptoutFlag"},
+ {0x000B00C2, RegisterTask, "RegisterTask"},
+ {0x000C0082, UnregisterTask, "UnregisterTask"},
+ {0x000D0082, ReconfigureTask, "ReconfigureTask"},
+ {0x000E0000, GetTaskIdList, "GetTaskIdList"},
+ {0x000F0042, GetStepIdList, "GetStepIdList"},
+ {0x00100102, GetNsDataIdList, "GetNsDataIdList"},
+ {0x00110102, GetOwnNsDataIdList, "GetOwnNsDataIdList"},
+ {0x00120102, GetNewDataNsDataIdList, "GetNewDataNsDataIdList"},
+ {0x00130102, GetOwnNewDataNsDataIdList, "GetOwnNewDataNsDataIdList"},
+ {0x00140082, SendProperty, "SendProperty"},
+ {0x00150042, SendPropertyHandle, "SendPropertyHandle"},
+ {0x00160082, ReceiveProperty, "ReceiveProperty"},
+ {0x00170082, UpdateTaskInterval, "UpdateTaskInterval"},
+ {0x00180082, UpdateTaskCount, "UpdateTaskCount"},
+ {0x00190042, GetTaskInterval, "GetTaskInterval"},
+ {0x001A0042, GetTaskCount, "GetTaskCount"},
+ {0x001B0042, GetTaskServiceStatus, "GetTaskServiceStatus"},
+ {0x001C0042, StartTask, "StartTask"},
+ {0x001D0042, StartTaskImmediate, "StartTaskImmediate"},
+ {0x001E0042, CancelTask, "CancelTask"},
+ {0x001F0000, GetTaskFinishHandle, "GetTaskFinishHandle"},
+ {0x00200082, GetTaskState, "GetTaskState"},
+ {0x00210042, GetTaskResult, "GetTaskResult"},
+ {0x00220042, GetTaskCommErrorCode, "GetTaskCommErrorCode"},
+ {0x002300C2, GetTaskStatus, "GetTaskStatus"},
+ {0x00240082, GetTaskError, "GetTaskError"},
+ {0x00250082, GetTaskInfo, "GetTaskInfo"},
+ {0x00260040, DeleteNsData, "DeleteNsData"},
+ {0x002700C2, GetNsDataHeaderInfo, "GetNsDataHeaderInfo"},
+ {0x00280102, ReadNsData, "ReadNsData"},
+ {0x00290080, SetNsDataAdditionalInfo, "SetNsDataAdditionalInfo"},
+ {0x002A0040, GetNsDataAdditionalInfo, "GetNsDataAdditionalInfo"},
+ {0x002B0080, SetNsDataNewFlag, "SetNsDataNewFlag"},
+ {0x002C0040, GetNsDataNewFlag, "GetNsDataNewFlag"},
+ {0x002D0040, GetNsDataLastUpdate, "GetNsDataLastUpdate"},
+ {0x002E0040, GetErrorCode, "GetErrorCode"},
+ {0x002F0140, RegisterStorageEntry, "RegisterStorageEntry"},
+ {0x00300000, GetStorageEntryInfo, "GetStorageEntryInfo"},
+ {0x00310100, SetStorageOption, "SetStorageOption"},
+ {0x00320000, GetStorageOption, "GetStorageOption"},
+ {0x00330042, StartBgImmediate, "StartBgImmediate"},
+ {0x00340042, GetTaskActivePriority, "GetTaskActivePriority"},
+ {0x003500C2, RegisterImmediateTask, "RegisterImmediateTask"},
+ {0x00360084, SetTaskQuery, "SetTaskQuery"},
+ {0x00370084, GetTaskQuery, "GetTaskQuery"},
+ // boss:p
+ {0x04040080, nullptr, "GetAppNewFlag"},
+ {0x04130082, nullptr, "SendPropertyPrivileged"},
+ {0x041500C0, nullptr, "DeleteNsDataPrivileged"},
+ {0x04160142, nullptr, "GetNsDataHeaderInfoPrivileged"},
+ {0x04170182, nullptr, "ReadNsDataPrivileged"},
+ {0x041A0100, nullptr, "SetNsDataNewFlagPrivileged"},
+ {0x041B00C0, nullptr, "GetNsDataNewFlagPrivileged"},
+};
BOSS_P_Interface::BOSS_P_Interface() {
- // Register(FunctionTable);
+ Register(FunctionTable);
}
} // namespace BOSS
diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp
index 515b344e6..eb04273db 100644
--- a/src/core/hle/service/cecd/cecd.cpp
+++ b/src/core/hle/service/cecd/cecd.cpp
@@ -5,6 +5,7 @@
#include "common/logging/log.h"
#include "core/hle/kernel/event.h"
#include "core/hle/service/cecd/cecd.h"
+#include "core/hle/service/cecd/cecd_ndm.h"
#include "core/hle/service/cecd/cecd_s.h"
#include "core/hle/service/cecd/cecd_u.h"
#include "core/hle/service/service.h"
@@ -43,12 +44,13 @@ void GetChangeStateEventHandle(Service::Interface* self) {
}
void Init() {
- AddService(new CECD_S_Interface);
- AddService(new CECD_U_Interface);
+ AddService(new CECD_NDM);
+ AddService(new CECD_S);
+ AddService(new CECD_U);
- cecinfo_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD_U::cecinfo_event");
+ cecinfo_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD::cecinfo_event");
change_state_event =
- Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD_U::change_state_event");
+ Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD::change_state_event");
}
void Shutdown() {
diff --git a/src/core/hle/service/cecd/cecd_ndm.cpp b/src/core/hle/service/cecd/cecd_ndm.cpp
new file mode 100644
index 000000000..7baf93750
--- /dev/null
+++ b/src/core/hle/service/cecd/cecd_ndm.cpp
@@ -0,0 +1,23 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/cecd/cecd.h"
+#include "core/hle/service/cecd/cecd_ndm.h"
+
+namespace Service {
+namespace CECD {
+
+static const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010000, nullptr, "Initialize"},
+ {0x00020000, nullptr, "Deinitialize"},
+ {0x00030000, nullptr, "ResumeDaemon"},
+ {0x00040040, nullptr, "SuspendDaemon"},
+};
+
+CECD_NDM::CECD_NDM() {
+ Register(FunctionTable);
+}
+
+} // namespace CECD
+} // namespace Service
diff --git a/src/core/hle/service/cecd/cecd_ndm.h b/src/core/hle/service/cecd/cecd_ndm.h
new file mode 100644
index 000000000..2e2e50ada
--- /dev/null
+++ b/src/core/hle/service/cecd/cecd_ndm.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace CECD {
+
+class CECD_NDM : public Interface {
+public:
+ CECD_NDM();
+
+ std::string GetPortName() const override {
+ return "cecd:ndm";
+ }
+};
+
+} // namespace CECD
+} // namespace Service
diff --git a/src/core/hle/service/cecd/cecd_s.cpp b/src/core/hle/service/cecd/cecd_s.cpp
index 7477b9320..eacda7d41 100644
--- a/src/core/hle/service/cecd/cecd_s.cpp
+++ b/src/core/hle/service/cecd/cecd_s.cpp
@@ -2,16 +2,34 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "core/hle/service/cecd/cecd.h"
#include "core/hle/service/cecd/cecd_s.h"
namespace Service {
namespace CECD {
-// Empty arrays are illegal -- commented out until an entry is added.
-// const Interface::FunctionInfo FunctionTable[] = { };
+static const Interface::FunctionInfo FunctionTable[] = {
+ // cecd:u shared commands
+ {0x000100C2, nullptr, "OpenRawFile"},
+ {0x00020042, nullptr, "ReadRawFile"},
+ {0x00030104, nullptr, "ReadMessage"},
+ {0x00040106, nullptr, "ReadMessageWithHMAC"},
+ {0x00050042, nullptr, "WriteRawFile"},
+ {0x00060104, nullptr, "WriteMessage"},
+ {0x00070106, nullptr, "WriteMessageWithHMAC"},
+ {0x00080102, nullptr, "Delete"},
+ {0x000A00C4, nullptr, "GetSystemInfo"},
+ {0x000B0040, nullptr, "RunCommand"},
+ {0x000C0040, nullptr, "RunCommandAlt"},
+ {0x000E0000, GetCecStateAbbreviated, "GetCecStateAbbreviated"},
+ {0x000F0000, GetCecInfoEventHandle, "GetCecInfoEventHandle"},
+ {0x00100000, GetChangeStateEventHandle, "GetChangeStateEventHandle"},
+ {0x00110104, nullptr, "OpenAndWrite"},
+ {0x00120104, nullptr, "OpenAndRead"},
+};
-CECD_S_Interface::CECD_S_Interface() {
- // Register(FunctionTable);
+CECD_S::CECD_S() {
+ Register(FunctionTable);
}
} // namespace CECD
diff --git a/src/core/hle/service/cecd/cecd_s.h b/src/core/hle/service/cecd/cecd_s.h
index df5c01849..ab6c6789a 100644
--- a/src/core/hle/service/cecd/cecd_s.h
+++ b/src/core/hle/service/cecd/cecd_s.h
@@ -9,9 +9,9 @@
namespace Service {
namespace CECD {
-class CECD_S_Interface : public Interface {
+class CECD_S : public Interface {
public:
- CECD_S_Interface();
+ CECD_S();
std::string GetPortName() const override {
return "cecd:s";
diff --git a/src/core/hle/service/cecd/cecd_u.cpp b/src/core/hle/service/cecd/cecd_u.cpp
index 4b747de7b..3ed864f0b 100644
--- a/src/core/hle/service/cecd/cecd_u.cpp
+++ b/src/core/hle/service/cecd/cecd_u.cpp
@@ -9,13 +9,26 @@ namespace Service {
namespace CECD {
static const Interface::FunctionInfo FunctionTable[] = {
+ // cecd:u shared commands
+ {0x000100C2, nullptr, "OpenRawFile"},
+ {0x00020042, nullptr, "ReadRawFile"},
+ {0x00030104, nullptr, "ReadMessage"},
+ {0x00040106, nullptr, "ReadMessageWithHMAC"},
+ {0x00050042, nullptr, "WriteRawFile"},
+ {0x00060104, nullptr, "WriteMessage"},
+ {0x00070106, nullptr, "WriteMessageWithHMAC"},
+ {0x00080102, nullptr, "Delete"},
+ {0x000A00C4, nullptr, "GetSystemInfo"},
+ {0x000B0040, nullptr, "RunCommand"},
+ {0x000C0040, nullptr, "RunCommandAlt"},
{0x000E0000, GetCecStateAbbreviated, "GetCecStateAbbreviated"},
{0x000F0000, GetCecInfoEventHandle, "GetCecInfoEventHandle"},
{0x00100000, GetChangeStateEventHandle, "GetChangeStateEventHandle"},
- {0x00120104, nullptr, "ReadSavedData"},
+ {0x00110104, nullptr, "OpenAndWrite"},
+ {0x00120104, nullptr, "OpenAndRead"},
};
-CECD_U_Interface::CECD_U_Interface() {
+CECD_U::CECD_U() {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/cecd/cecd_u.h b/src/core/hle/service/cecd/cecd_u.h
index 394030ffc..16e874ff5 100644
--- a/src/core/hle/service/cecd/cecd_u.h
+++ b/src/core/hle/service/cecd/cecd_u.h
@@ -9,9 +9,9 @@
namespace Service {
namespace CECD {
-class CECD_U_Interface : public Interface {
+class CECD_U : public Interface {
public:
- CECD_U_Interface();
+ CECD_U();
std::string GetPortName() const override {
return "cecd:u";
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index 5e340f4c8..0bf59eb76 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -12,6 +12,7 @@
#include "core/hle/result.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/cfg/cfg_i.h"
+#include "core/hle/service/cfg/cfg_nor.h"
#include "core/hle/service/cfg/cfg_s.h"
#include "core/hle/service/cfg/cfg_u.h"
#include "core/hle/service/fs/archive.h"
@@ -574,9 +575,10 @@ ResultCode LoadConfigNANDSaveFile() {
}
void Init() {
- AddService(new CFG_I_Interface);
- AddService(new CFG_S_Interface);
- AddService(new CFG_U_Interface);
+ AddService(new CFG_I);
+ AddService(new CFG_NOR);
+ AddService(new CFG_S);
+ AddService(new CFG_U);
LoadConfigNANDSaveFile();
diff --git a/src/core/hle/service/cfg/cfg_i.cpp b/src/core/hle/service/cfg/cfg_i.cpp
index 2ff52c8b8..e8db0fc42 100644
--- a/src/core/hle/service/cfg/cfg_i.cpp
+++ b/src/core/hle/service/cfg/cfg_i.cpp
@@ -20,6 +20,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00080080, nullptr, "GoThroughTable"},
{0x00090040, GetCountryCodeString, "GetCountryCodeString"},
{0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
+ {0x000B0000, nullptr, "IsFangateSupported"},
// cfg:i
{0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
{0x04020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"},
@@ -55,7 +56,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x08180042, nullptr, "SecureInfoGetSerialNo"},
};
-CFG_I_Interface::CFG_I_Interface() {
+CFG_I::CFG_I() {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/cfg/cfg_i.h b/src/core/hle/service/cfg/cfg_i.h
index d0a2cce39..8cfd47633 100644
--- a/src/core/hle/service/cfg/cfg_i.h
+++ b/src/core/hle/service/cfg/cfg_i.h
@@ -9,9 +9,9 @@
namespace Service {
namespace CFG {
-class CFG_I_Interface : public Service::Interface {
+class CFG_I final : public Interface {
public:
- CFG_I_Interface();
+ CFG_I();
std::string GetPortName() const override {
return "cfg:i";
diff --git a/src/core/hle/service/cfg/cfg_nor.cpp b/src/core/hle/service/cfg/cfg_nor.cpp
new file mode 100644
index 000000000..4ce02d115
--- /dev/null
+++ b/src/core/hle/service/cfg/cfg_nor.cpp
@@ -0,0 +1,23 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/cfg/cfg.h"
+#include "core/hle/service/cfg/cfg_nor.h"
+
+namespace Service {
+namespace CFG {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010040, nullptr, "Initialize"},
+ {0x00020000, nullptr, "Shutdown"},
+ {0x00050082, nullptr, "ReadData"},
+ {0x00060082, nullptr, "WriteData"},
+};
+
+CFG_NOR::CFG_NOR() {
+ Register(FunctionTable);
+}
+
+} // namespace CFG
+} // namespace Service
diff --git a/src/core/hle/service/cfg/cfg_nor.h b/src/core/hle/service/cfg/cfg_nor.h
new file mode 100644
index 000000000..c337718e7
--- /dev/null
+++ b/src/core/hle/service/cfg/cfg_nor.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace CFG {
+
+class CFG_NOR final : public Interface {
+public:
+ CFG_NOR();
+
+ std::string GetPortName() const override {
+ return "cfg:nor";
+ }
+};
+
+} // namespace CFG
+} // namespace Service
diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp
index eed26dec7..9386fe33d 100644
--- a/src/core/hle/service/cfg/cfg_s.cpp
+++ b/src/core/hle/service/cfg/cfg_s.cpp
@@ -20,6 +20,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00080080, nullptr, "GoThroughTable"},
{0x00090040, GetCountryCodeString, "GetCountryCodeString"},
{0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
+ {0x000B0000, nullptr, "IsFangateSupported"},
// cfg:s
{0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
{0x04020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"},
@@ -32,7 +33,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x04090000, nullptr, "UpdateConfigBlk00040003"},
};
-CFG_S_Interface::CFG_S_Interface() {
+CFG_S::CFG_S() {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/cfg/cfg_s.h b/src/core/hle/service/cfg/cfg_s.h
index 5568d6485..99fea46ee 100644
--- a/src/core/hle/service/cfg/cfg_s.h
+++ b/src/core/hle/service/cfg/cfg_s.h
@@ -9,9 +9,9 @@
namespace Service {
namespace CFG {
-class CFG_S_Interface : public Service::Interface {
+class CFG_S final : public Interface {
public:
- CFG_S_Interface();
+ CFG_S();
std::string GetPortName() const override {
return "cfg:s";
diff --git a/src/core/hle/service/cfg/cfg_u.cpp b/src/core/hle/service/cfg/cfg_u.cpp
index f28217134..7b66fee22 100644
--- a/src/core/hle/service/cfg/cfg_u.cpp
+++ b/src/core/hle/service/cfg/cfg_u.cpp
@@ -20,9 +20,10 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00080080, nullptr, "GoThroughTable"},
{0x00090040, GetCountryCodeString, "GetCountryCodeString"},
{0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
+ {0x000B0000, nullptr, "IsFangateSupported"},
};
-CFG_U_Interface::CFG_U_Interface() {
+CFG_U::CFG_U() {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/cfg/cfg_u.h b/src/core/hle/service/cfg/cfg_u.h
index 5303d8ac6..fc7844714 100644
--- a/src/core/hle/service/cfg/cfg_u.h
+++ b/src/core/hle/service/cfg/cfg_u.h
@@ -9,9 +9,9 @@
namespace Service {
namespace CFG {
-class CFG_U_Interface : public Service::Interface {
+class CFG_U final : public Interface {
public:
- CFG_U_Interface();
+ CFG_U();
std::string GetPortName() const override {
return "cfg:u";
diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp
index 20c759ad7..6cf62f9bc 100644
--- a/src/core/hle/service/csnd_snd.cpp
+++ b/src/core/hle/service/csnd_snd.cpp
@@ -4,85 +4,137 @@
#include <cstring>
#include "common/alignment.h"
-#include "core/hle/hle.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/csnd_snd.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace CSND_SND
+namespace Service {
+namespace CSND {
-namespace CSND_SND {
-
-const Interface::FunctionInfo FunctionTable[] = {
- {0x00010140, Initialize, "Initialize"},
- {0x00020000, Shutdown, "Shutdown"},
- {0x00030040, ExecuteType0Commands, "ExecuteType0Commands"},
- {0x00040080, nullptr, "ExecuteType1Commands"},
- {0x00050000, AcquireSoundChannels, "AcquireSoundChannels"},
- {0x00060000, nullptr, "ReleaseSoundChannels"},
- {0x00070000, nullptr, "AcquireCaptureDevice"},
- {0x00080040, nullptr, "ReleaseCaptureDevice"},
- {0x00090082, nullptr, "FlushDataCache"},
- {0x000A0082, nullptr, "StoreDataCache"},
- {0x000B0082, nullptr, "InvalidateDataCache"},
- {0x000C0000, nullptr, "Reset"},
+struct Type0Command {
+ // command id and next command offset
+ u32 command_id;
+ u32 finished;
+ u32 flags;
+ u8 parameters[20];
};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- Register(FunctionTable);
-}
+static_assert(sizeof(Type0Command) == 0x20, "Type0Command structure size is wrong");
static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory = nullptr;
static Kernel::SharedPtr<Kernel::Mutex> mutex = nullptr;
-void Initialize(Service::Interface* self) {
+/**
+ * CSND_SND::Initialize service function
+ * Inputs:
+ * 0 : Header Code[0x00010140]
+ * 1 : Shared memory block size, for mem-block creation
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Handle-list header
+ * 3 : Mutex handle
+ * 4 : Shared memory block handle
+ */
+static void Initialize(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 size = Common::AlignUp(cmd_buff[1], Memory::PAGE_SIZE);
+
using Kernel::MemoryPermission;
shared_memory = Kernel::SharedMemory::Create(nullptr, size, MemoryPermission::ReadWrite,
MemoryPermission::ReadWrite, 0,
Kernel::MemoryRegion::BASE, "CSND:SharedMemory");
- mutex = Kernel::Mutex::Create(false);
+ mutex = Kernel::Mutex::Create(false, "CSND:mutex");
cmd_buff[1] = RESULT_SUCCESS.raw;
cmd_buff[2] = IPC::CopyHandleDesc(2);
cmd_buff[3] = Kernel::g_handle_table.Create(mutex).MoveFrom();
cmd_buff[4] = Kernel::g_handle_table.Create(shared_memory).MoveFrom();
+
+ LOG_WARNING(Service_CSND, "(STUBBED) called");
}
-void ExecuteType0Commands(Service::Interface* self) {
- u32* const cmd_buff = Kernel::GetCommandBuffer();
- u8* const ptr = shared_memory->GetPointer(cmd_buff[1]);
+/**
+ * CSND_SND::Shutdown service function
+ * Inputs:
+ * 0 : Header Code[0x00020000]
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void Shutdown(Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
- if (shared_memory != nullptr && ptr != nullptr) {
- Type0Command command;
- std::memcpy(&command, ptr, sizeof(Type0Command));
+ shared_memory = nullptr;
+ mutex = nullptr;
- LOG_WARNING(Service, "(STUBBED) CSND_SND::ExecuteType0Commands");
- command.finished |= 1;
- cmd_buff[1] = 0;
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ LOG_WARNING(Service_CSND, "(STUBBED) called");
+}
- std::memcpy(ptr, &command, sizeof(Type0Command));
- } else {
+/**
+ * CSND_SND::ExecuteCommands service function
+ * Inputs:
+ * 0 : Header Code[0x00030040]
+ * 1 : Command offset in shared memory.
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Available channel bit mask
+ */
+static void ExecuteCommands(Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ if (shared_memory == nullptr) {
cmd_buff[1] = 1;
+ LOG_ERROR(Service_CSND, "called, shared memory not allocated");
+ return;
}
+
+ VAddr addr = cmd_buff[1];
+ u8* ptr = shared_memory->GetPointer(addr);
+
+ Type0Command command;
+ std::memcpy(&command, ptr, sizeof(Type0Command));
+ command.finished |= 1;
+ std::memcpy(ptr, &command, sizeof(Type0Command));
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_CSND, "(STUBBED) called, addr=0x%08X", addr);
}
-void AcquireSoundChannels(Service::Interface* self) {
+/**
+ * CSND_SND::AcquireSoundChannels service function
+ * Inputs:
+ * 0 : Header Code[0x00050000]
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Available channel bit mask
+ */
+static void AcquireSoundChannels(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- cmd_buff[1] = 0;
+ cmd_buff[1] = RESULT_SUCCESS.raw;
cmd_buff[2] = 0xFFFFFF00;
+ LOG_WARNING(Service_CSND, "(STUBBED) called");
}
-void Shutdown(Service::Interface* self) {
- shared_memory = nullptr;
- mutex = nullptr;
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010140, Initialize, "Initialize"},
+ {0x00020000, Shutdown, "Shutdown"},
+ {0x00030040, ExecuteCommands, "ExecuteCommands"},
+ {0x00040080, nullptr, "ExecuteType1Commands"},
+ {0x00050000, AcquireSoundChannels, "AcquireSoundChannels"},
+ {0x00060000, nullptr, "ReleaseSoundChannels"},
+ {0x00070000, nullptr, "AcquireCaptureDevice"},
+ {0x00080040, nullptr, "ReleaseCaptureDevice"},
+ {0x00090082, nullptr, "FlushDataCache"},
+ {0x000A0082, nullptr, "StoreDataCache"},
+ {0x000B0082, nullptr, "InvalidateDataCache"},
+ {0x000C0000, nullptr, "Reset"},
+};
+
+CSND_SND::CSND_SND() {
+ Register(FunctionTable);
}
-} // namespace
+} // namespace CSND
+} // namespace Service
diff --git a/src/core/hle/service/csnd_snd.h b/src/core/hle/service/csnd_snd.h
index a146d116b..ca6d4513e 100644
--- a/src/core/hle/service/csnd_snd.h
+++ b/src/core/hle/service/csnd_snd.h
@@ -6,31 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace CSND_SND
+namespace Service {
+namespace CSND {
-namespace CSND_SND {
-
-class Interface : public Service::Interface {
+class CSND_SND final : public Interface {
public:
- Interface();
+ CSND_SND();
std::string GetPortName() const override {
return "csnd:SND";
}
};
-struct Type0Command {
- // command id and next command offset
- u32 command_id;
- u32 finished;
- u32 flags;
- u8 parameters[20];
-};
-
-void Initialize(Service::Interface* self);
-void ExecuteType0Commands(Service::Interface* self);
-void AcquireSoundChannels(Service::Interface* self);
-void Shutdown(Service::Interface* self);
-
-} // namespace
+} // namespace CSND
+} // namespace Service
diff --git a/src/core/hle/service/dlp/dlp.h b/src/core/hle/service/dlp/dlp.h
index ec2fe46e8..3185fe322 100644
--- a/src/core/hle/service/dlp/dlp.h
+++ b/src/core/hle/service/dlp/dlp.h
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#pragma once
+
namespace Service {
namespace DLP {
diff --git a/src/core/hle/service/dlp/dlp_srvr.cpp b/src/core/hle/service/dlp/dlp_srvr.cpp
index 49d5b8d1c..25c07f401 100644
--- a/src/core/hle/service/dlp/dlp_srvr.cpp
+++ b/src/core/hle/service/dlp/dlp_srvr.cpp
@@ -22,7 +22,14 @@ static void unk_0x000E0040(Interface* self) {
const Interface::FunctionInfo FunctionTable[] = {
{0x00010183, nullptr, "Initialize"},
{0x00020000, nullptr, "Finalize"},
+ {0x00030000, nullptr, "GetServerState"},
+ {0x00050080, nullptr, "StartAccepting"},
+ {0x00070000, nullptr, "StartDistribution"},
{0x000800C0, nullptr, "SendWirelessRebootPassphrase"},
+ {0x00090040, nullptr, "AcceptClient"},
+ {0x000B0042, nullptr, "GetConnectingClients"},
+ {0x000C0040, nullptr, "GetClientInfo"},
+ {0x000D0040, nullptr, "GetClientState"},
{0x000E0040, unk_0x000E0040, "unk_0x000E0040"},
};
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index a15aa3696..fe8a6c2d6 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -12,9 +12,7 @@
using DspPipe = DSP::HLE::DspPipe;
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace DSP_DSP
-
+namespace Service {
namespace DSP_DSP {
static Kernel::SharedPtr<Kernel::Event> semaphore_event;
@@ -582,4 +580,5 @@ Interface::~Interface() {
interrupt_events = {};
}
-} // namespace
+} // namespace DSP_DSP
+} // namespace Service
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h
index 3e97da6eb..691d6f716 100644
--- a/src/core/hle/service/dsp_dsp.h
+++ b/src/core/hle/service/dsp_dsp.h
@@ -13,12 +13,10 @@ enum class DspPipe;
}
}
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace DSP_DSP
-
+namespace Service {
namespace DSP_DSP {
-class Interface : public Service::Interface {
+class Interface final : public Service::Interface {
public:
Interface();
~Interface() override;
@@ -35,3 +33,4 @@ public:
void SignalPipeInterrupt(DSP::HLE::DspPipe pipe);
} // namespace DSP_DSP
+} // namespace Service
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp
index 9905757c7..cd0a1a598 100644
--- a/src/core/hle/service/err_f.cpp
+++ b/src/core/hle/service/err_f.cpp
@@ -13,10 +13,8 @@
#include "core/hle/result.h"
#include "core/hle/service/err_f.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace ERR_F
-
-namespace ERR_F {
+namespace Service {
+namespace ERR {
enum class FatalErrType : u32 {
Generic = 0,
@@ -167,7 +165,7 @@ static void LogGenericInfo(const ErrInfo::ErrInfoCommon& errinfo_common) {
* 0 : Header code
* 1 : Result code
*/
-static void ThrowFatalError(Service::Interface* self) {
+static void ThrowFatalError(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
LOG_CRITICAL(Service_ERR, "Fatal error");
@@ -256,11 +254,9 @@ const Interface::FunctionInfo FunctionTable[] = {
// clang-format on
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+ERR_F::ERR_F() {
Register(FunctionTable);
}
-} // namespace
+} // namespace ERR
+} // namespace Service
diff --git a/src/core/hle/service/err_f.h b/src/core/hle/service/err_f.h
index 892d8af9b..5b27fc871 100644
--- a/src/core/hle/service/err_f.h
+++ b/src/core/hle/service/err_f.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace ERR_F
+namespace Service {
+namespace ERR {
-namespace ERR_F {
-
-class Interface : public Service::Interface {
+class ERR_F final : public Interface {
public:
- Interface();
+ ERR_F();
std::string GetPortName() const override {
return "err:f";
}
};
-} // namespace
+} // namespace ERR
+} // namespace Service
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index bef75f5df..6cddc1fdb 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -23,7 +23,7 @@
#include "core/file_sys/archive_systemsavedata.h"
#include "core/file_sys/directory_backend.h"
#include "core/file_sys/file_backend.h"
-#include "core/hle/hle.h"
+#include "core/hle/kernel/client_session.h"
#include "core/hle/result.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/fs/fs_user.h"
@@ -45,9 +45,7 @@ struct hash<Service::FS::ArchiveIdCode> {
};
}
-/// TODO(Subv): Confirm length of these strings
-const std::string SYSTEM_ID = "00000000000000000000000000000000";
-const std::string SDCARD_ID = "00000000000000000000000000000000";
+static constexpr Kernel::Handle INVALID_HANDLE{};
namespace Service {
namespace FS {
@@ -93,7 +91,7 @@ File::File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path&
File::~File() {}
-ResultVal<bool> File::SyncRequest() {
+void File::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) {
u32* cmd_buff = Kernel::GetCommandBuffer();
FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
switch (cmd) {
@@ -103,8 +101,8 @@ ResultVal<bool> File::SyncRequest() {
u64 offset = cmd_buff[1] | ((u64)cmd_buff[2]) << 32;
u32 length = cmd_buff[3];
u32 address = cmd_buff[5];
- LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x",
- GetTypeName().c_str(), GetName().c_str(), offset, length, address);
+ LOG_TRACE(Service_FS, "Read %s: offset=0x%llx length=%d address=0x%x", GetName().c_str(),
+ offset, length, address);
if (offset + length > backend->GetSize()) {
LOG_ERROR(Service_FS,
@@ -116,7 +114,7 @@ ResultVal<bool> File::SyncRequest() {
ResultVal<size_t> read = backend->Read(offset, data.size(), data.data());
if (read.Failed()) {
cmd_buff[1] = read.Code().raw;
- return read.Code();
+ return;
}
Memory::WriteBlock(address, data.data(), *read);
cmd_buff[2] = static_cast<u32>(*read);
@@ -129,22 +127,22 @@ ResultVal<bool> File::SyncRequest() {
u32 length = cmd_buff[3];
u32 flush = cmd_buff[4];
u32 address = cmd_buff[6];
- LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
- GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
+ LOG_TRACE(Service_FS, "Write %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
+ GetName().c_str(), offset, length, address, flush);
std::vector<u8> data(length);
Memory::ReadBlock(address, data.data(), data.size());
ResultVal<size_t> written = backend->Write(offset, data.size(), flush != 0, data.data());
if (written.Failed()) {
cmd_buff[1] = written.Code().raw;
- return written.Code();
+ return;
}
cmd_buff[2] = static_cast<u32>(*written);
break;
}
case FileCommand::GetSize: {
- LOG_TRACE(Service_FS, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str());
+ LOG_TRACE(Service_FS, "GetSize %s", GetName().c_str());
u64 size = backend->GetSize();
cmd_buff[2] = (u32)size;
cmd_buff[3] = size >> 32;
@@ -153,14 +151,13 @@ ResultVal<bool> File::SyncRequest() {
case FileCommand::SetSize: {
u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
- LOG_TRACE(Service_FS, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(),
- size);
+ LOG_TRACE(Service_FS, "SetSize %s size=%llu", GetName().c_str(), size);
backend->SetSize(size);
break;
}
case FileCommand::Close: {
- LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
+ LOG_TRACE(Service_FS, "Close %s", GetName().c_str());
backend->Close();
break;
}
@@ -173,7 +170,11 @@ ResultVal<bool> File::SyncRequest() {
case FileCommand::OpenLinkFile: {
LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str());
- cmd_buff[3] = Kernel::g_handle_table.Create(this).ValueOr(INVALID_HANDLE);
+ auto sessions = Kernel::ServerSession::CreateSessionPair(GetName(), shared_from_this());
+ ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
+ cmd_buff[3] = Kernel::g_handle_table
+ .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions))
+ .ValueOr(INVALID_HANDLE);
break;
}
@@ -194,10 +195,9 @@ ResultVal<bool> File::SyncRequest() {
LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd);
ResultCode error = UnimplementedFunction(ErrorModule::FS);
cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
- return error;
+ return;
}
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- return MakeResult<bool>(false);
}
Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend,
@@ -206,18 +206,16 @@ Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend,
Directory::~Directory() {}
-ResultVal<bool> Directory::SyncRequest() {
+void Directory::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) {
u32* cmd_buff = Kernel::GetCommandBuffer();
DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
switch (cmd) {
-
// Read from directory...
case DirectoryCommand::Read: {
u32 count = cmd_buff[1];
u32 address = cmd_buff[3];
std::vector<FileSys::Entry> entries(count);
- LOG_TRACE(Service_FS, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(),
- count);
+ LOG_TRACE(Service_FS, "Read %s: count=%d", GetName().c_str(), count);
// Number of entries actually read
u32 read = backend->Read(entries.size(), entries.data());
@@ -227,7 +225,7 @@ ResultVal<bool> Directory::SyncRequest() {
}
case DirectoryCommand::Close: {
- LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
+ LOG_TRACE(Service_FS, "Close %s", GetName().c_str());
backend->Close();
break;
}
@@ -237,10 +235,9 @@ ResultVal<bool> Directory::SyncRequest() {
LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd);
ResultCode error = UnimplementedFunction(ErrorModule::FS);
cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
- return MakeResult<bool>(false);
+ return;
}
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- return MakeResult<bool>(false);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -307,9 +304,9 @@ ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factor
return RESULT_SUCCESS;
}
-ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
- const FileSys::Path& path,
- const FileSys::Mode mode) {
+ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
+ const FileSys::Path& path,
+ const FileSys::Mode mode) {
ArchiveBackend* archive = GetArchive(archive_handle);
if (archive == nullptr)
return ERR_INVALID_ARCHIVE_HANDLE;
@@ -318,8 +315,8 @@ ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_han
if (backend.Failed())
return backend.Code();
- auto file = Kernel::SharedPtr<File>(new File(backend.MoveFrom(), path));
- return MakeResult<Kernel::SharedPtr<File>>(std::move(file));
+ auto file = std::shared_ptr<File>(new File(backend.MoveFrom(), path));
+ return MakeResult<std::shared_ptr<File>>(std::move(file));
}
ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) {
@@ -398,8 +395,8 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle,
}
}
-ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
- const FileSys::Path& path) {
+ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
+ const FileSys::Path& path) {
ArchiveBackend* archive = GetArchive(archive_handle);
if (archive == nullptr)
return ERR_INVALID_ARCHIVE_HANDLE;
@@ -408,8 +405,8 @@ ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle a
if (backend.Failed())
return backend.Code();
- auto directory = Kernel::SharedPtr<Directory>(new Directory(backend.MoveFrom(), path));
- return MakeResult<Kernel::SharedPtr<Directory>>(std::move(directory));
+ auto directory = std::shared_ptr<Directory>(new Directory(backend.MoveFrom(), path));
+ return MakeResult<std::shared_ptr<Directory>>(std::move(directory));
}
ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) {
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index 87089bd92..519c1f3a9 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -8,7 +8,7 @@
#include <string>
#include "common/common_types.h"
#include "core/file_sys/archive_backend.h"
-#include "core/hle/kernel/session.h"
+#include "core/hle/kernel/server_session.h"
#include "core/hle/result.h"
namespace FileSys {
@@ -17,9 +17,9 @@ class FileBackend;
}
/// The unique system identifier hash, also known as ID0
-extern const std::string SYSTEM_ID;
+static constexpr char SYSTEM_ID[]{"00000000000000000000000000000000"};
/// The scrambled SD card CID, also known as ID1
-extern const std::string SDCARD_ID;
+static constexpr char SDCARD_ID[]{"00000000000000000000000000000000"};
namespace Service {
namespace FS {
@@ -43,33 +43,37 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 };
typedef u64 ArchiveHandle;
-class File : public Kernel::Session {
+class File final : public SessionRequestHandler, public std::enable_shared_from_this<File> {
public:
File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path);
~File();
- std::string GetName() const override {
+ std::string GetName() const {
return "Path: " + path.DebugStr();
}
- ResultVal<bool> SyncRequest() override;
FileSys::Path path; ///< Path of the file
u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means
std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface
+
+protected:
+ void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override;
};
-class Directory : public Kernel::Session {
+class Directory final : public SessionRequestHandler {
public:
Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path);
~Directory();
- std::string GetName() const override {
+ std::string GetName() const {
return "Directory: " + path.DebugStr();
}
- ResultVal<bool> SyncRequest() override;
FileSys::Path path; ///< Path of the directory
std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface
+
+protected:
+ void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override;
};
/**
@@ -99,11 +103,11 @@ ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factor
* @param archive_handle Handle to an open Archive object
* @param path Path to the File inside of the Archive
* @param mode Mode under which to open the File
- * @return The opened File object as a Session
+ * @return The opened File object
*/
-ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
- const FileSys::Path& path,
- const FileSys::Mode mode);
+ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
+ const FileSys::Path& path,
+ const FileSys::Mode mode);
/**
* Delete a File from an Archive
@@ -178,10 +182,10 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle,
* Open a Directory from an Archive
* @param archive_handle Handle to an open Archive object
* @param path Path to the Directory inside of the Archive
- * @return The opened Directory object as a Session
+ * @return The opened Directory object
*/
-ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
- const FileSys::Path& path);
+ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
+ const FileSys::Path& path);
/**
* Get the free space in an Archive
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index 9ec17b395..337da1387 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -8,6 +8,7 @@
#include "common/logging/log.h"
#include "common/scope_exit.h"
#include "common/string_util.h"
+#include "core/hle/kernel/client_session.h"
#include "core/hle/result.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/fs/fs_user.h"
@@ -17,7 +18,7 @@
// Namespace FS_User
using Kernel::SharedPtr;
-using Kernel::Session;
+using Kernel::ServerSession;
namespace Service {
namespace FS {
@@ -67,10 +68,16 @@ static void OpenFile(Service::Interface* self) {
LOG_DEBUG(Service_FS, "path=%s, mode=%u attrs=%u", file_path.DebugStr().c_str(), mode.hex,
attributes);
- ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(archive_handle, file_path, mode);
+ ResultVal<std::shared_ptr<File>> file_res =
+ OpenFileFromArchive(archive_handle, file_path, mode);
cmd_buff[1] = file_res.Code().raw;
if (file_res.Succeeded()) {
- cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom();
+ std::shared_ptr<File> file = *file_res;
+ auto sessions = ServerSession::CreateSessionPair(file->GetName(), file);
+ file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
+ cmd_buff[3] = Kernel::g_handle_table
+ .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions))
+ .MoveFrom();
} else {
cmd_buff[3] = 0;
LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str());
@@ -127,10 +134,16 @@ static void OpenFileDirectly(Service::Interface* self) {
}
SCOPE_EXIT({ CloseArchive(*archive_handle); });
- ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(*archive_handle, file_path, mode);
+ ResultVal<std::shared_ptr<File>> file_res =
+ OpenFileFromArchive(*archive_handle, file_path, mode);
cmd_buff[1] = file_res.Code().raw;
if (file_res.Succeeded()) {
- cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom();
+ std::shared_ptr<File> file = *file_res;
+ auto sessions = ServerSession::CreateSessionPair(file->GetName(), file);
+ file->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
+ cmd_buff[3] = Kernel::g_handle_table
+ .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions))
+ .MoveFrom();
} else {
cmd_buff[3] = 0;
LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%u",
@@ -388,10 +401,16 @@ static void OpenDirectory(Service::Interface* self) {
LOG_DEBUG(Service_FS, "type=%u size=%u data=%s", static_cast<u32>(dirname_type), dirname_size,
dir_path.DebugStr().c_str());
- ResultVal<SharedPtr<Directory>> dir_res = OpenDirectoryFromArchive(archive_handle, dir_path);
+ ResultVal<std::shared_ptr<Directory>> dir_res =
+ OpenDirectoryFromArchive(archive_handle, dir_path);
cmd_buff[1] = dir_res.Code().raw;
if (dir_res.Succeeded()) {
- cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom();
+ std::shared_ptr<Directory> directory = *dir_res;
+ auto sessions = ServerSession::CreateSessionPair(directory->GetName(), directory);
+ directory->ClientConnected(std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions));
+ cmd_buff[3] = Kernel::g_handle_table
+ .Create(std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions))
+ .MoveFrom();
} else {
LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s",
dirname_type, dirname_size, dir_path.DebugStr().c_str());
@@ -1003,6 +1022,8 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x08680000, nullptr, "GetMediaType"},
{0x08690000, nullptr, "GetNandEraseCount"},
{0x086A0082, nullptr, "ReadNandReport"},
+ {0x087A0180, nullptr, "AddSeed"},
+ {0x088600C0, nullptr, "CheckUpdatedDat"},
};
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 78cb761be..947958703 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -18,13 +18,11 @@
// Main graphics debugger object - TODO: Here is probably not the best place for this
GraphicsDebugger g_debugger;
-// Beginning address of HW regs
-const static u32 REGS_BEGIN = 0x1EB00000;
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace GSP_GPU
+namespace Service {
+namespace GSP {
-namespace GSP_GPU {
+// Beginning address of HW regs
+const u32 REGS_BEGIN = 0x1EB00000;
const ResultCode ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED(
ErrorDescription::OutofRangeOrMisalignedAddress, ErrorModule::GX, ErrorSummary::InvalidArgument,
@@ -179,7 +177,7 @@ static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, VAddr
* 2 : number of registers to write sequentially
* 4 : pointer to source data array
*/
-static void WriteHWRegs(Service::Interface* self) {
+static void WriteHWRegs(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 reg_addr = cmd_buff[1];
u32 size = cmd_buff[2];
@@ -199,7 +197,7 @@ static void WriteHWRegs(Service::Interface* self) {
* 4 : pointer to source data array
* 6 : pointer to mask array
*/
-static void WriteHWRegsWithMask(Service::Interface* self) {
+static void WriteHWRegsWithMask(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 reg_addr = cmd_buff[1];
u32 size = cmd_buff[2];
@@ -211,7 +209,7 @@ static void WriteHWRegsWithMask(Service::Interface* self) {
}
/// Read a GSP GPU hardware register
-static void ReadHWRegs(Service::Interface* self) {
+static void ReadHWRegs(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 reg_addr = cmd_buff[1];
u32 size = cmd_buff[2];
@@ -298,7 +296,7 @@ ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
* Outputs:
* 1: Result code
*/
-static void SetBufferSwap(Service::Interface* self) {
+static void SetBufferSwap(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 screen_id = cmd_buff[1];
FrameBufferInfo* fb_info = (FrameBufferInfo*)&cmd_buff[2];
@@ -319,7 +317,7 @@ static void SetBufferSwap(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void FlushDataCache(Service::Interface* self) {
+static void FlushDataCache(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 address = cmd_buff[1];
u32 size = cmd_buff[2];
@@ -340,7 +338,7 @@ static void FlushDataCache(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetAxiConfigQoSMode(Service::Interface* self) {
+static void SetAxiConfigQoSMode(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 mode = cmd_buff[1];
@@ -359,7 +357,7 @@ static void SetAxiConfigQoSMode(Service::Interface* self) {
* 2 : Thread index into GSP command buffer
* 4 : Handle to GSP shared memory
*/
-static void RegisterInterruptRelayQueue(Service::Interface* self) {
+static void RegisterInterruptRelayQueue(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 flags = cmd_buff[1];
@@ -391,7 +389,7 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void UnregisterInterruptRelayQueue(Service::Interface* self) {
+static void UnregisterInterruptRelayQueue(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
g_thread_id = 0;
@@ -592,7 +590,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
* Outputs:
* 1: Result code
*/
-static void SetLcdForceBlack(Service::Interface* self) {
+static void SetLcdForceBlack(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
bool enable_black = cmd_buff[1] != 0;
@@ -609,7 +607,7 @@ static void SetLcdForceBlack(Service::Interface* self) {
}
/// This triggers handling of the GX command written to the command buffer in shared memory.
-static void TriggerCmdReqQueue(Service::Interface* self) {
+static void TriggerCmdReqQueue(Interface* self) {
// Iterate through each thread's command queue...
for (unsigned thread_id = 0; thread_id < 0x4; ++thread_id) {
CommandBuffer* command_buffer = (CommandBuffer*)GetCommandBuffer(thread_id);
@@ -638,6 +636,7 @@ static void TriggerCmdReqQueue(Service::Interface* self) {
* Inputs:
* 0: Header 0x00180000
* Outputs:
+ * 0: Header Code[0x00180240]
* 1: Result code
* 2: Left framebuffer virtual address for the main screen
* 3: Right framebuffer virtual address for the main screen
@@ -648,7 +647,7 @@ static void TriggerCmdReqQueue(Service::Interface* self) {
* 8: Bottom screen framebuffer format
* 9: Bottom screen framebuffer width
*/
-static void ImportDisplayCaptureInfo(Service::Interface* self) {
+static void ImportDisplayCaptureInfo(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
// TODO(Subv): We're always returning the framebuffer structures for thread_id = 0,
@@ -660,18 +659,19 @@ static void ImportDisplayCaptureInfo(Service::Interface* self) {
FrameBufferUpdate* top_screen = GetFrameBufferInfo(thread_id, 0);
FrameBufferUpdate* bottom_screen = GetFrameBufferInfo(thread_id, 1);
+ cmd_buff[0] = IPC::MakeHeader(0x18, 0x9, 0);
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ // Top Screen
cmd_buff[2] = top_screen->framebuffer_info[top_screen->index].address_left;
cmd_buff[3] = top_screen->framebuffer_info[top_screen->index].address_right;
cmd_buff[4] = top_screen->framebuffer_info[top_screen->index].format;
cmd_buff[5] = top_screen->framebuffer_info[top_screen->index].stride;
-
+ // Bottom Screen
cmd_buff[6] = bottom_screen->framebuffer_info[bottom_screen->index].address_left;
cmd_buff[7] = bottom_screen->framebuffer_info[bottom_screen->index].address_right;
cmd_buff[8] = bottom_screen->framebuffer_info[bottom_screen->index].format;
cmd_buff[9] = bottom_screen->framebuffer_info[bottom_screen->index].stride;
- cmd_buff[1] = RESULT_SUCCESS.raw;
-
LOG_WARNING(Service_GSP, "called");
}
@@ -680,7 +680,7 @@ static void ImportDisplayCaptureInfo(Service::Interface* self) {
* Outputs:
* 1: Result code
*/
-static void AcquireRight(Service::Interface* self) {
+static void AcquireRight(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
gpu_right_acquired = true;
@@ -695,7 +695,7 @@ static void AcquireRight(Service::Interface* self) {
* Outputs:
* 1: Result code
*/
-static void ReleaseRight(Service::Interface* self) {
+static void ReleaseRight(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
gpu_right_acquired = false;
@@ -739,10 +739,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x001F0082, nullptr, "StoreDataCache"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+GSP_GPU::GSP_GPU() {
Register(FunctionTable);
g_interrupt_event = nullptr;
@@ -757,10 +754,11 @@ Interface::Interface() {
first_initialization = true;
}
-Interface::~Interface() {
+GSP_GPU::~GSP_GPU() {
g_interrupt_event = nullptr;
g_shared_memory = nullptr;
gpu_right_acquired = false;
}
-} // namespace
+} // namespace GSP
+} // namespace Service
diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h
index 79a72f77d..c6e24073b 100644
--- a/src/core/hle/service/gsp_gpu.h
+++ b/src/core/hle/service/gsp_gpu.h
@@ -11,10 +11,8 @@
#include "core/hle/result.h"
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace GSP_GPU
-
-namespace GSP_GPU {
+namespace Service {
+namespace GSP {
/// GSP interrupt ID
enum class InterruptId : u8 {
@@ -176,11 +174,10 @@ struct CommandBuffer {
};
static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size");
-/// Interface to "srv:" service
-class Interface : public Service::Interface {
+class GSP_GPU final : public Interface {
public:
- Interface();
- ~Interface() override;
+ GSP_GPU();
+ ~GSP_GPU() override;
std::string GetPortName() const override {
return "gsp::Gpu";
@@ -203,4 +200,6 @@ ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info);
* @returns FramebufferUpdate Information about the specified framebuffer.
*/
FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index);
-} // namespace
+
+} // namespace GSP
+} // namespace Service
diff --git a/src/core/hle/service/gsp_lcd.cpp b/src/core/hle/service/gsp_lcd.cpp
index b916dd759..89cb4a3cc 100644
--- a/src/core/hle/service/gsp_lcd.cpp
+++ b/src/core/hle/service/gsp_lcd.cpp
@@ -4,26 +4,26 @@
#include "core/hle/service/gsp_lcd.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace GSP_LCD
-
-namespace GSP_LCD {
+namespace Service {
+namespace GSP {
const Interface::FunctionInfo FunctionTable[] = {
// clang-format off
+ {0x000A0080, nullptr, "SetBrightnessRaw"},
+ {0x000B0080, nullptr, "SetBrightness"},
{0x000F0000, nullptr, "PowerOnAllBacklights"},
{0x00100000, nullptr, "PowerOffAllBacklights"},
{0x00110040, nullptr, "PowerOnBacklight"},
{0x00120040, nullptr, "PowerOffBacklight"},
{0x00130040, nullptr, "SetLedForceOff"},
+ {0x00140000, nullptr, "GetVendor"},
+ {0x00150040, nullptr, "GetBrightness"},
// clang-format on
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+GSP_LCD::GSP_LCD() {
Register(FunctionTable);
}
-} // namespace
+} // namespace GSP
+} // namespace Service
diff --git a/src/core/hle/service/gsp_lcd.h b/src/core/hle/service/gsp_lcd.h
index 56b3cfe86..e9686a5e7 100644
--- a/src/core/hle/service/gsp_lcd.h
+++ b/src/core/hle/service/gsp_lcd.h
@@ -6,19 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace GSP_LCD
+namespace Service {
+namespace GSP {
-namespace GSP_LCD {
-
-/// Interface to "gsp::Lcd" service
-class Interface : public Service::Interface {
+class GSP_LCD final : public Interface {
public:
- Interface();
+ GSP_LCD();
std::string GetPortName() const override {
return "gsp::Lcd";
}
};
-} // namespace
+} // namespace GSP
+} // namespace Service
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 99baded11..676154bd4 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -3,9 +3,9 @@
// Refer to the license.txt file included.
#include <cmath>
-#include "common/emu_window.h"
#include "common/logging/log.h"
#include "core/core_timing.h"
+#include "core/frontend/emu_window.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/hid/hid.h"
@@ -37,7 +37,8 @@ static int enable_gyroscope_count = 0; // positive means enabled
static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) {
// 30 degree and 60 degree are angular thresholds for directions
- constexpr float TAN30 = 0.577350269, TAN60 = 1 / TAN30;
+ constexpr float TAN30 = 0.577350269f;
+ constexpr float TAN60 = 1 / TAN30;
// a circle pad radius greater than 40 will trigger circle pad direction
constexpr int CIRCLE_PAD_THRESHOLD_SQUARE = 40 * 40;
PadState state;
diff --git a/src/core/hle/service/http_c.cpp b/src/core/hle/service/http_c.cpp
index 3cf62a4b8..b01d6e031 100644
--- a/src/core/hle/service/http_c.cpp
+++ b/src/core/hle/service/http_c.cpp
@@ -4,10 +4,8 @@
#include "core/hle/service/http_c.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace HTTP_C
-
-namespace HTTP_C {
+namespace Service {
+namespace HTTP {
const Interface::FunctionInfo FunctionTable[] = {
{0x00010044, nullptr, "Initialize"},
@@ -55,6 +53,10 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x002E0040, nullptr, "DestroyRootCertChain"},
{0x002F0082, nullptr, "RootCertChainAddCert"},
{0x00300080, nullptr, "RootCertChainAddDefaultCert"},
+ {0x00310080, nullptr, "RootCertChainRemoveCert"},
+ {0x00320084, nullptr, "OpenClientCertContext"},
+ {0x00330040, nullptr, "OpenDefaultClientCertContext"},
+ {0x00340040, nullptr, "CloseClientCertContext"},
{0x00350186, nullptr, "SetDefaultProxy"},
{0x00360000, nullptr, "ClearDNSCache"},
{0x00370080, nullptr, "SetKeepAlive"},
@@ -62,11 +64,9 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00390000, nullptr, "Finalize"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+HTTP_C::HTTP_C() {
Register(FunctionTable);
}
-} // namespace
+} // namespace HTTP
+} // namespace Service
diff --git a/src/core/hle/service/http_c.h b/src/core/hle/service/http_c.h
index 5ea3d1df3..cff279c02 100644
--- a/src/core/hle/service/http_c.h
+++ b/src/core/hle/service/http_c.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace HTTP_C
+namespace Service {
+namespace HTTP {
-namespace HTTP_C {
-
-class Interface : public Service::Interface {
+class HTTP_C final : public Interface {
public:
- Interface();
+ HTTP_C();
std::string GetPortName() const override {
return "http:C";
}
};
-} // namespace
+} // namespace HTTP
+} // namespace Service
diff --git a/src/core/hle/service/ir/ir.cpp b/src/core/hle/service/ir/ir.cpp
index 4d6639ded..7f1731a50 100644
--- a/src/core/hle/service/ir/ir.cpp
+++ b/src/core/hle/service/ir/ir.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/ir/ir.h"
#include "core/hle/service/ir/ir_rst.h"
@@ -36,7 +37,7 @@ void InitializeIrNopShared(Interface* self) {
u32 send_buff_size = cmd_buff[4];
u32 unk2 = cmd_buff[5];
u8 baud_rate = cmd_buff[6] & 0xFF;
- Handle handle = cmd_buff[8];
+ Kernel::Handle handle = cmd_buff[8];
if (Kernel::g_handle_table.IsValid(handle)) {
transfer_shared_memory = Kernel::g_handle_table.Get<Kernel::SharedMemory>(handle);
diff --git a/src/core/hle/service/ldr_ro/cro_helper.cpp b/src/core/hle/service/ldr_ro/cro_helper.cpp
index 4f0aa77eb..f78545f37 100644
--- a/src/core/hle/service/ldr_ro/cro_helper.cpp
+++ b/src/core/hle/service/ldr_ro/cro_helper.cpp
@@ -7,10 +7,8 @@
#include "common/scope_exit.h"
#include "core/hle/service/ldr_ro/cro_helper.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace LDR_RO
-
-namespace LDR_RO {
+namespace Service {
+namespace LDR {
static const ResultCode ERROR_BUFFER_TOO_SMALL = // 0xE0E12C1F
ResultCode(static_cast<ErrorDescription>(31), ErrorModule::RO, ErrorSummary::InvalidArgument,
@@ -1493,4 +1491,5 @@ std::tuple<VAddr, u32> CROHelper::GetExecutablePages() const {
return std::make_tuple(0, 0);
}
-} // namespace
+} // namespace LDR
+} // namespace Service
diff --git a/src/core/hle/service/ldr_ro/cro_helper.h b/src/core/hle/service/ldr_ro/cro_helper.h
index 6a0d0d3bf..060d5a55f 100644
--- a/src/core/hle/service/ldr_ro/cro_helper.h
+++ b/src/core/hle/service/ldr_ro/cro_helper.h
@@ -11,10 +11,8 @@
#include "core/hle/result.h"
#include "core/memory.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace LDR_RO
-
-namespace LDR_RO {
+namespace Service {
+namespace LDR {
// GCC versions < 5.0 do not implement std::is_trivially_copyable.
// Excluding MSVC because it has weird behaviour for std::is_trivially_copyable.
@@ -710,4 +708,5 @@ private:
ResultCode ApplyExitRelocations(VAddr crs_address);
};
-} // namespace
+} // namespace LDR
+} // namespace Service
diff --git a/src/core/hle/service/ldr_ro/ldr_ro.cpp b/src/core/hle/service/ldr_ro/ldr_ro.cpp
index ec183d1f5..8d00a7577 100644
--- a/src/core/hle/service/ldr_ro/ldr_ro.cpp
+++ b/src/core/hle/service/ldr_ro/ldr_ro.cpp
@@ -12,10 +12,8 @@
#include "core/hle/service/ldr_ro/ldr_ro.h"
#include "core/hle/service/ldr_ro/memory_synchronizer.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace LDR_RO
-
-namespace LDR_RO {
+namespace Service {
+namespace LDR {
static const ResultCode ERROR_ALREADY_INITIALIZED = // 0xD9612FF9
ResultCode(ErrorDescription::AlreadyInitialized, ErrorModule::RO, ErrorSummary::Internal,
@@ -71,7 +69,7 @@ static bool VerifyBufferState(VAddr buffer_ptr, u32 size) {
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void Initialize(Service::Interface* self) {
+static void Initialize(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
VAddr crs_buffer_ptr = cmd_buff[1];
u32 crs_size = cmd_buff[2];
@@ -196,7 +194,7 @@ static void Initialize(Service::Interface* self) {
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void LoadCRR(Service::Interface* self) {
+static void LoadCRR(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 crr_buffer_ptr = cmd_buff[1];
u32 crr_size = cmd_buff[2];
@@ -229,7 +227,7 @@ static void LoadCRR(Service::Interface* self) {
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void UnloadCRR(Service::Interface* self) {
+static void UnloadCRR(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 crr_buffer_ptr = cmd_buff[1];
u32 descriptor = cmd_buff[2];
@@ -276,7 +274,7 @@ static void UnloadCRR(Service::Interface* self) {
* unified one of two, with an additional parameter link_on_load_bug_fix.
* There is a dispatcher template below.
*/
-static void LoadCRO(Service::Interface* self, bool link_on_load_bug_fix) {
+static void LoadCRO(Interface* self, bool link_on_load_bug_fix) {
u32* cmd_buff = Kernel::GetCommandBuffer();
VAddr cro_buffer_ptr = cmd_buff[1];
VAddr cro_address = cmd_buff[2];
@@ -459,7 +457,7 @@ static void LoadCRO(Service::Interface* self, bool link_on_load_bug_fix) {
}
}
- Core::g_app_core->ClearInstructionCache();
+ Core::CPU().ClearInstructionCache();
LOG_INFO(Service_LDR, "CRO \"%s\" loaded at 0x%08X, fixed_end=0x%08X", cro.ModuleName().data(),
cro_address, cro_address + fix_size);
@@ -469,7 +467,7 @@ static void LoadCRO(Service::Interface* self, bool link_on_load_bug_fix) {
}
template <bool link_on_load_bug_fix>
-static void LoadCRO(Service::Interface* self) {
+static void LoadCRO(Interface* self) {
LoadCRO(self, link_on_load_bug_fix);
}
@@ -486,7 +484,7 @@ static void LoadCRO(Service::Interface* self) {
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void UnloadCRO(Service::Interface* self) {
+static void UnloadCRO(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
VAddr cro_address = cmd_buff[1];
u32 zero = cmd_buff[2];
@@ -564,7 +562,7 @@ static void UnloadCRO(Service::Interface* self) {
memory_synchronizer.RemoveMemoryBlock(cro_address, cro_buffer_ptr);
}
- Core::g_app_core->ClearInstructionCache();
+ Core::CPU().ClearInstructionCache();
cmd_buff[1] = result.raw;
}
@@ -580,7 +578,7 @@ static void UnloadCRO(Service::Interface* self) {
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void LinkCRO(Service::Interface* self) {
+static void LinkCRO(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
VAddr cro_address = cmd_buff[1];
u32 descriptor = cmd_buff[2];
@@ -626,7 +624,7 @@ static void LinkCRO(Service::Interface* self) {
}
memory_synchronizer.SynchronizeOriginalMemory();
- Core::g_app_core->ClearInstructionCache();
+ Core::CPU().ClearInstructionCache();
cmd_buff[1] = result.raw;
}
@@ -642,7 +640,7 @@ static void LinkCRO(Service::Interface* self) {
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void UnlinkCRO(Service::Interface* self) {
+static void UnlinkCRO(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
VAddr cro_address = cmd_buff[1];
u32 descriptor = cmd_buff[2];
@@ -688,7 +686,7 @@ static void UnlinkCRO(Service::Interface* self) {
}
memory_synchronizer.SynchronizeOriginalMemory();
- Core::g_app_core->ClearInstructionCache();
+ Core::CPU().ClearInstructionCache();
cmd_buff[1] = result.raw;
}
@@ -704,7 +702,7 @@ static void UnlinkCRO(Service::Interface* self) {
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void Shutdown(Service::Interface* self) {
+static void Shutdown(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
VAddr crs_buffer_ptr = cmd_buff[1];
u32 descriptor = cmd_buff[2];
@@ -762,14 +760,12 @@ const Interface::FunctionInfo FunctionTable[] = {
// clang-format on
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+LDR_RO::LDR_RO() {
Register(FunctionTable);
loaded_crs = 0;
memory_synchronizer.Clear();
}
-} // namespace
+} // namespace LDR
+} // namespace Service
diff --git a/src/core/hle/service/ldr_ro/ldr_ro.h b/src/core/hle/service/ldr_ro/ldr_ro.h
index 331637cde..0f6fe7b60 100644
--- a/src/core/hle/service/ldr_ro/ldr_ro.h
+++ b/src/core/hle/service/ldr_ro/ldr_ro.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace LDR_RO
+namespace Service {
+namespace LDR {
-namespace LDR_RO {
-
-class Interface : public Service::Interface {
+class LDR_RO final : public Interface {
public:
- Interface();
+ LDR_RO();
std::string GetPortName() const override {
return "ldr:ro";
}
};
-} // namespace
+} // namespace LDR
+} // namespace Service
diff --git a/src/core/hle/service/ldr_ro/memory_synchronizer.cpp b/src/core/hle/service/ldr_ro/memory_synchronizer.cpp
index 989887264..0d44bf6bd 100644
--- a/src/core/hle/service/ldr_ro/memory_synchronizer.cpp
+++ b/src/core/hle/service/ldr_ro/memory_synchronizer.cpp
@@ -6,10 +6,8 @@
#include "common/assert.h"
#include "core/hle/service/ldr_ro/memory_synchronizer.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace LDR_RO
-
-namespace LDR_RO {
+namespace Service {
+namespace LDR {
auto MemorySynchronizer::FindMemoryBlock(VAddr mapping, VAddr original) {
auto block = std::find_if(memory_blocks.begin(), memory_blocks.end(),
@@ -40,4 +38,5 @@ void MemorySynchronizer::SynchronizeOriginalMemory() {
}
}
-} // namespace
+} // namespace LDR
+} // namespace Service
diff --git a/src/core/hle/service/ldr_ro/memory_synchronizer.h b/src/core/hle/service/ldr_ro/memory_synchronizer.h
index 883ee4acf..438293a58 100644
--- a/src/core/hle/service/ldr_ro/memory_synchronizer.h
+++ b/src/core/hle/service/ldr_ro/memory_synchronizer.h
@@ -7,10 +7,8 @@
#include <vector>
#include "core/memory.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace LDR_RO
-
-namespace LDR_RO {
+namespace Service {
+namespace LDR {
/**
* This is a work-around before we implement memory aliasing.
@@ -40,4 +38,5 @@ private:
auto FindMemoryBlock(VAddr mapping, VAddr original);
};
-} // namespace
+} // namespace LDR
+} // namespace Service
diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp
index 1f851d328..4f1dd2fce 100644
--- a/src/core/hle/service/mic_u.cpp
+++ b/src/core/hle/service/mic_u.cpp
@@ -4,13 +4,12 @@
#include "common/logging/log.h"
#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/mic_u.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace MIC_U
-
-namespace MIC_U {
+namespace Service {
+namespace MIC {
enum class Encoding : u8 {
PCM8 = 0,
@@ -49,10 +48,10 @@ static bool audio_buffer_loop;
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void MapSharedMem(Service::Interface* self) {
+static void MapSharedMem(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 size = cmd_buff[1];
- Handle mem_handle = cmd_buff[3];
+ Kernel::Handle mem_handle = cmd_buff[3];
shared_memory = Kernel::g_handle_table.Get<Kernel::SharedMemory>(mem_handle);
if (shared_memory) {
shared_memory->name = "MIC_U:shared_memory";
@@ -68,7 +67,7 @@ static void MapSharedMem(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void UnmapSharedMem(Service::Interface* self) {
+static void UnmapSharedMem(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -87,7 +86,7 @@ static void UnmapSharedMem(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void StartSampling(Service::Interface* self) {
+static void StartSampling(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
encoding = static_cast<Encoding>(cmd_buff[1] & 0xFF);
@@ -111,7 +110,7 @@ static void StartSampling(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void AdjustSampling(Service::Interface* self) {
+static void AdjustSampling(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
sample_rate = static_cast<SampleRate>(cmd_buff[1] & 0xFF);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -125,7 +124,7 @@ static void AdjustSampling(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void StopSampling(Service::Interface* self) {
+static void StopSampling(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
is_sampling = false;
@@ -140,7 +139,7 @@ static void StopSampling(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : 0 = sampling, non-zero = sampling
*/
-static void IsSampling(Service::Interface* self) {
+static void IsSampling(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = is_sampling;
@@ -155,7 +154,7 @@ static void IsSampling(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 3 : Event handle
*/
-static void GetBufferFullEvent(Service::Interface* self) {
+static void GetBufferFullEvent(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[3] = Kernel::g_handle_table.Create(buffer_full_event).MoveFrom();
@@ -170,7 +169,7 @@ static void GetBufferFullEvent(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetGain(Service::Interface* self) {
+static void SetGain(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
mic_gain = cmd_buff[1] & 0xFF;
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -185,7 +184,7 @@ static void SetGain(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Gain
*/
-static void GetGain(Service::Interface* self) {
+static void GetGain(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = mic_gain;
@@ -200,7 +199,7 @@ static void GetGain(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetPower(Service::Interface* self) {
+static void SetPower(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
mic_power = static_cast<bool>(cmd_buff[1] & 0xFF);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -215,7 +214,7 @@ static void SetPower(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Power
*/
-static void GetPower(Service::Interface* self) {
+static void GetPower(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = mic_power;
@@ -232,7 +231,7 @@ static void GetPower(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetIirFilterMic(Service::Interface* self) {
+static void SetIirFilterMic(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 size = cmd_buff[1];
@@ -250,7 +249,7 @@ static void SetIirFilterMic(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetClamp(Service::Interface* self) {
+static void SetClamp(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
clamp = static_cast<bool>(cmd_buff[1] & 0xFF);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -265,7 +264,7 @@ static void SetClamp(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Clamp (0 = don't clamp, non-zero = clamp)
*/
-static void GetClamp(Service::Interface* self) {
+static void GetClamp(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = clamp;
@@ -280,7 +279,7 @@ static void GetClamp(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetAllowShellClosed(Service::Interface* self) {
+static void SetAllowShellClosed(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
allow_shell_closed = static_cast<bool>(cmd_buff[1] & 0xFF);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
@@ -294,7 +293,7 @@ static void SetAllowShellClosed(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetClientVersion(Service::Interface* self) {
+static void SetClientVersion(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
const u32 version = cmd_buff[1];
@@ -324,10 +323,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00100040, SetClientVersion, "SetClientVersion"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+MIC_U::MIC_U() {
Register(FunctionTable);
shared_memory = nullptr;
buffer_full_event =
@@ -338,9 +334,10 @@ Interface::Interface() {
clamp = false;
}
-Interface::~Interface() {
+MIC_U::~MIC_U() {
shared_memory = nullptr;
buffer_full_event = nullptr;
}
-} // namespace
+} // namespace MIC
+} // namespace Service
diff --git a/src/core/hle/service/mic_u.h b/src/core/hle/service/mic_u.h
index 1cff7390e..ec2b67ab8 100644
--- a/src/core/hle/service/mic_u.h
+++ b/src/core/hle/service/mic_u.h
@@ -6,21 +6,18 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace MIC_U
+namespace Service {
+namespace MIC {
-// mic service
-
-namespace MIC_U {
-
-class Interface : public Service::Interface {
+class MIC_U final : public Interface {
public:
- Interface();
- ~Interface();
+ MIC_U();
+ ~MIC_U();
std::string GetPortName() const override {
return "mic:u";
}
};
-} // namespace
+} // namespace MIC
+} // namespace Service
diff --git a/src/core/hle/service/mvd/mvd.cpp b/src/core/hle/service/mvd/mvd.cpp
new file mode 100644
index 000000000..9416fe5d6
--- /dev/null
+++ b/src/core/hle/service/mvd/mvd.cpp
@@ -0,0 +1,17 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/mvd/mvd.h"
+#include "core/hle/service/mvd/mvd_std.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace MVD {
+
+void Init() {
+ AddService(new MVD_STD());
+}
+
+} // namespace MVD
+} // namespace Service
diff --git a/src/core/hle/service/mvd/mvd.h b/src/core/hle/service/mvd/mvd.h
new file mode 100644
index 000000000..7b212e839
--- /dev/null
+++ b/src/core/hle/service/mvd/mvd.h
@@ -0,0 +1,14 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service {
+namespace MVD {
+
+/// Initializes all MVD services.
+void Init();
+
+} // namespace MVD
+} // namespace Service
diff --git a/src/core/hle/service/mvd/mvd_std.cpp b/src/core/hle/service/mvd/mvd_std.cpp
new file mode 100644
index 000000000..fd7ca87d3
--- /dev/null
+++ b/src/core/hle/service/mvd/mvd_std.cpp
@@ -0,0 +1,32 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/mvd/mvd_std.h"
+
+namespace Service {
+namespace MVD {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // clang-format off
+ {0x00010082, nullptr, "Initialize"},
+ {0x00020000, nullptr, "Shutdown"},
+ {0x00030300, nullptr, "CalculateWorkBufSize"},
+ {0x000400C0, nullptr, "CalculateImageSize"},
+ {0x00080142, nullptr, "ProcessNALUnit"},
+ {0x00090042, nullptr, "ControlFrameRendering"},
+ {0x000A0000, nullptr, "GetStatus"},
+ {0x000B0000, nullptr, "GetStatusOther"},
+ {0x001D0042, nullptr, "GetConfig"},
+ {0x001E0044, nullptr, "SetConfig"},
+ {0x001F0902, nullptr, "SetOutputBuffer"},
+ {0x00210100, nullptr, "OverrideOutputBuffers"}
+ // clang-format on
+};
+
+MVD_STD::MVD_STD() {
+ Register(FunctionTable);
+}
+
+} // namespace MVD
+} // namespace Service
diff --git a/src/core/hle/service/mvd/mvd_std.h b/src/core/hle/service/mvd/mvd_std.h
new file mode 100644
index 000000000..7db9e2e50
--- /dev/null
+++ b/src/core/hle/service/mvd/mvd_std.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace MVD {
+
+class MVD_STD final : public Interface {
+public:
+ MVD_STD();
+
+ std::string GetPortName() const override {
+ return "mvd:std";
+ }
+};
+
+} // namespace MVD
+} // namespace Service
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp
new file mode 100644
index 000000000..d9738c6a1
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc.cpp
@@ -0,0 +1,18 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nfc/nfc.h"
+#include "core/hle/service/nfc/nfc_m.h"
+#include "core/hle/service/nfc/nfc_u.h"
+
+namespace Service {
+namespace NFC {
+
+void Init() {
+ AddService(new NFC_M());
+ AddService(new NFC_U());
+}
+
+} // namespace NFC
+} // namespace Service
diff --git a/src/core/hle/service/nfc/nfc.h b/src/core/hle/service/nfc/nfc.h
new file mode 100644
index 000000000..cd65a5fdc
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc.h
@@ -0,0 +1,14 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service {
+namespace NFC {
+
+/// Initialize all NFC services.
+void Init();
+
+} // namespace NFC
+} // namespace Service
diff --git a/src/core/hle/service/nfc/nfc_m.cpp b/src/core/hle/service/nfc/nfc_m.cpp
new file mode 100644
index 000000000..717335c11
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_m.cpp
@@ -0,0 +1,44 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nfc/nfc_m.h"
+
+namespace Service {
+namespace NFC {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // clang-format off
+ // nfc:u shared commands
+ {0x00010040, nullptr, "Initialize"},
+ {0x00020040, nullptr, "Shutdown"},
+ {0x00030000, nullptr, "StartCommunication"},
+ {0x00040000, nullptr, "StopCommunication"},
+ {0x00050040, nullptr, "StartTagScanning"},
+ {0x00060000, nullptr, "StopTagScanning"},
+ {0x00070000, nullptr, "LoadAmiiboData"},
+ {0x00080000, nullptr, "ResetTagScanState"},
+ {0x00090002, nullptr, "UpdateStoredAmiiboData"},
+ {0x000D0000, nullptr, "GetTagState"},
+ {0x000F0000, nullptr, "CommunicationGetStatus"},
+ {0x00100000, nullptr, "GetTagInfo2"},
+ {0x00110000, nullptr, "GetTagInfo"},
+ {0x00120000, nullptr, "CommunicationGetResult"},
+ {0x00130040, nullptr, "OpenAppData"},
+ {0x00140384, nullptr, "InitializeWriteAppData"},
+ {0x00150040, nullptr, "ReadAppData"},
+ {0x00160242, nullptr, "WriteAppData"},
+ {0x00170000, nullptr, "GetAmiiboSettings"},
+ {0x00180000, nullptr, "GetAmiiboConfig"},
+ {0x00190000, nullptr, "GetAppDataInitStruct"},
+ // nfc:m
+ {0x04040A40, nullptr, "SetAmiiboSettings"}
+ // clang-format on
+};
+
+NFC_M::NFC_M() {
+ Register(FunctionTable);
+}
+
+} // namespace NFC
+} // namespace Service
diff --git a/src/core/hle/service/nfc/nfc_m.h b/src/core/hle/service/nfc/nfc_m.h
new file mode 100644
index 000000000..fae75535b
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_m.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NFC {
+
+class NFC_M final : public Interface {
+public:
+ NFC_M();
+
+ std::string GetPortName() const override {
+ return "nfc:m";
+ }
+};
+
+} // namespace NFC
+} // namespace Service
diff --git a/src/core/hle/service/nfc/nfc_u.cpp b/src/core/hle/service/nfc/nfc_u.cpp
new file mode 100644
index 000000000..deffb0b4f
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_u.cpp
@@ -0,0 +1,41 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nfc/nfc_u.h"
+
+namespace Service {
+namespace NFC {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // clang-format off
+ {0x00010040, nullptr, "Initialize"},
+ {0x00020040, nullptr, "Shutdown"},
+ {0x00030000, nullptr, "StartCommunication"},
+ {0x00040000, nullptr, "StopCommunication"},
+ {0x00050040, nullptr, "StartTagScanning"},
+ {0x00060000, nullptr, "StopTagScanning"},
+ {0x00070000, nullptr, "LoadAmiiboData"},
+ {0x00080000, nullptr, "ResetTagScanState"},
+ {0x00090002, nullptr, "UpdateStoredAmiiboData"},
+ {0x000D0000, nullptr, "GetTagState"},
+ {0x000F0000, nullptr, "CommunicationGetStatus"},
+ {0x00100000, nullptr, "GetTagInfo2"},
+ {0x00110000, nullptr, "GetTagInfo"},
+ {0x00120000, nullptr, "CommunicationGetResult"},
+ {0x00130040, nullptr, "OpenAppData"},
+ {0x00140384, nullptr, "InitializeWriteAppData"},
+ {0x00150040, nullptr, "ReadAppData"},
+ {0x00160242, nullptr, "WriteAppData"},
+ {0x00170000, nullptr, "GetAmiiboSettings"},
+ {0x00180000, nullptr, "GetAmiiboConfig"},
+ {0x00190000, nullptr, "GetAppDataInitStruct"},
+ // clang-format on
+};
+
+NFC_U::NFC_U() {
+ Register(FunctionTable);
+}
+
+} // namespace NFC
+} // namespace Service
diff --git a/src/core/hle/service/nfc/nfc_u.h b/src/core/hle/service/nfc/nfc_u.h
new file mode 100644
index 000000000..eb7507314
--- /dev/null
+++ b/src/core/hle/service/nfc/nfc_u.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NFC {
+
+class NFC_U final : public Interface {
+public:
+ NFC_U();
+
+ std::string GetPortName() const override {
+ return "nfc:u";
+ }
+};
+
+} // namespace NFC
+} // namespace Service
diff --git a/src/core/hle/service/nim/nim_s.cpp b/src/core/hle/service/nim/nim_s.cpp
index e2ba693c9..28b87e6f7 100644
--- a/src/core/hle/service/nim/nim_s.cpp
+++ b/src/core/hle/service/nim/nim_s.cpp
@@ -10,6 +10,7 @@ namespace NIM {
const Interface::FunctionInfo FunctionTable[] = {
{0x000A0000, nullptr, "CheckSysupdateAvailableSOAP"},
{0x0016020A, nullptr, "ListTitles"},
+ {0x00290000, nullptr, "AccountCheckBalanceSOAP"},
{0x002D0042, nullptr, "DownloadTickets"},
{0x00420240, nullptr, "StartDownload"},
};
diff --git a/src/core/hle/service/nim/nim_u.cpp b/src/core/hle/service/nim/nim_u.cpp
index 7e07d02e8..7664bad60 100644
--- a/src/core/hle/service/nim/nim_u.cpp
+++ b/src/core/hle/service/nim/nim_u.cpp
@@ -15,6 +15,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00050000, nullptr, "CheckForSysUpdateEvent"},
{0x00090000, CheckSysUpdateAvailable, "CheckSysUpdateAvailable"},
{0x000A0000, nullptr, "GetState"},
+ {0x000B0000, nullptr, "GetSystemTitleHash"},
};
NIM_U_Interface::NIM_U_Interface() {
diff --git a/src/core/hle/service/ns_s.cpp b/src/core/hle/service/ns_s.cpp
index 6693f7c08..215c9aacc 100644
--- a/src/core/hle/service/ns_s.cpp
+++ b/src/core/hle/service/ns_s.cpp
@@ -4,10 +4,8 @@
#include "core/hle/service/ns_s.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NS_S
-
-namespace NS_S {
+namespace Service {
+namespace NS {
const Interface::FunctionInfo FunctionTable[] = {
{0x000100C0, nullptr, "LaunchFIRM"},
@@ -27,11 +25,9 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00160000, nullptr, "RebootSystemClean"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+NS_S::NS_S() {
Register(FunctionTable);
}
-} // namespace
+} // namespace NS
+} // namespace Service
diff --git a/src/core/hle/service/ns_s.h b/src/core/hle/service/ns_s.h
index 8d8e849b8..90288a521 100644
--- a/src/core/hle/service/ns_s.h
+++ b/src/core/hle/service/ns_s.h
@@ -6,19 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NS_S
+namespace Service {
+namespace NS {
-namespace NS_S {
-
-/// Interface to "NS:S" service
-class Interface : public Service::Interface {
+class NS_S final : public Interface {
public:
- Interface();
+ NS_S();
std::string GetPortName() const override {
return "ns:s";
}
};
-} // namespace
+} // namespace NS
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm.cpp b/src/core/hle/service/nwm/nwm.cpp
new file mode 100644
index 000000000..9f1994dc3
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm.cpp
@@ -0,0 +1,28 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nwm/nwm.h"
+#include "core/hle/service/nwm/nwm_cec.h"
+#include "core/hle/service/nwm/nwm_ext.h"
+#include "core/hle/service/nwm/nwm_inf.h"
+#include "core/hle/service/nwm/nwm_sap.h"
+#include "core/hle/service/nwm/nwm_soc.h"
+#include "core/hle/service/nwm/nwm_tst.h"
+#include "core/hle/service/nwm/nwm_uds.h"
+
+namespace Service {
+namespace NWM {
+
+void Init() {
+ AddService(new NWM_CEC);
+ AddService(new NWM_EXT);
+ AddService(new NWM_INF);
+ AddService(new NWM_SAP);
+ AddService(new NWM_SOC);
+ AddService(new NWM_TST);
+ AddService(new NWM_UDS);
+}
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm.h b/src/core/hle/service/nwm/nwm.h
new file mode 100644
index 000000000..6926b29a6
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm.h
@@ -0,0 +1,14 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service {
+namespace NWM {
+
+/// Initialize all NWM services
+void Init();
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_cec.cpp b/src/core/hle/service/nwm/nwm_cec.cpp
new file mode 100644
index 000000000..7f03987df
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_cec.cpp
@@ -0,0 +1,19 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nwm/nwm_cec.h"
+
+namespace Service {
+namespace NWM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x000D0082, nullptr, "SendProbeRequest"},
+};
+
+NWM_CEC::NWM_CEC() {
+ Register(FunctionTable);
+}
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_cec.h b/src/core/hle/service/nwm/nwm_cec.h
new file mode 100644
index 000000000..07b6addb5
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_cec.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NWM {
+
+class NWM_CEC final : public Interface {
+public:
+ NWM_CEC();
+
+ std::string GetPortName() const override {
+ return "nwm::CEC";
+ }
+};
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_ext.cpp b/src/core/hle/service/nwm/nwm_ext.cpp
new file mode 100644
index 000000000..605640a13
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_ext.cpp
@@ -0,0 +1,19 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nwm/nwm_ext.h"
+
+namespace Service {
+namespace NWM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00080040, nullptr, "ControlWirelessEnabled"},
+};
+
+NWM_EXT::NWM_EXT() {
+ Register(FunctionTable);
+}
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_ext.h b/src/core/hle/service/nwm/nwm_ext.h
new file mode 100644
index 000000000..51d39d9ea
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_ext.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NWM {
+
+class NWM_EXT final : public Interface {
+public:
+ NWM_EXT();
+
+ std::string GetPortName() const override {
+ return "nwm::EXT";
+ }
+};
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_inf.cpp b/src/core/hle/service/nwm/nwm_inf.cpp
new file mode 100644
index 000000000..c8470589b
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_inf.cpp
@@ -0,0 +1,21 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nwm/nwm_inf.h"
+
+namespace Service {
+namespace NWM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x000603C4, nullptr, "RecvBeaconBroadcastData"},
+ {0x00070742, nullptr, "ConnectToEncryptedAP"},
+ {0x00080302, nullptr, "ConnectToAP"},
+};
+
+NWM_INF::NWM_INF() {
+ Register(FunctionTable);
+}
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_inf.h b/src/core/hle/service/nwm/nwm_inf.h
new file mode 100644
index 000000000..0043d769c
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_inf.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NWM {
+
+class NWM_INF final : public Interface {
+public:
+ NWM_INF();
+
+ std::string GetPortName() const override {
+ return "nwm::INF";
+ }
+};
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_sap.cpp b/src/core/hle/service/nwm/nwm_sap.cpp
new file mode 100644
index 000000000..fd29ed761
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_sap.cpp
@@ -0,0 +1,20 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nwm/nwm_sap.h"
+
+namespace Service {
+namespace NWM {
+
+/*
+const Interface::FunctionInfo FunctionTable[] = {
+};
+*/
+
+NWM_SAP::NWM_SAP() {
+ // Register(FunctionTable);
+}
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_sap.h b/src/core/hle/service/nwm/nwm_sap.h
new file mode 100644
index 000000000..f692e06d4
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_sap.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NWM {
+
+class NWM_SAP final : public Interface {
+public:
+ NWM_SAP();
+
+ std::string GetPortName() const override {
+ return "nwm::SAP";
+ }
+};
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_soc.cpp b/src/core/hle/service/nwm/nwm_soc.cpp
new file mode 100644
index 000000000..fdffcb925
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_soc.cpp
@@ -0,0 +1,20 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nwm/nwm_soc.h"
+
+namespace Service {
+namespace NWM {
+
+/*
+const Interface::FunctionInfo FunctionTable[] = {
+};
+*/
+
+NWM_SOC::NWM_SOC() {
+ // Register(FunctionTable);
+}
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_soc.h b/src/core/hle/service/nwm/nwm_soc.h
new file mode 100644
index 000000000..594941d7e
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_soc.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NWM {
+
+class NWM_SOC final : public Interface {
+public:
+ NWM_SOC();
+
+ std::string GetPortName() const override {
+ return "nwm::SOC";
+ }
+};
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_tst.cpp b/src/core/hle/service/nwm/nwm_tst.cpp
new file mode 100644
index 000000000..5f292e5db
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_tst.cpp
@@ -0,0 +1,20 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/nwm/nwm_tst.h"
+
+namespace Service {
+namespace NWM {
+
+/*
+const Interface::FunctionInfo FunctionTable[] = {
+};
+*/
+
+NWM_TST::NWM_TST() {
+ // Register(FunctionTable);
+}
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm/nwm_tst.h b/src/core/hle/service/nwm/nwm_tst.h
new file mode 100644
index 000000000..8deca3216
--- /dev/null
+++ b/src/core/hle/service/nwm/nwm_tst.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NWM {
+
+class NWM_TST final : public Interface {
+public:
+ NWM_TST();
+
+ std::string GetPortName() const override {
+ return "nwm::TST";
+ }
+};
+
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm/nwm_uds.cpp
index 80081aae2..08fade320 100644
--- a/src/core/hle/service/nwm_uds.cpp
+++ b/src/core/hle/service/nwm/nwm_uds.cpp
@@ -5,14 +5,12 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/hle/kernel/event.h"
-#include "core/hle/service/nwm_uds.h"
+#include "core/hle/service/nwm/nwm_uds.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NWM_UDS
+namespace Service {
+namespace NWM {
-namespace NWM_UDS {
-
-static Kernel::SharedPtr<Kernel::Event> handle_event;
+static Kernel::SharedPtr<Kernel::Event> uds_handle_event;
/**
* NWM_UDS::Shutdown service function
@@ -22,7 +20,7 @@ static Kernel::SharedPtr<Kernel::Event> handle_event;
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void Shutdown(Service::Interface* self) {
+static void Shutdown(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
// TODO(purpasmart): Verify return header on HW
@@ -50,7 +48,7 @@ static void Shutdown(Service::Interface* self) {
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void RecvBeaconBroadcastData(Service::Interface* self) {
+static void RecvBeaconBroadcastData(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 out_buffer_size = cmd_buff[1];
u32 unk1 = cmd_buff[2];
@@ -90,7 +88,7 @@ static void RecvBeaconBroadcastData(Service::Interface* self) {
* 2 : Value 0
* 3 : Output handle
*/
-static void Initialize(Service::Interface* self) {
+static void InitializeWithVersion(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 unk1 = cmd_buff[1];
u32 unk2 = cmd_buff[12];
@@ -103,7 +101,7 @@ static void Initialize(Service::Interface* self) {
/*
cmd_buff[1] = RESULT_SUCCESS.raw;
cmd_buff[2] = 0;
- cmd_buff[3] = Kernel::g_handle_table.Create(handle_event)
+ cmd_buff[3] = Kernel::g_handle_table.Create(uds_handle_event)
.MoveFrom(); // TODO(purpasmart): Verify if this is a event handle
*/
cmd_buff[0] = IPC::MakeHeader(0x1B, 1, 2);
@@ -118,26 +116,29 @@ static void Initialize(Service::Interface* self) {
}
const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010442, nullptr, "Initialize (deprecated)"},
{0x00020000, nullptr, "Scrap"},
{0x00030000, Shutdown, "Shutdown"},
- {0x00040402, nullptr, "CreateNetwork"},
+ {0x00040402, nullptr, "CreateNetwork (deprecated)"},
{0x00050040, nullptr, "EjectClient"},
{0x00060000, nullptr, "EjectSpectator"},
{0x00070080, nullptr, "UpdateNetworkAttribute"},
{0x00080000, nullptr, "DestroyNetwork"},
+ {0x00090442, nullptr, "ConnectNetwork (deprecated)"},
{0x000A0000, nullptr, "DisconnectNetwork"},
{0x000B0000, nullptr, "GetConnectionStatus"},
{0x000D0040, nullptr, "GetNodeInformation"},
+ {0x000E0006, nullptr, "DecryptBeaconData (deprecated)"},
{0x000F0404, RecvBeaconBroadcastData, "RecvBeaconBroadcastData"},
- {0x00100042, nullptr, "SetBeaconAdditionalData"},
+ {0x00100042, nullptr, "SetApplicationData"},
{0x00110040, nullptr, "GetApplicationData"},
{0x00120100, nullptr, "Bind"},
{0x00130040, nullptr, "Unbind"},
- {0x001400C0, nullptr, "RecvBroadcastDataFrame"},
+ {0x001400C0, nullptr, "PullPacket"},
{0x00150080, nullptr, "SetMaxSendDelay"},
{0x00170182, nullptr, "SendTo"},
{0x001A0000, nullptr, "GetChannel"},
- {0x001B0302, Initialize, "Initialize"},
+ {0x001B0302, InitializeWithVersion, "InitializeWithVersion"},
{0x001D0044, nullptr, "BeginHostingNetwork"},
{0x001E0084, nullptr, "ConnectToNetwork"},
{0x001F0006, nullptr, "DecryptBeaconData"},
@@ -146,17 +147,15 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00220402, nullptr, "ScanOnConnection"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- handle_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "NWM_UDS::handle_event");
+NWM_UDS::NWM_UDS() {
+ uds_handle_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "NWM::uds_handle_event");
Register(FunctionTable);
}
-Interface::~Interface() {
- handle_event = nullptr;
+NWM_UDS::~NWM_UDS() {
+ uds_handle_event = nullptr;
}
-} // namespace
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm/nwm_uds.h
index 0ced2359c..55db748f6 100644
--- a/src/core/hle/service/nwm_uds.h
+++ b/src/core/hle/service/nwm/nwm_uds.h
@@ -6,21 +6,20 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NWM_UDS
+// Local-WLAN service
-// local-WLAN service
+namespace Service {
+namespace NWM {
-namespace NWM_UDS {
-
-class Interface : public Service::Interface {
+class NWM_UDS final : public Interface {
public:
- Interface();
- ~Interface() override;
+ NWM_UDS();
+ ~NWM_UDS() override;
std::string GetPortName() const override {
return "nwm::UDS";
}
};
-} // namespace
+} // namespace NWM
+} // namespace Service
diff --git a/src/core/hle/service/pm_app.cpp b/src/core/hle/service/pm_app.cpp
index 7d91694f6..caa16f952 100644
--- a/src/core/hle/service/pm_app.cpp
+++ b/src/core/hle/service/pm_app.cpp
@@ -4,31 +4,30 @@
#include "core/hle/service/pm_app.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace PM_APP
-
-namespace PM_APP {
+namespace Service {
+namespace PM {
const Interface::FunctionInfo FunctionTable[] = {
+ // clang-format off
{0x00010140, nullptr, "LaunchTitle"},
- {0x00020082, nullptr, "LaunchFIRMSetParams"},
- {0x00030080, nullptr, "TerminateProcesse"},
- {0x00040100, nullptr, "TerminateProcessTID"},
- {0x000500C0, nullptr, "TerminateProcessTID_unknown"},
+ {0x00020082, nullptr, "LaunchFIRM"},
+ {0x00030080, nullptr, "TerminateApplication"},
+ {0x00040100, nullptr, "TerminateTitle"},
+ {0x000500C0, nullptr, "TerminateProcess"},
+ {0x00060082, nullptr, "PrepareForReboot"},
{0x00070042, nullptr, "GetFIRMLaunchParams"},
{0x00080100, nullptr, "GetTitleExheaderFlags"},
{0x00090042, nullptr, "SetFIRMLaunchParams"},
- {0x000A0140, nullptr, "SetResourceLimit"},
- {0x000B0140, nullptr, "GetResourceLimitMax"},
+ {0x000A0140, nullptr, "SetAppResourceLimit"},
+ {0x000B0140, nullptr, "GetAppResourceLimit"},
{0x000C0080, nullptr, "UnregisterProcess"},
{0x000D0240, nullptr, "LaunchTitleUpdate"},
+ // clang-format on
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+PM_APP::PM_APP() {
Register(FunctionTable);
}
-} // namespace
+} // namespace PM
+} // namespace Service
diff --git a/src/core/hle/service/pm_app.h b/src/core/hle/service/pm_app.h
index c1fb1f9da..151c69f3d 100644
--- a/src/core/hle/service/pm_app.h
+++ b/src/core/hle/service/pm_app.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace PM_APP
+namespace Service {
+namespace PM {
-namespace PM_APP {
-
-class Interface : public Service::Interface {
+class PM_APP final : public Interface {
public:
- Interface();
+ PM_APP();
std::string GetPortName() const override {
return "pm:app";
}
};
-} // namespace
+} // namespace PM
+} // namespace Service
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp
index cc859c14c..8ff808fd9 100644
--- a/src/core/hle/service/ptm/ptm.cpp
+++ b/src/core/hle/service/ptm/ptm.cpp
@@ -6,7 +6,9 @@
#include "core/file_sys/file_backend.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/ptm/ptm.h"
+#include "core/hle/service/ptm/ptm_gets.h"
#include "core/hle/service/ptm/ptm_play.h"
+#include "core/hle/service/ptm/ptm_sets.h"
#include "core/hle/service/ptm/ptm_sysm.h"
#include "core/hle/service/ptm/ptm_u.h"
#include "core/hle/service/service.h"
@@ -81,7 +83,7 @@ void GetTotalStepCount(Service::Interface* self) {
LOG_WARNING(Service_PTM, "(STUBBED) called");
}
-void IsLegacyPowerOff(Service::Interface* self) {
+void GetSoftwareClosedFlag(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[1] = RESULT_SUCCESS.raw;
@@ -106,9 +108,12 @@ void CheckNew3DS(Service::Interface* self) {
}
void Init() {
- AddService(new PTM_Play_Interface);
- AddService(new PTM_Sysm_Interface);
- AddService(new PTM_U_Interface);
+ AddService(new PTM_Gets);
+ AddService(new PTM_Play);
+ AddService(new PTM_S);
+ AddService(new PTM_Sets);
+ AddService(new PTM_Sysm);
+ AddService(new PTM_U);
shell_open = true;
battery_is_charging = true;
@@ -137,7 +142,7 @@ void Init() {
Service::FS::OpenFileFromArchive(*archive_result, gamecoin_path, open_mode);
if (gamecoin_result.Succeeded()) {
auto gamecoin = gamecoin_result.MoveFrom();
- gamecoin->backend->Write(0, sizeof(GameCoin), 1,
+ gamecoin->backend->Write(0, sizeof(GameCoin), true,
reinterpret_cast<const u8*>(&default_game_coin));
gamecoin->backend->Close();
}
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
index 6e163a6f9..a1a628012 100644
--- a/src/core/hle/service/ptm/ptm.h
+++ b/src/core/hle/service/ptm/ptm.h
@@ -82,12 +82,13 @@ void GetBatteryChargeState(Interface* self);
void GetTotalStepCount(Interface* self);
/**
- * PTM::IsLegacyPowerOff service function
+ * PTM::GetSoftwareClosedFlag service function
* Outputs:
* 1: Result code, 0 on success, otherwise error code
- * 2: Whether the system is going through a power off
+ * 2: Whether or not the "software closed" dialog was requested by the last FIRM
+ * and should be displayed.
*/
-void IsLegacyPowerOff(Interface* self);
+void GetSoftwareClosedFlag(Interface* self);
/**
* PTM::CheckNew3DS service function
diff --git a/src/core/hle/service/ptm/ptm_gets.cpp b/src/core/hle/service/ptm/ptm_gets.cpp
new file mode 100644
index 000000000..b23e508d6
--- /dev/null
+++ b/src/core/hle/service/ptm/ptm_gets.cpp
@@ -0,0 +1,37 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/ptm/ptm.h"
+#include "core/hle/service/ptm/ptm_gets.h"
+
+namespace Service {
+namespace PTM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // ptm:u common commands
+ {0x00010002, nullptr, "RegisterAlarmClient"},
+ {0x00020080, nullptr, "SetRtcAlarm"},
+ {0x00030000, nullptr, "GetRtcAlarm"},
+ {0x00040000, nullptr, "CancelRtcAlarm"},
+ {0x00050000, GetAdapterState, "GetAdapterState"},
+ {0x00060000, GetShellState, "GetShellState"},
+ {0x00070000, GetBatteryLevel, "GetBatteryLevel"},
+ {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"},
+ {0x00090000, nullptr, "GetPedometerState"},
+ {0x000A0042, nullptr, "GetStepHistoryEntry"},
+ {0x000B00C2, nullptr, "GetStepHistory"},
+ {0x000C0000, GetTotalStepCount, "GetTotalStepCount"},
+ {0x000D0040, nullptr, "SetPedometerRecordingMode"},
+ {0x000E0000, nullptr, "GetPedometerRecordingMode"},
+ {0x000F0084, nullptr, "GetStepHistoryAll"},
+ // ptm:gets
+ {0x04010000, nullptr, "GetSystemTime"},
+};
+
+PTM_Gets::PTM_Gets() {
+ Register(FunctionTable);
+}
+
+} // namespace PTM
+} // namespace Service
diff --git a/src/core/hle/service/ptm/ptm_gets.h b/src/core/hle/service/ptm/ptm_gets.h
new file mode 100644
index 000000000..5552c9eff
--- /dev/null
+++ b/src/core/hle/service/ptm/ptm_gets.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace PTM {
+
+class PTM_Gets final : public Interface {
+public:
+ PTM_Gets();
+
+ std::string GetPortName() const override {
+ return "ptm:gets";
+ }
+};
+
+} // namespace PTM
+} // namespace Service
diff --git a/src/core/hle/service/ptm/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp
index 2e0c6e1a3..bcb00e0d4 100644
--- a/src/core/hle/service/ptm/ptm_play.cpp
+++ b/src/core/hle/service/ptm/ptm_play.cpp
@@ -2,19 +2,37 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "core/hle/service/ptm/ptm.h"
#include "core/hle/service/ptm/ptm_play.h"
namespace Service {
namespace PTM {
const Interface::FunctionInfo FunctionTable[] = {
+ // ptm:u common commands
+ {0x00010002, nullptr, "RegisterAlarmClient"},
+ {0x00020080, nullptr, "SetRtcAlarm"},
+ {0x00030000, nullptr, "GetRtcAlarm"},
+ {0x00040000, nullptr, "CancelRtcAlarm"},
+ {0x00050000, GetAdapterState, "GetAdapterState"},
+ {0x00060000, GetShellState, "GetShellState"},
+ {0x00070000, GetBatteryLevel, "GetBatteryLevel"},
+ {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"},
+ {0x00090000, nullptr, "GetPedometerState"},
+ {0x000A0042, nullptr, "GetStepHistoryEntry"},
+ {0x000B00C2, nullptr, "GetStepHistory"},
+ {0x000C0000, GetTotalStepCount, "GetTotalStepCount"},
+ {0x000D0040, nullptr, "SetPedometerRecordingMode"},
+ {0x000E0000, nullptr, "GetPedometerRecordingMode"},
+ {0x000F0084, nullptr, "GetStepHistoryAll"},
+ // ptm:play
{0x08070082, nullptr, "GetPlayHistory"},
{0x08080000, nullptr, "GetPlayHistoryStart"},
{0x08090000, nullptr, "GetPlayHistoryLength"},
{0x080B0080, nullptr, "CalcPlayHistoryStart"},
};
-PTM_Play_Interface::PTM_Play_Interface() {
+PTM_Play::PTM_Play() {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/ptm/ptm_play.h b/src/core/hle/service/ptm/ptm_play.h
index 47f229581..663faabee 100644
--- a/src/core/hle/service/ptm/ptm_play.h
+++ b/src/core/hle/service/ptm/ptm_play.h
@@ -9,9 +9,9 @@
namespace Service {
namespace PTM {
-class PTM_Play_Interface : public Service::Interface {
+class PTM_Play final : public Interface {
public:
- PTM_Play_Interface();
+ PTM_Play();
std::string GetPortName() const override {
return "ptm:play";
diff --git a/src/core/hle/service/ptm/ptm_sets.cpp b/src/core/hle/service/ptm/ptm_sets.cpp
new file mode 100644
index 000000000..a8c6cf227
--- /dev/null
+++ b/src/core/hle/service/ptm/ptm_sets.cpp
@@ -0,0 +1,20 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/ptm/ptm_sets.h"
+
+namespace Service {
+namespace PTM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // Note that this service does not have access to ptm:u's common commands
+ {0x00010080, nullptr, "SetSystemTime"},
+};
+
+PTM_Sets::PTM_Sets() {
+ Register(FunctionTable);
+}
+
+} // namespace PTM
+} // namespace Service
diff --git a/src/core/hle/service/ptm/ptm_sets.h b/src/core/hle/service/ptm/ptm_sets.h
new file mode 100644
index 000000000..d33b047e5
--- /dev/null
+++ b/src/core/hle/service/ptm/ptm_sets.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace PTM {
+
+class PTM_Sets final : public Interface {
+public:
+ PTM_Sets();
+
+ std::string GetPortName() const override {
+ return "ptm:sets";
+ }
+};
+
+} // namespace PTM
+} // namespace Service
diff --git a/src/core/hle/service/ptm/ptm_sysm.cpp b/src/core/hle/service/ptm/ptm_sysm.cpp
index 693158dbf..f95dfdbb1 100644
--- a/src/core/hle/service/ptm/ptm_sysm.cpp
+++ b/src/core/hle/service/ptm/ptm_sysm.cpp
@@ -9,6 +9,23 @@ namespace Service {
namespace PTM {
const Interface::FunctionInfo FunctionTable[] = {
+ // ptm:u common commands
+ {0x00010002, nullptr, "RegisterAlarmClient"},
+ {0x00020080, nullptr, "SetRtcAlarm"},
+ {0x00030000, nullptr, "GetRtcAlarm"},
+ {0x00040000, nullptr, "CancelRtcAlarm"},
+ {0x00050000, GetAdapterState, "GetAdapterState"},
+ {0x00060000, GetShellState, "GetShellState"},
+ {0x00070000, GetBatteryLevel, "GetBatteryLevel"},
+ {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"},
+ {0x00090000, nullptr, "GetPedometerState"},
+ {0x000A0042, nullptr, "GetStepHistoryEntry"},
+ {0x000B00C2, nullptr, "GetStepHistory"},
+ {0x000C0000, GetTotalStepCount, "GetTotalStepCount"},
+ {0x000D0040, nullptr, "SetPedometerRecordingMode"},
+ {0x000E0000, nullptr, "GetPedometerRecordingMode"},
+ {0x000F0084, nullptr, "GetStepHistoryAll"},
+ // ptm:sysm
{0x040100C0, nullptr, "SetRtcAlarmEx"},
{0x04020042, nullptr, "ReplySleepQuery"},
{0x04030042, nullptr, "NotifySleepPreparationComplete"},
@@ -33,8 +50,8 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x080C0080, nullptr, "SetUserTime"},
{0x080D0000, nullptr, "InvalidateSystemTime"},
{0x080E0140, nullptr, "NotifyPlayEvent"},
- {0x080F0000, IsLegacyPowerOff, "IsLegacyPowerOff"},
- {0x08100000, nullptr, "ClearLegacyPowerOff"},
+ {0x080F0000, GetSoftwareClosedFlag, "GetSoftwareClosedFlag"},
+ {0x08100000, nullptr, "ClearSoftwareClosedFlag"},
{0x08110000, GetShellState, "GetShellState"},
{0x08120000, nullptr, "IsShutdownByBatteryEmpty"},
{0x08130000, nullptr, "FormatSavedata"},
@@ -42,7 +59,11 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x08180040, nullptr, "ConfigureNew3DSCPU"},
};
-PTM_Sysm_Interface::PTM_Sysm_Interface() {
+PTM_S::PTM_S() {
+ Register(FunctionTable);
+}
+
+PTM_Sysm::PTM_Sysm() {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/ptm/ptm_sysm.h b/src/core/hle/service/ptm/ptm_sysm.h
index e37f20546..8afcebbba 100644
--- a/src/core/hle/service/ptm/ptm_sysm.h
+++ b/src/core/hle/service/ptm/ptm_sysm.h
@@ -9,9 +9,18 @@
namespace Service {
namespace PTM {
-class PTM_Sysm_Interface : public Interface {
+class PTM_S final : public Interface {
public:
- PTM_Sysm_Interface();
+ PTM_S();
+
+ std::string GetPortName() const override {
+ return "ptm:s";
+ }
+};
+
+class PTM_Sysm final : public Interface {
+public:
+ PTM_Sysm();
std::string GetPortName() const override {
return "ptm:sysm";
diff --git a/src/core/hle/service/ptm/ptm_u.cpp b/src/core/hle/service/ptm/ptm_u.cpp
index 65e868393..e0b65ba89 100644
--- a/src/core/hle/service/ptm/ptm_u.cpp
+++ b/src/core/hle/service/ptm/ptm_u.cpp
@@ -26,7 +26,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x000F0084, nullptr, "GetStepHistoryAll"},
};
-PTM_U_Interface::PTM_U_Interface() {
+PTM_U::PTM_U() {
Register(FunctionTable);
}
diff --git a/src/core/hle/service/ptm/ptm_u.h b/src/core/hle/service/ptm/ptm_u.h
index bf132f610..7b75d6e49 100644
--- a/src/core/hle/service/ptm/ptm_u.h
+++ b/src/core/hle/service/ptm/ptm_u.h
@@ -9,9 +9,9 @@
namespace Service {
namespace PTM {
-class PTM_U_Interface : public Interface {
+class PTM_U final : public Interface {
public:
- PTM_U_Interface();
+ PTM_U();
std::string GetPortName() const override {
return "ptm:u";
diff --git a/src/core/hle/service/qtm/qtm.cpp b/src/core/hle/service/qtm/qtm.cpp
new file mode 100644
index 000000000..f11542263
--- /dev/null
+++ b/src/core/hle/service/qtm/qtm.cpp
@@ -0,0 +1,21 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/qtm/qtm.h"
+#include "core/hle/service/qtm/qtm_s.h"
+#include "core/hle/service/qtm/qtm_sp.h"
+#include "core/hle/service/qtm/qtm_u.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace QTM {
+
+void Init() {
+ AddService(new QTM_S());
+ AddService(new QTM_SP());
+ AddService(new QTM_U());
+}
+
+} // namespace QTM
+} // namespace Service
diff --git a/src/core/hle/service/qtm/qtm.h b/src/core/hle/service/qtm/qtm.h
new file mode 100644
index 000000000..33b774c79
--- /dev/null
+++ b/src/core/hle/service/qtm/qtm.h
@@ -0,0 +1,14 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace Service {
+namespace QTM {
+
+/// Initializes all QTM services.
+void Init();
+
+} // namespace QTM
+} // namespace Service
diff --git a/src/core/hle/service/qtm/qtm_s.cpp b/src/core/hle/service/qtm/qtm_s.cpp
new file mode 100644
index 000000000..ad7df24a0
--- /dev/null
+++ b/src/core/hle/service/qtm/qtm_s.cpp
@@ -0,0 +1,23 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/qtm/qtm_s.h"
+
+namespace Service {
+namespace QTM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // clang-format off
+ // qtm common commands
+ {0x00010080, nullptr, "GetHeadtrackingInfoRaw"},
+ {0x00020080, nullptr, "GetHeadtrackingInfo"},
+ // clang-format on
+};
+
+QTM_S::QTM_S() {
+ Register(FunctionTable);
+}
+
+} // namespace QTM
+} // namespace Service
diff --git a/src/core/hle/service/qtm/qtm_s.h b/src/core/hle/service/qtm/qtm_s.h
new file mode 100644
index 000000000..e66138ed0
--- /dev/null
+++ b/src/core/hle/service/qtm/qtm_s.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace QTM {
+
+class QTM_S final : public Interface {
+public:
+ QTM_S();
+
+ std::string GetPortName() const override {
+ return "qtm:s";
+ }
+};
+
+} // namespace QTM
+} // namespace Service
diff --git a/src/core/hle/service/qtm/qtm_sp.cpp b/src/core/hle/service/qtm/qtm_sp.cpp
new file mode 100644
index 000000000..6e0695d34
--- /dev/null
+++ b/src/core/hle/service/qtm/qtm_sp.cpp
@@ -0,0 +1,23 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/qtm/qtm_sp.h"
+
+namespace Service {
+namespace QTM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // clang-format off
+ // qtm common commands
+ {0x00010080, nullptr, "GetHeadtrackingInfoRaw"},
+ {0x00020080, nullptr, "GetHeadtrackingInfo"},
+ // clang-format on
+};
+
+QTM_SP::QTM_SP() {
+ Register(FunctionTable);
+}
+
+} // namespace QTM
+} // namespace Service
diff --git a/src/core/hle/service/qtm/qtm_sp.h b/src/core/hle/service/qtm/qtm_sp.h
new file mode 100644
index 000000000..0ae0618fc
--- /dev/null
+++ b/src/core/hle/service/qtm/qtm_sp.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace QTM {
+
+class QTM_SP final : public Interface {
+public:
+ QTM_SP();
+
+ std::string GetPortName() const override {
+ return "qtm:sp";
+ }
+};
+
+} // namespace QTM
+} // namespace Service
diff --git a/src/core/hle/service/qtm/qtm_u.cpp b/src/core/hle/service/qtm/qtm_u.cpp
new file mode 100644
index 000000000..a0f808432
--- /dev/null
+++ b/src/core/hle/service/qtm/qtm_u.cpp
@@ -0,0 +1,23 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/qtm/qtm_u.h"
+
+namespace Service {
+namespace QTM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ // clang-format off
+ // qtm common commands
+ {0x00010080, nullptr, "GetHeadtrackingInfoRaw"},
+ {0x00020080, nullptr, "GetHeadtrackingInfo"},
+ // clang-format on
+};
+
+QTM_U::QTM_U() {
+ Register(FunctionTable);
+}
+
+} // namespace QTM
+} // namespace Service
diff --git a/src/core/hle/service/qtm/qtm_u.h b/src/core/hle/service/qtm/qtm_u.h
new file mode 100644
index 000000000..1ed4c0adc
--- /dev/null
+++ b/src/core/hle/service/qtm/qtm_u.h
@@ -0,0 +1,22 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace QTM {
+
+class QTM_U final : public Interface {
+public:
+ QTM_U();
+
+ std::string GetPortName() const override {
+ return "qtm:u";
+ }
+};
+
+} // namespace QTM
+} // namespace Service
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index ca7eeac8a..7e52a05d9 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -2,11 +2,14 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <boost/range/algorithm_ext/erase.hpp>
+
#include "common/logging/log.h"
#include "common/string_util.h"
+
+#include "core/hle/kernel/server_port.h"
#include "core/hle/service/ac_u.h"
-#include "core/hle/service/act_a.h"
-#include "core/hle/service/act_u.h"
+#include "core/hle/service/act/act.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/apt/apt.h"
#include "core/hle/service/boss/boss.h"
@@ -26,13 +29,16 @@
#include "core/hle/service/ir/ir.h"
#include "core/hle/service/ldr_ro/ldr_ro.h"
#include "core/hle/service/mic_u.h"
+#include "core/hle/service/mvd/mvd.h"
#include "core/hle/service/ndm/ndm.h"
#include "core/hle/service/news/news.h"
+#include "core/hle/service/nfc/nfc.h"
#include "core/hle/service/nim/nim.h"
#include "core/hle/service/ns_s.h"
-#include "core/hle/service/nwm_uds.h"
+#include "core/hle/service/nwm/nwm.h"
#include "core/hle/service/pm_app.h"
#include "core/hle/service/ptm/ptm.h"
+#include "core/hle/service/qtm/qtm.h"
#include "core/hle/service/service.h"
#include "core/hle/service/soc_u.h"
#include "core/hle/service/srv.h"
@@ -41,8 +47,8 @@
namespace Service {
-std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports;
-std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services;
+std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports;
+std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services;
/**
* Creates a function string for logging, complete with the name (or header code, depending
@@ -61,7 +67,23 @@ static std::string MakeFunctionString(const char* name, const char* port_name,
return function_string;
}
-ResultVal<bool> Interface::SyncRequest() {
+void SessionRequestHandler::ClientConnected(
+ Kernel::SharedPtr<Kernel::ServerSession> server_session) {
+ connected_sessions.push_back(server_session);
+}
+
+void SessionRequestHandler::ClientDisconnected(
+ Kernel::SharedPtr<Kernel::ServerSession> server_session) {
+ boost::range::remove_erase(connected_sessions, server_session);
+}
+
+Interface::Interface(u32 max_sessions) : max_sessions(max_sessions) {}
+Interface::~Interface() = default;
+
+void Interface::HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) {
+ // TODO(Subv): Make use of the server_session in the HLE service handlers to distinguish which
+ // session triggered each command.
+
u32* cmd_buff = Kernel::GetCommandBuffer();
auto itr = m_functions.find(cmd_buff[0]);
@@ -75,14 +97,12 @@ ResultVal<bool> Interface::SyncRequest() {
// TODO(bunnei): Hack - ignore error
cmd_buff[1] = 0;
- return MakeResult<bool>(false);
+ return;
}
LOG_TRACE(Service, "%s",
MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str());
itr->second.func(this);
-
- return MakeResult<bool>(false); // TODO: Implement return from actual function
}
void Interface::Register(const FunctionInfo* functions, size_t n) {
@@ -97,72 +117,81 @@ void Interface::Register(const FunctionInfo* functions, size_t n) {
// Module interface
static void AddNamedPort(Interface* interface_) {
- g_kernel_named_ports.emplace(interface_->GetPortName(), interface_);
+ auto ports =
+ Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(),
+ std::shared_ptr<Interface>(interface_));
+ auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports);
+ g_kernel_named_ports.emplace(interface_->GetPortName(), std::move(client_port));
}
void AddService(Interface* interface_) {
- g_srv_services.emplace(interface_->GetPortName(), interface_);
+ auto ports =
+ Kernel::ServerPort::CreatePortPair(interface_->GetMaxSessions(), interface_->GetPortName(),
+ std::shared_ptr<Interface>(interface_));
+ auto client_port = std::get<Kernel::SharedPtr<Kernel::ClientPort>>(ports);
+ g_srv_services.emplace(interface_->GetPortName(), std::move(client_port));
}
/// Initialize ServiceManager
void Init() {
- AddNamedPort(new SRV::Interface);
- AddNamedPort(new ERR_F::Interface);
-
- Service::FS::ArchiveInit();
- Service::AM::Init();
- Service::APT::Init();
- Service::BOSS::Init();
- Service::CAM::Init();
- Service::CECD::Init();
- Service::CFG::Init();
- Service::DLP::Init();
- Service::FRD::Init();
- Service::HID::Init();
- Service::IR::Init();
- Service::NEWS::Init();
- Service::NDM::Init();
- Service::NIM::Init();
- Service::PTM::Init();
-
- AddService(new AC_U::Interface);
- AddService(new ACT_A::Interface);
- AddService(new ACT_U::Interface);
- AddService(new CSND_SND::Interface);
+ AddNamedPort(new SRV::SRV);
+ AddNamedPort(new ERR::ERR_F);
+
+ FS::ArchiveInit();
+ ACT::Init();
+ AM::Init();
+ APT::Init();
+ BOSS::Init();
+ CAM::Init();
+ CECD::Init();
+ CFG::Init();
+ DLP::Init();
+ FRD::Init();
+ HID::Init();
+ IR::Init();
+ MVD::Init();
+ NDM::Init();
+ NEWS::Init();
+ NFC::Init();
+ NIM::Init();
+ NWM::Init();
+ PTM::Init();
+ QTM::Init();
+
+ AddService(new AC::AC_U);
+ AddService(new CSND::CSND_SND);
AddService(new DSP_DSP::Interface);
- AddService(new GSP_GPU::Interface);
- AddService(new GSP_LCD::Interface);
- AddService(new HTTP_C::Interface);
- AddService(new LDR_RO::Interface);
- AddService(new MIC_U::Interface);
- AddService(new NS_S::Interface);
- AddService(new NWM_UDS::Interface);
- AddService(new PM_APP::Interface);
- AddService(new SOC_U::Interface);
- AddService(new SSL_C::Interface);
- AddService(new Y2R_U::Interface);
+ AddService(new GSP::GSP_GPU);
+ AddService(new GSP::GSP_LCD);
+ AddService(new HTTP::HTTP_C);
+ AddService(new LDR::LDR_RO);
+ AddService(new MIC::MIC_U);
+ AddService(new NS::NS_S);
+ AddService(new PM::PM_APP);
+ AddService(new SOC::SOC_U);
+ AddService(new SSL::SSL_C);
+ AddService(new Y2R::Y2R_U);
LOG_DEBUG(Service, "initialized OK");
}
/// Shutdown ServiceManager
void Shutdown() {
-
- Service::PTM::Shutdown();
- Service::NDM::Shutdown();
- Service::NIM::Shutdown();
- Service::NEWS::Shutdown();
- Service::IR::Shutdown();
- Service::HID::Shutdown();
- Service::FRD::Shutdown();
- Service::DLP::Shutdown();
- Service::CFG::Shutdown();
- Service::CECD::Shutdown();
- Service::CAM::Shutdown();
- Service::BOSS::Shutdown();
- Service::APT::Shutdown();
- Service::AM::Shutdown();
- Service::FS::ArchiveShutdown();
+ PTM::Shutdown();
+ NIM::Shutdown();
+ NEWS::Shutdown();
+ NDM::Shutdown();
+ IR::Shutdown();
+ HID::Shutdown();
+ FRD::Shutdown();
+ DLP::Shutdown();
+ CFG::Shutdown();
+ CECD::Shutdown();
+ CAM::Shutdown();
+ BOSS::Shutdown();
+ APT::Shutdown();
+ AM::Shutdown();
+ FS::ArchiveShutdown();
g_srv_services.clear();
g_kernel_named_ports.clear();
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 29daacfc4..a7ba7688f 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -9,8 +9,15 @@
#include <unordered_map>
#include <boost/container/flat_map.hpp>
#include "common/common_types.h"
-#include "core/hle/kernel/session.h"
+#include "core/hle/ipc.h"
+#include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/thread.h"
#include "core/hle/result.h"
+#include "core/memory.h"
+
+namespace Kernel {
+class ServerSession;
+}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace Service
@@ -18,14 +25,63 @@
namespace Service {
static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
+/// Arbitrary default number of maximum connections to an HLE service.
+static const u32 DefaultMaxSessions = 10;
+
+/**
+ * Interface implemented by HLE Session handlers.
+ * This can be provided to a ServerSession in order to hook into several relevant events
+ * (such as a new connection or a SyncRequest) so they can be implemented in the emulator.
+ */
+class SessionRequestHandler {
+public:
+ /**
+ * Handles a sync request from the emulated application.
+ * @param server_session The ServerSession that was triggered for this sync request,
+ * it should be used to differentiate which client (As in ClientSession) we're answering to.
+ * TODO(Subv): Use a wrapper structure to hold all the information relevant to
+ * this request (ServerSession, Originator thread, Translated command buffer, etc).
+ * @returns ResultCode the result code of the translate operation.
+ */
+ virtual void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) = 0;
+
+ /**
+ * Signals that a client has just connected to this HLE handler and keeps the
+ * associated ServerSession alive for the duration of the connection.
+ * @param server_session Owning pointer to the ServerSession associated with the connection.
+ */
+ void ClientConnected(Kernel::SharedPtr<Kernel::ServerSession> server_session);
+
+ /**
+ * Signals that a client has just disconnected from this HLE handler and releases the
+ * associated ServerSession.
+ * @param server_session ServerSession associated with the connection.
+ */
+ void ClientDisconnected(Kernel::SharedPtr<Kernel::ServerSession> server_session);
-/// Interface to a CTROS service
-class Interface : public Kernel::Session {
- // TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be
- // just something that encapsulates a session and acts as a helper to implement service
- // processes.
+protected:
+ /// List of sessions that are connected to this handler.
+ /// A ServerSession whose server endpoint is an HLE implementation is kept alive by this list
+ // for the duration of the connection.
+ std::vector<Kernel::SharedPtr<Kernel::ServerSession>> connected_sessions;
+};
+
+/**
+ * Framework for implementing HLE service handlers which dispatch incoming SyncRequests based on a
+ * table mapping header ids to handler functions.
+ */
+class Interface : public SessionRequestHandler {
public:
- std::string GetName() const override {
+ /**
+ * Creates an HLE interface with the specified max sessions.
+ * @param max_sessions Maximum number of sessions that can be
+ * connected to this service at the same time.
+ */
+ Interface(u32 max_sessions = DefaultMaxSessions);
+
+ virtual ~Interface();
+
+ std::string GetName() const {
return GetPortName();
}
@@ -33,6 +89,15 @@ public:
version.raw = raw_version;
}
+ /**
+ * Gets the maximum allowed number of sessions that can be connected to this service
+ * at the same time.
+ * @returns The maximum number of connections allowed.
+ */
+ u32 GetMaxSessions() const {
+ return max_sessions;
+ }
+
typedef void (*Function)(Interface*);
struct FunctionInfo {
@@ -49,9 +114,9 @@ public:
return "[UNKNOWN SERVICE PORT]";
}
- ResultVal<bool> SyncRequest() override;
-
protected:
+ void HandleSyncRequest(Kernel::SharedPtr<Kernel::ServerSession> server_session) override;
+
/**
* Registers the functions in the service
*/
@@ -71,6 +136,7 @@ protected:
} version = {};
private:
+ u32 max_sessions; ///< Maximum number of concurrent sessions that this service can handle.
boost::container::flat_map<u32, FunctionInfo> m_functions;
};
@@ -81,9 +147,9 @@ void Init();
void Shutdown();
/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort SVC.
-extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports;
+extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_kernel_named_ports;
/// Map of services registered with the "srv:" service, retrieved using GetServiceHandle.
-extern std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services;
+extern std::unordered_map<std::string, Kernel::SharedPtr<Kernel::ClientPort>> g_srv_services;
/// Adds a service to the services table
void AddService(Interface* interface_);
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index 46b75db25..c3918cdd0 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -11,7 +11,7 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/scope_exit.h"
-#include "core/hle/kernel/session.h"
+#include "core/hle/kernel/server_session.h"
#include "core/hle/result.h"
#include "core/hle/service/soc_u.h"
#include "core/memory.h"
@@ -53,12 +53,10 @@
#define closesocket(x) close(x)
#endif
-static const s32 SOCKET_ERROR_VALUE = -1;
+namespace Service {
+namespace SOC {
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace SOC_U
-
-namespace SOC_U {
+const s32 SOCKET_ERROR_VALUE = -1;
/// Holds the translation from system network errors to 3DS network errors
static const std::unordered_map<int, int> error_map = {{
@@ -339,7 +337,7 @@ static void CleanupSockets() {
open_sockets.clear();
}
-static void Socket(Service::Interface* self) {
+static void Socket(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 domain = cmd_buffer[1]; // Address family
u32 type = cmd_buffer[2];
@@ -378,7 +376,7 @@ static void Socket(Service::Interface* self) {
cmd_buffer[2] = socket_handle;
}
-static void Bind(Service::Interface* self) {
+static void Bind(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
u32 len = cmd_buffer[2];
@@ -406,7 +404,7 @@ static void Bind(Service::Interface* self) {
cmd_buffer[2] = res;
}
-static void Fcntl(Service::Interface* self) {
+static void Fcntl(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
u32 ctr_cmd = cmd_buffer[2];
@@ -475,7 +473,7 @@ static void Fcntl(Service::Interface* self) {
}
}
-static void Listen(Service::Interface* self) {
+static void Listen(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
u32 backlog = cmd_buffer[2];
@@ -490,7 +488,7 @@ static void Listen(Service::Interface* self) {
cmd_buffer[2] = ret;
}
-static void Accept(Service::Interface* self) {
+static void Accept(Interface* self) {
// TODO(Subv): Calling this function on a blocking socket will block the emu thread,
// preventing graceful shutdown when closing the emulator, this can be fixed by always
// performing nonblocking operations and spinlock until the data is available
@@ -518,7 +516,7 @@ static void Accept(Service::Interface* self) {
cmd_buffer[3] = IPC::StaticBufferDesc(static_cast<u32>(max_addr_len), 0);
}
-static void GetHostId(Service::Interface* self) {
+static void GetHostId(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
char name[128];
@@ -536,7 +534,7 @@ static void GetHostId(Service::Interface* self) {
freeaddrinfo(res);
}
-static void Close(Service::Interface* self) {
+static void Close(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
@@ -553,7 +551,7 @@ static void Close(Service::Interface* self) {
cmd_buffer[1] = result;
}
-static void SendTo(Service::Interface* self) {
+static void SendTo(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
u32 len = cmd_buffer[2];
@@ -597,7 +595,7 @@ static void SendTo(Service::Interface* self) {
cmd_buffer[1] = result;
}
-static void RecvFrom(Service::Interface* self) {
+static void RecvFrom(Interface* self) {
// TODO(Subv): Calling this function on a blocking socket will block the emu thread,
// preventing graceful shutdown when closing the emulator, this can be fixed by always
// performing nonblocking operations and spinlock until the data is available
@@ -654,7 +652,7 @@ static void RecvFrom(Service::Interface* self) {
cmd_buffer[3] = total_received;
}
-static void Poll(Service::Interface* self) {
+static void Poll(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 nfds = cmd_buffer[1];
int timeout = cmd_buffer[2];
@@ -692,7 +690,7 @@ static void Poll(Service::Interface* self) {
cmd_buffer[2] = ret;
}
-static void GetSockName(Service::Interface* self) {
+static void GetSockName(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
socklen_t ctr_len = cmd_buffer[2];
@@ -720,7 +718,7 @@ static void GetSockName(Service::Interface* self) {
cmd_buffer[1] = result;
}
-static void Shutdown(Service::Interface* self) {
+static void Shutdown(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
int how = cmd_buffer[2];
@@ -733,7 +731,7 @@ static void Shutdown(Service::Interface* self) {
cmd_buffer[1] = result;
}
-static void GetPeerName(Service::Interface* self) {
+static void GetPeerName(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
socklen_t len = cmd_buffer[2];
@@ -761,7 +759,7 @@ static void GetPeerName(Service::Interface* self) {
cmd_buffer[1] = result;
}
-static void Connect(Service::Interface* self) {
+static void Connect(Interface* self) {
// TODO(Subv): Calling this function on a blocking socket will block the emu thread,
// preventing graceful shutdown when closing the emulator, this can be fixed by always
// performing nonblocking operations and spinlock until the data is available
@@ -790,7 +788,7 @@ static void Connect(Service::Interface* self) {
cmd_buffer[2] = ret;
}
-static void InitializeSockets(Service::Interface* self) {
+static void InitializeSockets(Interface* self) {
// TODO(Subv): Implement
#ifdef _WIN32
WSADATA data;
@@ -802,7 +800,7 @@ static void InitializeSockets(Service::Interface* self) {
cmd_buffer[1] = RESULT_SUCCESS.raw;
}
-static void ShutdownSockets(Service::Interface* self) {
+static void ShutdownSockets(Interface* self) {
// TODO(Subv): Implement
CleanupSockets();
@@ -814,7 +812,7 @@ static void ShutdownSockets(Service::Interface* self) {
cmd_buffer[1] = 0;
}
-static void GetSockOpt(Service::Interface* self) {
+static void GetSockOpt(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
u32 level = cmd_buffer[2];
@@ -849,7 +847,7 @@ static void GetSockOpt(Service::Interface* self) {
cmd_buffer[3] = optlen;
}
-static void SetSockOpt(Service::Interface* self) {
+static void SetSockOpt(Interface* self) {
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
u32 level = cmd_buffer[2];
@@ -916,18 +914,16 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00230040, nullptr, "AddGlobalSocket"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+SOC_U::SOC_U() {
Register(FunctionTable);
}
-Interface::~Interface() {
+SOC_U::~SOC_U() {
CleanupSockets();
#ifdef _WIN32
WSACleanup();
#endif
}
-} // namespace
+} // namespace SOC
+} // namespace Service
diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h
index 8d02ed30f..5f829fc1c 100644
--- a/src/core/hle/service/soc_u.h
+++ b/src/core/hle/service/soc_u.h
@@ -7,19 +7,18 @@
#include <string>
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace SOC_U
+namespace Service {
+namespace SOC {
-namespace SOC_U {
-
-class Interface : public Service::Interface {
+class SOC_U final : public Interface {
public:
- Interface();
- ~Interface();
+ SOC_U();
+ ~SOC_U();
std::string GetPortName() const override {
return "soc:U";
}
};
-} // namespace
+} // namespace SOC
+} // namespace Service
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index b25be413a..3bd787147 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -2,14 +2,16 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <tuple>
+
#include "common/common_types.h"
#include "common/logging/log.h"
+#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/server_session.h"
#include "core/hle/service/srv.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace SRV
-
+namespace Service {
namespace SRV {
static Kernel::SharedPtr<Kernel::Event> event_handle;
@@ -23,7 +25,7 @@ static Kernel::SharedPtr<Kernel::Event> event_handle;
* 0: 0x00010040
* 1: ResultCode
*/
-static void RegisterClient(Service::Interface* self) {
+static void RegisterClient(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
if (cmd_buff[1] != IPC::CallingPidDesc()) {
@@ -48,7 +50,7 @@ static void RegisterClient(Service::Interface* self) {
* 2: Translation descriptor: 0x20
* 3: Handle to semaphore signaled on process notification
*/
-static void EnableNotification(Service::Interface* self) {
+static void EnableNotification(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
// TODO(bunnei): Change to a semaphore once these have been implemented
@@ -73,7 +75,7 @@ static void EnableNotification(Service::Interface* self) {
* 1: ResultCode
* 3: Service handle
*/
-static void GetServiceHandle(Service::Interface* self) {
+static void GetServiceHandle(Interface* self) {
ResultCode res = RESULT_SUCCESS;
u32* cmd_buff = Kernel::GetCommandBuffer();
@@ -81,7 +83,15 @@ static void GetServiceHandle(Service::Interface* self) {
auto it = Service::g_srv_services.find(port_name);
if (it != Service::g_srv_services.end()) {
- cmd_buff[3] = Kernel::g_handle_table.Create(it->second).MoveFrom();
+ auto client_port = it->second;
+
+ auto client_session = client_port->Connect();
+ res = client_session.Code();
+
+ if (client_session.Succeeded()) {
+ // Return the client session
+ cmd_buff[3] = Kernel::g_handle_table.Create(*client_session).MoveFrom();
+ }
LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]);
} else {
LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str());
@@ -99,7 +109,7 @@ static void GetServiceHandle(Service::Interface* self) {
* 0: 0x00090040
* 1: ResultCode
*/
-static void Subscribe(Service::Interface* self) {
+static void Subscribe(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 notification_id = cmd_buff[1];
@@ -118,7 +128,7 @@ static void Subscribe(Service::Interface* self) {
* 0: 0x000A0040
* 1: ResultCode
*/
-static void Unsubscribe(Service::Interface* self) {
+static void Unsubscribe(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 notification_id = cmd_buff[1];
@@ -138,7 +148,7 @@ static void Unsubscribe(Service::Interface* self) {
* 0: 0x000C0040
* 1: ResultCode
*/
-static void PublishToSubscriber(Service::Interface* self) {
+static void PublishToSubscriber(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 notification_id = cmd_buff[1];
@@ -167,16 +177,14 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x000E00C0, nullptr, "IsServiceRegistered"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+SRV::SRV() {
Register(FunctionTable);
event_handle = nullptr;
}
-Interface::~Interface() {
+SRV::~SRV() {
event_handle = nullptr;
}
} // namespace SRV
+} // namespace Service
diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h
index 96c89b025..d3a9de879 100644
--- a/src/core/hle/service/srv.h
+++ b/src/core/hle/service/srv.h
@@ -2,22 +2,23 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "core/hle/service/service.h"
+#pragma once
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace SRV
+#include "core/hle/service/service.h"
+namespace Service {
namespace SRV {
/// Interface to "srv:" service
-class Interface : public Service::Interface {
+class SRV final : public Interface {
public:
- Interface();
- ~Interface() override;
+ SRV();
+ ~SRV() override;
std::string GetPortName() const override {
return "srv:";
}
};
-} // namespace
+} // namespace SRV
+} // namespace Service
diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp
index abab1d271..09ced9d7a 100644
--- a/src/core/hle/service/ssl_c.cpp
+++ b/src/core/hle/service/ssl_c.cpp
@@ -6,15 +6,13 @@
#include "common/common_types.h"
#include "core/hle/service/ssl_c.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace SSL_C
-
-namespace SSL_C {
+namespace Service {
+namespace SSL {
// TODO: Implement a proper CSPRNG in the future when actual security is needed
static std::mt19937 rand_gen;
-static void Initialize(Service::Interface* self) {
+static void Initialize(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
// Seed random number generator when the SSL service is initialized
@@ -25,7 +23,7 @@ static void Initialize(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw;
}
-static void GenerateRandomData(Service::Interface* self) {
+static void GenerateRandomData(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 size = cmd_buff[1];
@@ -66,6 +64,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00050082, nullptr, "AddTrustedRootCA"},
{0x00060080, nullptr, "RootCertChainAddDefaultCert"},
{0x00070080, nullptr, "RootCertChainRemoveCert"},
+ {0x000D0084, nullptr, "OpenClientCertContext"},
{0x000E0040, nullptr, "OpenDefaultClientCertContext"},
{0x000F0040, nullptr, "CloseClientCertContext"},
{0x00110042, GenerateRandomData, "GenerateRandomData"},
@@ -73,19 +72,19 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00130040, nullptr, "StartConnection"},
{0x00140040, nullptr, "StartConnectionGetOut"},
{0x00150082, nullptr, "Read"},
+ {0x00160082, nullptr, "ReadPeek"},
{0x00170082, nullptr, "Write"},
{0x00180080, nullptr, "ContextSetRootCertChain"},
{0x00190080, nullptr, "ContextSetClientCert"},
{0x001B0080, nullptr, "ContextClearOpt"},
+ {0x001C00C4, nullptr, "ContextGetProtocolCipher"},
{0x001E0040, nullptr, "DestroyContext"},
{0x001F0082, nullptr, "ContextInitSharedmem"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+SSL_C::SSL_C() {
Register(FunctionTable);
}
-} // namespace
+} // namespace SSL_C
+} // namespace Service
diff --git a/src/core/hle/service/ssl_c.h b/src/core/hle/service/ssl_c.h
index 58e87c1cb..fc50a2eb2 100644
--- a/src/core/hle/service/ssl_c.h
+++ b/src/core/hle/service/ssl_c.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace SSL_C
+namespace Service {
+namespace SSL {
-namespace SSL_C {
-
-class Interface : public Service::Interface {
+class SSL_C final : public Interface {
public:
- Interface();
+ SSL_C();
std::string GetPortName() const override {
return "ssl:C";
}
};
-} // namespace
+} // namespace SSL
+} // namespace Service
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp
index 097e09d28..a20194107 100644
--- a/src/core/hle/service/y2r_u.cpp
+++ b/src/core/hle/service/y2r_u.cpp
@@ -11,10 +11,8 @@
#include "core/hle/service/y2r_u.h"
#include "core/hw/y2r.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace Y2R_U
-
-namespace Y2R_U {
+namespace Service {
+namespace Y2R {
struct ConversionParameters {
InputFormat input_format;
@@ -83,7 +81,7 @@ ResultCode ConversionConfiguration::SetStandardCoefficient(
return RESULT_SUCCESS;
}
-static void SetInputFormat(Service::Interface* self) {
+static void SetInputFormat(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.input_format = static_cast<InputFormat>(cmd_buff[1]);
@@ -94,7 +92,7 @@ static void SetInputFormat(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called input_format=%hhu", conversion.input_format);
}
-static void GetInputFormat(Service::Interface* self) {
+static void GetInputFormat(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x2, 2, 0);
@@ -104,7 +102,7 @@ static void GetInputFormat(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called input_format=%hhu", conversion.input_format);
}
-static void SetOutputFormat(Service::Interface* self) {
+static void SetOutputFormat(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.output_format = static_cast<OutputFormat>(cmd_buff[1]);
@@ -115,7 +113,7 @@ static void SetOutputFormat(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called output_format=%hhu", conversion.output_format);
}
-static void GetOutputFormat(Service::Interface* self) {
+static void GetOutputFormat(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x4, 2, 0);
@@ -125,7 +123,7 @@ static void GetOutputFormat(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called output_format=%hhu", conversion.output_format);
}
-static void SetRotation(Service::Interface* self) {
+static void SetRotation(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.rotation = static_cast<Rotation>(cmd_buff[1]);
@@ -136,7 +134,7 @@ static void SetRotation(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called rotation=%hhu", conversion.rotation);
}
-static void GetRotation(Service::Interface* self) {
+static void GetRotation(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x6, 2, 0);
@@ -146,7 +144,7 @@ static void GetRotation(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called rotation=%hhu", conversion.rotation);
}
-static void SetBlockAlignment(Service::Interface* self) {
+static void SetBlockAlignment(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.block_alignment = static_cast<BlockAlignment>(cmd_buff[1]);
@@ -157,7 +155,7 @@ static void SetBlockAlignment(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called block_alignment=%hhu", conversion.block_alignment);
}
-static void GetBlockAlignment(Service::Interface* self) {
+static void GetBlockAlignment(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x8, 2, 0);
@@ -174,7 +172,7 @@ static void GetBlockAlignment(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetSpacialDithering(Service::Interface* self) {
+static void SetSpacialDithering(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
spacial_dithering_enabled = cmd_buff[1] & 0xF;
@@ -190,7 +188,7 @@ static void SetSpacialDithering(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : u8, 0 = Disabled, 1 = Enabled
*/
-static void GetSpacialDithering(Service::Interface* self) {
+static void GetSpacialDithering(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0);
@@ -207,7 +205,7 @@ static void GetSpacialDithering(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetTemporalDithering(Service::Interface* self) {
+static void SetTemporalDithering(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
temporal_dithering_enabled = cmd_buff[1] & 0xF;
@@ -223,7 +221,7 @@ static void SetTemporalDithering(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : u8, 0 = Disabled, 1 = Enabled
*/
-static void GetTemporalDithering(Service::Interface* self) {
+static void GetTemporalDithering(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0xC, 2, 0);
@@ -240,7 +238,7 @@ static void GetTemporalDithering(Service::Interface* self) {
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
-static void SetTransferEndInterrupt(Service::Interface* self) {
+static void SetTransferEndInterrupt(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
transfer_end_interrupt_enabled = cmd_buff[1] & 0xf;
@@ -256,7 +254,7 @@ static void SetTransferEndInterrupt(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : u8, 0 = Disabled, 1 = Enabled
*/
-static void GetTransferEndInterrupt(Service::Interface* self) {
+static void GetTransferEndInterrupt(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0xE, 2, 0);
@@ -272,7 +270,7 @@ static void GetTransferEndInterrupt(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 3 : The handle of the completion event
*/
-static void GetTransferEndEvent(Service::Interface* self) {
+static void GetTransferEndEvent(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0xF, 2, 0);
@@ -282,7 +280,7 @@ static void GetTransferEndEvent(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called");
}
-static void SetSendingY(Service::Interface* self) {
+static void SetSendingY(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.src_Y.address = cmd_buff[1];
@@ -299,7 +297,7 @@ static void SetSendingY(Service::Interface* self) {
cmd_buff[6]);
}
-static void SetSendingU(Service::Interface* self) {
+static void SetSendingU(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.src_U.address = cmd_buff[1];
@@ -316,7 +314,7 @@ static void SetSendingU(Service::Interface* self) {
cmd_buff[6]);
}
-static void SetSendingV(Service::Interface* self) {
+static void SetSendingV(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.src_V.address = cmd_buff[1];
@@ -333,7 +331,7 @@ static void SetSendingV(Service::Interface* self) {
cmd_buff[6]);
}
-static void SetSendingYUYV(Service::Interface* self) {
+static void SetSendingYUYV(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.src_YUYV.address = cmd_buff[1];
@@ -356,7 +354,7 @@ static void SetSendingYUYV(Service::Interface* self) {
* 1 : Result of the function, 0 on success, otherwise error code
* 2 : u8, 0 = Not Finished, 1 = Finished
*/
-static void IsFinishedSendingYuv(Service::Interface* self) {
+static void IsFinishedSendingYuv(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x14, 2, 0);
@@ -372,7 +370,7 @@ static void IsFinishedSendingYuv(Service::Interface* self) {
* 1 : Result of the function, 0 on success, otherwise error code
* 2 : u8, 0 = Not Finished, 1 = Finished
*/
-static void IsFinishedSendingY(Service::Interface* self) {
+static void IsFinishedSendingY(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x15, 2, 0);
@@ -388,7 +386,7 @@ static void IsFinishedSendingY(Service::Interface* self) {
* 1 : Result of the function, 0 on success, otherwise error code
* 2 : u8, 0 = Not Finished, 1 = Finished
*/
-static void IsFinishedSendingU(Service::Interface* self) {
+static void IsFinishedSendingU(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x16, 2, 0);
@@ -404,7 +402,7 @@ static void IsFinishedSendingU(Service::Interface* self) {
* 1 : Result of the function, 0 on success, otherwise error code
* 2 : u8, 0 = Not Finished, 1 = Finished
*/
-static void IsFinishedSendingV(Service::Interface* self) {
+static void IsFinishedSendingV(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x17, 2, 0);
@@ -414,7 +412,7 @@ static void IsFinishedSendingV(Service::Interface* self) {
LOG_WARNING(Service_Y2R, "(STUBBED) called");
}
-static void SetReceiving(Service::Interface* self) {
+static void SetReceiving(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.dst.address = cmd_buff[1];
@@ -437,7 +435,7 @@ static void SetReceiving(Service::Interface* self) {
* 1 : Result of the function, 0 on success, otherwise error code
* 2 : u8, 0 = Not Finished, 1 = Finished
*/
-static void IsFinishedReceiving(Service::Interface* self) {
+static void IsFinishedReceiving(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x19, 2, 0);
@@ -447,7 +445,7 @@ static void IsFinishedReceiving(Service::Interface* self) {
LOG_WARNING(Service_Y2R, "(STUBBED) called");
}
-static void SetInputLineWidth(Service::Interface* self) {
+static void SetInputLineWidth(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x1A, 1, 0);
@@ -456,7 +454,7 @@ static void SetInputLineWidth(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called input_line_width=%u", cmd_buff[1]);
}
-static void GetInputLineWidth(Service::Interface* self) {
+static void GetInputLineWidth(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x1B, 2, 0);
@@ -466,7 +464,7 @@ static void GetInputLineWidth(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called input_line_width=%u", conversion.input_line_width);
}
-static void SetInputLines(Service::Interface* self) {
+static void SetInputLines(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x1C, 1, 0);
@@ -475,7 +473,7 @@ static void SetInputLines(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called input_lines=%u", cmd_buff[1]);
}
-static void GetInputLines(Service::Interface* self) {
+static void GetInputLines(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x1D, 2, 0);
@@ -485,7 +483,7 @@ static void GetInputLines(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called input_lines=%u", conversion.input_lines);
}
-static void SetCoefficient(Service::Interface* self) {
+static void SetCoefficient(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
const u16* coefficients = reinterpret_cast<const u16*>(&cmd_buff[1]);
@@ -499,7 +497,7 @@ static void SetCoefficient(Service::Interface* self) {
coefficients[5], coefficients[6], coefficients[7]);
}
-static void GetCoefficient(Service::Interface* self) {
+static void GetCoefficient(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x1F, 5, 0);
@@ -509,7 +507,7 @@ static void GetCoefficient(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called");
}
-static void SetStandardCoefficient(Service::Interface* self) {
+static void SetStandardCoefficient(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 index = cmd_buff[1];
@@ -520,7 +518,7 @@ static void SetStandardCoefficient(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called standard_coefficient=%u", index);
}
-static void GetStandardCoefficient(Service::Interface* self) {
+static void GetStandardCoefficient(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 index = cmd_buff[1];
@@ -539,7 +537,7 @@ static void GetStandardCoefficient(Service::Interface* self) {
}
}
-static void SetAlpha(Service::Interface* self) {
+static void SetAlpha(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.alpha = cmd_buff[1];
@@ -550,7 +548,7 @@ static void SetAlpha(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called alpha=%hu", conversion.alpha);
}
-static void GetAlpha(Service::Interface* self) {
+static void GetAlpha(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x23, 2, 0);
@@ -560,7 +558,7 @@ static void GetAlpha(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called alpha=%hu", conversion.alpha);
}
-static void SetDitheringWeightParams(Service::Interface* self) {
+static void SetDitheringWeightParams(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
std::memcpy(&dithering_weight_params, &cmd_buff[1], sizeof(DitheringWeightParams));
@@ -570,7 +568,7 @@ static void SetDitheringWeightParams(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called");
}
-static void GetDitheringWeightParams(Service::Interface* self) {
+static void GetDitheringWeightParams(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x25, 9, 0);
@@ -580,7 +578,7 @@ static void GetDitheringWeightParams(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called");
}
-static void StartConversion(Service::Interface* self) {
+static void StartConversion(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
// dst_image_size would seem to be perfect for this, but it doesn't include the gap :(
@@ -599,7 +597,7 @@ static void StartConversion(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called");
}
-static void StopConversion(Service::Interface* self) {
+static void StopConversion(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x27, 1, 0);
@@ -614,7 +612,7 @@ static void StopConversion(Service::Interface* self) {
* 1 : Result of function, 0 on success, otherwise error code
* 2 : 1 if there's a conversion running, otherwise 0.
*/
-static void IsBusyConversion(Service::Interface* self) {
+static void IsBusyConversion(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x28, 2, 0);
@@ -627,7 +625,7 @@ static void IsBusyConversion(Service::Interface* self) {
/**
* Y2R_U::SetPackageParameter service function
*/
-static void SetPackageParameter(Service::Interface* self) {
+static void SetPackageParameter(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
auto params = reinterpret_cast<const ConversionParameters*>(&cmd_buff[1]);
@@ -668,7 +666,7 @@ cleanup:
params->padding, params->alpha);
}
-static void PingProcess(Service::Interface* self) {
+static void PingProcess(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x2A, 2, 0);
@@ -678,7 +676,7 @@ static void PingProcess(Service::Interface* self) {
LOG_WARNING(Service_Y2R, "(STUBBED) called");
}
-static void DriverInitialize(Service::Interface* self) {
+static void DriverInitialize(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
conversion.input_format = InputFormat::YUV422_Indiv8;
@@ -704,7 +702,7 @@ static void DriverInitialize(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called");
}
-static void DriverFinalize(Service::Interface* self) {
+static void DriverFinalize(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x2C, 1, 0);
@@ -713,7 +711,7 @@ static void DriverFinalize(Service::Interface* self) {
LOG_DEBUG(Service_Y2R, "called");
}
-static void GetPackageParameter(Service::Interface* self) {
+static void GetPackageParameter(Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
cmd_buff[0] = IPC::MakeHeader(0x2D, 4, 0);
@@ -771,18 +769,16 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x002D0000, GetPackageParameter, "GetPackageParameter"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+Y2R_U::Y2R_U() {
completion_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "Y2R:Completed");
std::memset(&conversion, 0, sizeof(conversion));
Register(FunctionTable);
}
-Interface::~Interface() {
+Y2R_U::~Y2R_U() {
completion_event = nullptr;
}
-} // namespace
+} // namespace Y2R
+} // namespace Service \ No newline at end of file
diff --git a/src/core/hle/service/y2r_u.h b/src/core/hle/service/y2r_u.h
index 1b47b5322..dddeed0be 100644
--- a/src/core/hle/service/y2r_u.h
+++ b/src/core/hle/service/y2r_u.h
@@ -10,10 +10,8 @@
#include "core/hle/result.h"
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace Y2R_U
-
-namespace Y2R_U {
+namespace Service {
+namespace Y2R {
enum class InputFormat : u8 {
/// 8-bit input, with YUV components in separate planes and 4:2:2 subsampling.
@@ -127,14 +125,15 @@ struct DitheringWeightParams {
u16 w3_xOdd_yOdd;
};
-class Interface : public Service::Interface {
+class Y2R_U final : public Interface {
public:
- Interface();
- ~Interface() override;
+ Y2R_U();
+ ~Y2R_U() override;
std::string GetPortName() const override {
return "y2r:u";
}
};
-} // namespace
+} // namespace Y2R
+} // namespace Service
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index c6b80dc50..2ca270de3 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -13,6 +13,7 @@
#include "core/hle/function_wrappers.h"
#include "core/hle/kernel/address_arbiter.h"
#include "core/hle/kernel/client_port.h"
+#include "core/hle/kernel/client_session.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/mutex.h"
@@ -20,6 +21,7 @@
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/semaphore.h"
#include "core/hle/kernel/server_port.h"
+#include "core/hle/kernel/server_session.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h"
@@ -41,6 +43,9 @@ const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS,
ErrorSummary::InvalidArgument,
ErrorLevel::Usage); // 0xE0E0181E
+const ResultCode ERR_SYNC_TIMEOUT(ErrorDescription::Timeout, ErrorModule::OS,
+ ErrorSummary::StatusChanged, ErrorLevel::Info);
+
const ResultCode ERR_MISALIGNED_ADDRESS{// 0xE0E01BF1
ErrorDescription::MisalignedAddress, ErrorModule::OS,
ErrorSummary::InvalidArgument, ErrorLevel::Usage};
@@ -161,7 +166,8 @@ static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 add
}
/// Maps a memory block to specified address
-static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) {
+static ResultCode MapMemoryBlock(Kernel::Handle handle, u32 addr, u32 permissions,
+ u32 other_permissions) {
using Kernel::SharedMemory;
using Kernel::MemoryPermission;
@@ -193,7 +199,7 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
}
-static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) {
+static ResultCode UnmapMemoryBlock(Kernel::Handle handle, u32 addr) {
using Kernel::SharedMemory;
LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X", handle, addr);
@@ -208,7 +214,7 @@ static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) {
}
/// Connect to an OS service given the port name, returns the handle to the port to out
-static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) {
+static ResultCode ConnectToPort(Kernel::Handle* out_handle, const char* port_name) {
if (port_name == nullptr)
return ERR_NOT_FOUND;
if (std::strlen(port_name) > 11)
@@ -222,54 +228,66 @@ static ResultCode ConnectToPort(Handle* out_handle, const char* port_name) {
return ERR_NOT_FOUND;
}
- CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(it->second));
+ auto client_port = it->second;
+
+ SharedPtr<Kernel::ClientSession> client_session;
+ CASCADE_RESULT(client_session, client_port->Connect());
+
+ // Return the client session
+ CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(client_session));
return RESULT_SUCCESS;
}
-/// Synchronize to an OS service
-static ResultCode SendSyncRequest(Handle handle) {
- SharedPtr<Kernel::Session> session = Kernel::g_handle_table.Get<Kernel::Session>(handle);
+/// Makes a blocking IPC call to an OS service.
+static ResultCode SendSyncRequest(Kernel::Handle handle) {
+ SharedPtr<Kernel::ClientSession> session =
+ Kernel::g_handle_table.Get<Kernel::ClientSession>(handle);
if (session == nullptr) {
return ERR_INVALID_HANDLE;
}
LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str());
- return session->SyncRequest().Code();
+ // TODO(Subv): svcSendSyncRequest should put the caller thread to sleep while the server
+ // responds and cause a reschedule.
+ return session->SendSyncRequest();
}
/// Close a handle
-static ResultCode CloseHandle(Handle handle) {
+static ResultCode CloseHandle(Kernel::Handle handle) {
LOG_TRACE(Kernel_SVC, "Closing handle 0x%08X", handle);
return Kernel::g_handle_table.Close(handle);
}
/// Wait for a handle to synchronize, timeout after the specified nanoseconds
-static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) {
+static ResultCode WaitSynchronization1(Kernel::Handle handle, s64 nano_seconds) {
auto object = Kernel::g_handle_table.GetWaitObject(handle);
Kernel::Thread* thread = Kernel::GetCurrentThread();
- thread->waitsynch_waited = false;
-
if (object == nullptr)
return ERR_INVALID_HANDLE;
LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle,
object->GetTypeName().c_str(), object->GetName().c_str(), nano_seconds);
- HLE::Reschedule(__func__);
-
- // Check for next thread to schedule
if (object->ShouldWait()) {
+ if (nano_seconds == 0)
+ return ERR_SYNC_TIMEOUT;
+
object->AddWaitingThread(thread);
- Kernel::WaitCurrentThread_WaitSynchronization({object}, false, false);
+ // TODO(Subv): Perform things like update the mutex lock owner's priority to
+ // prevent priority inversion. Currently this is done in Mutex::ShouldWait,
+ // but it should be moved to a function that is called from here.
+ thread->status = THREADSTATUS_WAIT_SYNCH;
// Create an event to wake the thread up after the specified nanosecond delay has passed
thread->WakeAfterDelay(nano_seconds);
- // NOTE: output of this SVC will be set later depending on how the thread resumes
- return HLE::RESULT_INVALID;
+ // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread
+ // resumes due to a signal in its wait objects.
+ // Otherwise we retain the default value of timeout.
+ return ERR_SYNC_TIMEOUT;
}
object->Acquire();
@@ -278,13 +296,9 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) {
}
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
-static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all,
- s64 nano_seconds) {
- bool wait_thread = !wait_all;
- int handle_index = 0;
+static ResultCode WaitSynchronizationN(s32* out, Kernel::Handle* handles, s32 handle_count,
+ bool wait_all, s64 nano_seconds) {
Kernel::Thread* thread = Kernel::GetCurrentThread();
- bool was_waiting = thread->waitsynch_waited;
- thread->waitsynch_waited = false;
// Check if 'handles' is invalid
if (handles == nullptr)
@@ -300,94 +314,117 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS,
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
- // If 'handle_count' is non-zero, iterate through each handle and wait the current thread if
- // necessary
- if (handle_count != 0) {
- bool selected = false; // True once an object has been selected
-
- Kernel::SharedPtr<Kernel::WaitObject> wait_object;
-
- for (int i = 0; i < handle_count; ++i) {
- auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
- if (object == nullptr)
- return ERR_INVALID_HANDLE;
-
- // Check if the current thread should wait on this object...
- if (object->ShouldWait()) {
-
- // Check we are waiting on all objects...
- if (wait_all)
- // Wait the thread
- wait_thread = true;
- } else {
- // Do not wait on this object, check if this object should be selected...
- if (!wait_all && (!selected || (wait_object == object && was_waiting))) {
- // Do not wait the thread
- wait_thread = false;
- handle_index = i;
- wait_object = object;
- selected = true;
- }
- }
- }
- } else {
- // If no handles were passed in, put the thread to sleep only when 'wait_all' is false
- // NOTE: This should deadlock the current thread if no timeout was specified
- if (!wait_all) {
- wait_thread = true;
- }
+ using ObjectPtr = Kernel::SharedPtr<Kernel::WaitObject>;
+ std::vector<ObjectPtr> objects(handle_count);
+
+ for (int i = 0; i < handle_count; ++i) {
+ auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
+ if (object == nullptr)
+ return ERR_INVALID_HANDLE;
+ objects[i] = object;
}
- SCOPE_EXIT({
- HLE::Reschedule("WaitSynchronizationN");
- }); // Reschedule after putting the threads to sleep.
+ // Clear the mapping of wait object indices.
+ // We don't want any lingering state in this map.
+ // It will be repopulated later in the wait_all = false case.
+ thread->wait_objects_index.clear();
+
+ if (wait_all) {
+ bool all_available =
+ std::all_of(objects.begin(), objects.end(),
+ [](const ObjectPtr& object) { return !object->ShouldWait(); });
+ if (all_available) {
+ // We can acquire all objects right now, do so.
+ for (auto& object : objects)
+ object->Acquire();
+ // Note: In this case, the `out` parameter is not set,
+ // and retains whatever value it had before.
+ return RESULT_SUCCESS;
+ }
+
+ // Not all objects were available right now, prepare to suspend the thread.
- // If thread should wait, then set its state to waiting
- if (wait_thread) {
+ // If a timeout value of 0 was provided, just return the Timeout error code instead of
+ // suspending the thread.
+ if (nano_seconds == 0)
+ return ERR_SYNC_TIMEOUT;
- // Actually wait the current thread on each object if we decided to wait...
- std::vector<SharedPtr<Kernel::WaitObject>> wait_objects;
- wait_objects.reserve(handle_count);
+ // Put the thread to sleep
+ thread->status = THREADSTATUS_WAIT_SYNCH;
- for (int i = 0; i < handle_count; ++i) {
- auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
- object->AddWaitingThread(Kernel::GetCurrentThread());
- wait_objects.push_back(object);
+ // Add the thread to each of the objects' waiting threads.
+ for (auto& object : objects) {
+ object->AddWaitingThread(thread);
+ // TODO(Subv): Perform things like update the mutex lock owner's priority to
+ // prevent priority inversion. Currently this is done in Mutex::ShouldWait,
+ // but it should be moved to a function that is called from here.
}
- Kernel::WaitCurrentThread_WaitSynchronization(std::move(wait_objects), true, wait_all);
+ // Set the thread's waitlist to the list of objects passed to WaitSynchronizationN
+ thread->wait_objects = std::move(objects);
// Create an event to wake the thread up after the specified nanosecond delay has passed
- Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds);
-
- // NOTE: output of this SVC will be set later depending on how the thread resumes
- return HLE::RESULT_INVALID;
- }
+ thread->WakeAfterDelay(nano_seconds);
- // Acquire objects if we did not wait...
- for (int i = 0; i < handle_count; ++i) {
- auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
+ // This value gets set to -1 by default in this case, it is not modified after this.
+ *out = -1;
+ // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to
+ // a signal in one of its wait objects.
+ return ERR_SYNC_TIMEOUT;
+ } else {
+ // Find the first object that is acquirable in the provided list of objects
+ auto itr = std::find_if(objects.begin(), objects.end(),
+ [](const ObjectPtr& object) { return !object->ShouldWait(); });
- // Acquire the object if it is not waiting...
- if (!object->ShouldWait()) {
+ if (itr != objects.end()) {
+ // We found a ready object, acquire it and set the result value
+ Kernel::WaitObject* object = itr->get();
object->Acquire();
+ *out = std::distance(objects.begin(), itr);
+ return RESULT_SUCCESS;
+ }
+
+ // No objects were ready to be acquired, prepare to suspend the thread.
+
+ // If a timeout value of 0 was provided, just return the Timeout error code instead of
+ // suspending the thread.
+ if (nano_seconds == 0)
+ return ERR_SYNC_TIMEOUT;
+
+ // Put the thread to sleep
+ thread->status = THREADSTATUS_WAIT_SYNCH;
- // If this was the first non-waiting object and 'wait_all' is false, don't acquire
- // any other objects
- if (!wait_all)
- break;
+ // Clear the thread's waitlist, we won't use it for wait_all = false
+ thread->wait_objects.clear();
+
+ // Add the thread to each of the objects' waiting threads.
+ for (size_t i = 0; i < objects.size(); ++i) {
+ Kernel::WaitObject* object = objects[i].get();
+ // Set the index of this object in the mapping of Objects -> index for this thread.
+ thread->wait_objects_index[object->GetObjectId()] = static_cast<int>(i);
+ object->AddWaitingThread(thread);
+ // TODO(Subv): Perform things like update the mutex lock owner's priority to
+ // prevent priority inversion. Currently this is done in Mutex::ShouldWait,
+ // but it should be moved to a function that is called from here.
}
- }
- // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does
- // not seem to set it to any meaningful value.
- *out = handle_count != 0 ? (wait_all ? -1 : handle_index) : 0;
+ // Note: If no handles and no timeout were given, then the thread will deadlock, this is
+ // consistent with hardware behavior.
- return RESULT_SUCCESS;
+ // Create an event to wake the thread up after the specified nanosecond delay has passed
+ thread->WakeAfterDelay(nano_seconds);
+
+ // Note: The output of this SVC will be set to RESULT_SUCCESS if the thread resumes due to a
+ // signal in one of its wait objects.
+ // Otherwise we retain the default value of timeout, and -1 in the out parameter
+ thread->wait_set_output = true;
+ *out = -1;
+ return ERR_SYNC_TIMEOUT;
+ }
}
/// Create an address arbiter (to allocate access to shared resources)
-static ResultCode CreateAddressArbiter(Handle* out_handle) {
+static ResultCode CreateAddressArbiter(Kernel::Handle* out_handle) {
using Kernel::AddressArbiter;
SharedPtr<AddressArbiter> arbiter = AddressArbiter::Create();
@@ -397,7 +434,7 @@ static ResultCode CreateAddressArbiter(Handle* out_handle) {
}
/// Arbitrate address
-static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 value,
+static ResultCode ArbitrateAddress(Kernel::Handle handle, u32 address, u32 type, u32 value,
s64 nanoseconds) {
using Kernel::AddressArbiter;
@@ -440,7 +477,7 @@ static void OutputDebugString(const char* string) {
}
/// Get resource limit
-static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle) {
+static ResultCode GetResourceLimit(Kernel::Handle* resource_limit, Kernel::Handle process_handle) {
LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle);
SharedPtr<Kernel::Process> process =
@@ -454,7 +491,7 @@ static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle
}
/// Get resource limit current values
-static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit_handle,
+static ResultCode GetResourceLimitCurrentValues(s64* values, Kernel::Handle resource_limit_handle,
u32* names, u32 name_count) {
LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
resource_limit_handle, names, name_count);
@@ -471,8 +508,8 @@ static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_lim
}
/// Get resource limit max values
-static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit_handle, u32* names,
- u32 name_count) {
+static ResultCode GetResourceLimitLimitValues(s64* values, Kernel::Handle resource_limit_handle,
+ u32* names, u32 name_count) {
LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
resource_limit_handle, names, name_count);
@@ -488,7 +525,7 @@ static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit
}
/// Creates a new thread
-static ResultCode CreateThread(Handle* out_handle, s32 priority, u32 entry_point, u32 arg,
+static ResultCode CreateThread(Kernel::Handle* out_handle, s32 priority, u32 entry_point, u32 arg,
u32 stack_top, s32 processor_id) {
using Kernel::Thread;
@@ -546,13 +583,13 @@ static ResultCode CreateThread(Handle* out_handle, s32 priority, u32 entry_point
/// Called when a thread exits
static void ExitThread() {
- LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::g_app_core->GetPC());
+ LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::CPU().GetPC());
- Kernel::GetCurrentThread()->Stop();
+ Kernel::ExitCurrentThread();
}
/// Gets the priority for the specified thread
-static ResultCode GetThreadPriority(s32* priority, Handle handle) {
+static ResultCode GetThreadPriority(s32* priority, Kernel::Handle handle) {
const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
if (thread == nullptr)
return ERR_INVALID_HANDLE;
@@ -562,7 +599,7 @@ static ResultCode GetThreadPriority(s32* priority, Handle handle) {
}
/// Sets the priority for the specified thread
-static ResultCode SetThreadPriority(Handle handle, s32 priority) {
+static ResultCode SetThreadPriority(Kernel::Handle handle, s32 priority) {
SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
if (thread == nullptr)
return ERR_INVALID_HANDLE;
@@ -572,11 +609,11 @@ static ResultCode SetThreadPriority(Handle handle, s32 priority) {
}
/// Create a mutex
-static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) {
+static ResultCode CreateMutex(Kernel::Handle* out_handle, u32 initial_locked) {
using Kernel::Mutex;
SharedPtr<Mutex> mutex = Mutex::Create(initial_locked != 0);
- mutex->name = Common::StringFromFormat("mutex-%08x", Core::g_app_core->GetReg(14));
+ mutex->name = Common::StringFromFormat("mutex-%08x", Core::CPU().GetReg(14));
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex)));
LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X",
@@ -586,7 +623,7 @@ static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) {
}
/// Release a mutex
-static ResultCode ReleaseMutex(Handle handle) {
+static ResultCode ReleaseMutex(Kernel::Handle handle) {
using Kernel::Mutex;
LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle);
@@ -601,7 +638,7 @@ static ResultCode ReleaseMutex(Handle handle) {
}
/// Get the ID of the specified process
-static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
+static ResultCode GetProcessId(u32* process_id, Kernel::Handle process_handle) {
LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle);
const SharedPtr<Kernel::Process> process =
@@ -614,7 +651,7 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
}
/// Get the ID of the process that owns the specified thread
-static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
+static ResultCode GetProcessIdOfThread(u32* process_id, Kernel::Handle thread_handle) {
LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle);
const SharedPtr<Kernel::Thread> thread =
@@ -631,7 +668,7 @@ static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
}
/// Get the ID for the specified thread.
-static ResultCode GetThreadId(u32* thread_id, Handle handle) {
+static ResultCode GetThreadId(u32* thread_id, Kernel::Handle handle) {
LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle);
const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(handle);
@@ -643,11 +680,11 @@ static ResultCode GetThreadId(u32* thread_id, Handle handle) {
}
/// Creates a semaphore
-static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_count) {
+static ResultCode CreateSemaphore(Kernel::Handle* out_handle, s32 initial_count, s32 max_count) {
using Kernel::Semaphore;
CASCADE_RESULT(SharedPtr<Semaphore> semaphore, Semaphore::Create(initial_count, max_count));
- semaphore->name = Common::StringFromFormat("semaphore-%08x", Core::g_app_core->GetReg(14));
+ semaphore->name = Common::StringFromFormat("semaphore-%08x", Core::CPU().GetReg(14));
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(semaphore)));
LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X",
@@ -656,7 +693,7 @@ static ResultCode CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max
}
/// Releases a certain number of slots in a semaphore
-static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {
+static ResultCode ReleaseSemaphore(s32* count, Kernel::Handle handle, s32 release_count) {
using Kernel::Semaphore;
LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, handle);
@@ -672,7 +709,7 @@ static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count)
/// Query process memory
static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info,
- Handle process_handle, u32 addr) {
+ Kernel::Handle process_handle, u32 addr) {
using Kernel::Process;
Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle);
if (process == nullptr)
@@ -700,11 +737,11 @@ static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32
}
/// Create an event
-static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) {
+static ResultCode CreateEvent(Kernel::Handle* out_handle, u32 reset_type) {
using Kernel::Event;
SharedPtr<Event> evt = Event::Create(static_cast<Kernel::ResetType>(reset_type));
- evt->name = Common::StringFromFormat("event-%08x", Core::g_app_core->GetReg(14));
+ evt->name = Common::StringFromFormat("event-%08x", Core::CPU().GetReg(14));
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(evt)));
LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", reset_type,
@@ -713,14 +750,14 @@ static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) {
}
/// Duplicates a kernel handle
-static ResultCode DuplicateHandle(Handle* out, Handle handle) {
+static ResultCode DuplicateHandle(Kernel::Handle* out, Kernel::Handle handle) {
CASCADE_RESULT(*out, Kernel::g_handle_table.Duplicate(handle));
LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out);
return RESULT_SUCCESS;
}
/// Signals an event
-static ResultCode SignalEvent(Handle handle) {
+static ResultCode SignalEvent(Kernel::Handle handle) {
using Kernel::Event;
LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle);
@@ -734,7 +771,7 @@ static ResultCode SignalEvent(Handle handle) {
}
/// Clears an event
-static ResultCode ClearEvent(Handle handle) {
+static ResultCode ClearEvent(Kernel::Handle handle) {
using Kernel::Event;
LOG_TRACE(Kernel_SVC, "called event=0x%08X", handle);
@@ -747,11 +784,11 @@ static ResultCode ClearEvent(Handle handle) {
}
/// Creates a timer
-static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) {
+static ResultCode CreateTimer(Kernel::Handle* out_handle, u32 reset_type) {
using Kernel::Timer;
SharedPtr<Timer> timer = Timer::Create(static_cast<Kernel::ResetType>(reset_type));
- timer->name = Common::StringFromFormat("timer-%08x", Core::g_app_core->GetReg(14));
+ timer->name = Common::StringFromFormat("timer-%08x", Core::CPU().GetReg(14));
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(timer)));
LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X", reset_type,
@@ -760,7 +797,7 @@ static ResultCode CreateTimer(Handle* out_handle, u32 reset_type) {
}
/// Clears a timer
-static ResultCode ClearTimer(Handle handle) {
+static ResultCode ClearTimer(Kernel::Handle handle) {
using Kernel::Timer;
LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle);
@@ -774,7 +811,7 @@ static ResultCode ClearTimer(Handle handle) {
}
/// Starts a timer
-static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) {
+static ResultCode SetTimer(Kernel::Handle handle, s64 initial, s64 interval) {
using Kernel::Timer;
LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle);
@@ -789,7 +826,7 @@ static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) {
}
/// Cancels a timer
-static ResultCode CancelTimer(Handle handle) {
+static ResultCode CancelTimer(Kernel::Handle handle) {
using Kernel::Timer;
LOG_TRACE(Kernel_SVC, "called timer=0x%08X", handle);
@@ -818,14 +855,13 @@ static void SleepThread(s64 nanoseconds) {
static s64 GetSystemTick() {
s64 result = CoreTiming::GetTicks();
// Advance time to defeat dumb games (like Cubic Ninja) that busy-wait for the frame to end.
- Core::g_app_core->AddTicks(
- 150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b
+ Core::CPU().AddTicks(150); // Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b
return result;
}
/// Creates a memory block at the specified address with the specified permissions and size
-static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 my_permission,
- u32 other_permission) {
+static ResultCode CreateMemoryBlock(Kernel::Handle* out_handle, u32 addr, u32 size,
+ u32 my_permission, u32 other_permission) {
using Kernel::SharedMemory;
if (size % Memory::PAGE_SIZE != 0)
@@ -876,8 +912,8 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
return RESULT_SUCCESS;
}
-static ResultCode CreatePort(Handle* server_port, Handle* client_port, const char* name,
- u32 max_sessions) {
+static ResultCode CreatePort(Kernel::Handle* server_port, Kernel::Handle* client_port,
+ const char* name, u32 max_sessions) {
// TODO(Subv): Implement named ports.
ASSERT_MSG(name == nullptr, "Named ports are currently unimplemented");
@@ -942,7 +978,7 @@ static ResultCode GetSystemInfo(s64* out, u32 type, s32 param) {
return RESULT_SUCCESS;
}
-static ResultCode GetProcessInfo(s64* out, Handle process_handle, u32 type) {
+static ResultCode GetProcessInfo(s64* out, Kernel::Handle process_handle, u32 type) {
LOG_TRACE(Kernel_SVC, "called process=0x%08X type=%u", process_handle, type);
using Kernel::Process;
@@ -1148,6 +1184,8 @@ void CallSVC(u32 immediate) {
if (info) {
if (info->func) {
info->func();
+ // TODO(Subv): Not all service functions should cause a reschedule in all cases.
+ Core::System::GetInstance().PrepareReschedule();
} else {
LOG_ERROR(Kernel_SVC, "unimplemented SVC function %s(..)", info->name);
}
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index cfba82e51..1a1ee90b2 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -430,9 +430,9 @@ inline void Write(u32 addr, const T data) {
// TODO: hwtest this
if (config.GetStartAddress() != 0) {
if (!is_second_filler) {
- GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC0);
+ Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PSC0);
} else {
- GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC1);
+ Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PSC1);
}
}
@@ -473,7 +473,7 @@ inline void Write(u32 addr, const T data) {
}
g_regs.display_transfer_config.trigger = 0;
- GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF);
+ Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PPF);
}
break;
}
@@ -487,8 +487,8 @@ inline void Write(u32 addr, const T data) {
u32* buffer = (u32*)Memory::GetPhysicalPointer(config.GetPhysicalAddress());
if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
- Pica::g_debug_context->recorder->MemoryAccessed(
- (u8*)buffer, config.size * sizeof(u32), config.GetPhysicalAddress());
+ Pica::g_debug_context->recorder->MemoryAccessed((u8*)buffer, config.size,
+ config.GetPhysicalAddress());
}
Pica::CommandProcessor::ProcessCommandList(buffer, config.size);
@@ -548,8 +548,8 @@ static void VBlankCallback(u64 userdata, int cycles_late) {
// screen, or if both use the same interrupts and these two instead determine the
// beginning and end of the VBlank period. If needed, split the interrupt firing into
// two different intervals.
- GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0);
- GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1);
+ Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC0);
+ Service::GSP::SignalInterrupt(Service::GSP::InterruptId::PDC1);
// Check for user input updates
Service::HID::Update();
diff --git a/src/core/hw/y2r.cpp b/src/core/hw/y2r.cpp
index 6a6c707a2..e697f84b3 100644
--- a/src/core/hw/y2r.cpp
+++ b/src/core/hw/y2r.cpp
@@ -18,7 +18,7 @@
namespace HW {
namespace Y2R {
-using namespace Y2R_U;
+using namespace Service::Y2R;
static const size_t MAX_TILES = 1024 / 8;
static const size_t TILE_SIZE = 8 * 8;
diff --git a/src/core/hw/y2r.h b/src/core/hw/y2r.h
index 6b6e71bec..25fcd781c 100644
--- a/src/core/hw/y2r.h
+++ b/src/core/hw/y2r.h
@@ -2,13 +2,16 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-namespace Y2R_U {
+#pragma once
+
+namespace Service {
+namespace Y2R {
struct ConversionConfiguration;
}
+}
namespace HW {
namespace Y2R {
-
-void PerformConversion(Y2R_U::ConversionConfiguration& cvt);
+void PerformConversion(Service::Y2R::ConversionConfiguration& cvt);
}
}
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h
index cfcc21cc4..3f376778a 100644
--- a/src/core/loader/3dsx.h
+++ b/src/core/loader/3dsx.h
@@ -27,34 +27,14 @@ public:
*/
static FileType IdentifyType(FileUtil::IOFile& file);
- /**
- * Returns the type of this file
- * @return FileType corresponding to the loaded file
- */
FileType GetFileType() override {
return IdentifyType(file);
}
- /**
- * Load the bootable file
- * @return ResultStatus result of function
- */
ResultStatus Load() override;
- /**
- * Get the icon (typically icon section) of the application
- * @param buffer Reference to buffer to store data
- * @return ResultStatus result of function
- */
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
- /**
- * Get the RomFS of the application
- * @param romfs_file Reference to buffer to store data
- * @param offset Offset in the file to the RomFS
- * @param size Size of the RomFS in bytes
- * @return ResultStatus result of function
- */
ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset,
u64& size) override;
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 584bf6e27..862aa90d8 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -26,18 +26,10 @@ public:
*/
static FileType IdentifyType(FileUtil::IOFile& file);
- /**
- * Returns the type of this file
- * @return FileType corresponding to the loaded file
- */
FileType GetFileType() override {
return IdentifyType(file);
}
- /**
- * Load the bootable file
- * @return ResultStatus result of function
- */
ResultStatus Load() override;
private:
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 5e3d46638..a6c2a745f 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -144,6 +144,15 @@ public:
}
/**
+ * Get the program id of the application
+ * @param out_program_id Reference to store program id into
+ * @return ResultStatus result of function
+ */
+ virtual ResultStatus ReadProgramId(u64& out_program_id) {
+ return ResultStatus::ErrorNotImplemented;
+ }
+
+ /**
* Get the RomFS of the application
* Since the RomFS can be huge, we return a file reference instead of copying to a buffer
* @param romfs_file The file containing the RomFS
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index dce7f50f9..a204dc336 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -366,6 +366,18 @@ ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) {
return LoadSectionExeFS("logo", buffer);
}
+ResultStatus AppLoader_NCCH::ReadProgramId(u64& out_program_id) {
+ if (!file.IsOpen())
+ return ResultStatus::Error;
+
+ ResultStatus result = LoadExeFS();
+ if (result != ResultStatus::Success)
+ return result;
+
+ out_program_id = ncch_header.program_id;
+ return ResultStatus::Success;
+}
+
ResultStatus AppLoader_NCCH::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset,
u64& size) {
if (!file.IsOpen())
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index e9e11727b..fe08f5b45 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -171,18 +171,10 @@ public:
*/
static FileType IdentifyType(FileUtil::IOFile& file);
- /**
- * Returns the type of this file
- * @return FileType corresponding to the loaded file
- */
FileType GetFileType() override {
return IdentifyType(file);
}
- /**
- * Load the application
- * @return ResultStatus result of function
- */
ResultStatus Load() override;
/**
@@ -191,33 +183,20 @@ public:
*/
boost::optional<u32> LoadKernelSystemMode();
- /**
- * Get the code (typically .code section) of the application
- * @param buffer Reference to buffer to store data
- * @return ResultStatus result of function
- */
ResultStatus ReadCode(std::vector<u8>& buffer) override;
- /**
- * Get the icon (typically icon section) of the application
- * @param buffer Reference to buffer to store data
- * @return ResultStatus result of function
- */
ResultStatus ReadIcon(std::vector<u8>& buffer) override;
- /**
- * Get the banner (typically banner section) of the application
- * @param buffer Reference to buffer to store data
- * @return ResultStatus result of function
- */
ResultStatus ReadBanner(std::vector<u8>& buffer) override;
+ ResultStatus ReadLogo(std::vector<u8>& buffer) override;
+
/**
- * Get the logo (typically logo section) of the application
- * @param buffer Reference to buffer to store data
+ * Get the program id of the application
+ * @param out_program_id Reference to store program id into
* @return ResultStatus result of function
*/
- ResultStatus ReadLogo(std::vector<u8>& buffer) override;
+ ResultStatus ReadProgramId(u64& out_program_id) override;
/**
* Get the RomFS of the application
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 626e06cd9..5d23c52f9 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -7,7 +7,7 @@
#include "settings.h"
#include "video_core/video_core.h"
-#include "common/emu_window.h"
+#include "core/frontend/emu_window.h"
namespace Settings {
diff --git a/src/core/system.cpp b/src/core/system.cpp
deleted file mode 100644
index a5f763805..000000000
--- a/src/core/system.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "audio_core/audio_core.h"
-#include "core/core.h"
-#include "core/core_timing.h"
-#include "core/gdbstub/gdbstub.h"
-#include "core/hle/hle.h"
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/memory.h"
-#include "core/hw/hw.h"
-#include "core/system.h"
-#include "video_core/video_core.h"
-
-namespace System {
-
-static bool is_powered_on{false};
-
-Result Init(EmuWindow* emu_window, u32 system_mode) {
- Core::Init();
- CoreTiming::Init();
- Memory::Init();
- HW::Init();
- Kernel::Init(system_mode);
- HLE::Init();
- if (!VideoCore::Init(emu_window)) {
- return Result::ErrorInitVideoCore;
- }
- AudioCore::Init();
- GDBStub::Init();
-
- is_powered_on = true;
-
- return Result::Success;
-}
-
-bool IsPoweredOn() {
- return is_powered_on;
-}
-
-void Shutdown() {
- GDBStub::Shutdown();
- AudioCore::Shutdown();
- VideoCore::Shutdown();
- HLE::Shutdown();
- Kernel::Shutdown();
- HW::Shutdown();
- CoreTiming::Shutdown();
- Core::Shutdown();
-
- is_powered_on = false;
-}
-
-} // namespace
diff --git a/src/core/system.h b/src/core/system.h
deleted file mode 100644
index b41fc088a..000000000
--- a/src/core/system.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-class EmuWindow;
-
-namespace System {
-
-enum class Result {
- Success, ///< Everything is fine
- Error, ///< Something went wrong (no module specified)
- ErrorInitCore, ///< Something went wrong during core init
- ErrorInitVideoCore, ///< Something went wrong during video core init
-};
-
-Result Init(EmuWindow* emu_window, u32 system_mode);
-bool IsPoweredOn();
-void Shutdown();
-}
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 89237e477..b47156ca4 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -13,6 +13,6 @@ include_directories(../../externals/catch/single_include/)
add_executable(tests ${SRCS} ${HEADERS})
target_link_libraries(tests core video_core audio_core common)
-target_link_libraries(tests ${PLATFORM_LIBRARIES})
+target_link_libraries(tests ${PLATFORM_LIBRARIES} Threads::Threads)
add_test(NAME tests COMMAND $<TARGET_FILE:tests>)
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 581a37897..6ca319b59 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -39,6 +39,7 @@ set(HEADERS
rasterizer.h
rasterizer_interface.h
renderer_base.h
+ shader/debug_data.h
shader/shader.h
shader/shader_interpreter.h
swrasterizer.h
@@ -59,6 +60,9 @@ create_directory_groups(${SRCS} ${HEADERS})
add_library(video_core STATIC ${SRCS} ${HEADERS})
target_link_libraries(video_core glad)
+if (ARCHITECTURE_x86_64)
+ target_link_libraries(video_core xbyak)
+endif()
if (PNG_FOUND)
target_link_libraries(video_core ${PNG_LIBRARIES})
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index c80c96762..ea58e9f54 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -59,7 +59,10 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
regs[id] = (old_value & ~write_mask) | (value & write_mask);
- DebugUtils::OnPicaRegWrite({(u16)id, (u16)mask, regs[id]});
+ // Double check for is_pica_tracing to avoid call overhead
+ if (DebugUtils::IsPicaTracing()) {
+ DebugUtils::OnPicaRegWrite({(u16)id, (u16)mask, regs[id]});
+ }
if (g_debug_context)
g_debug_context->OnEvent(DebugContext::Event::PicaCommandLoaded,
@@ -68,7 +71,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
switch (id) {
// Trigger IRQ
case PICA_REG_INDEX(trigger_irq):
- GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D);
+ Service::GSP::SignalInterrupt(Service::GSP::InterruptId::P3D);
break;
case PICA_REG_INDEX_WORKAROUND(triangle_topology, 0x25E):
@@ -136,9 +139,10 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
immediate_input.attr[immediate_attribute_id++] = attribute;
if (immediate_attribute_id >= regs.vs.num_input_attributes + 1) {
+ MICROPROFILE_SCOPE(GPU_Drawing);
immediate_attribute_id = 0;
- Shader::UnitState<false> shader_unit;
+ Shader::UnitState shader_unit;
g_state.vs.Setup();
// Send to vertex shader
@@ -165,6 +169,8 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
case PICA_REG_INDEX(gpu_mode):
if (regs.gpu_mode == Regs::GPUMode::Configuring) {
+ MICROPROFILE_SCOPE(GPU_Drawing);
+
// Draw immediate mode triangles when GPU Mode is set to GPUMode::Configuring
VideoCore::g_renderer->Rasterizer()->DrawTriangles();
@@ -237,7 +243,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
unsigned int vertex_cache_pos = 0;
vertex_cache_ids.fill(-1);
- Shader::UnitState<false> shader_unit;
+ Shader::UnitState shader_unit;
g_state.vs.Setup();
for (unsigned int index = 0; index < regs.num_vertices; ++index) {
@@ -251,7 +257,6 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
ASSERT(vertex != -1);
bool vertex_cache_hit = false;
- Shader::OutputRegisters output_registers;
if (is_indexed) {
if (g_debug_context && Pica::g_debug_context->recorder) {
@@ -279,10 +284,9 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
g_debug_context->OnEvent(DebugContext::Event::VertexShaderInvocation,
(void*)&input);
g_state.vs.Run(shader_unit, input, loader.GetNumTotalAttributes());
- output_registers = shader_unit.output_registers;
// Retrieve vertex from register data
- output_vertex = output_registers.ToVertex(regs.vs);
+ output_vertex = shader_unit.output_registers.ToVertex(regs.vs);
if (is_indexed) {
vertex_cache[vertex_cache_pos] = output_vertex;
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 8806464d9..c44b3d95a 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -276,10 +276,10 @@ void DumpShader(const std::string& filename, const Regs::ShaderConfig& config,
static std::unique_ptr<PicaTrace> pica_trace;
static std::mutex pica_trace_mutex;
-static int is_pica_tracing = false;
+bool g_is_pica_tracing = false;
void StartPicaTracing() {
- if (is_pica_tracing) {
+ if (g_is_pica_tracing) {
LOG_WARNING(HW_GPU, "StartPicaTracing called even though tracing already running!");
return;
}
@@ -287,34 +287,26 @@ void StartPicaTracing() {
std::lock_guard<std::mutex> lock(pica_trace_mutex);
pica_trace = std::make_unique<PicaTrace>();
- is_pica_tracing = true;
-}
-
-bool IsPicaTracing() {
- return is_pica_tracing != 0;
+ g_is_pica_tracing = true;
}
void OnPicaRegWrite(PicaTrace::Write write) {
- // Double check for is_pica_tracing to avoid pointless locking overhead
- if (!is_pica_tracing)
- return;
-
std::lock_guard<std::mutex> lock(pica_trace_mutex);
- if (!is_pica_tracing)
+ if (!g_is_pica_tracing)
return;
pica_trace->writes.push_back(write);
}
std::unique_ptr<PicaTrace> FinishPicaTracing() {
- if (!is_pica_tracing) {
+ if (!g_is_pica_tracing) {
LOG_WARNING(HW_GPU, "FinishPicaTracing called even though tracing isn't running!");
return {};
}
// signalize that no further tracing should be performed
- is_pica_tracing = false;
+ g_is_pica_tracing = false;
// Wait until running tracing is finished
std::lock_guard<std::mutex> lock(pica_trace_mutex);
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
index 189c93abb..46ea8d9c7 100644
--- a/src/video_core/debug_utils/debug_utils.h
+++ b/src/video_core/debug_utils/debug_utils.h
@@ -196,8 +196,12 @@ struct PicaTrace {
std::vector<Write> writes;
};
+extern bool g_is_pica_tracing;
+
void StartPicaTracing();
-bool IsPicaTracing();
+inline bool IsPicaTracing() {
+ return g_is_pica_tracing;
+}
void OnPicaRegWrite(PicaTrace::Write write);
std::unique_ptr<PicaTrace> FinishPicaTracing();
diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h
index 3c6636d66..c1f9b43c2 100644
--- a/src/video_core/gpu_debugger.h
+++ b/src/video_core/gpu_debugger.h
@@ -28,7 +28,8 @@ public:
* @note All methods in this class are called from the GSP thread
*/
virtual void GXCommandProcessed(int total_command_count) {
- const GSP_GPU::Command& cmd = observed->ReadGXCommandHistory(total_command_count - 1);
+ const Service::GSP::Command& cmd =
+ observed->ReadGXCommandHistory(total_command_count - 1);
LOG_TRACE(Debug_GPU, "Received command: id=%x", (int)cmd.id.Value());
}
@@ -48,16 +49,16 @@ public:
return;
gx_command_history.emplace_back();
- GSP_GPU::Command& cmd = gx_command_history.back();
+ Service::GSP::Command& cmd = gx_command_history.back();
- memcpy(&cmd, command_data, sizeof(GSP_GPU::Command));
+ memcpy(&cmd, command_data, sizeof(Service::GSP::Command));
ForEachObserver([this](DebuggerObserver* observer) {
observer->GXCommandProcessed(static_cast<int>(this->gx_command_history.size()));
});
}
- const GSP_GPU::Command& ReadGXCommandHistory(int index) const {
+ const Service::GSP::Command& ReadGXCommandHistory(int index) const {
// TODO: Is this thread-safe?
return gx_command_history[index];
}
@@ -80,5 +81,5 @@ private:
std::vector<DebuggerObserver*> observers;
- std::vector<GSP_GPU::Command> gx_command_history;
+ std::vector<Service::GSP::Command> gx_command_history;
};
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index ba65db419..5a306a5c8 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -11,6 +11,7 @@
#include "common/color.h"
#include "common/logging/log.h"
#include "common/math_util.h"
+#include "common/microprofile.h"
#include "common/vector_math.h"
#include "core/hw/gpu.h"
#include "video_core/pica.h"
@@ -21,6 +22,10 @@
#include "video_core/renderer_opengl/pica_to_gl.h"
#include "video_core/renderer_opengl/renderer_opengl.h"
+MICROPROFILE_DEFINE(OpenGL_Drawing, "OpenGL", "Drawing", MP_RGB(128, 128, 192));
+MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(100, 100, 255));
+MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
+
static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace &&
stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace &&
@@ -168,6 +173,7 @@ void RasterizerOpenGL::DrawTriangles() {
if (vertex_batch.empty())
return;
+ MICROPROFILE_SCOPE(OpenGL_Drawing);
const auto& regs = Pica::g_state.regs;
// Sync and bind the framebuffer surfaces
@@ -189,10 +195,6 @@ void RasterizerOpenGL::DrawTriangles() {
GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
(has_stencil && depth_surface != nullptr) ? depth_surface->texture.handle : 0, 0);
- if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- return;
- }
-
// Sync the viewport
// These registers hold half-width and half-height, so must be multiplied by 2
GLsizei viewport_width = (GLsizei)Pica::float24::FromRaw(regs.viewport_size_x).ToFloat32() * 2;
@@ -698,18 +700,22 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
}
void RasterizerOpenGL::FlushAll() {
+ MICROPROFILE_SCOPE(OpenGL_CacheManagement);
res_cache.FlushAll();
}
void RasterizerOpenGL::FlushRegion(PAddr addr, u32 size) {
+ MICROPROFILE_SCOPE(OpenGL_CacheManagement);
res_cache.FlushRegion(addr, size, nullptr, false);
}
void RasterizerOpenGL::FlushAndInvalidateRegion(PAddr addr, u32 size) {
+ MICROPROFILE_SCOPE(OpenGL_CacheManagement);
res_cache.FlushRegion(addr, size, nullptr, true);
}
bool RasterizerOpenGL::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) {
+ MICROPROFILE_SCOPE(OpenGL_Blits);
using PixelFormat = CachedSurface::PixelFormat;
using SurfaceType = CachedSurface::SurfaceType;
@@ -782,6 +788,7 @@ bool RasterizerOpenGL::AccelerateTextureCopy(const GPU::Regs::DisplayTransferCon
}
bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) {
+ MICROPROFILE_SCOPE(OpenGL_Blits);
using PixelFormat = CachedSurface::PixelFormat;
using SurfaceType = CachedSurface::SurfaceType;
@@ -807,10 +814,6 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
0);
- if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- return false;
- }
-
GLfloat color_values[4] = {0.0f, 0.0f, 0.0f, 0.0f};
// TODO: Handle additional pixel format and fill value size combinations to accelerate more
@@ -883,10 +886,10 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
}
}
- cur_state.color_mask.red_enabled = true;
- cur_state.color_mask.green_enabled = true;
- cur_state.color_mask.blue_enabled = true;
- cur_state.color_mask.alpha_enabled = true;
+ cur_state.color_mask.red_enabled = GL_TRUE;
+ cur_state.color_mask.green_enabled = GL_TRUE;
+ cur_state.color_mask.blue_enabled = GL_TRUE;
+ cur_state.color_mask.alpha_enabled = GL_TRUE;
cur_state.Apply();
glClearBufferfv(GL_COLOR, 0, color_values);
} else if (dst_type == SurfaceType::Depth) {
@@ -895,10 +898,6 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
dst_surface->texture.handle, 0);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
- if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- return false;
- }
-
GLfloat value_float;
if (dst_surface->pixel_format == CachedSurface::PixelFormat::D16) {
value_float = config.value_32bit / 65535.0f; // 2^16 - 1
@@ -914,10 +913,6 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config)
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
dst_surface->texture.handle, 0);
- if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
- return false;
- }
-
GLfloat value_float = (config.value_32bit & 0xFFFFFF) / 16777215.0f; // 2^24 - 1
GLint value_int = (config.value_32bit >> 24);
@@ -942,6 +937,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const GPU::Regs::FramebufferConfig& con
if (framebuffer_addr == 0) {
return false;
}
+ MICROPROFILE_SCOPE(OpenGL_CacheManagement);
CachedSurface src_params;
src_params.addr = framebuffer_addr;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 61f6e767f..85aa06cd5 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -11,11 +11,11 @@
#include <vector>
#include <glad/glad.h>
#include "common/bit_field.h"
-#include "common/emu_window.h"
#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/microprofile.h"
#include "common/vector_math.h"
+#include "core/frontend/emu_window.h"
#include "core/memory.h"
#include "video_core/debug_utils/debug_utils.h"
#include "video_core/pica_state.h"
@@ -103,7 +103,7 @@ static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width,
}
}
-bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex,
+void RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex,
CachedSurface::SurfaceType type,
const MathUtil::Rectangle<int>& src_rect,
const MathUtil::Rectangle<int>& dst_rect) {
@@ -158,21 +158,14 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex,
buffers = GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
}
- bool can_blit = OpenGLState::CheckFBStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE &&
- OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE;
-
- if (can_blit) {
- glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom,
- dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, buffers,
- buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST);
- }
+ glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left,
+ dst_rect.top, dst_rect.right, dst_rect.bottom, buffers,
+ buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST);
// Restore previous framebuffer bindings
cur_state.draw.read_framebuffer = old_fbs[0];
cur_state.draw.draw_framebuffer = old_fbs[1];
cur_state.Apply();
-
- return can_blit;
}
bool RasterizerCacheOpenGL::TryBlitSurfaces(CachedSurface* src_surface,
@@ -186,9 +179,9 @@ bool RasterizerCacheOpenGL::TryBlitSurfaces(CachedSurface* src_surface,
return false;
}
- return BlitTextures(src_surface->texture.handle, dst_surface->texture.handle,
- CachedSurface::GetFormatType(src_surface->pixel_format), src_rect,
- dst_rect);
+ BlitTextures(src_surface->texture.handle, dst_surface->texture.handle,
+ CachedSurface::GetFormatType(src_surface->pixel_format), src_rect, dst_rect);
+ return true;
}
static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pixel_format,
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index 32abfbaf5..b50e8292b 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -187,7 +187,7 @@ public:
~RasterizerCacheOpenGL();
/// Blits one texture to another
- bool BlitTextures(GLuint src_tex, GLuint dst_tex, CachedSurface::SurfaceType type,
+ void BlitTextures(GLuint src_tex, GLuint dst_tex, CachedSurface::SurfaceType type,
const MathUtil::Rectangle<int>& src_rect,
const MathUtil::Rectangle<int>& dst_rect);
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index 8f278722d..4c4f98ac9 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -293,7 +293,7 @@ static void AppendAlphaTestCondition(std::string& out, Regs::CompareFunc func) {
case CompareFunc::GreaterThanOrEqual: {
static const char* op[] = {"!=", "==", ">=", ">", "<=", "<"};
unsigned index = (unsigned)func - (unsigned)CompareFunc::Equal;
- out += "int(last_tex_env_out.a * 255.0f) " + std::string(op[index]) + " alphatest_ref";
+ out += "int(last_tex_env_out.a * 255.0) " + std::string(op[index]) + " alphatest_ref";
break;
}
@@ -422,16 +422,13 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
if (abs) {
// LUT index is in the range of (0.0, 1.0)
index = lighting.light[light_num].two_sided_diffuse ? "abs(" + index + ")"
- : "max(" + index + ", 0.f)";
- return "(FLOAT_255 * clamp(" + index + ", 0.0, 1.0))";
+ : "max(" + index + ", 0.0)";
} else {
// LUT index is in the range of (-1.0, 1.0)
- index = "clamp(" + index + ", -1.0, 1.0)";
- return "(FLOAT_255 * ((" + index + " < 0) ? " + index + " + 2.0 : " + index +
- ") / 2.0)";
+ index = "((" + index + " < 0) ? " + index + " + 2.0 : " + index + ") / 2.0";
}
- return std::string();
+ return "(OFFSET_256 + SCALE_256 * clamp(" + index + ", 0.0, 1.0))";
};
// Gets the lighting lookup table value given the specified sampler and index
@@ -462,7 +459,7 @@ static void WriteLighting(std::string& out, const PicaShaderConfig& config) {
if (light_config.dist_atten_enable) {
std::string index = "(" + light_src + ".dist_atten_scale * length(-view - " +
light_src + ".position) + " + light_src + ".dist_atten_bias)";
- index = "((clamp(" + index + ", 0.0, FLOAT_255)))";
+ index = "(OFFSET_256 + SCALE_256 * clamp(" + index + ", 0.0, 1.0))";
const unsigned lut_num =
((unsigned)Regs::LightingSampler::DistanceAttenuation + light_config.num);
dist_atten = GetLutValue((Regs::LightingSampler)lut_num, index);
@@ -580,8 +577,10 @@ std::string GenerateFragmentShader(const PicaShaderConfig& config) {
#version 330 core
#define NUM_TEV_STAGES 6
#define NUM_LIGHTS 8
-#define LIGHTING_LUT_SIZE 256
-#define FLOAT_255 (255.0 / 256.0)
+
+// Texture coordinate offsets and scales
+#define OFFSET_256 (0.5 / 256.0)
+#define SCALE_256 (255.0 / 256.0)
in vec4 primary_color;
in vec2 texcoord[3];
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 2a731f483..3c03b424a 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -232,19 +232,6 @@ void OpenGLState::Apply() const {
cur_state = *this;
}
-GLenum OpenGLState::CheckFBStatus(GLenum target) {
- GLenum fb_status = glCheckFramebufferStatus(target);
- if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
- const char* fb_description =
- (target == GL_READ_FRAMEBUFFER ? "READ"
- : (target == GL_DRAW_FRAMEBUFFER ? "DRAW" : "UNK"));
- LOG_CRITICAL(Render_OpenGL, "OpenGL %s framebuffer check failed, status %X", fb_description,
- fb_status);
- }
-
- return fb_status;
-}
-
void OpenGLState::ResetTexture(GLuint handle) {
for (auto& unit : cur_state.texture_units) {
if (unit.texture_2d == handle) {
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 01dead883..aee3c2946 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -90,9 +90,6 @@ public:
/// Apply this state as the current OpenGL state
void Apply() const;
- /// Check the status of the current OpenGL read or draw framebuffer configuration
- static GLenum CheckFBStatus(GLenum target);
-
/// Resets and unbinds any references to the given resource in the current OpenGL state
static void ResetTexture(GLuint handle);
static void ResetSampler(GLuint handle);
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 93f0ac105..2aa90e5c1 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -9,10 +9,10 @@
#include <glad/glad.h>
#include "common/assert.h"
#include "common/bit_field.h"
-#include "common/emu_window.h"
#include "common/logging/log.h"
#include "common/profiler_reporting.h"
#include "common/synchronized_wrapper.h"
+#include "core/frontend/emu_window.h"
#include "core/hw/gpu.h"
#include "core/hw/hw.h"
#include "core/hw/lcd.h"
diff --git a/src/video_core/shader/debug_data.h b/src/video_core/shader/debug_data.h
new file mode 100644
index 000000000..9e82122e1
--- /dev/null
+++ b/src/video_core/shader/debug_data.h
@@ -0,0 +1,186 @@
+// Copyright 2016 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <vector>
+#include "common/common_types.h"
+#include "common/vector_math.h"
+#include "video_core/pica_types.h"
+
+namespace Pica {
+namespace Shader {
+
+/// Helper structure used to keep track of data useful for inspection of shader emulation
+template <bool full_debugging>
+struct DebugData;
+
+template <>
+struct DebugData<false> {
+ // TODO: Hide these behind and interface and move them to DebugData<true>
+ u32 max_offset = 0; ///< maximum program counter ever reached
+ u32 max_opdesc_id = 0; ///< maximum swizzle pattern index ever used
+};
+
+template <>
+struct DebugData<true> {
+ /// Records store the input and output operands of a particular instruction.
+ struct Record {
+ enum Type {
+ // Floating point arithmetic operands
+ SRC1 = 0x1,
+ SRC2 = 0x2,
+ SRC3 = 0x4,
+
+ // Initial and final output operand value
+ DEST_IN = 0x8,
+ DEST_OUT = 0x10,
+
+ // Current and next instruction offset (in words)
+ CUR_INSTR = 0x20,
+ NEXT_INSTR = 0x40,
+
+ // Output address register value
+ ADDR_REG_OUT = 0x80,
+
+ // Result of a comparison instruction
+ CMP_RESULT = 0x100,
+
+ // Input values for conditional flow control instructions
+ COND_BOOL_IN = 0x200,
+ COND_CMP_IN = 0x400,
+
+ // Input values for a loop
+ LOOP_INT_IN = 0x800,
+ };
+
+ Math::Vec4<float24> src1;
+ Math::Vec4<float24> src2;
+ Math::Vec4<float24> src3;
+
+ Math::Vec4<float24> dest_in;
+ Math::Vec4<float24> dest_out;
+
+ s32 address_registers[2];
+ bool conditional_code[2];
+ bool cond_bool;
+ bool cond_cmp[2];
+ Math::Vec4<u8> loop_int;
+
+ u32 instruction_offset;
+ u32 next_instruction;
+
+ /// set of enabled fields (as a combination of Type flags)
+ unsigned mask = 0;
+ };
+
+ u32 max_offset = 0; ///< maximum program counter ever reached
+ u32 max_opdesc_id = 0; ///< maximum swizzle pattern index ever used
+
+ /// List of records for each executed shader instruction
+ std::vector<DebugData<true>::Record> records;
+};
+
+/// Type alias for better readability
+using DebugDataRecord = DebugData<true>::Record;
+
+/// Helper function to set a DebugData<true>::Record field based on the template enum parameter.
+template <DebugDataRecord::Type type, typename ValueType>
+inline void SetField(DebugDataRecord& record, ValueType value);
+
+template <>
+inline void SetField<DebugDataRecord::SRC1>(DebugDataRecord& record, float24* value) {
+ record.src1.x = value[0];
+ record.src1.y = value[1];
+ record.src1.z = value[2];
+ record.src1.w = value[3];
+}
+
+template <>
+inline void SetField<DebugDataRecord::SRC2>(DebugDataRecord& record, float24* value) {
+ record.src2.x = value[0];
+ record.src2.y = value[1];
+ record.src2.z = value[2];
+ record.src2.w = value[3];
+}
+
+template <>
+inline void SetField<DebugDataRecord::SRC3>(DebugDataRecord& record, float24* value) {
+ record.src3.x = value[0];
+ record.src3.y = value[1];
+ record.src3.z = value[2];
+ record.src3.w = value[3];
+}
+
+template <>
+inline void SetField<DebugDataRecord::DEST_IN>(DebugDataRecord& record, float24* value) {
+ record.dest_in.x = value[0];
+ record.dest_in.y = value[1];
+ record.dest_in.z = value[2];
+ record.dest_in.w = value[3];
+}
+
+template <>
+inline void SetField<DebugDataRecord::DEST_OUT>(DebugDataRecord& record, float24* value) {
+ record.dest_out.x = value[0];
+ record.dest_out.y = value[1];
+ record.dest_out.z = value[2];
+ record.dest_out.w = value[3];
+}
+
+template <>
+inline void SetField<DebugDataRecord::ADDR_REG_OUT>(DebugDataRecord& record, s32* value) {
+ record.address_registers[0] = value[0];
+ record.address_registers[1] = value[1];
+}
+
+template <>
+inline void SetField<DebugDataRecord::CMP_RESULT>(DebugDataRecord& record, bool* value) {
+ record.conditional_code[0] = value[0];
+ record.conditional_code[1] = value[1];
+}
+
+template <>
+inline void SetField<DebugDataRecord::COND_BOOL_IN>(DebugDataRecord& record, bool value) {
+ record.cond_bool = value;
+}
+
+template <>
+inline void SetField<DebugDataRecord::COND_CMP_IN>(DebugDataRecord& record, bool* value) {
+ record.cond_cmp[0] = value[0];
+ record.cond_cmp[1] = value[1];
+}
+
+template <>
+inline void SetField<DebugDataRecord::LOOP_INT_IN>(DebugDataRecord& record, Math::Vec4<u8> value) {
+ record.loop_int = value;
+}
+
+template <>
+inline void SetField<DebugDataRecord::CUR_INSTR>(DebugDataRecord& record, u32 value) {
+ record.instruction_offset = value;
+}
+
+template <>
+inline void SetField<DebugDataRecord::NEXT_INSTR>(DebugDataRecord& record, u32 value) {
+ record.next_instruction = value;
+}
+
+/// Helper function to set debug information on the current shader iteration.
+template <DebugDataRecord::Type type, typename ValueType>
+inline void Record(DebugData<false>& debug_data, u32 offset, ValueType value) {
+ // Debugging disabled => nothing to do
+}
+
+template <DebugDataRecord::Type type, typename ValueType>
+inline void Record(DebugData<true>& debug_data, u32 offset, ValueType value) {
+ if (offset >= debug_data.records.size())
+ debug_data.records.resize(offset + 1);
+
+ SetField<type, ValueType>(debug_data.records[offset], value);
+ debug_data.records[offset].mask |= type;
+}
+
+} // namespace Shader
+} // namespace Pica
diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp
index 3febe739c..a4aa3c9e0 100644
--- a/src/video_core/shader/shader.cpp
+++ b/src/video_core/shader/shader.cpp
@@ -25,7 +25,7 @@ namespace Pica {
namespace Shader {
-OutputVertex OutputRegisters::ToVertex(const Regs::ShaderConfig& config) {
+OutputVertex OutputRegisters::ToVertex(const Regs::ShaderConfig& config) const {
// Setup output data
OutputVertex ret;
// TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to
@@ -109,15 +109,12 @@ void ShaderSetup::Setup() {
MICROPROFILE_DEFINE(GPU_Shader, "GPU", "Shader", MP_RGB(50, 50, 240));
-void ShaderSetup::Run(UnitState<false>& state, const InputVertex& input, int num_attributes) {
+void ShaderSetup::Run(UnitState& state, const InputVertex& input, int num_attributes) {
auto& config = g_state.regs.vs;
auto& setup = g_state.vs;
MICROPROFILE_SCOPE(GPU_Shader);
- state.debug.max_offset = 0;
- state.debug.max_opdesc_id = 0;
-
// Setup input register table
const auto& attribute_register_map = config.input_register_map;
@@ -128,22 +125,23 @@ void ShaderSetup::Run(UnitState<false>& state, const InputVertex& input, int num
state.conditional_code[1] = false;
#ifdef ARCHITECTURE_x86_64
- if (VideoCore::g_shader_jit_enabled)
+ if (VideoCore::g_shader_jit_enabled) {
jit_shader->Run(setup, state, config.main_offset);
- else
- RunInterpreter(setup, state, config.main_offset);
+ } else {
+ DebugData<false> dummy_debug_data;
+ RunInterpreter(setup, state, dummy_debug_data, config.main_offset);
+ }
#else
- RunInterpreter(setup, state, config.main_offset);
+ DebugData<false> dummy_debug_data;
+ RunInterpreter(setup, state, dummy_debug_data, config.main_offset);
#endif // ARCHITECTURE_x86_64
}
DebugData<true> ShaderSetup::ProduceDebugInfo(const InputVertex& input, int num_attributes,
const Regs::ShaderConfig& config,
const ShaderSetup& setup) {
- UnitState<true> state;
-
- state.debug.max_offset = 0;
- state.debug.max_opdesc_id = 0;
+ UnitState state;
+ DebugData<true> debug_data;
// Setup input register table
boost::fill(state.registers.input, Math::Vec4<float24>::AssignToAll(float24::Zero()));
@@ -154,8 +152,8 @@ DebugData<true> ShaderSetup::ProduceDebugInfo(const InputVertex& input, int num_
state.conditional_code[0] = false;
state.conditional_code[1] = false;
- RunInterpreter(setup, state, config.main_offset);
- return state.debug;
+ RunInterpreter(setup, state, debug_data, config.main_offset);
+ return debug_data;
}
} // namespace Shader
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h
index 8858d67f8..2b07759b9 100644
--- a/src/video_core/shader/shader.h
+++ b/src/video_core/shader/shader.h
@@ -8,8 +8,6 @@
#include <cstddef>
#include <memory>
#include <type_traits>
-#include <vector>
-#include <boost/container/static_vector.hpp>
#include <nihstro/shader_bytecode.h>
#include "common/assert.h"
#include "common/common_funcs.h"
@@ -17,6 +15,7 @@
#include "common/vector_math.h"
#include "video_core/pica.h"
#include "video_core/pica_types.h"
+#include "video_core/shader/debug_data.h"
using nihstro::RegisterType;
using nihstro::SourceRegister;
@@ -85,187 +84,16 @@ struct OutputRegisters {
alignas(16) Math::Vec4<float24> value[16];
- OutputVertex ToVertex(const Regs::ShaderConfig& config);
+ OutputVertex ToVertex(const Regs::ShaderConfig& config) const;
};
static_assert(std::is_pod<OutputRegisters>::value, "Structure is not POD");
-// Helper structure used to keep track of data useful for inspection of shader emulation
-template <bool full_debugging>
-struct DebugData;
-
-template <>
-struct DebugData<false> {
- // TODO: Hide these behind and interface and move them to DebugData<true>
- u32 max_offset; // maximum program counter ever reached
- u32 max_opdesc_id; // maximum swizzle pattern index ever used
-};
-
-template <>
-struct DebugData<true> {
- // Records store the input and output operands of a particular instruction.
- struct Record {
- enum Type {
- // Floating point arithmetic operands
- SRC1 = 0x1,
- SRC2 = 0x2,
- SRC3 = 0x4,
-
- // Initial and final output operand value
- DEST_IN = 0x8,
- DEST_OUT = 0x10,
-
- // Current and next instruction offset (in words)
- CUR_INSTR = 0x20,
- NEXT_INSTR = 0x40,
-
- // Output address register value
- ADDR_REG_OUT = 0x80,
-
- // Result of a comparison instruction
- CMP_RESULT = 0x100,
-
- // Input values for conditional flow control instructions
- COND_BOOL_IN = 0x200,
- COND_CMP_IN = 0x400,
-
- // Input values for a loop
- LOOP_INT_IN = 0x800,
- };
-
- Math::Vec4<float24> src1;
- Math::Vec4<float24> src2;
- Math::Vec4<float24> src3;
-
- Math::Vec4<float24> dest_in;
- Math::Vec4<float24> dest_out;
-
- s32 address_registers[2];
- bool conditional_code[2];
- bool cond_bool;
- bool cond_cmp[2];
- Math::Vec4<u8> loop_int;
-
- u32 instruction_offset;
- u32 next_instruction;
-
- // set of enabled fields (as a combination of Type flags)
- unsigned mask = 0;
- };
-
- u32 max_offset; // maximum program counter ever reached
- u32 max_opdesc_id; // maximum swizzle pattern index ever used
-
- // List of records for each executed shader instruction
- std::vector<DebugData<true>::Record> records;
-};
-
-// Type alias for better readability
-using DebugDataRecord = DebugData<true>::Record;
-
-// Helper function to set a DebugData<true>::Record field based on the template enum parameter.
-template <DebugDataRecord::Type type, typename ValueType>
-inline void SetField(DebugDataRecord& record, ValueType value);
-
-template <>
-inline void SetField<DebugDataRecord::SRC1>(DebugDataRecord& record, float24* value) {
- record.src1.x = value[0];
- record.src1.y = value[1];
- record.src1.z = value[2];
- record.src1.w = value[3];
-}
-
-template <>
-inline void SetField<DebugDataRecord::SRC2>(DebugDataRecord& record, float24* value) {
- record.src2.x = value[0];
- record.src2.y = value[1];
- record.src2.z = value[2];
- record.src2.w = value[3];
-}
-
-template <>
-inline void SetField<DebugDataRecord::SRC3>(DebugDataRecord& record, float24* value) {
- record.src3.x = value[0];
- record.src3.y = value[1];
- record.src3.z = value[2];
- record.src3.w = value[3];
-}
-
-template <>
-inline void SetField<DebugDataRecord::DEST_IN>(DebugDataRecord& record, float24* value) {
- record.dest_in.x = value[0];
- record.dest_in.y = value[1];
- record.dest_in.z = value[2];
- record.dest_in.w = value[3];
-}
-
-template <>
-inline void SetField<DebugDataRecord::DEST_OUT>(DebugDataRecord& record, float24* value) {
- record.dest_out.x = value[0];
- record.dest_out.y = value[1];
- record.dest_out.z = value[2];
- record.dest_out.w = value[3];
-}
-
-template <>
-inline void SetField<DebugDataRecord::ADDR_REG_OUT>(DebugDataRecord& record, s32* value) {
- record.address_registers[0] = value[0];
- record.address_registers[1] = value[1];
-}
-
-template <>
-inline void SetField<DebugDataRecord::CMP_RESULT>(DebugDataRecord& record, bool* value) {
- record.conditional_code[0] = value[0];
- record.conditional_code[1] = value[1];
-}
-
-template <>
-inline void SetField<DebugDataRecord::COND_BOOL_IN>(DebugDataRecord& record, bool value) {
- record.cond_bool = value;
-}
-
-template <>
-inline void SetField<DebugDataRecord::COND_CMP_IN>(DebugDataRecord& record, bool* value) {
- record.cond_cmp[0] = value[0];
- record.cond_cmp[1] = value[1];
-}
-
-template <>
-inline void SetField<DebugDataRecord::LOOP_INT_IN>(DebugDataRecord& record, Math::Vec4<u8> value) {
- record.loop_int = value;
-}
-
-template <>
-inline void SetField<DebugDataRecord::CUR_INSTR>(DebugDataRecord& record, u32 value) {
- record.instruction_offset = value;
-}
-
-template <>
-inline void SetField<DebugDataRecord::NEXT_INSTR>(DebugDataRecord& record, u32 value) {
- record.next_instruction = value;
-}
-
-// Helper function to set debug information on the current shader iteration.
-template <DebugDataRecord::Type type, typename ValueType>
-inline void Record(DebugData<false>& debug_data, u32 offset, ValueType value) {
- // Debugging disabled => nothing to do
-}
-
-template <DebugDataRecord::Type type, typename ValueType>
-inline void Record(DebugData<true>& debug_data, u32 offset, ValueType value) {
- if (offset >= debug_data.records.size())
- debug_data.records.resize(offset + 1);
-
- SetField<type, ValueType>(debug_data.records[offset], value);
- debug_data.records[offset].mask |= type;
-}
-
/**
* This structure contains the state information that needs to be unique for a shader unit. The 3DS
* has four shader units that process shaders in parallel. At the present, Citra only implements a
* single shader unit that processes all shaders serially. Putting the state information in a struct
* here will make it easier for us to parallelize the shader processing later.
*/
-template <bool Debug>
struct UnitState {
struct Registers {
// The registers are accessed by the shader JIT using SSE instructions, and are therefore
@@ -283,8 +111,6 @@ struct UnitState {
// TODO: How many bits do these actually have?
s32 address_registers[3];
- DebugData<Debug> debug;
-
static size_t InputOffset(const SourceRegister& reg) {
switch (reg.GetRegisterType()) {
case RegisterType::Input:
@@ -332,21 +158,16 @@ struct ShaderSetup {
std::array<Math::Vec4<u8>, 4> i;
} uniforms;
- static size_t UniformOffset(RegisterType type, unsigned index) {
- switch (type) {
- case RegisterType::FloatUniform:
- return offsetof(ShaderSetup, uniforms.f) + index * sizeof(Math::Vec4<float24>);
-
- case RegisterType::BoolUniform:
- return offsetof(ShaderSetup, uniforms.b) + index * sizeof(bool);
+ static size_t GetFloatUniformOffset(unsigned index) {
+ return offsetof(ShaderSetup, uniforms.f) + index * sizeof(Math::Vec4<float24>);
+ }
- case RegisterType::IntUniform:
- return offsetof(ShaderSetup, uniforms.i) + index * sizeof(Math::Vec4<u8>);
+ static size_t GetBoolUniformOffset(unsigned index) {
+ return offsetof(ShaderSetup, uniforms.b) + index * sizeof(bool);
+ }
- default:
- UNREACHABLE();
- return 0;
- }
+ static size_t GetIntUniformOffset(unsigned index) {
+ return offsetof(ShaderSetup, uniforms.i) + index * sizeof(Math::Vec4<u8>);
}
std::array<u32, 1024> program_code;
@@ -364,7 +185,7 @@ struct ShaderSetup {
* @param input Input vertex into the shader
* @param num_attributes The number of vertex shader attributes
*/
- void Run(UnitState<false>& state, const InputVertex& input, int num_attributes);
+ void Run(UnitState& state, const InputVertex& input, int num_attributes);
/**
* Produce debug information based on the given shader and input vertex
diff --git a/src/video_core/shader/shader_interpreter.cpp b/src/video_core/shader/shader_interpreter.cpp
index 6abb6761f..70db4167e 100644
--- a/src/video_core/shader/shader_interpreter.cpp
+++ b/src/video_core/shader/shader_interpreter.cpp
@@ -6,6 +6,7 @@
#include <array>
#include <cmath>
#include <numeric>
+#include <boost/container/static_vector.hpp>
#include <nihstro/shader_bytecode.h>
#include "common/assert.h"
#include "common/common_types.h"
@@ -38,12 +39,42 @@ struct CallStackElement {
};
template <bool Debug>
-void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned offset) {
+void RunInterpreter(const ShaderSetup& setup, UnitState& state, DebugData<Debug>& debug_data,
+ unsigned offset) {
// TODO: Is there a maximal size for this?
boost::container::static_vector<CallStackElement, 16> call_stack;
-
u32 program_counter = offset;
+ auto call = [&program_counter, &call_stack](u32 offset, u32 num_instructions, u32 return_offset,
+ u8 repeat_count, u8 loop_increment) {
+ // -1 to make sure when incrementing the PC we end up at the correct offset
+ program_counter = offset - 1;
+ ASSERT(call_stack.size() < call_stack.capacity());
+ call_stack.push_back(
+ {offset + num_instructions, return_offset, repeat_count, loop_increment, offset});
+ };
+
+ auto evaluate_condition = [&state](Instruction::FlowControlType flow_control) {
+ using Op = Instruction::FlowControlType::Op;
+
+ bool result_x = flow_control.refx.Value() == state.conditional_code[0];
+ bool result_y = flow_control.refy.Value() == state.conditional_code[1];
+
+ switch (flow_control.op) {
+ case Op::Or:
+ return result_x || result_y;
+ case Op::And:
+ return result_x && result_y;
+ case Op::JustX:
+ return result_x;
+ case Op::JustY:
+ return result_y;
+ default:
+ UNREACHABLE();
+ return false;
+ }
+ };
+
const auto& uniforms = g_state.vs.uniforms;
const auto& swizzle_data = g_state.vs.swizzle_data;
const auto& program_code = g_state.vs.program_code;
@@ -74,20 +105,11 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
const Instruction instr = {program_code[program_counter]};
const SwizzlePattern swizzle = {swizzle_data[instr.common.operand_desc_id]};
- auto call = [&program_counter, &call_stack](UnitState<Debug>& state, u32 offset,
- u32 num_instructions, u32 return_offset,
- u8 repeat_count, u8 loop_increment) {
- // -1 to make sure when incrementing the PC we end up at the correct offset
- program_counter = offset - 1;
- ASSERT(call_stack.size() < call_stack.capacity());
- call_stack.push_back(
- {offset + num_instructions, return_offset, repeat_count, loop_increment, offset});
- };
- Record<DebugDataRecord::CUR_INSTR>(state.debug, iteration, program_counter);
+ Record<DebugDataRecord::CUR_INSTR>(debug_data, iteration, program_counter);
if (iteration > 0)
- Record<DebugDataRecord::NEXT_INSTR>(state.debug, iteration - 1, program_counter);
+ Record<DebugDataRecord::NEXT_INSTR>(debug_data, iteration - 1, program_counter);
- state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + program_counter);
+ debug_data.max_offset = std::max<u32>(debug_data.max_offset, 1 + program_counter);
auto LookupSourceRegister = [&](const SourceRegister& source_reg) -> const float24* {
switch (source_reg.GetRegisterType()) {
@@ -155,54 +177,54 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
? &state.registers.temporary[instr.common.dest.Value().GetIndex()][0]
: dummy_vec4_float24;
- state.debug.max_opdesc_id =
- std::max<u32>(state.debug.max_opdesc_id, 1 + instr.common.operand_desc_id);
+ debug_data.max_opdesc_id =
+ std::max<u32>(debug_data.max_opdesc_id, 1 + instr.common.operand_desc_id);
switch (instr.opcode.Value().EffectiveOpCode()) {
case OpCode::Id::ADD: {
- Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
- Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
- Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
+ Record<DebugDataRecord::SRC1>(debug_data, iteration, src1);
+ Record<DebugDataRecord::SRC2>(debug_data, iteration, src2);
+ Record<DebugDataRecord::DEST_IN>(debug_data, iteration, dest);
for (int i = 0; i < 4; ++i) {
if (!swizzle.DestComponentEnabled(i))
continue;
dest[i] = src1[i] + src2[i];
}
- Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
+ Record<DebugDataRecord::DEST_OUT>(debug_data, iteration, dest);
break;
}
case OpCode::Id::MUL: {
- Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
- Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
- Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
+ Record<DebugDataRecord::SRC1>(debug_data, iteration, src1);
+ Record<DebugDataRecord::SRC2>(debug_data, iteration, src2);
+ Record<DebugDataRecord::DEST_IN>(debug_data, iteration, dest);
for (int i = 0; i < 4; ++i) {
if (!swizzle.DestComponentEnabled(i))
continue;
dest[i] = src1[i] * src2[i];
}
- Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
+ Record<DebugDataRecord::DEST_OUT>(debug_data, iteration, dest);
break;
}
case OpCode::Id::FLR:
- Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
- Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
+ Record<DebugDataRecord::SRC1>(debug_data, iteration, src1);
+ Record<DebugDataRecord::DEST_IN>(debug_data, iteration, dest);
for (int i = 0; i < 4; ++i) {
if (!swizzle.DestComponentEnabled(i))
continue;
dest[i] = float24::FromFloat32(std::floor(src1[i].ToFloat32()));
}
- Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
+ Record<DebugDataRecord::DEST_OUT>(debug_data, iteration, dest);
break;
case OpCode::Id::MAX:
- Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
- Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
- Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
+ Record<DebugDataRecord::SRC1>(debug_data, iteration, src1);
+ Record<DebugDataRecord::SRC2>(debug_data, iteration, src2);
+ Record<DebugDataRecord::DEST_IN>(debug_data, iteration, dest);
for (int i = 0; i < 4; ++i) {
if (!swizzle.DestComponentEnabled(i))
continue;
@@ -212,13 +234,13 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
// max(NaN, 0) -> 0
dest[i] = (src1[i] > src2[i]) ? src1[i] : src2[i];
}
- Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
+ Record<DebugDataRecord::DEST_OUT>(debug_data, iteration, dest);
break;
case OpCode::Id::MIN:
- Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
- Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
- Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
+ Record<DebugDataRecord::SRC1>(debug_data, iteration, src1);
+ Record<DebugDataRecord::SRC2>(debug_data, iteration, src2);
+ Record<DebugDataRecord::DEST_IN>(debug_data, iteration, dest);
for (int i = 0; i < 4; ++i) {
if (!swizzle.DestComponentEnabled(i))
continue;
@@ -228,16 +250,16 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
// min(NaN, 0) -> 0
dest[i] = (src1[i] < src2[i]) ? src1[i] : src2[i];
}
- Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
+ Record<DebugDataRecord::DEST_OUT>(debug_data, iteration, dest);
break;
case OpCode::Id::DP3:
case OpCode::Id::DP4:
case OpCode::Id::DPH:
case OpCode::Id::DPHI: {
- Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
- Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
- Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
+ Record<DebugDataRecord::SRC1>(debug_data, iteration, src1);
+ Record<DebugDataRecord::SRC2>(debug_data, iteration, src2);
+ Record<DebugDataRecord::DEST_IN>(debug_data, iteration, dest);
OpCode::Id opcode = instr.opcode.Value().EffectiveOpCode();
if (opcode == OpCode::Id::DPH || opcode == OpCode::Id::DPHI)
@@ -253,14 +275,14 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
dest[i] = dot;
}
- Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
+ Record<DebugDataRecord::DEST_OUT>(debug_data, iteration, dest);
break;
}
// Reciprocal
case OpCode::Id::RCP: {
- Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
- Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
+ Record<DebugDataRecord::SRC1>(debug_data, iteration, src1);
+ Record<DebugDataRecord::DEST_IN>(debug_data, iteration, dest);
float24 rcp_res = float24::FromFloat32(1.0f / src1[0].ToFloat32());
for (int i = 0; i < 4; ++i) {
if (!swizzle.DestComponentEnabled(i))
@@ -268,14 +290,14 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
dest[i] = rcp_res;
}
- Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
+ Record<DebugDataRecord::DEST_OUT>(debug_data, iteration, dest);
break;
}
// Reciprocal Square Root
case OpCode::Id::RSQ: {
- Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
- Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
+ Record<DebugDataRecord::SRC1>(debug_data, iteration, src1);
+ Record<DebugDataRecord::DEST_IN>(debug_data, iteration, dest);
float24 rsq_res = float24::FromFloat32(1.0f / std::sqrt(src1[0].ToFloat32()));
for (int i = 0; i < 4; ++i) {
if (!swizzle.DestComponentEnabled(i))
@@ -283,12 +305,12 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
dest[i] = rsq_res;
}
- Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
+ Record<DebugDataRecord::DEST_OUT>(debug_data, iteration, dest);
break;
}
case OpCode::Id::MOVA: {
- Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
+ Record<DebugDataRecord::SRC1>(debug_data, iteration, src1);
for (int i = 0; i < 2; ++i) {
if (!swizzle.DestComponentEnabled(i))
continue;
@@ -296,29 +318,29 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
// TODO: Figure out how the rounding is done on hardware
state.address_registers[i] = static_cast<s32>(src1[i].ToFloat32());
}
- Record<DebugDataRecord::ADDR_REG_OUT>(state.debug, iteration,
+ Record<DebugDataRecord::ADDR_REG_OUT>(debug_data, iteration,
state.address_registers);
break;
}
case OpCode::Id::MOV: {
- Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
- Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
+ Record<DebugDataRecord::SRC1>(debug_data, iteration, src1);
+ Record<DebugDataRecord::DEST_IN>(debug_data, iteration, dest);
for (int i = 0; i < 4; ++i) {
if (!swizzle.DestComponentEnabled(i))
continue;
dest[i] = src1[i];
}
- Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
+ Record<DebugDataRecord::DEST_OUT>(debug_data, iteration, dest);
break;
}
case OpCode::Id::SGE:
case OpCode::Id::SGEI:
- Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
- Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
- Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
+ Record<DebugDataRecord::SRC1>(debug_data, iteration, src1);
+ Record<DebugDataRecord::SRC2>(debug_data, iteration, src2);
+ Record<DebugDataRecord::DEST_IN>(debug_data, iteration, dest);
for (int i = 0; i < 4; ++i) {
if (!swizzle.DestComponentEnabled(i))
continue;
@@ -326,14 +348,14 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
dest[i] = (src1[i] >= src2[i]) ? float24::FromFloat32(1.0f)
: float24::FromFloat32(0.0f);
}
- Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
+ Record<DebugDataRecord::DEST_OUT>(debug_data, iteration, dest);
break;
case OpCode::Id::SLT:
case OpCode::Id::SLTI:
- Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
- Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
- Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
+ Record<DebugDataRecord::SRC1>(debug_data, iteration, src1);
+ Record<DebugDataRecord::SRC2>(debug_data, iteration, src2);
+ Record<DebugDataRecord::DEST_IN>(debug_data, iteration, dest);
for (int i = 0; i < 4; ++i) {
if (!swizzle.DestComponentEnabled(i))
continue;
@@ -341,12 +363,12 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
dest[i] = (src1[i] < src2[i]) ? float24::FromFloat32(1.0f)
: float24::FromFloat32(0.0f);
}
- Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
+ Record<DebugDataRecord::DEST_OUT>(debug_data, iteration, dest);
break;
case OpCode::Id::CMP:
- Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
- Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
+ Record<DebugDataRecord::SRC1>(debug_data, iteration, src1);
+ Record<DebugDataRecord::SRC2>(debug_data, iteration, src2);
for (int i = 0; i < 2; ++i) {
// TODO: Can you restrict to one compare via dest masking?
@@ -383,12 +405,12 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
break;
}
}
- Record<DebugDataRecord::CMP_RESULT>(state.debug, iteration, state.conditional_code);
+ Record<DebugDataRecord::CMP_RESULT>(debug_data, iteration, state.conditional_code);
break;
case OpCode::Id::EX2: {
- Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
- Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
+ Record<DebugDataRecord::SRC1>(debug_data, iteration, src1);
+ Record<DebugDataRecord::DEST_IN>(debug_data, iteration, dest);
// EX2 only takes first component exp2 and writes it to all dest components
float24 ex2_res = float24::FromFloat32(std::exp2(src1[0].ToFloat32()));
@@ -399,13 +421,13 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
dest[i] = ex2_res;
}
- Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
+ Record<DebugDataRecord::DEST_OUT>(debug_data, iteration, dest);
break;
}
case OpCode::Id::LG2: {
- Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
- Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
+ Record<DebugDataRecord::SRC1>(debug_data, iteration, src1);
+ Record<DebugDataRecord::DEST_IN>(debug_data, iteration, dest);
// LG2 only takes the first component log2 and writes it to all dest components
float24 lg2_res = float24::FromFloat32(std::log2(src1[0].ToFloat32()));
@@ -416,7 +438,7 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
dest[i] = lg2_res;
}
- Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
+ Record<DebugDataRecord::DEST_OUT>(debug_data, iteration, dest);
break;
}
@@ -498,17 +520,17 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
? &state.registers.temporary[instr.mad.dest.Value().GetIndex()][0]
: dummy_vec4_float24;
- Record<DebugDataRecord::SRC1>(state.debug, iteration, src1);
- Record<DebugDataRecord::SRC2>(state.debug, iteration, src2);
- Record<DebugDataRecord::SRC3>(state.debug, iteration, src3);
- Record<DebugDataRecord::DEST_IN>(state.debug, iteration, dest);
+ Record<DebugDataRecord::SRC1>(debug_data, iteration, src1);
+ Record<DebugDataRecord::SRC2>(debug_data, iteration, src2);
+ Record<DebugDataRecord::SRC3>(debug_data, iteration, src3);
+ Record<DebugDataRecord::DEST_IN>(debug_data, iteration, dest);
for (int i = 0; i < 4; ++i) {
if (!swizzle.DestComponentEnabled(i))
continue;
dest[i] = src1[i] * src2[i] + src3[i];
}
- Record<DebugDataRecord::DEST_OUT>(state.debug, iteration, dest);
+ Record<DebugDataRecord::DEST_OUT>(debug_data, iteration, dest);
} else {
LOG_ERROR(HW_GPU, "Unhandled multiply-add instruction: 0x%02x (%s): 0x%08x",
(int)instr.opcode.Value().EffectiveOpCode(),
@@ -518,26 +540,6 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
}
default: {
- static auto evaluate_condition = [](const UnitState<Debug>& state, bool refx, bool refy,
- Instruction::FlowControlType flow_control) {
- bool results[2] = {refx == state.conditional_code[0],
- refy == state.conditional_code[1]};
-
- switch (flow_control.op) {
- case flow_control.Or:
- return results[0] || results[1];
-
- case flow_control.And:
- return results[0] && results[1];
-
- case flow_control.JustX:
- return results[0];
-
- case flow_control.JustY:
- return results[1];
- }
- };
-
// Handle each instruction on its own
switch (instr.opcode.Value()) {
case OpCode::Id::END:
@@ -545,17 +547,15 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
break;
case OpCode::Id::JMPC:
- Record<DebugDataRecord::COND_CMP_IN>(state.debug, iteration,
- state.conditional_code);
- if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy,
- instr.flow_control)) {
+ Record<DebugDataRecord::COND_CMP_IN>(debug_data, iteration, state.conditional_code);
+ if (evaluate_condition(instr.flow_control)) {
program_counter = instr.flow_control.dest_offset - 1;
}
break;
case OpCode::Id::JMPU:
Record<DebugDataRecord::COND_BOOL_IN>(
- state.debug, iteration, uniforms.b[instr.flow_control.bool_uniform_id]);
+ debug_data, iteration, uniforms.b[instr.flow_control.bool_uniform_id]);
if (uniforms.b[instr.flow_control.bool_uniform_id] ==
!(instr.flow_control.num_instructions & 1)) {
@@ -564,25 +564,23 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
break;
case OpCode::Id::CALL:
- call(state, instr.flow_control.dest_offset, instr.flow_control.num_instructions,
+ call(instr.flow_control.dest_offset, instr.flow_control.num_instructions,
program_counter + 1, 0, 0);
break;
case OpCode::Id::CALLU:
Record<DebugDataRecord::COND_BOOL_IN>(
- state.debug, iteration, uniforms.b[instr.flow_control.bool_uniform_id]);
+ debug_data, iteration, uniforms.b[instr.flow_control.bool_uniform_id]);
if (uniforms.b[instr.flow_control.bool_uniform_id]) {
- call(state, instr.flow_control.dest_offset, instr.flow_control.num_instructions,
+ call(instr.flow_control.dest_offset, instr.flow_control.num_instructions,
program_counter + 1, 0, 0);
}
break;
case OpCode::Id::CALLC:
- Record<DebugDataRecord::COND_CMP_IN>(state.debug, iteration,
- state.conditional_code);
- if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy,
- instr.flow_control)) {
- call(state, instr.flow_control.dest_offset, instr.flow_control.num_instructions,
+ Record<DebugDataRecord::COND_CMP_IN>(debug_data, iteration, state.conditional_code);
+ if (evaluate_condition(instr.flow_control)) {
+ call(instr.flow_control.dest_offset, instr.flow_control.num_instructions,
program_counter + 1, 0, 0);
}
break;
@@ -592,14 +590,13 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
case OpCode::Id::IFU:
Record<DebugDataRecord::COND_BOOL_IN>(
- state.debug, iteration, uniforms.b[instr.flow_control.bool_uniform_id]);
+ debug_data, iteration, uniforms.b[instr.flow_control.bool_uniform_id]);
if (uniforms.b[instr.flow_control.bool_uniform_id]) {
- call(state, program_counter + 1,
- instr.flow_control.dest_offset - program_counter - 1,
+ call(program_counter + 1, instr.flow_control.dest_offset - program_counter - 1,
instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0,
0);
} else {
- call(state, instr.flow_control.dest_offset, instr.flow_control.num_instructions,
+ call(instr.flow_control.dest_offset, instr.flow_control.num_instructions,
instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0,
0);
}
@@ -609,16 +606,13 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
case OpCode::Id::IFC: {
// TODO: Do we need to consider swizzlers here?
- Record<DebugDataRecord::COND_CMP_IN>(state.debug, iteration,
- state.conditional_code);
- if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy,
- instr.flow_control)) {
- call(state, program_counter + 1,
- instr.flow_control.dest_offset - program_counter - 1,
+ Record<DebugDataRecord::COND_CMP_IN>(debug_data, iteration, state.conditional_code);
+ if (evaluate_condition(instr.flow_control)) {
+ call(program_counter + 1, instr.flow_control.dest_offset - program_counter - 1,
instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0,
0);
} else {
- call(state, instr.flow_control.dest_offset, instr.flow_control.num_instructions,
+ call(instr.flow_control.dest_offset, instr.flow_control.num_instructions,
instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0,
0);
}
@@ -633,9 +627,8 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
uniforms.i[instr.flow_control.int_uniform_id].w);
state.address_registers[2] = loop_param.y;
- Record<DebugDataRecord::LOOP_INT_IN>(state.debug, iteration, loop_param);
- call(state, program_counter + 1,
- instr.flow_control.dest_offset - program_counter + 1,
+ Record<DebugDataRecord::LOOP_INT_IN>(debug_data, iteration, loop_param);
+ call(program_counter + 1, instr.flow_control.dest_offset - program_counter + 1,
instr.flow_control.dest_offset + 1, loop_param.x, loop_param.z);
break;
}
@@ -657,8 +650,8 @@ void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned
}
// Explicit instantiation
-template void RunInterpreter(const ShaderSetup& setup, UnitState<false>& state, unsigned offset);
-template void RunInterpreter(const ShaderSetup& setup, UnitState<true>& state, unsigned offset);
+template void RunInterpreter(const ShaderSetup&, UnitState&, DebugData<false>&, unsigned offset);
+template void RunInterpreter(const ShaderSetup&, UnitState&, DebugData<true>&, unsigned offset);
} // namespace
diff --git a/src/video_core/shader/shader_interpreter.h b/src/video_core/shader/shader_interpreter.h
index 48ede0a2e..d31dcd7a6 100644
--- a/src/video_core/shader/shader_interpreter.h
+++ b/src/video_core/shader/shader_interpreter.h
@@ -8,11 +8,14 @@ namespace Pica {
namespace Shader {
-template <bool Debug>
struct UnitState;
template <bool Debug>
-void RunInterpreter(const ShaderSetup& setup, UnitState<Debug>& state, unsigned offset);
+struct DebugData;
+
+template <bool Debug>
+void RunInterpreter(const ShaderSetup& setup, UnitState& state, DebugData<Debug>& debug_data,
+ unsigned offset);
} // namespace
diff --git a/src/video_core/shader/shader_jit_x64.cpp b/src/video_core/shader/shader_jit_x64.cpp
index c96110bb2..c588b778b 100644
--- a/src/video_core/shader/shader_jit_x64.cpp
+++ b/src/video_core/shader/shader_jit_x64.cpp
@@ -6,24 +6,30 @@
#include <cmath>
#include <cstdint>
#include <nihstro/shader_bytecode.h>
+#include <smmintrin.h>
#include <xmmintrin.h>
#include "common/assert.h"
#include "common/logging/log.h"
#include "common/vector_math.h"
-#include "common/x64/abi.h"
#include "common/x64/cpu_detect.h"
-#include "common/x64/emitter.h"
-#include "shader.h"
-#include "shader_jit_x64.h"
+#include "common/x64/xbyak_abi.h"
+#include "common/x64/xbyak_util.h"
#include "video_core/pica_state.h"
#include "video_core/pica_types.h"
+#include "video_core/shader/shader.h"
+#include "video_core/shader/shader_jit_x64.h"
+
+using namespace Common::X64;
+using namespace Xbyak::util;
+using Xbyak::Label;
+using Xbyak::Reg32;
+using Xbyak::Reg64;
+using Xbyak::Xmm;
namespace Pica {
namespace Shader {
-using namespace Gen;
-
typedef void (JitShader::*JitFunction)(Instruction instr);
const JitFunction instr_table[64] = {
@@ -98,44 +104,47 @@ const JitFunction instr_table[64] = {
// purposes, as documented below:
/// Pointer to the uniform memory
-static const X64Reg SETUP = R9;
+static const Reg64 SETUP = r9;
/// The two 32-bit VS address offset registers set by the MOVA instruction
-static const X64Reg ADDROFFS_REG_0 = R10;
-static const X64Reg ADDROFFS_REG_1 = R11;
+static const Reg64 ADDROFFS_REG_0 = r10;
+static const Reg64 ADDROFFS_REG_1 = r11;
/// VS loop count register (Multiplied by 16)
-static const X64Reg LOOPCOUNT_REG = R12;
+static const Reg32 LOOPCOUNT_REG = r12d;
/// Current VS loop iteration number (we could probably use LOOPCOUNT_REG, but this quicker)
-static const X64Reg LOOPCOUNT = RSI;
+static const Reg32 LOOPCOUNT = esi;
/// Number to increment LOOPCOUNT_REG by on each loop iteration (Multiplied by 16)
-static const X64Reg LOOPINC = RDI;
+static const Reg32 LOOPINC = edi;
/// Result of the previous CMP instruction for the X-component comparison
-static const X64Reg COND0 = R13;
+static const Reg64 COND0 = r13;
/// Result of the previous CMP instruction for the Y-component comparison
-static const X64Reg COND1 = R14;
+static const Reg64 COND1 = r14;
/// Pointer to the UnitState instance for the current VS unit
-static const X64Reg STATE = R15;
+static const Reg64 STATE = r15;
/// SIMD scratch register
-static const X64Reg SCRATCH = XMM0;
+static const Xmm SCRATCH = xmm0;
/// Loaded with the first swizzled source register, otherwise can be used as a scratch register
-static const X64Reg SRC1 = XMM1;
+static const Xmm SRC1 = xmm1;
/// Loaded with the second swizzled source register, otherwise can be used as a scratch register
-static const X64Reg SRC2 = XMM2;
+static const Xmm SRC2 = xmm2;
/// Loaded with the third swizzled source register, otherwise can be used as a scratch register
-static const X64Reg SRC3 = XMM3;
+static const Xmm SRC3 = xmm3;
/// Additional scratch register
-static const X64Reg SCRATCH2 = XMM4;
+static const Xmm SCRATCH2 = xmm4;
/// Constant vector of [1.0f, 1.0f, 1.0f, 1.0f], used to efficiently set a vector to one
-static const X64Reg ONE = XMM14;
+static const Xmm ONE = xmm14;
/// Constant vector of [-0.f, -0.f, -0.f, -0.f], used to efficiently negate a vector with XOR
-static const X64Reg NEGBIT = XMM15;
+static const Xmm NEGBIT = xmm15;
// State registers that must not be modified by external functions calls
// Scratch registers, e.g., SRC1 and SCRATCH, have to be saved on the side if needed
-static const BitSet32 persistent_regs = {
- SETUP, STATE, // Pointers to register blocks
- ADDROFFS_REG_0, ADDROFFS_REG_1, LOOPCOUNT_REG, COND0, COND1, // Cached registers
- ONE + 16, NEGBIT + 16, // Constants
-};
+static const BitSet32 persistent_regs = BuildRegSet({
+ // Pointers to register blocks
+ SETUP, STATE,
+ // Cached registers
+ ADDROFFS_REG_0, ADDROFFS_REG_1, LOOPCOUNT_REG, COND0, COND1,
+ // Constants
+ ONE, NEGBIT,
+});
/// Raw constant for the source register selector that indicates no swizzling is performed
static const u8 NO_SRC_REG_SWIZZLE = 0x1b;
@@ -157,7 +166,8 @@ static void LogCritical(const char* msg) {
void JitShader::Compile_Assert(bool condition, const char* msg) {
if (!condition) {
- ABI_CallFunctionP(reinterpret_cast<const void*>(LogCritical), const_cast<char*>(msg));
+ mov(ABI_PARAM1, reinterpret_cast<size_t>(msg));
+ CallFarFunction(*this, LogCritical);
}
}
@@ -169,16 +179,16 @@ void JitShader::Compile_Assert(bool condition, const char* msg) {
* @param dest Destination XMM register to store the loaded, swizzled source register
*/
void JitShader::Compile_SwizzleSrc(Instruction instr, unsigned src_num, SourceRegister src_reg,
- X64Reg dest) {
- X64Reg src_ptr;
+ Xmm dest) {
+ Reg64 src_ptr;
size_t src_offset;
if (src_reg.GetRegisterType() == RegisterType::FloatUniform) {
src_ptr = SETUP;
- src_offset = ShaderSetup::UniformOffset(RegisterType::FloatUniform, src_reg.GetIndex());
+ src_offset = ShaderSetup::GetFloatUniformOffset(src_reg.GetIndex());
} else {
src_ptr = STATE;
- src_offset = UnitState<false>::InputOffset(src_reg);
+ src_offset = UnitState::InputOffset(src_reg);
}
int src_offset_disp = (int)src_offset;
@@ -206,13 +216,13 @@ void JitShader::Compile_SwizzleSrc(Instruction instr, unsigned src_num, SourceRe
if (src_num == offset_src && address_register_index != 0) {
switch (address_register_index) {
case 1: // address offset 1
- MOVAPS(dest, MComplex(src_ptr, ADDROFFS_REG_0, SCALE_1, src_offset_disp));
+ movaps(dest, xword[src_ptr + ADDROFFS_REG_0 + src_offset_disp]);
break;
case 2: // address offset 2
- MOVAPS(dest, MComplex(src_ptr, ADDROFFS_REG_1, SCALE_1, src_offset_disp));
+ movaps(dest, xword[src_ptr + ADDROFFS_REG_1 + src_offset_disp]);
break;
case 3: // address offset 3
- MOVAPS(dest, MComplex(src_ptr, LOOPCOUNT_REG, SCALE_1, src_offset_disp));
+ movaps(dest, xword[src_ptr + LOOPCOUNT_REG.cvt64() + src_offset_disp]);
break;
default:
UNREACHABLE();
@@ -220,7 +230,7 @@ void JitShader::Compile_SwizzleSrc(Instruction instr, unsigned src_num, SourceRe
}
} else {
// Load the source
- MOVAPS(dest, MDisp(src_ptr, src_offset_disp));
+ movaps(dest, xword[src_ptr + src_offset_disp]);
}
SwizzlePattern swiz = {g_state.vs.swizzle_data[operand_desc_id]};
@@ -232,17 +242,17 @@ void JitShader::Compile_SwizzleSrc(Instruction instr, unsigned src_num, SourceRe
sel = ((sel & 0xc0) >> 6) | ((sel & 3) << 6) | ((sel & 0xc) << 2) | ((sel & 0x30) >> 2);
// Shuffle inputs for swizzle
- SHUFPS(dest, R(dest), sel);
+ shufps(dest, dest, sel);
}
// If the source register should be negated, flip the negative bit using XOR
const bool negate[] = {swiz.negate_src1, swiz.negate_src2, swiz.negate_src3};
if (negate[src_num - 1]) {
- XORPS(dest, R(NEGBIT));
+ xorps(dest, NEGBIT);
}
}
-void JitShader::Compile_DestEnable(Instruction instr, X64Reg src) {
+void JitShader::Compile_DestEnable(Instruction instr, Xmm src) {
DestRegister dest;
unsigned operand_desc_id;
if (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD ||
@@ -256,28 +266,26 @@ void JitShader::Compile_DestEnable(Instruction instr, X64Reg src) {
SwizzlePattern swiz = {g_state.vs.swizzle_data[operand_desc_id]};
- int dest_offset_disp = (int)UnitState<false>::OutputOffset(dest);
- ASSERT_MSG(dest_offset_disp == UnitState<false>::OutputOffset(dest),
- "Destinaton offset too large for int type");
+ size_t dest_offset_disp = UnitState::OutputOffset(dest);
// If all components are enabled, write the result to the destination register
if (swiz.dest_mask == NO_DEST_REG_MASK) {
// Store dest back to memory
- MOVAPS(MDisp(STATE, dest_offset_disp), src);
+ movaps(xword[STATE + dest_offset_disp], src);
} else {
// Not all components are enabled, so mask the result when storing to the destination
// register...
- MOVAPS(SCRATCH, MDisp(STATE, dest_offset_disp));
+ movaps(SCRATCH, xword[STATE + dest_offset_disp]);
if (Common::GetCPUCaps().sse4_1) {
u8 mask = ((swiz.dest_mask & 1) << 3) | ((swiz.dest_mask & 8) >> 3) |
((swiz.dest_mask & 2) << 1) | ((swiz.dest_mask & 4) >> 1);
- BLENDPS(SCRATCH, R(src), mask);
+ blendps(SCRATCH, src, mask);
} else {
- MOVAPS(SCRATCH2, R(src));
- UNPCKHPS(SCRATCH2, R(SCRATCH)); // Unpack X/Y components of source and destination
- UNPCKLPS(SCRATCH, R(src)); // Unpack Z/W components of source and destination
+ movaps(SCRATCH2, src);
+ unpckhps(SCRATCH2, SCRATCH); // Unpack X/Y components of source and destination
+ unpcklps(SCRATCH, src); // Unpack Z/W components of source and destination
// Compute selector to selectively copy source components to destination for SHUFPS
// instruction
@@ -285,62 +293,61 @@ void JitShader::Compile_DestEnable(Instruction instr, X64Reg src) {
((swiz.DestComponentEnabled(1) ? 3 : 2) << 2) |
((swiz.DestComponentEnabled(2) ? 0 : 1) << 4) |
((swiz.DestComponentEnabled(3) ? 2 : 3) << 6);
- SHUFPS(SCRATCH, R(SCRATCH2), sel);
+ shufps(SCRATCH, SCRATCH2, sel);
}
// Store dest back to memory
- MOVAPS(MDisp(STATE, dest_offset_disp), SCRATCH);
+ movaps(xword[STATE + dest_offset_disp], SCRATCH);
}
}
-void JitShader::Compile_SanitizedMul(Gen::X64Reg src1, Gen::X64Reg src2, Gen::X64Reg scratch) {
- MOVAPS(scratch, R(src1));
- CMPPS(scratch, R(src2), CMP_ORD);
+void JitShader::Compile_SanitizedMul(Xmm src1, Xmm src2, Xmm scratch) {
+ movaps(scratch, src1);
+ cmpordps(scratch, src2);
- MULPS(src1, R(src2));
+ mulps(src1, src2);
- MOVAPS(src2, R(src1));
- CMPPS(src2, R(src2), CMP_UNORD);
+ movaps(src2, src1);
+ cmpunordps(src2, src2);
- XORPS(scratch, R(src2));
- ANDPS(src1, R(scratch));
+ xorps(scratch, src2);
+ andps(src1, scratch);
}
void JitShader::Compile_EvaluateCondition(Instruction instr) {
// Note: NXOR is used below to check for equality
switch (instr.flow_control.op) {
case Instruction::FlowControlType::Or:
- MOV(32, R(RAX), R(COND0));
- MOV(32, R(RBX), R(COND1));
- XOR(32, R(RAX), Imm32(instr.flow_control.refx.Value() ^ 1));
- XOR(32, R(RBX), Imm32(instr.flow_control.refy.Value() ^ 1));
- OR(32, R(RAX), R(RBX));
+ mov(eax, COND0);
+ mov(ebx, COND1);
+ xor(eax, (instr.flow_control.refx.Value() ^ 1));
+ xor(ebx, (instr.flow_control.refy.Value() ^ 1));
+ or (eax, ebx);
break;
case Instruction::FlowControlType::And:
- MOV(32, R(RAX), R(COND0));
- MOV(32, R(RBX), R(COND1));
- XOR(32, R(RAX), Imm32(instr.flow_control.refx.Value() ^ 1));
- XOR(32, R(RBX), Imm32(instr.flow_control.refy.Value() ^ 1));
- AND(32, R(RAX), R(RBX));
+ mov(eax, COND0);
+ mov(ebx, COND1);
+ xor(eax, (instr.flow_control.refx.Value() ^ 1));
+ xor(ebx, (instr.flow_control.refy.Value() ^ 1));
+ and(eax, ebx);
break;
case Instruction::FlowControlType::JustX:
- MOV(32, R(RAX), R(COND0));
- XOR(32, R(RAX), Imm32(instr.flow_control.refx.Value() ^ 1));
+ mov(eax, COND0);
+ xor(eax, (instr.flow_control.refx.Value() ^ 1));
break;
case Instruction::FlowControlType::JustY:
- MOV(32, R(RAX), R(COND1));
- XOR(32, R(RAX), Imm32(instr.flow_control.refy.Value() ^ 1));
+ mov(eax, COND1);
+ xor(eax, (instr.flow_control.refy.Value() ^ 1));
break;
}
}
void JitShader::Compile_UniformCondition(Instruction instr) {
- int offset =
- ShaderSetup::UniformOffset(RegisterType::BoolUniform, instr.flow_control.bool_uniform_id);
- CMP(sizeof(bool) * 8, MDisp(SETUP, offset), Imm8(0));
+ size_t offset = ShaderSetup::GetBoolUniformOffset(instr.flow_control.bool_uniform_id);
+ cmp(byte[SETUP + offset], 0);
}
BitSet32 JitShader::PersistentCallerSavedRegs() {
@@ -350,7 +357,7 @@ BitSet32 JitShader::PersistentCallerSavedRegs() {
void JitShader::Compile_ADD(Instruction instr) {
Compile_SwizzleSrc(instr, 1, instr.common.src1, SRC1);
Compile_SwizzleSrc(instr, 2, instr.common.src2, SRC2);
- ADDPS(SRC1, R(SRC2));
+ addps(SRC1, SRC2);
Compile_DestEnable(instr, SRC1);
}
@@ -360,15 +367,15 @@ void JitShader::Compile_DP3(Instruction instr) {
Compile_SanitizedMul(SRC1, SRC2, SCRATCH);
- MOVAPS(SRC2, R(SRC1));
- SHUFPS(SRC2, R(SRC2), _MM_SHUFFLE(1, 1, 1, 1));
+ movaps(SRC2, SRC1);
+ shufps(SRC2, SRC2, _MM_SHUFFLE(1, 1, 1, 1));
- MOVAPS(SRC3, R(SRC1));
- SHUFPS(SRC3, R(SRC3), _MM_SHUFFLE(2, 2, 2, 2));
+ movaps(SRC3, SRC1);
+ shufps(SRC3, SRC3, _MM_SHUFFLE(2, 2, 2, 2));
- SHUFPS(SRC1, R(SRC1), _MM_SHUFFLE(0, 0, 0, 0));
- ADDPS(SRC1, R(SRC2));
- ADDPS(SRC1, R(SRC3));
+ shufps(SRC1, SRC1, _MM_SHUFFLE(0, 0, 0, 0));
+ addps(SRC1, SRC2);
+ addps(SRC1, SRC3);
Compile_DestEnable(instr, SRC1);
}
@@ -379,13 +386,13 @@ void JitShader::Compile_DP4(Instruction instr) {
Compile_SanitizedMul(SRC1, SRC2, SCRATCH);
- MOVAPS(SRC2, R(SRC1));
- SHUFPS(SRC1, R(SRC1), _MM_SHUFFLE(2, 3, 0, 1)); // XYZW -> ZWXY
- ADDPS(SRC1, R(SRC2));
+ movaps(SRC2, SRC1);
+ shufps(SRC1, SRC1, _MM_SHUFFLE(2, 3, 0, 1)); // XYZW -> ZWXY
+ addps(SRC1, SRC2);
- MOVAPS(SRC2, R(SRC1));
- SHUFPS(SRC1, R(SRC1), _MM_SHUFFLE(0, 1, 2, 3)); // XYZW -> WZYX
- ADDPS(SRC1, R(SRC2));
+ movaps(SRC2, SRC1);
+ shufps(SRC1, SRC1, _MM_SHUFFLE(0, 1, 2, 3)); // XYZW -> WZYX
+ addps(SRC1, SRC2);
Compile_DestEnable(instr, SRC1);
}
@@ -401,50 +408,50 @@ void JitShader::Compile_DPH(Instruction instr) {
if (Common::GetCPUCaps().sse4_1) {
// Set 4th component to 1.0
- BLENDPS(SRC1, R(ONE), 0x8); // 0b1000
+ blendps(SRC1, ONE, 0b1000);
} else {
// Set 4th component to 1.0
- MOVAPS(SCRATCH, R(SRC1));
- UNPCKHPS(SCRATCH, R(ONE)); // XYZW, 1111 -> Z1__
- UNPCKLPD(SRC1, R(SCRATCH)); // XYZW, Z1__ -> XYZ1
+ movaps(SCRATCH, SRC1);
+ unpckhps(SCRATCH, ONE); // XYZW, 1111 -> Z1__
+ unpcklpd(SRC1, SCRATCH); // XYZW, Z1__ -> XYZ1
}
Compile_SanitizedMul(SRC1, SRC2, SCRATCH);
- MOVAPS(SRC2, R(SRC1));
- SHUFPS(SRC1, R(SRC1), _MM_SHUFFLE(2, 3, 0, 1)); // XYZW -> ZWXY
- ADDPS(SRC1, R(SRC2));
+ movaps(SRC2, SRC1);
+ shufps(SRC1, SRC1, _MM_SHUFFLE(2, 3, 0, 1)); // XYZW -> ZWXY
+ addps(SRC1, SRC2);
- MOVAPS(SRC2, R(SRC1));
- SHUFPS(SRC1, R(SRC1), _MM_SHUFFLE(0, 1, 2, 3)); // XYZW -> WZYX
- ADDPS(SRC1, R(SRC2));
+ movaps(SRC2, SRC1);
+ shufps(SRC1, SRC1, _MM_SHUFFLE(0, 1, 2, 3)); // XYZW -> WZYX
+ addps(SRC1, SRC2);
Compile_DestEnable(instr, SRC1);
}
void JitShader::Compile_EX2(Instruction instr) {
Compile_SwizzleSrc(instr, 1, instr.common.src1, SRC1);
- MOVSS(XMM0, R(SRC1));
+ movss(xmm0, SRC1); // ABI_PARAM1
- ABI_PushRegistersAndAdjustStack(PersistentCallerSavedRegs(), 0);
- ABI_CallFunction(reinterpret_cast<const void*>(exp2f));
- ABI_PopRegistersAndAdjustStack(PersistentCallerSavedRegs(), 0);
+ ABI_PushRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0);
+ CallFarFunction(*this, exp2f);
+ ABI_PopRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0);
- SHUFPS(XMM0, R(XMM0), _MM_SHUFFLE(0, 0, 0, 0));
- MOVAPS(SRC1, R(XMM0));
+ shufps(xmm0, xmm0, _MM_SHUFFLE(0, 0, 0, 0)); // ABI_RETURN
+ movaps(SRC1, xmm0);
Compile_DestEnable(instr, SRC1);
}
void JitShader::Compile_LG2(Instruction instr) {
Compile_SwizzleSrc(instr, 1, instr.common.src1, SRC1);
- MOVSS(XMM0, R(SRC1));
+ movss(xmm0, SRC1); // ABI_PARAM1
- ABI_PushRegistersAndAdjustStack(PersistentCallerSavedRegs(), 0);
- ABI_CallFunction(reinterpret_cast<const void*>(log2f));
- ABI_PopRegistersAndAdjustStack(PersistentCallerSavedRegs(), 0);
+ ABI_PushRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0);
+ CallFarFunction(*this, log2f);
+ ABI_PopRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0);
- SHUFPS(XMM0, R(XMM0), _MM_SHUFFLE(0, 0, 0, 0));
- MOVAPS(SRC1, R(XMM0));
+ shufps(xmm0, xmm0, _MM_SHUFFLE(0, 0, 0, 0)); // ABI_RETURN
+ movaps(SRC1, xmm0);
Compile_DestEnable(instr, SRC1);
}
@@ -464,8 +471,8 @@ void JitShader::Compile_SGE(Instruction instr) {
Compile_SwizzleSrc(instr, 2, instr.common.src2, SRC2);
}
- CMPPS(SRC2, R(SRC1), CMP_LE);
- ANDPS(SRC2, R(ONE));
+ cmpleps(SRC2, SRC1);
+ andps(SRC2, ONE);
Compile_DestEnable(instr, SRC2);
}
@@ -479,8 +486,8 @@ void JitShader::Compile_SLT(Instruction instr) {
Compile_SwizzleSrc(instr, 2, instr.common.src2, SRC2);
}
- CMPPS(SRC1, R(SRC2), CMP_LT);
- ANDPS(SRC1, R(ONE));
+ cmpltps(SRC1, SRC2);
+ andps(SRC1, ONE);
Compile_DestEnable(instr, SRC1);
}
@@ -489,10 +496,10 @@ void JitShader::Compile_FLR(Instruction instr) {
Compile_SwizzleSrc(instr, 1, instr.common.src1, SRC1);
if (Common::GetCPUCaps().sse4_1) {
- ROUNDFLOORPS(SRC1, R(SRC1));
+ roundps(SRC1, SRC1, _MM_FROUND_FLOOR);
} else {
- CVTTPS2DQ(SRC1, R(SRC1));
- CVTDQ2PS(SRC1, R(SRC1));
+ cvttps2dq(SRC1, SRC1);
+ cvtdq2ps(SRC1, SRC1);
}
Compile_DestEnable(instr, SRC1);
@@ -502,7 +509,7 @@ void JitShader::Compile_MAX(Instruction instr) {
Compile_SwizzleSrc(instr, 1, instr.common.src1, SRC1);
Compile_SwizzleSrc(instr, 2, instr.common.src2, SRC2);
// SSE semantics match PICA200 ones: In case of NaN, SRC2 is returned.
- MAXPS(SRC1, R(SRC2));
+ maxps(SRC1, SRC2);
Compile_DestEnable(instr, SRC1);
}
@@ -510,7 +517,7 @@ void JitShader::Compile_MIN(Instruction instr) {
Compile_SwizzleSrc(instr, 1, instr.common.src1, SRC1);
Compile_SwizzleSrc(instr, 2, instr.common.src2, SRC2);
// SSE semantics match PICA200 ones: In case of NaN, SRC2 is returned.
- MINPS(SRC1, R(SRC2));
+ minps(SRC1, SRC2);
Compile_DestEnable(instr, SRC1);
}
@@ -524,37 +531,37 @@ void JitShader::Compile_MOVA(Instruction instr) {
Compile_SwizzleSrc(instr, 1, instr.common.src1, SRC1);
// Convert floats to integers using truncation (only care about X and Y components)
- CVTTPS2DQ(SRC1, R(SRC1));
+ cvttps2dq(SRC1, SRC1);
// Get result
- MOVQ_xmm(R(RAX), SRC1);
+ movq(rax, SRC1);
// Handle destination enable
if (swiz.DestComponentEnabled(0) && swiz.DestComponentEnabled(1)) {
// Move and sign-extend low 32 bits
- MOVSX(64, 32, ADDROFFS_REG_0, R(RAX));
+ movsxd(ADDROFFS_REG_0, eax);
// Move and sign-extend high 32 bits
- SHR(64, R(RAX), Imm8(32));
- MOVSX(64, 32, ADDROFFS_REG_1, R(RAX));
+ shr(rax, 32);
+ movsxd(ADDROFFS_REG_1, eax);
// Multiply by 16 to be used as an offset later
- SHL(64, R(ADDROFFS_REG_0), Imm8(4));
- SHL(64, R(ADDROFFS_REG_1), Imm8(4));
+ shl(ADDROFFS_REG_0, 4);
+ shl(ADDROFFS_REG_1, 4);
} else {
if (swiz.DestComponentEnabled(0)) {
// Move and sign-extend low 32 bits
- MOVSX(64, 32, ADDROFFS_REG_0, R(RAX));
+ movsxd(ADDROFFS_REG_0, eax);
// Multiply by 16 to be used as an offset later
- SHL(64, R(ADDROFFS_REG_0), Imm8(4));
+ shl(ADDROFFS_REG_0, 4);
} else if (swiz.DestComponentEnabled(1)) {
// Move and sign-extend high 32 bits
- SHR(64, R(RAX), Imm8(32));
- MOVSX(64, 32, ADDROFFS_REG_1, R(RAX));
+ shr(rax, 32);
+ movsxd(ADDROFFS_REG_1, eax);
// Multiply by 16 to be used as an offset later
- SHL(64, R(ADDROFFS_REG_1), Imm8(4));
+ shl(ADDROFFS_REG_1, 4);
}
}
}
@@ -569,8 +576,8 @@ void JitShader::Compile_RCP(Instruction instr) {
// TODO(bunnei): RCPSS is a pretty rough approximation, this might cause problems if Pica
// performs this operation more accurately. This should be checked on hardware.
- RCPSS(SRC1, R(SRC1));
- SHUFPS(SRC1, R(SRC1), _MM_SHUFFLE(0, 0, 0, 0)); // XYWZ -> XXXX
+ rcpss(SRC1, SRC1);
+ shufps(SRC1, SRC1, _MM_SHUFFLE(0, 0, 0, 0)); // XYWZ -> XXXX
Compile_DestEnable(instr, SRC1);
}
@@ -580,8 +587,8 @@ void JitShader::Compile_RSQ(Instruction instr) {
// TODO(bunnei): RSQRTSS is a pretty rough approximation, this might cause problems if Pica
// performs this operation more accurately. This should be checked on hardware.
- RSQRTSS(SRC1, R(SRC1));
- SHUFPS(SRC1, R(SRC1), _MM_SHUFFLE(0, 0, 0, 0)); // XYWZ -> XXXX
+ rsqrtss(SRC1, SRC1);
+ shufps(SRC1, SRC1, _MM_SHUFFLE(0, 0, 0, 0)); // XYWZ -> XXXX
Compile_DestEnable(instr, SRC1);
}
@@ -589,34 +596,35 @@ void JitShader::Compile_RSQ(Instruction instr) {
void JitShader::Compile_NOP(Instruction instr) {}
void JitShader::Compile_END(Instruction instr) {
- ABI_PopRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8);
- RET();
+ ABI_PopRegistersAndAdjustStack(*this, ABI_ALL_CALLEE_SAVED, 8);
+ ret();
}
void JitShader::Compile_CALL(Instruction instr) {
// Push offset of the return
- PUSH(64, Imm32(instr.flow_control.dest_offset + instr.flow_control.num_instructions));
+ push(qword, (instr.flow_control.dest_offset + instr.flow_control.num_instructions));
// Call the subroutine
- FixupBranch b = CALL();
- fixup_branches.push_back({b, instr.flow_control.dest_offset});
+ call(instruction_labels[instr.flow_control.dest_offset]);
// Skip over the return offset that's on the stack
- ADD(64, R(RSP), Imm32(8));
+ add(rsp, 8);
}
void JitShader::Compile_CALLC(Instruction instr) {
Compile_EvaluateCondition(instr);
- FixupBranch b = J_CC(CC_Z, true);
+ Label b;
+ jz(b);
Compile_CALL(instr);
- SetJumpTarget(b);
+ L(b);
}
void JitShader::Compile_CALLU(Instruction instr) {
Compile_UniformCondition(instr);
- FixupBranch b = J_CC(CC_Z, true);
+ Label b;
+ jz(b);
Compile_CALL(instr);
- SetJumpTarget(b);
+ L(b);
}
void JitShader::Compile_CMP(Instruction instr) {
@@ -633,33 +641,33 @@ void JitShader::Compile_CMP(Instruction instr) {
static const u8 cmp[] = {CMP_EQ, CMP_NEQ, CMP_LT, CMP_LE, CMP_LT, CMP_LE};
bool invert_op_x = (op_x == Op::GreaterThan || op_x == Op::GreaterEqual);
- Gen::X64Reg lhs_x = invert_op_x ? SRC2 : SRC1;
- Gen::X64Reg rhs_x = invert_op_x ? SRC1 : SRC2;
+ Xmm lhs_x = invert_op_x ? SRC2 : SRC1;
+ Xmm rhs_x = invert_op_x ? SRC1 : SRC2;
if (op_x == op_y) {
// Compare X-component and Y-component together
- CMPPS(lhs_x, R(rhs_x), cmp[op_x]);
- MOVQ_xmm(R(COND0), lhs_x);
+ cmpps(lhs_x, rhs_x, cmp[op_x]);
+ movq(COND0, lhs_x);
- MOV(64, R(COND1), R(COND0));
+ mov(COND1, COND0);
} else {
bool invert_op_y = (op_y == Op::GreaterThan || op_y == Op::GreaterEqual);
- Gen::X64Reg lhs_y = invert_op_y ? SRC2 : SRC1;
- Gen::X64Reg rhs_y = invert_op_y ? SRC1 : SRC2;
+ Xmm lhs_y = invert_op_y ? SRC2 : SRC1;
+ Xmm rhs_y = invert_op_y ? SRC1 : SRC2;
// Compare X-component
- MOVAPS(SCRATCH, R(lhs_x));
- CMPSS(SCRATCH, R(rhs_x), cmp[op_x]);
+ movaps(SCRATCH, lhs_x);
+ cmpss(SCRATCH, rhs_x, cmp[op_x]);
// Compare Y-component
- CMPPS(lhs_y, R(rhs_y), cmp[op_y]);
+ cmpps(lhs_y, rhs_y, cmp[op_y]);
- MOVQ_xmm(R(COND0), SCRATCH);
- MOVQ_xmm(R(COND1), lhs_y);
+ movq(COND0, SCRATCH);
+ movq(COND1, lhs_y);
}
- SHR(32, R(COND0), Imm8(31));
- SHR(64, R(COND1), Imm8(63));
+ shr(COND0.cvt32(), 31); // ignores upper 32 bits in source
+ shr(COND1, 63);
}
void JitShader::Compile_MAD(Instruction instr) {
@@ -674,7 +682,7 @@ void JitShader::Compile_MAD(Instruction instr) {
}
Compile_SanitizedMul(SRC1, SRC2, SCRATCH);
- ADDPS(SRC1, R(SRC3));
+ addps(SRC1, SRC3);
Compile_DestEnable(instr, SRC1);
}
@@ -682,6 +690,7 @@ void JitShader::Compile_MAD(Instruction instr) {
void JitShader::Compile_IF(Instruction instr) {
Compile_Assert(instr.flow_control.dest_offset >= program_counter,
"Backwards if-statements not supported");
+ Label l_else, l_endif;
// Evaluate the "IF" condition
if (instr.opcode.Value() == OpCode::Id::IFU) {
@@ -689,26 +698,25 @@ void JitShader::Compile_IF(Instruction instr) {
} else if (instr.opcode.Value() == OpCode::Id::IFC) {
Compile_EvaluateCondition(instr);
}
- FixupBranch b = J_CC(CC_Z, true);
+ jz(l_else, T_NEAR);
// Compile the code that corresponds to the condition evaluating as true
Compile_Block(instr.flow_control.dest_offset);
// If there isn't an "ELSE" condition, we are done here
if (instr.flow_control.num_instructions == 0) {
- SetJumpTarget(b);
+ L(l_else);
return;
}
- FixupBranch b2 = J(true);
-
- SetJumpTarget(b);
+ jmp(l_endif, T_NEAR);
+ L(l_else);
// This code corresponds to the "ELSE" condition
// Comple the code that corresponds to the condition evaluating as false
Compile_Block(instr.flow_control.dest_offset + instr.flow_control.num_instructions);
- SetJumpTarget(b2);
+ L(l_endif);
}
void JitShader::Compile_LOOP(Instruction instr) {
@@ -721,25 +729,25 @@ void JitShader::Compile_LOOP(Instruction instr) {
// This decodes the fields from the integer uniform at index instr.flow_control.int_uniform_id.
// The Y (LOOPCOUNT_REG) and Z (LOOPINC) component are kept multiplied by 16 (Left shifted by
// 4 bits) to be used as an offset into the 16-byte vector registers later
- int offset =
- ShaderSetup::UniformOffset(RegisterType::IntUniform, instr.flow_control.int_uniform_id);
- MOV(32, R(LOOPCOUNT), MDisp(SETUP, offset));
- MOV(32, R(LOOPCOUNT_REG), R(LOOPCOUNT));
- SHR(32, R(LOOPCOUNT_REG), Imm8(4));
- AND(32, R(LOOPCOUNT_REG), Imm32(0xFF0)); // Y-component is the start
- MOV(32, R(LOOPINC), R(LOOPCOUNT));
- SHR(32, R(LOOPINC), Imm8(12));
- AND(32, R(LOOPINC), Imm32(0xFF0)); // Z-component is the incrementer
- MOVZX(32, 8, LOOPCOUNT, R(LOOPCOUNT)); // X-component is iteration count
- ADD(32, R(LOOPCOUNT), Imm8(1)); // Iteration count is X-component + 1
-
- auto loop_start = GetCodePtr();
+ size_t offset = ShaderSetup::GetIntUniformOffset(instr.flow_control.int_uniform_id);
+ mov(LOOPCOUNT, dword[SETUP + offset]);
+ mov(LOOPCOUNT_REG, LOOPCOUNT);
+ shr(LOOPCOUNT_REG, 4);
+ and(LOOPCOUNT_REG, 0xFF0); // Y-component is the start
+ mov(LOOPINC, LOOPCOUNT);
+ shr(LOOPINC, 12);
+ and(LOOPINC, 0xFF0); // Z-component is the incrementer
+ movzx(LOOPCOUNT, LOOPCOUNT.cvt8()); // X-component is iteration count
+ add(LOOPCOUNT, 1); // Iteration count is X-component + 1
+
+ Label l_loop_start;
+ L(l_loop_start);
Compile_Block(instr.flow_control.dest_offset + 1);
- ADD(32, R(LOOPCOUNT_REG), R(LOOPINC)); // Increment LOOPCOUNT_REG by Z-component
- SUB(32, R(LOOPCOUNT), Imm8(1)); // Increment loop count by 1
- J_CC(CC_NZ, loop_start); // Loop if not equal
+ add(LOOPCOUNT_REG, LOOPINC); // Increment LOOPCOUNT_REG by Z-component
+ sub(LOOPCOUNT, 1); // Increment loop count by 1
+ jnz(l_loop_start); // Loop if not equal
looping = false;
}
@@ -755,8 +763,12 @@ void JitShader::Compile_JMP(Instruction instr) {
bool inverted_condition =
(instr.opcode.Value() == OpCode::Id::JMPU) && (instr.flow_control.num_instructions & 1);
- FixupBranch b = J_CC(inverted_condition ? CC_Z : CC_NZ, true);
- fixup_branches.push_back({b, instr.flow_control.dest_offset});
+ Label& b = instruction_labels[instr.flow_control.dest_offset];
+ if (inverted_condition) {
+ jz(b, T_NEAR);
+ } else {
+ jnz(b, T_NEAR);
+ }
}
void JitShader::Compile_Block(unsigned end) {
@@ -767,13 +779,14 @@ void JitShader::Compile_Block(unsigned end) {
void JitShader::Compile_Return() {
// Peek return offset on the stack and check if we're at that offset
- MOV(64, R(RAX), MDisp(RSP, 8));
- CMP(32, R(RAX), Imm32(program_counter));
+ mov(rax, qword[rsp + 8]);
+ cmp(eax, (program_counter));
// If so, jump back to before CALL
- FixupBranch b = J_CC(CC_NZ, true);
- RET();
- SetJumpTarget(b);
+ Label b;
+ jnz(b);
+ ret();
+ L(b);
}
void JitShader::Compile_NextInstr() {
@@ -781,9 +794,7 @@ void JitShader::Compile_NextInstr() {
Compile_Return();
}
- ASSERT_MSG(code_ptr[program_counter] == nullptr,
- "Tried to compile already compiled shader location!");
- code_ptr[program_counter] = GetCodePtr();
+ L(instruction_labels[program_counter]);
Instruction instr = GetVertexShaderInstruction(program_counter++);
@@ -824,64 +835,53 @@ void JitShader::FindReturnOffsets() {
void JitShader::Compile() {
// Reset flow control state
- program = (CompiledShader*)GetCodePtr();
+ program = (CompiledShader*)getCurr();
program_counter = 0;
looping = false;
- code_ptr.fill(nullptr);
- fixup_branches.clear();
+ instruction_labels.fill(Xbyak::Label());
// Find all `CALL` instructions and identify return locations
FindReturnOffsets();
// The stack pointer is 8 modulo 16 at the entry of a procedure
- ABI_PushRegistersAndAdjustStack(ABI_ALL_CALLEE_SAVED, 8);
+ ABI_PushRegistersAndAdjustStack(*this, ABI_ALL_CALLEE_SAVED, 8);
- MOV(PTRBITS, R(SETUP), R(ABI_PARAM1));
- MOV(PTRBITS, R(STATE), R(ABI_PARAM2));
+ mov(SETUP, ABI_PARAM1);
+ mov(STATE, ABI_PARAM2);
// Zero address/loop registers
- XOR(64, R(ADDROFFS_REG_0), R(ADDROFFS_REG_0));
- XOR(64, R(ADDROFFS_REG_1), R(ADDROFFS_REG_1));
- XOR(64, R(LOOPCOUNT_REG), R(LOOPCOUNT_REG));
+ xor(ADDROFFS_REG_0.cvt32(), ADDROFFS_REG_0.cvt32());
+ xor(ADDROFFS_REG_1.cvt32(), ADDROFFS_REG_1.cvt32());
+ xor(LOOPCOUNT_REG, LOOPCOUNT_REG);
// Used to set a register to one
static const __m128 one = {1.f, 1.f, 1.f, 1.f};
- MOV(PTRBITS, R(RAX), ImmPtr(&one));
- MOVAPS(ONE, MatR(RAX));
+ mov(rax, reinterpret_cast<size_t>(&one));
+ movaps(ONE, xword[rax]);
// Used to negate registers
static const __m128 neg = {-0.f, -0.f, -0.f, -0.f};
- MOV(PTRBITS, R(RAX), ImmPtr(&neg));
- MOVAPS(NEGBIT, MatR(RAX));
+ mov(rax, reinterpret_cast<size_t>(&neg));
+ movaps(NEGBIT, xword[rax]);
// Jump to start of the shader program
- JMPptr(R(ABI_PARAM3));
+ jmp(ABI_PARAM3);
// Compile entire program
Compile_Block(static_cast<unsigned>(g_state.vs.program_code.size()));
- // Set the target for any incomplete branches now that the entire shader program has been
- // emitted
- for (const auto& branch : fixup_branches) {
- SetJumpTarget(branch.first, code_ptr[branch.second]);
- }
-
// Free memory that's no longer needed
return_offsets.clear();
return_offsets.shrink_to_fit();
- fixup_branches.clear();
- fixup_branches.shrink_to_fit();
- uintptr_t size =
- reinterpret_cast<uintptr_t>(GetCodePtr()) - reinterpret_cast<uintptr_t>(program);
- ASSERT_MSG(size <= MAX_SHADER_SIZE, "Compiled a shader that exceeds the allocated size!");
+ ready();
+ uintptr_t size = reinterpret_cast<uintptr_t>(getCurr()) - reinterpret_cast<uintptr_t>(program);
+ ASSERT_MSG(size <= MAX_SHADER_SIZE, "Compiled a shader that exceeds the allocated size!");
LOG_DEBUG(HW_GPU, "Compiled shader size=%lu", size);
}
-JitShader::JitShader() {
- AllocCodeSpace(MAX_SHADER_SIZE);
-}
+JitShader::JitShader() : Xbyak::CodeGenerator(MAX_SHADER_SIZE) {}
} // namespace Shader
diff --git a/src/video_core/shader/shader_jit_x64.h b/src/video_core/shader/shader_jit_x64.h
index 98de5ecef..f37548306 100644
--- a/src/video_core/shader/shader_jit_x64.h
+++ b/src/video_core/shader/shader_jit_x64.h
@@ -9,6 +9,7 @@
#include <utility>
#include <vector>
#include <nihstro/shader_bytecode.h>
+#include <xbyak.h>
#include "common/bit_set.h"
#include "common/common_types.h"
#include "common/x64/emitter.h"
@@ -29,12 +30,12 @@ constexpr size_t MAX_SHADER_SIZE = 1024 * 64;
* This class implements the shader JIT compiler. It recompiles a Pica shader program into x86_64
* code that can be executed on the host machine directly.
*/
-class JitShader : public Gen::XCodeBlock {
+class JitShader : public Xbyak::CodeGenerator {
public:
JitShader();
- void Run(const ShaderSetup& setup, UnitState<false>& state, unsigned offset) const {
- program(&setup, &state, code_ptr[offset]);
+ void Run(const ShaderSetup& setup, UnitState& state, unsigned offset) const {
+ program(&setup, &state, instruction_labels[offset].getAddress());
}
void Compile();
@@ -71,14 +72,14 @@ private:
void Compile_NextInstr();
void Compile_SwizzleSrc(Instruction instr, unsigned src_num, SourceRegister src_reg,
- Gen::X64Reg dest);
- void Compile_DestEnable(Instruction instr, Gen::X64Reg dest);
+ Xbyak::Xmm dest);
+ void Compile_DestEnable(Instruction instr, Xbyak::Xmm dest);
/**
* Compiles a `MUL src1, src2` operation, properly handling the PICA semantics when multiplying
* zero by inf. Clobbers `src2` and `scratch`.
*/
- void Compile_SanitizedMul(Gen::X64Reg src1, Gen::X64Reg src2, Gen::X64Reg scratch);
+ void Compile_SanitizedMul(Xbyak::Xmm src1, Xbyak::Xmm src2, Xbyak::Xmm scratch);
void Compile_EvaluateCondition(Instruction instr);
void Compile_UniformCondition(Instruction instr);
@@ -103,7 +104,7 @@ private:
void FindReturnOffsets();
/// Mapping of Pica VS instructions to pointers in the emitted code
- std::array<const u8*, 1024> code_ptr;
+ std::array<Xbyak::Label, 1024> instruction_labels;
/// Offsets in code where a return needs to be inserted
std::vector<unsigned> return_offsets;
@@ -111,9 +112,6 @@ private:
unsigned program_counter = 0; ///< Offset of the next instruction to decode
bool looping = false; ///< True if compiling a loop, used to check for nested loops
- /// Branches that need to be fixed up once the entire shader program is compiled
- std::vector<std::pair<Gen::FixupBranch, unsigned>> fixup_branches;
-
using CompiledShader = void(const void* setup, void* state, const u8* start_addr);
CompiledShader* program = nullptr;
};