summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/citra/CMakeLists.txt7
-rw-r--r--src/citra/citra.cpp42
-rw-r--r--src/citra/config.cpp39
-rw-r--r--src/citra/config.h6
-rw-r--r--src/citra/default_ini.h4
-rw-r--r--src/citra/emu_window/emu_window_glfw.cpp41
-rw-r--r--src/citra/emu_window/emu_window_glfw.h2
-rw-r--r--src/citra_qt/CMakeLists.txt6
-rw-r--r--src/citra_qt/bootmanager.cpp35
-rw-r--r--src/citra_qt/bootmanager.h5
-rw-r--r--src/citra_qt/config.cpp65
-rw-r--r--src/citra_qt/config.h4
-rw-r--r--src/citra_qt/debugger/disassembler.cpp5
-rw-r--r--src/citra_qt/debugger/graphics_breakpoint_observer.h2
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints.cpp112
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints.h6
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints_p.h2
-rw-r--r--src/citra_qt/debugger/graphics_cmdlists.cpp68
-rw-r--r--src/citra_qt/debugger/graphics_cmdlists.h2
-rw-r--r--src/citra_qt/debugger/graphics_framebuffer.cpp62
-rw-r--r--src/citra_qt/debugger/graphics_framebuffer.h4
-rw-r--r--src/citra_qt/debugger/graphics_tracing.cpp170
-rw-r--r--src/citra_qt/debugger/graphics_tracing.h32
-rw-r--r--src/citra_qt/debugger/graphics_vertex_shader.cpp4
-rw-r--r--src/citra_qt/debugger/profiler.cpp2
-rw-r--r--src/citra_qt/hotkeys.cpp5
-rw-r--r--src/citra_qt/hotkeys.h4
-rw-r--r--src/citra_qt/main.cpp18
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/assert.h1
-rw-r--r--src/common/bit_field.h5
-rw-r--r--src/common/chunk_file.h10
-rw-r--r--src/common/color.h27
-rw-r--r--src/common/common_funcs.h17
-rw-r--r--src/common/common_types.h28
-rw-r--r--src/common/emu_window.cpp6
-rw-r--r--src/common/emu_window.h12
-rw-r--r--src/common/fifo_queue.h111
-rw-r--r--src/common/file_util.cpp11
-rw-r--r--src/common/file_util.h16
-rw-r--r--src/common/logging/filter.h1
-rw-r--r--src/common/logging/log.h4
-rw-r--r--src/common/make_unique.h1
-rw-r--r--src/common/memory_util.cpp11
-rw-r--r--src/common/memory_util.h4
-rw-r--r--src/common/misc.cpp5
-rw-r--r--src/common/platform.h55
-rw-r--r--src/common/profiler.cpp11
-rw-r--r--src/common/profiler_reporting.h5
-rw-r--r--src/common/string_util.cpp11
-rw-r--r--src/common/string_util.h3
-rw-r--r--src/common/swap.h10
-rw-r--r--src/common/synchronized_wrapper.h1
-rw-r--r--src/common/thread.cpp17
-rw-r--r--src/common/thread.h16
-rw-r--r--src/common/thunk.h42
-rw-r--r--src/core/CMakeLists.txt16
-rw-r--r--src/core/arm/disassembler/load_symbol_map.cpp1
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp32
-rw-r--r--src/core/arm/dyncom/arm_dyncom.h7
-rw-r--r--src/core/arm/dyncom/arm_dyncom_dec.cpp27
-rw-r--r--src/core/arm/dyncom/arm_dyncom_dec.h16
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp473
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.h2
-rw-r--r--src/core/arm/dyncom/arm_dyncom_run.cpp93
-rw-r--r--src/core/arm/dyncom/arm_dyncom_run.h23
-rw-r--r--src/core/arm/dyncom/arm_dyncom_thumb.cpp61
-rw-r--r--src/core/arm/dyncom/arm_dyncom_thumb.h30
-rw-r--r--src/core/arm/interpreter/arminit.cpp128
-rw-r--r--src/core/arm/interpreter/armsupp.cpp637
-rw-r--r--src/core/arm/skyeye_common/arm_regformat.h2
-rw-r--r--src/core/arm/skyeye_common/armdefs.h318
-rw-r--r--src/core/arm/skyeye_common/armmmu.h103
-rw-r--r--src/core/arm/skyeye_common/armstate.cpp657
-rw-r--r--src/core/arm/skyeye_common/armstate.h252
-rw-r--r--src/core/arm/skyeye_common/armsupp.cpp208
-rw-r--r--src/core/arm/skyeye_common/armsupp.h32
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.cpp38
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.h14
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp_helper.h4
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpdouble.cpp12
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpinstr.cpp197
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpsingle.cpp4
-rw-r--r--src/core/core.cpp3
-rw-r--r--src/core/core_timing.cpp6
-rw-r--r--src/core/file_sys/archive_backend.cpp2
-rw-r--r--src/core/file_sys/archive_extsavedata.cpp5
-rw-r--r--src/core/file_sys/archive_extsavedata.h7
-rw-r--r--src/core/file_sys/archive_romfs.cpp10
-rw-r--r--src/core/file_sys/archive_romfs.h10
-rw-r--r--src/core/file_sys/archive_savedata.cpp8
-rw-r--r--src/core/file_sys/archive_savedata.h7
-rw-r--r--src/core/file_sys/archive_savedatacheck.cpp17
-rw-r--r--src/core/file_sys/archive_savedatacheck.h9
-rw-r--r--src/core/file_sys/archive_sdmc.cpp3
-rw-r--r--src/core/file_sys/archive_sdmc.h7
-rw-r--r--src/core/file_sys/archive_systemsavedata.cpp6
-rw-r--r--src/core/file_sys/archive_systemsavedata.h7
-rw-r--r--src/core/file_sys/disk_archive.cpp12
-rw-r--r--src/core/file_sys/disk_archive.h15
-rw-r--r--src/core/file_sys/file_backend.h10
-rw-r--r--src/core/file_sys/ivfc_archive.cpp21
-rw-r--r--src/core/file_sys/ivfc_archive.h27
-rw-r--r--src/core/hle/applets/applet.cpp101
-rw-r--r--src/core/hle/applets/applet.h77
-rw-r--r--src/core/hle/applets/swkbd.cpp113
-rw-r--r--src/core/hle/applets/swkbd.h90
-rw-r--r--src/core/hle/function_wrappers.h26
-rw-r--r--src/core/hle/hle.cpp1
-rw-r--r--src/core/hle/kernel/event.cpp2
-rw-r--r--src/core/hle/kernel/event.h1
-rw-r--r--src/core/hle/kernel/kernel.cpp2
-rw-r--r--src/core/hle/kernel/kernel.h9
-rw-r--r--src/core/hle/kernel/process.cpp38
-rw-r--r--src/core/hle/kernel/process.h47
-rw-r--r--src/core/hle/kernel/session.h6
-rw-r--r--src/core/hle/kernel/shared_memory.h3
-rw-r--r--src/core/hle/kernel/thread.cpp31
-rw-r--r--src/core/hle/kernel/thread.h1
-rw-r--r--src/core/hle/kernel/vm_manager.cpp16
-rw-r--r--src/core/hle/kernel/vm_manager.h7
-rw-r--r--src/core/hle/result.h2
-rw-r--r--src/core/hle/service/am/am.cpp9
-rw-r--r--src/core/hle/service/am/am.h13
-rw-r--r--src/core/hle/service/am/am_app.cpp14
-rw-r--r--src/core/hle/service/apt/apt.cpp163
-rw-r--r--src/core/hle/service/apt/apt.h58
-rw-r--r--src/core/hle/service/apt/apt_a.cpp31
-rw-r--r--src/core/hle/service/apt/apt_u.cpp4
-rw-r--r--src/core/hle/service/cfg/cfg_s.cpp4
-rw-r--r--src/core/hle/service/dsp_dsp.cpp5
-rw-r--r--src/core/hle/service/dsp_dsp.h3
-rw-r--r--src/core/hle/service/frd/frd_u.cpp13
-rw-r--r--src/core/hle/service/fs/archive.cpp12
-rw-r--r--src/core/hle/service/fs/archive.h13
-rw-r--r--src/core/hle/service/fs/fs_user.cpp12
-rw-r--r--src/core/hle/service/gsp_gpu.cpp55
-rw-r--r--src/core/hle/service/gsp_gpu.h14
-rw-r--r--src/core/hle/service/hid/hid.cpp11
-rw-r--r--src/core/hle/service/hid/hid.h19
-rw-r--r--src/core/hle/service/nwm_uds.cpp4
-rw-r--r--src/core/hle/service/nwm_uds.h1
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/service/service.h3
-rw-r--r--src/core/hle/service/soc_u.cpp93
-rw-r--r--src/core/hle/service/soc_u.h2
-rw-r--r--src/core/hle/service/srv.cpp4
-rw-r--r--src/core/hle/service/srv.h1
-rw-r--r--src/core/hle/service/y2r_u.cpp5
-rw-r--r--src/core/hle/service/y2r_u.h3
-rw-r--r--src/core/hle/shared_page.cpp6
-rw-r--r--src/core/hle/shared_page.h3
-rw-r--r--src/core/hle/svc.cpp41
-rw-r--r--src/core/hle/svc.h2
-rw-r--r--src/core/hw/gpu.cpp214
-rw-r--r--src/core/hw/gpu.h2
-rw-r--r--src/core/hw/hw.cpp30
-rw-r--r--src/core/hw/lcd.cpp12
-rw-r--r--src/core/hw/lcd.h1
-rw-r--r--src/core/hw/y2r.cpp6
-rw-r--r--src/core/loader/3dsx.cpp73
-rw-r--r--src/core/loader/3dsx.h2
-rw-r--r--src/core/loader/elf.cpp93
-rw-r--r--src/core/loader/elf.h2
-rw-r--r--src/core/loader/loader.cpp28
-rw-r--r--src/core/loader/loader.h29
-rw-r--r--src/core/loader/ncch.cpp87
-rw-r--r--src/core/loader/ncch.h19
-rw-r--r--src/core/mem_map.cpp19
-rw-r--r--src/core/mem_map.h5
-rw-r--r--src/core/memory.cpp9
-rw-r--r--src/core/memory.h2
-rw-r--r--src/core/settings.h54
-rw-r--r--src/core/tracer/citrace.h101
-rw-r--r--src/core/tracer/recorder.cpp187
-rw-r--r--src/core/tracer/recorder.h90
-rw-r--r--src/video_core/CMakeLists.txt1
-rw-r--r--src/video_core/clipper.cpp4
-rw-r--r--src/video_core/command_processor.cpp246
-rw-r--r--src/video_core/command_processor.h4
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp45
-rw-r--r--src/video_core/debug_utils/debug_utils.h16
-rw-r--r--src/video_core/hwrasterizer_base.h9
-rw-r--r--src/video_core/pica.cpp72
-rw-r--r--src/video_core/pica.h319
-rw-r--r--src/video_core/primitive_assembly.cpp3
-rw-r--r--src/video_core/rasterizer.cpp189
-rw-r--r--src/video_core/renderer_base.h4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp19
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h5
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp16
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.cpp111
-rw-r--r--src/video_core/renderer_opengl/gl_resource_manager.h110
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp13
-rw-r--r--src/video_core/renderer_opengl/pica_to_gl.h29
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp19
-rw-r--r--src/video_core/vertex_shader.cpp75
-rw-r--r--src/video_core/vertex_shader.h7
-rw-r--r--src/video_core/video_core.h7
199 files changed, 4980 insertions, 3380 deletions
diff --git a/src/citra/CMakeLists.txt b/src/citra/CMakeLists.txt
index 713f49193..918687312 100644
--- a/src/citra/CMakeLists.txt
+++ b/src/citra/CMakeLists.txt
@@ -16,6 +16,11 @@ create_directory_groups(${SRCS} ${HEADERS})
16add_executable(citra ${SRCS} ${HEADERS}) 16add_executable(citra ${SRCS} ${HEADERS})
17target_link_libraries(citra core common video_core) 17target_link_libraries(citra core common video_core)
18target_link_libraries(citra ${GLFW_LIBRARIES} ${OPENGL_gl_LIBRARY} inih) 18target_link_libraries(citra ${GLFW_LIBRARIES} ${OPENGL_gl_LIBRARY} inih)
19if (MSVC)
20 target_link_libraries(citra getopt)
21endif()
19target_link_libraries(citra ${PLATFORM_LIBRARIES}) 22target_link_libraries(citra ${PLATFORM_LIBRARIES})
20 23
21#install(TARGETS citra RUNTIME DESTINATION ${bindir}) 24if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|FreeBSD|OpenBSD|NetBSD")
25 install(TARGETS citra RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
26endif() \ No newline at end of file
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp
index ce8d7dd25..182646f4c 100644
--- a/src/citra/citra.cpp
+++ b/src/citra/citra.cpp
@@ -2,13 +2,20 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <string>
5#include <thread> 6#include <thread>
7#include <iostream>
8
9#ifdef _MSC_VER
10#include <getopt.h>
11#else
12#include <unistd.h>
13#include <getopt.h>
14#endif
6 15
7#include "common/logging/log.h" 16#include "common/logging/log.h"
8#include "common/logging/text_formatter.h"
9#include "common/logging/backend.h" 17#include "common/logging/backend.h"
10#include "common/logging/filter.h" 18#include "common/logging/filter.h"
11#include "common/scope_exit.h"
12 19
13#include "core/settings.h" 20#include "core/settings.h"
14#include "core/system.h" 21#include "core/system.h"
@@ -20,12 +27,39 @@
20 27
21#include "video_core/video_core.h" 28#include "video_core/video_core.h"
22 29
30
31static void PrintHelp()
32{
33 std::cout << "Usage: citra <filename>" << std::endl;
34}
35
23/// Application entry point 36/// Application entry point
24int main(int argc, char **argv) { 37int main(int argc, char **argv) {
38 int option_index = 0;
39 std::string boot_filename;
40 static struct option long_options[] = {
41 { "help", no_argument, 0, 'h' },
42 { 0, 0, 0, 0 }
43 };
44
45 while (optind < argc) {
46 char arg = getopt_long(argc, argv, ":h", long_options, &option_index);
47 if (arg != -1) {
48 switch (arg) {
49 case 'h':
50 PrintHelp();
51 return 0;
52 }
53 } else {
54 boot_filename = argv[optind];
55 optind++;
56 }
57 }
58
25 Log::Filter log_filter(Log::Level::Debug); 59 Log::Filter log_filter(Log::Level::Debug);
26 Log::SetFilter(&log_filter); 60 Log::SetFilter(&log_filter);
27 61
28 if (argc < 2) { 62 if (boot_filename.empty()) {
29 LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified"); 63 LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified");
30 return -1; 64 return -1;
31 } 65 }
@@ -33,7 +67,7 @@ int main(int argc, char **argv) {
33 Config config; 67 Config config;
34 log_filter.ParseFilterString(Settings::values.log_filter); 68 log_filter.ParseFilterString(Settings::values.log_filter);
35 69
36 std::string boot_filename = argv[1]; 70
37 EmuWindow_GLFW* emu_window = new EmuWindow_GLFW; 71 EmuWindow_GLFW* emu_window = new EmuWindow_GLFW;
38 72
39 VideoCore::g_hw_renderer_enabled = Settings::values.use_hw_renderer; 73 VideoCore::g_hw_renderer_enabled = Settings::values.use_hw_renderer;
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index 1378567c1..2c1407a6f 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -2,7 +2,9 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#define GLFW_INCLUDE_NONE
5#include <GLFW/glfw3.h> 6#include <GLFW/glfw3.h>
7#include <inih/cpp/INIReader.h>
6 8
7#include "citra/default_ini.h" 9#include "citra/default_ini.h"
8 10
@@ -10,7 +12,6 @@
10#include "common/logging/log.h" 12#include "common/logging/log.h"
11 13
12#include "core/settings.h" 14#include "core/settings.h"
13#include "core/core.h"
14 15
15#include "config.h" 16#include "config.h"
16 17
@@ -39,31 +40,21 @@ bool Config::LoadINI(INIReader* config, const char* location, const std::string&
39 return true; 40 return true;
40} 41}
41 42
43static const std::array<int, Settings::NativeInput::NUM_INPUTS> defaults = {
44 GLFW_KEY_A, GLFW_KEY_S, GLFW_KEY_Z, GLFW_KEY_X,
45 GLFW_KEY_Q, GLFW_KEY_W, GLFW_KEY_1, GLFW_KEY_2,
46 GLFW_KEY_M, GLFW_KEY_N, GLFW_KEY_B,
47 GLFW_KEY_T, GLFW_KEY_G, GLFW_KEY_F, GLFW_KEY_H,
48 GLFW_KEY_UP, GLFW_KEY_DOWN, GLFW_KEY_LEFT, GLFW_KEY_RIGHT,
49 GLFW_KEY_I, GLFW_KEY_K, GLFW_KEY_J, GLFW_KEY_L
50};
51
42void Config::ReadValues() { 52void Config::ReadValues() {
43 // Controls 53 // Controls
44 Settings::values.pad_a_key = glfw_config->GetInteger("Controls", "pad_a", GLFW_KEY_A); 54 for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
45 Settings::values.pad_b_key = glfw_config->GetInteger("Controls", "pad_b", GLFW_KEY_S); 55 Settings::values.input_mappings[Settings::NativeInput::All[i]] =
46 Settings::values.pad_x_key = glfw_config->GetInteger("Controls", "pad_x", GLFW_KEY_Z); 56 glfw_config->GetInteger("Controls", Settings::NativeInput::Mapping[i], defaults[i]);
47 Settings::values.pad_y_key = glfw_config->GetInteger("Controls", "pad_y", GLFW_KEY_X); 57 }
48 Settings::values.pad_l_key = glfw_config->GetInteger("Controls", "pad_l", GLFW_KEY_Q);
49 Settings::values.pad_r_key = glfw_config->GetInteger("Controls", "pad_r", GLFW_KEY_W);
50 Settings::values.pad_zl_key = glfw_config->GetInteger("Controls", "pad_zl", GLFW_KEY_1);
51 Settings::values.pad_zr_key = glfw_config->GetInteger("Controls", "pad_zr", GLFW_KEY_2);
52 Settings::values.pad_start_key = glfw_config->GetInteger("Controls", "pad_start", GLFW_KEY_M);
53 Settings::values.pad_select_key = glfw_config->GetInteger("Controls", "pad_select", GLFW_KEY_N);
54 Settings::values.pad_home_key = glfw_config->GetInteger("Controls", "pad_home", GLFW_KEY_B);
55 Settings::values.pad_dup_key = glfw_config->GetInteger("Controls", "pad_dup", GLFW_KEY_T);
56 Settings::values.pad_ddown_key = glfw_config->GetInteger("Controls", "pad_ddown", GLFW_KEY_G);
57 Settings::values.pad_dleft_key = glfw_config->GetInteger("Controls", "pad_dleft", GLFW_KEY_F);
58 Settings::values.pad_dright_key = glfw_config->GetInteger("Controls", "pad_dright", GLFW_KEY_H);
59 Settings::values.pad_sup_key = glfw_config->GetInteger("Controls", "pad_sup", GLFW_KEY_UP);
60 Settings::values.pad_sdown_key = glfw_config->GetInteger("Controls", "pad_sdown", GLFW_KEY_DOWN);
61 Settings::values.pad_sleft_key = glfw_config->GetInteger("Controls", "pad_sleft", GLFW_KEY_LEFT);
62 Settings::values.pad_sright_key = glfw_config->GetInteger("Controls", "pad_sright", GLFW_KEY_RIGHT);
63 Settings::values.pad_cup_key = glfw_config->GetInteger("Controls", "pad_cup", GLFW_KEY_I);
64 Settings::values.pad_cdown_key = glfw_config->GetInteger("Controls", "pad_cdown", GLFW_KEY_K);
65 Settings::values.pad_cleft_key = glfw_config->GetInteger("Controls", "pad_cleft", GLFW_KEY_J);
66 Settings::values.pad_cright_key = glfw_config->GetInteger("Controls", "pad_cright", GLFW_KEY_L);
67 58
68 // Core 59 // Core
69 Settings::values.frame_skip = glfw_config->GetInteger("Core", "frame_skip", 0); 60 Settings::values.frame_skip = glfw_config->GetInteger("Core", "frame_skip", 0);
diff --git a/src/citra/config.h b/src/citra/config.h
index 0eb176c7d..c326ec669 100644
--- a/src/citra/config.h
+++ b/src/citra/config.h
@@ -4,11 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <map> 7#include <string>
8 8
9#include <inih/cpp/INIReader.h> 9class INIReader;
10
11#include "common/common_types.h"
12 10
13class Config { 11class Config {
14 INIReader* glfw_config; 12 INIReader* glfw_config;
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index fd5a90d56..1925bece8 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -33,10 +33,6 @@ pad_cleft =
33pad_cright = 33pad_cright =
34 34
35[Core] 35[Core]
36# The refresh rate for the GPU
37# Defaults to 30
38gpu_refresh_rate =
39
40# The applied frameskip amount. Must be a power of two. 36# The applied frameskip amount. Must be a power of two.
41# 0 (default): No frameskip, 1: x2 frameskip, 2: x4 frameskip, 3: x8 frameskip, etc. 37# 0 (default): No frameskip, 1: x2 frameskip, 2: x4 frameskip, 3: x8 frameskip, etc.
42frame_skip = 38frame_skip =
diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp
index 341b48d2a..6d6656b5a 100644
--- a/src/citra/emu_window/emu_window_glfw.cpp
+++ b/src/citra/emu_window/emu_window_glfw.cpp
@@ -2,13 +2,25 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <cstdlib>
7#include <string>
8
9// Let’s use our own GL header, instead of one from GLFW.
10#include "video_core/renderer_opengl/generated/gl_3_2_core.h"
11#define GLFW_INCLUDE_NONE
5#include <GLFW/glfw3.h> 12#include <GLFW/glfw3.h>
6 13
14#include "common/assert.h"
15#include "common/key_map.h"
7#include "common/logging/log.h" 16#include "common/logging/log.h"
17#include "common/scm_rev.h"
18#include "common/string_util.h"
8 19
9#include "video_core/video_core.h" 20#include "video_core/video_core.h"
10 21
11#include "core/settings.h" 22#include "core/settings.h"
23#include "core/hle/service/hid/hid.h"
12 24
13#include "citra/emu_window/emu_window_glfw.h" 25#include "citra/emu_window/emu_window_glfw.h"
14 26
@@ -138,32 +150,9 @@ void EmuWindow_GLFW::DoneCurrent() {
138} 150}
139 151
140void EmuWindow_GLFW::ReloadSetKeymaps() { 152void EmuWindow_GLFW::ReloadSetKeymaps() {
141 KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, Service::HID::PAD_A); 153 for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
142 KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, Service::HID::PAD_B); 154 KeyMap::SetKeyMapping({Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id}, Service::HID::pad_mapping[i]);
143 KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, Service::HID::PAD_SELECT); 155 }
144 KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, Service::HID::PAD_START);
145 KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, Service::HID::PAD_RIGHT);
146 KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, Service::HID::PAD_LEFT);
147 KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, Service::HID::PAD_UP);
148 KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, Service::HID::PAD_DOWN);
149 KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, Service::HID::PAD_R);
150 KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, Service::HID::PAD_L);
151 KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, Service::HID::PAD_X);
152 KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, Service::HID::PAD_Y);
153
154 KeyMap::SetKeyMapping({Settings::values.pad_zl_key, keyboard_id}, Service::HID::PAD_ZL);
155 KeyMap::SetKeyMapping({Settings::values.pad_zr_key, keyboard_id}, Service::HID::PAD_ZR);
156
157 // KeyMap::SetKeyMapping({Settings::values.pad_touch_key, keyboard_id}, Service::HID::PAD_TOUCH);
158
159 KeyMap::SetKeyMapping({Settings::values.pad_cright_key, keyboard_id}, Service::HID::PAD_C_RIGHT);
160 KeyMap::SetKeyMapping({Settings::values.pad_cleft_key, keyboard_id}, Service::HID::PAD_C_LEFT);
161 KeyMap::SetKeyMapping({Settings::values.pad_cup_key, keyboard_id}, Service::HID::PAD_C_UP);
162 KeyMap::SetKeyMapping({Settings::values.pad_cdown_key, keyboard_id}, Service::HID::PAD_C_DOWN);
163 KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, Service::HID::PAD_CIRCLE_RIGHT);
164 KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, Service::HID::PAD_CIRCLE_LEFT);
165 KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, Service::HID::PAD_CIRCLE_UP);
166 KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, Service::HID::PAD_CIRCLE_DOWN);
167} 156}
168 157
169void EmuWindow_GLFW::OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) { 158void EmuWindow_GLFW::OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) {
diff --git a/src/citra/emu_window/emu_window_glfw.h b/src/citra/emu_window/emu_window_glfw.h
index 16c109b79..7ccd5e6aa 100644
--- a/src/citra/emu_window/emu_window_glfw.h
+++ b/src/citra/emu_window/emu_window_glfw.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <utility>
8
7#include "common/emu_window.h" 9#include "common/emu_window.h"
8 10
9struct GLFWwindow; 11struct GLFWwindow;
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index c2d1ad240..47aaeca24 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -12,6 +12,7 @@ set(SRCS
12 debugger/graphics_breakpoints.cpp 12 debugger/graphics_breakpoints.cpp
13 debugger/graphics_cmdlists.cpp 13 debugger/graphics_cmdlists.cpp
14 debugger/graphics_framebuffer.cpp 14 debugger/graphics_framebuffer.cpp
15 debugger/graphics_tracing.cpp
15 debugger/graphics_vertex_shader.cpp 16 debugger/graphics_vertex_shader.cpp
16 debugger/profiler.cpp 17 debugger/profiler.cpp
17 debugger/ramview.cpp 18 debugger/ramview.cpp
@@ -35,6 +36,7 @@ set(HEADERS
35 debugger/graphics_breakpoints_p.h 36 debugger/graphics_breakpoints_p.h
36 debugger/graphics_cmdlists.h 37 debugger/graphics_cmdlists.h
37 debugger/graphics_framebuffer.h 38 debugger/graphics_framebuffer.h
39 debugger/graphics_tracing.h
38 debugger/graphics_vertex_shader.h 40 debugger/graphics_vertex_shader.h
39 debugger/profiler.h 41 debugger/profiler.h
40 debugger/ramview.h 42 debugger/ramview.h
@@ -73,7 +75,9 @@ target_link_libraries(citra-qt core common video_core qhexedit)
73target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) 75target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS})
74target_link_libraries(citra-qt ${PLATFORM_LIBRARIES}) 76target_link_libraries(citra-qt ${PLATFORM_LIBRARIES})
75 77
76#install(TARGETS citra-qt RUNTIME DESTINATION ${bindir}) 78if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|FreeBSD|OpenBSD|NetBSD")
79 install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
80endif()
77 81
78if (Qt5_FOUND AND MSVC) 82if (Qt5_FOUND AND MSVC)
79 set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin") 83 set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin")
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 3db09c65b..b12bd858b 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -11,6 +11,10 @@
11#include "bootmanager.h" 11#include "bootmanager.h"
12#include "main.h" 12#include "main.h"
13 13
14#include "common/string_util.h"
15#include "common/scm_rev.h"
16#include "common/key_map.h"
17
14#include "core/core.h" 18#include "core/core.h"
15#include "core/settings.h" 19#include "core/settings.h"
16#include "core/system.h" 20#include "core/system.h"
@@ -61,7 +65,7 @@ void EmuThread::run() {
61 was_active = false; 65 was_active = false;
62 } else { 66 } else {
63 std::unique_lock<std::mutex> lock(running_mutex); 67 std::unique_lock<std::mutex> lock(running_mutex);
64 running_cv.wait(lock, [this]{ return IsRunning() || stop_run; }); 68 running_cv.wait(lock, [this]{ return IsRunning() || exec_step || stop_run; });
65 } 69 }
66 } 70 }
67 71
@@ -244,32 +248,9 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent *event)
244 248
245void GRenderWindow::ReloadSetKeymaps() 249void GRenderWindow::ReloadSetKeymaps()
246{ 250{
247 KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, Service::HID::PAD_A); 251 for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
248 KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, Service::HID::PAD_B); 252 KeyMap::SetKeyMapping({Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id}, Service::HID::pad_mapping[i]);
249 KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, Service::HID::PAD_SELECT); 253 }
250 KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, Service::HID::PAD_START);
251 KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, Service::HID::PAD_RIGHT);
252 KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, Service::HID::PAD_LEFT);
253 KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, Service::HID::PAD_UP);
254 KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, Service::HID::PAD_DOWN);
255 KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, Service::HID::PAD_R);
256 KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, Service::HID::PAD_L);
257 KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, Service::HID::PAD_X);
258 KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, Service::HID::PAD_Y);
259
260 KeyMap::SetKeyMapping({Settings::values.pad_zl_key, keyboard_id}, Service::HID::PAD_ZL);
261 KeyMap::SetKeyMapping({Settings::values.pad_zr_key, keyboard_id}, Service::HID::PAD_ZR);
262
263 // KeyMap::SetKeyMapping({Settings::values.pad_touch_key, keyboard_id}, Service::HID::PAD_TOUCH);
264
265 KeyMap::SetKeyMapping({Settings::values.pad_cright_key, keyboard_id}, Service::HID::PAD_C_RIGHT);
266 KeyMap::SetKeyMapping({Settings::values.pad_cleft_key, keyboard_id}, Service::HID::PAD_C_LEFT);
267 KeyMap::SetKeyMapping({Settings::values.pad_cup_key, keyboard_id}, Service::HID::PAD_C_UP);
268 KeyMap::SetKeyMapping({Settings::values.pad_cdown_key, keyboard_id}, Service::HID::PAD_C_DOWN);
269 KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, Service::HID::PAD_CIRCLE_RIGHT);
270 KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, Service::HID::PAD_CIRCLE_LEFT);
271 KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, Service::HID::PAD_CIRCLE_UP);
272 KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, Service::HID::PAD_CIRCLE_DOWN);
273} 254}
274 255
275void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height) 256void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height)
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h
index 475124319..1a1e0e6a5 100644
--- a/src/citra_qt/bootmanager.h
+++ b/src/citra_qt/bootmanager.h
@@ -35,7 +35,10 @@ public:
35 * Steps the emulation thread by a single CPU instruction (if the CPU is not already running) 35 * Steps the emulation thread by a single CPU instruction (if the CPU is not already running)
36 * @note This function is thread-safe 36 * @note This function is thread-safe
37 */ 37 */
38 void ExecStep() { exec_step = true; } 38 void ExecStep() {
39 exec_step = true;
40 running_cv.notify_all();
41 }
39 42
40 /** 43 /**
41 * Sets whether the emulation thread is running or not 44 * Sets whether the emulation thread is running or not
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index 2a9af1f38..5716634ee 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -2,11 +2,11 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <QSettings>
5#include <QString> 6#include <QString>
6#include <QStringList> 7#include <QStringList>
7 8
8#include "core/settings.h" 9#include "core/settings.h"
9#include "core/core.h"
10#include "common/file_util.h" 10#include "common/file_util.h"
11 11
12#include "config.h" 12#include "config.h"
@@ -21,31 +21,21 @@ Config::Config() {
21 Reload(); 21 Reload();
22} 22}
23 23
24static const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> defaults = {
25 Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X,
26 Qt::Key_Q, Qt::Key_W, Qt::Key_1, Qt::Key_2,
27 Qt::Key_M, Qt::Key_N, Qt::Key_B,
28 Qt::Key_T, Qt::Key_G, Qt::Key_F, Qt::Key_H,
29 Qt::Key_Up, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right,
30 Qt::Key_I, Qt::Key_K, Qt::Key_J, Qt::Key_L
31};
32
24void Config::ReadValues() { 33void Config::ReadValues() {
25 qt_config->beginGroup("Controls"); 34 qt_config->beginGroup("Controls");
26 Settings::values.pad_a_key = qt_config->value("pad_a", Qt::Key_A).toInt(); 35 for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
27 Settings::values.pad_b_key = qt_config->value("pad_b", Qt::Key_S).toInt(); 36 Settings::values.input_mappings[Settings::NativeInput::All[i]] =
28 Settings::values.pad_x_key = qt_config->value("pad_x", Qt::Key_Z).toInt(); 37 qt_config->value(QString::fromStdString(Settings::NativeInput::Mapping[i]), defaults[i]).toInt();
29 Settings::values.pad_y_key = qt_config->value("pad_y", Qt::Key_X).toInt(); 38 }
30 Settings::values.pad_l_key = qt_config->value("pad_l", Qt::Key_Q).toInt();
31 Settings::values.pad_r_key = qt_config->value("pad_r", Qt::Key_W).toInt();
32 Settings::values.pad_zl_key = qt_config->value("pad_zl", Qt::Key_1).toInt();
33 Settings::values.pad_zr_key = qt_config->value("pad_zr", Qt::Key_2).toInt();
34 Settings::values.pad_start_key = qt_config->value("pad_start", Qt::Key_M).toInt();
35 Settings::values.pad_select_key = qt_config->value("pad_select", Qt::Key_N).toInt();
36 Settings::values.pad_home_key = qt_config->value("pad_home", Qt::Key_B).toInt();
37 Settings::values.pad_dup_key = qt_config->value("pad_dup", Qt::Key_T).toInt();
38 Settings::values.pad_ddown_key = qt_config->value("pad_ddown", Qt::Key_G).toInt();
39 Settings::values.pad_dleft_key = qt_config->value("pad_dleft", Qt::Key_F).toInt();
40 Settings::values.pad_dright_key = qt_config->value("pad_dright", Qt::Key_H).toInt();
41 Settings::values.pad_sup_key = qt_config->value("pad_sup", Qt::Key_Up).toInt();
42 Settings::values.pad_sdown_key = qt_config->value("pad_sdown", Qt::Key_Down).toInt();
43 Settings::values.pad_sleft_key = qt_config->value("pad_sleft", Qt::Key_Left).toInt();
44 Settings::values.pad_sright_key = qt_config->value("pad_sright", Qt::Key_Right).toInt();
45 Settings::values.pad_cup_key = qt_config->value("pad_cup", Qt::Key_I).toInt();
46 Settings::values.pad_cdown_key = qt_config->value("pad_cdown", Qt::Key_K).toInt();
47 Settings::values.pad_cleft_key = qt_config->value("pad_cleft", Qt::Key_J).toInt();
48 Settings::values.pad_cright_key = qt_config->value("pad_cright", Qt::Key_L).toInt();
49 qt_config->endGroup(); 39 qt_config->endGroup();
50 40
51 qt_config->beginGroup("Core"); 41 qt_config->beginGroup("Core");
@@ -75,29 +65,10 @@ void Config::ReadValues() {
75 65
76void Config::SaveValues() { 66void Config::SaveValues() {
77 qt_config->beginGroup("Controls"); 67 qt_config->beginGroup("Controls");
78 qt_config->setValue("pad_a", Settings::values.pad_a_key); 68 for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
79 qt_config->setValue("pad_b", Settings::values.pad_b_key); 69 qt_config->setValue(QString::fromStdString(Settings::NativeInput::Mapping[i]),
80 qt_config->setValue("pad_x", Settings::values.pad_x_key); 70 Settings::values.input_mappings[Settings::NativeInput::All[i]]);
81 qt_config->setValue("pad_y", Settings::values.pad_y_key); 71 }
82 qt_config->setValue("pad_l", Settings::values.pad_l_key);
83 qt_config->setValue("pad_r", Settings::values.pad_r_key);
84 qt_config->setValue("pad_zl", Settings::values.pad_zl_key);
85 qt_config->setValue("pad_zr", Settings::values.pad_zr_key);
86 qt_config->setValue("pad_start", Settings::values.pad_start_key);
87 qt_config->setValue("pad_select", Settings::values.pad_select_key);
88 qt_config->setValue("pad_home", Settings::values.pad_home_key);
89 qt_config->setValue("pad_dup", Settings::values.pad_dup_key);
90 qt_config->setValue("pad_ddown", Settings::values.pad_ddown_key);
91 qt_config->setValue("pad_dleft", Settings::values.pad_dleft_key);
92 qt_config->setValue("pad_dright", Settings::values.pad_dright_key);
93 qt_config->setValue("pad_sup", Settings::values.pad_sup_key);
94 qt_config->setValue("pad_sdown", Settings::values.pad_sdown_key);
95 qt_config->setValue("pad_sleft", Settings::values.pad_sleft_key);
96 qt_config->setValue("pad_sright", Settings::values.pad_sright_key);
97 qt_config->setValue("pad_cup", Settings::values.pad_cup_key);
98 qt_config->setValue("pad_cdown", Settings::values.pad_cdown_key);
99 qt_config->setValue("pad_cleft", Settings::values.pad_cleft_key);
100 qt_config->setValue("pad_cright", Settings::values.pad_cright_key);
101 qt_config->endGroup(); 72 qt_config->endGroup();
102 73
103 qt_config->beginGroup("Core"); 74 qt_config->beginGroup("Core");
diff --git a/src/citra_qt/config.h b/src/citra_qt/config.h
index 4485cae73..dd0b2ef0b 100644
--- a/src/citra_qt/config.h
+++ b/src/citra_qt/config.h
@@ -4,9 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <QSettings> 7#include <string>
8 8
9#include "common/common_types.h" 9class QSettings;
10 10
11class Config { 11class Config {
12 QSettings* qt_config; 12 QSettings* qt_config;
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp
index e99ec1b30..1e5ef5299 100644
--- a/src/citra_qt/debugger/disassembler.cpp
+++ b/src/citra_qt/debugger/disassembler.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <QShortcut>
6
5#include "disassembler.h" 7#include "disassembler.h"
6 8
7#include "../bootmanager.h" 9#include "../bootmanager.h"
@@ -13,7 +15,6 @@
13#include "common/break_points.h" 15#include "common/break_points.h"
14#include "common/symbols.h" 16#include "common/symbols.h"
15#include "core/arm/arm_interface.h" 17#include "core/arm/arm_interface.h"
16#include "core/arm/skyeye_common/armdefs.h"
17#include "core/arm/disassembler/arm_disasm.h" 18#include "core/arm/disassembler/arm_disasm.h"
18 19
19 20
@@ -217,7 +218,7 @@ void DisassemblerWidget::OnToggleStartStop() {
217} 218}
218 219
219void DisassemblerWidget::OnDebugModeEntered() { 220void DisassemblerWidget::OnDebugModeEntered() {
220 ARMword next_instr = Core::g_app_core->GetPC(); 221 u32 next_instr = Core::g_app_core->GetPC();
221 222
222 if (model->GetBreakPoints().IsAddressBreakPoint(next_instr)) 223 if (model->GetBreakPoints().IsAddressBreakPoint(next_instr))
223 emu_thread->SetRunning(false); 224 emu_thread->SetRunning(false);
diff --git a/src/citra_qt/debugger/graphics_breakpoint_observer.h b/src/citra_qt/debugger/graphics_breakpoint_observer.h
index f0d3361f8..02a0f4f4f 100644
--- a/src/citra_qt/debugger/graphics_breakpoint_observer.h
+++ b/src/citra_qt/debugger/graphics_breakpoint_observer.h
@@ -13,7 +13,7 @@
13 * This is because the Pica breakpoint callbacks are called from a non-GUI thread, while 13 * This is because the Pica breakpoint callbacks are called from a non-GUI thread, while
14 * the widget usually wants to perform reactions in the GUI thread. 14 * the widget usually wants to perform reactions in the GUI thread.
15 */ 15 */
16class BreakPointObserverDock : public QDockWidget, private Pica::DebugContext::BreakPointObserver { 16class BreakPointObserverDock : public QDockWidget, protected Pica::DebugContext::BreakPointObserver {
17 Q_OBJECT 17 Q_OBJECT
18 18
19public: 19public:
diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp
index 1da64f616..5202c168c 100644
--- a/src/citra_qt/debugger/graphics_breakpoints.cpp
+++ b/src/citra_qt/debugger/graphics_breakpoints.cpp
@@ -4,7 +4,7 @@
4 4
5#include <QMetaType> 5#include <QMetaType>
6#include <QPushButton> 6#include <QPushButton>
7#include <QTreeWidget> 7#include <QTreeView>
8#include <QVBoxLayout> 8#include <QVBoxLayout>
9#include <QLabel> 9#include <QLabel>
10 10
@@ -23,7 +23,7 @@ BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_conte
23 23
24int BreakPointModel::columnCount(const QModelIndex& parent) const 24int BreakPointModel::columnCount(const QModelIndex& parent) const
25{ 25{
26 return 2; 26 return 1;
27} 27}
28 28
29int BreakPointModel::rowCount(const QModelIndex& parent) const 29int BreakPointModel::rowCount(const QModelIndex& parent) const
@@ -38,29 +38,29 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const
38 switch (role) { 38 switch (role) {
39 case Qt::DisplayRole: 39 case Qt::DisplayRole:
40 { 40 {
41 switch (index.column()) { 41 if (index.column() == 0) {
42 case 0:
43 {
44 static const std::map<Pica::DebugContext::Event, QString> map = { 42 static const std::map<Pica::DebugContext::Event, QString> map = {
45 { Pica::DebugContext::Event::CommandLoaded, tr("Pica command loaded") }, 43 { Pica::DebugContext::Event::PicaCommandLoaded, tr("Pica command loaded") },
46 { Pica::DebugContext::Event::CommandProcessed, tr("Pica command processed") }, 44 { Pica::DebugContext::Event::PicaCommandProcessed, tr("Pica command processed") },
47 { Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch") }, 45 { Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch") },
48 { Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch") }, 46 { Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch") },
49 { Pica::DebugContext::Event::VertexLoaded, tr("Vertex loaded") } 47 { Pica::DebugContext::Event::VertexLoaded, tr("Vertex loaded") },
48 { Pica::DebugContext::Event::IncomingDisplayTransfer, tr("Incoming display transfer") },
49 { Pica::DebugContext::Event::GSPCommandProcessed, tr("GSP command processed") },
50 { Pica::DebugContext::Event::BufferSwapped, tr("Buffers swapped") }
50 }; 51 };
51 52
52 DEBUG_ASSERT(map.size() == static_cast<size_t>(Pica::DebugContext::Event::NumEvents)); 53 DEBUG_ASSERT(map.size() == static_cast<size_t>(Pica::DebugContext::Event::NumEvents));
53
54 return (map.find(event) != map.end()) ? map.at(event) : QString(); 54 return (map.find(event) != map.end()) ? map.at(event) : QString();
55 } 55 }
56 56
57 case 1: 57 break;
58 return data(index, Role_IsEnabled).toBool() ? tr("Enabled") : tr("Disabled"); 58 }
59
60 default:
61 break;
62 }
63 59
60 case Qt::CheckStateRole:
61 {
62 if (index.column() == 0)
63 return data(index, Role_IsEnabled).toBool() ? Qt::Checked : Qt::Unchecked;
64 break; 64 break;
65 } 65 }
66 66
@@ -84,37 +84,34 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const
84 return QVariant(); 84 return QVariant();
85} 85}
86 86
87QVariant BreakPointModel::headerData(int section, Qt::Orientation orientation, int role) const 87Qt::ItemFlags BreakPointModel::flags(const QModelIndex &index) const
88{ 88{
89 switch(role) { 89 if (!index.isValid())
90 case Qt::DisplayRole: 90 return 0;
91 {
92 if (section == 0) {
93 return tr("Event");
94 } else if (section == 1) {
95 return tr("Status");
96 }
97
98 break;
99 }
100 }
101 91
102 return QVariant(); 92 Qt::ItemFlags flags = Qt::ItemIsEnabled;
93 if (index.column() == 0)
94 flags |= Qt::ItemIsUserCheckable;
95 return flags;
103} 96}
104 97
98
105bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, int role) 99bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, int role)
106{ 100{
107 const auto event = static_cast<Pica::DebugContext::Event>(index.row()); 101 const auto event = static_cast<Pica::DebugContext::Event>(index.row());
108 102
109 switch (role) { 103 switch (role) {
110 case Role_IsEnabled: 104 case Qt::CheckStateRole:
111 { 105 {
106 if (index.column() != 0)
107 return false;
108
112 auto context = context_weak.lock(); 109 auto context = context_weak.lock();
113 if (!context) 110 if (!context)
114 return false; 111 return false;
115 112
116 context->breakpoints[event].enabled = value.toBool(); 113 context->breakpoints[event].enabled = value == Qt::Checked;
117 QModelIndex changed_index = createIndex(index.row(), 1); 114 QModelIndex changed_index = createIndex(index.row(), 0);
118 emit dataChanged(changed_index, changed_index); 115 emit dataChanged(changed_index, changed_index);
119 return true; 116 return true;
120 } 117 }
@@ -133,7 +130,7 @@ void BreakPointModel::OnBreakPointHit(Pica::DebugContext::Event event)
133 active_breakpoint = context->active_breakpoint; 130 active_breakpoint = context->active_breakpoint;
134 at_breakpoint = context->at_breakpoint; 131 at_breakpoint = context->at_breakpoint;
135 emit dataChanged(createIndex(static_cast<int>(event), 0), 132 emit dataChanged(createIndex(static_cast<int>(event), 0),
136 createIndex(static_cast<int>(event), 1)); 133 createIndex(static_cast<int>(event), 0));
137} 134}
138 135
139void BreakPointModel::OnResumed() 136void BreakPointModel::OnResumed()
@@ -144,7 +141,7 @@ void BreakPointModel::OnResumed()
144 141
145 at_breakpoint = context->at_breakpoint; 142 at_breakpoint = context->at_breakpoint;
146 emit dataChanged(createIndex(static_cast<int>(active_breakpoint), 0), 143 emit dataChanged(createIndex(static_cast<int>(active_breakpoint), 0),
147 createIndex(static_cast<int>(active_breakpoint), 1)); 144 createIndex(static_cast<int>(active_breakpoint), 0));
148 active_breakpoint = context->active_breakpoint; 145 active_breakpoint = context->active_breakpoint;
149} 146}
150 147
@@ -162,13 +159,15 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::Debug
162 159
163 breakpoint_model = new BreakPointModel(debug_context, this); 160 breakpoint_model = new BreakPointModel(debug_context, this);
164 breakpoint_list = new QTreeView; 161 breakpoint_list = new QTreeView;
162 breakpoint_list->setRootIsDecorated(false);
163 breakpoint_list->setHeaderHidden(true);
165 breakpoint_list->setModel(breakpoint_model); 164 breakpoint_list->setModel(breakpoint_model);
166 165
167 toggle_breakpoint_button = new QPushButton(tr("Enable"));
168 toggle_breakpoint_button->setEnabled(false);
169
170 qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event"); 166 qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event");
171 167
168 connect(breakpoint_list, SIGNAL(doubleClicked(const QModelIndex&)),
169 this, SLOT(OnItemDoubleClicked(const QModelIndex&)));
170
172 connect(resume_button, SIGNAL(clicked()), this, SLOT(OnResumeRequested())); 171 connect(resume_button, SIGNAL(clicked()), this, SLOT(OnResumeRequested()));
173 172
174 connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)), 173 connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)),
@@ -184,11 +183,6 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::Debug
184 connect(this, SIGNAL(BreakPointsChanged(const QModelIndex&,const QModelIndex&)), 183 connect(this, SIGNAL(BreakPointsChanged(const QModelIndex&,const QModelIndex&)),
185 breakpoint_model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&))); 184 breakpoint_model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)));
186 185
187 connect(breakpoint_list->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
188 this, SLOT(OnBreakpointSelectionChanged(QModelIndex)));
189
190 connect(toggle_breakpoint_button, SIGNAL(clicked()), this, SLOT(OnToggleBreakpointEnabled()));
191
192 QWidget* main_widget = new QWidget; 186 QWidget* main_widget = new QWidget;
193 auto main_layout = new QVBoxLayout; 187 auto main_layout = new QVBoxLayout;
194 { 188 {
@@ -198,7 +192,6 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::Debug
198 main_layout->addLayout(sub_layout); 192 main_layout->addLayout(sub_layout);
199 } 193 }
200 main_layout->addWidget(breakpoint_list); 194 main_layout->addWidget(breakpoint_list);
201 main_layout->addWidget(toggle_breakpoint_button);
202 main_widget->setLayout(main_layout); 195 main_widget->setLayout(main_layout);
203 196
204 setWidget(main_widget); 197 setWidget(main_widget);
@@ -234,32 +227,15 @@ void GraphicsBreakPointsWidget::OnResumeRequested()
234 context->Resume(); 227 context->Resume();
235} 228}
236 229
237void GraphicsBreakPointsWidget::OnBreakpointSelectionChanged(const QModelIndex& index) 230void GraphicsBreakPointsWidget::OnItemDoubleClicked(const QModelIndex& index)
238{ 231{
239 if (!index.isValid()) { 232 if (!index.isValid())
240 toggle_breakpoint_button->setEnabled(false);
241 return; 233 return;
242 }
243 234
244 toggle_breakpoint_button->setEnabled(true); 235 QModelIndex check_index = breakpoint_list->model()->index(index.row(), 0);
245 UpdateToggleBreakpointButton(index); 236 QVariant enabled = breakpoint_list->model()->data(check_index, Qt::CheckStateRole);
246} 237 QVariant new_state = Qt::Unchecked;
247 238 if (enabled == Qt::Unchecked)
248void GraphicsBreakPointsWidget::OnToggleBreakpointEnabled() 239 new_state = Qt::Checked;
249{ 240 breakpoint_list->model()->setData(check_index, new_state, Qt::CheckStateRole);
250 QModelIndex index = breakpoint_list->selectionModel()->currentIndex();
251 bool new_state = !(breakpoint_model->data(index, BreakPointModel::Role_IsEnabled).toBool());
252
253 breakpoint_model->setData(index, new_state,
254 BreakPointModel::Role_IsEnabled);
255 UpdateToggleBreakpointButton(index);
256}
257
258void GraphicsBreakPointsWidget::UpdateToggleBreakpointButton(const QModelIndex& index)
259{
260 if (true == breakpoint_model->data(index, BreakPointModel::Role_IsEnabled).toBool()) {
261 toggle_breakpoint_button->setText(tr("Disable"));
262 } else {
263 toggle_breakpoint_button->setText(tr("Enable"));
264 }
265} 241}
diff --git a/src/citra_qt/debugger/graphics_breakpoints.h b/src/citra_qt/debugger/graphics_breakpoints.h
index 5b9ba324e..d900729da 100644
--- a/src/citra_qt/debugger/graphics_breakpoints.h
+++ b/src/citra_qt/debugger/graphics_breakpoints.h
@@ -31,10 +31,9 @@ public:
31 31
32public slots: 32public slots:
33 void OnBreakPointHit(Pica::DebugContext::Event event, void* data); 33 void OnBreakPointHit(Pica::DebugContext::Event event, void* data);
34 void OnItemDoubleClicked(const QModelIndex&);
34 void OnResumeRequested(); 35 void OnResumeRequested();
35 void OnResumed(); 36 void OnResumed();
36 void OnBreakpointSelectionChanged(const QModelIndex&);
37 void OnToggleBreakpointEnabled();
38 37
39signals: 38signals:
40 void Resumed(); 39 void Resumed();
@@ -42,11 +41,8 @@ signals:
42 void BreakPointsChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); 41 void BreakPointsChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
43 42
44private: 43private:
45 void UpdateToggleBreakpointButton(const QModelIndex& index);
46
47 QLabel* status_text; 44 QLabel* status_text;
48 QPushButton* resume_button; 45 QPushButton* resume_button;
49 QPushButton* toggle_breakpoint_button;
50 46
51 BreakPointModel* breakpoint_model; 47 BreakPointModel* breakpoint_model;
52 QTreeView* breakpoint_list; 48 QTreeView* breakpoint_list;
diff --git a/src/citra_qt/debugger/graphics_breakpoints_p.h b/src/citra_qt/debugger/graphics_breakpoints_p.h
index 34e72e859..00d8d5101 100644
--- a/src/citra_qt/debugger/graphics_breakpoints_p.h
+++ b/src/citra_qt/debugger/graphics_breakpoints_p.h
@@ -23,7 +23,7 @@ public:
23 int columnCount(const QModelIndex& parent = QModelIndex()) const override; 23 int columnCount(const QModelIndex& parent = QModelIndex()) const override;
24 int rowCount(const QModelIndex& parent = QModelIndex()) const override; 24 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
25 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; 25 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
26 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; 26 Qt::ItemFlags flags(const QModelIndex &index) const;
27 27
28 bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; 28 bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
29 29
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp
index cabf5fe07..7ac3ea542 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.cpp
+++ b/src/citra_qt/debugger/graphics_cmdlists.cpp
@@ -2,12 +2,15 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <QApplication>
6#include <QClipboard>
5#include <QLabel> 7#include <QLabel>
6#include <QListView> 8#include <QListView>
7#include <QMainWindow> 9#include <QMainWindow>
8#include <QPushButton> 10#include <QPushButton>
9#include <QVBoxLayout> 11#include <QVBoxLayout>
10#include <QTreeView> 12#include <QTreeView>
13#include <QHeaderView>
11#include <QSpinBox> 14#include <QSpinBox>
12#include <QComboBox> 15#include <QComboBox>
13 16
@@ -74,7 +77,7 @@ TextureInfoDockWidget::TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo
74 format_choice->addItem(tr("I8")); 77 format_choice->addItem(tr("I8"));
75 format_choice->addItem(tr("A8")); 78 format_choice->addItem(tr("A8"));
76 format_choice->addItem(tr("IA4")); 79 format_choice->addItem(tr("IA4"));
77 format_choice->addItem(tr("UNK10")); 80 format_choice->addItem(tr("I4"));
78 format_choice->addItem(tr("A4")); 81 format_choice->addItem(tr("A4"));
79 format_choice->addItem(tr("ETC1")); 82 format_choice->addItem(tr("ETC1"));
80 format_choice->addItem(tr("ETC1A4")); 83 format_choice->addItem(tr("ETC1A4"));
@@ -168,11 +171,11 @@ GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(p
168} 171}
169 172
170int GPUCommandListModel::rowCount(const QModelIndex& parent) const { 173int GPUCommandListModel::rowCount(const QModelIndex& parent) const {
171 return pica_trace.writes.size(); 174 return static_cast<int>(pica_trace.writes.size());
172} 175}
173 176
174int GPUCommandListModel::columnCount(const QModelIndex& parent) const { 177int GPUCommandListModel::columnCount(const QModelIndex& parent) const {
175 return 2; 178 return 3;
176} 179}
177 180
178QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const { 181QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const {
@@ -185,14 +188,13 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const {
185 188
186 if (role == Qt::DisplayRole) { 189 if (role == Qt::DisplayRole) {
187 QString content; 190 QString content;
188 if (index.column() == 0) { 191 switch ( index.column() ) {
189 QString content = QString::fromLatin1(Pica::Regs::GetCommandName(cmd.cmd_id).c_str()); 192 case 0:
190 content.append(" "); 193 return QString::fromLatin1(Pica::Regs::GetCommandName(cmd.cmd_id).c_str());
191 return content; 194 case 1:
192 } else if (index.column() == 1) { 195 return QString("%1").arg(cmd.cmd_id, 3, 16, QLatin1Char('0'));
193 QString content = QString("%1 ").arg(cmd.hex, 8, 16, QLatin1Char('0')); 196 case 2:
194 content.append(QString("%1 ").arg(val, 8, 16, QLatin1Char('0'))); 197 return QString("%1").arg(val, 8, 16, QLatin1Char('0'));
195 return content;
196 } 198 }
197 } else if (role == CommandIdRole) { 199 } else if (role == CommandIdRole) {
198 return QVariant::fromValue<int>(cmd.cmd_id.Value()); 200 return QVariant::fromValue<int>(cmd.cmd_id.Value());
@@ -205,10 +207,13 @@ QVariant GPUCommandListModel::headerData(int section, Qt::Orientation orientatio
205 switch(role) { 207 switch(role) {
206 case Qt::DisplayRole: 208 case Qt::DisplayRole:
207 { 209 {
208 if (section == 0) { 210 switch (section) {
211 case 0:
209 return tr("Command Name"); 212 return tr("Command Name");
210 } else if (section == 1) { 213 case 1:
211 return tr("Data"); 214 return tr("Register");
215 case 2:
216 return tr("New Value");
212 } 217 }
213 218
214 break; 219 break;
@@ -297,6 +302,13 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi
297 list_widget->setModel(model); 302 list_widget->setModel(model);
298 list_widget->setFont(QFont("monospace")); 303 list_widget->setFont(QFont("monospace"));
299 list_widget->setRootIsDecorated(false); 304 list_widget->setRootIsDecorated(false);
305 list_widget->setUniformRowHeights(true);
306
307#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
308 list_widget->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
309#else
310 list_widget->header()->setResizeMode(QHeaderView::ResizeToContents);
311#endif
300 312
301 connect(list_widget->selectionModel(), SIGNAL(currentChanged(const QModelIndex&,const QModelIndex&)), 313 connect(list_widget->selectionModel(), SIGNAL(currentChanged(const QModelIndex&,const QModelIndex&)),
302 this, SLOT(SetCommandInfo(const QModelIndex&))); 314 this, SLOT(SetCommandInfo(const QModelIndex&)));
@@ -304,16 +316,24 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi
304 this, SLOT(OnCommandDoubleClicked(const QModelIndex&))); 316 this, SLOT(OnCommandDoubleClicked(const QModelIndex&)));
305 317
306 toggle_tracing = new QPushButton(tr("Start Tracing")); 318 toggle_tracing = new QPushButton(tr("Start Tracing"));
319 QPushButton* copy_all = new QPushButton(tr("Copy All"));
307 320
308 connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing())); 321 connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing()));
309 connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)), 322 connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)),
310 model, SLOT(OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&))); 323 model, SLOT(OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&)));
311 324
325 connect(copy_all, SIGNAL(clicked()), this, SLOT(CopyAllToClipboard()));
326
312 command_info_widget = new QWidget; 327 command_info_widget = new QWidget;
313 328
314 QVBoxLayout* main_layout = new QVBoxLayout; 329 QVBoxLayout* main_layout = new QVBoxLayout;
315 main_layout->addWidget(list_widget); 330 main_layout->addWidget(list_widget);
316 main_layout->addWidget(toggle_tracing); 331 {
332 QHBoxLayout* sub_layout = new QHBoxLayout;
333 sub_layout->addWidget(toggle_tracing);
334 sub_layout->addWidget(copy_all);
335 main_layout->addLayout(sub_layout);
336 }
317 main_layout->addWidget(command_info_widget); 337 main_layout->addWidget(command_info_widget);
318 main_widget->setLayout(main_layout); 338 main_widget->setLayout(main_layout);
319 339
@@ -330,3 +350,21 @@ void GPUCommandListWidget::OnToggleTracing() {
330 toggle_tracing->setText(tr("Start Tracing")); 350 toggle_tracing->setText(tr("Start Tracing"));
331 } 351 }
332} 352}
353
354void GPUCommandListWidget::CopyAllToClipboard() {
355 QClipboard* clipboard = QApplication::clipboard();
356 QString text;
357
358 QAbstractItemModel* model = static_cast<QAbstractListModel*>(list_widget->model());
359
360 for (int row = 0; row < model->rowCount({}); ++row) {
361 for (int col = 0; col < model->columnCount({}); ++col) {
362 QModelIndex index = model->index(row, col);
363 text += model->data(index).value<QString>();
364 text += '\t';
365 }
366 text += '\n';
367 }
368
369 clipboard->setText(text);
370}
diff --git a/src/citra_qt/debugger/graphics_cmdlists.h b/src/citra_qt/debugger/graphics_cmdlists.h
index a465d044c..4859b6ec8 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.h
+++ b/src/citra_qt/debugger/graphics_cmdlists.h
@@ -49,6 +49,8 @@ public slots:
49 49
50 void SetCommandInfo(const QModelIndex&); 50 void SetCommandInfo(const QModelIndex&);
51 51
52 void CopyAllToClipboard();
53
52signals: 54signals:
53 void TracingFinished(const Pica::DebugUtils::PicaTrace&); 55 void TracingFinished(const Pica::DebugUtils::PicaTrace&);
54 56
diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp
index 6bbe7572c..39eefbf75 100644
--- a/src/citra_qt/debugger/graphics_framebuffer.cpp
+++ b/src/citra_qt/debugger/graphics_framebuffer.cpp
@@ -55,7 +55,9 @@ GraphicsFramebufferWidget::GraphicsFramebufferWidget(std::shared_ptr<Pica::Debug
55 framebuffer_format_control->addItem(tr("RGBA4")); 55 framebuffer_format_control->addItem(tr("RGBA4"));
56 framebuffer_format_control->addItem(tr("D16")); 56 framebuffer_format_control->addItem(tr("D16"));
57 framebuffer_format_control->addItem(tr("D24")); 57 framebuffer_format_control->addItem(tr("D24"));
58 framebuffer_format_control->addItem(tr("D24S8")); 58 framebuffer_format_control->addItem(tr("D24X8"));
59 framebuffer_format_control->addItem(tr("X24S8"));
60 framebuffer_format_control->addItem(tr("(unknown)"));
59 61
60 // TODO: This QLabel should shrink the image to the available space rather than just expanding... 62 // TODO: This QLabel should shrink the image to the available space rather than just expanding...
61 framebuffer_picture_label = new QLabel; 63 framebuffer_picture_label = new QLabel;
@@ -184,8 +186,32 @@ void GraphicsFramebufferWidget::OnUpdate()
184 framebuffer_address = framebuffer.GetColorBufferPhysicalAddress(); 186 framebuffer_address = framebuffer.GetColorBufferPhysicalAddress();
185 framebuffer_width = framebuffer.GetWidth(); 187 framebuffer_width = framebuffer.GetWidth();
186 framebuffer_height = framebuffer.GetHeight(); 188 framebuffer_height = framebuffer.GetHeight();
187 // TODO: It's unknown how this format is actually specified 189
188 framebuffer_format = Format::RGBA8; 190 switch (framebuffer.color_format) {
191 case Pica::Regs::ColorFormat::RGBA8:
192 framebuffer_format = Format::RGBA8;
193 break;
194
195 case Pica::Regs::ColorFormat::RGB8:
196 framebuffer_format = Format::RGB8;
197 break;
198
199 case Pica::Regs::ColorFormat::RGB5A1:
200 framebuffer_format = Format::RGB5A1;
201 break;
202
203 case Pica::Regs::ColorFormat::RGB565:
204 framebuffer_format = Format::RGB565;
205 break;
206
207 case Pica::Regs::ColorFormat::RGBA4:
208 framebuffer_format = Format::RGBA4;
209 break;
210
211 default:
212 framebuffer_format = Format::Unknown;
213 break;
214 }
189 215
190 break; 216 break;
191 } 217 }
@@ -197,7 +223,24 @@ void GraphicsFramebufferWidget::OnUpdate()
197 framebuffer_address = framebuffer.GetDepthBufferPhysicalAddress(); 223 framebuffer_address = framebuffer.GetDepthBufferPhysicalAddress();
198 framebuffer_width = framebuffer.GetWidth(); 224 framebuffer_width = framebuffer.GetWidth();
199 framebuffer_height = framebuffer.GetHeight(); 225 framebuffer_height = framebuffer.GetHeight();
200 framebuffer_format = Format::D16; 226
227 switch (framebuffer.depth_format) {
228 case Pica::Regs::DepthFormat::D16:
229 framebuffer_format = Format::D16;
230 break;
231
232 case Pica::Regs::DepthFormat::D24:
233 framebuffer_format = Format::D24;
234 break;
235
236 case Pica::Regs::DepthFormat::D24S8:
237 framebuffer_format = Format::D24X8;
238 break;
239
240 default:
241 framebuffer_format = Format::Unknown;
242 break;
243 }
201 244
202 break; 245 break;
203 } 246 }
@@ -258,7 +301,7 @@ void GraphicsFramebufferWidget::OnUpdate()
258 color.b() = (data >> 16) & 0xFF; 301 color.b() = (data >> 16) & 0xFF;
259 break; 302 break;
260 } 303 }
261 case Format::D24S8: 304 case Format::D24X8:
262 { 305 {
263 Math::Vec2<u32> data = Color::DecodeD24S8(pixel); 306 Math::Vec2<u32> data = Color::DecodeD24S8(pixel);
264 color.r() = data.x & 0xFF; 307 color.r() = data.x & 0xFF;
@@ -266,6 +309,12 @@ void GraphicsFramebufferWidget::OnUpdate()
266 color.b() = (data.x >> 16) & 0xFF; 309 color.b() = (data.x >> 16) & 0xFF;
267 break; 310 break;
268 } 311 }
312 case Format::X24S8:
313 {
314 Math::Vec2<u32> data = Color::DecodeD24S8(pixel);
315 color.r() = color.g() = color.b() = data.y;
316 break;
317 }
269 default: 318 default:
270 qDebug() << "Unknown fb color format " << static_cast<int>(framebuffer_format); 319 qDebug() << "Unknown fb color format " << static_cast<int>(framebuffer_format);
271 break; 320 break;
@@ -286,7 +335,8 @@ void GraphicsFramebufferWidget::OnUpdate()
286u32 GraphicsFramebufferWidget::BytesPerPixel(GraphicsFramebufferWidget::Format format) { 335u32 GraphicsFramebufferWidget::BytesPerPixel(GraphicsFramebufferWidget::Format format) {
287 switch (format) { 336 switch (format) {
288 case Format::RGBA8: 337 case Format::RGBA8:
289 case Format::D24S8: 338 case Format::D24X8:
339 case Format::X24S8:
290 return 4; 340 return 4;
291 case Format::RGB8: 341 case Format::RGB8:
292 case Format::D24: 342 case Format::D24:
diff --git a/src/citra_qt/debugger/graphics_framebuffer.h b/src/citra_qt/debugger/graphics_framebuffer.h
index 4cb396ffe..e9eae679f 100644
--- a/src/citra_qt/debugger/graphics_framebuffer.h
+++ b/src/citra_qt/debugger/graphics_framebuffer.h
@@ -35,7 +35,9 @@ class GraphicsFramebufferWidget : public BreakPointObserverDock {
35 RGBA4 = 4, 35 RGBA4 = 4,
36 D16 = 5, 36 D16 = 5,
37 D24 = 6, 37 D24 = 6,
38 D24S8 = 7 38 D24X8 = 7,
39 X24S8 = 8,
40 Unknown = 9
39 }; 41 };
40 42
41 static u32 BytesPerPixel(Format format); 43 static u32 BytesPerPixel(Format format);
diff --git a/src/citra_qt/debugger/graphics_tracing.cpp b/src/citra_qt/debugger/graphics_tracing.cpp
new file mode 100644
index 000000000..3f20f149d
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_tracing.cpp
@@ -0,0 +1,170 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <memory>
6
7#include <QBoxLayout>
8#include <QComboBox>
9#include <QFileDialog>
10#include <QLabel>
11#include <QMessageBox>
12#include <QPushButton>
13#include <QSpinBox>
14
15#include <boost/range/algorithm/copy.hpp>
16
17#include "core/hw/gpu.h"
18#include "core/hw/lcd.h"
19
20#include "video_core/pica.h"
21
22#include "nihstro/float24.h"
23
24#include "graphics_tracing.h"
25
26GraphicsTracingWidget::GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context,
27 QWidget* parent)
28 : BreakPointObserverDock(debug_context, tr("CiTrace Recorder"), parent) {
29
30 setObjectName("CiTracing");
31
32 QPushButton* start_recording = new QPushButton(tr("Start Recording"));
33 QPushButton* stop_recording = new QPushButton(QIcon::fromTheme("document-save"), tr("Stop and Save"));
34 QPushButton* abort_recording = new QPushButton(tr("Abort Recording"));
35
36 connect(this, SIGNAL(SetStartTracingButtonEnabled(bool)), start_recording, SLOT(setVisible(bool)));
37 connect(this, SIGNAL(SetStopTracingButtonEnabled(bool)), stop_recording, SLOT(setVisible(bool)));
38 connect(this, SIGNAL(SetAbortTracingButtonEnabled(bool)), abort_recording, SLOT(setVisible(bool)));
39 connect(start_recording, SIGNAL(clicked()), this, SLOT(StartRecording()));
40 connect(stop_recording, SIGNAL(clicked()), this, SLOT(StopRecording()));
41 connect(abort_recording, SIGNAL(clicked()), this, SLOT(AbortRecording()));
42
43 stop_recording->setVisible(false);
44 abort_recording->setVisible(false);
45
46 auto main_widget = new QWidget;
47 auto main_layout = new QVBoxLayout;
48 {
49 auto sub_layout = new QHBoxLayout;
50 sub_layout->addWidget(start_recording);
51 sub_layout->addWidget(stop_recording);
52 sub_layout->addWidget(abort_recording);
53 main_layout->addLayout(sub_layout);
54 }
55 main_widget->setLayout(main_layout);
56 setWidget(main_widget);
57}
58
59void GraphicsTracingWidget::StartRecording() {
60 auto context = context_weak.lock();
61 if (!context)
62 return;
63
64 auto shader_binary = Pica::g_state.vs.program_code;
65 auto swizzle_data = Pica::g_state.vs.swizzle_data;
66
67 // Encode floating point numbers to 24-bit values
68 // TODO: Drop this explicit conversion once we store float24 values bit-correctly internally.
69 std::array<uint32_t, 4 * 16> default_attributes;
70 for (unsigned i = 0; i < 16; ++i) {
71 for (unsigned comp = 0; comp < 3; ++comp) {
72 default_attributes[4 * i + comp] = nihstro::to_float24(Pica::g_state.vs.default_attributes[i][comp].ToFloat32());
73 }
74 }
75
76 std::array<uint32_t, 4 * 96> vs_float_uniforms;
77 for (unsigned i = 0; i < 96; ++i)
78 for (unsigned comp = 0; comp < 3; ++comp)
79 vs_float_uniforms[4 * i + comp] = nihstro::to_float24(Pica::g_state.vs.uniforms.f[i][comp].ToFloat32());
80
81 CiTrace::Recorder::InitialState state;
82 std::copy_n((u32*)&GPU::g_regs, sizeof(GPU::g_regs) / sizeof(u32), std::back_inserter(state.gpu_registers));
83 std::copy_n((u32*)&LCD::g_regs, sizeof(LCD::g_regs) / sizeof(u32), std::back_inserter(state.lcd_registers));
84 std::copy_n((u32*)&Pica::g_state.regs, sizeof(Pica::g_state.regs) / sizeof(u32), std::back_inserter(state.pica_registers));
85 boost::copy(default_attributes, std::back_inserter(state.default_attributes));
86 boost::copy(shader_binary, std::back_inserter(state.vs_program_binary));
87 boost::copy(swizzle_data, std::back_inserter(state.vs_swizzle_data));
88 boost::copy(vs_float_uniforms, std::back_inserter(state.vs_float_uniforms));
89 //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_program_binary));
90 //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_swizzle_data));
91 //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_float_uniforms));
92
93 auto recorder = new CiTrace::Recorder(state);
94 context->recorder = std::shared_ptr<CiTrace::Recorder>(recorder);
95
96 emit SetStartTracingButtonEnabled(false);
97 emit SetStopTracingButtonEnabled(true);
98 emit SetAbortTracingButtonEnabled(true);
99}
100
101void GraphicsTracingWidget::StopRecording() {
102 auto context = context_weak.lock();
103 if (!context)
104 return;
105
106 QString filename = QFileDialog::getSaveFileName(this, tr("Save CiTrace"), "citrace.ctf",
107 tr("CiTrace File (*.ctf)"));
108
109 if (filename.isEmpty()) {
110 // If the user canceled the dialog, keep recording
111 return;
112 }
113
114 context->recorder->Finish(filename.toStdString());
115 context->recorder = nullptr;
116
117 emit SetStopTracingButtonEnabled(false);
118 emit SetAbortTracingButtonEnabled(false);
119 emit SetStartTracingButtonEnabled(true);
120}
121
122void GraphicsTracingWidget::AbortRecording() {
123 auto context = context_weak.lock();
124 if (!context)
125 return;
126
127 context->recorder = nullptr;
128
129 emit SetStopTracingButtonEnabled(false);
130 emit SetAbortTracingButtonEnabled(false);
131 emit SetStartTracingButtonEnabled(true);
132}
133
134void GraphicsTracingWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) {
135 widget()->setEnabled(true);
136}
137
138void GraphicsTracingWidget::OnResumed() {
139 widget()->setEnabled(false);
140}
141
142void GraphicsTracingWidget::OnEmulationStarting(EmuThread* emu_thread) {
143 // Disable tracing starting/stopping until a GPU breakpoint is reached
144 widget()->setEnabled(false);
145}
146
147void GraphicsTracingWidget::OnEmulationStopping() {
148 // TODO: Is it safe to access the context here?
149
150 auto context = context_weak.lock();
151 if (!context)
152 return;
153
154
155 if (context->recorder) {
156 auto reply = QMessageBox::question(this, tr("CiTracing still active"),
157 tr("A CiTrace is still being recorded. Do you want to save it? If not, all recorded data will be discarded."),
158 QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
159
160 if (reply == QMessageBox::Yes) {
161 StopRecording();
162 } else {
163 AbortRecording();
164 }
165 }
166
167 // If the widget was disabled before, enable it now to allow starting
168 // tracing before starting the next emulation session
169 widget()->setEnabled(true);
170}
diff --git a/src/citra_qt/debugger/graphics_tracing.h b/src/citra_qt/debugger/graphics_tracing.h
new file mode 100644
index 000000000..2a0e4819b
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_tracing.h
@@ -0,0 +1,32 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "graphics_breakpoint_observer.h"
8
9class EmuThread;
10
11class GraphicsTracingWidget : public BreakPointObserverDock {
12 Q_OBJECT
13
14public:
15 GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent = nullptr);
16
17private slots:
18 void StartRecording();
19 void StopRecording();
20 void AbortRecording();
21
22 void OnBreakPointHit(Pica::DebugContext::Event event, void* data) override;
23 void OnResumed() override;
24
25 void OnEmulationStarting(EmuThread* emu_thread);
26 void OnEmulationStopping();
27
28signals:
29 void SetStartTracingButtonEnabled(bool enable);
30 void SetStopTracingButtonEnabled(bool enable);
31 void SetAbortTracingButtonEnabled(bool enable);
32};
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp
index 14d3f8f39..f42a2f4ce 100644
--- a/src/citra_qt/debugger/graphics_vertex_shader.cpp
+++ b/src/citra_qt/debugger/graphics_vertex_shader.cpp
@@ -34,7 +34,7 @@ int GraphicsVertexShaderModel::columnCount(const QModelIndex& parent) const {
34} 34}
35 35
36int GraphicsVertexShaderModel::rowCount(const QModelIndex& parent) const { 36int GraphicsVertexShaderModel::rowCount(const QModelIndex& parent) const {
37 return info.code.size(); 37 return static_cast<int>(info.code.size());
38} 38}
39 39
40QVariant GraphicsVertexShaderModel::headerData(int section, Qt::Orientation orientation, int role) const { 40QVariant GraphicsVertexShaderModel::headerData(int section, Qt::Orientation orientation, int role) const {
@@ -259,7 +259,7 @@ void GraphicsVertexShaderModel::OnUpdate()
259 for (auto pattern : Pica::g_state.vs.swizzle_data) 259 for (auto pattern : Pica::g_state.vs.swizzle_data)
260 info.swizzle_info.push_back({pattern}); 260 info.swizzle_info.push_back({pattern});
261 261
262 info.labels.insert({ Pica::g_state.regs.vs_main_offset, "main" }); 262 info.labels.insert({ Pica::g_state.regs.vs.main_offset, "main" });
263 263
264 endResetModel(); 264 endResetModel();
265} 265}
diff --git a/src/citra_qt/debugger/profiler.cpp b/src/citra_qt/debugger/profiler.cpp
index 2ac1748b7..89b28c2f4 100644
--- a/src/citra_qt/debugger/profiler.cpp
+++ b/src/citra_qt/debugger/profiler.cpp
@@ -74,7 +74,7 @@ int ProfilerModel::rowCount(const QModelIndex& parent) const
74 if (parent.isValid()) { 74 if (parent.isValid()) {
75 return 0; 75 return 0;
76 } else { 76 } else {
77 return results.time_per_category.size() + 2; 77 return static_cast<int>(results.time_per_category.size() + 2);
78 } 78 }
79} 79}
80 80
diff --git a/src/citra_qt/hotkeys.cpp b/src/citra_qt/hotkeys.cpp
index 322c25c9e..5ed6cf0b1 100644
--- a/src/citra_qt/hotkeys.cpp
+++ b/src/citra_qt/hotkeys.cpp
@@ -2,10 +2,13 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map>
6
5#include <QKeySequence> 7#include <QKeySequence>
6#include <QSettings> 8#include <QSettings>
9#include <QShortcut>
10
7#include "hotkeys.h" 11#include "hotkeys.h"
8#include <map>
9 12
10struct Hotkey 13struct Hotkey
11{ 14{
diff --git a/src/citra_qt/hotkeys.h b/src/citra_qt/hotkeys.h
index 75c7cc625..2317f8188 100644
--- a/src/citra_qt/hotkeys.h
+++ b/src/citra_qt/hotkeys.h
@@ -2,12 +2,12 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <QShortcut>
6#include <QDialog>
7#include "ui_hotkeys.h" 5#include "ui_hotkeys.h"
8 6
7class QDialog;
9class QKeySequence; 8class QKeySequence;
10class QSettings; 9class QSettings;
10class QShortcut;
11 11
12/** 12/**
13 * Register a hotkey. 13 * Register a hotkey.
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 8041816a0..34831f2ec 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -10,18 +10,16 @@
10#include "qhexedit.h" 10#include "qhexedit.h"
11#include "main.h" 11#include "main.h"
12 12
13#include "common/string_util.h"
13#include "common/logging/text_formatter.h" 14#include "common/logging/text_formatter.h"
14#include "common/logging/log.h" 15#include "common/logging/log.h"
15#include "common/logging/backend.h" 16#include "common/logging/backend.h"
16#include "common/logging/filter.h" 17#include "common/logging/filter.h"
17#include "common/make_unique.h" 18#include "common/make_unique.h"
18#include "common/platform.h" 19#include "common/platform.h"
20#include "common/scm_rev.h"
19#include "common/scope_exit.h" 21#include "common/scope_exit.h"
20 22
21#if EMU_PLATFORM == PLATFORM_LINUX
22#include <unistd.h>
23#endif
24
25#include "bootmanager.h" 23#include "bootmanager.h"
26#include "hotkeys.h" 24#include "hotkeys.h"
27 25
@@ -34,6 +32,7 @@
34#include "debugger/graphics_breakpoints.h" 32#include "debugger/graphics_breakpoints.h"
35#include "debugger/graphics_cmdlists.h" 33#include "debugger/graphics_cmdlists.h"
36#include "debugger/graphics_framebuffer.h" 34#include "debugger/graphics_framebuffer.h"
35#include "debugger/graphics_tracing.h"
37#include "debugger/graphics_vertex_shader.h" 36#include "debugger/graphics_vertex_shader.h"
38#include "debugger/profiler.h" 37#include "debugger/profiler.h"
39 38
@@ -96,6 +95,10 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
96 addDockWidget(Qt::RightDockWidgetArea, graphicsVertexShaderWidget); 95 addDockWidget(Qt::RightDockWidgetArea, graphicsVertexShaderWidget);
97 graphicsVertexShaderWidget->hide(); 96 graphicsVertexShaderWidget->hide();
98 97
98 auto graphicsTracingWidget = new GraphicsTracingWidget(Pica::g_debug_context, this);
99 addDockWidget(Qt::RightDockWidgetArea, graphicsTracingWidget);
100 graphicsTracingWidget->hide();
101
99 QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); 102 QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging"));
100 debug_menu->addAction(profilerWidget->toggleViewAction()); 103 debug_menu->addAction(profilerWidget->toggleViewAction());
101 debug_menu->addAction(disasmWidget->toggleViewAction()); 104 debug_menu->addAction(disasmWidget->toggleViewAction());
@@ -106,6 +109,7 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
106 debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction()); 109 debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction());
107 debug_menu->addAction(graphicsFramebufferWidget->toggleViewAction()); 110 debug_menu->addAction(graphicsFramebufferWidget->toggleViewAction());
108 debug_menu->addAction(graphicsVertexShaderWidget->toggleViewAction()); 111 debug_menu->addAction(graphicsVertexShaderWidget->toggleViewAction());
112 debug_menu->addAction(graphicsTracingWidget->toggleViewAction());
109 113
110 // Set default UI state 114 // Set default UI state
111 // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half 115 // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half
@@ -150,6 +154,9 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
150 connect(this, SIGNAL(EmulationStopping()), registersWidget, SLOT(OnEmulationStopping())); 154 connect(this, SIGNAL(EmulationStopping()), registersWidget, SLOT(OnEmulationStopping()));
151 connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window, SLOT(OnEmulationStarting(EmuThread*))); 155 connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window, SLOT(OnEmulationStarting(EmuThread*)));
152 connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping())); 156 connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping()));
157 connect(this, SIGNAL(EmulationStarting(EmuThread*)), graphicsTracingWidget, SLOT(OnEmulationStarting(EmuThread*)));
158 connect(this, SIGNAL(EmulationStopping()), graphicsTracingWidget, SLOT(OnEmulationStopping()));
159
153 160
154 // Setup hotkeys 161 // Setup hotkeys
155 RegisterHotkey("Main Window", "Load File", QKeySequence::Open); 162 RegisterHotkey("Main Window", "Load File", QKeySequence::Open);
@@ -256,6 +263,7 @@ void GMainWindow::ShutdownGame() {
256 263
257 // Update the GUI 264 // Update the GUI
258 ui.action_Start->setEnabled(false); 265 ui.action_Start->setEnabled(false);
266 ui.action_Start->setText(tr("Start"));
259 ui.action_Pause->setEnabled(false); 267 ui.action_Pause->setEnabled(false);
260 ui.action_Stop->setEnabled(false); 268 ui.action_Stop->setEnabled(false);
261 render_window->hide(); 269 render_window->hide();
@@ -284,6 +292,8 @@ void GMainWindow::OnStartGame()
284 emu_thread->SetRunning(true); 292 emu_thread->SetRunning(true);
285 293
286 ui.action_Start->setEnabled(false); 294 ui.action_Start->setEnabled(false);
295 ui.action_Start->setText(tr("Continue"));
296
287 ui.action_Pause->setEnabled(true); 297 ui.action_Pause->setEnabled(true);
288 ui.action_Stop->setEnabled(true); 298 ui.action_Stop->setEnabled(true);
289} 299}
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index e78f4f144..4c086cd2f 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -31,7 +31,6 @@ set(HEADERS
31 cpu_detect.h 31 cpu_detect.h
32 debug_interface.h 32 debug_interface.h
33 emu_window.h 33 emu_window.h
34 fifo_queue.h
35 file_util.h 34 file_util.h
36 key_map.h 35 key_map.h
37 linear_disk_cache.h 36 linear_disk_cache.h
@@ -53,7 +52,6 @@ set(HEADERS
53 synchronized_wrapper.h 52 synchronized_wrapper.h
54 thread.h 53 thread.h
55 thread_queue_list.h 54 thread_queue_list.h
56 thunk.h
57 timer.h 55 timer.h
58 vector_math.h 56 vector_math.h
59 ) 57 )
diff --git a/src/common/assert.h b/src/common/assert.h
index 7b7d8bf28..6849778b7 100644
--- a/src/common/assert.h
+++ b/src/common/assert.h
@@ -4,7 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstdio>
8#include <cstdlib> 7#include <cstdlib>
9 8
10#include "common/common_funcs.h" 9#include "common/common_funcs.h"
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 1f3ecf844..f64ebdaf6 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -32,6 +32,7 @@
32 32
33#pragma once 33#pragma once
34 34
35#include <cstddef>
35#include <limits> 36#include <limits>
36#include <type_traits> 37#include <type_traits>
37 38
@@ -160,7 +161,7 @@ public:
160 if (std::numeric_limits<T>::is_signed) 161 if (std::numeric_limits<T>::is_signed)
161 { 162 {
162 std::size_t shift = 8 * sizeof(T)-bits; 163 std::size_t shift = 8 * sizeof(T)-bits;
163 return (T)(((storage & GetMask()) << (shift - position)) >> shift); 164 return (T)((storage << (shift - position)) >> shift);
164 } 165 }
165 else 166 else
166 { 167 {
@@ -188,7 +189,7 @@ private:
188 189
189 __forceinline StorageType GetMask() const 190 __forceinline StorageType GetMask() const
190 { 191 {
191 return ((~(StorageTypeU)0) >> (8 * sizeof(T)-bits)) << position; 192 return (((StorageTypeU)~0) >> (8 * sizeof(T)-bits)) << position;
192 } 193 }
193 194
194 StorageType storage; 195 StorageType storage;
diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h
index dcd80525e..8be0b1109 100644
--- a/src/common/chunk_file.h
+++ b/src/common/chunk_file.h
@@ -26,16 +26,18 @@
26// - Zero backwards/forwards compatibility 26// - Zero backwards/forwards compatibility
27// - Serialization code for anything complex has to be manually written. 27// - Serialization code for anything complex has to be manually written.
28 28
29#include <map> 29#include <cstring>
30#include <vector>
31#include <deque> 30#include <deque>
32#include <string>
33#include <list> 31#include <list>
32#include <map>
34#include <set> 33#include <set>
34#include <string>
35#include <type_traits> 35#include <type_traits>
36#include <utility>
37#include <vector>
36 38
39#include "common/assert.h"
37#include "common/common_types.h" 40#include "common/common_types.h"
38#include "common/file_util.h"
39#include "common/logging/log.h" 41#include "common/logging/log.h"
40 42
41template <class T> 43template <class T>
diff --git a/src/common/color.h b/src/common/color.h
index 422fdc8af..9dafdca0c 100644
--- a/src/common/color.h
+++ b/src/common/color.h
@@ -208,7 +208,32 @@ inline void EncodeD24(u32 value, u8* bytes) {
208 * @param bytes Pointer where to store the encoded value 208 * @param bytes Pointer where to store the encoded value
209 */ 209 */
210inline void EncodeD24S8(u32 depth, u8 stencil, u8* bytes) { 210inline void EncodeD24S8(u32 depth, u8 stencil, u8* bytes) {
211 *reinterpret_cast<u32_le*>(bytes) = (stencil << 24) | depth; 211 bytes[0] = depth & 0xFF;
212 bytes[1] = (depth >> 8) & 0xFF;
213 bytes[2] = (depth >> 16) & 0xFF;
214 bytes[3] = stencil;
215}
216
217/**
218 * Encode a 24 bit depth value as D24X8 format (32 bits per pixel with 8 bits unused)
219 * @param depth 24 bit source depth value to encode
220 * @param bytes Pointer where to store the encoded value
221 * @note unused bits will not be modified
222 */
223inline void EncodeD24X8(u32 depth, u8* bytes) {
224 bytes[0] = depth & 0xFF;
225 bytes[1] = (depth >> 8) & 0xFF;
226 bytes[2] = (depth >> 16) & 0xFF;
227}
228
229/**
230 * Encode an 8 bit stencil value as X24S8 format (32 bits per pixel with 24 bits unused)
231 * @param stencil 8 bit source stencil value to encode
232 * @param bytes Pointer where to store the encoded value
233 * @note unused bits will not be modified
234 */
235inline void EncodeX24S8(u8 stencil, u8* bytes) {
236 bytes[3] = stencil;
212} 237}
213 238
214} // namespace 239} // namespace
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 91b74c6bc..59bd16dbf 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -5,15 +5,6 @@
5#pragma once 5#pragma once
6 6
7#include "common_types.h" 7#include "common_types.h"
8#include <cstdlib>
9
10
11#define b2(x) ( (x) | ( (x) >> 1) )
12#define b4(x) ( b2(x) | ( b2(x) >> 2) )
13#define b8(x) ( b4(x) | ( b4(x) >> 4) )
14#define b16(x) ( b8(x) | ( b8(x) >> 8) )
15#define b32(x) (b16(x) | (b16(x) >>16) )
16#define ROUND_UP_POW2(x) (b32(x - 1) + 1)
17 8
18#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 9#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
19 10
@@ -43,8 +34,6 @@
43 34
44#ifndef _MSC_VER 35#ifndef _MSC_VER
45 36
46#include <errno.h>
47
48#if defined(__x86_64__) || defined(_M_X64) 37#if defined(__x86_64__) || defined(_M_X64)
49#define Crash() __asm__ __volatile__("int $3") 38#define Crash() __asm__ __volatile__("int $3")
50#elif defined(_M_ARM) 39#elif defined(_M_ARM)
@@ -80,8 +69,10 @@ inline u64 _rotr64(u64 x, unsigned int shift){
80} 69}
81 70
82#else // _MSC_VER 71#else // _MSC_VER
83 // Function Cross-Compatibility 72 #if (_MSC_VER < 1900)
84 #define snprintf _snprintf 73 // Function Cross-Compatibility
74 #define snprintf _snprintf
75 #endif
85 76
86 // Locale Cross-Compatibility 77 // Locale Cross-Compatibility
87 #define locale_t _locale_t 78 #define locale_t _locale_t
diff --git a/src/common/common_types.h b/src/common/common_types.h
index f6de0adfc..fa3e0b8d6 100644
--- a/src/common/common_types.h
+++ b/src/common/common_types.h
@@ -24,9 +24,7 @@
24 24
25#pragma once 25#pragma once
26 26
27#include <cmath>
28#include <cstdint> 27#include <cstdint>
29#include <cstdlib>
30 28
31#ifdef _MSC_VER 29#ifdef _MSC_VER
32#ifndef __func__ 30#ifndef __func__
@@ -52,32 +50,6 @@ typedef double f64; ///< 64-bit floating point
52typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space. 50typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space.
53typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space. 51typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space.
54 52
55/// Union for fast 16-bit type casting
56union t16 {
57 u8 _u8[2]; ///< 8-bit unsigned char(s)
58 u16 _u16; ///< 16-bit unsigned shorts(s)
59};
60
61/// Union for fast 32-bit type casting
62union t32 {
63 f32 _f32; ///< 32-bit floating point(s)
64 u32 _u32; ///< 32-bit unsigned int(s)
65 s32 _s32; ///< 32-bit signed int(s)
66 u16 _u16[2]; ///< 16-bit unsigned shorts(s)
67 u8 _u8[4]; ///< 8-bit unsigned char(s)
68};
69
70/// Union for fast 64-bit type casting
71union t64 {
72 f64 _f64; ///< 64-bit floating point
73 u64 _u64; ///< 64-bit unsigned long
74 f32 _f32[2]; ///< 32-bit floating point(s)
75 u32 _u32[2]; ///< 32-bit unsigned int(s)
76 s32 _s32[2]; ///< 32-bit signed int(s)
77 u16 _u16[4]; ///< 16-bit unsigned shorts(s)
78 u8 _u8[8]; ///< 8-bit unsigned char(s)
79};
80
81// An inheritable class to disallow the copy constructor and operator= functions 53// An inheritable class to disallow the copy constructor and operator= functions
82class NonCopyable { 54class NonCopyable {
83protected: 55protected:
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index 43facb85c..b69b05cb9 100644
--- a/src/common/emu_window.cpp
+++ b/src/common/emu_window.cpp
@@ -2,6 +2,12 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <cmath>
7
8#include "common/assert.h"
9#include "common/key_map.h"
10
5#include "emu_window.h" 11#include "emu_window.h"
6#include "video_core/video_core.h" 12#include "video_core/video_core.h"
7 13
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index 8eca6b5d5..a0ae4c9fa 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -4,11 +4,17 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <tuple>
8#include <utility>
9
7#include "common/common_types.h" 10#include "common/common_types.h"
8#include "common/key_map.h"
9#include "common/math_util.h" 11#include "common/math_util.h"
10#include "common/scm_rev.h" 12
11#include "common/string_util.h" 13#include "core/hle/service/hid/hid.h"
14
15namespace KeyMap {
16struct HostDeviceKey;
17}
12 18
13/** 19/**
14 * Abstraction class used to provide an interface between emulation code and the frontend 20 * Abstraction class used to provide an interface between emulation code and the frontend
diff --git a/src/common/fifo_queue.h b/src/common/fifo_queue.h
deleted file mode 100644
index b426e6596..000000000
--- a/src/common/fifo_queue.h
+++ /dev/null
@@ -1,111 +0,0 @@
1#pragma once
2
3// a simple lockless thread-safe,
4// single reader, single writer queue
5
6#include "common/atomic.h"
7
8namespace Common
9{
10
11template <typename T>
12class FifoQueue
13{
14public:
15 FifoQueue() : m_size(0)
16 {
17 m_write_ptr = m_read_ptr = new ElementPtr();
18 }
19
20 ~FifoQueue()
21 {
22 // this will empty out the whole queue
23 delete m_read_ptr;
24 }
25
26 u32 Size() const
27 {
28 return m_size;
29 }
30
31 bool Empty() const
32 {
33 //return (m_read_ptr == m_write_ptr);
34 return (0 == m_size);
35 }
36
37 T& Front() const
38 {
39 return *m_read_ptr->current;
40 }
41
42 template <typename Arg>
43 void Push(Arg&& t)
44 {
45 // create the element, add it to the queue
46 m_write_ptr->current = new T(std::forward<Arg>(t));
47 // set the next pointer to a new element ptr
48 // then advance the write pointer
49 m_write_ptr = m_write_ptr->next = new ElementPtr();
50 Common::AtomicIncrement(m_size);
51 }
52
53 void Pop()
54 {
55 Common::AtomicDecrement(m_size);
56 ElementPtr *const tmpptr = m_read_ptr;
57 // advance the read pointer
58 m_read_ptr = m_read_ptr->next;
59 // set the next element to NULL to stop the recursive deletion
60 tmpptr->next = nullptr;
61 delete tmpptr; // this also deletes the element
62 }
63
64 bool Pop(T& t)
65 {
66 if (Empty())
67 return false;
68
69 t = std::move(Front());
70 Pop();
71
72 return true;
73 }
74
75 // not thread-safe
76 void Clear()
77 {
78 m_size = 0;
79 delete m_read_ptr;
80 m_write_ptr = m_read_ptr = new ElementPtr();
81 }
82
83private:
84 // stores a pointer to element
85 // and a pointer to the next ElementPtr
86 class ElementPtr
87 {
88 public:
89 ElementPtr() : current(nullptr), next(nullptr) {}
90
91 ~ElementPtr()
92 {
93 if (current)
94 {
95 delete current;
96 // recusion ftw
97 if (next)
98 delete next;
99 }
100 }
101
102 T *volatile current;
103 ElementPtr *volatile next;
104 };
105
106 ElementPtr *volatile m_write_ptr;
107 ElementPtr *volatile m_read_ptr;
108 volatile u32 m_size;
109};
110
111}
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 24648ea33..836b58d52 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -17,6 +17,8 @@
17 #include <direct.h> // getcwd 17 #include <direct.h> // getcwd
18 #include <tchar.h> 18 #include <tchar.h>
19 19
20 #include "common/string_util.h"
21
20 // 64 bit offsets for windows 22 // 64 bit offsets for windows
21 #define fseeko _fseeki64 23 #define fseeko _fseeki64
22 #define ftello _ftelli64 24 #define ftello _ftelli64
@@ -25,8 +27,13 @@
25 #define fstat64 _fstat64 27 #define fstat64 _fstat64
26 #define fileno _fileno 28 #define fileno _fileno
27#else 29#else
28 #include <sys/param.h> 30 #ifdef __APPLE__
29 #include <sys/types.h> 31 #include <sys/param.h>
32 #endif
33 #include <cctype>
34 #include <cerrno>
35 #include <cstdlib>
36 #include <cstring>
30 #include <dirent.h> 37 #include <dirent.h>
31 #include <pwd.h> 38 #include <pwd.h>
32 #include <unistd.h> 39 #include <unistd.h>
diff --git a/src/common/file_util.h b/src/common/file_util.h
index b65829291..d0dccdf69 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -6,13 +6,12 @@
6 6
7#include <array> 7#include <array>
8#include <fstream> 8#include <fstream>
9#include <cstddef>
9#include <cstdio> 10#include <cstdio>
10#include <cstring>
11#include <string> 11#include <string>
12#include <vector> 12#include <vector>
13 13
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "common/string_util.h"
16 15
17// User directory indices for GetUserPath 16// User directory indices for GetUserPath
18enum { 17enum {
@@ -117,9 +116,6 @@ bool SetCurrentDir(const std::string &directory);
117// directory. To be used in "multi-user" mode (that is, installed). 116// directory. To be used in "multi-user" mode (that is, installed).
118const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath=""); 117const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath="");
119 118
120// probably doesn't belong here
121//std::string GetThemeDir(const std::string& theme_name);
122
123// Returns the path to where the sys file are 119// Returns the path to where the sys file are
124std::string GetSysDirectory(); 120std::string GetSysDirectory();
125 121
@@ -182,6 +178,10 @@ public:
182 template <typename T> 178 template <typename T>
183 size_t WriteArray(const T* data, size_t length) 179 size_t WriteArray(const T* data, size_t length)
184 { 180 {
181 static_assert(std::is_standard_layout<T>::value, "Given array does not consist of standard layout objects");
182 // TODO: gcc 4.8 does not support is_trivially_copyable, but we really should check for it here.
183 //static_assert(std::is_trivially_copyable<T>::value, "Given array does not consist of trivially copyable objects");
184
185 if (!IsOpen()) { 185 if (!IsOpen()) {
186 m_good = false; 186 m_good = false;
187 return -1; 187 return -1;
@@ -204,6 +204,12 @@ public:
204 return WriteArray(reinterpret_cast<const char*>(data), length); 204 return WriteArray(reinterpret_cast<const char*>(data), length);
205 } 205 }
206 206
207 template<typename T>
208 size_t WriteObject(const T& object) {
209 static_assert(!std::is_pointer<T>::value, "Given object is a pointer");
210 return WriteArray(&object, 1);
211 }
212
207 bool IsOpen() { return nullptr != m_file; } 213 bool IsOpen() { return nullptr != m_file; }
208 214
209 // m_good is set to false when a read, write or other function fails 215 // m_good is set to false when a read, write or other function fails
diff --git a/src/common/logging/filter.h b/src/common/logging/filter.h
index 0b71ea3b2..a2b4eca43 100644
--- a/src/common/logging/filter.h
+++ b/src/common/logging/filter.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <cstddef>
8#include <string> 9#include <string>
9 10
10#include "common/logging/log.h" 11#include "common/logging/log.h"
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 5b3a731e9..e16dde7fc 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -4,10 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cassert>
8#include <chrono>
9#include <string>
10
11#include "common/common_types.h" 7#include "common/common_types.h"
12 8
13namespace Log { 9namespace Log {
diff --git a/src/common/make_unique.h b/src/common/make_unique.h
index 2a7b76412..f6e7f017c 100644
--- a/src/common/make_unique.h
+++ b/src/common/make_unique.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <algorithm>
7#include <memory> 8#include <memory>
8 9
9namespace Common { 10namespace Common {
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp
index 20b791a10..2b3ace528 100644
--- a/src/common/memory_util.cpp
+++ b/src/common/memory_util.cpp
@@ -3,14 +3,17 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5 5
6#include "common/common_funcs.h"
7#include "common/logging/log.h" 6#include "common/logging/log.h"
8#include "common/memory_util.h" 7#include "common/memory_util.h"
9#include "common/string_util.h"
10 8
11#ifdef _WIN32 9#ifdef _WIN32
12#include <windows.h> 10 #include <windows.h>
13#include <psapi.h> 11 #include <psapi.h>
12 #include "common/common_funcs.h"
13 #include "common/string_util.h"
14#else
15 #include <cstdlib>
16 #include <sys/mman.h>
14#endif 17#endif
15 18
16#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) 19#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
diff --git a/src/common/memory_util.h b/src/common/memory_util.h
index 9fdbf1f12..9bf37c44f 100644
--- a/src/common/memory_util.h
+++ b/src/common/memory_util.h
@@ -4,9 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#ifndef _WIN32 7#include <cstddef>
8#include <sys/mman.h>
9#endif
10#include <string> 8#include <string>
11 9
12void* AllocateExecutableMemory(size_t size, bool low = true); 10void* AllocateExecutableMemory(size_t size, bool low = true);
diff --git a/src/common/misc.cpp b/src/common/misc.cpp
index 53cacf37c..d2a049b63 100644
--- a/src/common/misc.cpp
+++ b/src/common/misc.cpp
@@ -2,12 +2,13 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_funcs.h" 5#include <cstddef>
6 6
7#ifdef _WIN32 7#ifdef _WIN32
8#include <windows.h> 8#include <windows.h>
9#else 9#else
10#include <string.h> 10#include <cerrno>
11#include <cstring>
11#endif 12#endif
12 13
13// Neither Android nor OS X support TLS 14// Neither Android nor OS X support TLS
diff --git a/src/common/platform.h b/src/common/platform.h
index df780ac6f..0a912dda3 100644
--- a/src/common/platform.h
+++ b/src/common/platform.h
@@ -24,66 +24,11 @@
24 24
25#pragma once 25#pragma once
26 26
27#include "common/common_types.h"
28
29////////////////////////////////////////////////////////////////////////////////////////////////////
30// Platform definitions
31
32/// Enumeration for defining the supported platforms
33#define PLATFORM_NULL 0
34#define PLATFORM_WINDOWS 1
35#define PLATFORM_MACOSX 2
36#define PLATFORM_LINUX 3
37#define PLATFORM_ANDROID 4
38
39//////////////////////////////////////////////////////////////////////////////////////////////////// 27////////////////////////////////////////////////////////////////////////////////////////////////////
40// Platform detection 28// Platform detection
41 29
42#ifndef EMU_PLATFORM
43
44#if defined( __WIN32__ ) || defined( _WIN32 )
45#define EMU_PLATFORM PLATFORM_WINDOWS
46
47#elif defined( __APPLE__ ) || defined( __APPLE_CC__ )
48#define EMU_PLATFORM PLATFORM_MACOSX
49
50#elif defined(__linux__)
51#define EMU_PLATFORM PLATFORM_LINUX
52
53#else // Assume linux otherwise
54#define EMU_PLATFORM PLATFORM_LINUX
55
56#endif
57
58#endif
59
60#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) 30#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__)
61 #define EMU_ARCH_BITS 64 31 #define EMU_ARCH_BITS 64
62#elif defined(__i386) || defined(_M_IX86) || defined(__arm__) || defined(_M_ARM) 32#elif defined(__i386) || defined(_M_IX86) || defined(__arm__) || defined(_M_ARM)
63 #define EMU_ARCH_BITS 32 33 #define EMU_ARCH_BITS 32
64#endif 34#endif
65
66////////////////////////////////////////////////////////////////////////////////////////////////////
67// Feature detection
68
69#if defined _M_GENERIC
70# define _M_SSE 0x0
71#elif defined __GNUC__
72# if defined __SSE4_2__
73# define _M_SSE 0x402
74# elif defined __SSE4_1__
75# define _M_SSE 0x401
76# elif defined __SSSE3__
77# define _M_SSE 0x301
78# elif defined __SSE3__
79# define _M_SSE 0x300
80# endif
81#elif (_MSC_VER >= 1500) || __INTEL_COMPILER // Visual Studio 2008
82# define _M_SSE 0x402
83#endif
84
85////////////////////////////////////////////////////////////////////////////////////////////////////
86// Compiler-Specific Definitions
87
88#define GCC_VERSION_AVAILABLE(major, minor) (defined(__GNUC__) && (__GNUC__ > (major) || \
89 (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))))
diff --git a/src/common/profiler.cpp b/src/common/profiler.cpp
index cf6b6b258..7792edd2f 100644
--- a/src/common/profiler.cpp
+++ b/src/common/profiler.cpp
@@ -2,13 +2,18 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <cstddef>
7#include <vector>
8
9#include "common/assert.h"
5#include "common/profiler.h" 10#include "common/profiler.h"
6#include "common/profiler_reporting.h" 11#include "common/profiler_reporting.h"
7#include "common/assert.h" 12#include "common/synchronized_wrapper.h"
8 13
9#if defined(_MSC_VER) && _MSC_VER <= 1800 // MSVC 2013. 14#if defined(_MSC_VER) && _MSC_VER <= 1800 // MSVC 2013.
10#define WIN32_LEAN_AND_MEAN 15 #define WIN32_LEAN_AND_MEAN
11#include <Windows.h> // For QueryPerformanceCounter/Frequency 16 #include <Windows.h> // For QueryPerformanceCounter/Frequency
12#endif 17#endif
13 18
14namespace Common { 19namespace Common {
diff --git a/src/common/profiler_reporting.h b/src/common/profiler_reporting.h
index 3abb73315..df98e05b7 100644
--- a/src/common/profiler_reporting.h
+++ b/src/common/profiler_reporting.h
@@ -4,10 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <cstddef>
8#include <chrono>
9#include <mutex>
10#include <utility>
11#include <vector> 8#include <vector>
12 9
13#include "common/profiler.h" 10#include "common/profiler.h"
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 7dc0ba7ba..b2f7f7b1d 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -2,9 +2,13 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <boost/range/algorithm.hpp> 5#include <cctype>
6#include <cerrno>
7#include <cstdio>
8#include <cstdlib>
9#include <cstring>
10#include <boost/range/algorithm/transform.hpp>
6 11
7#include "common/common_funcs.h"
8#include "common/common_paths.h" 12#include "common/common_paths.h"
9#include "common/logging/log.h" 13#include "common/logging/log.h"
10#include "common/string_util.h" 14#include "common/string_util.h"
@@ -12,6 +16,7 @@
12#ifdef _MSC_VER 16#ifdef _MSC_VER
13 #include <Windows.h> 17 #include <Windows.h>
14 #include <codecvt> 18 #include <codecvt>
19 #include "common/common_funcs.h"
15#else 20#else
16 #include <iconv.h> 21 #include <iconv.h>
17#endif 22#endif
@@ -308,7 +313,7 @@ static std::string UTF16ToUTF8(const std::wstring& input)
308 std::string output; 313 std::string output;
309 output.resize(size); 314 output.resize(size);
310 315
311 if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), &output[0], output.size(), nullptr, nullptr)) 316 if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), &output[0], static_cast<int>(output.size()), nullptr, nullptr))
312 output.clear(); 317 output.clear();
313 318
314 return output; 319 return output;
diff --git a/src/common/string_util.h b/src/common/string_util.h
index fdc410499..c5c474c6f 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -5,9 +5,10 @@
5#pragma once 5#pragma once
6 6
7#include <cstdarg> 7#include <cstdarg>
8#include <cstddef>
8#include <iomanip> 9#include <iomanip>
9#include <string>
10#include <sstream> 10#include <sstream>
11#include <string>
11#include <vector> 12#include <vector>
12 13
13#include "common/common_types.h" 14#include "common/common_types.h"
diff --git a/src/common/swap.h b/src/common/swap.h
index 588cebc70..b92e5bfa4 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -17,12 +17,16 @@
17 17
18#pragma once 18#pragma once
19 19
20#if defined(__linux__) 20#if defined(_MSC_VER)
21#include <byteswap.h> 21 #include <cstdlib>
22#elif defined(__linux__)
23 #include <byteswap.h>
22#elif defined(__FreeBSD__) 24#elif defined(__FreeBSD__)
23#include <sys/endian.h> 25 #include <sys/endian.h>
24#endif 26#endif
25 27
28#include "common/common_types.h"
29
26// GCC 4.6+ 30// GCC 4.6+
27#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) 31#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
28 32
diff --git a/src/common/synchronized_wrapper.h b/src/common/synchronized_wrapper.h
index 946252b8c..ae5e8b1ed 100644
--- a/src/common/synchronized_wrapper.h
+++ b/src/common/synchronized_wrapper.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <algorithm>
7#include <mutex> 8#include <mutex>
8 9
9namespace Common { 10namespace Common {
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 8bf005857..7bbf080bc 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -5,11 +5,20 @@
5#include "common/thread.h" 5#include "common/thread.h"
6 6
7#ifdef __APPLE__ 7#ifdef __APPLE__
8#include <mach/mach.h> 8 #include <mach/mach.h>
9#elif defined(BSD4_4) || defined(__OpenBSD__)
10#include <pthread_np.h>
11#elif defined(_WIN32) 9#elif defined(_WIN32)
12#include <Windows.h> 10 #include <Windows.h>
11#else
12 #if defined(BSD4_4) || defined(__OpenBSD__)
13 #include <pthread_np.h>
14 #else
15 #include <pthread.h>
16 #endif
17 #include <sched.h>
18#endif
19
20#ifndef _WIN32
21 #include <unistd.h>
13#endif 22#endif
14 23
15namespace Common 24namespace Common
diff --git a/src/common/thread.h b/src/common/thread.h
index 7bc419497..8255ee6d3 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -4,24 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include <cstddef>
8#include <cstdio>
9#include <cstring>
10#include <thread> 8#include <thread>
11#include <condition_variable> 9#include <condition_variable>
12#include <mutex> 10#include <mutex>
13 11
14// This may not be defined outside _WIN32 12#include "common/common_types.h"
15#ifndef _WIN32
16#ifndef INFINITE
17#define INFINITE 0xffffffff
18#endif
19
20//for gettimeofday and struct time(spec|val)
21#include <time.h>
22#include <sys/time.h>
23#include <unistd.h>
24#endif
25 13
26// Support for C++11's thread_local keyword was surprisingly spotty in compilers until very 14// Support for C++11's thread_local keyword was surprisingly spotty in compilers until very
27// recently. Fortunately, thread local variables have been well supported for compilers for a while, 15// recently. Fortunately, thread local variables have been well supported for compilers for a while,
diff --git a/src/common/thunk.h b/src/common/thunk.h
deleted file mode 100644
index 533480056..000000000
--- a/src/common/thunk.h
+++ /dev/null
@@ -1,42 +0,0 @@
1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <map>
8
9#include "common/common_types.h"
10
11// This simple class creates a wrapper around a C/C++ function that saves all fp state
12// before entering it, and restores it upon exit. This is required to be able to selectively
13// call functions from generated code, without inflicting the performance hit and increase
14// of complexity that it means to protect the generated code from this problem.
15
16// This process is called thunking.
17
18// There will only ever be one level of thunking on the stack, plus,
19// we don't want to pollute the stack, so we store away regs somewhere global.
20// NOT THREAD SAFE. This may only be used from the CPU thread.
21// Any other thread using this stuff will be FATAL.
22
23class ThunkManager : public Gen::XCodeBlock
24{
25 std::map<void *, const u8 *> thunks;
26
27 const u8 *save_regs;
28 const u8 *load_regs;
29
30public:
31 ThunkManager() {
32 Init();
33 }
34 ~ThunkManager() {
35 Shutdown();
36 }
37 void *ProtectFunction(void *function, int num_params);
38private:
39 void Init();
40 void Shutdown();
41 void Reset();
42};
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 4fcda4874..6cc60fd58 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -4,10 +4,9 @@ set(SRCS
4 arm/dyncom/arm_dyncom.cpp 4 arm/dyncom/arm_dyncom.cpp
5 arm/dyncom/arm_dyncom_dec.cpp 5 arm/dyncom/arm_dyncom_dec.cpp
6 arm/dyncom/arm_dyncom_interpreter.cpp 6 arm/dyncom/arm_dyncom_interpreter.cpp
7 arm/dyncom/arm_dyncom_run.cpp
8 arm/dyncom/arm_dyncom_thumb.cpp 7 arm/dyncom/arm_dyncom_thumb.cpp
9 arm/interpreter/arminit.cpp 8 arm/skyeye_common/armstate.cpp
10 arm/interpreter/armsupp.cpp 9 arm/skyeye_common/armsupp.cpp
11 arm/skyeye_common/vfp/vfp.cpp 10 arm/skyeye_common/vfp/vfp.cpp
12 arm/skyeye_common/vfp/vfpdouble.cpp 11 arm/skyeye_common/vfp/vfpdouble.cpp
13 arm/skyeye_common/vfp/vfpinstr.cpp 12 arm/skyeye_common/vfp/vfpinstr.cpp
@@ -25,6 +24,8 @@ set(SRCS
25 file_sys/ivfc_archive.cpp 24 file_sys/ivfc_archive.cpp
26 hle/config_mem.cpp 25 hle/config_mem.cpp
27 hle/hle.cpp 26 hle/hle.cpp
27 hle/applets/applet.cpp
28 hle/applets/swkbd.cpp
28 hle/kernel/address_arbiter.cpp 29 hle/kernel/address_arbiter.cpp
29 hle/kernel/event.cpp 30 hle/kernel/event.cpp
30 hle/kernel/kernel.cpp 31 hle/kernel/kernel.cpp
@@ -113,6 +114,7 @@ set(SRCS
113 loader/elf.cpp 114 loader/elf.cpp
114 loader/loader.cpp 115 loader/loader.cpp
115 loader/ncch.cpp 116 loader/ncch.cpp
117 tracer/recorder.cpp
116 mem_map.cpp 118 mem_map.cpp
117 memory.cpp 119 memory.cpp
118 settings.cpp 120 settings.cpp
@@ -129,8 +131,8 @@ set(HEADERS
129 arm/dyncom/arm_dyncom_run.h 131 arm/dyncom/arm_dyncom_run.h
130 arm/dyncom/arm_dyncom_thumb.h 132 arm/dyncom/arm_dyncom_thumb.h
131 arm/skyeye_common/arm_regformat.h 133 arm/skyeye_common/arm_regformat.h
132 arm/skyeye_common/armdefs.h 134 arm/skyeye_common/armstate.h
133 arm/skyeye_common/armmmu.h 135 arm/skyeye_common/armsupp.h
134 arm/skyeye_common/vfp/asm_vfp.h 136 arm/skyeye_common/vfp/asm_vfp.h
135 arm/skyeye_common/vfp/vfp.h 137 arm/skyeye_common/vfp/vfp.h
136 arm/skyeye_common/vfp/vfp_helper.h 138 arm/skyeye_common/vfp/vfp_helper.h
@@ -150,6 +152,8 @@ set(HEADERS
150 hle/config_mem.h 152 hle/config_mem.h
151 hle/function_wrappers.h 153 hle/function_wrappers.h
152 hle/hle.h 154 hle/hle.h
155 hle/applets/applet.h
156 hle/applets/swkbd.h
153 hle/kernel/address_arbiter.h 157 hle/kernel/address_arbiter.h
154 hle/kernel/event.h 158 hle/kernel/event.h
155 hle/kernel/kernel.h 159 hle/kernel/kernel.h
@@ -239,6 +243,8 @@ set(HEADERS
239 loader/elf.h 243 loader/elf.h
240 loader/loader.h 244 loader/loader.h
241 loader/ncch.h 245 loader/ncch.h
246 tracer/recorder.h
247 tracer/citrace.h
242 mem_map.h 248 mem_map.h
243 memory.h 249 memory.h
244 memory_setup.h 250 memory_setup.h
diff --git a/src/core/arm/disassembler/load_symbol_map.cpp b/src/core/arm/disassembler/load_symbol_map.cpp
index 13d26d170..eb20bf6f7 100644
--- a/src/core/arm/disassembler/load_symbol_map.cpp
+++ b/src/core/arm/disassembler/load_symbol_map.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <sstream>
5#include <string> 6#include <string>
6#include <vector> 7#include <vector>
7 8
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index 529c4ac70..c665f706f 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -6,7 +6,8 @@
6 6
7#include "common/make_unique.h" 7#include "common/make_unique.h"
8 8
9#include "core/arm/skyeye_common/armdefs.h" 9#include "core/arm/skyeye_common/armstate.h"
10#include "core/arm/skyeye_common/armsupp.h"
10#include "core/arm/skyeye_common/vfp/vfp.h" 11#include "core/arm/skyeye_common/vfp/vfp.h"
11 12
12#include "core/arm/dyncom/arm_dyncom.h" 13#include "core/arm/dyncom/arm_dyncom.h"
@@ -17,26 +18,7 @@
17#include "core/core_timing.h" 18#include "core/core_timing.h"
18 19
19ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) { 20ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) {
20 state = Common::make_unique<ARMul_State>(); 21 state = Common::make_unique<ARMul_State>(initial_mode);
21
22 ARMul_NewState(state.get());
23 ARMul_SelectProcessor(state.get(), ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop);
24
25 state->abort_model = ABORT_BASE_RESTORED;
26
27 state->bigendSig = LOW;
28 state->lateabtSig = LOW;
29 state->NirqSig = HIGH;
30
31 // Reset the core to initial state
32 ARMul_Reset(state.get());
33 state->Emulate = RUN;
34
35 // Switch to the desired privilege mode.
36 switch_mode(state.get(), initial_mode);
37
38 state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack
39 state->Reg[15] = 0x00000000;
40} 22}
41 23
42ARM_DynCom::~ARM_DynCom() { 24ARM_DynCom::~ARM_DynCom() {
@@ -100,8 +82,8 @@ void ARM_DynCom::ResetContext(Core::ThreadContext& context, u32 stack_top, u32 e
100} 82}
101 83
102void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) { 84void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) {
103 memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers)); 85 memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers));
104 memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers)); 86 memcpy(ctx.fpu_registers, state->ExtReg.data(), sizeof(ctx.fpu_registers));
105 87
106 ctx.sp = state->Reg[13]; 88 ctx.sp = state->Reg[13];
107 ctx.lr = state->Reg[14]; 89 ctx.lr = state->Reg[14];
@@ -113,8 +95,8 @@ void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) {
113} 95}
114 96
115void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) { 97void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) {
116 memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers)); 98 memcpy(state->Reg.data(), ctx.cpu_registers, sizeof(ctx.cpu_registers));
117 memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers)); 99 memcpy(state->ExtReg.data(), ctx.fpu_registers, sizeof(ctx.fpu_registers));
118 100
119 state->Reg[13] = ctx.sp; 101 state->Reg[13] = ctx.sp;
120 state->Reg[14] = ctx.lr; 102 state->Reg[14] = ctx.lr;
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index 2488c879c..87ab6908a 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -9,7 +9,12 @@
9#include "common/common_types.h" 9#include "common/common_types.h"
10 10
11#include "core/arm/arm_interface.h" 11#include "core/arm/arm_interface.h"
12#include "core/arm/skyeye_common/armdefs.h" 12#include "core/arm/skyeye_common/arm_regformat.h"
13#include "core/arm/skyeye_common/armstate.h"
14
15namespace Core {
16struct ThreadContext;
17}
13 18
14class ARM_DynCom final : virtual public ARM_Interface { 19class ARM_DynCom final : virtual public ARM_Interface {
15public: 20public:
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.cpp b/src/core/arm/dyncom/arm_dyncom_dec.cpp
index 697be9556..ee4288314 100644
--- a/src/core/arm/dyncom/arm_dyncom_dec.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_dec.cpp
@@ -2,10 +2,10 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/arm/skyeye_common/armdefs.h"
6#include "core/arm/dyncom/arm_dyncom_dec.h" 5#include "core/arm/dyncom/arm_dyncom_dec.h"
6#include "core/arm/skyeye_common/armsupp.h"
7 7
8const ISEITEM arm_instruction[] = { 8const InstructionSetEncodingItem arm_instruction[] = {
9 { "vmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 4, 4, 0 }}, 9 { "vmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 4, 4, 0 }},
10 { "vmls", 7, ARMVFP2, { 28, 31, 0xF, 25, 27, 0x1, 23, 23, 1, 11, 11, 0, 8, 9, 0x2, 6, 6, 1, 4, 4, 0 }}, 10 { "vmls", 7, ARMVFP2, { 28, 31, 0xF, 25, 27, 0x1, 23, 23, 1, 11, 11, 0, 8, 9, 0x2, 6, 6, 1, 4, 4, 0 }},
11 { "vnmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 4, 4, 0 }}, 11 { "vnmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 4, 4, 0 }},
@@ -207,7 +207,7 @@ const ISEITEM arm_instruction[] = {
207 { "bbl", 1, 0, { 25, 27, 0x00000005 }}, 207 { "bbl", 1, 0, { 25, 27, 0x00000005 }},
208}; 208};
209 209
210const ISEITEM arm_exclusion_code[] = { 210const InstructionSetEncodingItem arm_exclusion_code[] = {
211 { "vmla", 0, ARMVFP2, { 0 }}, 211 { "vmla", 0, ARMVFP2, { 0 }},
212 { "vmls", 0, ARMVFP2, { 0 }}, 212 { "vmls", 0, ARMVFP2, { 0 }},
213 { "vnmla", 0, ARMVFP2, { 0 }}, 213 { "vnmla", 0, ARMVFP2, { 0 }},
@@ -414,14 +414,13 @@ const ISEITEM arm_exclusion_code[] = {
414 { "invalid", 0, INVALID, { 0 }} 414 { "invalid", 0, INVALID, { 0 }}
415}; 415};
416 416
417int decode_arm_instr(uint32_t instr, int32_t *idx) { 417ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx) {
418 int n = 0; 418 int n = 0;
419 int base = 0; 419 int base = 0;
420 int ret = DECODE_FAILURE; 420 int instr_slots = sizeof(arm_instruction) / sizeof(InstructionSetEncodingItem);
421 int i = 0; 421 ARMDecodeStatus ret = ARMDecodeStatus::FAILURE;
422 int instr_slots = sizeof(arm_instruction) / sizeof(ISEITEM);
423 422
424 for (i = 0; i < instr_slots; i++) { 423 for (int i = 0; i < instr_slots; i++) {
425 n = arm_instruction[i].attribute_value; 424 n = arm_instruction[i].attribute_value;
426 base = 0; 425 base = 0;
427 426
@@ -438,11 +437,11 @@ int decode_arm_instr(uint32_t instr, int32_t *idx) {
438 n--; 437 n--;
439 } 438 }
440 439
441 // All conditions is satisfied. 440 // All conditions are satisfied.
442 if (n == 0) 441 if (n == 0)
443 ret = DECODE_SUCCESS; 442 ret = ARMDecodeStatus::SUCCESS;
444 443
445 if (ret == DECODE_SUCCESS) { 444 if (ret == ARMDecodeStatus::SUCCESS) {
446 n = arm_exclusion_code[i].attribute_value; 445 n = arm_exclusion_code[i].attribute_value;
447 if (n != 0) { 446 if (n != 0) {
448 base = 0; 447 base = 0;
@@ -454,13 +453,13 @@ int decode_arm_instr(uint32_t instr, int32_t *idx) {
454 n--; 453 n--;
455 } 454 }
456 455
457 // All conditions is satisfied. 456 // All conditions are satisfied.
458 if (n == 0) 457 if (n == 0)
459 ret = DECODE_FAILURE; 458 ret = ARMDecodeStatus::FAILURE;
460 } 459 }
461 } 460 }
462 461
463 if (ret == DECODE_SUCCESS) { 462 if (ret == ARMDecodeStatus::SUCCESS) {
464 *idx = i; 463 *idx = i;
465 return ret; 464 return ret;
466 } 465 }
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.h b/src/core/arm/dyncom/arm_dyncom_dec.h
index 4b5f5ad7e..d7170e0fc 100644
--- a/src/core/arm/dyncom/arm_dyncom_dec.h
+++ b/src/core/arm/dyncom/arm_dyncom_dec.h
@@ -4,22 +4,22 @@
4 4
5#pragma once 5#pragma once
6 6
7int decode_arm_instr(uint32_t instr, int32_t *idx); 7#include "common/common_types.h"
8 8
9enum DECODE_STATUS { 9enum class ARMDecodeStatus {
10 DECODE_SUCCESS, 10 SUCCESS,
11 DECODE_FAILURE 11 FAILURE
12}; 12};
13 13
14struct instruction_set_encoding_item { 14ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx);
15
16struct InstructionSetEncodingItem {
15 const char *name; 17 const char *name;
16 int attribute_value; 18 int attribute_value;
17 int version; 19 int version;
18 u32 content[21]; 20 u32 content[21];
19}; 21};
20 22
21typedef struct instruction_set_encoding_item ISEITEM;
22
23// ARM versions 23// ARM versions
24enum { 24enum {
25 INVALID = 0, 25 INVALID = 0,
@@ -36,4 +36,4 @@ enum {
36 ARMV6K, 36 ARMV6K,
37}; 37};
38 38
39extern const ISEITEM arm_instruction[]; 39extern const InstructionSetEncodingItem arm_instruction[];
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index b00eb49a9..d022546ed 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -17,8 +17,8 @@
17#include "core/arm/dyncom/arm_dyncom_interpreter.h" 17#include "core/arm/dyncom/arm_dyncom_interpreter.h"
18#include "core/arm/dyncom/arm_dyncom_thumb.h" 18#include "core/arm/dyncom/arm_dyncom_thumb.h"
19#include "core/arm/dyncom/arm_dyncom_run.h" 19#include "core/arm/dyncom/arm_dyncom_run.h"
20#include "core/arm/skyeye_common/armdefs.h" 20#include "core/arm/skyeye_common/armstate.h"
21#include "core/arm/skyeye_common/armmmu.h" 21#include "core/arm/skyeye_common/armsupp.h"
22#include "core/arm/skyeye_common/vfp/vfp.h" 22#include "core/arm/skyeye_common/vfp/vfp.h"
23 23
24Common::Profiling::TimingCategory profile_execute("DynCom::Execute"); 24Common::Profiling::TimingCategory profile_execute("DynCom::Execute");
@@ -47,28 +47,6 @@ enum {
47 47
48typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper); 48typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper);
49 49
50// Defines a reservation granule of 2 words, which protects the first 2 words starting at the tag.
51// This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough to
52// support LDR/STREXD.
53static const ARMword RESERVATION_GRANULE_MASK = 0xFFFFFFF8;
54
55// Exclusive memory access
56static int exclusive_detect(ARMul_State* state, ARMword addr) {
57 if(state->exclusive_tag == (addr & RESERVATION_GRANULE_MASK))
58 return 0;
59 else
60 return -1;
61}
62
63static void add_exclusive_addr(ARMul_State* state, ARMword addr){
64 state->exclusive_tag = addr & RESERVATION_GRANULE_MASK;
65 return;
66}
67
68static void remove_exclusive(ARMul_State* state, ARMword addr){
69 state->exclusive_tag = 0xFFFFFFFF;
70}
71
72static int CondPassed(ARMul_State* cpu, unsigned int cond) { 50static int CondPassed(ARMul_State* cpu, unsigned int cond) {
73 const u32 NFLAG = cpu->NFlag; 51 const u32 NFLAG = cpu->NFlag;
74 const u32 ZFLAG = cpu->ZFlag; 52 const u32 ZFLAG = cpu->ZFlag;
@@ -3490,21 +3468,15 @@ enum {
3490 FETCH_FAILURE 3468 FETCH_FAILURE
3491}; 3469};
3492 3470
3493static tdstate decode_thumb_instr(u32 inst, u32 addr, u32* arm_inst, u32* inst_size, ARM_INST_PTR* ptr_inst_base) { 3471static ThumbDecodeStatus DecodeThumbInstruction(u32 inst, u32 addr, u32* arm_inst, u32* inst_size, ARM_INST_PTR* ptr_inst_base) {
3494 // Check if in Thumb mode 3472 // Check if in Thumb mode
3495 tdstate ret = thumb_translate (addr, inst, arm_inst, inst_size); 3473 ThumbDecodeStatus ret = TranslateThumbInstruction (addr, inst, arm_inst, inst_size);
3496 if(ret == t_branch){ 3474 if (ret == ThumbDecodeStatus::BRANCH) {
3497 // TODO: FIXME, endian should be judged
3498 u32 tinstr;
3499 if((addr & 0x3) != 0)
3500 tinstr = inst >> 16;
3501 else
3502 tinstr = inst & 0xFFFF;
3503
3504 int inst_index; 3475 int inst_index;
3505 int table_length = sizeof(arm_instruction_trans) / sizeof(transop_fp_t); 3476 int table_length = sizeof(arm_instruction_trans) / sizeof(transop_fp_t);
3477 u32 tinstr = GetThumbInstruction(inst, addr);
3506 3478
3507 switch((tinstr & 0xF800) >> 11){ 3479 switch ((tinstr & 0xF800) >> 11) {
3508 case 26: 3480 case 26:
3509 case 27: 3481 case 27:
3510 if (((tinstr & 0x0F00) != 0x0E00) && ((tinstr & 0x0F00) != 0x0F00)){ 3482 if (((tinstr & 0x0F00) != 0x0E00) && ((tinstr & 0x0F00) != 0x0F00)){
@@ -3537,7 +3509,7 @@ static tdstate decode_thumb_instr(u32 inst, u32 addr, u32* arm_inst, u32* inst_s
3537 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); 3509 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
3538 break; 3510 break;
3539 default: 3511 default:
3540 ret = t_undefined; 3512 ret = ThumbDecodeStatus::UNDEFINED;
3541 break; 3513 break;
3542 } 3514 }
3543 } 3515 }
@@ -3549,10 +3521,6 @@ enum {
3549 FETCH_EXCEPTION 3521 FETCH_EXCEPTION
3550}; 3522};
3551 3523
3552typedef struct instruction_set_encoding_item ISEITEM;
3553
3554extern const ISEITEM arm_instruction[];
3555
3556static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) { 3524static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) {
3557 Common::Profiling::ScopeTimer timer_decode(profile_decode); 3525 Common::Profiling::ScopeTimer timer_decode(profile_decode);
3558 3526
@@ -3574,20 +3542,19 @@ static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) {
3574 inst = Memory::Read32(phys_addr & 0xFFFFFFFC); 3542 inst = Memory::Read32(phys_addr & 0xFFFFFFFC);
3575 3543
3576 size++; 3544 size++;
3577 // If we are in thumb instruction, we will translate one thumb to one corresponding arm instruction 3545 // If we are in Thumb mode, we'll translate one Thumb instruction to the corresponding ARM instruction
3578 if (cpu->TFlag) { 3546 if (cpu->TFlag) {
3579 uint32_t arm_inst; 3547 uint32_t arm_inst;
3580 tdstate state = decode_thumb_instr(inst, phys_addr, &arm_inst, &inst_size, &inst_base); 3548 ThumbDecodeStatus state = DecodeThumbInstruction(inst, phys_addr, &arm_inst, &inst_size, &inst_base);
3581 3549
3582 // We have translated the branch instruction of thumb in thumb decoder 3550 // We have translated the Thumb branch instruction in the Thumb decoder
3583 if(state == t_branch){ 3551 if (state == ThumbDecodeStatus::BRANCH) {
3584 goto translated; 3552 goto translated;
3585 } 3553 }
3586 inst = arm_inst; 3554 inst = arm_inst;
3587 } 3555 }
3588 3556
3589 ret = decode_arm_instr(inst, &idx); 3557 if (DecodeARMInstruction(inst, &idx) == ARMDecodeStatus::FAILURE) {
3590 if (ret == DECODE_FAILURE) {
3591 std::string disasm = ARM_Disasm::Disassemble(phys_addr, inst); 3558 std::string disasm = ARM_Disasm::Disassemble(phys_addr, inst);
3592 LOG_ERROR(Core_ARM11, "Decode failure.\tPC : [0x%x]\tInstruction : %s [%x]", phys_addr, disasm.c_str(), inst); 3559 LOG_ERROR(Core_ARM11, "Decode failure.\tPC : [0x%x]\tInstruction : %s [%x]", phys_addr, disasm.c_str(), inst);
3593 LOG_ERROR(Core_ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x", cpu->Cpsr, cpu->TFlag, cpu->Reg[15]); 3560 LOG_ERROR(Core_ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x", cpu->Cpsr, cpu->TFlag, cpu->Reg[15]);
@@ -3964,7 +3931,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
3964 if (inst_cream->S && (inst_cream->Rd == 15)) { 3931 if (inst_cream->S && (inst_cream->Rd == 15)) {
3965 if (CurrentModeHasSPSR) { 3932 if (CurrentModeHasSPSR) {
3966 cpu->Cpsr = cpu->Spsr_copy; 3933 cpu->Cpsr = cpu->Spsr_copy;
3967 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 3934 cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
3968 LOAD_NZCVT; 3935 LOAD_NZCVT;
3969 } 3936 }
3970 } else if (inst_cream->S) { 3937 } else if (inst_cream->S) {
@@ -3978,7 +3945,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
3978 goto DISPATCH; 3945 goto DISPATCH;
3979 } 3946 }
3980 } 3947 }
3981 cpu->Reg[15] += GET_INST_SIZE(cpu); 3948 cpu->Reg[15] += cpu->GetInstructionSize();
3982 INC_PC(sizeof(adc_inst)); 3949 INC_PC(sizeof(adc_inst));
3983 FETCH_INST; 3950 FETCH_INST;
3984 GOTO_NEXT_INST; 3951 GOTO_NEXT_INST;
@@ -3990,7 +3957,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
3990 3957
3991 u32 rn_val = RN; 3958 u32 rn_val = RN;
3992 if (inst_cream->Rn == 15) 3959 if (inst_cream->Rn == 15)
3993 rn_val += 2 * GET_INST_SIZE(cpu); 3960 rn_val += 2 * cpu->GetInstructionSize();
3994 3961
3995 bool carry; 3962 bool carry;
3996 bool overflow; 3963 bool overflow;
@@ -3999,7 +3966,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
3999 if (inst_cream->S && (inst_cream->Rd == 15)) { 3966 if (inst_cream->S && (inst_cream->Rd == 15)) {
4000 if (CurrentModeHasSPSR) { 3967 if (CurrentModeHasSPSR) {
4001 cpu->Cpsr = cpu->Spsr_copy; 3968 cpu->Cpsr = cpu->Spsr_copy;
4002 switch_mode(cpu, cpu->Cpsr & 0x1f); 3969 cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F);
4003 LOAD_NZCVT; 3970 LOAD_NZCVT;
4004 } 3971 }
4005 } else if (inst_cream->S) { 3972 } else if (inst_cream->S) {
@@ -4013,7 +3980,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4013 goto DISPATCH; 3980 goto DISPATCH;
4014 } 3981 }
4015 } 3982 }
4016 cpu->Reg[15] += GET_INST_SIZE(cpu); 3983 cpu->Reg[15] += cpu->GetInstructionSize();
4017 INC_PC(sizeof(add_inst)); 3984 INC_PC(sizeof(add_inst));
4018 FETCH_INST; 3985 FETCH_INST;
4019 GOTO_NEXT_INST; 3986 GOTO_NEXT_INST;
@@ -4028,7 +3995,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4028 if (inst_cream->S && (inst_cream->Rd == 15)) { 3995 if (inst_cream->S && (inst_cream->Rd == 15)) {
4029 if (CurrentModeHasSPSR) { 3996 if (CurrentModeHasSPSR) {
4030 cpu->Cpsr = cpu->Spsr_copy; 3997 cpu->Cpsr = cpu->Spsr_copy;
4031 switch_mode(cpu, cpu->Cpsr & 0x1f); 3998 cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F);
4032 LOAD_NZCVT; 3999 LOAD_NZCVT;
4033 } 4000 }
4034 } else if (inst_cream->S) { 4001 } else if (inst_cream->S) {
@@ -4041,7 +4008,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4041 goto DISPATCH; 4008 goto DISPATCH;
4042 } 4009 }
4043 } 4010 }
4044 cpu->Reg[15] += GET_INST_SIZE(cpu); 4011 cpu->Reg[15] += cpu->GetInstructionSize();
4045 INC_PC(sizeof(and_inst)); 4012 INC_PC(sizeof(and_inst));
4046 FETCH_INST; 4013 FETCH_INST;
4047 GOTO_NEXT_INST; 4014 GOTO_NEXT_INST;
@@ -4057,7 +4024,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4057 INC_PC(sizeof(bbl_inst)); 4024 INC_PC(sizeof(bbl_inst));
4058 goto DISPATCH; 4025 goto DISPATCH;
4059 } 4026 }
4060 cpu->Reg[15] += GET_INST_SIZE(cpu); 4027 cpu->Reg[15] += cpu->GetInstructionSize();
4061 INC_PC(sizeof(bbl_inst)); 4028 INC_PC(sizeof(bbl_inst));
4062 goto DISPATCH; 4029 goto DISPATCH;
4063 } 4030 }
@@ -4067,14 +4034,14 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4067 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4034 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4068 u32 lop = RN; 4035 u32 lop = RN;
4069 if (inst_cream->Rn == 15) { 4036 if (inst_cream->Rn == 15) {
4070 lop += 2 * GET_INST_SIZE(cpu); 4037 lop += 2 * cpu->GetInstructionSize();
4071 } 4038 }
4072 u32 rop = SHIFTER_OPERAND; 4039 u32 rop = SHIFTER_OPERAND;
4073 RD = lop & (~rop); 4040 RD = lop & (~rop);
4074 if ((inst_cream->S) && (inst_cream->Rd == 15)) { 4041 if ((inst_cream->S) && (inst_cream->Rd == 15)) {
4075 if (CurrentModeHasSPSR) { 4042 if (CurrentModeHasSPSR) {
4076 cpu->Cpsr = cpu->Spsr_copy; 4043 cpu->Cpsr = cpu->Spsr_copy;
4077 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 4044 cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
4078 LOAD_NZCVT; 4045 LOAD_NZCVT;
4079 } 4046 }
4080 } else if (inst_cream->S) { 4047 } else if (inst_cream->S) {
@@ -4087,7 +4054,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4087 goto DISPATCH; 4054 goto DISPATCH;
4088 } 4055 }
4089 } 4056 }
4090 cpu->Reg[15] += GET_INST_SIZE(cpu); 4057 cpu->Reg[15] += cpu->GetInstructionSize();
4091 INC_PC(sizeof(bic_inst)); 4058 INC_PC(sizeof(bic_inst));
4092 FETCH_INST; 4059 FETCH_INST;
4093 GOTO_NEXT_INST; 4060 GOTO_NEXT_INST;
@@ -4098,7 +4065,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4098 bkpt_inst* const inst_cream = (bkpt_inst*)inst_base->component; 4065 bkpt_inst* const inst_cream = (bkpt_inst*)inst_base->component;
4099 LOG_DEBUG(Core_ARM11, "Breakpoint instruction hit. Immediate: 0x%08X", inst_cream->imm); 4066 LOG_DEBUG(Core_ARM11, "Breakpoint instruction hit. Immediate: 0x%08X", inst_cream->imm);
4100 } 4067 }
4101 cpu->Reg[15] += GET_INST_SIZE(cpu); 4068 cpu->Reg[15] += cpu->GetInstructionSize();
4102 INC_PC(sizeof(bkpt_inst)); 4069 INC_PC(sizeof(bkpt_inst));
4103 FETCH_INST; 4070 FETCH_INST;
4104 GOTO_NEXT_INST; 4071 GOTO_NEXT_INST;
@@ -4109,13 +4076,13 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4109 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4076 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4110 unsigned int inst = inst_cream->inst; 4077 unsigned int inst = inst_cream->inst;
4111 if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) { 4078 if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) {
4112 cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu)); 4079 cpu->Reg[14] = (cpu->Reg[15] + cpu->GetInstructionSize());
4113 if(cpu->TFlag) 4080 if(cpu->TFlag)
4114 cpu->Reg[14] |= 0x1; 4081 cpu->Reg[14] |= 0x1;
4115 cpu->Reg[15] = cpu->Reg[inst_cream->val.Rm] & 0xfffffffe; 4082 cpu->Reg[15] = cpu->Reg[inst_cream->val.Rm] & 0xfffffffe;
4116 cpu->TFlag = cpu->Reg[inst_cream->val.Rm] & 0x1; 4083 cpu->TFlag = cpu->Reg[inst_cream->val.Rm] & 0x1;
4117 } else { 4084 } else {
4118 cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu)); 4085 cpu->Reg[14] = (cpu->Reg[15] + cpu->GetInstructionSize());
4119 cpu->TFlag = 0x1; 4086 cpu->TFlag = 0x1;
4120 int signed_int = inst_cream->val.signed_immed_24; 4087 int signed_int = inst_cream->val.signed_immed_24;
4121 signed_int = (signed_int & 0x800000) ? (0x3F000000 | signed_int) : signed_int; 4088 signed_int = (signed_int & 0x800000) ? (0x3F000000 | signed_int) : signed_int;
@@ -4125,7 +4092,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4125 INC_PC(sizeof(blx_inst)); 4092 INC_PC(sizeof(blx_inst));
4126 goto DISPATCH; 4093 goto DISPATCH;
4127 } 4094 }
4128 cpu->Reg[15] += GET_INST_SIZE(cpu); 4095 cpu->Reg[15] += cpu->GetInstructionSize();
4129 INC_PC(sizeof(blx_inst)); 4096 INC_PC(sizeof(blx_inst));
4130 goto DISPATCH; 4097 goto DISPATCH;
4131 } 4098 }
@@ -4144,16 +4111,18 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4144 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { 4111 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
4145 bx_inst* const inst_cream = (bx_inst*)inst_base->component; 4112 bx_inst* const inst_cream = (bx_inst*)inst_base->component;
4146 4113
4114 u32 address = RM;
4115
4147 if (inst_cream->Rm == 15) 4116 if (inst_cream->Rm == 15)
4148 LOG_WARNING(Core_ARM11, "BX at pc %x: use of Rm = R15 is discouraged", cpu->Reg[15]); 4117 address += 2 * cpu->GetInstructionSize();
4149 4118
4150 cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1; 4119 cpu->TFlag = address & 1;
4151 cpu->Reg[15] = cpu->Reg[inst_cream->Rm] & 0xfffffffe; 4120 cpu->Reg[15] = address & 0xfffffffe;
4152 INC_PC(sizeof(bx_inst)); 4121 INC_PC(sizeof(bx_inst));
4153 goto DISPATCH; 4122 goto DISPATCH;
4154 } 4123 }
4155 4124
4156 cpu->Reg[15] += GET_INST_SIZE(cpu); 4125 cpu->Reg[15] += cpu->GetInstructionSize();
4157 INC_PC(sizeof(bx_inst)); 4126 INC_PC(sizeof(bx_inst));
4158 goto DISPATCH; 4127 goto DISPATCH;
4159 } 4128 }
@@ -4165,7 +4134,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4165 cpu->NumInstrsToExecute = 0; 4134 cpu->NumInstrsToExecute = 0;
4166 return num_instrs; 4135 return num_instrs;
4167 } 4136 }
4168 cpu->Reg[15] += GET_INST_SIZE(cpu); 4137 cpu->Reg[15] += cpu->GetInstructionSize();
4169 INC_PC(sizeof(cdp_inst)); 4138 INC_PC(sizeof(cdp_inst));
4170 FETCH_INST; 4139 FETCH_INST;
4171 GOTO_NEXT_INST; 4140 GOTO_NEXT_INST;
@@ -4173,10 +4142,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4173 4142
4174 CLREX_INST: 4143 CLREX_INST:
4175 { 4144 {
4176 remove_exclusive(cpu, 0); 4145 cpu->UnsetExclusiveMemoryAddress();
4177 cpu->exclusive_state = 0; 4146 cpu->Reg[15] += cpu->GetInstructionSize();
4178
4179 cpu->Reg[15] += GET_INST_SIZE(cpu);
4180 INC_PC(sizeof(clrex_inst)); 4147 INC_PC(sizeof(clrex_inst));
4181 FETCH_INST; 4148 FETCH_INST;
4182 GOTO_NEXT_INST; 4149 GOTO_NEXT_INST;
@@ -4187,7 +4154,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4187 clz_inst* inst_cream = (clz_inst*)inst_base->component; 4154 clz_inst* inst_cream = (clz_inst*)inst_base->component;
4188 RD = clz(RM); 4155 RD = clz(RM);
4189 } 4156 }
4190 cpu->Reg[15] += GET_INST_SIZE(cpu); 4157 cpu->Reg[15] += cpu->GetInstructionSize();
4191 INC_PC(sizeof(clz_inst)); 4158 INC_PC(sizeof(clz_inst));
4192 FETCH_INST; 4159 FETCH_INST;
4193 GOTO_NEXT_INST; 4160 GOTO_NEXT_INST;
@@ -4206,7 +4173,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4206 cpu->CFlag = carry; 4173 cpu->CFlag = carry;
4207 cpu->VFlag = overflow; 4174 cpu->VFlag = overflow;
4208 } 4175 }
4209 cpu->Reg[15] += GET_INST_SIZE(cpu); 4176 cpu->Reg[15] += cpu->GetInstructionSize();
4210 INC_PC(sizeof(cmn_inst)); 4177 INC_PC(sizeof(cmn_inst));
4211 FETCH_INST; 4178 FETCH_INST;
4212 GOTO_NEXT_INST; 4179 GOTO_NEXT_INST;
@@ -4218,7 +4185,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4218 4185
4219 u32 rn_val = RN; 4186 u32 rn_val = RN;
4220 if (inst_cream->Rn == 15) 4187 if (inst_cream->Rn == 15)
4221 rn_val += 2 * GET_INST_SIZE(cpu); 4188 rn_val += 2 * cpu->GetInstructionSize();
4222 4189
4223 bool carry; 4190 bool carry;
4224 bool overflow; 4191 bool overflow;
@@ -4229,7 +4196,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4229 cpu->CFlag = carry; 4196 cpu->CFlag = carry;
4230 cpu->VFlag = overflow; 4197 cpu->VFlag = overflow;
4231 } 4198 }
4232 cpu->Reg[15] += GET_INST_SIZE(cpu); 4199 cpu->Reg[15] += cpu->GetInstructionSize();
4233 INC_PC(sizeof(cmp_inst)); 4200 INC_PC(sizeof(cmp_inst));
4234 FETCH_INST; 4201 FETCH_INST;
4235 GOTO_NEXT_INST; 4202 GOTO_NEXT_INST;
@@ -4239,7 +4206,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4239 cps_inst *inst_cream = (cps_inst *)inst_base->component; 4206 cps_inst *inst_cream = (cps_inst *)inst_base->component;
4240 uint32_t aif_val = 0; 4207 uint32_t aif_val = 0;
4241 uint32_t aif_mask = 0; 4208 uint32_t aif_mask = 0;
4242 if (InAPrivilegedMode(cpu)) { 4209 if (cpu->InAPrivilegedMode()) {
4243 if (inst_cream->imod1) { 4210 if (inst_cream->imod1) {
4244 if (inst_cream->A) { 4211 if (inst_cream->A) {
4245 aif_val |= (inst_cream->imod0 << 8); 4212 aif_val |= (inst_cream->imod0 << 8);
@@ -4258,10 +4225,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4258 } 4225 }
4259 if (inst_cream->mmod) { 4226 if (inst_cream->mmod) {
4260 cpu->Cpsr = (cpu->Cpsr & 0xffffffe0) | inst_cream->mode; 4227 cpu->Cpsr = (cpu->Cpsr & 0xffffffe0) | inst_cream->mode;
4261 switch_mode(cpu, inst_cream->mode); 4228 cpu->ChangePrivilegeMode(inst_cream->mode);
4262 } 4229 }
4263 } 4230 }
4264 cpu->Reg[15] += GET_INST_SIZE(cpu); 4231 cpu->Reg[15] += cpu->GetInstructionSize();
4265 INC_PC(sizeof(cps_inst)); 4232 INC_PC(sizeof(cps_inst));
4266 FETCH_INST; 4233 FETCH_INST;
4267 GOTO_NEXT_INST; 4234 GOTO_NEXT_INST;
@@ -4277,7 +4244,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4277 goto DISPATCH; 4244 goto DISPATCH;
4278 } 4245 }
4279 } 4246 }
4280 cpu->Reg[15] += GET_INST_SIZE(cpu); 4247 cpu->Reg[15] += cpu->GetInstructionSize();
4281 INC_PC(sizeof(mov_inst)); 4248 INC_PC(sizeof(mov_inst));
4282 FETCH_INST; 4249 FETCH_INST;
4283 GOTO_NEXT_INST; 4250 GOTO_NEXT_INST;
@@ -4289,14 +4256,14 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4289 4256
4290 u32 lop = RN; 4257 u32 lop = RN;
4291 if (inst_cream->Rn == 15) { 4258 if (inst_cream->Rn == 15) {
4292 lop += 2 * GET_INST_SIZE(cpu); 4259 lop += 2 * cpu->GetInstructionSize();
4293 } 4260 }
4294 u32 rop = SHIFTER_OPERAND; 4261 u32 rop = SHIFTER_OPERAND;
4295 RD = lop ^ rop; 4262 RD = lop ^ rop;
4296 if (inst_cream->S && (inst_cream->Rd == 15)) { 4263 if (inst_cream->S && (inst_cream->Rd == 15)) {
4297 if (CurrentModeHasSPSR) { 4264 if (CurrentModeHasSPSR) {
4298 cpu->Cpsr = cpu->Spsr_copy; 4265 cpu->Cpsr = cpu->Spsr_copy;
4299 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 4266 cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
4300 LOAD_NZCVT; 4267 LOAD_NZCVT;
4301 } 4268 }
4302 } else if (inst_cream->S) { 4269 } else if (inst_cream->S) {
@@ -4309,7 +4276,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4309 goto DISPATCH; 4276 goto DISPATCH;
4310 } 4277 }
4311 } 4278 }
4312 cpu->Reg[15] += GET_INST_SIZE(cpu); 4279 cpu->Reg[15] += cpu->GetInstructionSize();
4313 INC_PC(sizeof(eor_inst)); 4280 INC_PC(sizeof(eor_inst));
4314 FETCH_INST; 4281 FETCH_INST;
4315 GOTO_NEXT_INST; 4282 GOTO_NEXT_INST;
@@ -4318,7 +4285,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4318 { 4285 {
4319 // Instruction not implemented 4286 // Instruction not implemented
4320 //LOG_CRITICAL(Core_ARM11, "unimplemented instruction"); 4287 //LOG_CRITICAL(Core_ARM11, "unimplemented instruction");
4321 cpu->Reg[15] += GET_INST_SIZE(cpu); 4288 cpu->Reg[15] += cpu->GetInstructionSize();
4322 INC_PC(sizeof(ldc_inst)); 4289 INC_PC(sizeof(ldc_inst));
4323 FETCH_INST; 4290 FETCH_INST;
4324 GOTO_NEXT_INST; 4291 GOTO_NEXT_INST;
@@ -4333,30 +4300,30 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4333 if (BIT(inst, 22) && !BIT(inst, 15)) { 4300 if (BIT(inst, 22) && !BIT(inst, 15)) {
4334 for (int i = 0; i < 13; i++) { 4301 for (int i = 0; i < 13; i++) {
4335 if(BIT(inst, i)) { 4302 if(BIT(inst, i)) {
4336 cpu->Reg[i] = ReadMemory32(cpu, addr); 4303 cpu->Reg[i] = cpu->ReadMemory32(addr);
4337 addr += 4; 4304 addr += 4;
4338 } 4305 }
4339 } 4306 }
4340 if (BIT(inst, 13)) { 4307 if (BIT(inst, 13)) {
4341 if (cpu->Mode == USER32MODE) 4308 if (cpu->Mode == USER32MODE)
4342 cpu->Reg[13] = ReadMemory32(cpu, addr); 4309 cpu->Reg[13] = cpu->ReadMemory32(addr);
4343 else 4310 else
4344 cpu->Reg_usr[0] = ReadMemory32(cpu, addr); 4311 cpu->Reg_usr[0] = cpu->ReadMemory32(addr);
4345 4312
4346 addr += 4; 4313 addr += 4;
4347 } 4314 }
4348 if (BIT(inst, 14)) { 4315 if (BIT(inst, 14)) {
4349 if (cpu->Mode == USER32MODE) 4316 if (cpu->Mode == USER32MODE)
4350 cpu->Reg[14] = ReadMemory32(cpu, addr); 4317 cpu->Reg[14] = cpu->ReadMemory32(addr);
4351 else 4318 else
4352 cpu->Reg_usr[1] = ReadMemory32(cpu, addr); 4319 cpu->Reg_usr[1] = cpu->ReadMemory32(addr);
4353 4320
4354 addr += 4; 4321 addr += 4;
4355 } 4322 }
4356 } else if (!BIT(inst, 22)) { 4323 } else if (!BIT(inst, 22)) {
4357 for(int i = 0; i < 16; i++ ){ 4324 for(int i = 0; i < 16; i++ ){
4358 if(BIT(inst, i)){ 4325 if(BIT(inst, i)){
4359 unsigned int ret = ReadMemory32(cpu, addr); 4326 unsigned int ret = cpu->ReadMemory32(addr);
4360 4327
4361 // For armv5t, should enter thumb when bits[0] is non-zero. 4328 // For armv5t, should enter thumb when bits[0] is non-zero.
4362 if(i == 15){ 4329 if(i == 15){
@@ -4371,18 +4338,18 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4371 } else if (BIT(inst, 22) && BIT(inst, 15)) { 4338 } else if (BIT(inst, 22) && BIT(inst, 15)) {
4372 for(int i = 0; i < 15; i++ ){ 4339 for(int i = 0; i < 15; i++ ){
4373 if(BIT(inst, i)){ 4340 if(BIT(inst, i)){
4374 cpu->Reg[i] = ReadMemory32(cpu, addr); 4341 cpu->Reg[i] = cpu->ReadMemory32(addr);
4375 addr += 4; 4342 addr += 4;
4376 } 4343 }
4377 } 4344 }
4378 4345
4379 if (CurrentModeHasSPSR) { 4346 if (CurrentModeHasSPSR) {
4380 cpu->Cpsr = cpu->Spsr_copy; 4347 cpu->Cpsr = cpu->Spsr_copy;
4381 switch_mode(cpu, cpu->Cpsr & 0x1f); 4348 cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F);
4382 LOAD_NZCVT; 4349 LOAD_NZCVT;
4383 } 4350 }
4384 4351
4385 cpu->Reg[15] = ReadMemory32(cpu, addr); 4352 cpu->Reg[15] = cpu->ReadMemory32(addr);
4386 } 4353 }
4387 4354
4388 if (BIT(inst, 15)) { 4355 if (BIT(inst, 15)) {
@@ -4390,7 +4357,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4390 goto DISPATCH; 4357 goto DISPATCH;
4391 } 4358 }
4392 } 4359 }
4393 cpu->Reg[15] += GET_INST_SIZE(cpu); 4360 cpu->Reg[15] += cpu->GetInstructionSize();
4394 INC_PC(sizeof(ldst_inst)); 4361 INC_PC(sizeof(ldst_inst));
4395 FETCH_INST; 4362 FETCH_INST;
4396 GOTO_NEXT_INST; 4363 GOTO_NEXT_INST;
@@ -4408,7 +4375,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4408 } 4375 }
4409 RD = operand2; 4376 RD = operand2;
4410 } 4377 }
4411 cpu->Reg[15] += GET_INST_SIZE(cpu); 4378 cpu->Reg[15] += cpu->GetInstructionSize();
4412 INC_PC(sizeof(sxth_inst)); 4379 INC_PC(sizeof(sxth_inst));
4413 FETCH_INST; 4380 FETCH_INST;
4414 GOTO_NEXT_INST; 4381 GOTO_NEXT_INST;
@@ -4418,7 +4385,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4418 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 4385 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4419 inst_cream->get_addr(cpu, inst_cream->inst, addr); 4386 inst_cream->get_addr(cpu, inst_cream->inst, addr);
4420 4387
4421 unsigned int value = ReadMemory32(cpu, addr); 4388 unsigned int value = cpu->ReadMemory32(addr);
4422 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; 4389 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4423 4390
4424 if (BITS(inst_cream->inst, 12, 15) == 15) { 4391 if (BITS(inst_cream->inst, 12, 15) == 15) {
@@ -4429,7 +4396,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4429 goto DISPATCH; 4396 goto DISPATCH;
4430 } 4397 }
4431 4398
4432 cpu->Reg[15] += GET_INST_SIZE(cpu); 4399 cpu->Reg[15] += cpu->GetInstructionSize();
4433 INC_PC(sizeof(ldst_inst)); 4400 INC_PC(sizeof(ldst_inst));
4434 FETCH_INST; 4401 FETCH_INST;
4435 GOTO_NEXT_INST; 4402 GOTO_NEXT_INST;
@@ -4440,7 +4407,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4440 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 4407 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4441 inst_cream->get_addr(cpu, inst_cream->inst, addr); 4408 inst_cream->get_addr(cpu, inst_cream->inst, addr);
4442 4409
4443 unsigned int value = ReadMemory32(cpu, addr); 4410 unsigned int value = cpu->ReadMemory32(addr);
4444 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; 4411 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4445 4412
4446 if (BITS(inst_cream->inst, 12, 15) == 15) { 4413 if (BITS(inst_cream->inst, 12, 15) == 15) {
@@ -4451,7 +4418,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4451 goto DISPATCH; 4418 goto DISPATCH;
4452 } 4419 }
4453 } 4420 }
4454 cpu->Reg[15] += GET_INST_SIZE(cpu); 4421 cpu->Reg[15] += cpu->GetInstructionSize();
4455 INC_PC(sizeof(ldst_inst)); 4422 INC_PC(sizeof(ldst_inst));
4456 FETCH_INST; 4423 FETCH_INST;
4457 GOTO_NEXT_INST; 4424 GOTO_NEXT_INST;
@@ -4462,7 +4429,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4462 uxth_inst* inst_cream = (uxth_inst*)inst_base->component; 4429 uxth_inst* inst_cream = (uxth_inst*)inst_base->component;
4463 RD = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff; 4430 RD = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff;
4464 } 4431 }
4465 cpu->Reg[15] += GET_INST_SIZE(cpu); 4432 cpu->Reg[15] += cpu->GetInstructionSize();
4466 INC_PC(sizeof(uxth_inst)); 4433 INC_PC(sizeof(uxth_inst));
4467 FETCH_INST; 4434 FETCH_INST;
4468 GOTO_NEXT_INST; 4435 GOTO_NEXT_INST;
@@ -4475,7 +4442,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4475 4442
4476 RD = RN + operand2; 4443 RD = RN + operand2;
4477 } 4444 }
4478 cpu->Reg[15] += GET_INST_SIZE(cpu); 4445 cpu->Reg[15] += cpu->GetInstructionSize();
4479 INC_PC(sizeof(uxtah_inst)); 4446 INC_PC(sizeof(uxtah_inst));
4480 FETCH_INST; 4447 FETCH_INST;
4481 GOTO_NEXT_INST; 4448 GOTO_NEXT_INST;
@@ -4493,7 +4460,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4493 goto DISPATCH; 4460 goto DISPATCH;
4494 } 4461 }
4495 } 4462 }
4496 cpu->Reg[15] += GET_INST_SIZE(cpu); 4463 cpu->Reg[15] += cpu->GetInstructionSize();
4497 INC_PC(sizeof(ldst_inst)); 4464 INC_PC(sizeof(ldst_inst));
4498 FETCH_INST; 4465 FETCH_INST;
4499 GOTO_NEXT_INST; 4466 GOTO_NEXT_INST;
@@ -4511,7 +4478,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4511 goto DISPATCH; 4478 goto DISPATCH;
4512 } 4479 }
4513 } 4480 }
4514 cpu->Reg[15] += GET_INST_SIZE(cpu); 4481 cpu->Reg[15] += cpu->GetInstructionSize();
4515 INC_PC(sizeof(ldst_inst)); 4482 INC_PC(sizeof(ldst_inst));
4516 FETCH_INST; 4483 FETCH_INST;
4517 GOTO_NEXT_INST; 4484 GOTO_NEXT_INST;
@@ -4525,8 +4492,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4525 4492
4526 // The 3DS doesn't have LPAE (Large Physical Access Extension), so it 4493 // The 3DS doesn't have LPAE (Large Physical Access Extension), so it
4527 // wouldn't do this as a single read. 4494 // wouldn't do this as a single read.
4528 cpu->Reg[BITS(inst_cream->inst, 12, 15) + 0] = ReadMemory32(cpu, addr); 4495 cpu->Reg[BITS(inst_cream->inst, 12, 15) + 0] = cpu->ReadMemory32(addr);
4529 cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1] = ReadMemory32(cpu, addr + 4); 4496 cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1] = cpu->ReadMemory32(addr + 4);
4530 4497
4531 // No dispatch since this operation should not modify R15 4498 // No dispatch since this operation should not modify R15
4532 } 4499 }
@@ -4542,16 +4509,15 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4542 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; 4509 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
4543 unsigned int read_addr = RN; 4510 unsigned int read_addr = RN;
4544 4511
4545 add_exclusive_addr(cpu, read_addr); 4512 cpu->SetExclusiveMemoryAddress(read_addr);
4546 cpu->exclusive_state = 1;
4547 4513
4548 RD = ReadMemory32(cpu, read_addr); 4514 RD = cpu->ReadMemory32(read_addr);
4549 if (inst_cream->Rd == 15) { 4515 if (inst_cream->Rd == 15) {
4550 INC_PC(sizeof(generic_arm_inst)); 4516 INC_PC(sizeof(generic_arm_inst));
4551 goto DISPATCH; 4517 goto DISPATCH;
4552 } 4518 }
4553 } 4519 }
4554 cpu->Reg[15] += GET_INST_SIZE(cpu); 4520 cpu->Reg[15] += cpu->GetInstructionSize();
4555 INC_PC(sizeof(generic_arm_inst)); 4521 INC_PC(sizeof(generic_arm_inst));
4556 FETCH_INST; 4522 FETCH_INST;
4557 GOTO_NEXT_INST; 4523 GOTO_NEXT_INST;
@@ -4562,8 +4528,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4562 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; 4528 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
4563 unsigned int read_addr = RN; 4529 unsigned int read_addr = RN;
4564 4530
4565 add_exclusive_addr(cpu, read_addr); 4531 cpu->SetExclusiveMemoryAddress(read_addr);
4566 cpu->exclusive_state = 1;
4567 4532
4568 RD = Memory::Read8(read_addr); 4533 RD = Memory::Read8(read_addr);
4569 if (inst_cream->Rd == 15) { 4534 if (inst_cream->Rd == 15) {
@@ -4571,7 +4536,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4571 goto DISPATCH; 4536 goto DISPATCH;
4572 } 4537 }
4573 } 4538 }
4574 cpu->Reg[15] += GET_INST_SIZE(cpu); 4539 cpu->Reg[15] += cpu->GetInstructionSize();
4575 INC_PC(sizeof(generic_arm_inst)); 4540 INC_PC(sizeof(generic_arm_inst));
4576 FETCH_INST; 4541 FETCH_INST;
4577 GOTO_NEXT_INST; 4542 GOTO_NEXT_INST;
@@ -4582,16 +4547,15 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4582 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; 4547 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
4583 unsigned int read_addr = RN; 4548 unsigned int read_addr = RN;
4584 4549
4585 add_exclusive_addr(cpu, read_addr); 4550 cpu->SetExclusiveMemoryAddress(read_addr);
4586 cpu->exclusive_state = 1;
4587 4551
4588 RD = ReadMemory16(cpu, read_addr); 4552 RD = cpu->ReadMemory16(read_addr);
4589 if (inst_cream->Rd == 15) { 4553 if (inst_cream->Rd == 15) {
4590 INC_PC(sizeof(generic_arm_inst)); 4554 INC_PC(sizeof(generic_arm_inst));
4591 goto DISPATCH; 4555 goto DISPATCH;
4592 } 4556 }
4593 } 4557 }
4594 cpu->Reg[15] += GET_INST_SIZE(cpu); 4558 cpu->Reg[15] += cpu->GetInstructionSize();
4595 INC_PC(sizeof(generic_arm_inst)); 4559 INC_PC(sizeof(generic_arm_inst));
4596 FETCH_INST; 4560 FETCH_INST;
4597 GOTO_NEXT_INST; 4561 GOTO_NEXT_INST;
@@ -4602,18 +4566,17 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4602 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; 4566 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
4603 unsigned int read_addr = RN; 4567 unsigned int read_addr = RN;
4604 4568
4605 add_exclusive_addr(cpu, read_addr); 4569 cpu->SetExclusiveMemoryAddress(read_addr);
4606 cpu->exclusive_state = 1;
4607 4570
4608 RD = ReadMemory32(cpu, read_addr); 4571 RD = cpu->ReadMemory32(read_addr);
4609 RD2 = ReadMemory32(cpu, read_addr + 4); 4572 RD2 = cpu->ReadMemory32(read_addr + 4);
4610 4573
4611 if (inst_cream->Rd == 15) { 4574 if (inst_cream->Rd == 15) {
4612 INC_PC(sizeof(generic_arm_inst)); 4575 INC_PC(sizeof(generic_arm_inst));
4613 goto DISPATCH; 4576 goto DISPATCH;
4614 } 4577 }
4615 } 4578 }
4616 cpu->Reg[15] += GET_INST_SIZE(cpu); 4579 cpu->Reg[15] += cpu->GetInstructionSize();
4617 INC_PC(sizeof(generic_arm_inst)); 4580 INC_PC(sizeof(generic_arm_inst));
4618 FETCH_INST; 4581 FETCH_INST;
4619 GOTO_NEXT_INST; 4582 GOTO_NEXT_INST;
@@ -4624,13 +4587,13 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4624 ldst_inst* inst_cream = (ldst_inst*)inst_base->component; 4587 ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
4625 inst_cream->get_addr(cpu, inst_cream->inst, addr); 4588 inst_cream->get_addr(cpu, inst_cream->inst, addr);
4626 4589
4627 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = ReadMemory16(cpu, addr); 4590 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = cpu->ReadMemory16(addr);
4628 if (BITS(inst_cream->inst, 12, 15) == 15) { 4591 if (BITS(inst_cream->inst, 12, 15) == 15) {
4629 INC_PC(sizeof(ldst_inst)); 4592 INC_PC(sizeof(ldst_inst));
4630 goto DISPATCH; 4593 goto DISPATCH;
4631 } 4594 }
4632 } 4595 }
4633 cpu->Reg[15] += GET_INST_SIZE(cpu); 4596 cpu->Reg[15] += cpu->GetInstructionSize();
4634 INC_PC(sizeof(ldst_inst)); 4597 INC_PC(sizeof(ldst_inst));
4635 FETCH_INST; 4598 FETCH_INST;
4636 GOTO_NEXT_INST; 4599 GOTO_NEXT_INST;
@@ -4650,7 +4613,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4650 goto DISPATCH; 4613 goto DISPATCH;
4651 } 4614 }
4652 } 4615 }
4653 cpu->Reg[15] += GET_INST_SIZE(cpu); 4616 cpu->Reg[15] += cpu->GetInstructionSize();
4654 INC_PC(sizeof(ldst_inst)); 4617 INC_PC(sizeof(ldst_inst));
4655 FETCH_INST; 4618 FETCH_INST;
4656 GOTO_NEXT_INST; 4619 GOTO_NEXT_INST;
@@ -4661,7 +4624,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4661 ldst_inst* inst_cream = (ldst_inst*)inst_base->component; 4624 ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
4662 inst_cream->get_addr(cpu, inst_cream->inst, addr); 4625 inst_cream->get_addr(cpu, inst_cream->inst, addr);
4663 4626
4664 unsigned int value = ReadMemory16(cpu, addr); 4627 unsigned int value = cpu->ReadMemory16(addr);
4665 if (BIT(value, 15)) { 4628 if (BIT(value, 15)) {
4666 value |= 0xffff0000; 4629 value |= 0xffff0000;
4667 } 4630 }
@@ -4671,7 +4634,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4671 goto DISPATCH; 4634 goto DISPATCH;
4672 } 4635 }
4673 } 4636 }
4674 cpu->Reg[15] += GET_INST_SIZE(cpu); 4637 cpu->Reg[15] += cpu->GetInstructionSize();
4675 INC_PC(sizeof(ldst_inst)); 4638 INC_PC(sizeof(ldst_inst));
4676 FETCH_INST; 4639 FETCH_INST;
4677 GOTO_NEXT_INST; 4640 GOTO_NEXT_INST;
@@ -4682,7 +4645,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4682 ldst_inst* inst_cream = (ldst_inst*)inst_base->component; 4645 ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
4683 inst_cream->get_addr(cpu, inst_cream->inst, addr); 4646 inst_cream->get_addr(cpu, inst_cream->inst, addr);
4684 4647
4685 unsigned int value = ReadMemory32(cpu, addr); 4648 unsigned int value = cpu->ReadMemory32(addr);
4686 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; 4649 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4687 4650
4688 if (BITS(inst_cream->inst, 12, 15) == 15) { 4651 if (BITS(inst_cream->inst, 12, 15) == 15) {
@@ -4690,7 +4653,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4690 goto DISPATCH; 4653 goto DISPATCH;
4691 } 4654 }
4692 } 4655 }
4693 cpu->Reg[15] += GET_INST_SIZE(cpu); 4656 cpu->Reg[15] += cpu->GetInstructionSize();
4694 INC_PC(sizeof(ldst_inst)); 4657 INC_PC(sizeof(ldst_inst));
4695 FETCH_INST; 4658 FETCH_INST;
4696 GOTO_NEXT_INST; 4659 GOTO_NEXT_INST;
@@ -4705,10 +4668,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4705 DEBUG_MSG; 4668 DEBUG_MSG;
4706 } else { 4669 } else {
4707 if (inst_cream->cp_num == 15) 4670 if (inst_cream->cp_num == 15)
4708 WriteCP15Register(cpu, RD, CRn, OPCODE_1, CRm, OPCODE_2); 4671 cpu->WriteCP15Register(RD, CRn, OPCODE_1, CRm, OPCODE_2);
4709 } 4672 }
4710 } 4673 }
4711 cpu->Reg[15] += GET_INST_SIZE(cpu); 4674 cpu->Reg[15] += cpu->GetInstructionSize();
4712 INC_PC(sizeof(mcr_inst)); 4675 INC_PC(sizeof(mcr_inst));
4713 FETCH_INST; 4676 FETCH_INST;
4714 GOTO_NEXT_INST; 4677 GOTO_NEXT_INST;
@@ -4725,7 +4688,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4725 inst_cream->cp_num, inst_cream->crm, inst_cream->opcode_1, inst_cream->rt, inst_cream->rt2); 4688 inst_cream->cp_num, inst_cream->crm, inst_cream->opcode_1, inst_cream->rt, inst_cream->rt2);
4726 } 4689 }
4727 4690
4728 cpu->Reg[15] += GET_INST_SIZE(cpu); 4691 cpu->Reg[15] += cpu->GetInstructionSize();
4729 INC_PC(sizeof(mcrr_inst)); 4692 INC_PC(sizeof(mcrr_inst));
4730 FETCH_INST; 4693 FETCH_INST;
4731 GOTO_NEXT_INST; 4694 GOTO_NEXT_INST;
@@ -4750,7 +4713,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4750 goto DISPATCH; 4713 goto DISPATCH;
4751 } 4714 }
4752 } 4715 }
4753 cpu->Reg[15] += GET_INST_SIZE(cpu); 4716 cpu->Reg[15] += cpu->GetInstructionSize();
4754 INC_PC(sizeof(mla_inst)); 4717 INC_PC(sizeof(mla_inst));
4755 FETCH_INST; 4718 FETCH_INST;
4756 GOTO_NEXT_INST; 4719 GOTO_NEXT_INST;
@@ -4764,7 +4727,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4764 if (inst_cream->S && (inst_cream->Rd == 15)) { 4727 if (inst_cream->S && (inst_cream->Rd == 15)) {
4765 if (CurrentModeHasSPSR) { 4728 if (CurrentModeHasSPSR) {
4766 cpu->Cpsr = cpu->Spsr_copy; 4729 cpu->Cpsr = cpu->Spsr_copy;
4767 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 4730 cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
4768 LOAD_NZCVT; 4731 LOAD_NZCVT;
4769 } 4732 }
4770 } else if (inst_cream->S) { 4733 } else if (inst_cream->S) {
@@ -4777,7 +4740,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4777 goto DISPATCH; 4740 goto DISPATCH;
4778 } 4741 }
4779 } 4742 }
4780 cpu->Reg[15] += GET_INST_SIZE(cpu); 4743 cpu->Reg[15] += cpu->GetInstructionSize();
4781 INC_PC(sizeof(mov_inst)); 4744 INC_PC(sizeof(mov_inst));
4782 FETCH_INST; 4745 FETCH_INST;
4783 GOTO_NEXT_INST; 4746 GOTO_NEXT_INST;
@@ -4798,10 +4761,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4798 goto END; 4761 goto END;
4799 } else { 4762 } else {
4800 if (inst_cream->cp_num == 15) 4763 if (inst_cream->cp_num == 15)
4801 RD = ReadCP15Register(cpu, CRn, OPCODE_1, CRm, OPCODE_2); 4764 RD = cpu->ReadCP15Register(CRn, OPCODE_1, CRm, OPCODE_2);
4802 } 4765 }
4803 } 4766 }
4804 cpu->Reg[15] += GET_INST_SIZE(cpu); 4767 cpu->Reg[15] += cpu->GetInstructionSize();
4805 INC_PC(sizeof(mrc_inst)); 4768 INC_PC(sizeof(mrc_inst));
4806 FETCH_INST; 4769 FETCH_INST;
4807 GOTO_NEXT_INST; 4770 GOTO_NEXT_INST;
@@ -4818,7 +4781,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4818 inst_cream->cp_num, inst_cream->crm, inst_cream->opcode_1, inst_cream->rt, inst_cream->rt2); 4781 inst_cream->cp_num, inst_cream->crm, inst_cream->opcode_1, inst_cream->rt, inst_cream->rt2);
4819 } 4782 }
4820 4783
4821 cpu->Reg[15] += GET_INST_SIZE(cpu); 4784 cpu->Reg[15] += cpu->GetInstructionSize();
4822 INC_PC(sizeof(mcrr_inst)); 4785 INC_PC(sizeof(mcrr_inst));
4823 FETCH_INST; 4786 FETCH_INST;
4824 GOTO_NEXT_INST; 4787 GOTO_NEXT_INST;
@@ -4836,7 +4799,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4836 RD = cpu->Cpsr; 4799 RD = cpu->Cpsr;
4837 } 4800 }
4838 } 4801 }
4839 cpu->Reg[15] += GET_INST_SIZE(cpu); 4802 cpu->Reg[15] += cpu->GetInstructionSize();
4840 INC_PC(sizeof(mrs_inst)); 4803 INC_PC(sizeof(mrs_inst));
4841 FETCH_INST; 4804 FETCH_INST;
4842 GOTO_NEXT_INST; 4805 GOTO_NEXT_INST;
@@ -4859,7 +4822,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4859 | (BIT(inst, 18) ? 0xff0000 : 0) | (BIT(inst, 19) ? 0xff000000 : 0); 4822 | (BIT(inst, 18) ? 0xff0000 : 0) | (BIT(inst, 19) ? 0xff000000 : 0);
4860 uint32_t mask = 0; 4823 uint32_t mask = 0;
4861 if (!inst_cream->R) { 4824 if (!inst_cream->R) {
4862 if (InAPrivilegedMode(cpu)) { 4825 if (cpu->InAPrivilegedMode()) {
4863 if ((operand & StateMask) != 0) { 4826 if ((operand & StateMask) != 0) {
4864 /// UNPREDICTABLE 4827 /// UNPREDICTABLE
4865 DEBUG_MSG; 4828 DEBUG_MSG;
@@ -4871,7 +4834,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4871 SAVE_NZCVT; 4834 SAVE_NZCVT;
4872 4835
4873 cpu->Cpsr = (cpu->Cpsr & ~mask) | (operand & mask); 4836 cpu->Cpsr = (cpu->Cpsr & ~mask) | (operand & mask);
4874 switch_mode(cpu, cpu->Cpsr & 0x1f); 4837 cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F);
4875 LOAD_NZCVT; 4838 LOAD_NZCVT;
4876 } else { 4839 } else {
4877 if (CurrentModeHasSPSR) { 4840 if (CurrentModeHasSPSR) {
@@ -4880,7 +4843,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4880 } 4843 }
4881 } 4844 }
4882 } 4845 }
4883 cpu->Reg[15] += GET_INST_SIZE(cpu); 4846 cpu->Reg[15] += cpu->GetInstructionSize();
4884 INC_PC(sizeof(msr_inst)); 4847 INC_PC(sizeof(msr_inst));
4885 FETCH_INST; 4848 FETCH_INST;
4886 GOTO_NEXT_INST; 4849 GOTO_NEXT_INST;
@@ -4902,7 +4865,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4902 goto DISPATCH; 4865 goto DISPATCH;
4903 } 4866 }
4904 } 4867 }
4905 cpu->Reg[15] += GET_INST_SIZE(cpu); 4868 cpu->Reg[15] += cpu->GetInstructionSize();
4906 INC_PC(sizeof(mul_inst)); 4869 INC_PC(sizeof(mul_inst));
4907 FETCH_INST; 4870 FETCH_INST;
4908 GOTO_NEXT_INST; 4871 GOTO_NEXT_INST;
@@ -4917,7 +4880,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4917 if (inst_cream->S && (inst_cream->Rd == 15)) { 4880 if (inst_cream->S && (inst_cream->Rd == 15)) {
4918 if (CurrentModeHasSPSR) { 4881 if (CurrentModeHasSPSR) {
4919 cpu->Cpsr = cpu->Spsr_copy; 4882 cpu->Cpsr = cpu->Spsr_copy;
4920 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 4883 cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
4921 LOAD_NZCVT; 4884 LOAD_NZCVT;
4922 } 4885 }
4923 } else if (inst_cream->S) { 4886 } else if (inst_cream->S) {
@@ -4930,7 +4893,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4930 goto DISPATCH; 4893 goto DISPATCH;
4931 } 4894 }
4932 } 4895 }
4933 cpu->Reg[15] += GET_INST_SIZE(cpu); 4896 cpu->Reg[15] += cpu->GetInstructionSize();
4934 INC_PC(sizeof(mvn_inst)); 4897 INC_PC(sizeof(mvn_inst));
4935 FETCH_INST; 4898 FETCH_INST;
4936 GOTO_NEXT_INST; 4899 GOTO_NEXT_INST;
@@ -4947,7 +4910,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4947 if (inst_cream->S && (inst_cream->Rd == 15)) { 4910 if (inst_cream->S && (inst_cream->Rd == 15)) {
4948 if (CurrentModeHasSPSR) { 4911 if (CurrentModeHasSPSR) {
4949 cpu->Cpsr = cpu->Spsr_copy; 4912 cpu->Cpsr = cpu->Spsr_copy;
4950 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 4913 cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
4951 LOAD_NZCVT; 4914 LOAD_NZCVT;
4952 } 4915 }
4953 } else if (inst_cream->S) { 4916 } else if (inst_cream->S) {
@@ -4960,7 +4923,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4960 goto DISPATCH; 4923 goto DISPATCH;
4961 } 4924 }
4962 } 4925 }
4963 cpu->Reg[15] += GET_INST_SIZE(cpu); 4926 cpu->Reg[15] += cpu->GetInstructionSize();
4964 INC_PC(sizeof(orr_inst)); 4927 INC_PC(sizeof(orr_inst));
4965 FETCH_INST; 4928 FETCH_INST;
4966 GOTO_NEXT_INST; 4929 GOTO_NEXT_INST;
@@ -4968,7 +4931,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4968 4931
4969 NOP_INST: 4932 NOP_INST:
4970 { 4933 {
4971 cpu->Reg[15] += GET_INST_SIZE(cpu); 4934 cpu->Reg[15] += cpu->GetInstructionSize();
4972 INC_PC_STUB; 4935 INC_PC_STUB;
4973 FETCH_INST; 4936 FETCH_INST;
4974 GOTO_NEXT_INST; 4937 GOTO_NEXT_INST;
@@ -4980,7 +4943,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4980 pkh_inst *inst_cream = (pkh_inst *)inst_base->component; 4943 pkh_inst *inst_cream = (pkh_inst *)inst_base->component;
4981 RD = (RN & 0xFFFF) | ((RM << inst_cream->imm) & 0xFFFF0000); 4944 RD = (RN & 0xFFFF) | ((RM << inst_cream->imm) & 0xFFFF0000);
4982 } 4945 }
4983 cpu->Reg[15] += GET_INST_SIZE(cpu); 4946 cpu->Reg[15] += cpu->GetInstructionSize();
4984 INC_PC(sizeof(pkh_inst)); 4947 INC_PC(sizeof(pkh_inst));
4985 FETCH_INST; 4948 FETCH_INST;
4986 GOTO_NEXT_INST; 4949 GOTO_NEXT_INST;
@@ -4993,7 +4956,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4993 int shift_imm = inst_cream->imm ? inst_cream->imm : 31; 4956 int shift_imm = inst_cream->imm ? inst_cream->imm : 31;
4994 RD = ((static_cast<s32>(RM) >> shift_imm) & 0xFFFF) | (RN & 0xFFFF0000); 4957 RD = ((static_cast<s32>(RM) >> shift_imm) & 0xFFFF) | (RN & 0xFFFF0000);
4995 } 4958 }
4996 cpu->Reg[15] += GET_INST_SIZE(cpu); 4959 cpu->Reg[15] += cpu->GetInstructionSize();
4997 INC_PC(sizeof(pkh_inst)); 4960 INC_PC(sizeof(pkh_inst));
4998 FETCH_INST; 4961 FETCH_INST;
4999 GOTO_NEXT_INST; 4962 GOTO_NEXT_INST;
@@ -5003,7 +4966,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5003 { 4966 {
5004 // Not implemented. PLD is a hint instruction, so it's optional. 4967 // Not implemented. PLD is a hint instruction, so it's optional.
5005 4968
5006 cpu->Reg[15] += GET_INST_SIZE(cpu); 4969 cpu->Reg[15] += cpu->GetInstructionSize();
5007 INC_PC(sizeof(pld_inst)); 4970 INC_PC(sizeof(pld_inst));
5008 FETCH_INST; 4971 FETCH_INST;
5009 GOTO_NEXT_INST; 4972 GOTO_NEXT_INST;
@@ -5076,7 +5039,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5076 RD = result; 5039 RD = result;
5077 } 5040 }
5078 5041
5079 cpu->Reg[15] += GET_INST_SIZE(cpu); 5042 cpu->Reg[15] += cpu->GetInstructionSize();
5080 INC_PC(sizeof(generic_arm_inst)); 5043 INC_PC(sizeof(generic_arm_inst));
5081 FETCH_INST; 5044 FETCH_INST;
5082 GOTO_NEXT_INST; 5045 GOTO_NEXT_INST;
@@ -5138,7 +5101,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5138 RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); 5101 RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);
5139 } 5102 }
5140 5103
5141 cpu->Reg[15] += GET_INST_SIZE(cpu); 5104 cpu->Reg[15] += cpu->GetInstructionSize();
5142 INC_PC(sizeof(generic_arm_inst)); 5105 INC_PC(sizeof(generic_arm_inst));
5143 FETCH_INST; 5106 FETCH_INST;
5144 GOTO_NEXT_INST; 5107 GOTO_NEXT_INST;
@@ -5171,7 +5134,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5171 } 5134 }
5172 } 5135 }
5173 5136
5174 cpu->Reg[15] += GET_INST_SIZE(cpu); 5137 cpu->Reg[15] += cpu->GetInstructionSize();
5175 INC_PC(sizeof(rev_inst)); 5138 INC_PC(sizeof(rev_inst));
5176 FETCH_INST; 5139 FETCH_INST;
5177 GOTO_NEXT_INST; 5140 GOTO_NEXT_INST;
@@ -5185,8 +5148,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5185 u32 address = 0; 5148 u32 address = 0;
5186 inst_cream->get_addr(cpu, inst_cream->inst, address); 5149 inst_cream->get_addr(cpu, inst_cream->inst, address);
5187 5150
5188 cpu->Cpsr = ReadMemory32(cpu, address); 5151 cpu->Cpsr = cpu->ReadMemory32(address);
5189 cpu->Reg[15] = ReadMemory32(cpu, address + 4); 5152 cpu->Reg[15] = cpu->ReadMemory32(address + 4);
5190 5153
5191 INC_PC(sizeof(ldst_inst)); 5154 INC_PC(sizeof(ldst_inst));
5192 goto DISPATCH; 5155 goto DISPATCH;
@@ -5199,7 +5162,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5199 5162
5200 u32 rn_val = RN; 5163 u32 rn_val = RN;
5201 if (inst_cream->Rn == 15) 5164 if (inst_cream->Rn == 15)
5202 rn_val += 2 * GET_INST_SIZE(cpu); 5165 rn_val += 2 * cpu->GetInstructionSize();
5203 5166
5204 bool carry; 5167 bool carry;
5205 bool overflow; 5168 bool overflow;
@@ -5208,7 +5171,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5208 if (inst_cream->S && (inst_cream->Rd == 15)) { 5171 if (inst_cream->S && (inst_cream->Rd == 15)) {
5209 if (CurrentModeHasSPSR) { 5172 if (CurrentModeHasSPSR) {
5210 cpu->Cpsr = cpu->Spsr_copy; 5173 cpu->Cpsr = cpu->Spsr_copy;
5211 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 5174 cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
5212 LOAD_NZCVT; 5175 LOAD_NZCVT;
5213 } 5176 }
5214 } else if (inst_cream->S) { 5177 } else if (inst_cream->S) {
@@ -5222,7 +5185,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5222 goto DISPATCH; 5185 goto DISPATCH;
5223 } 5186 }
5224 } 5187 }
5225 cpu->Reg[15] += GET_INST_SIZE(cpu); 5188 cpu->Reg[15] += cpu->GetInstructionSize();
5226 INC_PC(sizeof(rsb_inst)); 5189 INC_PC(sizeof(rsb_inst));
5227 FETCH_INST; 5190 FETCH_INST;
5228 GOTO_NEXT_INST; 5191 GOTO_NEXT_INST;
@@ -5239,7 +5202,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5239 if (inst_cream->S && (inst_cream->Rd == 15)) { 5202 if (inst_cream->S && (inst_cream->Rd == 15)) {
5240 if (CurrentModeHasSPSR) { 5203 if (CurrentModeHasSPSR) {
5241 cpu->Cpsr = cpu->Spsr_copy; 5204 cpu->Cpsr = cpu->Spsr_copy;
5242 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 5205 cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
5243 LOAD_NZCVT; 5206 LOAD_NZCVT;
5244 } 5207 }
5245 } else if (inst_cream->S) { 5208 } else if (inst_cream->S) {
@@ -5253,7 +5216,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5253 goto DISPATCH; 5216 goto DISPATCH;
5254 } 5217 }
5255 } 5218 }
5256 cpu->Reg[15] += GET_INST_SIZE(cpu); 5219 cpu->Reg[15] += cpu->GetInstructionSize();
5257 INC_PC(sizeof(rsc_inst)); 5220 INC_PC(sizeof(rsc_inst));
5258 FETCH_INST; 5221 FETCH_INST;
5259 GOTO_NEXT_INST; 5222 GOTO_NEXT_INST;
@@ -5361,7 +5324,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5361 } 5324 }
5362 } 5325 }
5363 5326
5364 cpu->Reg[15] += GET_INST_SIZE(cpu); 5327 cpu->Reg[15] += cpu->GetInstructionSize();
5365 INC_PC(sizeof(generic_arm_inst)); 5328 INC_PC(sizeof(generic_arm_inst));
5366 FETCH_INST; 5329 FETCH_INST;
5367 GOTO_NEXT_INST; 5330 GOTO_NEXT_INST;
@@ -5379,7 +5342,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5379 if (inst_cream->S && (inst_cream->Rd == 15)) { 5342 if (inst_cream->S && (inst_cream->Rd == 15)) {
5380 if (CurrentModeHasSPSR) { 5343 if (CurrentModeHasSPSR) {
5381 cpu->Cpsr = cpu->Spsr_copy; 5344 cpu->Cpsr = cpu->Spsr_copy;
5382 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 5345 cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
5383 LOAD_NZCVT; 5346 LOAD_NZCVT;
5384 } 5347 }
5385 } else if (inst_cream->S) { 5348 } else if (inst_cream->S) {
@@ -5393,7 +5356,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5393 goto DISPATCH; 5356 goto DISPATCH;
5394 } 5357 }
5395 } 5358 }
5396 cpu->Reg[15] += GET_INST_SIZE(cpu); 5359 cpu->Reg[15] += cpu->GetInstructionSize();
5397 INC_PC(sizeof(sbc_inst)); 5360 INC_PC(sizeof(sbc_inst));
5398 FETCH_INST; 5361 FETCH_INST;
5399 GOTO_NEXT_INST; 5362 GOTO_NEXT_INST;
@@ -5432,7 +5395,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5432 RD = result; 5395 RD = result;
5433 } 5396 }
5434 5397
5435 cpu->Reg[15] += GET_INST_SIZE(cpu); 5398 cpu->Reg[15] += cpu->GetInstructionSize();
5436 INC_PC(sizeof(generic_arm_inst)); 5399 INC_PC(sizeof(generic_arm_inst));
5437 FETCH_INST; 5400 FETCH_INST;
5438 GOTO_NEXT_INST; 5401 GOTO_NEXT_INST;
@@ -5451,7 +5414,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5451 5414
5452 LOG_WARNING(Core_ARM11, "SETEND %s executed", big_endian ? "BE" : "LE"); 5415 LOG_WARNING(Core_ARM11, "SETEND %s executed", big_endian ? "BE" : "LE");
5453 5416
5454 cpu->Reg[15] += GET_INST_SIZE(cpu); 5417 cpu->Reg[15] += cpu->GetInstructionSize();
5455 INC_PC(sizeof(setend_inst)); 5418 INC_PC(sizeof(setend_inst));
5456 FETCH_INST; 5419 FETCH_INST;
5457 GOTO_NEXT_INST; 5420 GOTO_NEXT_INST;
@@ -5464,7 +5427,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5464 LOG_TRACE(Core_ARM11, "SEV executed."); 5427 LOG_TRACE(Core_ARM11, "SEV executed.");
5465 } 5428 }
5466 5429
5467 cpu->Reg[15] += GET_INST_SIZE(cpu); 5430 cpu->Reg[15] += cpu->GetInstructionSize();
5468 INC_PC_STUB; 5431 INC_PC_STUB;
5469 FETCH_INST; 5432 FETCH_INST;
5470 GOTO_NEXT_INST; 5433 GOTO_NEXT_INST;
@@ -5536,7 +5499,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5536 } 5499 }
5537 } 5500 }
5538 5501
5539 cpu->Reg[15] += GET_INST_SIZE(cpu); 5502 cpu->Reg[15] += cpu->GetInstructionSize();
5540 INC_PC(sizeof(generic_arm_inst)); 5503 INC_PC(sizeof(generic_arm_inst));
5541 FETCH_INST; 5504 FETCH_INST;
5542 GOTO_NEXT_INST; 5505 GOTO_NEXT_INST;
@@ -5561,7 +5524,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5561 if (AddOverflow(operand1 * operand2, RN, RD)) 5524 if (AddOverflow(operand1 * operand2, RN, RD))
5562 cpu->Cpsr |= (1 << 27); 5525 cpu->Cpsr |= (1 << 27);
5563 } 5526 }
5564 cpu->Reg[15] += GET_INST_SIZE(cpu); 5527 cpu->Reg[15] += cpu->GetInstructionSize();
5565 INC_PC(sizeof(smla_inst)); 5528 INC_PC(sizeof(smla_inst));
5566 FETCH_INST; 5529 FETCH_INST;
5567 GOTO_NEXT_INST; 5530 GOTO_NEXT_INST;
@@ -5617,7 +5580,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5617 } 5580 }
5618 } 5581 }
5619 5582
5620 cpu->Reg[15] += GET_INST_SIZE(cpu); 5583 cpu->Reg[15] += cpu->GetInstructionSize();
5621 INC_PC(sizeof(smlad_inst)); 5584 INC_PC(sizeof(smlad_inst));
5622 FETCH_INST; 5585 FETCH_INST;
5623 GOTO_NEXT_INST; 5586 GOTO_NEXT_INST;
@@ -5646,7 +5609,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5646 cpu->ZFlag = (RDHI == 0 && RDLO == 0); 5609 cpu->ZFlag = (RDHI == 0 && RDLO == 0);
5647 } 5610 }
5648 } 5611 }
5649 cpu->Reg[15] += GET_INST_SIZE(cpu); 5612 cpu->Reg[15] += cpu->GetInstructionSize();
5650 INC_PC(sizeof(umlal_inst)); 5613 INC_PC(sizeof(umlal_inst));
5651 FETCH_INST; 5614 FETCH_INST;
5652 GOTO_NEXT_INST; 5615 GOTO_NEXT_INST;
@@ -5676,7 +5639,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5676 RDHI = ((dest >> 32) & 0xFFFFFFFF); 5639 RDHI = ((dest >> 32) & 0xFFFFFFFF);
5677 } 5640 }
5678 5641
5679 cpu->Reg[15] += GET_INST_SIZE(cpu); 5642 cpu->Reg[15] += cpu->GetInstructionSize();
5680 INC_PC(sizeof(smlalxy_inst)); 5643 INC_PC(sizeof(smlalxy_inst));
5681 FETCH_INST; 5644 FETCH_INST;
5682 GOTO_NEXT_INST; 5645 GOTO_NEXT_INST;
@@ -5695,13 +5658,13 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5695 const s16 operand2 = (high) ? ((rm_val >> 16) & 0xFFFF) : (rm_val & 0xFFFF); 5658 const s16 operand2 = (high) ? ((rm_val >> 16) & 0xFFFF) : (rm_val & 0xFFFF);
5696 const s64 result = (s64)(s32)rn_val * (s64)(s32)operand2 + ((s64)(s32)ra_val << 16); 5659 const s64 result = (s64)(s32)rn_val * (s64)(s32)operand2 + ((s64)(s32)ra_val << 16);
5697 5660
5698 RD = (result & (0xFFFFFFFFFFFFFFFFLL >> 15)) >> 16; 5661 RD = BITS(result, 16, 47);
5699 5662
5700 if ((result >> 16) != (s32)RD) 5663 if ((result >> 16) != (s32)RD)
5701 cpu->Cpsr |= (1 << 27); 5664 cpu->Cpsr |= (1 << 27);
5702 } 5665 }
5703 5666
5704 cpu->Reg[15] += GET_INST_SIZE(cpu); 5667 cpu->Reg[15] += cpu->GetInstructionSize();
5705 INC_PC(sizeof(smlad_inst)); 5668 INC_PC(sizeof(smlad_inst));
5706 FETCH_INST; 5669 FETCH_INST;
5707 GOTO_NEXT_INST; 5670 GOTO_NEXT_INST;
@@ -5739,7 +5702,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5739 RDHI = ((result >> 32) & 0xFFFFFFFF); 5702 RDHI = ((result >> 32) & 0xFFFFFFFF);
5740 } 5703 }
5741 5704
5742 cpu->Reg[15] += GET_INST_SIZE(cpu); 5705 cpu->Reg[15] += cpu->GetInstructionSize();
5743 INC_PC(sizeof(smlald_inst)); 5706 INC_PC(sizeof(smlald_inst));
5744 FETCH_INST; 5707 FETCH_INST;
5745 GOTO_NEXT_INST; 5708 GOTO_NEXT_INST;
@@ -5775,7 +5738,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5775 RD = ((result >> 32) & 0xFFFFFFFF); 5738 RD = ((result >> 32) & 0xFFFFFFFF);
5776 } 5739 }
5777 5740
5778 cpu->Reg[15] += GET_INST_SIZE(cpu); 5741 cpu->Reg[15] += cpu->GetInstructionSize();
5779 INC_PC(sizeof(smlad_inst)); 5742 INC_PC(sizeof(smlad_inst));
5780 FETCH_INST; 5743 FETCH_INST;
5781 GOTO_NEXT_INST; 5744 GOTO_NEXT_INST;
@@ -5797,7 +5760,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5797 operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31); 5760 operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31);
5798 RD = operand1 * operand2; 5761 RD = operand1 * operand2;
5799 } 5762 }
5800 cpu->Reg[15] += GET_INST_SIZE(cpu); 5763 cpu->Reg[15] += cpu->GetInstructionSize();
5801 INC_PC(sizeof(smul_inst)); 5764 INC_PC(sizeof(smul_inst));
5802 FETCH_INST; 5765 FETCH_INST;
5803 GOTO_NEXT_INST; 5766 GOTO_NEXT_INST;
@@ -5823,7 +5786,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5823 cpu->ZFlag = (RDHI == 0 && RDLO == 0); 5786 cpu->ZFlag = (RDHI == 0 && RDLO == 0);
5824 } 5787 }
5825 } 5788 }
5826 cpu->Reg[15] += GET_INST_SIZE(cpu); 5789 cpu->Reg[15] += cpu->GetInstructionSize();
5827 INC_PC(sizeof(umull_inst)); 5790 INC_PC(sizeof(umull_inst));
5828 FETCH_INST; 5791 FETCH_INST;
5829 GOTO_NEXT_INST; 5792 GOTO_NEXT_INST;
@@ -5839,7 +5802,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5839 s64 result = (s64)rm * (s64)(s32)RN; 5802 s64 result = (s64)rm * (s64)(s32)RN;
5840 RD = BITS(result, 16, 47); 5803 RD = BITS(result, 16, 47);
5841 } 5804 }
5842 cpu->Reg[15] += GET_INST_SIZE(cpu); 5805 cpu->Reg[15] += cpu->GetInstructionSize();
5843 INC_PC(sizeof(smlad_inst)); 5806 INC_PC(sizeof(smlad_inst));
5844 FETCH_INST; 5807 FETCH_INST;
5845 GOTO_NEXT_INST; 5808 GOTO_NEXT_INST;
@@ -5853,10 +5816,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5853 u32 address = 0; 5816 u32 address = 0;
5854 inst_cream->get_addr(cpu, inst_cream->inst, address); 5817 inst_cream->get_addr(cpu, inst_cream->inst, address);
5855 5818
5856 WriteMemory32(cpu, address + 0, cpu->Reg[14]); 5819 cpu->WriteMemory32(address + 0, cpu->Reg[14]);
5857 WriteMemory32(cpu, address + 4, cpu->Spsr_copy); 5820 cpu->WriteMemory32(address + 4, cpu->Spsr_copy);
5858 5821
5859 cpu->Reg[15] += GET_INST_SIZE(cpu); 5822 cpu->Reg[15] += cpu->GetInstructionSize();
5860 INC_PC(sizeof(ldst_inst)); 5823 INC_PC(sizeof(ldst_inst));
5861 FETCH_INST; 5824 FETCH_INST;
5862 GOTO_NEXT_INST; 5825 GOTO_NEXT_INST;
@@ -5889,7 +5852,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5889 RD = rn_val; 5852 RD = rn_val;
5890 } 5853 }
5891 5854
5892 cpu->Reg[15] += GET_INST_SIZE(cpu); 5855 cpu->Reg[15] += cpu->GetInstructionSize();
5893 INC_PC(sizeof(ssat_inst)); 5856 INC_PC(sizeof(ssat_inst));
5894 FETCH_INST; 5857 FETCH_INST;
5895 GOTO_NEXT_INST; 5858 GOTO_NEXT_INST;
@@ -5911,7 +5874,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5911 cpu->Cpsr |= (1 << 27); 5874 cpu->Cpsr |= (1 << 27);
5912 } 5875 }
5913 5876
5914 cpu->Reg[15] += GET_INST_SIZE(cpu); 5877 cpu->Reg[15] += cpu->GetInstructionSize();
5915 INC_PC(sizeof(ssat_inst)); 5878 INC_PC(sizeof(ssat_inst));
5916 FETCH_INST; 5879 FETCH_INST;
5917 GOTO_NEXT_INST; 5880 GOTO_NEXT_INST;
@@ -5921,7 +5884,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5921 { 5884 {
5922 // Instruction not implemented 5885 // Instruction not implemented
5923 //LOG_CRITICAL(Core_ARM11, "unimplemented instruction"); 5886 //LOG_CRITICAL(Core_ARM11, "unimplemented instruction");
5924 cpu->Reg[15] += GET_INST_SIZE(cpu); 5887 cpu->Reg[15] += cpu->GetInstructionSize();
5925 INC_PC(sizeof(stc_inst)); 5888 INC_PC(sizeof(stc_inst));
5926 FETCH_INST; 5889 FETCH_INST;
5927 GOTO_NEXT_INST; 5890 GOTO_NEXT_INST;
@@ -5939,36 +5902,36 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5939 if (BIT(inst_cream->inst, 22) == 1) { 5902 if (BIT(inst_cream->inst, 22) == 1) {
5940 for (int i = 0; i < 13; i++) { 5903 for (int i = 0; i < 13; i++) {
5941 if (BIT(inst_cream->inst, i)) { 5904 if (BIT(inst_cream->inst, i)) {
5942 WriteMemory32(cpu, addr, cpu->Reg[i]); 5905 cpu->WriteMemory32(addr, cpu->Reg[i]);
5943 addr += 4; 5906 addr += 4;
5944 } 5907 }
5945 } 5908 }
5946 if (BIT(inst_cream->inst, 13)) { 5909 if (BIT(inst_cream->inst, 13)) {
5947 if (cpu->Mode == USER32MODE) 5910 if (cpu->Mode == USER32MODE)
5948 WriteMemory32(cpu, addr, cpu->Reg[13]); 5911 cpu->WriteMemory32(addr, cpu->Reg[13]);
5949 else 5912 else
5950 WriteMemory32(cpu, addr, cpu->Reg_usr[0]); 5913 cpu->WriteMemory32(addr, cpu->Reg_usr[0]);
5951 5914
5952 addr += 4; 5915 addr += 4;
5953 } 5916 }
5954 if (BIT(inst_cream->inst, 14)) { 5917 if (BIT(inst_cream->inst, 14)) {
5955 if (cpu->Mode == USER32MODE) 5918 if (cpu->Mode == USER32MODE)
5956 WriteMemory32(cpu, addr, cpu->Reg[14]); 5919 cpu->WriteMemory32(addr, cpu->Reg[14]);
5957 else 5920 else
5958 WriteMemory32(cpu, addr, cpu->Reg_usr[1]); 5921 cpu->WriteMemory32(addr, cpu->Reg_usr[1]);
5959 5922
5960 addr += 4; 5923 addr += 4;
5961 } 5924 }
5962 if (BIT(inst_cream->inst, 15)) { 5925 if (BIT(inst_cream->inst, 15)) {
5963 WriteMemory32(cpu, addr, cpu->Reg_usr[1] + 8); 5926 cpu->WriteMemory32(addr, cpu->Reg_usr[1] + 8);
5964 } 5927 }
5965 } else { 5928 } else {
5966 for (int i = 0; i < 15; i++) { 5929 for (int i = 0; i < 15; i++) {
5967 if (BIT(inst_cream->inst, i)) { 5930 if (BIT(inst_cream->inst, i)) {
5968 if (i == Rn) 5931 if (i == Rn)
5969 WriteMemory32(cpu, addr, old_RN); 5932 cpu->WriteMemory32(addr, old_RN);
5970 else 5933 else
5971 WriteMemory32(cpu, addr, cpu->Reg[i]); 5934 cpu->WriteMemory32(addr, cpu->Reg[i]);
5972 5935
5973 addr += 4; 5936 addr += 4;
5974 } 5937 }
@@ -5976,10 +5939,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5976 5939
5977 // Check PC reg 5940 // Check PC reg
5978 if (BIT(inst_cream->inst, 15)) 5941 if (BIT(inst_cream->inst, 15))
5979 WriteMemory32(cpu, addr, cpu->Reg_usr[1] + 8); 5942 cpu->WriteMemory32(addr, cpu->Reg_usr[1] + 8);
5980 } 5943 }
5981 } 5944 }
5982 cpu->Reg[15] += GET_INST_SIZE(cpu); 5945 cpu->Reg[15] += cpu->GetInstructionSize();
5983 INC_PC(sizeof(ldst_inst)); 5946 INC_PC(sizeof(ldst_inst));
5984 FETCH_INST; 5947 FETCH_INST;
5985 GOTO_NEXT_INST; 5948 GOTO_NEXT_INST;
@@ -5997,7 +5960,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5997 } 5960 }
5998 RD = operand2; 5961 RD = operand2;
5999 } 5962 }
6000 cpu->Reg[15] += GET_INST_SIZE(cpu); 5963 cpu->Reg[15] += cpu->GetInstructionSize();
6001 INC_PC(sizeof(sxtb_inst)); 5964 INC_PC(sizeof(sxtb_inst));
6002 FETCH_INST; 5965 FETCH_INST;
6003 GOTO_NEXT_INST; 5966 GOTO_NEXT_INST;
@@ -6009,9 +5972,9 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6009 inst_cream->get_addr(cpu, inst_cream->inst, addr); 5972 inst_cream->get_addr(cpu, inst_cream->inst, addr);
6010 5973
6011 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; 5974 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)];
6012 WriteMemory32(cpu, addr, value); 5975 cpu->WriteMemory32(addr, value);
6013 } 5976 }
6014 cpu->Reg[15] += GET_INST_SIZE(cpu); 5977 cpu->Reg[15] += cpu->GetInstructionSize();
6015 INC_PC(sizeof(ldst_inst)); 5978 INC_PC(sizeof(ldst_inst));
6016 FETCH_INST; 5979 FETCH_INST;
6017 GOTO_NEXT_INST; 5980 GOTO_NEXT_INST;
@@ -6022,7 +5985,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6022 uxtb_inst* inst_cream = (uxtb_inst*)inst_base->component; 5985 uxtb_inst* inst_cream = (uxtb_inst*)inst_base->component;
6023 RD = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff; 5986 RD = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff;
6024 } 5987 }
6025 cpu->Reg[15] += GET_INST_SIZE(cpu); 5988 cpu->Reg[15] += cpu->GetInstructionSize();
6026 INC_PC(sizeof(uxtb_inst)); 5989 INC_PC(sizeof(uxtb_inst));
6027 FETCH_INST; 5990 FETCH_INST;
6028 GOTO_NEXT_INST; 5991 GOTO_NEXT_INST;
@@ -6035,7 +5998,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6035 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff; 5998 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff;
6036 RD = RN + operand2; 5999 RD = RN + operand2;
6037 } 6000 }
6038 cpu->Reg[15] += GET_INST_SIZE(cpu); 6001 cpu->Reg[15] += cpu->GetInstructionSize();
6039 INC_PC(sizeof(uxtab_inst)); 6002 INC_PC(sizeof(uxtab_inst));
6040 FETCH_INST; 6003 FETCH_INST;
6041 GOTO_NEXT_INST; 6004 GOTO_NEXT_INST;
@@ -6048,7 +6011,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6048 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; 6011 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff;
6049 Memory::Write8(addr, value); 6012 Memory::Write8(addr, value);
6050 } 6013 }
6051 cpu->Reg[15] += GET_INST_SIZE(cpu); 6014 cpu->Reg[15] += cpu->GetInstructionSize();
6052 INC_PC(sizeof(ldst_inst)); 6015 INC_PC(sizeof(ldst_inst));
6053 FETCH_INST; 6016 FETCH_INST;
6054 GOTO_NEXT_INST; 6017 GOTO_NEXT_INST;
@@ -6061,7 +6024,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6061 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; 6024 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff;
6062 Memory::Write8(addr, value); 6025 Memory::Write8(addr, value);
6063 } 6026 }
6064 cpu->Reg[15] += GET_INST_SIZE(cpu); 6027 cpu->Reg[15] += cpu->GetInstructionSize();
6065 INC_PC(sizeof(ldst_inst)); 6028 INC_PC(sizeof(ldst_inst));
6066 FETCH_INST; 6029 FETCH_INST;
6067 GOTO_NEXT_INST; 6030 GOTO_NEXT_INST;
@@ -6074,10 +6037,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6074 6037
6075 // The 3DS doesn't have the Large Physical Access Extension (LPAE) 6038 // The 3DS doesn't have the Large Physical Access Extension (LPAE)
6076 // so STRD wouldn't store these as a single write. 6039 // so STRD wouldn't store these as a single write.
6077 WriteMemory32(cpu, addr + 0, cpu->Reg[BITS(inst_cream->inst, 12, 15)]); 6040 cpu->WriteMemory32(addr + 0, cpu->Reg[BITS(inst_cream->inst, 12, 15)]);
6078 WriteMemory32(cpu, addr + 4, cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1]); 6041 cpu->WriteMemory32(addr + 4, cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1]);
6079 } 6042 }
6080 cpu->Reg[15] += GET_INST_SIZE(cpu); 6043 cpu->Reg[15] += cpu->GetInstructionSize();
6081 INC_PC(sizeof(ldst_inst)); 6044 INC_PC(sizeof(ldst_inst));
6082 FETCH_INST; 6045 FETCH_INST;
6083 GOTO_NEXT_INST; 6046 GOTO_NEXT_INST;
@@ -6088,18 +6051,16 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6088 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; 6051 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
6089 unsigned int write_addr = cpu->Reg[inst_cream->Rn]; 6052 unsigned int write_addr = cpu->Reg[inst_cream->Rn];
6090 6053
6091 if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) { 6054 if (cpu->IsExclusiveMemoryAccess(write_addr)) {
6092 remove_exclusive(cpu, write_addr); 6055 cpu->UnsetExclusiveMemoryAddress();
6093 cpu->exclusive_state = 0; 6056 cpu->WriteMemory32(write_addr, RM);
6094
6095 WriteMemory32(cpu, write_addr, RM);
6096 RD = 0; 6057 RD = 0;
6097 } else { 6058 } else {
6098 // Failed to write due to mutex access 6059 // Failed to write due to mutex access
6099 RD = 1; 6060 RD = 1;
6100 } 6061 }
6101 } 6062 }
6102 cpu->Reg[15] += GET_INST_SIZE(cpu); 6063 cpu->Reg[15] += cpu->GetInstructionSize();
6103 INC_PC(sizeof(generic_arm_inst)); 6064 INC_PC(sizeof(generic_arm_inst));
6104 FETCH_INST; 6065 FETCH_INST;
6105 GOTO_NEXT_INST; 6066 GOTO_NEXT_INST;
@@ -6110,10 +6071,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6110 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; 6071 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
6111 unsigned int write_addr = cpu->Reg[inst_cream->Rn]; 6072 unsigned int write_addr = cpu->Reg[inst_cream->Rn];
6112 6073
6113 if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) { 6074 if (cpu->IsExclusiveMemoryAccess(write_addr)) {
6114 remove_exclusive(cpu, write_addr); 6075 cpu->UnsetExclusiveMemoryAddress();
6115 cpu->exclusive_state = 0;
6116
6117 Memory::Write8(write_addr, cpu->Reg[inst_cream->Rm]); 6076 Memory::Write8(write_addr, cpu->Reg[inst_cream->Rm]);
6118 RD = 0; 6077 RD = 0;
6119 } else { 6078 } else {
@@ -6121,7 +6080,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6121 RD = 1; 6080 RD = 1;
6122 } 6081 }
6123 } 6082 }
6124 cpu->Reg[15] += GET_INST_SIZE(cpu); 6083 cpu->Reg[15] += cpu->GetInstructionSize();
6125 INC_PC(sizeof(generic_arm_inst)); 6084 INC_PC(sizeof(generic_arm_inst));
6126 FETCH_INST; 6085 FETCH_INST;
6127 GOTO_NEXT_INST; 6086 GOTO_NEXT_INST;
@@ -6132,20 +6091,19 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6132 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; 6091 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
6133 unsigned int write_addr = cpu->Reg[inst_cream->Rn]; 6092 unsigned int write_addr = cpu->Reg[inst_cream->Rn];
6134 6093
6135 if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) { 6094 if (cpu->IsExclusiveMemoryAccess(write_addr)) {
6136 remove_exclusive(cpu, write_addr); 6095 cpu->UnsetExclusiveMemoryAddress();
6137 cpu->exclusive_state = 0;
6138 6096
6139 const u32 rt = cpu->Reg[inst_cream->Rm + 0]; 6097 const u32 rt = cpu->Reg[inst_cream->Rm + 0];
6140 const u32 rt2 = cpu->Reg[inst_cream->Rm + 1]; 6098 const u32 rt2 = cpu->Reg[inst_cream->Rm + 1];
6141 u64 value; 6099 u64 value;
6142 6100
6143 if (InBigEndianMode(cpu)) 6101 if (cpu->InBigEndianMode())
6144 value = (((u64)rt << 32) | rt2); 6102 value = (((u64)rt << 32) | rt2);
6145 else 6103 else
6146 value = (((u64)rt2 << 32) | rt); 6104 value = (((u64)rt2 << 32) | rt);
6147 6105
6148 WriteMemory64(cpu, write_addr, value); 6106 cpu->WriteMemory64(write_addr, value);
6149 RD = 0; 6107 RD = 0;
6150 } 6108 }
6151 else { 6109 else {
@@ -6153,7 +6111,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6153 RD = 1; 6111 RD = 1;
6154 } 6112 }
6155 } 6113 }
6156 cpu->Reg[15] += GET_INST_SIZE(cpu); 6114 cpu->Reg[15] += cpu->GetInstructionSize();
6157 INC_PC(sizeof(generic_arm_inst)); 6115 INC_PC(sizeof(generic_arm_inst));
6158 FETCH_INST; 6116 FETCH_INST;
6159 GOTO_NEXT_INST; 6117 GOTO_NEXT_INST;
@@ -6164,18 +6122,16 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6164 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component; 6122 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
6165 unsigned int write_addr = cpu->Reg[inst_cream->Rn]; 6123 unsigned int write_addr = cpu->Reg[inst_cream->Rn];
6166 6124
6167 if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) { 6125 if (cpu->IsExclusiveMemoryAccess(write_addr)) {
6168 remove_exclusive(cpu, write_addr); 6126 cpu->UnsetExclusiveMemoryAddress();
6169 cpu->exclusive_state = 0; 6127 cpu->WriteMemory16(write_addr, RM);
6170
6171 WriteMemory16(cpu, write_addr, RM);
6172 RD = 0; 6128 RD = 0;
6173 } else { 6129 } else {
6174 // Failed to write due to mutex access 6130 // Failed to write due to mutex access
6175 RD = 1; 6131 RD = 1;
6176 } 6132 }
6177 } 6133 }
6178 cpu->Reg[15] += GET_INST_SIZE(cpu); 6134 cpu->Reg[15] += cpu->GetInstructionSize();
6179 INC_PC(sizeof(generic_arm_inst)); 6135 INC_PC(sizeof(generic_arm_inst));
6180 FETCH_INST; 6136 FETCH_INST;
6181 GOTO_NEXT_INST; 6137 GOTO_NEXT_INST;
@@ -6187,9 +6143,9 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6187 inst_cream->get_addr(cpu, inst_cream->inst, addr); 6143 inst_cream->get_addr(cpu, inst_cream->inst, addr);
6188 6144
6189 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xffff; 6145 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xffff;
6190 WriteMemory16(cpu, addr, value); 6146 cpu->WriteMemory16(addr, value);
6191 } 6147 }
6192 cpu->Reg[15] += GET_INST_SIZE(cpu); 6148 cpu->Reg[15] += cpu->GetInstructionSize();
6193 INC_PC(sizeof(ldst_inst)); 6149 INC_PC(sizeof(ldst_inst));
6194 FETCH_INST; 6150 FETCH_INST;
6195 GOTO_NEXT_INST; 6151 GOTO_NEXT_INST;
@@ -6201,9 +6157,9 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6201 inst_cream->get_addr(cpu, inst_cream->inst, addr); 6157 inst_cream->get_addr(cpu, inst_cream->inst, addr);
6202 6158
6203 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; 6159 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)];
6204 WriteMemory32(cpu, addr, value); 6160 cpu->WriteMemory32(addr, value);
6205 } 6161 }
6206 cpu->Reg[15] += GET_INST_SIZE(cpu); 6162 cpu->Reg[15] += cpu->GetInstructionSize();
6207 INC_PC(sizeof(ldst_inst)); 6163 INC_PC(sizeof(ldst_inst));
6208 FETCH_INST; 6164 FETCH_INST;
6209 GOTO_NEXT_INST; 6165 GOTO_NEXT_INST;
@@ -6224,7 +6180,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6224 if (inst_cream->S && (inst_cream->Rd == 15)) { 6180 if (inst_cream->S && (inst_cream->Rd == 15)) {
6225 if (CurrentModeHasSPSR) { 6181 if (CurrentModeHasSPSR) {
6226 cpu->Cpsr = cpu->Spsr_copy; 6182 cpu->Cpsr = cpu->Spsr_copy;
6227 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 6183 cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
6228 LOAD_NZCVT; 6184 LOAD_NZCVT;
6229 } 6185 }
6230 } else if (inst_cream->S) { 6186 } else if (inst_cream->S) {
@@ -6238,7 +6194,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6238 goto DISPATCH; 6194 goto DISPATCH;
6239 } 6195 }
6240 } 6196 }
6241 cpu->Reg[15] += GET_INST_SIZE(cpu); 6197 cpu->Reg[15] += cpu->GetInstructionSize();
6242 INC_PC(sizeof(sub_inst)); 6198 INC_PC(sizeof(sub_inst));
6243 FETCH_INST; 6199 FETCH_INST;
6244 GOTO_NEXT_INST; 6200 GOTO_NEXT_INST;
@@ -6246,10 +6202,11 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6246 SWI_INST: 6202 SWI_INST:
6247 { 6203 {
6248 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { 6204 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
6249 SVC::CallSVC(Memory::Read32(cpu->Reg[15])); 6205 swi_inst* const inst_cream = (swi_inst*)inst_base->component;
6206 SVC::CallSVC(inst_cream->num & 0xFFFF);
6250 } 6207 }
6251 6208
6252 cpu->Reg[15] += GET_INST_SIZE(cpu); 6209 cpu->Reg[15] += cpu->GetInstructionSize();
6253 INC_PC(sizeof(swi_inst)); 6210 INC_PC(sizeof(swi_inst));
6254 FETCH_INST; 6211 FETCH_INST;
6255 GOTO_NEXT_INST; 6212 GOTO_NEXT_INST;
@@ -6260,12 +6217,12 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6260 swp_inst* inst_cream = (swp_inst*)inst_base->component; 6217 swp_inst* inst_cream = (swp_inst*)inst_base->component;
6261 6218
6262 addr = RN; 6219 addr = RN;
6263 unsigned int value = ReadMemory32(cpu, addr); 6220 unsigned int value = cpu->ReadMemory32(addr);
6264 WriteMemory32(cpu, addr, RM); 6221 cpu->WriteMemory32(addr, RM);
6265 6222
6266 RD = value; 6223 RD = value;
6267 } 6224 }
6268 cpu->Reg[15] += GET_INST_SIZE(cpu); 6225 cpu->Reg[15] += cpu->GetInstructionSize();
6269 INC_PC(sizeof(swp_inst)); 6226 INC_PC(sizeof(swp_inst));
6270 FETCH_INST; 6227 FETCH_INST;
6271 GOTO_NEXT_INST; 6228 GOTO_NEXT_INST;
@@ -6279,7 +6236,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6279 Memory::Write8(addr, (RM & 0xFF)); 6236 Memory::Write8(addr, (RM & 0xFF));
6280 RD = value; 6237 RD = value;
6281 } 6238 }
6282 cpu->Reg[15] += GET_INST_SIZE(cpu); 6239 cpu->Reg[15] += cpu->GetInstructionSize();
6283 INC_PC(sizeof(swp_inst)); 6240 INC_PC(sizeof(swp_inst));
6284 FETCH_INST; 6241 FETCH_INST;
6285 GOTO_NEXT_INST; 6242 GOTO_NEXT_INST;
@@ -6295,7 +6252,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6295 operand2 = (0x80 & operand2)? (0xFFFFFF00 | operand2):operand2; 6252 operand2 = (0x80 & operand2)? (0xFFFFFF00 | operand2):operand2;
6296 RD = RN + operand2; 6253 RD = RN + operand2;
6297 } 6254 }
6298 cpu->Reg[15] += GET_INST_SIZE(cpu); 6255 cpu->Reg[15] += cpu->GetInstructionSize();
6299 INC_PC(sizeof(uxtab_inst)); 6256 INC_PC(sizeof(uxtab_inst));
6300 FETCH_INST; 6257 FETCH_INST;
6301 GOTO_NEXT_INST; 6258 GOTO_NEXT_INST;
@@ -6328,7 +6285,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6328 } 6285 }
6329 } 6286 }
6330 6287
6331 cpu->Reg[15] += GET_INST_SIZE(cpu); 6288 cpu->Reg[15] += cpu->GetInstructionSize();
6332 INC_PC(sizeof(sxtab_inst)); 6289 INC_PC(sizeof(sxtab_inst));
6333 FETCH_INST; 6290 FETCH_INST;
6334 GOTO_NEXT_INST; 6291 GOTO_NEXT_INST;
@@ -6344,7 +6301,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6344 operand2 = (0x8000 & operand2) ? (0xFFFF0000 | operand2) : operand2; 6301 operand2 = (0x8000 & operand2) ? (0xFFFF0000 | operand2) : operand2;
6345 RD = RN + operand2; 6302 RD = RN + operand2;
6346 } 6303 }
6347 cpu->Reg[15] += GET_INST_SIZE(cpu); 6304 cpu->Reg[15] += cpu->GetInstructionSize();
6348 INC_PC(sizeof(sxtah_inst)); 6305 INC_PC(sizeof(sxtah_inst));
6349 FETCH_INST; 6306 FETCH_INST;
6350 GOTO_NEXT_INST; 6307 GOTO_NEXT_INST;
@@ -6359,7 +6316,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6359 u32 rop = SHIFTER_OPERAND; 6316 u32 rop = SHIFTER_OPERAND;
6360 6317
6361 if (inst_cream->Rn == 15) 6318 if (inst_cream->Rn == 15)
6362 lop += GET_INST_SIZE(cpu) * 2; 6319 lop += cpu->GetInstructionSize() * 2;
6363 6320
6364 u32 result = lop ^ rop; 6321 u32 result = lop ^ rop;
6365 6322
@@ -6367,7 +6324,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6367 UPDATE_ZFLAG(result); 6324 UPDATE_ZFLAG(result);
6368 UPDATE_CFLAG_WITH_SC; 6325 UPDATE_CFLAG_WITH_SC;
6369 } 6326 }
6370 cpu->Reg[15] += GET_INST_SIZE(cpu); 6327 cpu->Reg[15] += cpu->GetInstructionSize();
6371 INC_PC(sizeof(teq_inst)); 6328 INC_PC(sizeof(teq_inst));
6372 FETCH_INST; 6329 FETCH_INST;
6373 GOTO_NEXT_INST; 6330 GOTO_NEXT_INST;
@@ -6381,7 +6338,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6381 u32 rop = SHIFTER_OPERAND; 6338 u32 rop = SHIFTER_OPERAND;
6382 6339
6383 if (inst_cream->Rn == 15) 6340 if (inst_cream->Rn == 15)
6384 lop += GET_INST_SIZE(cpu) * 2; 6341 lop += cpu->GetInstructionSize() * 2;
6385 6342
6386 u32 result = lop & rop; 6343 u32 result = lop & rop;
6387 6344
@@ -6389,7 +6346,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6389 UPDATE_ZFLAG(result); 6346 UPDATE_ZFLAG(result);
6390 UPDATE_CFLAG_WITH_SC; 6347 UPDATE_CFLAG_WITH_SC;
6391 } 6348 }
6392 cpu->Reg[15] += GET_INST_SIZE(cpu); 6349 cpu->Reg[15] += cpu->GetInstructionSize();
6393 INC_PC(sizeof(tst_inst)); 6350 INC_PC(sizeof(tst_inst));
6394 FETCH_INST; 6351 FETCH_INST;
6395 GOTO_NEXT_INST; 6352 GOTO_NEXT_INST;
@@ -6560,7 +6517,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6560 RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16); 6517 RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);
6561 } 6518 }
6562 6519
6563 cpu->Reg[15] += GET_INST_SIZE(cpu); 6520 cpu->Reg[15] += cpu->GetInstructionSize();
6564 INC_PC(sizeof(generic_arm_inst)); 6521 INC_PC(sizeof(generic_arm_inst));
6565 FETCH_INST; 6522 FETCH_INST;
6566 GOTO_NEXT_INST; 6523 GOTO_NEXT_INST;
@@ -6640,7 +6597,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6640 } 6597 }
6641 } 6598 }
6642 6599
6643 cpu->Reg[15] += GET_INST_SIZE(cpu); 6600 cpu->Reg[15] += cpu->GetInstructionSize();
6644 INC_PC(sizeof(generic_arm_inst)); 6601 INC_PC(sizeof(generic_arm_inst));
6645 FETCH_INST; 6602 FETCH_INST;
6646 GOTO_NEXT_INST; 6603 GOTO_NEXT_INST;
@@ -6659,7 +6616,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6659 RDLO = (result & 0xFFFFFFFF); 6616 RDLO = (result & 0xFFFFFFFF);
6660 RDHI = ((result >> 32) & 0xFFFFFFFF); 6617 RDHI = ((result >> 32) & 0xFFFFFFFF);
6661 } 6618 }
6662 cpu->Reg[15] += GET_INST_SIZE(cpu); 6619 cpu->Reg[15] += cpu->GetInstructionSize();
6663 INC_PC(sizeof(umaal_inst)); 6620 INC_PC(sizeof(umaal_inst));
6664 FETCH_INST; 6621 FETCH_INST;
6665 GOTO_NEXT_INST; 6622 GOTO_NEXT_INST;
@@ -6682,7 +6639,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6682 cpu->ZFlag = (RDHI == 0 && RDLO == 0); 6639 cpu->ZFlag = (RDHI == 0 && RDLO == 0);
6683 } 6640 }
6684 } 6641 }
6685 cpu->Reg[15] += GET_INST_SIZE(cpu); 6642 cpu->Reg[15] += cpu->GetInstructionSize();
6686 INC_PC(sizeof(umlal_inst)); 6643 INC_PC(sizeof(umlal_inst));
6687 FETCH_INST; 6644 FETCH_INST;
6688 GOTO_NEXT_INST; 6645 GOTO_NEXT_INST;
@@ -6702,7 +6659,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6702 cpu->ZFlag = (RDHI == 0 && RDLO == 0); 6659 cpu->ZFlag = (RDHI == 0 && RDLO == 0);
6703 } 6660 }
6704 } 6661 }
6705 cpu->Reg[15] += GET_INST_SIZE(cpu); 6662 cpu->Reg[15] += cpu->GetInstructionSize();
6706 INC_PC(sizeof(umull_inst)); 6663 INC_PC(sizeof(umull_inst));
6707 FETCH_INST; 6664 FETCH_INST;
6708 GOTO_NEXT_INST; 6665 GOTO_NEXT_INST;
@@ -6730,7 +6687,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6730 { 6687 {
6731 bl_1_thumb* inst_cream = (bl_1_thumb*)inst_base->component; 6688 bl_1_thumb* inst_cream = (bl_1_thumb*)inst_base->component;
6732 cpu->Reg[14] = cpu->Reg[15] + 4 + inst_cream->imm; 6689 cpu->Reg[14] = cpu->Reg[15] + 4 + inst_cream->imm;
6733 cpu->Reg[15] += GET_INST_SIZE(cpu); 6690 cpu->Reg[15] += cpu->GetInstructionSize();
6734 INC_PC(sizeof(bl_1_thumb)); 6691 INC_PC(sizeof(bl_1_thumb));
6735 FETCH_INST; 6692 FETCH_INST;
6736 GOTO_NEXT_INST; 6693 GOTO_NEXT_INST;
@@ -6811,7 +6768,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6811 RD = ((lo_val & 0xFFFF) | hi_val << 16); 6768 RD = ((lo_val & 0xFFFF) | hi_val << 16);
6812 } 6769 }
6813 6770
6814 cpu->Reg[15] += GET_INST_SIZE(cpu); 6771 cpu->Reg[15] += cpu->GetInstructionSize();
6815 INC_PC(sizeof(generic_arm_inst)); 6772 INC_PC(sizeof(generic_arm_inst));
6816 FETCH_INST; 6773 FETCH_INST;
6817 GOTO_NEXT_INST; 6774 GOTO_NEXT_INST;
@@ -6841,7 +6798,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6841 RD = finalDif; 6798 RD = finalDif;
6842 } 6799 }
6843 6800
6844 cpu->Reg[15] += GET_INST_SIZE(cpu); 6801 cpu->Reg[15] += cpu->GetInstructionSize();
6845 INC_PC(sizeof(generic_arm_inst)); 6802 INC_PC(sizeof(generic_arm_inst));
6846 FETCH_INST; 6803 FETCH_INST;
6847 GOTO_NEXT_INST; 6804 GOTO_NEXT_INST;
@@ -6874,7 +6831,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6874 RD = rn_val; 6831 RD = rn_val;
6875 } 6832 }
6876 6833
6877 cpu->Reg[15] += GET_INST_SIZE(cpu); 6834 cpu->Reg[15] += cpu->GetInstructionSize();
6878 INC_PC(sizeof(ssat_inst)); 6835 INC_PC(sizeof(ssat_inst));
6879 FETCH_INST; 6836 FETCH_INST;
6880 GOTO_NEXT_INST; 6837 GOTO_NEXT_INST;
@@ -6896,7 +6853,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6896 cpu->Cpsr |= (1 << 27); 6853 cpu->Cpsr |= (1 << 27);
6897 } 6854 }
6898 6855
6899 cpu->Reg[15] += GET_INST_SIZE(cpu); 6856 cpu->Reg[15] += cpu->GetInstructionSize();
6900 INC_PC(sizeof(ssat_inst)); 6857 INC_PC(sizeof(ssat_inst));
6901 FETCH_INST; 6858 FETCH_INST;
6902 GOTO_NEXT_INST; 6859 GOTO_NEXT_INST;
@@ -6927,7 +6884,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6927 } 6884 }
6928 } 6885 }
6929 6886
6930 cpu->Reg[15] += GET_INST_SIZE(cpu); 6887 cpu->Reg[15] += cpu->GetInstructionSize();
6931 INC_PC(sizeof(uxtab_inst)); 6888 INC_PC(sizeof(uxtab_inst));
6932 FETCH_INST; 6889 FETCH_INST;
6933 GOTO_NEXT_INST; 6890 GOTO_NEXT_INST;
@@ -6940,7 +6897,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6940 LOG_TRACE(Core_ARM11, "WFE executed."); 6897 LOG_TRACE(Core_ARM11, "WFE executed.");
6941 } 6898 }
6942 6899
6943 cpu->Reg[15] += GET_INST_SIZE(cpu); 6900 cpu->Reg[15] += cpu->GetInstructionSize();
6944 INC_PC_STUB; 6901 INC_PC_STUB;
6945 FETCH_INST; 6902 FETCH_INST;
6946 GOTO_NEXT_INST; 6903 GOTO_NEXT_INST;
@@ -6953,7 +6910,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6953 LOG_TRACE(Core_ARM11, "WFI executed."); 6910 LOG_TRACE(Core_ARM11, "WFI executed.");
6954 } 6911 }
6955 6912
6956 cpu->Reg[15] += GET_INST_SIZE(cpu); 6913 cpu->Reg[15] += cpu->GetInstructionSize();
6957 INC_PC_STUB; 6914 INC_PC_STUB;
6958 FETCH_INST; 6915 FETCH_INST;
6959 GOTO_NEXT_INST; 6916 GOTO_NEXT_INST;
@@ -6966,7 +6923,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6966 LOG_TRACE(Core_ARM11, "YIELD executed."); 6923 LOG_TRACE(Core_ARM11, "YIELD executed.");
6967 } 6924 }
6968 6925
6969 cpu->Reg[15] += GET_INST_SIZE(cpu); 6926 cpu->Reg[15] += cpu->GetInstructionSize();
6970 INC_PC_STUB; 6927 INC_PC_STUB;
6971 FETCH_INST; 6928 FETCH_INST;
6972 GOTO_NEXT_INST; 6929 GOTO_NEXT_INST;
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.h b/src/core/arm/dyncom/arm_dyncom_interpreter.h
index 1c324d29c..7a46dcc94 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.h
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.h
@@ -4,6 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "core/arm/skyeye_common/armdefs.h" 7struct ARMul_State;
8 8
9unsigned InterpreterMainLoop(ARMul_State* state); 9unsigned InterpreterMainLoop(ARMul_State* state);
diff --git a/src/core/arm/dyncom/arm_dyncom_run.cpp b/src/core/arm/dyncom/arm_dyncom_run.cpp
deleted file mode 100644
index 5a9a6a788..000000000
--- a/src/core/arm/dyncom/arm_dyncom_run.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
1// Copyright 2012 Michael Kang, 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/arm/dyncom/arm_dyncom_run.h"
6#include "core/arm/skyeye_common/armdefs.h"
7
8void switch_mode(ARMul_State* core, uint32_t mode) {
9 if (core->Mode == mode)
10 return;
11
12 if (mode != USERBANK) {
13 switch (core->Mode) {
14 case SYSTEM32MODE: // Shares registers with user mode
15 case USER32MODE:
16 core->Reg_usr[0] = core->Reg[13];
17 core->Reg_usr[1] = core->Reg[14];
18 break;
19 case IRQ32MODE:
20 core->Reg_irq[0] = core->Reg[13];
21 core->Reg_irq[1] = core->Reg[14];
22 core->Spsr[IRQBANK] = core->Spsr_copy;
23 break;
24 case SVC32MODE:
25 core->Reg_svc[0] = core->Reg[13];
26 core->Reg_svc[1] = core->Reg[14];
27 core->Spsr[SVCBANK] = core->Spsr_copy;
28 break;
29 case ABORT32MODE:
30 core->Reg_abort[0] = core->Reg[13];
31 core->Reg_abort[1] = core->Reg[14];
32 core->Spsr[ABORTBANK] = core->Spsr_copy;
33 break;
34 case UNDEF32MODE:
35 core->Reg_undef[0] = core->Reg[13];
36 core->Reg_undef[1] = core->Reg[14];
37 core->Spsr[UNDEFBANK] = core->Spsr_copy;
38 break;
39 case FIQ32MODE:
40 core->Reg_firq[0] = core->Reg[13];
41 core->Reg_firq[1] = core->Reg[14];
42 core->Spsr[FIQBANK] = core->Spsr_copy;
43 break;
44 }
45
46 switch (mode) {
47 case USER32MODE:
48 core->Reg[13] = core->Reg_usr[0];
49 core->Reg[14] = core->Reg_usr[1];
50 core->Bank = USERBANK;
51 break;
52 case IRQ32MODE:
53 core->Reg[13] = core->Reg_irq[0];
54 core->Reg[14] = core->Reg_irq[1];
55 core->Spsr_copy = core->Spsr[IRQBANK];
56 core->Bank = IRQBANK;
57 break;
58 case SVC32MODE:
59 core->Reg[13] = core->Reg_svc[0];
60 core->Reg[14] = core->Reg_svc[1];
61 core->Spsr_copy = core->Spsr[SVCBANK];
62 core->Bank = SVCBANK;
63 break;
64 case ABORT32MODE:
65 core->Reg[13] = core->Reg_abort[0];
66 core->Reg[14] = core->Reg_abort[1];
67 core->Spsr_copy = core->Spsr[ABORTBANK];
68 core->Bank = ABORTBANK;
69 break;
70 case UNDEF32MODE:
71 core->Reg[13] = core->Reg_undef[0];
72 core->Reg[14] = core->Reg_undef[1];
73 core->Spsr_copy = core->Spsr[UNDEFBANK];
74 core->Bank = UNDEFBANK;
75 break;
76 case FIQ32MODE:
77 core->Reg[13] = core->Reg_firq[0];
78 core->Reg[14] = core->Reg_firq[1];
79 core->Spsr_copy = core->Spsr[FIQBANK];
80 core->Bank = FIQBANK;
81 break;
82 case SYSTEM32MODE: // Shares registers with user mode.
83 core->Reg[13] = core->Reg_usr[0];
84 core->Reg[14] = core->Reg_usr[1];
85 core->Bank = SYSTEMBANK;
86 break;
87 }
88
89 // Set the mode bits in the APSR
90 core->Cpsr = (core->Cpsr & ~core->Mode) | mode;
91 core->Mode = mode;
92 }
93}
diff --git a/src/core/arm/dyncom/arm_dyncom_run.h b/src/core/arm/dyncom/arm_dyncom_run.h
index 85774c565..13bef17fc 100644
--- a/src/core/arm/dyncom/arm_dyncom_run.h
+++ b/src/core/arm/dyncom/arm_dyncom_run.h
@@ -18,40 +18,31 @@
18 18
19#pragma once 19#pragma once
20 20
21#include "core/arm/skyeye_common/armdefs.h" 21#include "core/arm/skyeye_common/armstate.h"
22
23void switch_mode(ARMul_State* core, uint32_t mode);
24
25// Note that for the 3DS, a Thumb instruction will only ever be
26// two bytes in size. Thus we don't need to worry about ThumbEE
27// or Thumb-2 where instructions can be 4 bytes in length.
28static inline u32 GET_INST_SIZE(ARMul_State* core) {
29 return core->TFlag? 2 : 4;
30}
31 22
32/** 23/**
33 * Checks if the PC is being read, and if so, word-aligns it. 24 * Checks if the PC is being read, and if so, word-aligns it.
34 * Used with address calculations. 25 * Used with address calculations.
35 * 26 *
36 * @param core The ARM CPU state instance. 27 * @param cpu The ARM CPU state instance.
37 * @param Rn The register being read. 28 * @param Rn The register being read.
38 * 29 *
39 * @return If the PC is being read, then the word-aligned PC value is returned. 30 * @return If the PC is being read, then the word-aligned PC value is returned.
40 * If the PC is not being read, then the value stored in the register is returned. 31 * If the PC is not being read, then the value stored in the register is returned.
41 */ 32 */
42static inline u32 CHECK_READ_REG15_WA(ARMul_State* core, int Rn) { 33static inline u32 CHECK_READ_REG15_WA(ARMul_State* cpu, int Rn) {
43 return (Rn == 15) ? ((core->Reg[15] & ~0x3) + GET_INST_SIZE(core) * 2) : core->Reg[Rn]; 34 return (Rn == 15) ? ((cpu->Reg[15] & ~0x3) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn];
44} 35}
45 36
46/** 37/**
47 * Reads the PC. Used for data processing operations that use the PC. 38 * Reads the PC. Used for data processing operations that use the PC.
48 * 39 *
49 * @param core The ARM CPU state instance. 40 * @param cpu The ARM CPU state instance.
50 * @param Rn The register being read. 41 * @param Rn The register being read.
51 * 42 *
52 * @return If the PC is being read, then the incremented PC value is returned. 43 * @return If the PC is being read, then the incremented PC value is returned.
53 * If the PC is not being read, then the values stored in the register is returned. 44 * If the PC is not being read, then the values stored in the register is returned.
54 */ 45 */
55static inline u32 CHECK_READ_REG15(ARMul_State* core, int Rn) { 46static inline u32 CHECK_READ_REG15(ARMul_State* cpu, int Rn) {
56 return (Rn == 15) ? ((core->Reg[15] & ~0x1) + GET_INST_SIZE(core) * 2) : core->Reg[Rn]; 47 return (Rn == 15) ? ((cpu->Reg[15] & ~0x1) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn];
57} 48}
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
index 3e79c44c0..29272fd5d 100644
--- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
@@ -6,20 +6,15 @@
6// ARM instruction, and using the existing ARM simulator. 6// ARM instruction, and using the existing ARM simulator.
7 7
8#include "core/arm/dyncom/arm_dyncom_thumb.h" 8#include "core/arm/dyncom/arm_dyncom_thumb.h"
9#include "core/arm/skyeye_common/armsupp.h"
9 10
10// Decode a 16bit Thumb instruction. The instruction is in the low 16-bits of the tinstr field, 11// Decode a 16bit Thumb instruction. The instruction is in the low 16-bits of the tinstr field,
11// with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions 12// with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions
12// allows easier simulation of the special dual BL instruction. 13// allows easier simulation of the special dual BL instruction.
13 14
14tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { 15ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
15 tdstate valid = t_uninitialized; 16 ThumbDecodeStatus valid = ThumbDecodeStatus::UNINITIALIZED;
16 ARMword tinstr = instr; 17 u32 tinstr = GetThumbInstruction(instr, addr);
17
18 // The endian should be judge here
19 if((addr & 0x3) != 0)
20 tinstr = instr >> 16;
21 else
22 tinstr &= 0xFFFF;
23 18
24 *ainstr = 0xDEADC0DE; // Debugging to catch non updates 19 *ainstr = 0xDEADC0DE; // Debugging to catch non updates
25 20
@@ -36,7 +31,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
36 31
37 case 3: // ADD/SUB 32 case 3: // ADD/SUB
38 { 33 {
39 static const ARMword subset[4] = { 34 static const u32 subset[4] = {
40 0xE0900000, // ADDS Rd,Rs,Rn 35 0xE0900000, // ADDS Rd,Rs,Rn
41 0xE0500000, // SUBS Rd,Rs,Rn 36 0xE0500000, // SUBS Rd,Rs,Rn
42 0xE2900000, // ADDS Rd,Rs,#imm3 37 0xE2900000, // ADDS Rd,Rs,#imm3
@@ -55,7 +50,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
55 case 6: // ADD 50 case 6: // ADD
56 case 7: // SUB 51 case 7: // SUB
57 { 52 {
58 static const ARMword subset[4] = { 53 static const u32 subset[4] = {
59 0xE3B00000, // MOVS Rd,#imm8 54 0xE3B00000, // MOVS Rd,#imm8
60 0xE3500000, // CMP Rd,#imm8 55 0xE3500000, // CMP Rd,#imm8
61 0xE2900000, // ADDS Rd,Rd,#imm8 56 0xE2900000, // ADDS Rd,Rd,#imm8
@@ -84,7 +79,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
84 }; 79 };
85 80
86 static const struct { 81 static const struct {
87 ARMword opcode; 82 u32 opcode;
88 otype type; 83 otype type;
89 } subset[16] = { 84 } subset[16] = {
90 { 0xE0100000, t_norm }, // ANDS Rd,Rd,Rs 85 { 0xE0100000, t_norm }, // ANDS Rd,Rd,Rs
@@ -129,15 +124,14 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
129 break; 124 break;
130 } 125 }
131 } else { 126 } else {
132 ARMword Rd = ((tinstr & 0x0007) >> 0); 127 u32 Rd = ((tinstr & 0x0007) >> 0);
133 ARMword Rs = ((tinstr & 0x0038) >> 3); 128 u32 Rs = ((tinstr & 0x0078) >> 3);
134 129
135 if (tinstr & (1 << 7)) 130 if (tinstr & (1 << 7))
136 Rd += 8; 131 Rd += 8;
137 if (tinstr & (1 << 6))
138 Rs += 8;
139 132
140 switch ((tinstr & 0x03C0) >> 6) { 133 switch ((tinstr & 0x03C0) >> 6) {
134 case 0x0: // ADD Rd,Rd,Rs
141 case 0x1: // ADD Rd,Rd,Hs 135 case 0x1: // ADD Rd,Rd,Hs
142 case 0x2: // ADD Hd,Hd,Rs 136 case 0x2: // ADD Hd,Hd,Rs
143 case 0x3: // ADD Hd,Hd,Hs 137 case 0x3: // ADD Hd,Hd,Hs
@@ -146,19 +140,19 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
146 |(Rd << 12) // Rd 140 |(Rd << 12) // Rd
147 |(Rs << 0); // Rm 141 |(Rs << 0); // Rm
148 break; 142 break;
143 case 0x4: // CMP Rd,Rs
149 case 0x5: // CMP Rd,Hs 144 case 0x5: // CMP Rd,Hs
150 case 0x6: // CMP Hd,Rs 145 case 0x6: // CMP Hd,Rs
151 case 0x7: // CMP Hd,Hs 146 case 0x7: // CMP Hd,Hs
152 *ainstr = 0xE1500000 // base 147 *ainstr = 0xE1500000 // base
153 | (Rd << 16) // Rn 148 | (Rd << 16) // Rn
154 |(Rd << 12) // Rd
155 |(Rs << 0); // Rm 149 |(Rs << 0); // Rm
156 break; 150 break;
151 case 0x8: // MOV Rd,Rs
157 case 0x9: // MOV Rd,Hs 152 case 0x9: // MOV Rd,Hs
158 case 0xA: // MOV Hd,Rs 153 case 0xA: // MOV Hd,Rs
159 case 0xB: // MOV Hd,Hs 154 case 0xB: // MOV Hd,Hs
160 *ainstr = 0xE1A00000 // base 155 *ainstr = 0xE1A00000 // base
161 | (Rd << 16) // Rn
162 |(Rd << 12) // Rd 156 |(Rd << 12) // Rd
163 |(Rs << 0); // Rm 157 |(Rs << 0); // Rm
164 break; 158 break;
@@ -167,11 +161,6 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
167 *ainstr = 0xE12FFF10 // base 161 *ainstr = 0xE12FFF10 // base
168 | ((tinstr & 0x0078) >> 3); // Rd 162 | ((tinstr & 0x0078) >> 3); // Rd
169 break; 163 break;
170 case 0x0: // UNDEFINED
171 case 0x4: // UNDEFINED
172 case 0x8: // UNDEFINED
173 valid = t_undefined;
174 break;
175 case 0xE: // BLX 164 case 0xE: // BLX
176 case 0xF: // BLX 165 case 0xF: // BLX
177 *ainstr = 0xE1200030 // base 166 *ainstr = 0xE1200030 // base
@@ -190,7 +179,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
190 case 10: 179 case 10:
191 case 11: 180 case 11:
192 { 181 {
193 static const ARMword subset[8] = { 182 static const u32 subset[8] = {
194 0xE7800000, // STR Rd,[Rb,Ro] 183 0xE7800000, // STR Rd,[Rb,Ro]
195 0xE18000B0, // STRH Rd,[Rb,Ro] 184 0xE18000B0, // STRH Rd,[Rb,Ro]
196 0xE7C00000, // STRB Rd,[Rb,Ro] 185 0xE7C00000, // STRB Rd,[Rb,Ro]
@@ -213,7 +202,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
213 case 14: // STRB Rd,[Rb,#imm5] 202 case 14: // STRB Rd,[Rb,#imm5]
214 case 15: // LDRB Rd,[Rb,#imm5] 203 case 15: // LDRB Rd,[Rb,#imm5]
215 { 204 {
216 static const ARMword subset[4] = { 205 static const u32 subset[4] = {
217 0xE5800000, // STR Rd,[Rb,#imm5] 206 0xE5800000, // STR Rd,[Rb,#imm5]
218 0xE5900000, // LDR Rd,[Rb,#imm5] 207 0xE5900000, // LDR Rd,[Rb,#imm5]
219 0xE5C00000, // STRB Rd,[Rb,#imm5] 208 0xE5C00000, // STRB Rd,[Rb,#imm5]
@@ -280,7 +269,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
280 | BITS(tinstr, 0, 3) // imm4 field; 269 | BITS(tinstr, 0, 3) // imm4 field;
281 | (BITS(tinstr, 4, 7) << 8); // beginning 4 bits of imm12 270 | (BITS(tinstr, 4, 7) << 8); // beginning 4 bits of imm12
282 } else if ((tinstr & 0x0F00) == 0x0200) { 271 } else if ((tinstr & 0x0F00) == 0x0200) {
283 static const ARMword subset[4] = { 272 static const u32 subset[4] = {
284 0xE6BF0070, // SXTH 273 0xE6BF0070, // SXTH
285 0xE6AF0070, // SXTB 274 0xE6AF0070, // SXTB
286 0xE6FF0070, // UXTH 275 0xE6FF0070, // UXTH
@@ -304,7 +293,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
304 | (BIT(tinstr, 4) << 18); // enable bit 293 | (BIT(tinstr, 4) << 18); // enable bit
305 } 294 }
306 } else if ((tinstr & 0x0F00) == 0x0a00) { 295 } else if ((tinstr & 0x0F00) == 0x0a00) {
307 static const ARMword subset[3] = { 296 static const u32 subset[3] = {
308 0xE6BF0F30, // REV 297 0xE6BF0F30, // REV
309 0xE6BF0FB0, // REV16 298 0xE6BF0FB0, // REV16
310 0xE6FF0FB0, // REVSH 299 0xE6FF0FB0, // REVSH
@@ -314,7 +303,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
314 | (BITS(tinstr, 0, 2) << 12) // Rd 303 | (BITS(tinstr, 0, 2) << 12) // Rd
315 | BITS(tinstr, 3, 5); // Rm 304 | BITS(tinstr, 3, 5); // Rm
316 } else { 305 } else {
317 static const ARMword subset[4] = { 306 static const u32 subset[4] = {
318 0xE92D0000, // STMDB sp!,{rlist} 307 0xE92D0000, // STMDB sp!,{rlist}
319 0xE92D4000, // STMDB sp!,{rlist,lr} 308 0xE92D4000, // STMDB sp!,{rlist,lr}
320 0xE8BD0000, // LDMIA sp!,{rlist} 309 0xE8BD0000, // LDMIA sp!,{rlist}
@@ -362,21 +351,21 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
362 else 351 else
363 *ainstr |= (tinstr & 0x00FF); 352 *ainstr |= (tinstr & 0x00FF);
364 } else if ((tinstr & 0x0F00) != 0x0E00) 353 } else if ((tinstr & 0x0F00) != 0x0E00)
365 valid = t_branch; 354 valid = ThumbDecodeStatus::BRANCH;
366 else // UNDEFINED : cc=1110(AL) uses different format 355 else // UNDEFINED : cc=1110(AL) uses different format
367 valid = t_undefined; 356 valid = ThumbDecodeStatus::UNDEFINED;
368 357
369 break; 358 break;
370 359
371 case 28: // B 360 case 28: // B
372 valid = t_branch; 361 valid = ThumbDecodeStatus::BRANCH;
373 break; 362 break;
374 363
375 case 29: 364 case 29:
376 if(tinstr & 0x1) 365 if (tinstr & 0x1)
377 valid = t_undefined; 366 valid = ThumbDecodeStatus::UNDEFINED;
378 else 367 else
379 valid = t_branch; 368 valid = ThumbDecodeStatus::BRANCH;
380 break; 369 break;
381 370
382 case 30: // BL instruction 1 371 case 30: // BL instruction 1
@@ -385,7 +374,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
385 // simulation simple (from the user perspective) we check if the following instruction is 374 // simulation simple (from the user perspective) we check if the following instruction is
386 // the second half of this BL, and if it is we simulate it immediately 375 // the second half of this BL, and if it is we simulate it immediately
387 376
388 valid = t_branch; 377 valid = ThumbDecodeStatus::BRANCH;
389 break; 378 break;
390 379
391 case 31: // BL instruction 2 380 case 31: // BL instruction 2
@@ -394,7 +383,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
394 // ever be matched with the fmt19 "BL instruction 1" instruction. However, we do allow the 383 // ever be matched with the fmt19 "BL instruction 1" instruction. However, we do allow the
395 // simulation of it on its own, with undefined results if r14 is not suitably initialised. 384 // simulation of it on its own, with undefined results if r14 is not suitably initialised.
396 385
397 valid = t_branch; 386 valid = ThumbDecodeStatus::BRANCH;
398 break; 387 break;
399 } 388 }
400 389
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.h b/src/core/arm/dyncom/arm_dyncom_thumb.h
index 8394ff156..447974363 100644
--- a/src/core/arm/dyncom/arm_dyncom_thumb.h
+++ b/src/core/arm/dyncom/arm_dyncom_thumb.h
@@ -26,22 +26,24 @@
26 26
27#pragma once 27#pragma once
28 28
29#include "core/arm/skyeye_common/armdefs.h" 29#include "common/common_types.h"
30 30
31enum tdstate { 31enum class ThumbDecodeStatus {
32 t_undefined, // Undefined Thumb instruction 32 UNDEFINED, // Undefined Thumb instruction
33 t_decoded, // Instruction decoded to ARM equivalent 33 DECODED, // Instruction decoded to ARM equivalent
34 t_branch, // Thumb branch (already processed) 34 BRANCH, // Thumb branch (already processed)
35 t_uninitialized, 35 UNINITIALIZED,
36}; 36};
37 37
38tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size); 38// Translates a Thumb mode instruction into its ARM equivalent.
39ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size);
39 40
40static inline u32 get_thumb_instr(u32 instr, u32 pc) { 41static inline u32 GetThumbInstruction(u32 instr, u32 address) {
41 u32 tinstr; 42 // Normally you would need to handle instruction endianness,
42 if ((pc & 0x3) != 0) 43 // however, it is fixed to little-endian on the MPCore, so
43 tinstr = instr >> 16; 44 // there's no need to check for this beforehand.
44 else 45 if ((address & 0x3) != 0)
45 tinstr = instr & 0xFFFF; 46 return instr >> 16;
46 return tinstr; 47
48 return instr & 0xFFFF;
47} 49}
diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp
deleted file mode 100644
index 4f7a48fab..000000000
--- a/src/core/arm/interpreter/arminit.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
1/* arminit.c -- ARMulator initialization: ARM6 Instruction Emulator.
2 Copyright (C) 1994 Advanced RISC Machines Ltd.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18#include <cstring>
19#include "core/arm/skyeye_common/armdefs.h"
20#include "core/arm/skyeye_common/vfp/vfp.h"
21
22/***************************************************************************\
23* Returns a new instantiation of the ARMulator's state *
24\***************************************************************************/
25ARMul_State* ARMul_NewState(ARMul_State* state)
26{
27 state->Emulate = RUN;
28 state->Mode = USER32MODE;
29
30 state->lateabtSig = HIGH;
31 state->bigendSig = LOW;
32
33 return state;
34}
35
36/***************************************************************************\
37* Call this routine to set ARMulator to model a certain processor *
38\***************************************************************************/
39
40void ARMul_SelectProcessor(ARMul_State* state, unsigned properties)
41{
42 state->is_v4 = (properties & (ARM_v4_Prop | ARM_v5_Prop)) != 0;
43 state->is_v5 = (properties & ARM_v5_Prop) != 0;
44 state->is_v5e = (properties & ARM_v5e_Prop) != 0;
45 state->is_v6 = (properties & ARM_v6_Prop) != 0;
46 state->is_v7 = (properties & ARM_v7_Prop) != 0;
47}
48
49// Resets certain MPCore CP15 values to their ARM-defined reset values.
50static void ResetMPCoreCP15Registers(ARMul_State* cpu)
51{
52 // c0
53 cpu->CP15[CP15_MAIN_ID] = 0x410FB024;
54 cpu->CP15[CP15_TLB_TYPE] = 0x00000800;
55 cpu->CP15[CP15_PROCESSOR_FEATURE_0] = 0x00000111;
56 cpu->CP15[CP15_PROCESSOR_FEATURE_1] = 0x00000001;
57 cpu->CP15[CP15_DEBUG_FEATURE_0] = 0x00000002;
58 cpu->CP15[CP15_MEMORY_MODEL_FEATURE_0] = 0x01100103;
59 cpu->CP15[CP15_MEMORY_MODEL_FEATURE_1] = 0x10020302;
60 cpu->CP15[CP15_MEMORY_MODEL_FEATURE_2] = 0x01222000;
61 cpu->CP15[CP15_MEMORY_MODEL_FEATURE_3] = 0x00000000;
62 cpu->CP15[CP15_ISA_FEATURE_0] = 0x00100011;
63 cpu->CP15[CP15_ISA_FEATURE_1] = 0x12002111;
64 cpu->CP15[CP15_ISA_FEATURE_2] = 0x11221011;
65 cpu->CP15[CP15_ISA_FEATURE_3] = 0x01102131;
66 cpu->CP15[CP15_ISA_FEATURE_4] = 0x00000141;
67
68 // c1
69 cpu->CP15[CP15_CONTROL] = 0x00054078;
70 cpu->CP15[CP15_AUXILIARY_CONTROL] = 0x0000000F;
71 cpu->CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = 0x00000000;
72
73 // c2
74 cpu->CP15[CP15_TRANSLATION_BASE_TABLE_0] = 0x00000000;
75 cpu->CP15[CP15_TRANSLATION_BASE_TABLE_1] = 0x00000000;
76 cpu->CP15[CP15_TRANSLATION_BASE_CONTROL] = 0x00000000;
77
78 // c3
79 cpu->CP15[CP15_DOMAIN_ACCESS_CONTROL] = 0x00000000;
80
81 // c7
82 cpu->CP15[CP15_PHYS_ADDRESS] = 0x00000000;
83
84 // c9
85 cpu->CP15[CP15_DATA_CACHE_LOCKDOWN] = 0xFFFFFFF0;
86
87 // c10
88 cpu->CP15[CP15_TLB_LOCKDOWN] = 0x00000000;
89 cpu->CP15[CP15_PRIMARY_REGION_REMAP] = 0x00098AA4;
90 cpu->CP15[CP15_NORMAL_REGION_REMAP] = 0x44E048E0;
91
92 // c13
93 cpu->CP15[CP15_PID] = 0x00000000;
94 cpu->CP15[CP15_CONTEXT_ID] = 0x00000000;
95 cpu->CP15[CP15_THREAD_UPRW] = 0x00000000;
96 cpu->CP15[CP15_THREAD_URO] = 0x00000000;
97 cpu->CP15[CP15_THREAD_PRW] = 0x00000000;
98
99 // c15
100 cpu->CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = 0x00000000;
101 cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = 0x00000000;
102 cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = 0x00000000;
103 cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = 0x00000000;
104 cpu->CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000;
105}
106
107/***************************************************************************\
108* Call this routine to set up the initial machine state (or perform a RESET *
109\***************************************************************************/
110void ARMul_Reset(ARMul_State* state)
111{
112 VFPInit(state);
113
114 state->Reg[15] = 0;
115 state->Cpsr = INTBITS | SVC32MODE;
116 state->Mode = SVC32MODE;
117 state->Bank = SVCBANK;
118
119 ResetMPCoreCP15Registers(state);
120
121 state->NresetSig = HIGH;
122 state->NfiqSig = HIGH;
123 state->NirqSig = HIGH;
124 state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
125 state->abortSig = LOW;
126
127 state->NumInstrs = 0;
128}
diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp
deleted file mode 100644
index 83f7f3e2c..000000000
--- a/src/core/arm/interpreter/armsupp.cpp
+++ /dev/null
@@ -1,637 +0,0 @@
1/* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator.
2 Copyright (C) 1994 Advanced RISC Machines Ltd.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18#include "common/logging/log.h"
19
20#include "core/mem_map.h"
21#include "core/arm/skyeye_common/armdefs.h"
22#include "core/arm/skyeye_common/arm_regformat.h"
23
24// Unsigned sum of absolute difference
25u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right)
26{
27 if (left > right)
28 return left - right;
29
30 return right - left;
31}
32
33// Add with carry, indicates if a carry-out or signed overflow occurred.
34u32 AddWithCarry(u32 left, u32 right, u32 carry_in, bool* carry_out_occurred, bool* overflow_occurred)
35{
36 u64 unsigned_sum = (u64)left + (u64)right + (u64)carry_in;
37 s64 signed_sum = (s64)(s32)left + (s64)(s32)right + (s64)carry_in;
38 u64 result = (unsigned_sum & 0xFFFFFFFF);
39
40 if (carry_out_occurred)
41 *carry_out_occurred = (result != unsigned_sum);
42
43 if (overflow_occurred)
44 *overflow_occurred = ((s64)(s32)result != signed_sum);
45
46 return (u32)result;
47}
48
49// Compute whether an addition of A and B, giving RESULT, overflowed.
50bool AddOverflow(ARMword a, ARMword b, ARMword result)
51{
52 return ((NEG(a) && NEG(b) && POS(result)) ||
53 (POS(a) && POS(b) && NEG(result)));
54}
55
56// Compute whether a subtraction of A and B, giving RESULT, overflowed.
57bool SubOverflow(ARMword a, ARMword b, ARMword result)
58{
59 return ((NEG(a) && POS(b) && POS(result)) ||
60 (POS(a) && NEG(b) && NEG(result)));
61}
62
63// Returns true if the Q flag should be set as a result of overflow.
64bool ARMul_AddOverflowQ(ARMword a, ARMword b)
65{
66 u32 result = a + b;
67 if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0)
68 return true;
69
70 return false;
71}
72
73// 8-bit signed saturated addition
74u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right)
75{
76 u8 result = left + right;
77
78 if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) == 0) {
79 if (left & 0x80)
80 result = 0x80;
81 else
82 result = 0x7F;
83 }
84
85 return result;
86}
87
88// 8-bit signed saturated subtraction
89u8 ARMul_SignedSaturatedSub8(u8 left, u8 right)
90{
91 u8 result = left - right;
92
93 if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) != 0) {
94 if (left & 0x80)
95 result = 0x80;
96 else
97 result = 0x7F;
98 }
99
100 return result;
101}
102
103// 16-bit signed saturated addition
104u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right)
105{
106 u16 result = left + right;
107
108 if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) == 0) {
109 if (left & 0x8000)
110 result = 0x8000;
111 else
112 result = 0x7FFF;
113 }
114
115 return result;
116}
117
118// 16-bit signed saturated subtraction
119u16 ARMul_SignedSaturatedSub16(u16 left, u16 right)
120{
121 u16 result = left - right;
122
123 if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) != 0) {
124 if (left & 0x8000)
125 result = 0x8000;
126 else
127 result = 0x7FFF;
128 }
129
130 return result;
131}
132
133// 8-bit unsigned saturated addition
134u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right)
135{
136 u8 result = left + right;
137
138 if (result < left)
139 result = 0xFF;
140
141 return result;
142}
143
144// 16-bit unsigned saturated addition
145u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right)
146{
147 u16 result = left + right;
148
149 if (result < left)
150 result = 0xFFFF;
151
152 return result;
153}
154
155// 8-bit unsigned saturated subtraction
156u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right)
157{
158 if (left <= right)
159 return 0;
160
161 return left - right;
162}
163
164// 16-bit unsigned saturated subtraction
165u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right)
166{
167 if (left <= right)
168 return 0;
169
170 return left - right;
171}
172
173// Signed saturation.
174u32 ARMul_SignedSatQ(s32 value, u8 shift, bool* saturation_occurred)
175{
176 const u32 max = (1 << shift) - 1;
177 const s32 top = (value >> shift);
178
179 if (top > 0) {
180 *saturation_occurred = true;
181 return max;
182 }
183 else if (top < -1) {
184 *saturation_occurred = true;
185 return ~max;
186 }
187
188 *saturation_occurred = false;
189 return (u32)value;
190}
191
192// Unsigned saturation
193u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred)
194{
195 const u32 max = (1 << shift) - 1;
196
197 if (value < 0) {
198 *saturation_occurred = true;
199 return 0;
200 } else if ((u32)value > max) {
201 *saturation_occurred = true;
202 return max;
203 }
204
205 *saturation_occurred = false;
206 return (u32)value;
207}
208
209// Whether or not the given CPU is in big endian mode (E bit is set)
210bool InBigEndianMode(ARMul_State* cpu)
211{
212 return (cpu->Cpsr & (1 << 9)) != 0;
213}
214
215// Whether or not the given CPU is in a mode other than user mode.
216bool InAPrivilegedMode(ARMul_State* cpu)
217{
218 return (cpu->Mode != USER32MODE);
219}
220
221// Reads from the CP15 registers. Used with implementation of the MRC instruction.
222// Note that since the 3DS does not have the hypervisor extensions, these registers
223// are not implemented.
224u32 ReadCP15Register(ARMul_State* cpu, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
225{
226 // Unprivileged registers
227 if (crn == 13 && opcode_1 == 0 && crm == 0)
228 {
229 if (opcode_2 == 2)
230 return cpu->CP15[CP15_THREAD_UPRW];
231
232 if (opcode_2 == 3)
233 return cpu->CP15[CP15_THREAD_URO];
234 }
235
236 if (InAPrivilegedMode(cpu))
237 {
238 if (crn == 0 && opcode_1 == 0)
239 {
240 if (crm == 0)
241 {
242 if (opcode_2 == 0)
243 return cpu->CP15[CP15_MAIN_ID];
244
245 if (opcode_2 == 1)
246 return cpu->CP15[CP15_CACHE_TYPE];
247
248 if (opcode_2 == 3)
249 return cpu->CP15[CP15_TLB_TYPE];
250
251 if (opcode_2 == 5)
252 return cpu->CP15[CP15_CPU_ID];
253 }
254 else if (crm == 1)
255 {
256 if (opcode_2 == 0)
257 return cpu->CP15[CP15_PROCESSOR_FEATURE_0];
258
259 if (opcode_2 == 1)
260 return cpu->CP15[CP15_PROCESSOR_FEATURE_1];
261
262 if (opcode_2 == 2)
263 return cpu->CP15[CP15_DEBUG_FEATURE_0];
264
265 if (opcode_2 == 4)
266 return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_0];
267
268 if (opcode_2 == 5)
269 return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_1];
270
271 if (opcode_2 == 6)
272 return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_2];
273
274 if (opcode_2 == 7)
275 return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_3];
276 }
277 else if (crm == 2)
278 {
279 if (opcode_2 == 0)
280 return cpu->CP15[CP15_ISA_FEATURE_0];
281
282 if (opcode_2 == 1)
283 return cpu->CP15[CP15_ISA_FEATURE_1];
284
285 if (opcode_2 == 2)
286 return cpu->CP15[CP15_ISA_FEATURE_2];
287
288 if (opcode_2 == 3)
289 return cpu->CP15[CP15_ISA_FEATURE_3];
290
291 if (opcode_2 == 4)
292 return cpu->CP15[CP15_ISA_FEATURE_4];
293 }
294 }
295
296 if (crn == 1 && opcode_1 == 0 && crm == 0)
297 {
298 if (opcode_2 == 0)
299 return cpu->CP15[CP15_CONTROL];
300
301 if (opcode_2 == 1)
302 return cpu->CP15[CP15_AUXILIARY_CONTROL];
303
304 if (opcode_2 == 2)
305 return cpu->CP15[CP15_COPROCESSOR_ACCESS_CONTROL];
306 }
307
308 if (crn == 2 && opcode_1 == 0 && crm == 0)
309 {
310 if (opcode_2 == 0)
311 return cpu->CP15[CP15_TRANSLATION_BASE_TABLE_0];
312
313 if (opcode_2 == 1)
314 return cpu->CP15[CP15_TRANSLATION_BASE_TABLE_1];
315
316 if (opcode_2 == 2)
317 return cpu->CP15[CP15_TRANSLATION_BASE_CONTROL];
318 }
319
320 if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
321 return cpu->CP15[CP15_DOMAIN_ACCESS_CONTROL];
322
323 if (crn == 5 && opcode_1 == 0 && crm == 0)
324 {
325 if (opcode_2 == 0)
326 return cpu->CP15[CP15_FAULT_STATUS];
327
328 if (opcode_2 == 1)
329 return cpu->CP15[CP15_INSTR_FAULT_STATUS];
330 }
331
332 if (crn == 6 && opcode_1 == 0 && crm == 0)
333 {
334 if (opcode_2 == 0)
335 return cpu->CP15[CP15_FAULT_ADDRESS];
336
337 if (opcode_2 == 1)
338 return cpu->CP15[CP15_WFAR];
339 }
340
341 if (crn == 7 && opcode_1 == 0 && crm == 4 && opcode_2 == 0)
342 return cpu->CP15[CP15_PHYS_ADDRESS];
343
344 if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
345 return cpu->CP15[CP15_DATA_CACHE_LOCKDOWN];
346
347 if (crn == 10 && opcode_1 == 0)
348 {
349 if (crm == 0 && opcode_2 == 0)
350 return cpu->CP15[CP15_TLB_LOCKDOWN];
351
352 if (crm == 2)
353 {
354 if (opcode_2 == 0)
355 return cpu->CP15[CP15_PRIMARY_REGION_REMAP];
356
357 if (opcode_2 == 1)
358 return cpu->CP15[CP15_NORMAL_REGION_REMAP];
359 }
360 }
361
362 if (crn == 13 && crm == 0)
363 {
364 if (opcode_2 == 0)
365 return cpu->CP15[CP15_PID];
366
367 if (opcode_2 == 1)
368 return cpu->CP15[CP15_CONTEXT_ID];
369
370 if (opcode_2 == 4)
371 return cpu->CP15[CP15_THREAD_PRW];
372 }
373
374 if (crn == 15)
375 {
376 if (opcode_1 == 0 && crm == 12)
377 {
378 if (opcode_2 == 0)
379 return cpu->CP15[CP15_PERFORMANCE_MONITOR_CONTROL];
380
381 if (opcode_2 == 1)
382 return cpu->CP15[CP15_CYCLE_COUNTER];
383
384 if (opcode_2 == 2)
385 return cpu->CP15[CP15_COUNT_0];
386
387 if (opcode_2 == 3)
388 return cpu->CP15[CP15_COUNT_1];
389 }
390
391 if (opcode_1 == 5 && opcode_2 == 2)
392 {
393 if (crm == 5)
394 return cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS];
395
396 if (crm == 6)
397 return cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS];
398
399 if (crm == 7)
400 return cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE];
401 }
402
403 if (opcode_1 == 7 && crm == 1 && opcode_2 == 0)
404 return cpu->CP15[CP15_TLB_DEBUG_CONTROL];
405 }
406 }
407
408 LOG_ERROR(Core_ARM11, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.", crn, crm, opcode_1, opcode_2);
409 return 0;
410}
411
412// Write to the CP15 registers. Used with implementation of the MCR instruction.
413// Note that since the 3DS does not have the hypervisor extensions, these registers
414// are not implemented.
415void WriteCP15Register(ARMul_State* cpu, u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
416{
417 if (InAPrivilegedMode(cpu))
418 {
419 if (crn == 1 && opcode_1 == 0 && crm == 0)
420 {
421 if (opcode_2 == 0)
422 cpu->CP15[CP15_CONTROL] = value;
423 else if (opcode_2 == 1)
424 cpu->CP15[CP15_AUXILIARY_CONTROL] = value;
425 else if (opcode_2 == 2)
426 cpu->CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = value;
427 }
428 else if (crn == 2 && opcode_1 == 0 && crm == 0)
429 {
430 if (opcode_2 == 0)
431 cpu->CP15[CP15_TRANSLATION_BASE_TABLE_0] = value;
432 else if (opcode_2 == 1)
433 cpu->CP15[CP15_TRANSLATION_BASE_TABLE_1] = value;
434 else if (opcode_2 == 2)
435 cpu->CP15[CP15_TRANSLATION_BASE_CONTROL] = value;
436 }
437 else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
438 {
439 cpu->CP15[CP15_DOMAIN_ACCESS_CONTROL] = value;
440 }
441 else if (crn == 5 && opcode_1 == 0 && crm == 0)
442 {
443 if (opcode_2 == 0)
444 cpu->CP15[CP15_FAULT_STATUS] = value;
445 else if (opcode_2 == 1)
446 cpu->CP15[CP15_INSTR_FAULT_STATUS] = value;
447 }
448 else if (crn == 6 && opcode_1 == 0 && crm == 0)
449 {
450 if (opcode_2 == 0)
451 cpu->CP15[CP15_FAULT_ADDRESS] = value;
452 else if (opcode_2 == 1)
453 cpu->CP15[CP15_WFAR] = value;
454 }
455 else if (crn == 7 && opcode_1 == 0)
456 {
457 if (crm == 0 && opcode_2 == 4)
458 {
459 cpu->CP15[CP15_WAIT_FOR_INTERRUPT] = value;
460 }
461 else if (crm == 4 && opcode_2 == 0)
462 {
463 // NOTE: Not entirely accurate. This should do permission checks.
464 cpu->CP15[CP15_PHYS_ADDRESS] = Memory::VirtualToPhysicalAddress(value);
465 }
466 else if (crm == 5)
467 {
468 if (opcode_2 == 0)
469 cpu->CP15[CP15_INVALIDATE_INSTR_CACHE] = value;
470 else if (opcode_2 == 1)
471 cpu->CP15[CP15_INVALIDATE_INSTR_CACHE_USING_MVA] = value;
472 else if (opcode_2 == 2)
473 cpu->CP15[CP15_INVALIDATE_INSTR_CACHE_USING_INDEX] = value;
474 else if (opcode_2 == 6)
475 cpu->CP15[CP15_FLUSH_BRANCH_TARGET_CACHE] = value;
476 else if (opcode_2 == 7)
477 cpu->CP15[CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY] = value;
478 }
479 else if (crm == 6)
480 {
481 if (opcode_2 == 0)
482 cpu->CP15[CP15_INVALIDATE_DATA_CACHE] = value;
483 else if (opcode_2 == 1)
484 cpu->CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value;
485 else if (opcode_2 == 2)
486 cpu->CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value;
487 }
488 else if (crm == 7 && opcode_2 == 0)
489 {
490 cpu->CP15[CP15_INVALIDATE_DATA_AND_INSTR_CACHE] = value;
491 }
492 else if (crm == 10)
493 {
494 if (opcode_2 == 0)
495 cpu->CP15[CP15_CLEAN_DATA_CACHE] = value;
496 else if (opcode_2 == 1)
497 cpu->CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_MVA] = value;
498 else if (opcode_2 == 2)
499 cpu->CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX] = value;
500 }
501 else if (crm == 14)
502 {
503 if (opcode_2 == 0)
504 cpu->CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE] = value;
505 else if (opcode_2 == 1)
506 cpu->CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value;
507 else if (opcode_2 == 2)
508 cpu->CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value;
509 }
510 }
511 else if (crn == 8 && opcode_1 == 0)
512 {
513 LOG_WARNING(Core_ARM11, "TLB operations not fully implemented.");
514
515 if (crm == 5)
516 {
517 if (opcode_2 == 0)
518 cpu->CP15[CP15_INVALIDATE_ITLB] = value;
519 else if (opcode_2 == 1)
520 cpu->CP15[CP15_INVALIDATE_ITLB_SINGLE_ENTRY] = value;
521 else if (opcode_2 == 2)
522 cpu->CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH] = value;
523 else if (opcode_2 == 3)
524 cpu->CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_MVA] = value;
525 }
526 else if (crm == 6)
527 {
528 if (opcode_2 == 0)
529 cpu->CP15[CP15_INVALIDATE_DTLB] = value;
530 else if (opcode_2 == 1)
531 cpu->CP15[CP15_INVALIDATE_DTLB_SINGLE_ENTRY] = value;
532 else if (opcode_2 == 2)
533 cpu->CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH] = value;
534 else if (opcode_2 == 3)
535 cpu->CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_MVA] = value;
536 }
537 else if (crm == 7)
538 {
539 if (opcode_2 == 0)
540 cpu->CP15[CP15_INVALIDATE_UTLB] = value;
541 else if (opcode_2 == 1)
542 cpu->CP15[CP15_INVALIDATE_UTLB_SINGLE_ENTRY] = value;
543 else if (opcode_2 == 2)
544 cpu->CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH] = value;
545 else if (opcode_2 == 3)
546 cpu->CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_MVA] = value;
547 }
548 }
549 else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
550 {
551 cpu->CP15[CP15_DATA_CACHE_LOCKDOWN] = value;
552 }
553 else if (crn == 10 && opcode_1 == 0)
554 {
555 if (crm == 0 && opcode_2 == 0)
556 {
557 cpu->CP15[CP15_TLB_LOCKDOWN] = value;
558 }
559 else if (crm == 2)
560 {
561 if (opcode_2 == 0)
562 cpu->CP15[CP15_PRIMARY_REGION_REMAP] = value;
563 else if (opcode_2 == 1)
564 cpu->CP15[CP15_NORMAL_REGION_REMAP] = value;
565 }
566 }
567 else if (crn == 13 && opcode_1 == 0 && crm == 0)
568 {
569 if (opcode_2 == 0)
570 cpu->CP15[CP15_PID] = value;
571 else if (opcode_2 == 1)
572 cpu->CP15[CP15_CONTEXT_ID] = value;
573 else if (opcode_2 == 3)
574 cpu->CP15[CP15_THREAD_URO] = value;
575 else if (opcode_2 == 4)
576 cpu->CP15[CP15_THREAD_PRW] = value;
577 }
578 else if (crn == 15)
579 {
580 if (opcode_1 == 0 && crm == 12)
581 {
582 if (opcode_2 == 0)
583 cpu->CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = value;
584 else if (opcode_2 == 1)
585 cpu->CP15[CP15_CYCLE_COUNTER] = value;
586 else if (opcode_2 == 2)
587 cpu->CP15[CP15_COUNT_0] = value;
588 else if (opcode_2 == 3)
589 cpu->CP15[CP15_COUNT_1] = value;
590 }
591 else if (opcode_1 == 5)
592 {
593 if (crm == 4)
594 {
595 if (opcode_2 == 2)
596 cpu->CP15[CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY] = value;
597 else if (opcode_2 == 4)
598 cpu->CP15[CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY] = value;
599 }
600 else if (crm == 5 && opcode_2 == 2)
601 {
602 cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = value;
603 }
604 else if (crm == 6 && opcode_2 == 2)
605 {
606 cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = value;
607 }
608 else if (crm == 7 && opcode_2 == 2)
609 {
610 cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = value;
611 }
612 }
613 else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0)
614 {
615 cpu->CP15[CP15_TLB_DEBUG_CONTROL] = value;
616 }
617 }
618 }
619
620 // Unprivileged registers
621 if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4)
622 {
623 cpu->CP15[CP15_FLUSH_PREFETCH_BUFFER] = value;
624 }
625 else if (crn == 7 && opcode_1 == 0 && crm == 10)
626 {
627 if (opcode_2 == 4)
628 cpu->CP15[CP15_DATA_SYNC_BARRIER] = value;
629 else if (opcode_2 == 5)
630 cpu->CP15[CP15_DATA_MEMORY_BARRIER] = value;
631
632 }
633 else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2)
634 {
635 cpu->CP15[CP15_THREAD_UPRW] = value;
636 }
637}
diff --git a/src/core/arm/skyeye_common/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h
index a92effbb4..d1c721809 100644
--- a/src/core/arm/skyeye_common/arm_regformat.h
+++ b/src/core/arm/skyeye_common/arm_regformat.h
@@ -59,6 +59,8 @@ enum {
59 VFP_FPSID, 59 VFP_FPSID,
60 VFP_FPSCR, 60 VFP_FPSCR,
61 VFP_FPEXC, 61 VFP_FPEXC,
62 VFP_FPINST,
63 VFP_FPINST2,
62 VFP_MVFR0, 64 VFP_MVFR0,
63 VFP_MVFR1, 65 VFP_MVFR1,
64 66
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h
deleted file mode 100644
index d2c901100..000000000
--- a/src/core/arm/skyeye_common/armdefs.h
+++ /dev/null
@@ -1,318 +0,0 @@
1/* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator.
2 Copyright (C) 1994 Advanced RISC Machines Ltd.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18#pragma once
19
20#include <unordered_map>
21
22#include "common/common_types.h"
23#include "core/arm/skyeye_common/arm_regformat.h"
24
25#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1))
26#define BIT(s, n) ((s >> (n)) & 1)
27
28// Signal levels
29enum {
30 LOW = 0,
31 HIGH = 1,
32 LOWHIGH = 1,
33 HIGHLOW = 2
34};
35
36// Cache types
37enum {
38 NONCACHE = 0,
39 DATACACHE = 1,
40 INSTCACHE = 2,
41};
42
43// Abort models
44enum {
45 ABORT_BASE_RESTORED = 0,
46 ABORT_EARLY = 1,
47 ABORT_BASE_UPDATED = 2
48};
49
50#define POS(i) ( (~(i)) >> 31 )
51#define NEG(i) ( (i) >> 31 )
52
53typedef u64 ARMdword; // must be 64 bits wide
54typedef u32 ARMword; // must be 32 bits wide
55typedef u16 ARMhword; // must be 16 bits wide
56typedef u8 ARMbyte; // must be 8 bits wide
57
58#define VFP_REG_NUM 64
59struct ARMul_State
60{
61 ARMword Emulate; // To start and stop emulation
62
63 // Order of the following register should not be modified
64 ARMword Reg[16]; // The current register file
65 ARMword Cpsr; // The current PSR
66 ARMword Spsr_copy;
67 ARMword phys_pc;
68 ARMword Reg_usr[2];
69 ARMword Reg_svc[2]; // R13_SVC R14_SVC
70 ARMword Reg_abort[2]; // R13_ABORT R14_ABORT
71 ARMword Reg_undef[2]; // R13 UNDEF R14 UNDEF
72 ARMword Reg_irq[2]; // R13_IRQ R14_IRQ
73 ARMword Reg_firq[7]; // R8---R14 FIRQ
74 ARMword Spsr[7]; // The exception psr's
75 ARMword Mode; // The current mode
76 ARMword Bank; // The current register bank
77 ARMword exclusive_tag; // The address for which the local monitor is in exclusive access mode
78 ARMword exclusive_state;
79 ARMword exclusive_result;
80 ARMword CP15[CP15_REGISTER_COUNT];
81
82 // FPSID, FPSCR, and FPEXC
83 ARMword VFP[VFP_SYSTEM_REGISTER_COUNT];
84 // VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31).
85 // VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31),
86 // and only 32 singleword registers are accessible (S0-S31).
87 ARMword ExtReg[VFP_REG_NUM];
88 /* ---- End of the ordered registers ---- */
89
90 ARMword NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed
91 unsigned int shifter_carry_out;
92
93 // Add armv6 flags dyf:2010-08-09
94 ARMword GEFlag, EFlag, AFlag, QFlag;
95
96 ARMword TFlag; // Thumb state
97
98 unsigned long long NumInstrs; // The number of instructions executed
99 unsigned NumInstrsToExecute;
100
101 unsigned NresetSig; // Reset the processor
102 unsigned NfiqSig;
103 unsigned NirqSig;
104
105 unsigned abortSig;
106 unsigned NtransSig;
107 unsigned bigendSig;
108 unsigned syscallSig;
109
110/* 2004-05-09 chy
111----------------------------------------------------------
112read ARM Architecture Reference Manual
1132.6.5 Data Abort
114There are three Abort Model in ARM arch.
115
116Early Abort Model: used in some ARMv3 and earlier implementations. In this
117model, base register wirteback occurred for LDC,LDM,STC,STM instructions, and
118the base register was unchanged for all other instructions. (oldest)
119
120Base Restored Abort Model: If a Data Abort occurs in an instruction which
121specifies base register writeback, the value in the base register is
122unchanged. (strongarm, xscale)
123
124Base Updated Abort Model: If a Data Abort occurs in an instruction which
125specifies base register writeback, the base register writeback still occurs.
126(arm720T)
127
128read PART B
129chap2 The System Control Coprocessor CP15
1302.4 Register1:control register
131L(bit 6): in some ARMv3 and earlier implementations, the abort model of the
132processor could be configured:
1330=early Abort Model Selected(now obsolete)
1341=Late Abort Model selceted(same as Base Updated Abort Model)
135
136on later processors, this bit reads as 1 and ignores writes.
137-------------------------------------------------------------
138So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model)
139 if lateabtSig=0, then it means Base Restored Abort Model
140*/
141 unsigned lateabtSig;
142
143 // For differentiating ARM core emulaiton.
144 bool is_v4; // Are we emulating a v4 architecture (or higher)?
145 bool is_v5; // Are we emulating a v5 architecture?
146 bool is_v5e; // Are we emulating a v5e architecture?
147 bool is_v6; // Are we emulating a v6 architecture?
148 bool is_v7; // Are we emulating a v7 architecture?
149
150 // ARM_ARM A2-18
151 // 0 Base Restored Abort Model, 1 the Early Abort Model, 2 Base Updated Abort Model
152 int abort_model;
153
154 // TODO(bunnei): Move this cache to a better place - it should be per codeset (likely per
155 // process for our purposes), not per ARMul_State (which tracks CPU core state).
156 std::unordered_map<u32, int> instruction_cache;
157};
158
159/***************************************************************************\
160* Types of ARM we know about *
161\***************************************************************************/
162
163enum {
164 ARM_v4_Prop = 0x01,
165 ARM_v5_Prop = 0x02,
166 ARM_v5e_Prop = 0x04,
167 ARM_v6_Prop = 0x08,
168 ARM_v7_Prop = 0x10,
169};
170
171/***************************************************************************\
172* The hardware vector addresses *
173\***************************************************************************/
174
175enum {
176 ARMResetV = 0,
177 ARMUndefinedInstrV = 4,
178 ARMSWIV = 8,
179 ARMPrefetchAbortV = 12,
180 ARMDataAbortV = 16,
181 ARMAddrExceptnV = 20,
182 ARMIRQV = 24,
183 ARMFIQV = 28,
184 ARMErrorV = 32, // This is an offset, not an address!
185
186 ARMul_ResetV = ARMResetV,
187 ARMul_UndefinedInstrV = ARMUndefinedInstrV,
188 ARMul_SWIV = ARMSWIV,
189 ARMul_PrefetchAbortV = ARMPrefetchAbortV,
190 ARMul_DataAbortV = ARMDataAbortV,
191 ARMul_AddrExceptnV = ARMAddrExceptnV,
192 ARMul_IRQV = ARMIRQV,
193 ARMul_FIQV = ARMFIQV
194};
195
196/***************************************************************************\
197* Mode and Bank Constants *
198\***************************************************************************/
199
200enum PrivilegeMode {
201 USER32MODE = 16,
202 FIQ32MODE = 17,
203 IRQ32MODE = 18,
204 SVC32MODE = 19,
205 ABORT32MODE = 23,
206 UNDEF32MODE = 27,
207 SYSTEM32MODE = 31
208};
209
210enum {
211 USERBANK = 0,
212 FIQBANK = 1,
213 IRQBANK = 2,
214 SVCBANK = 3,
215 ABORTBANK = 4,
216 UNDEFBANK = 5,
217 DUMMYBANK = 6,
218 SYSTEMBANK = 7
219};
220
221/***************************************************************************\
222* Definitons of things in the emulator *
223\***************************************************************************/
224extern void ARMul_Reset(ARMul_State* state);
225extern ARMul_State* ARMul_NewState(ARMul_State* state);
226
227/***************************************************************************\
228* Definitons of things in the co-processor interface *
229\***************************************************************************/
230
231enum {
232 ARMul_FIRST = 0,
233 ARMul_TRANSFER = 1,
234 ARMul_BUSY = 2,
235 ARMul_DATA = 3,
236 ARMul_INTERRUPT = 4,
237 ARMul_DONE = 0,
238 ARMul_CANT = 1,
239 ARMul_INC = 3
240};
241
242/***************************************************************************\
243* Definitons of things in the host environment *
244\***************************************************************************/
245
246enum ConditionCode {
247 EQ = 0,
248 NE = 1,
249 CS = 2,
250 CC = 3,
251 MI = 4,
252 PL = 5,
253 VS = 6,
254 VC = 7,
255 HI = 8,
256 LS = 9,
257 GE = 10,
258 LT = 11,
259 GT = 12,
260 LE = 13,
261 AL = 14,
262 NV = 15,
263};
264
265// Flags for use with the APSR.
266enum : u32 {
267 NBIT = (1U << 31U),
268 ZBIT = (1 << 30),
269 CBIT = (1 << 29),
270 VBIT = (1 << 28),
271 QBIT = (1 << 27),
272 JBIT = (1 << 24),
273 EBIT = (1 << 9),
274 ABIT = (1 << 8),
275 IBIT = (1 << 7),
276 FBIT = (1 << 6),
277 TBIT = (1 << 5),
278
279 // Masks for groups of bits in the APSR.
280 MODEBITS = 0x1F,
281 INTBITS = 0x1C0,
282};
283
284// Values for Emulate.
285enum {
286 STOP = 0, // Stop
287 CHANGEMODE = 1, // Change mode
288 ONCE = 2, // Execute just one iteration
289 RUN = 3 // Continuous execution
290};
291
292
293extern bool AddOverflow(ARMword, ARMword, ARMword);
294extern bool SubOverflow(ARMword, ARMword, ARMword);
295
296extern void ARMul_SelectProcessor(ARMul_State*, unsigned);
297
298extern u32 AddWithCarry(u32, u32, u32, bool*, bool*);
299extern bool ARMul_AddOverflowQ(ARMword, ARMword);
300
301extern u8 ARMul_SignedSaturatedAdd8(u8, u8);
302extern u8 ARMul_SignedSaturatedSub8(u8, u8);
303extern u16 ARMul_SignedSaturatedAdd16(u16, u16);
304extern u16 ARMul_SignedSaturatedSub16(u16, u16);
305
306extern u8 ARMul_UnsignedSaturatedAdd8(u8, u8);
307extern u16 ARMul_UnsignedSaturatedAdd16(u16, u16);
308extern u8 ARMul_UnsignedSaturatedSub8(u8, u8);
309extern u16 ARMul_UnsignedSaturatedSub16(u16, u16);
310extern u8 ARMul_UnsignedAbsoluteDifference(u8, u8);
311extern u32 ARMul_SignedSatQ(s32, u8, bool*);
312extern u32 ARMul_UnsignedSatQ(s32, u8, bool*);
313
314extern bool InBigEndianMode(ARMul_State*);
315extern bool InAPrivilegedMode(ARMul_State*);
316
317extern u32 ReadCP15Register(ARMul_State* cpu, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2);
318extern void WriteCP15Register(ARMul_State* cpu, u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2);
diff --git a/src/core/arm/skyeye_common/armmmu.h b/src/core/arm/skyeye_common/armmmu.h
deleted file mode 100644
index c67d7209b..000000000
--- a/src/core/arm/skyeye_common/armmmu.h
+++ /dev/null
@@ -1,103 +0,0 @@
1/*
2 armmmu.c - Memory Management Unit emulation.
3 ARMulator extensions for the ARM7100 family.
4 Copyright (C) 1999 Ben Williamson
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/
20
21#pragma once
22
23#include "common/swap.h"
24
25#include "core/memory.h"
26#include "core/arm/skyeye_common/armdefs.h"
27
28// Register numbers in the MMU
29enum
30{
31 MMU_ID = 0,
32 MMU_CONTROL = 1,
33 MMU_TRANSLATION_TABLE_BASE = 2,
34 MMU_DOMAIN_ACCESS_CONTROL = 3,
35 MMU_FAULT_STATUS = 5,
36 MMU_FAULT_ADDRESS = 6,
37 MMU_CACHE_OPS = 7,
38 MMU_TLB_OPS = 8,
39 MMU_CACHE_LOCKDOWN = 9,
40 MMU_TLB_LOCKDOWN = 10,
41 MMU_PID = 13,
42
43 // MMU_V4
44 MMU_V4_CACHE_OPS = 7,
45 MMU_V4_TLB_OPS = 8,
46
47 // MMU_V3
48 MMU_V3_FLUSH_TLB = 5,
49 MMU_V3_FLUSH_TLB_ENTRY = 6,
50 MMU_V3_FLUSH_CACHE = 7,
51};
52
53// Reads data in big/little endian format based on the
54// state of the E (endian) bit in the emulated CPU's APSR.
55inline u16 ReadMemory16(ARMul_State* cpu, u32 address) {
56 u16 data = Memory::Read16(address);
57
58 if (InBigEndianMode(cpu))
59 data = Common::swap16(data);
60
61 return data;
62}
63
64inline u32 ReadMemory32(ARMul_State* cpu, u32 address) {
65 u32 data = Memory::Read32(address);
66
67 if (InBigEndianMode(cpu))
68 data = Common::swap32(data);
69
70 return data;
71}
72
73inline u64 ReadMemory64(ARMul_State* cpu, u32 address) {
74 u64 data = Memory::Read64(address);
75
76 if (InBigEndianMode(cpu))
77 data = Common::swap64(data);
78
79 return data;
80}
81
82// Writes data in big/little endian format based on the
83// state of the E (endian) bit in the emulated CPU's APSR.
84inline void WriteMemory16(ARMul_State* cpu, u32 address, u16 data) {
85 if (InBigEndianMode(cpu))
86 data = Common::swap16(data);
87
88 Memory::Write16(address, data);
89}
90
91inline void WriteMemory32(ARMul_State* cpu, u32 address, u32 data) {
92 if (InBigEndianMode(cpu))
93 data = Common::swap32(data);
94
95 Memory::Write32(address, data);
96}
97
98inline void WriteMemory64(ARMul_State* cpu, u32 address, u64 data) {
99 if (InBigEndianMode(cpu))
100 data = Common::swap64(data);
101
102 Memory::Write64(address, data);
103}
diff --git a/src/core/arm/skyeye_common/armstate.cpp b/src/core/arm/skyeye_common/armstate.cpp
new file mode 100644
index 000000000..ccb2eb0eb
--- /dev/null
+++ b/src/core/arm/skyeye_common/armstate.cpp
@@ -0,0 +1,657 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/swap.h"
6#include "common/logging/log.h"
7#include "core/mem_map.h"
8#include "core/memory.h"
9#include "core/arm/skyeye_common/armstate.h"
10#include "core/arm/skyeye_common/vfp/vfp.h"
11
12ARMul_State::ARMul_State(PrivilegeMode initial_mode)
13{
14 Reset();
15 ChangePrivilegeMode(initial_mode);
16}
17
18void ARMul_State::ChangePrivilegeMode(u32 new_mode)
19{
20 if (Mode == new_mode)
21 return;
22
23 if (new_mode != USERBANK) {
24 switch (Mode) {
25 case SYSTEM32MODE: // Shares registers with user mode
26 case USER32MODE:
27 Reg_usr[0] = Reg[13];
28 Reg_usr[1] = Reg[14];
29 break;
30 case IRQ32MODE:
31 Reg_irq[0] = Reg[13];
32 Reg_irq[1] = Reg[14];
33 Spsr[IRQBANK] = Spsr_copy;
34 break;
35 case SVC32MODE:
36 Reg_svc[0] = Reg[13];
37 Reg_svc[1] = Reg[14];
38 Spsr[SVCBANK] = Spsr_copy;
39 break;
40 case ABORT32MODE:
41 Reg_abort[0] = Reg[13];
42 Reg_abort[1] = Reg[14];
43 Spsr[ABORTBANK] = Spsr_copy;
44 break;
45 case UNDEF32MODE:
46 Reg_undef[0] = Reg[13];
47 Reg_undef[1] = Reg[14];
48 Spsr[UNDEFBANK] = Spsr_copy;
49 break;
50 case FIQ32MODE:
51 Reg_firq[0] = Reg[13];
52 Reg_firq[1] = Reg[14];
53 Spsr[FIQBANK] = Spsr_copy;
54 break;
55 }
56
57 switch (new_mode) {
58 case USER32MODE:
59 Reg[13] = Reg_usr[0];
60 Reg[14] = Reg_usr[1];
61 Bank = USERBANK;
62 break;
63 case IRQ32MODE:
64 Reg[13] = Reg_irq[0];
65 Reg[14] = Reg_irq[1];
66 Spsr_copy = Spsr[IRQBANK];
67 Bank = IRQBANK;
68 break;
69 case SVC32MODE:
70 Reg[13] = Reg_svc[0];
71 Reg[14] = Reg_svc[1];
72 Spsr_copy = Spsr[SVCBANK];
73 Bank = SVCBANK;
74 break;
75 case ABORT32MODE:
76 Reg[13] = Reg_abort[0];
77 Reg[14] = Reg_abort[1];
78 Spsr_copy = Spsr[ABORTBANK];
79 Bank = ABORTBANK;
80 break;
81 case UNDEF32MODE:
82 Reg[13] = Reg_undef[0];
83 Reg[14] = Reg_undef[1];
84 Spsr_copy = Spsr[UNDEFBANK];
85 Bank = UNDEFBANK;
86 break;
87 case FIQ32MODE:
88 Reg[13] = Reg_firq[0];
89 Reg[14] = Reg_firq[1];
90 Spsr_copy = Spsr[FIQBANK];
91 Bank = FIQBANK;
92 break;
93 case SYSTEM32MODE: // Shares registers with user mode.
94 Reg[13] = Reg_usr[0];
95 Reg[14] = Reg_usr[1];
96 Bank = SYSTEMBANK;
97 break;
98 }
99
100 // Set the mode bits in the APSR
101 Cpsr = (Cpsr & ~Mode) | new_mode;
102 Mode = new_mode;
103 }
104}
105
106// Performs a reset
107void ARMul_State::Reset()
108{
109 VFPInit(this);
110
111 // Set stack pointer to the top of the stack
112 Reg[13] = 0x10000000;
113 Reg[15] = 0;
114
115 Cpsr = INTBITS | SVC32MODE;
116 Mode = SVC32MODE;
117 Bank = SVCBANK;
118
119 ResetMPCoreCP15Registers();
120
121 NresetSig = HIGH;
122 NfiqSig = HIGH;
123 NirqSig = HIGH;
124 NtransSig = (Mode & 3) ? HIGH : LOW;
125 abortSig = LOW;
126
127 NumInstrs = 0;
128 Emulate = RUN;
129}
130
131// Resets certain MPCore CP15 values to their ARM-defined reset values.
132void ARMul_State::ResetMPCoreCP15Registers()
133{
134 // c0
135 CP15[CP15_MAIN_ID] = 0x410FB024;
136 CP15[CP15_TLB_TYPE] = 0x00000800;
137 CP15[CP15_PROCESSOR_FEATURE_0] = 0x00000111;
138 CP15[CP15_PROCESSOR_FEATURE_1] = 0x00000001;
139 CP15[CP15_DEBUG_FEATURE_0] = 0x00000002;
140 CP15[CP15_MEMORY_MODEL_FEATURE_0] = 0x01100103;
141 CP15[CP15_MEMORY_MODEL_FEATURE_1] = 0x10020302;
142 CP15[CP15_MEMORY_MODEL_FEATURE_2] = 0x01222000;
143 CP15[CP15_MEMORY_MODEL_FEATURE_3] = 0x00000000;
144 CP15[CP15_ISA_FEATURE_0] = 0x00100011;
145 CP15[CP15_ISA_FEATURE_1] = 0x12002111;
146 CP15[CP15_ISA_FEATURE_2] = 0x11221011;
147 CP15[CP15_ISA_FEATURE_3] = 0x01102131;
148 CP15[CP15_ISA_FEATURE_4] = 0x00000141;
149
150 // c1
151 CP15[CP15_CONTROL] = 0x00054078;
152 CP15[CP15_AUXILIARY_CONTROL] = 0x0000000F;
153 CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = 0x00000000;
154
155 // c2
156 CP15[CP15_TRANSLATION_BASE_TABLE_0] = 0x00000000;
157 CP15[CP15_TRANSLATION_BASE_TABLE_1] = 0x00000000;
158 CP15[CP15_TRANSLATION_BASE_CONTROL] = 0x00000000;
159
160 // c3
161 CP15[CP15_DOMAIN_ACCESS_CONTROL] = 0x00000000;
162
163 // c7
164 CP15[CP15_PHYS_ADDRESS] = 0x00000000;
165
166 // c9
167 CP15[CP15_DATA_CACHE_LOCKDOWN] = 0xFFFFFFF0;
168
169 // c10
170 CP15[CP15_TLB_LOCKDOWN] = 0x00000000;
171 CP15[CP15_PRIMARY_REGION_REMAP] = 0x00098AA4;
172 CP15[CP15_NORMAL_REGION_REMAP] = 0x44E048E0;
173
174 // c13
175 CP15[CP15_PID] = 0x00000000;
176 CP15[CP15_CONTEXT_ID] = 0x00000000;
177 CP15[CP15_THREAD_UPRW] = 0x00000000;
178 CP15[CP15_THREAD_URO] = 0x00000000;
179 CP15[CP15_THREAD_PRW] = 0x00000000;
180
181 // c15
182 CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = 0x00000000;
183 CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = 0x00000000;
184 CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = 0x00000000;
185 CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = 0x00000000;
186 CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000;
187}
188
189u16 ARMul_State::ReadMemory16(u32 address) const
190{
191 u16 data = Memory::Read16(address);
192
193 if (InBigEndianMode())
194 data = Common::swap16(data);
195
196 return data;
197}
198
199u32 ARMul_State::ReadMemory32(u32 address) const
200{
201 u32 data = Memory::Read32(address);
202
203 if (InBigEndianMode())
204 data = Common::swap32(data);
205
206 return data;
207}
208
209u64 ARMul_State::ReadMemory64(u32 address) const
210{
211 u64 data = Memory::Read64(address);
212
213 if (InBigEndianMode())
214 data = Common::swap64(data);
215
216 return data;
217}
218
219void ARMul_State::WriteMemory16(u32 address, u16 data)
220{
221 if (InBigEndianMode())
222 data = Common::swap16(data);
223
224 Memory::Write16(address, data);
225}
226
227void ARMul_State::WriteMemory32(u32 address, u32 data)
228{
229 if (InBigEndianMode())
230 data = Common::swap32(data);
231
232 Memory::Write32(address, data);
233}
234
235void ARMul_State::WriteMemory64(u32 address, u64 data)
236{
237 if (InBigEndianMode())
238 data = Common::swap64(data);
239
240 Memory::Write64(address, data);
241}
242
243
244// Reads from the CP15 registers. Used with implementation of the MRC instruction.
245// Note that since the 3DS does not have the hypervisor extensions, these registers
246// are not implemented.
247u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const
248{
249 // Unprivileged registers
250 if (crn == 13 && opcode_1 == 0 && crm == 0)
251 {
252 if (opcode_2 == 2)
253 return CP15[CP15_THREAD_UPRW];
254
255 if (opcode_2 == 3)
256 return CP15[CP15_THREAD_URO];
257 }
258
259 if (InAPrivilegedMode())
260 {
261 if (crn == 0 && opcode_1 == 0)
262 {
263 if (crm == 0)
264 {
265 if (opcode_2 == 0)
266 return CP15[CP15_MAIN_ID];
267
268 if (opcode_2 == 1)
269 return CP15[CP15_CACHE_TYPE];
270
271 if (opcode_2 == 3)
272 return CP15[CP15_TLB_TYPE];
273
274 if (opcode_2 == 5)
275 return CP15[CP15_CPU_ID];
276 }
277 else if (crm == 1)
278 {
279 if (opcode_2 == 0)
280 return CP15[CP15_PROCESSOR_FEATURE_0];
281
282 if (opcode_2 == 1)
283 return CP15[CP15_PROCESSOR_FEATURE_1];
284
285 if (opcode_2 == 2)
286 return CP15[CP15_DEBUG_FEATURE_0];
287
288 if (opcode_2 == 4)
289 return CP15[CP15_MEMORY_MODEL_FEATURE_0];
290
291 if (opcode_2 == 5)
292 return CP15[CP15_MEMORY_MODEL_FEATURE_1];
293
294 if (opcode_2 == 6)
295 return CP15[CP15_MEMORY_MODEL_FEATURE_2];
296
297 if (opcode_2 == 7)
298 return CP15[CP15_MEMORY_MODEL_FEATURE_3];
299 }
300 else if (crm == 2)
301 {
302 if (opcode_2 == 0)
303 return CP15[CP15_ISA_FEATURE_0];
304
305 if (opcode_2 == 1)
306 return CP15[CP15_ISA_FEATURE_1];
307
308 if (opcode_2 == 2)
309 return CP15[CP15_ISA_FEATURE_2];
310
311 if (opcode_2 == 3)
312 return CP15[CP15_ISA_FEATURE_3];
313
314 if (opcode_2 == 4)
315 return CP15[CP15_ISA_FEATURE_4];
316 }
317 }
318
319 if (crn == 1 && opcode_1 == 0 && crm == 0)
320 {
321 if (opcode_2 == 0)
322 return CP15[CP15_CONTROL];
323
324 if (opcode_2 == 1)
325 return CP15[CP15_AUXILIARY_CONTROL];
326
327 if (opcode_2 == 2)
328 return CP15[CP15_COPROCESSOR_ACCESS_CONTROL];
329 }
330
331 if (crn == 2 && opcode_1 == 0 && crm == 0)
332 {
333 if (opcode_2 == 0)
334 return CP15[CP15_TRANSLATION_BASE_TABLE_0];
335
336 if (opcode_2 == 1)
337 return CP15[CP15_TRANSLATION_BASE_TABLE_1];
338
339 if (opcode_2 == 2)
340 return CP15[CP15_TRANSLATION_BASE_CONTROL];
341 }
342
343 if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
344 return CP15[CP15_DOMAIN_ACCESS_CONTROL];
345
346 if (crn == 5 && opcode_1 == 0 && crm == 0)
347 {
348 if (opcode_2 == 0)
349 return CP15[CP15_FAULT_STATUS];
350
351 if (opcode_2 == 1)
352 return CP15[CP15_INSTR_FAULT_STATUS];
353 }
354
355 if (crn == 6 && opcode_1 == 0 && crm == 0)
356 {
357 if (opcode_2 == 0)
358 return CP15[CP15_FAULT_ADDRESS];
359
360 if (opcode_2 == 1)
361 return CP15[CP15_WFAR];
362 }
363
364 if (crn == 7 && opcode_1 == 0 && crm == 4 && opcode_2 == 0)
365 return CP15[CP15_PHYS_ADDRESS];
366
367 if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
368 return CP15[CP15_DATA_CACHE_LOCKDOWN];
369
370 if (crn == 10 && opcode_1 == 0)
371 {
372 if (crm == 0 && opcode_2 == 0)
373 return CP15[CP15_TLB_LOCKDOWN];
374
375 if (crm == 2)
376 {
377 if (opcode_2 == 0)
378 return CP15[CP15_PRIMARY_REGION_REMAP];
379
380 if (opcode_2 == 1)
381 return CP15[CP15_NORMAL_REGION_REMAP];
382 }
383 }
384
385 if (crn == 13 && crm == 0)
386 {
387 if (opcode_2 == 0)
388 return CP15[CP15_PID];
389
390 if (opcode_2 == 1)
391 return CP15[CP15_CONTEXT_ID];
392
393 if (opcode_2 == 4)
394 return CP15[CP15_THREAD_PRW];
395 }
396
397 if (crn == 15)
398 {
399 if (opcode_1 == 0 && crm == 12)
400 {
401 if (opcode_2 == 0)
402 return CP15[CP15_PERFORMANCE_MONITOR_CONTROL];
403
404 if (opcode_2 == 1)
405 return CP15[CP15_CYCLE_COUNTER];
406
407 if (opcode_2 == 2)
408 return CP15[CP15_COUNT_0];
409
410 if (opcode_2 == 3)
411 return CP15[CP15_COUNT_1];
412 }
413
414 if (opcode_1 == 5 && opcode_2 == 2)
415 {
416 if (crm == 5)
417 return CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS];
418
419 if (crm == 6)
420 return CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS];
421
422 if (crm == 7)
423 return CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE];
424 }
425
426 if (opcode_1 == 7 && crm == 1 && opcode_2 == 0)
427 return CP15[CP15_TLB_DEBUG_CONTROL];
428 }
429 }
430
431 LOG_ERROR(Core_ARM11, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.", crn, crm, opcode_1, opcode_2);
432 return 0;
433}
434
435// Write to the CP15 registers. Used with implementation of the MCR instruction.
436// Note that since the 3DS does not have the hypervisor extensions, these registers
437// are not implemented.
438void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
439{
440 if (InAPrivilegedMode())
441 {
442 if (crn == 1 && opcode_1 == 0 && crm == 0)
443 {
444 if (opcode_2 == 0)
445 CP15[CP15_CONTROL] = value;
446 else if (opcode_2 == 1)
447 CP15[CP15_AUXILIARY_CONTROL] = value;
448 else if (opcode_2 == 2)
449 CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = value;
450 }
451 else if (crn == 2 && opcode_1 == 0 && crm == 0)
452 {
453 if (opcode_2 == 0)
454 CP15[CP15_TRANSLATION_BASE_TABLE_0] = value;
455 else if (opcode_2 == 1)
456 CP15[CP15_TRANSLATION_BASE_TABLE_1] = value;
457 else if (opcode_2 == 2)
458 CP15[CP15_TRANSLATION_BASE_CONTROL] = value;
459 }
460 else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
461 {
462 CP15[CP15_DOMAIN_ACCESS_CONTROL] = value;
463 }
464 else if (crn == 5 && opcode_1 == 0 && crm == 0)
465 {
466 if (opcode_2 == 0)
467 CP15[CP15_FAULT_STATUS] = value;
468 else if (opcode_2 == 1)
469 CP15[CP15_INSTR_FAULT_STATUS] = value;
470 }
471 else if (crn == 6 && opcode_1 == 0 && crm == 0)
472 {
473 if (opcode_2 == 0)
474 CP15[CP15_FAULT_ADDRESS] = value;
475 else if (opcode_2 == 1)
476 CP15[CP15_WFAR] = value;
477 }
478 else if (crn == 7 && opcode_1 == 0)
479 {
480 if (crm == 0 && opcode_2 == 4)
481 {
482 CP15[CP15_WAIT_FOR_INTERRUPT] = value;
483 }
484 else if (crm == 4 && opcode_2 == 0)
485 {
486 // NOTE: Not entirely accurate. This should do permission checks.
487 CP15[CP15_PHYS_ADDRESS] = Memory::VirtualToPhysicalAddress(value);
488 }
489 else if (crm == 5)
490 {
491 if (opcode_2 == 0)
492 CP15[CP15_INVALIDATE_INSTR_CACHE] = value;
493 else if (opcode_2 == 1)
494 CP15[CP15_INVALIDATE_INSTR_CACHE_USING_MVA] = value;
495 else if (opcode_2 == 2)
496 CP15[CP15_INVALIDATE_INSTR_CACHE_USING_INDEX] = value;
497 else if (opcode_2 == 6)
498 CP15[CP15_FLUSH_BRANCH_TARGET_CACHE] = value;
499 else if (opcode_2 == 7)
500 CP15[CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY] = value;
501 }
502 else if (crm == 6)
503 {
504 if (opcode_2 == 0)
505 CP15[CP15_INVALIDATE_DATA_CACHE] = value;
506 else if (opcode_2 == 1)
507 CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value;
508 else if (opcode_2 == 2)
509 CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value;
510 }
511 else if (crm == 7 && opcode_2 == 0)
512 {
513 CP15[CP15_INVALIDATE_DATA_AND_INSTR_CACHE] = value;
514 }
515 else if (crm == 10)
516 {
517 if (opcode_2 == 0)
518 CP15[CP15_CLEAN_DATA_CACHE] = value;
519 else if (opcode_2 == 1)
520 CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_MVA] = value;
521 else if (opcode_2 == 2)
522 CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX] = value;
523 }
524 else if (crm == 14)
525 {
526 if (opcode_2 == 0)
527 CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE] = value;
528 else if (opcode_2 == 1)
529 CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value;
530 else if (opcode_2 == 2)
531 CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value;
532 }
533 }
534 else if (crn == 8 && opcode_1 == 0)
535 {
536 if (crm == 5)
537 {
538 if (opcode_2 == 0)
539 CP15[CP15_INVALIDATE_ITLB] = value;
540 else if (opcode_2 == 1)
541 CP15[CP15_INVALIDATE_ITLB_SINGLE_ENTRY] = value;
542 else if (opcode_2 == 2)
543 CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH] = value;
544 else if (opcode_2 == 3)
545 CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_MVA] = value;
546 }
547 else if (crm == 6)
548 {
549 if (opcode_2 == 0)
550 CP15[CP15_INVALIDATE_DTLB] = value;
551 else if (opcode_2 == 1)
552 CP15[CP15_INVALIDATE_DTLB_SINGLE_ENTRY] = value;
553 else if (opcode_2 == 2)
554 CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH] = value;
555 else if (opcode_2 == 3)
556 CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_MVA] = value;
557 }
558 else if (crm == 7)
559 {
560 if (opcode_2 == 0)
561 CP15[CP15_INVALIDATE_UTLB] = value;
562 else if (opcode_2 == 1)
563 CP15[CP15_INVALIDATE_UTLB_SINGLE_ENTRY] = value;
564 else if (opcode_2 == 2)
565 CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH] = value;
566 else if (opcode_2 == 3)
567 CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_MVA] = value;
568 }
569 }
570 else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
571 {
572 CP15[CP15_DATA_CACHE_LOCKDOWN] = value;
573 }
574 else if (crn == 10 && opcode_1 == 0)
575 {
576 if (crm == 0 && opcode_2 == 0)
577 {
578 CP15[CP15_TLB_LOCKDOWN] = value;
579 }
580 else if (crm == 2)
581 {
582 if (opcode_2 == 0)
583 CP15[CP15_PRIMARY_REGION_REMAP] = value;
584 else if (opcode_2 == 1)
585 CP15[CP15_NORMAL_REGION_REMAP] = value;
586 }
587 }
588 else if (crn == 13 && opcode_1 == 0 && crm == 0)
589 {
590 if (opcode_2 == 0)
591 CP15[CP15_PID] = value;
592 else if (opcode_2 == 1)
593 CP15[CP15_CONTEXT_ID] = value;
594 else if (opcode_2 == 3)
595 CP15[CP15_THREAD_URO] = value;
596 else if (opcode_2 == 4)
597 CP15[CP15_THREAD_PRW] = value;
598 }
599 else if (crn == 15)
600 {
601 if (opcode_1 == 0 && crm == 12)
602 {
603 if (opcode_2 == 0)
604 CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = value;
605 else if (opcode_2 == 1)
606 CP15[CP15_CYCLE_COUNTER] = value;
607 else if (opcode_2 == 2)
608 CP15[CP15_COUNT_0] = value;
609 else if (opcode_2 == 3)
610 CP15[CP15_COUNT_1] = value;
611 }
612 else if (opcode_1 == 5)
613 {
614 if (crm == 4)
615 {
616 if (opcode_2 == 2)
617 CP15[CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY] = value;
618 else if (opcode_2 == 4)
619 CP15[CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY] = value;
620 }
621 else if (crm == 5 && opcode_2 == 2)
622 {
623 CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = value;
624 }
625 else if (crm == 6 && opcode_2 == 2)
626 {
627 CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = value;
628 }
629 else if (crm == 7 && opcode_2 == 2)
630 {
631 CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = value;
632 }
633 }
634 else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0)
635 {
636 CP15[CP15_TLB_DEBUG_CONTROL] = value;
637 }
638 }
639 }
640
641 // Unprivileged registers
642 if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4)
643 {
644 CP15[CP15_FLUSH_PREFETCH_BUFFER] = value;
645 }
646 else if (crn == 7 && opcode_1 == 0 && crm == 10)
647 {
648 if (opcode_2 == 4)
649 CP15[CP15_DATA_SYNC_BARRIER] = value;
650 else if (opcode_2 == 5)
651 CP15[CP15_DATA_MEMORY_BARRIER] = value;
652 }
653 else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2)
654 {
655 CP15[CP15_THREAD_UPRW] = value;
656 }
657}
diff --git a/src/core/arm/skyeye_common/armstate.h b/src/core/arm/skyeye_common/armstate.h
new file mode 100644
index 000000000..b364e2621
--- /dev/null
+++ b/src/core/arm/skyeye_common/armstate.h
@@ -0,0 +1,252 @@
1/* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator.
2 Copyright (C) 1994 Advanced RISC Machines Ltd.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18#pragma once
19
20#include <array>
21#include <unordered_map>
22
23#include "common/common_types.h"
24#include "core/arm/skyeye_common/arm_regformat.h"
25
26// Signal levels
27enum {
28 LOW = 0,
29 HIGH = 1,
30 LOWHIGH = 1,
31 HIGHLOW = 2
32};
33
34// Cache types
35enum {
36 NONCACHE = 0,
37 DATACACHE = 1,
38 INSTCACHE = 2,
39};
40
41// ARM privilege modes
42enum PrivilegeMode {
43 USER32MODE = 16,
44 FIQ32MODE = 17,
45 IRQ32MODE = 18,
46 SVC32MODE = 19,
47 ABORT32MODE = 23,
48 UNDEF32MODE = 27,
49 SYSTEM32MODE = 31
50};
51
52// ARM privilege mode register banks
53enum {
54 USERBANK = 0,
55 FIQBANK = 1,
56 IRQBANK = 2,
57 SVCBANK = 3,
58 ABORTBANK = 4,
59 UNDEFBANK = 5,
60 DUMMYBANK = 6,
61 SYSTEMBANK = 7
62};
63
64// Hardware vector addresses
65enum {
66 ARMResetV = 0,
67 ARMUndefinedInstrV = 4,
68 ARMSWIV = 8,
69 ARMPrefetchAbortV = 12,
70 ARMDataAbortV = 16,
71 ARMAddrExceptnV = 20,
72 ARMIRQV = 24,
73 ARMFIQV = 28,
74 ARMErrorV = 32, // This is an offset, not an address!
75
76 ARMul_ResetV = ARMResetV,
77 ARMul_UndefinedInstrV = ARMUndefinedInstrV,
78 ARMul_SWIV = ARMSWIV,
79 ARMul_PrefetchAbortV = ARMPrefetchAbortV,
80 ARMul_DataAbortV = ARMDataAbortV,
81 ARMul_AddrExceptnV = ARMAddrExceptnV,
82 ARMul_IRQV = ARMIRQV,
83 ARMul_FIQV = ARMFIQV
84};
85
86// Coprocessor status values
87enum {
88 ARMul_FIRST = 0,
89 ARMul_TRANSFER = 1,
90 ARMul_BUSY = 2,
91 ARMul_DATA = 3,
92 ARMul_INTERRUPT = 4,
93 ARMul_DONE = 0,
94 ARMul_CANT = 1,
95 ARMul_INC = 3
96};
97
98// Instruction condition codes
99enum ConditionCode {
100 EQ = 0,
101 NE = 1,
102 CS = 2,
103 CC = 3,
104 MI = 4,
105 PL = 5,
106 VS = 6,
107 VC = 7,
108 HI = 8,
109 LS = 9,
110 GE = 10,
111 LT = 11,
112 GT = 12,
113 LE = 13,
114 AL = 14,
115 NV = 15,
116};
117
118// Flags for use with the APSR.
119enum : u32 {
120 NBIT = (1U << 31U),
121 ZBIT = (1 << 30),
122 CBIT = (1 << 29),
123 VBIT = (1 << 28),
124 QBIT = (1 << 27),
125 JBIT = (1 << 24),
126 EBIT = (1 << 9),
127 ABIT = (1 << 8),
128 IBIT = (1 << 7),
129 FBIT = (1 << 6),
130 TBIT = (1 << 5),
131
132 // Masks for groups of bits in the APSR.
133 MODEBITS = 0x1F,
134 INTBITS = 0x1C0,
135};
136
137// Values for Emulate.
138enum {
139 STOP = 0, // Stop
140 CHANGEMODE = 1, // Change mode
141 ONCE = 2, // Execute just one iteration
142 RUN = 3 // Continuous execution
143};
144
145
146struct ARMul_State final
147{
148public:
149 explicit ARMul_State(PrivilegeMode initial_mode);
150
151 void ChangePrivilegeMode(u32 new_mode);
152 void Reset();
153
154 // Reads/writes data in big/little endian format based on the
155 // state of the E (endian) bit in the APSR.
156 u16 ReadMemory16(u32 address) const;
157 u32 ReadMemory32(u32 address) const;
158 u64 ReadMemory64(u32 address) const;
159 void WriteMemory16(u32 address, u16 data);
160 void WriteMemory32(u32 address, u32 data);
161 void WriteMemory64(u32 address, u64 data);
162
163 u32 ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const;
164 void WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2);
165
166 // Exclusive memory access functions
167 bool IsExclusiveMemoryAccess(u32 address) const {
168 return exclusive_state && exclusive_tag == (address & RESERVATION_GRANULE_MASK);
169 }
170 void SetExclusiveMemoryAddress(u32 address) {
171 exclusive_tag = address & RESERVATION_GRANULE_MASK;
172 exclusive_state = true;
173 }
174 void UnsetExclusiveMemoryAddress() {
175 exclusive_tag = 0xFFFFFFFF;
176 exclusive_state = false;
177 }
178
179 // Whether or not the given CPU is in big endian mode (E bit is set)
180 bool InBigEndianMode() const {
181 return (Cpsr & (1 << 9)) != 0;
182 }
183 // Whether or not the given CPU is in a mode other than user mode.
184 bool InAPrivilegedMode() const {
185 return (Mode != USER32MODE);
186 }
187 // Note that for the 3DS, a Thumb instruction will only ever be
188 // two bytes in size. Thus we don't need to worry about ThumbEE
189 // or Thumb-2 where instructions can be 4 bytes in length.
190 u32 GetInstructionSize() const {
191 return TFlag ? 2 : 4;
192 }
193
194 std::array<u32, 16> Reg; // The current register file
195 std::array<u32, 2> Reg_usr;
196 std::array<u32, 2> Reg_svc; // R13_SVC R14_SVC
197 std::array<u32, 2> Reg_abort; // R13_ABORT R14_ABORT
198 std::array<u32, 2> Reg_undef; // R13 UNDEF R14 UNDEF
199 std::array<u32, 2> Reg_irq; // R13_IRQ R14_IRQ
200 std::array<u32, 7> Reg_firq; // R8---R14 FIRQ
201 std::array<u32, 7> Spsr; // The exception psr's
202 std::array<u32, CP15_REGISTER_COUNT> CP15;
203
204 // FPSID, FPSCR, and FPEXC
205 std::array<u32, VFP_SYSTEM_REGISTER_COUNT> VFP;
206
207 // VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31).
208 // VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31),
209 // and only 32 singleword registers are accessible (S0-S31).
210 std::array<u32, 64> ExtReg;
211
212 u32 Emulate; // To start and stop emulation
213 u32 Cpsr; // The current PSR
214 u32 Spsr_copy;
215 u32 phys_pc;
216
217 u32 Mode; // The current mode
218 u32 Bank; // The current register bank
219
220 u32 NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed
221 unsigned int shifter_carry_out;
222
223 u32 TFlag; // Thumb state
224
225 unsigned long long NumInstrs; // The number of instructions executed
226 unsigned NumInstrsToExecute;
227
228 unsigned NresetSig; // Reset the processor
229 unsigned NfiqSig;
230 unsigned NirqSig;
231
232 unsigned abortSig;
233 unsigned NtransSig;
234 unsigned bigendSig;
235 unsigned syscallSig;
236
237 // TODO(bunnei): Move this cache to a better place - it should be per codeset (likely per
238 // process for our purposes), not per ARMul_State (which tracks CPU core state).
239 std::unordered_map<u32, int> instruction_cache;
240
241private:
242 void ResetMPCoreCP15Registers();
243
244 // Defines a reservation granule of 2 words, which protects the first 2 words starting at the tag.
245 // This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough to
246 // support LDR/STREXD.
247 static const u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8;
248
249 u32 exclusive_tag; // The address for which the local monitor is in exclusive access mode
250 u32 exclusive_result;
251 bool exclusive_state;
252};
diff --git a/src/core/arm/skyeye_common/armsupp.cpp b/src/core/arm/skyeye_common/armsupp.cpp
new file mode 100644
index 000000000..d31fb9449
--- /dev/null
+++ b/src/core/arm/skyeye_common/armsupp.cpp
@@ -0,0 +1,208 @@
1/* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator.
2 Copyright (C) 1994 Advanced RISC Machines Ltd.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
17
18#include "common/logging/log.h"
19
20#include "core/mem_map.h"
21#include "core/arm/skyeye_common/arm_regformat.h"
22#include "core/arm/skyeye_common/armstate.h"
23#include "core/arm/skyeye_common/armsupp.h"
24
25// Unsigned sum of absolute difference
26u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right)
27{
28 if (left > right)
29 return left - right;
30
31 return right - left;
32}
33
34// Add with carry, indicates if a carry-out or signed overflow occurred.
35u32 AddWithCarry(u32 left, u32 right, u32 carry_in, bool* carry_out_occurred, bool* overflow_occurred)
36{
37 u64 unsigned_sum = (u64)left + (u64)right + (u64)carry_in;
38 s64 signed_sum = (s64)(s32)left + (s64)(s32)right + (s64)carry_in;
39 u64 result = (unsigned_sum & 0xFFFFFFFF);
40
41 if (carry_out_occurred)
42 *carry_out_occurred = (result != unsigned_sum);
43
44 if (overflow_occurred)
45 *overflow_occurred = ((s64)(s32)result != signed_sum);
46
47 return (u32)result;
48}
49
50// Compute whether an addition of A and B, giving RESULT, overflowed.
51bool AddOverflow(u32 a, u32 b, u32 result)
52{
53 return ((NEG(a) && NEG(b) && POS(result)) ||
54 (POS(a) && POS(b) && NEG(result)));
55}
56
57// Compute whether a subtraction of A and B, giving RESULT, overflowed.
58bool SubOverflow(u32 a, u32 b, u32 result)
59{
60 return ((NEG(a) && POS(b) && POS(result)) ||
61 (POS(a) && NEG(b) && NEG(result)));
62}
63
64// Returns true if the Q flag should be set as a result of overflow.
65bool ARMul_AddOverflowQ(u32 a, u32 b)
66{
67 u32 result = a + b;
68 if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0)
69 return true;
70
71 return false;
72}
73
74// 8-bit signed saturated addition
75u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right)
76{
77 u8 result = left + right;
78
79 if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) == 0) {
80 if (left & 0x80)
81 result = 0x80;
82 else
83 result = 0x7F;
84 }
85
86 return result;
87}
88
89// 8-bit signed saturated subtraction
90u8 ARMul_SignedSaturatedSub8(u8 left, u8 right)
91{
92 u8 result = left - right;
93
94 if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) != 0) {
95 if (left & 0x80)
96 result = 0x80;
97 else
98 result = 0x7F;
99 }
100
101 return result;
102}
103
104// 16-bit signed saturated addition
105u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right)
106{
107 u16 result = left + right;
108
109 if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) == 0) {
110 if (left & 0x8000)
111 result = 0x8000;
112 else
113 result = 0x7FFF;
114 }
115
116 return result;
117}
118
119// 16-bit signed saturated subtraction
120u16 ARMul_SignedSaturatedSub16(u16 left, u16 right)
121{
122 u16 result = left - right;
123
124 if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) != 0) {
125 if (left & 0x8000)
126 result = 0x8000;
127 else
128 result = 0x7FFF;
129 }
130
131 return result;
132}
133
134// 8-bit unsigned saturated addition
135u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right)
136{
137 u8 result = left + right;
138
139 if (result < left)
140 result = 0xFF;
141
142 return result;
143}
144
145// 16-bit unsigned saturated addition
146u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right)
147{
148 u16 result = left + right;
149
150 if (result < left)
151 result = 0xFFFF;
152
153 return result;
154}
155
156// 8-bit unsigned saturated subtraction
157u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right)
158{
159 if (left <= right)
160 return 0;
161
162 return left - right;
163}
164
165// 16-bit unsigned saturated subtraction
166u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right)
167{
168 if (left <= right)
169 return 0;
170
171 return left - right;
172}
173
174// Signed saturation.
175u32 ARMul_SignedSatQ(s32 value, u8 shift, bool* saturation_occurred)
176{
177 const u32 max = (1 << shift) - 1;
178 const s32 top = (value >> shift);
179
180 if (top > 0) {
181 *saturation_occurred = true;
182 return max;
183 }
184 else if (top < -1) {
185 *saturation_occurred = true;
186 return ~max;
187 }
188
189 *saturation_occurred = false;
190 return (u32)value;
191}
192
193// Unsigned saturation
194u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred)
195{
196 const u32 max = (1 << shift) - 1;
197
198 if (value < 0) {
199 *saturation_occurred = true;
200 return 0;
201 } else if ((u32)value > max) {
202 *saturation_occurred = true;
203 return max;
204 }
205
206 *saturation_occurred = false;
207 return (u32)value;
208}
diff --git a/src/core/arm/skyeye_common/armsupp.h b/src/core/arm/skyeye_common/armsupp.h
new file mode 100644
index 000000000..391309fa8
--- /dev/null
+++ b/src/core/arm/skyeye_common/armsupp.h
@@ -0,0 +1,32 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1))
10#define BIT(s, n) ((s >> (n)) & 1)
11
12#define POS(i) ( (~(i)) >> 31 )
13#define NEG(i) ( (i) >> 31 )
14
15bool AddOverflow(u32, u32, u32);
16bool SubOverflow(u32, u32, u32);
17
18u32 AddWithCarry(u32, u32, u32, bool*, bool*);
19bool ARMul_AddOverflowQ(u32, u32);
20
21u8 ARMul_SignedSaturatedAdd8(u8, u8);
22u8 ARMul_SignedSaturatedSub8(u8, u8);
23u16 ARMul_SignedSaturatedAdd16(u16, u16);
24u16 ARMul_SignedSaturatedSub16(u16, u16);
25
26u8 ARMul_UnsignedSaturatedAdd8(u8, u8);
27u16 ARMul_UnsignedSaturatedAdd16(u16, u16);
28u8 ARMul_UnsignedSaturatedSub8(u8, u8);
29u16 ARMul_UnsignedSaturatedSub16(u16, u16);
30u8 ARMul_UnsignedAbsoluteDifference(u8, u8);
31u32 ARMul_SignedSatQ(s32, u8, bool*);
32u32 ARMul_UnsignedSatQ(s32, u8, bool*);
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp
index 571d6c2f2..26f303de4 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfp.cpp
@@ -20,39 +20,30 @@
20 20
21/* Note: this file handles interface with arm core and vfp registers */ 21/* Note: this file handles interface with arm core and vfp registers */
22 22
23#include "common/common_funcs.h"
23#include "common/logging/log.h" 24#include "common/logging/log.h"
24 25
25#include "core/arm/skyeye_common/armdefs.h" 26#include "core/arm/skyeye_common/armstate.h"
26#include "core/arm/skyeye_common/vfp/asm_vfp.h" 27#include "core/arm/skyeye_common/vfp/asm_vfp.h"
27#include "core/arm/skyeye_common/vfp/vfp.h" 28#include "core/arm/skyeye_common/vfp/vfp.h"
28 29
29unsigned VFPInit(ARMul_State* state) 30void VFPInit(ARMul_State* state)
30{ 31{
31 state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 | 32 state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
32 VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION; 33 VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
33 state->VFP[VFP_FPEXC] = 0; 34 state->VFP[VFP_FPEXC] = 0;
34 state->VFP[VFP_FPSCR] = 0; 35 state->VFP[VFP_FPSCR] = 0;
35 36
37 // ARM11 MPCore instruction register reset values.
38 state->VFP[VFP_FPINST] = 0xEE000A00;
39 state->VFP[VFP_FPINST2] = 0;
40
36 // ARM11 MPCore feature register values. 41 // ARM11 MPCore feature register values.
37 state->VFP[VFP_MVFR0] = 0x11111111; 42 state->VFP[VFP_MVFR0] = 0x11111111;
38 state->VFP[VFP_MVFR1] = 0; 43 state->VFP[VFP_MVFR1] = 0;
39
40 return 0;
41}
42
43void VMSR(ARMul_State* state, ARMword reg, ARMword Rt)
44{
45 if (reg == 1)
46 {
47 state->VFP[VFP_FPSCR] = state->Reg[Rt];
48 }
49 else if (reg == 8)
50 {
51 state->VFP[VFP_FPEXC] = state->Reg[Rt];
52 }
53} 44}
54 45
55void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value) 46void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value)
56{ 47{
57 if (to_arm) 48 if (to_arm)
58 { 49 {
@@ -64,7 +55,7 @@ void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword*
64 } 55 }
65} 56}
66 57
67void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2) 58void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2)
68{ 59{
69 if (to_arm) 60 if (to_arm)
70 { 61 {
@@ -77,7 +68,7 @@ void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword
77 state->ExtReg[n*2] = *value1; 68 state->ExtReg[n*2] = *value1;
78 } 69 }
79} 70}
80void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2) 71void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2)
81{ 72{
82 if (to_arm) 73 if (to_arm)
83 { 74 {
@@ -91,7 +82,7 @@ void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMwor
91 } 82 }
92} 83}
93 84
94void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm) 85void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm)
95{ 86{
96 if (single) 87 if (single)
97 { 88 {
@@ -104,7 +95,7 @@ void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm)
104 state->ExtReg[d*2] = 0; 95 state->ExtReg[d*2] = 0;
105 } 96 }
106} 97}
107void VMOVR(ARMul_State* state, ARMword single, ARMword d, ARMword m) 98void VMOVR(ARMul_State* state, u32 single, u32 d, u32 m)
108{ 99{
109 if (single) 100 if (single)
110 { 101 {
@@ -153,9 +144,8 @@ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpsc
153 LOG_TRACE(Core_ARM11, "VFP: raising exceptions %08x\n", exceptions); 144 LOG_TRACE(Core_ARM11, "VFP: raising exceptions %08x\n", exceptions);
154 145
155 if (exceptions == VFP_EXCEPTION_ERROR) { 146 if (exceptions == VFP_EXCEPTION_ERROR) {
156 LOG_TRACE(Core_ARM11, "unhandled bounce %x\n", inst); 147 LOG_CRITICAL(Core_ARM11, "unhandled bounce %x\n", inst);
157 exit(-1); 148 Crash();
158 return;
159 } 149 }
160 150
161 /* 151 /*
diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h
index acefae9bb..88908da9f 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.h
+++ b/src/core/arm/skyeye_common/vfp/vfp.h
@@ -26,7 +26,7 @@
26#define CHECK_VFP_ENABLED 26#define CHECK_VFP_ENABLED
27#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]); 27#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
28 28
29unsigned VFPInit(ARMul_State* state); 29void VFPInit(ARMul_State* state);
30 30
31s32 vfp_get_float(ARMul_State* state, u32 reg); 31s32 vfp_get_float(ARMul_State* state, u32 reg);
32void vfp_put_float(ARMul_State* state, s32 val, u32 reg); 32void vfp_put_float(ARMul_State* state, s32 val, u32 reg);
@@ -36,10 +36,8 @@ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpsc
36u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr); 36u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
37u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr); 37u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
38 38
39void VMSR(ARMul_State* state, ARMword reg, ARMword Rt); 39void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value);
40void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value); 40void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2);
41void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2); 41void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2);
42void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2); 42void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm);
43void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm); 43void VMOVR(ARMul_State* state, u32 single, u32 d, u32 imm);
44void VMOVR(ARMul_State* state, ARMword single, ARMword d, ARMword imm);
45
diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h
index 2007d6dc4..91a8d4d57 100644
--- a/src/core/arm/skyeye_common/vfp/vfp_helper.h
+++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h
@@ -34,7 +34,7 @@
34 34
35#include <cstdio> 35#include <cstdio>
36#include "common/common_types.h" 36#include "common/common_types.h"
37#include "core/arm/skyeye_common/armdefs.h" 37#include "core/arm/skyeye_common/armstate.h"
38#include "core/arm/skyeye_common/vfp/asm_vfp.h" 38#include "core/arm/skyeye_common/vfp/asm_vfp.h"
39 39
40#define do_div(n, base) {n/=base;} 40#define do_div(n, base) {n/=base;}
@@ -415,7 +415,7 @@ struct op {
415 u32 flags; 415 u32 flags;
416}; 416};
417 417
418static inline u32 fls(ARMword x) 418static inline u32 fls(u32 x)
419{ 419{
420 int r = 32; 420 int r = 32;
421 421
diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
index f91049585..1d844a66e 100644
--- a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
@@ -70,9 +70,9 @@ static void vfp_double_dump(const char *str, struct vfp_double *d)
70 70
71static void vfp_double_normalise_denormal(struct vfp_double *vd) 71static void vfp_double_normalise_denormal(struct vfp_double *vd)
72{ 72{
73 int bits = 31 - fls((ARMword)(vd->significand >> 32)); 73 int bits = 31 - fls((u32)(vd->significand >> 32));
74 if (bits == 31) 74 if (bits == 31)
75 bits = 63 - fls((ARMword)vd->significand); 75 bits = 63 - fls((u32)vd->significand);
76 76
77 vfp_double_dump("normalise_denormal: in", vd); 77 vfp_double_dump("normalise_denormal: in", vd);
78 78
@@ -109,9 +109,9 @@ u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd,
109 exponent = vd->exponent; 109 exponent = vd->exponent;
110 significand = vd->significand; 110 significand = vd->significand;
111 111
112 shift = 32 - fls((ARMword)(significand >> 32)); 112 shift = 32 - fls((u32)(significand >> 32));
113 if (shift == 32) 113 if (shift == 32)
114 shift = 64 - fls((ARMword)significand); 114 shift = 64 - fls((u32)significand);
115 if (shift) { 115 if (shift) {
116 exponent -= shift; 116 exponent -= shift;
117 significand <<= shift; 117 significand <<= shift;
@@ -566,7 +566,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32
566 /* 566 /*
567 * 2^0 <= m < 2^32-2^8 567 * 2^0 <= m < 2^32-2^8
568 */ 568 */
569 d = (ARMword)((vdm.significand << 1) >> shift); 569 d = (u32)((vdm.significand << 1) >> shift);
570 rem = vdm.significand << (65 - shift); 570 rem = vdm.significand << (65 - shift);
571 571
572 if (rmode == FPSCR_ROUND_NEAREST) { 572 if (rmode == FPSCR_ROUND_NEAREST) {
@@ -647,7 +647,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32
647 int shift = 1023 + 63 - vdm.exponent; /* 58 */ 647 int shift = 1023 + 63 - vdm.exponent; /* 58 */
648 u64 rem, incr = 0; 648 u64 rem, incr = 0;
649 649
650 d = (ARMword)((vdm.significand << 1) >> shift); 650 d = (u32)((vdm.significand << 1) >> shift);
651 rem = vdm.significand << (65 - shift); 651 rem = vdm.significand << (65 - shift);
652 652
653 if (rmode == FPSCR_ROUND_NEAREST) { 653 if (rmode == FPSCR_ROUND_NEAREST) {
diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
index 67fe63aa4..9b99fc5bc 100644
--- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
@@ -51,7 +51,7 @@ VMLA_INST:
51 51
52 CHECK_VFP_CDP_RET; 52 CHECK_VFP_CDP_RET;
53 } 53 }
54 cpu->Reg[15] += GET_INST_SIZE(cpu); 54 cpu->Reg[15] += cpu->GetInstructionSize();
55 INC_PC(sizeof(vmla_inst)); 55 INC_PC(sizeof(vmla_inst));
56 FETCH_INST; 56 FETCH_INST;
57 GOTO_NEXT_INST; 57 GOTO_NEXT_INST;
@@ -100,7 +100,7 @@ VMLS_INST:
100 100
101 CHECK_VFP_CDP_RET; 101 CHECK_VFP_CDP_RET;
102 } 102 }
103 cpu->Reg[15] += GET_INST_SIZE(cpu); 103 cpu->Reg[15] += cpu->GetInstructionSize();
104 INC_PC(sizeof(vmls_inst)); 104 INC_PC(sizeof(vmls_inst));
105 FETCH_INST; 105 FETCH_INST;
106 GOTO_NEXT_INST; 106 GOTO_NEXT_INST;
@@ -149,7 +149,7 @@ VNMLA_INST:
149 149
150 CHECK_VFP_CDP_RET; 150 CHECK_VFP_CDP_RET;
151 } 151 }
152 cpu->Reg[15] += GET_INST_SIZE(cpu); 152 cpu->Reg[15] += cpu->GetInstructionSize();
153 INC_PC(sizeof(vnmla_inst)); 153 INC_PC(sizeof(vnmla_inst));
154 FETCH_INST; 154 FETCH_INST;
155 GOTO_NEXT_INST; 155 GOTO_NEXT_INST;
@@ -199,7 +199,7 @@ VNMLS_INST:
199 199
200 CHECK_VFP_CDP_RET; 200 CHECK_VFP_CDP_RET;
201 } 201 }
202 cpu->Reg[15] += GET_INST_SIZE(cpu); 202 cpu->Reg[15] += cpu->GetInstructionSize();
203 INC_PC(sizeof(vnmls_inst)); 203 INC_PC(sizeof(vnmls_inst));
204 FETCH_INST; 204 FETCH_INST;
205 GOTO_NEXT_INST; 205 GOTO_NEXT_INST;
@@ -248,7 +248,7 @@ VNMUL_INST:
248 248
249 CHECK_VFP_CDP_RET; 249 CHECK_VFP_CDP_RET;
250 } 250 }
251 cpu->Reg[15] += GET_INST_SIZE(cpu); 251 cpu->Reg[15] += cpu->GetInstructionSize();
252 INC_PC(sizeof(vnmul_inst)); 252 INC_PC(sizeof(vnmul_inst));
253 FETCH_INST; 253 FETCH_INST;
254 GOTO_NEXT_INST; 254 GOTO_NEXT_INST;
@@ -297,7 +297,7 @@ VMUL_INST:
297 297
298 CHECK_VFP_CDP_RET; 298 CHECK_VFP_CDP_RET;
299 } 299 }
300 cpu->Reg[15] += GET_INST_SIZE(cpu); 300 cpu->Reg[15] += cpu->GetInstructionSize();
301 INC_PC(sizeof(vmul_inst)); 301 INC_PC(sizeof(vmul_inst));
302 FETCH_INST; 302 FETCH_INST;
303 GOTO_NEXT_INST; 303 GOTO_NEXT_INST;
@@ -346,7 +346,7 @@ VADD_INST:
346 346
347 CHECK_VFP_CDP_RET; 347 CHECK_VFP_CDP_RET;
348 } 348 }
349 cpu->Reg[15] += GET_INST_SIZE(cpu); 349 cpu->Reg[15] += cpu->GetInstructionSize();
350 INC_PC(sizeof(vadd_inst)); 350 INC_PC(sizeof(vadd_inst));
351 FETCH_INST; 351 FETCH_INST;
352 GOTO_NEXT_INST; 352 GOTO_NEXT_INST;
@@ -395,7 +395,7 @@ VSUB_INST:
395 395
396 CHECK_VFP_CDP_RET; 396 CHECK_VFP_CDP_RET;
397 } 397 }
398 cpu->Reg[15] += GET_INST_SIZE(cpu); 398 cpu->Reg[15] += cpu->GetInstructionSize();
399 INC_PC(sizeof(vsub_inst)); 399 INC_PC(sizeof(vsub_inst));
400 FETCH_INST; 400 FETCH_INST;
401 GOTO_NEXT_INST; 401 GOTO_NEXT_INST;
@@ -444,7 +444,7 @@ VDIV_INST:
444 444
445 CHECK_VFP_CDP_RET; 445 CHECK_VFP_CDP_RET;
446 } 446 }
447 cpu->Reg[15] += GET_INST_SIZE(cpu); 447 cpu->Reg[15] += cpu->GetInstructionSize();
448 INC_PC(sizeof(vdiv_inst)); 448 INC_PC(sizeof(vdiv_inst));
449 FETCH_INST; 449 FETCH_INST;
450 GOTO_NEXT_INST; 450 GOTO_NEXT_INST;
@@ -492,7 +492,7 @@ VMOVI_INST:
492 492
493 VMOVI(cpu, inst_cream->single, inst_cream->d, inst_cream->imm); 493 VMOVI(cpu, inst_cream->single, inst_cream->d, inst_cream->imm);
494 } 494 }
495 cpu->Reg[15] += GET_INST_SIZE(cpu); 495 cpu->Reg[15] += cpu->GetInstructionSize();
496 INC_PC(sizeof(vmovi_inst)); 496 INC_PC(sizeof(vmovi_inst));
497 FETCH_INST; 497 FETCH_INST;
498 GOTO_NEXT_INST; 498 GOTO_NEXT_INST;
@@ -536,7 +536,7 @@ VMOVR_INST:
536 536
537 VMOVR(cpu, inst_cream->single, inst_cream->d, inst_cream->m); 537 VMOVR(cpu, inst_cream->single, inst_cream->d, inst_cream->m);
538 } 538 }
539 cpu->Reg[15] += GET_INST_SIZE(cpu); 539 cpu->Reg[15] += cpu->GetInstructionSize();
540 INC_PC(sizeof(vmovr_inst)); 540 INC_PC(sizeof(vmovr_inst));
541 FETCH_INST; 541 FETCH_INST;
542 GOTO_NEXT_INST; 542 GOTO_NEXT_INST;
@@ -585,7 +585,7 @@ VABS_INST:
585 585
586 CHECK_VFP_CDP_RET; 586 CHECK_VFP_CDP_RET;
587 } 587 }
588 cpu->Reg[15] += GET_INST_SIZE(cpu); 588 cpu->Reg[15] += cpu->GetInstructionSize();
589 INC_PC(sizeof(vabs_inst)); 589 INC_PC(sizeof(vabs_inst));
590 FETCH_INST; 590 FETCH_INST;
591 GOTO_NEXT_INST; 591 GOTO_NEXT_INST;
@@ -635,7 +635,7 @@ VNEG_INST:
635 635
636 CHECK_VFP_CDP_RET; 636 CHECK_VFP_CDP_RET;
637 } 637 }
638 cpu->Reg[15] += GET_INST_SIZE(cpu); 638 cpu->Reg[15] += cpu->GetInstructionSize();
639 INC_PC(sizeof(vneg_inst)); 639 INC_PC(sizeof(vneg_inst));
640 FETCH_INST; 640 FETCH_INST;
641 GOTO_NEXT_INST; 641 GOTO_NEXT_INST;
@@ -684,7 +684,7 @@ VSQRT_INST:
684 684
685 CHECK_VFP_CDP_RET; 685 CHECK_VFP_CDP_RET;
686 } 686 }
687 cpu->Reg[15] += GET_INST_SIZE(cpu); 687 cpu->Reg[15] += cpu->GetInstructionSize();
688 INC_PC(sizeof(vsqrt_inst)); 688 INC_PC(sizeof(vsqrt_inst));
689 FETCH_INST; 689 FETCH_INST;
690 GOTO_NEXT_INST; 690 GOTO_NEXT_INST;
@@ -733,7 +733,7 @@ VCMP_INST:
733 733
734 CHECK_VFP_CDP_RET; 734 CHECK_VFP_CDP_RET;
735 } 735 }
736 cpu->Reg[15] += GET_INST_SIZE(cpu); 736 cpu->Reg[15] += cpu->GetInstructionSize();
737 INC_PC(sizeof(vcmp_inst)); 737 INC_PC(sizeof(vcmp_inst));
738 FETCH_INST; 738 FETCH_INST;
739 GOTO_NEXT_INST; 739 GOTO_NEXT_INST;
@@ -782,7 +782,7 @@ VCMP2_INST:
782 782
783 CHECK_VFP_CDP_RET; 783 CHECK_VFP_CDP_RET;
784 } 784 }
785 cpu->Reg[15] += GET_INST_SIZE(cpu); 785 cpu->Reg[15] += cpu->GetInstructionSize();
786 INC_PC(sizeof(vcmp2_inst)); 786 INC_PC(sizeof(vcmp2_inst));
787 FETCH_INST; 787 FETCH_INST;
788 GOTO_NEXT_INST; 788 GOTO_NEXT_INST;
@@ -831,7 +831,7 @@ VCVTBDS_INST:
831 831
832 CHECK_VFP_CDP_RET; 832 CHECK_VFP_CDP_RET;
833 } 833 }
834 cpu->Reg[15] += GET_INST_SIZE(cpu); 834 cpu->Reg[15] += cpu->GetInstructionSize();
835 INC_PC(sizeof(vcvtbds_inst)); 835 INC_PC(sizeof(vcvtbds_inst));
836 FETCH_INST; 836 FETCH_INST;
837 GOTO_NEXT_INST; 837 GOTO_NEXT_INST;
@@ -882,7 +882,7 @@ VCVTBFF_INST:
882 882
883 CHECK_VFP_CDP_RET; 883 CHECK_VFP_CDP_RET;
884 } 884 }
885 cpu->Reg[15] += GET_INST_SIZE(cpu); 885 cpu->Reg[15] += cpu->GetInstructionSize();
886 INC_PC(sizeof(vcvtbff_inst)); 886 INC_PC(sizeof(vcvtbff_inst));
887 FETCH_INST; 887 FETCH_INST;
888 GOTO_NEXT_INST; 888 GOTO_NEXT_INST;
@@ -931,7 +931,7 @@ VCVTBFI_INST:
931 931
932 CHECK_VFP_CDP_RET; 932 CHECK_VFP_CDP_RET;
933 } 933 }
934 cpu->Reg[15] += GET_INST_SIZE(cpu); 934 cpu->Reg[15] += cpu->GetInstructionSize();
935 INC_PC(sizeof(vcvtbfi_inst)); 935 INC_PC(sizeof(vcvtbfi_inst));
936 FETCH_INST; 936 FETCH_INST;
937 GOTO_NEXT_INST; 937 GOTO_NEXT_INST;
@@ -981,7 +981,7 @@ VMOVBRS_INST:
981 981
982 VMOVBRS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->n, &(cpu->Reg[inst_cream->t])); 982 VMOVBRS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->n, &(cpu->Reg[inst_cream->t]));
983 } 983 }
984 cpu->Reg[15] += GET_INST_SIZE(cpu); 984 cpu->Reg[15] += cpu->GetInstructionSize();
985 INC_PC(sizeof(vmovbrs_inst)); 985 INC_PC(sizeof(vmovbrs_inst));
986 FETCH_INST; 986 FETCH_INST;
987 GOTO_NEXT_INST; 987 GOTO_NEXT_INST;
@@ -995,7 +995,7 @@ VMOVBRS_INST:
995#ifdef VFP_INTERPRETER_STRUCT 995#ifdef VFP_INTERPRETER_STRUCT
996struct vmsr_inst { 996struct vmsr_inst {
997 unsigned int reg; 997 unsigned int reg;
998 unsigned int Rd; 998 unsigned int Rt;
999}; 999};
1000#endif 1000#endif
1001#ifdef VFP_INTERPRETER_TRANS 1001#ifdef VFP_INTERPRETER_TRANS
@@ -1009,7 +1009,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index)
1009 inst_base->br = NON_BRANCH; 1009 inst_base->br = NON_BRANCH;
1010 1010
1011 inst_cream->reg = BITS(inst, 16, 19); 1011 inst_cream->reg = BITS(inst, 16, 19);
1012 inst_cream->Rd = BITS(inst, 12, 15); 1012 inst_cream->Rt = BITS(inst, 12, 15);
1013 1013
1014 return inst_base; 1014 return inst_base;
1015} 1015}
@@ -1017,17 +1017,32 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index)
1017#ifdef VFP_INTERPRETER_IMPL 1017#ifdef VFP_INTERPRETER_IMPL
1018VMSR_INST: 1018VMSR_INST:
1019{ 1019{
1020 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1020 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
1021 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled , 1021 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled ,
1022 and in privileged mode */ 1022 and in privileged mode */
1023 /* Exceptions must be checked, according to v7 ref manual */ 1023 /* Exceptions must be checked, according to v7 ref manual */
1024 CHECK_VFP_ENABLED; 1024 CHECK_VFP_ENABLED;
1025 1025
1026 vmsr_inst *inst_cream = (vmsr_inst *)inst_base->component; 1026 vmsr_inst* const inst_cream = (vmsr_inst*)inst_base->component;
1027
1028 unsigned int reg = inst_cream->reg;
1029 unsigned int rt = inst_cream->Rt;
1027 1030
1028 VMSR(cpu, inst_cream->reg, inst_cream->Rd); 1031 if (reg == 1)
1032 {
1033 cpu->VFP[VFP_FPSCR] = cpu->Reg[rt];
1034 }
1035 else if (cpu->InAPrivilegedMode())
1036 {
1037 if (reg == 8)
1038 cpu->VFP[VFP_FPEXC] = cpu->Reg[rt];
1039 else if (reg == 9)
1040 cpu->VFP[VFP_FPINST] = cpu->Reg[rt];
1041 else if (reg == 10)
1042 cpu->VFP[VFP_FPINST2] = cpu->Reg[rt];
1043 }
1029 } 1044 }
1030 cpu->Reg[15] += GET_INST_SIZE(cpu); 1045 cpu->Reg[15] += cpu->GetInstructionSize();
1031 INC_PC(sizeof(vmsr_inst)); 1046 INC_PC(sizeof(vmsr_inst));
1032 FETCH_INST; 1047 FETCH_INST;
1033 GOTO_NEXT_INST; 1048 GOTO_NEXT_INST;
@@ -1075,7 +1090,7 @@ VMOVBRC_INST:
1075 1090
1076 cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index] = cpu->Reg[inst_cream->t]; 1091 cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index] = cpu->Reg[inst_cream->t];
1077 } 1092 }
1078 cpu->Reg[15] += GET_INST_SIZE(cpu); 1093 cpu->Reg[15] += cpu->GetInstructionSize();
1079 INC_PC(sizeof(vmovbrc_inst)); 1094 INC_PC(sizeof(vmovbrc_inst));
1080 FETCH_INST; 1095 FETCH_INST;
1081 GOTO_NEXT_INST; 1096 GOTO_NEXT_INST;
@@ -1111,19 +1126,22 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmrs)(unsigned int inst, int index)
1111#ifdef VFP_INTERPRETER_IMPL 1126#ifdef VFP_INTERPRETER_IMPL
1112VMRS_INST: 1127VMRS_INST:
1113{ 1128{
1114 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1129 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
1115 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled, 1130 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled,
1116 and in privileged mode */ 1131 and in privileged mode */
1117 /* Exceptions must be checked, according to v7 ref manual */ 1132 /* Exceptions must be checked, according to v7 ref manual */
1118 CHECK_VFP_ENABLED; 1133 CHECK_VFP_ENABLED;
1119 1134
1120 vmrs_inst *inst_cream = (vmrs_inst *)inst_base->component; 1135 vmrs_inst* const inst_cream = (vmrs_inst*)inst_base->component;
1121 1136
1122 if (inst_cream->reg == 1) /* FPSCR */ 1137 unsigned int reg = inst_cream->reg;
1138 unsigned int rt = inst_cream->Rt;
1139
1140 if (reg == 1) // FPSCR
1123 { 1141 {
1124 if (inst_cream->Rt != 15) 1142 if (rt != 15)
1125 { 1143 {
1126 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSCR]; 1144 cpu->Reg[rt] = cpu->VFP[VFP_FPSCR];
1127 } 1145 }
1128 else 1146 else
1129 { 1147 {
@@ -1133,28 +1151,29 @@ VMRS_INST:
1133 cpu->VFlag = (cpu->VFP[VFP_FPSCR] >> 28) & 1; 1151 cpu->VFlag = (cpu->VFP[VFP_FPSCR] >> 28) & 1;
1134 } 1152 }
1135 } 1153 }
1136 else 1154 else if (reg == 0)
1137 { 1155 {
1138 switch (inst_cream->reg) 1156 cpu->Reg[rt] = cpu->VFP[VFP_FPSID];
1139 { 1157 }
1140 case 0: 1158 else if (reg == 6)
1141 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSID]; 1159 {
1142 break; 1160 cpu->Reg[rt] = cpu->VFP[VFP_MVFR1];
1143 case 6: 1161 }
1144 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR1]; 1162 else if (reg == 7)
1145 break; 1163 {
1146 case 7: 1164 cpu->Reg[rt] = cpu->VFP[VFP_MVFR0];
1147 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR0]; 1165 }
1148 break; 1166 else if (cpu->InAPrivilegedMode())
1149 case 8: 1167 {
1150 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPEXC]; 1168 if (reg == 8)
1151 break; 1169 cpu->Reg[rt] = cpu->VFP[VFP_FPEXC];
1152 default: 1170 else if (reg == 9)
1153 break; 1171 cpu->Reg[rt] = cpu->VFP[VFP_FPINST];
1154 } 1172 else if (reg == 10)
1173 cpu->Reg[rt] = cpu->VFP[VFP_FPINST2];
1155 } 1174 }
1156 } 1175 }
1157 cpu->Reg[15] += GET_INST_SIZE(cpu); 1176 cpu->Reg[15] += cpu->GetInstructionSize();
1158 INC_PC(sizeof(vmrs_inst)); 1177 INC_PC(sizeof(vmrs_inst));
1159 FETCH_INST; 1178 FETCH_INST;
1160 GOTO_NEXT_INST; 1179 GOTO_NEXT_INST;
@@ -1202,7 +1221,7 @@ VMOVBCR_INST:
1202 1221
1203 cpu->Reg[inst_cream->t] = cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index]; 1222 cpu->Reg[inst_cream->t] = cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index];
1204 } 1223 }
1205 cpu->Reg[15] += GET_INST_SIZE(cpu); 1224 cpu->Reg[15] += cpu->GetInstructionSize();
1206 INC_PC(sizeof(vmovbcr_inst)); 1225 INC_PC(sizeof(vmovbcr_inst));
1207 FETCH_INST; 1226 FETCH_INST;
1208 GOTO_NEXT_INST; 1227 GOTO_NEXT_INST;
@@ -1255,7 +1274,7 @@ VMOVBRRSS_INST:
1255 VMOVBRRSS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m, 1274 VMOVBRRSS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m,
1256 &cpu->Reg[inst_cream->t], &cpu->Reg[inst_cream->t2]); 1275 &cpu->Reg[inst_cream->t], &cpu->Reg[inst_cream->t2]);
1257 } 1276 }
1258 cpu->Reg[15] += GET_INST_SIZE(cpu); 1277 cpu->Reg[15] += cpu->GetInstructionSize();
1259 INC_PC(sizeof(vmovbrrss_inst)); 1278 INC_PC(sizeof(vmovbrrss_inst));
1260 FETCH_INST; 1279 FETCH_INST;
1261 GOTO_NEXT_INST; 1280 GOTO_NEXT_INST;
@@ -1303,7 +1322,7 @@ VMOVBRRD_INST:
1303 VMOVBRRD(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m, 1322 VMOVBRRD(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m,
1304 &(cpu->Reg[inst_cream->t]), &(cpu->Reg[inst_cream->t2])); 1323 &(cpu->Reg[inst_cream->t]), &(cpu->Reg[inst_cream->t2]));
1305 } 1324 }
1306 cpu->Reg[15] += GET_INST_SIZE(cpu); 1325 cpu->Reg[15] += cpu->GetInstructionSize();
1307 INC_PC(sizeof(vmovbrrd_inst)); 1326 INC_PC(sizeof(vmovbrrd_inst));
1308 FETCH_INST; 1327 FETCH_INST;
1309 GOTO_NEXT_INST; 1328 GOTO_NEXT_INST;
@@ -1359,23 +1378,23 @@ VSTR_INST:
1359 1378
1360 if (inst_cream->single) 1379 if (inst_cream->single)
1361 { 1380 {
1362 WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d]); 1381 cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d]);
1363 } 1382 }
1364 else 1383 else
1365 { 1384 {
1366 const u32 word1 = cpu->ExtReg[inst_cream->d*2+0]; 1385 const u32 word1 = cpu->ExtReg[inst_cream->d*2+0];
1367 const u32 word2 = cpu->ExtReg[inst_cream->d*2+1]; 1386 const u32 word2 = cpu->ExtReg[inst_cream->d*2+1];
1368 1387
1369 if (InBigEndianMode(cpu)) { 1388 if (cpu->InBigEndianMode()) {
1370 WriteMemory32(cpu, addr + 0, word2); 1389 cpu->WriteMemory32(addr + 0, word2);
1371 WriteMemory32(cpu, addr + 4, word1); 1390 cpu->WriteMemory32(addr + 4, word1);
1372 } else { 1391 } else {
1373 WriteMemory32(cpu, addr + 0, word1); 1392 cpu->WriteMemory32(addr + 0, word1);
1374 WriteMemory32(cpu, addr + 4, word2); 1393 cpu->WriteMemory32(addr + 4, word2);
1375 } 1394 }
1376 } 1395 }
1377 } 1396 }
1378 cpu->Reg[15] += GET_INST_SIZE(cpu); 1397 cpu->Reg[15] += cpu->GetInstructionSize();
1379 INC_PC(sizeof(vstr_inst)); 1398 INC_PC(sizeof(vstr_inst));
1380 FETCH_INST; 1399 FETCH_INST;
1381 GOTO_NEXT_INST; 1400 GOTO_NEXT_INST;
@@ -1425,7 +1444,7 @@ VPUSH_INST:
1425 { 1444 {
1426 if (inst_cream->single) 1445 if (inst_cream->single)
1427 { 1446 {
1428 WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d+i]); 1447 cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d+i]);
1429 addr += 4; 1448 addr += 4;
1430 } 1449 }
1431 else 1450 else
@@ -1433,12 +1452,12 @@ VPUSH_INST:
1433 const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0]; 1452 const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0];
1434 const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1]; 1453 const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1];
1435 1454
1436 if (InBigEndianMode(cpu)) { 1455 if (cpu->InBigEndianMode()) {
1437 WriteMemory32(cpu, addr + 0, word2); 1456 cpu->WriteMemory32(addr + 0, word2);
1438 WriteMemory32(cpu, addr + 4, word1); 1457 cpu->WriteMemory32(addr + 4, word1);
1439 } else { 1458 } else {
1440 WriteMemory32(cpu, addr + 0, word1); 1459 cpu->WriteMemory32(addr + 0, word1);
1441 WriteMemory32(cpu, addr + 4, word2); 1460 cpu->WriteMemory32(addr + 4, word2);
1442 } 1461 }
1443 1462
1444 addr += 8; 1463 addr += 8;
@@ -1447,7 +1466,7 @@ VPUSH_INST:
1447 1466
1448 cpu->Reg[R13] -= inst_cream->imm32; 1467 cpu->Reg[R13] -= inst_cream->imm32;
1449 } 1468 }
1450 cpu->Reg[15] += GET_INST_SIZE(cpu); 1469 cpu->Reg[15] += cpu->GetInstructionSize();
1451 INC_PC(sizeof(vpush_inst)); 1470 INC_PC(sizeof(vpush_inst));
1452 FETCH_INST; 1471 FETCH_INST;
1453 GOTO_NEXT_INST; 1472 GOTO_NEXT_INST;
@@ -1503,7 +1522,7 @@ VSTM_INST: /* encoding 1 */
1503 { 1522 {
1504 if (inst_cream->single) 1523 if (inst_cream->single)
1505 { 1524 {
1506 WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d+i]); 1525 cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d+i]);
1507 addr += 4; 1526 addr += 4;
1508 } 1527 }
1509 else 1528 else
@@ -1511,12 +1530,12 @@ VSTM_INST: /* encoding 1 */
1511 const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0]; 1530 const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0];
1512 const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1]; 1531 const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1];
1513 1532
1514 if (InBigEndianMode(cpu)) { 1533 if (cpu->InBigEndianMode()) {
1515 WriteMemory32(cpu, addr + 0, word2); 1534 cpu->WriteMemory32(addr + 0, word2);
1516 WriteMemory32(cpu, addr + 4, word1); 1535 cpu->WriteMemory32(addr + 4, word1);
1517 } else { 1536 } else {
1518 WriteMemory32(cpu, addr + 0, word1); 1537 cpu->WriteMemory32(addr + 0, word1);
1519 WriteMemory32(cpu, addr + 4, word2); 1538 cpu->WriteMemory32(addr + 4, word2);
1520 } 1539 }
1521 1540
1522 addr += 8; 1541 addr += 8;
@@ -1578,15 +1597,15 @@ VPOP_INST:
1578 { 1597 {
1579 if (inst_cream->single) 1598 if (inst_cream->single)
1580 { 1599 {
1581 cpu->ExtReg[inst_cream->d+i] = ReadMemory32(cpu, addr); 1600 cpu->ExtReg[inst_cream->d+i] = cpu->ReadMemory32(addr);
1582 addr += 4; 1601 addr += 4;
1583 } 1602 }
1584 else 1603 else
1585 { 1604 {
1586 const u32 word1 = ReadMemory32(cpu, addr + 0); 1605 const u32 word1 = cpu->ReadMemory32(addr + 0);
1587 const u32 word2 = ReadMemory32(cpu, addr + 4); 1606 const u32 word2 = cpu->ReadMemory32(addr + 4);
1588 1607
1589 if (InBigEndianMode(cpu)) { 1608 if (cpu->InBigEndianMode()) {
1590 cpu->ExtReg[(inst_cream->d+i)*2+0] = word2; 1609 cpu->ExtReg[(inst_cream->d+i)*2+0] = word2;
1591 cpu->ExtReg[(inst_cream->d+i)*2+1] = word1; 1610 cpu->ExtReg[(inst_cream->d+i)*2+1] = word1;
1592 } else { 1611 } else {
@@ -1599,7 +1618,7 @@ VPOP_INST:
1599 } 1618 }
1600 cpu->Reg[R13] += inst_cream->imm32; 1619 cpu->Reg[R13] += inst_cream->imm32;
1601 } 1620 }
1602 cpu->Reg[15] += GET_INST_SIZE(cpu); 1621 cpu->Reg[15] += cpu->GetInstructionSize();
1603 INC_PC(sizeof(vpop_inst)); 1622 INC_PC(sizeof(vpop_inst));
1604 FETCH_INST; 1623 FETCH_INST;
1605 GOTO_NEXT_INST; 1624 GOTO_NEXT_INST;
@@ -1651,14 +1670,14 @@ VLDR_INST:
1651 1670
1652 if (inst_cream->single) 1671 if (inst_cream->single)
1653 { 1672 {
1654 cpu->ExtReg[inst_cream->d] = ReadMemory32(cpu, addr); 1673 cpu->ExtReg[inst_cream->d] = cpu->ReadMemory32(addr);
1655 } 1674 }
1656 else 1675 else
1657 { 1676 {
1658 const u32 word1 = ReadMemory32(cpu, addr + 0); 1677 const u32 word1 = cpu->ReadMemory32(addr + 0);
1659 const u32 word2 = ReadMemory32(cpu, addr + 4); 1678 const u32 word2 = cpu->ReadMemory32(addr + 4);
1660 1679
1661 if (InBigEndianMode(cpu)) { 1680 if (cpu->InBigEndianMode()) {
1662 cpu->ExtReg[inst_cream->d*2+0] = word2; 1681 cpu->ExtReg[inst_cream->d*2+0] = word2;
1663 cpu->ExtReg[inst_cream->d*2+1] = word1; 1682 cpu->ExtReg[inst_cream->d*2+1] = word1;
1664 } else { 1683 } else {
@@ -1667,7 +1686,7 @@ VLDR_INST:
1667 } 1686 }
1668 } 1687 }
1669 } 1688 }
1670 cpu->Reg[15] += GET_INST_SIZE(cpu); 1689 cpu->Reg[15] += cpu->GetInstructionSize();
1671 INC_PC(sizeof(vldr_inst)); 1690 INC_PC(sizeof(vldr_inst));
1672 FETCH_INST; 1691 FETCH_INST;
1673 GOTO_NEXT_INST; 1692 GOTO_NEXT_INST;
@@ -1723,15 +1742,15 @@ VLDM_INST:
1723 { 1742 {
1724 if (inst_cream->single) 1743 if (inst_cream->single)
1725 { 1744 {
1726 cpu->ExtReg[inst_cream->d+i] = ReadMemory32(cpu, addr); 1745 cpu->ExtReg[inst_cream->d+i] = cpu->ReadMemory32(addr);
1727 addr += 4; 1746 addr += 4;
1728 } 1747 }
1729 else 1748 else
1730 { 1749 {
1731 const u32 word1 = ReadMemory32(cpu, addr + 0); 1750 const u32 word1 = cpu->ReadMemory32(addr + 0);
1732 const u32 word2 = ReadMemory32(cpu, addr + 4); 1751 const u32 word2 = cpu->ReadMemory32(addr + 4);
1733 1752
1734 if (InBigEndianMode(cpu)) { 1753 if (cpu->InBigEndianMode()) {
1735 cpu->ExtReg[(inst_cream->d+i)*2+0] = word2; 1754 cpu->ExtReg[(inst_cream->d+i)*2+0] = word2;
1736 cpu->ExtReg[(inst_cream->d+i)*2+1] = word1; 1755 cpu->ExtReg[(inst_cream->d+i)*2+1] = word1;
1737 } else { 1756 } else {
@@ -1747,7 +1766,7 @@ VLDM_INST:
1747 cpu->Reg[inst_cream->n] - inst_cream->imm32); 1766 cpu->Reg[inst_cream->n] - inst_cream->imm32);
1748 } 1767 }
1749 } 1768 }
1750 cpu->Reg[15] += GET_INST_SIZE(cpu); 1769 cpu->Reg[15] += cpu->GetInstructionSize();
1751 INC_PC(sizeof(vldm_inst)); 1770 INC_PC(sizeof(vldm_inst));
1752 FETCH_INST; 1771 FETCH_INST;
1753 GOTO_NEXT_INST; 1772 GOTO_NEXT_INST;
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
index 5a655a6f2..e5d339252 100644
--- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
@@ -53,6 +53,8 @@
53 53
54#include <cinttypes> 54#include <cinttypes>
55 55
56#include "common/common_funcs.h"
57#include "common/common_types.h"
56#include "common/logging/log.h" 58#include "common/logging/log.h"
57 59
58#include "core/arm/skyeye_common/vfp/vfp_helper.h" 60#include "core/arm/skyeye_common/vfp/vfp_helper.h"
@@ -1246,7 +1248,7 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
1246 1248
1247 if (!fop->fn) { 1249 if (!fop->fn) {
1248 LOG_CRITICAL(Core_ARM11, "could not find single op %d, inst=0x%x@0x%x", FEXT_TO_IDX(inst), inst, state->Reg[15]); 1250 LOG_CRITICAL(Core_ARM11, "could not find single op %d, inst=0x%x@0x%x", FEXT_TO_IDX(inst), inst, state->Reg[15]);
1249 exit(-1); 1251 Crash();
1250 goto invalid; 1252 goto invalid;
1251 } 1253 }
1252 1254
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 79038cd52..dddc16708 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -2,15 +2,12 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h"
6#include "common/logging/log.h" 5#include "common/logging/log.h"
7 6
8#include "core/core.h" 7#include "core/core.h"
9#include "core/core_timing.h" 8#include "core/core_timing.h"
10 9
11#include "core/settings.h"
12#include "core/arm/arm_interface.h" 10#include "core/arm/arm_interface.h"
13#include "core/arm/disassembler/arm_disasm.h"
14#include "core/arm/dyncom/arm_dyncom.h" 11#include "core/arm/dyncom/arm_dyncom.h"
15#include "core/hle/hle.h" 12#include "core/hle/hle.h"
16#include "core/hle/kernel/thread.h" 13#include "core/hle/kernel/thread.h"
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index e53c2e606..20f2da0fe 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -3,12 +3,12 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <atomic> 5#include <atomic>
6#include <cstdio>
7#include <mutex> 6#include <mutex>
8#include <vector> 7#include <vector>
9 8
10#include "common/assert.h"
11#include "common/chunk_file.h" 9#include "common/chunk_file.h"
10#include "common/logging/log.h"
11#include "common/string_util.h"
12 12
13#include "core/arm/arm_interface.h" 13#include "core/arm/arm_interface.h"
14#include "core/core.h" 14#include "core/core.h"
@@ -502,7 +502,7 @@ void Advance() {
502 Core::g_app_core->down_count += diff; 502 Core::g_app_core->down_count += diff;
503 } 503 }
504 if (advance_callback) 504 if (advance_callback)
505 advance_callback(cycles_executed); 505 advance_callback(static_cast<int>(cycles_executed));
506} 506}
507 507
508void LogPendingEvents() { 508void LogPendingEvents() {
diff --git a/src/core/file_sys/archive_backend.cpp b/src/core/file_sys/archive_backend.cpp
index 45a559ce8..3f81447df 100644
--- a/src/core/file_sys/archive_backend.cpp
+++ b/src/core/file_sys/archive_backend.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstddef>
6#include <iomanip>
5#include <sstream> 7#include <sstream>
6 8
7#include "common/logging/log.h" 9#include "common/logging/log.h"
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index e50c58a52..92dad8e6f 100644
--- a/src/core/file_sys/archive_extsavedata.cpp
+++ b/src/core/file_sys/archive_extsavedata.cpp
@@ -2,17 +2,18 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <sys/stat.h> 5#include <algorithm>
6#include <vector>
6 7
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "common/file_util.h" 9#include "common/file_util.h"
9#include "common/logging/log.h" 10#include "common/logging/log.h"
10#include "common/make_unique.h" 11#include "common/make_unique.h"
12#include "common/string_util.h"
11 13
12#include "core/file_sys/archive_extsavedata.h" 14#include "core/file_sys/archive_extsavedata.h"
13#include "core/file_sys/disk_archive.h" 15#include "core/file_sys/disk_archive.h"
14#include "core/hle/service/fs/archive.h" 16#include "core/hle/service/fs/archive.h"
15#include "core/settings.h"
16 17
17//////////////////////////////////////////////////////////////////////////////////////////////////// 18////////////////////////////////////////////////////////////////////////////////////////////////////
18// FileSys namespace 19// FileSys namespace
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h
index ef0b27bde..ec8d770fc 100644
--- a/src/core/file_sys/archive_extsavedata.h
+++ b/src/core/file_sys/archive_extsavedata.h
@@ -4,10 +4,13 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8#include <string>
9
7#include "common/common_types.h" 10#include "common/common_types.h"
8 11
9#include "core/file_sys/disk_archive.h" 12#include "core/file_sys/archive_backend.h"
10#include "core/loader/loader.h" 13#include "core/hle/result.h"
11 14
12//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace 16// FileSys namespace
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp
index d4a12ed10..696b51a94 100644
--- a/src/core/file_sys/archive_romfs.cpp
+++ b/src/core/file_sys/archive_romfs.cpp
@@ -2,30 +2,30 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
5#include <memory> 6#include <memory>
6 7
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "common/file_util.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/make_unique.h" 10#include "common/make_unique.h"
11 11
12#include "core/file_sys/archive_romfs.h" 12#include "core/file_sys/archive_romfs.h"
13#include "core/file_sys/ivfc_archive.h"
13 14
14//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace 16// FileSys namespace
16 17
17namespace FileSys { 18namespace FileSys {
18 19
19ArchiveFactory_RomFS::ArchiveFactory_RomFS(const Loader::AppLoader& app_loader) 20ArchiveFactory_RomFS::ArchiveFactory_RomFS(Loader::AppLoader& app_loader) {
20 : romfs_data(std::make_shared<std::vector<u8>>()) {
21 // Load the RomFS from the app 21 // Load the RomFS from the app
22 if (Loader::ResultStatus::Success != app_loader.ReadRomFS(*romfs_data)) { 22 if (Loader::ResultStatus::Success != app_loader.ReadRomFS(romfs_file, data_offset, data_size)) {
23 LOG_ERROR(Service_FS, "Unable to read RomFS!"); 23 LOG_ERROR(Service_FS, "Unable to read RomFS!");
24 } 24 }
25} 25}
26 26
27ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_RomFS::Open(const Path& path) { 27ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_RomFS::Open(const Path& path) {
28 auto archive = Common::make_unique<IVFCArchive>(romfs_data); 28 auto archive = Common::make_unique<IVFCArchive>(romfs_file, data_offset, data_size);
29 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 29 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
30} 30}
31 31
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h
index 409bc670a..2bedfa9c6 100644
--- a/src/core/file_sys/archive_romfs.h
+++ b/src/core/file_sys/archive_romfs.h
@@ -5,11 +5,13 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <string>
8#include <vector> 9#include <vector>
9 10
10#include "common/common_types.h" 11#include "common/common_types.h"
11 12
12#include "core/file_sys/ivfc_archive.h" 13#include "core/file_sys/archive_backend.h"
14#include "core/hle/result.h"
13#include "core/loader/loader.h" 15#include "core/loader/loader.h"
14 16
15//////////////////////////////////////////////////////////////////////////////////////////////////// 17////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -20,14 +22,16 @@ namespace FileSys {
20/// File system interface to the RomFS archive 22/// File system interface to the RomFS archive
21class ArchiveFactory_RomFS final : public ArchiveFactory { 23class ArchiveFactory_RomFS final : public ArchiveFactory {
22public: 24public:
23 ArchiveFactory_RomFS(const Loader::AppLoader& app_loader); 25 ArchiveFactory_RomFS(Loader::AppLoader& app_loader);
24 26
25 std::string GetName() const override { return "RomFS"; } 27 std::string GetName() const override { return "RomFS"; }
26 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; 28 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
27 ResultCode Format(const Path& path) override; 29 ResultCode Format(const Path& path) override;
28 30
29private: 31private:
30 std::shared_ptr<std::vector<u8>> romfs_data; 32 std::shared_ptr<FileUtil::IOFile> romfs_file;
33 u64 data_offset;
34 u64 data_size;
31}; 35};
32 36
33} // namespace FileSys 37} // namespace FileSys
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
index a92309377..12876899f 100644
--- a/src/core/file_sys/archive_savedata.cpp
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -2,18 +2,18 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <sys/stat.h> 5#include <algorithm>
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/file_util.h" 8#include "common/file_util.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/make_unique.h" 10#include "common/make_unique.h"
11#include "common/string_util.h"
11 12
12#include "core/file_sys/archive_savedata.h" 13#include "core/file_sys/archive_savedata.h"
13#include "core/file_sys/disk_archive.h" 14#include "core/file_sys/disk_archive.h"
14#include "core/hle/kernel/process.h" 15#include "core/hle/kernel/process.h"
15#include "core/hle/service/fs/archive.h" 16#include "core/hle/service/fs/archive.h"
16#include "core/settings.h"
17 17
18//////////////////////////////////////////////////////////////////////////////////////////////////// 18////////////////////////////////////////////////////////////////////////////////////////////////////
19// FileSys namespace 19// FileSys namespace
@@ -37,7 +37,7 @@ ArchiveFactory_SaveData::ArchiveFactory_SaveData(const std::string& sdmc_directo
37} 37}
38 38
39ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) { 39ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) {
40 std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->program_id); 40 std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id);
41 if (!FileUtil::Exists(concrete_mount_point)) { 41 if (!FileUtil::Exists(concrete_mount_point)) {
42 // When a SaveData archive is created for the first time, it is not yet formatted 42 // When a SaveData archive is created for the first time, it is not yet formatted
43 // and the save file/directory structure expected by the game has not yet been initialized. 43 // and the save file/directory structure expected by the game has not yet been initialized.
@@ -52,7 +52,7 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const P
52} 52}
53 53
54ResultCode ArchiveFactory_SaveData::Format(const Path& path) { 54ResultCode ArchiveFactory_SaveData::Format(const Path& path) {
55 std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->program_id); 55 std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id);
56 FileUtil::DeleteDirRecursively(concrete_mount_point); 56 FileUtil::DeleteDirRecursively(concrete_mount_point);
57 FileUtil::CreateFullPath(concrete_mount_point); 57 FileUtil::CreateFullPath(concrete_mount_point);
58 return RESULT_SUCCESS; 58 return RESULT_SUCCESS;
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h
index db17afc92..1f65297dd 100644
--- a/src/core/file_sys/archive_savedata.h
+++ b/src/core/file_sys/archive_savedata.h
@@ -4,10 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include <memory>
8#include <string>
8 9
9#include "core/file_sys/disk_archive.h" 10#include "core/file_sys/archive_backend.h"
10#include "core/loader/loader.h" 11#include "core/hle/result.h"
11 12
12//////////////////////////////////////////////////////////////////////////////////////////////////// 13////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace 14// FileSys namespace
diff --git a/src/core/file_sys/archive_savedatacheck.cpp b/src/core/file_sys/archive_savedatacheck.cpp
index e7e4fbf1d..ea1dfe2c7 100644
--- a/src/core/file_sys/archive_savedatacheck.cpp
+++ b/src/core/file_sys/archive_savedatacheck.cpp
@@ -2,11 +2,17 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <vector>
7
8#include "common/common_types.h"
5#include "common/file_util.h" 9#include "common/file_util.h"
6#include "common/logging/log.h" 10#include "common/logging/log.h"
7#include "common/make_unique.h" 11#include "common/make_unique.h"
12#include "common/string_util.h"
8 13
9#include "core/file_sys/archive_savedatacheck.h" 14#include "core/file_sys/archive_savedatacheck.h"
15#include "core/file_sys/ivfc_archive.h"
10#include "core/hle/service/fs/archive.h" 16#include "core/hle/service/fs/archive.h"
11 17
12//////////////////////////////////////////////////////////////////////////////////////////////////// 18////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -31,17 +37,14 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveDataCheck::Open(co
31 auto vec = path.AsBinary(); 37 auto vec = path.AsBinary();
32 const u32* data = reinterpret_cast<u32*>(vec.data()); 38 const u32* data = reinterpret_cast<u32*>(vec.data());
33 std::string file_path = GetSaveDataCheckPath(mount_point, data[1], data[0]); 39 std::string file_path = GetSaveDataCheckPath(mount_point, data[1], data[0]);
34 FileUtil::IOFile file(file_path, "rb"); 40 auto file = std::make_shared<FileUtil::IOFile>(file_path, "rb");
35 41
36 if (!file.IsOpen()) { 42 if (!file->IsOpen()) {
37 return ResultCode(-1); // TODO(Subv): Find the right error code 43 return ResultCode(-1); // TODO(Subv): Find the right error code
38 } 44 }
39 auto size = file.GetSize(); 45 auto size = file->GetSize();
40 auto raw_data = std::make_shared<std::vector<u8>>(size);
41 file.ReadBytes(raw_data->data(), size);
42 file.Close();
43 46
44 auto archive = Common::make_unique<IVFCArchive>(std::move(raw_data)); 47 auto archive = Common::make_unique<IVFCArchive>(file, 0, size);
45 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 48 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
46} 49}
47 50
diff --git a/src/core/file_sys/archive_savedatacheck.h b/src/core/file_sys/archive_savedatacheck.h
index f78a6f02e..b14aefe8b 100644
--- a/src/core/file_sys/archive_savedatacheck.h
+++ b/src/core/file_sys/archive_savedatacheck.h
@@ -4,12 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <vector> 7#include <memory>
8#include <string>
8 9
9#include "common/common_types.h" 10#include "core/file_sys/archive_backend.h"
10 11#include "core/hle/result.h"
11#include "core/file_sys/ivfc_archive.h"
12#include "core/loader/loader.h"
13 12
14//////////////////////////////////////////////////////////////////////////////////////////////////// 13////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace 14// FileSys namespace
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index c1234a186..5c825f429 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -2,9 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <sys/stat.h> 5#include <algorithm>
6 6
7#include "common/common_types.h"
8#include "common/file_util.h" 7#include "common/file_util.h"
9#include "common/logging/log.h" 8#include "common/logging/log.h"
10#include "common/make_unique.h" 9#include "common/make_unique.h"
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index 1becf6c0f..10b273bdb 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -4,10 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include <memory>
8#include <string>
8 9
9#include "core/file_sys/disk_archive.h" 10#include "core/file_sys/archive_backend.h"
10#include "core/loader/loader.h" 11#include "core/hle/result.h"
11 12
12//////////////////////////////////////////////////////////////////////////////////////////////////// 13////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace 14// FileSys namespace
diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp
index 4fe785c97..896f89529 100644
--- a/src/core/file_sys/archive_systemsavedata.cpp
+++ b/src/core/file_sys/archive_systemsavedata.cpp
@@ -2,15 +2,17 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <sys/stat.h> 5#include <algorithm>
6#include <vector>
6 7
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "common/file_util.h" 9#include "common/file_util.h"
9#include "common/make_unique.h" 10#include "common/make_unique.h"
11#include "common/string_util.h"
10 12
11#include "core/file_sys/archive_systemsavedata.h" 13#include "core/file_sys/archive_systemsavedata.h"
14#include "core/file_sys/disk_archive.h"
12#include "core/hle/service/fs/archive.h" 15#include "core/hle/service/fs/archive.h"
13#include "core/settings.h"
14 16
15//////////////////////////////////////////////////////////////////////////////////////////////////// 17////////////////////////////////////////////////////////////////////////////////////////////////////
16// FileSys namespace 18// FileSys namespace
diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h
index 3431fed88..afc689848 100644
--- a/src/core/file_sys/archive_systemsavedata.h
+++ b/src/core/file_sys/archive_systemsavedata.h
@@ -4,10 +4,13 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8#include <string>
9
7#include "common/common_types.h" 10#include "common/common_types.h"
8 11
9#include "core/file_sys/disk_archive.h" 12#include "core/file_sys/archive_backend.h"
10#include "core/loader/loader.h" 13#include "core/hle/result.h"
11 14
12//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace 16// FileSys namespace
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp
index 9980cced1..1096fd34d 100644
--- a/src/core/file_sys/disk_archive.cpp
+++ b/src/core/file_sys/disk_archive.cpp
@@ -2,7 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <sys/stat.h> 5#include <algorithm>
6#include <cstdio>
6 7
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "common/file_util.h" 9#include "common/file_util.h"
@@ -10,7 +11,6 @@
10#include "common/make_unique.h" 11#include "common/make_unique.h"
11 12
12#include "core/file_sys/disk_archive.h" 13#include "core/file_sys/disk_archive.h"
13#include "core/settings.h"
14 14
15//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
16// FileSys namespace 16// FileSys namespace
@@ -105,12 +105,12 @@ bool DiskFile::Open() {
105 return true; 105 return true;
106} 106}
107 107
108size_t DiskFile::Read(const u64 offset, const u32 length, u8* buffer) const { 108size_t DiskFile::Read(const u64 offset, const size_t length, u8* buffer) const {
109 file->Seek(offset, SEEK_SET); 109 file->Seek(offset, SEEK_SET);
110 return file->ReadBytes(buffer, length); 110 return file->ReadBytes(buffer, length);
111} 111}
112 112
113size_t DiskFile::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { 113size_t DiskFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const {
114 file->Seek(offset, SEEK_SET); 114 file->Seek(offset, SEEK_SET);
115 size_t written = file->WriteBytes(buffer, length); 115 size_t written = file->WriteBytes(buffer, length);
116 if (flush) 116 if (flush)
@@ -118,8 +118,8 @@ size_t DiskFile::Write(const u64 offset, const u32 length, const u32 flush, cons
118 return written; 118 return written;
119} 119}
120 120
121size_t DiskFile::GetSize() const { 121u64 DiskFile::GetSize() const {
122 return static_cast<size_t>(file->GetSize()); 122 return file->GetSize();
123} 123}
124 124
125bool DiskFile::SetSize(const u64 size) const { 125bool DiskFile::SetSize(const u64 size) const {
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h
index a22d3837a..c5da07508 100644
--- a/src/core/file_sys/disk_archive.h
+++ b/src/core/file_sys/disk_archive.h
@@ -4,13 +4,18 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
8#include <memory>
9#include <string>
10#include <vector>
11
7#include "common/common_types.h" 12#include "common/common_types.h"
8#include "common/file_util.h" 13#include "common/file_util.h"
9 14
10#include "core/file_sys/archive_backend.h" 15#include "core/file_sys/archive_backend.h"
11#include "core/file_sys/directory_backend.h" 16#include "core/file_sys/directory_backend.h"
12#include "core/file_sys/file_backend.h" 17#include "core/file_sys/file_backend.h"
13#include "core/loader/loader.h" 18#include "core/hle/result.h"
14 19
15//////////////////////////////////////////////////////////////////////////////////////////////////// 20////////////////////////////////////////////////////////////////////////////////////////////////////
16// FileSys namespace 21// FileSys namespace
@@ -50,10 +55,10 @@ public:
50 DiskFile(const DiskArchive& archive, const Path& path, const Mode mode); 55 DiskFile(const DiskArchive& archive, const Path& path, const Mode mode);
51 56
52 bool Open() override; 57 bool Open() override;
53 size_t Read(const u64 offset, const u32 length, u8* buffer) const override; 58 size_t Read(u64 offset, size_t length, u8* buffer) const override;
54 size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; 59 size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const override;
55 size_t GetSize() const override; 60 u64 GetSize() const override;
56 bool SetSize(const u64 size) const override; 61 bool SetSize(u64 size) const override;
57 bool Close() const override; 62 bool Close() const override;
58 63
59 void Flush() const override { 64 void Flush() const override {
diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h
index 0fcff1845..df7165df3 100644
--- a/src/core/file_sys/file_backend.h
+++ b/src/core/file_sys/file_backend.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8 10
9//////////////////////////////////////////////////////////////////////////////////////////////////// 11////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -29,7 +31,7 @@ public:
29 * @param buffer Buffer to read data into 31 * @param buffer Buffer to read data into
30 * @return Number of bytes read 32 * @return Number of bytes read
31 */ 33 */
32 virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0; 34 virtual size_t Read(u64 offset, size_t length, u8* buffer) const = 0;
33 35
34 /** 36 /**
35 * Write data to the file 37 * Write data to the file
@@ -39,20 +41,20 @@ public:
39 * @param buffer Buffer to read data from 41 * @param buffer Buffer to read data from
40 * @return Number of bytes written 42 * @return Number of bytes written
41 */ 43 */
42 virtual size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const = 0; 44 virtual size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const = 0;
43 45
44 /** 46 /**
45 * Get the size of the file in bytes 47 * Get the size of the file in bytes
46 * @return Size of the file in bytes 48 * @return Size of the file in bytes
47 */ 49 */
48 virtual size_t GetSize() const = 0; 50 virtual u64 GetSize() const = 0;
49 51
50 /** 52 /**
51 * Set the size of the file in bytes 53 * Set the size of the file in bytes
52 * @param size New size of the file 54 * @param size New size of the file
53 * @return true if successful 55 * @return true if successful
54 */ 56 */
55 virtual bool SetSize(const u64 size) const = 0; 57 virtual bool SetSize(u64 size) const = 0;
56 58
57 /** 59 /**
58 * Close the file 60 * Close the file
diff --git a/src/core/file_sys/ivfc_archive.cpp b/src/core/file_sys/ivfc_archive.cpp
index 2d2509d16..e16aa1491 100644
--- a/src/core/file_sys/ivfc_archive.cpp
+++ b/src/core/file_sys/ivfc_archive.cpp
@@ -2,10 +2,10 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
5#include <memory> 6#include <memory>
6 7
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "common/file_util.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/make_unique.h" 10#include "common/make_unique.h"
11 11
@@ -16,15 +16,12 @@
16 16
17namespace FileSys { 17namespace FileSys {
18 18
19IVFCArchive::IVFCArchive(std::shared_ptr<const std::vector<u8>> data) : data(data) {
20}
21
22std::string IVFCArchive::GetName() const { 19std::string IVFCArchive::GetName() const {
23 return "IVFC"; 20 return "IVFC";
24} 21}
25 22
26std::unique_ptr<FileBackend> IVFCArchive::OpenFile(const Path& path, const Mode mode) const { 23std::unique_ptr<FileBackend> IVFCArchive::OpenFile(const Path& path, const Mode mode) const {
27 return Common::make_unique<IVFCFile>(data); 24 return Common::make_unique<IVFCFile>(romfs_file, data_offset, data_size);
28} 25}
29 26
30bool IVFCArchive::DeleteFile(const Path& path) const { 27bool IVFCArchive::DeleteFile(const Path& path) const {
@@ -64,19 +61,21 @@ std::unique_ptr<DirectoryBackend> IVFCArchive::OpenDirectory(const Path& path) c
64 61
65//////////////////////////////////////////////////////////////////////////////////////////////////// 62////////////////////////////////////////////////////////////////////////////////////////////////////
66 63
67size_t IVFCFile::Read(const u64 offset, const u32 length, u8* buffer) const { 64size_t IVFCFile::Read(const u64 offset, const size_t length, u8* buffer) const {
68 LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length); 65 LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length);
69 memcpy(buffer, data->data() + offset, length); 66 romfs_file->Seek(data_offset + offset, SEEK_SET);
70 return length; 67 size_t read_length = (size_t)std::min((u64)length, data_size - offset);
68
69 return romfs_file->ReadBytes(buffer, read_length);
71} 70}
72 71
73size_t IVFCFile::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { 72size_t IVFCFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const {
74 LOG_ERROR(Service_FS, "Attempted to write to IVFC file"); 73 LOG_ERROR(Service_FS, "Attempted to write to IVFC file");
75 return 0; 74 return 0;
76} 75}
77 76
78size_t IVFCFile::GetSize() const { 77u64 IVFCFile::GetSize() const {
79 return sizeof(u8) * data->size(); 78 return data_size;
80} 79}
81 80
82bool IVFCFile::SetSize(const u64 size) const { 81bool IVFCFile::SetSize(const u64 size) const {
diff --git a/src/core/file_sys/ivfc_archive.h b/src/core/file_sys/ivfc_archive.h
index 10415798d..c15a6c4ae 100644
--- a/src/core/file_sys/ivfc_archive.h
+++ b/src/core/file_sys/ivfc_archive.h
@@ -4,15 +4,18 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
7#include <memory> 8#include <memory>
9#include <string>
8#include <vector> 10#include <vector>
9 11
10#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/file_util.h"
11 14
12#include "core/file_sys/archive_backend.h" 15#include "core/file_sys/archive_backend.h"
13#include "core/file_sys/directory_backend.h" 16#include "core/file_sys/directory_backend.h"
14#include "core/file_sys/file_backend.h" 17#include "core/file_sys/file_backend.h"
15#include "core/loader/loader.h" 18#include "core/hle/result.h"
16 19
17//////////////////////////////////////////////////////////////////////////////////////////////////// 20////////////////////////////////////////////////////////////////////////////////////////////////////
18// FileSys namespace 21// FileSys namespace
@@ -26,7 +29,8 @@ namespace FileSys {
26 */ 29 */
27class IVFCArchive : public ArchiveBackend { 30class IVFCArchive : public ArchiveBackend {
28public: 31public:
29 IVFCArchive(std::shared_ptr<const std::vector<u8>> data); 32 IVFCArchive(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)
33 : romfs_file(file), data_offset(offset), data_size(size) {}
30 34
31 std::string GetName() const override; 35 std::string GetName() const override;
32 36
@@ -40,23 +44,28 @@ public:
40 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; 44 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
41 45
42protected: 46protected:
43 std::shared_ptr<const std::vector<u8>> data; 47 std::shared_ptr<FileUtil::IOFile> romfs_file;
48 u64 data_offset;
49 u64 data_size;
44}; 50};
45 51
46class IVFCFile : public FileBackend { 52class IVFCFile : public FileBackend {
47public: 53public:
48 IVFCFile(std::shared_ptr<const std::vector<u8>> data) : data(data) {} 54 IVFCFile(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)
55 : romfs_file(file), data_offset(offset), data_size(size) {}
49 56
50 bool Open() override { return true; } 57 bool Open() override { return true; }
51 size_t Read(const u64 offset, const u32 length, u8* buffer) const override; 58 size_t Read(u64 offset, size_t length, u8* buffer) const override;
52 size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; 59 size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const override;
53 size_t GetSize() const override; 60 u64 GetSize() const override;
54 bool SetSize(const u64 size) const override; 61 bool SetSize(u64 size) const override;
55 bool Close() const override { return false; } 62 bool Close() const override { return false; }
56 void Flush() const override { } 63 void Flush() const override { }
57 64
58private: 65private:
59 std::shared_ptr<const std::vector<u8>> data; 66 std::shared_ptr<FileUtil::IOFile> romfs_file;
67 u64 data_offset;
68 u64 data_size;
60}; 69};
61 70
62class IVFCDirectory : public DirectoryBackend { 71class IVFCDirectory : public DirectoryBackend {
diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp
new file mode 100644
index 000000000..826f6cbb6
--- /dev/null
+++ b/src/core/hle/applets/applet.cpp
@@ -0,0 +1,101 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstddef>
6#include <memory>
7#include <type_traits>
8#include <unordered_map>
9
10#include "common/assert.h"
11#include "common/common_types.h"
12
13#include "core/core_timing.h"
14#include "core/hle/applets/applet.h"
15#include "core/hle/applets/swkbd.h"
16#include "core/hle/result.h"
17#include "core/hle/service/apt/apt.h"
18
19////////////////////////////////////////////////////////////////////////////////////////////////////
20
21// Specializes std::hash for AppletId, so that we can use it in std::unordered_map.
22// Workaround for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970
23namespace std {
24 template <>
25 struct hash<Service::APT::AppletId> {
26 typedef Service::APT::AppletId argument_type;
27 typedef std::size_t result_type;
28
29 result_type operator()(const argument_type& id_code) const {
30 typedef std::underlying_type<argument_type>::type Type;
31 return std::hash<Type>()(static_cast<Type>(id_code));
32 }
33 };
34}
35
36namespace HLE {
37namespace Applets {
38
39static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> applets;
40static u32 applet_update_event = -1; ///< The CoreTiming event identifier for the Applet update callback.
41/// The interval at which the Applet update callback will be called, 16.6ms
42static const u64 applet_update_interval_us = 16666;
43
44ResultCode Applet::Create(Service::APT::AppletId id) {
45 switch (id) {
46 case Service::APT::AppletId::SoftwareKeyboard1:
47 case Service::APT::AppletId::SoftwareKeyboard2:
48 applets[id] = std::make_shared<SoftwareKeyboard>(id);
49 break;
50 default:
51 // TODO(Subv): Find the right error code
52 return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported, ErrorLevel::Permanent);
53 }
54
55 return RESULT_SUCCESS;
56}
57
58std::shared_ptr<Applet> Applet::Get(Service::APT::AppletId id) {
59 auto itr = applets.find(id);
60 if (itr != applets.end())
61 return itr->second;
62 return nullptr;
63}
64
65/// Handles updating the current Applet every time it's called.
66static void AppletUpdateEvent(u64 applet_id, int cycles_late) {
67 Service::APT::AppletId id = static_cast<Service::APT::AppletId>(applet_id);
68 std::shared_ptr<Applet> applet = Applet::Get(id);
69 ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id=%08X", id);
70
71 applet->Update();
72
73 // If the applet is still running after the last update, reschedule the event
74 if (applet->IsRunning()) {
75 CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late,
76 applet_update_event, applet_id);
77 } else {
78 // Otherwise the applet has terminated, in which case we should clean it up
79 applets[id] = nullptr;
80 }
81}
82
83ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) {
84 ResultCode result = StartImpl(parameter);
85 if (result.IsError())
86 return result;
87 // Schedule the update event
88 CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event, static_cast<u64>(id));
89 return result;
90}
91
92void Init() {
93 // Register the applet update callback
94 applet_update_event = CoreTiming::RegisterEvent("HLE Applet Update Event", AppletUpdateEvent);
95}
96
97void Shutdown() {
98}
99
100}
101} // namespace
diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h
new file mode 100644
index 000000000..b235d0b8a
--- /dev/null
+++ b/src/core/hle/applets/applet.h
@@ -0,0 +1,77 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8
9#include "core/hle/result.h"
10#include "core/hle/service/apt/apt.h"
11
12namespace HLE {
13namespace Applets {
14
15class Applet {
16public:
17 virtual ~Applet() { }
18 Applet(Service::APT::AppletId id) : id(id) { }
19
20 /**
21 * Creates an instance of the Applet subclass identified by the parameter.
22 * and stores it in a global map.
23 * @param id Id of the applet to create.
24 * @returns ResultCode Whether the operation was successful or not.
25 */
26 static ResultCode Create(Service::APT::AppletId id);
27
28 /**
29 * Retrieves the Applet instance identified by the specified id.
30 * @param id Id of the Applet to retrieve.
31 * @returns Requested Applet or nullptr if not found.
32 */
33 static std::shared_ptr<Applet> Get(Service::APT::AppletId id);
34
35 /**
36 * Handles a parameter from the application.
37 * @param parameter Parameter data to handle.
38 * @returns ResultCode Whether the operation was successful or not.
39 */
40 virtual ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) = 0;
41
42 /**
43 * Handles the Applet start event, triggered from the application.
44 * @param parameter Parameter data to handle.
45 * @returns ResultCode Whether the operation was successful or not.
46 */
47 ResultCode Start(const Service::APT::AppletStartupParameter& parameter);
48
49 /**
50 * Whether the applet is currently executing instead of the host application or not.
51 */
52 virtual bool IsRunning() const = 0;
53
54 /**
55 * Handles an update tick for the Applet, lets it update the screen, send commands, etc.
56 */
57 virtual void Update() = 0;
58
59protected:
60 /**
61 * Handles the Applet start event, triggered from the application.
62 * @param parameter Parameter data to handle.
63 * @returns ResultCode Whether the operation was successful or not.
64 */
65 virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0;
66
67 Service::APT::AppletId id; ///< Id of this Applet
68};
69
70/// Initializes the HLE applets
71void Init();
72
73/// Shuts down the HLE applets
74void Shutdown();
75
76}
77} // namespace
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp
new file mode 100644
index 000000000..1db6b5a17
--- /dev/null
+++ b/src/core/hle/applets/swkbd.cpp
@@ -0,0 +1,113 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6#include <string>
7
8#include "common/assert.h"
9#include "common/logging/log.h"
10#include "common/string_util.h"
11
12#include "core/hle/applets/swkbd.h"
13#include "core/hle/kernel/kernel.h"
14#include "core/hle/kernel/shared_memory.h"
15#include "core/hle/service/hid/hid.h"
16#include "core/hle/service/gsp_gpu.h"
17#include "core/hle/result.h"
18#include "core/memory.h"
19
20#include "video_core/video_core.h"
21
22////////////////////////////////////////////////////////////////////////////////////////////////////
23
24namespace HLE {
25namespace Applets {
26
27SoftwareKeyboard::SoftwareKeyboard(Service::APT::AppletId id) : Applet(id), started(false) {
28 // Create the SharedMemory that will hold the framebuffer data
29 // TODO(Subv): What size should we use here?
30 using Kernel::MemoryPermission;
31 framebuffer_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "SoftwareKeyboard Memory");
32}
33
34ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) {
35 if (parameter.signal != static_cast<u32>(Service::APT::SignalType::LibAppJustStarted)) {
36 LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal);
37 UNIMPLEMENTED();
38 // TODO(Subv): Find the right error code
39 return ResultCode(-1);
40 }
41
42 Service::APT::MessageParameter result;
43 // The buffer passed in parameter contains the data returned by GSPGPU::ImportDisplayCaptureInfo
44 result.signal = static_cast<u32>(Service::APT::SignalType::LibAppFinished);
45 result.data = nullptr;
46 result.buffer_size = 0;
47 result.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
48 result.sender_id = static_cast<u32>(id);
49 result.object = framebuffer_memory;
50
51 Service::APT::SendParameter(result);
52 return RESULT_SUCCESS;
53}
54
55ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter const& parameter) {
56 ASSERT_MSG(parameter.buffer_size == sizeof(config), "The size of the parameter (SoftwareKeyboardConfig) is wrong");
57
58 memcpy(&config, parameter.data, parameter.buffer_size);
59 text_memory = boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object);
60
61 // TODO(Subv): Verify if this is the correct behavior
62 memset(text_memory->GetPointer(), 0, text_memory->size);
63
64 DrawScreenKeyboard();
65
66 started = true;
67 return RESULT_SUCCESS;
68}
69
70void SoftwareKeyboard::Update() {
71 // TODO(Subv): Handle input using the touch events from the HID module
72
73 // TODO(Subv): Remove this hardcoded text
74 std::u16string text = Common::UTF8ToUTF16("Citra");
75 memcpy(text_memory->GetPointer(), text.c_str(), text.length() * sizeof(char16_t));
76
77 // TODO(Subv): Ask for input and write it to the shared memory
78 // TODO(Subv): Find out what are the possible values for the return code,
79 // some games seem to check for a hardcoded 2
80 config.return_code = 2;
81 config.text_length = 6;
82 config.text_offset = 0;
83
84 // TODO(Subv): We're finalizing the applet immediately after it's started,
85 // but we should defer this call until after all the input has been collected.
86 Finalize();
87}
88
89void SoftwareKeyboard::DrawScreenKeyboard() {
90 auto bottom_screen = GSP_GPU::GetFrameBufferInfo(0, 1);
91 auto info = bottom_screen->framebuffer_info[bottom_screen->index];
92
93 // TODO(Subv): Draw the HLE keyboard, for now just zero-fill the framebuffer
94 memset(Memory::GetPointer(info.address_left), 0, info.stride * 320);
95
96 GSP_GPU::SetBufferSwap(1, info);
97}
98
99void SoftwareKeyboard::Finalize() {
100 // Let the application know that we're closing
101 Service::APT::MessageParameter message;
102 message.buffer_size = sizeof(SoftwareKeyboardConfig);
103 message.data = reinterpret_cast<u8*>(&config);
104 message.signal = static_cast<u32>(Service::APT::SignalType::LibAppClosed);
105 message.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
106 message.sender_id = static_cast<u32>(id);
107 Service::APT::SendParameter(message);
108
109 started = false;
110}
111
112}
113} // namespace
diff --git a/src/core/hle/applets/swkbd.h b/src/core/hle/applets/swkbd.h
new file mode 100644
index 000000000..cb95b8d90
--- /dev/null
+++ b/src/core/hle/applets/swkbd.h
@@ -0,0 +1,90 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/common_funcs.h"
9
10#include "core/hle/applets/applet.h"
11#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/shared_memory.h"
13#include "core/hle/result.h"
14#include "core/hle/service/apt/apt.h"
15
16namespace HLE {
17namespace Applets {
18
19struct SoftwareKeyboardConfig {
20 INSERT_PADDING_WORDS(0x8);
21
22 u16 max_text_length; ///< Maximum length of the input text
23
24 INSERT_PADDING_BYTES(0x6E);
25
26 char16_t display_text[65]; ///< Text to display when asking the user for input
27
28 INSERT_PADDING_BYTES(0xE);
29
30 u32 default_text_offset; ///< Offset of the default text in the output SharedMemory
31
32 INSERT_PADDING_WORDS(0x3);
33
34 u32 shared_memory_size; ///< Size of the SharedMemory
35
36 INSERT_PADDING_WORDS(0x1);
37
38 u32 return_code; ///< Return code of the SoftwareKeyboard, usually 2, other values are unknown
39
40 INSERT_PADDING_WORDS(0x2);
41
42 u32 text_offset; ///< Offset in the SharedMemory where the output text starts
43 u16 text_length; ///< Length in characters of the output text
44
45 INSERT_PADDING_BYTES(0x2B6);
46};
47
48/**
49 * The size of this structure (0x400) has been verified via reverse engineering of multiple games
50 * that use the software keyboard.
51 */
52static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config size is wrong");
53
54class SoftwareKeyboard final : public Applet {
55public:
56 SoftwareKeyboard(Service::APT::AppletId id);
57 ~SoftwareKeyboard() {}
58
59 ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
60 ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
61 void Update() override;
62 bool IsRunning() const override { return started; }
63
64 /**
65 * Draws a keyboard to the current bottom screen framebuffer.
66 */
67 void DrawScreenKeyboard();
68
69 /**
70 * Sends the LibAppletClosing signal to the application,
71 * along with the relevant data buffers.
72 */
73 void Finalize();
74
75 /// TODO(Subv): Find out what this is actually used for.
76 /// It is believed that the application stores the current screen image here.
77 Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
78
79 /// SharedMemory where the output text will be stored
80 Kernel::SharedPtr<Kernel::SharedMemory> text_memory;
81
82 /// Configuration of this instance of the SoftwareKeyboard, as received from the application
83 SoftwareKeyboardConfig config;
84
85 /// Whether this applet is currently running instead of the host application or not.
86 bool started;
87};
88
89}
90} // namespace
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 5949cb470..1a0518926 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -87,8 +87,28 @@ template<ResultCode func(u32, s64)> void Wrap() {
87 } 87 }
88} 88}
89 89
90template<ResultCode func(void*, void*, u32)> void Wrap(){ 90template<ResultCode func(MemoryInfo*, PageInfo*, u32)> void Wrap() {
91 FuncReturn(func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2)).raw); 91 MemoryInfo memory_info = {};
92 PageInfo page_info = {};
93 u32 retval = func(&memory_info, &page_info, PARAM(2)).raw;
94 Core::g_app_core->SetReg(1, memory_info.base_address);
95 Core::g_app_core->SetReg(2, memory_info.size);
96 Core::g_app_core->SetReg(3, memory_info.permission);
97 Core::g_app_core->SetReg(4, memory_info.state);
98 Core::g_app_core->SetReg(5, page_info.flags);
99 FuncReturn(retval);
100}
101
102template<ResultCode func(MemoryInfo*, PageInfo*, Handle, u32)> void Wrap() {
103 MemoryInfo memory_info = {};
104 PageInfo page_info = {};
105 u32 retval = func(&memory_info, &page_info, PARAM(2), PARAM(3)).raw;
106 Core::g_app_core->SetReg(1, memory_info.base_address);
107 Core::g_app_core->SetReg(2, memory_info.size);
108 Core::g_app_core->SetReg(3, memory_info.permission);
109 Core::g_app_core->SetReg(4, memory_info.state);
110 Core::g_app_core->SetReg(5, page_info.flags);
111 FuncReturn(retval);
92} 112}
93 113
94template<ResultCode func(s32*, u32)> void Wrap(){ 114template<ResultCode func(s32*, u32)> void Wrap(){
@@ -113,7 +133,7 @@ template<ResultCode func(u32)> void Wrap() {
113 FuncReturn(func(PARAM(0)).raw); 133 FuncReturn(func(PARAM(0)).raw);
114} 134}
115 135
116template<ResultCode func(s64*, u32, u32*, s32)> void Wrap(){ 136template<ResultCode func(s64*, u32, u32*, u32)> void Wrap(){
117 FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), (u32*)Memory::GetPointer(PARAM(2)), 137 FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), (u32*)Memory::GetPointer(PARAM(2)),
118 (s32)PARAM(3)).raw); 138 (s32)PARAM(3)).raw);
119} 139}
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
index fdeb9a028..cd0a400dc 100644
--- a/src/core/hle/hle.cpp
+++ b/src/core/hle/hle.cpp
@@ -10,7 +10,6 @@
10#include "core/hle/hle.h" 10#include "core/hle/hle.h"
11#include "core/hle/config_mem.h" 11#include "core/hle/config_mem.h"
12#include "core/hle/shared_page.h" 12#include "core/hle/shared_page.h"
13#include "core/hle/kernel/thread.h"
14#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
15 14
16//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index f338f3266..53feebbc0 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -21,7 +21,7 @@ SharedPtr<Event> Event::Create(ResetType reset_type, std::string name) {
21 SharedPtr<Event> evt(new Event); 21 SharedPtr<Event> evt(new Event);
22 22
23 evt->signaled = false; 23 evt->signaled = false;
24 evt->reset_type = evt->intitial_reset_type = reset_type; 24 evt->reset_type = reset_type;
25 evt->name = std::move(name); 25 evt->name = std::move(name);
26 26
27 return evt; 27 return evt;
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index fba960d2a..89d405236 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -26,7 +26,6 @@ public:
26 static const HandleType HANDLE_TYPE = HandleType::Event; 26 static const HandleType HANDLE_TYPE = HandleType::Event;
27 HandleType GetHandleType() const override { return HANDLE_TYPE; } 27 HandleType GetHandleType() const override { return HANDLE_TYPE; }
28 28
29 ResetType intitial_reset_type; ///< ResetType specified at Event initialization
30 ResetType reset_type; ///< Current ResetType 29 ResetType reset_type; ///< Current ResetType
31 30
32 bool signaled; ///< Whether the event has already been signaled 31 bool signaled; ///< Whether the event has already been signaled
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 20e11da16..5711c0405 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -7,8 +7,6 @@
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9 9
10#include "core/arm/arm_interface.h"
11#include "core/core.h"
12#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/resource_limit.h" 11#include "core/hle/kernel/resource_limit.h"
14#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/process.h"
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 64595f758..4d4276f7a 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -4,10 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <boost/intrusive_ptr.hpp> 7#include <boost/smart_ptr/intrusive_ptr.hpp>
8 8
9#include <algorithm>
9#include <array> 10#include <array>
10#include <memory> 11#include <cstddef>
11#include <string> 12#include <string>
12#include <vector> 13#include <vector>
13 14
@@ -16,8 +17,6 @@
16#include "core/hle/hle.h" 17#include "core/hle/hle.h"
17#include "core/hle/result.h" 18#include "core/hle/result.h"
18 19
19struct ApplicationInfo;
20
21namespace Kernel { 20namespace Kernel {
22 21
23class Thread; 22class Thread;
@@ -48,6 +47,7 @@ enum class HandleType : u32 {
48 Semaphore = 10, 47 Semaphore = 10,
49 Timer = 11, 48 Timer = 11,
50 ResourceLimit = 12, 49 ResourceLimit = 12,
50 CodeSet = 13,
51}; 51};
52 52
53enum { 53enum {
@@ -86,6 +86,7 @@ public:
86 case HandleType::Process: 86 case HandleType::Process:
87 case HandleType::AddressArbiter: 87 case HandleType::AddressArbiter:
88 case HandleType::ResourceLimit: 88 case HandleType::ResourceLimit:
89 case HandleType::CodeSet:
89 return false; 90 return false;
90 } 91 }
91 } 92 }
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index b0e75ba59..a7892c652 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -5,24 +5,39 @@
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/common_funcs.h" 6#include "common/common_funcs.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/make_unique.h"
8 9
9#include "core/hle/kernel/process.h" 10#include "core/hle/kernel/process.h"
10#include "core/hle/kernel/resource_limit.h" 11#include "core/hle/kernel/resource_limit.h"
11#include "core/hle/kernel/thread.h" 12#include "core/hle/kernel/thread.h"
13#include "core/hle/kernel/vm_manager.h"
14#include "core/mem_map.h"
12#include "core/memory.h" 15#include "core/memory.h"
13 16
14namespace Kernel { 17namespace Kernel {
15 18
19SharedPtr<CodeSet> CodeSet::Create(std::string name, u64 program_id) {
20 SharedPtr<CodeSet> codeset(new CodeSet);
21
22 codeset->name = std::move(name);
23 codeset->program_id = program_id;
24
25 return codeset;
26}
27
28CodeSet::CodeSet() {}
29CodeSet::~CodeSet() {}
30
16u32 Process::next_process_id; 31u32 Process::next_process_id;
17 32
18SharedPtr<Process> Process::Create(std::string name, u64 program_id) { 33SharedPtr<Process> Process::Create(SharedPtr<CodeSet> code_set) {
19 SharedPtr<Process> process(new Process); 34 SharedPtr<Process> process(new Process);
20 35
21 process->name = std::move(name); 36 process->codeset = std::move(code_set);
22 process->program_id = program_id;
23
24 process->flags.raw = 0; 37 process->flags.raw = 0;
25 process->flags.memory_region = MemoryRegion::APPLICATION; 38 process->flags.memory_region = MemoryRegion::APPLICATION;
39 process->address_space = Common::make_unique<VMManager>();
40 Memory::InitLegacyAddressSpace(*process->address_space);
26 41
27 return process; 42 return process;
28} 43}
@@ -87,8 +102,19 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
87 } 102 }
88} 103}
89 104
90void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { 105void Process::Run(s32 main_thread_priority, u32 stack_size) {
91 Kernel::SetupMainThread(entry_point, main_thread_priority); 106 auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) {
107 auto vma = address_space->MapMemoryBlock(segment.addr, codeset->memory,
108 segment.offset, segment.size, memory_state).Unwrap();
109 address_space->Reprotect(vma, permissions);
110 };
111
112 MapSegment(codeset->code, VMAPermission::ReadExecute, MemoryState::Code);
113 MapSegment(codeset->rodata, VMAPermission::Read, MemoryState::Code);
114 MapSegment(codeset->data, VMAPermission::ReadWrite, MemoryState::Private);
115
116 address_space->LogLayout();
117 Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority);
92} 118}
93 119
94Kernel::Process::Process() {} 120Kernel::Process::Process() {}
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 7b8a68610..83d3aceae 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -5,6 +5,9 @@
5#pragma once 5#pragma once
6 6
7#include <bitset> 7#include <bitset>
8#include <cstddef>
9#include <memory>
10#include <string>
8 11
9#include <boost/container/static_vector.hpp> 12#include <boost/container/static_vector.hpp>
10 13
@@ -12,7 +15,6 @@
12#include "common/common_types.h" 15#include "common/common_types.h"
13 16
14#include "core/hle/kernel/kernel.h" 17#include "core/hle/kernel/kernel.h"
15#include "core/hle/result.h"
16 18
17namespace Kernel { 19namespace Kernel {
18 20
@@ -46,23 +48,51 @@ union ProcessFlags {
46}; 48};
47 49
48class ResourceLimit; 50class ResourceLimit;
51class VMManager;
52
53struct CodeSet final : public Object {
54 static SharedPtr<CodeSet> Create(std::string name, u64 program_id);
55
56 std::string GetTypeName() const override { return "CodeSet"; }
57 std::string GetName() const override { return name; }
58
59 static const HandleType HANDLE_TYPE = HandleType::CodeSet;
60 HandleType GetHandleType() const override { return HANDLE_TYPE; }
61
62 /// Name of the process
63 std::string name;
64 /// Title ID corresponding to the process
65 u64 program_id;
66
67 std::shared_ptr<std::vector<u8>> memory;
68
69 struct Segment {
70 size_t offset = 0;
71 VAddr addr = 0;
72 u32 size = 0;
73 };
74
75 Segment code, rodata, data;
76 VAddr entrypoint;
77
78private:
79 CodeSet();
80 ~CodeSet() override;
81};
49 82
50class Process final : public Object { 83class Process final : public Object {
51public: 84public:
52 static SharedPtr<Process> Create(std::string name, u64 program_id); 85 static SharedPtr<Process> Create(SharedPtr<CodeSet> code_set);
53 86
54 std::string GetTypeName() const override { return "Process"; } 87 std::string GetTypeName() const override { return "Process"; }
55 std::string GetName() const override { return name; } 88 std::string GetName() const override { return codeset->name; }
56 89
57 static const HandleType HANDLE_TYPE = HandleType::Process; 90 static const HandleType HANDLE_TYPE = HandleType::Process;
58 HandleType GetHandleType() const override { return HANDLE_TYPE; } 91 HandleType GetHandleType() const override { return HANDLE_TYPE; }
59 92
60 static u32 next_process_id; 93 static u32 next_process_id;
61 94
62 /// Name of the process 95 SharedPtr<CodeSet> codeset;
63 std::string name;
64 /// Title ID corresponding to the process
65 u64 program_id;
66 /// Resource limit descriptor for this process 96 /// Resource limit descriptor for this process
67 SharedPtr<ResourceLimit> resource_limit; 97 SharedPtr<ResourceLimit> resource_limit;
68 98
@@ -80,6 +110,7 @@ public:
80 110
81 /// Bitmask of the used TLS slots 111 /// Bitmask of the used TLS slots
82 std::bitset<300> used_tls_slots; 112 std::bitset<300> used_tls_slots;
113 std::unique_ptr<VMManager> address_space;
83 114
84 /** 115 /**
85 * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them 116 * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
@@ -90,7 +121,7 @@ public:
90 /** 121 /**
91 * Applies address space changes and launches the process main thread. 122 * Applies address space changes and launches the process main thread.
92 */ 123 */
93 void Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size); 124 void Run(s32 main_thread_priority, u32 stack_size);
94 125
95private: 126private:
96 Process(); 127 Process();
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index 257da9105..adaffcafe 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -4,8 +4,14 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <string>
8
9#include "common/assert.h"
10#include "common/common_types.h"
11
7#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/kernel.h"
8#include "core/hle/kernel/thread.h" 13#include "core/hle/kernel/thread.h"
14#include "core/hle/result.h"
9#include "core/memory.h" 15#include "core/memory.h"
10 16
11namespace IPC { 17namespace IPC {
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 204266896..7a2922776 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -4,9 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <string>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8 10
9#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
12#include "core/hle/result.h"
10 13
11namespace Kernel { 14namespace Kernel {
12 15
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 4729a7fe0..29ea6d531 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -13,7 +13,7 @@
13#include "common/thread_queue_list.h" 13#include "common/thread_queue_list.h"
14 14
15#include "core/arm/arm_interface.h" 15#include "core/arm/arm_interface.h"
16#include "core/arm/skyeye_common/armdefs.h" 16#include "core/arm/skyeye_common/armstate.h"
17#include "core/core.h" 17#include "core/core.h"
18#include "core/core_timing.h" 18#include "core/core_timing.h"
19#include "core/hle/hle.h" 19#include "core/hle/hle.h"
@@ -37,6 +37,10 @@ void Thread::Acquire() {
37 ASSERT_MSG(!ShouldWait(), "object unavailable!"); 37 ASSERT_MSG(!ShouldWait(), "object unavailable!");
38} 38}
39 39
40// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing
41// us to simply use a pool index or similar.
42static Kernel::HandleTable wakeup_callback_handle_table;
43
40// Lists all thread ids that aren't deleted/etc. 44// Lists all thread ids that aren't deleted/etc.
41static std::vector<SharedPtr<Thread>> thread_list; 45static std::vector<SharedPtr<Thread>> thread_list;
42 46
@@ -93,6 +97,8 @@ void Thread::Stop() {
93 97
94 // Cancel any outstanding wakeup events for this thread 98 // Cancel any outstanding wakeup events for this thread
95 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); 99 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
100 wakeup_callback_handle_table.Close(callback_handle);
101 callback_handle = 0;
96 102
97 // Clean up thread from ready queue 103 // Clean up thread from ready queue
98 // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) 104 // This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
@@ -108,6 +114,7 @@ void Thread::Stop() {
108 for (auto& wait_object : wait_objects) { 114 for (auto& wait_object : wait_objects) {
109 wait_object->RemoveWaitingThread(this); 115 wait_object->RemoveWaitingThread(this);
110 } 116 }
117 wait_objects.clear();
111 118
112 Kernel::g_current_process->used_tls_slots[tls_index] = false; 119 Kernel::g_current_process->used_tls_slots[tls_index] = false;
113 120
@@ -210,6 +217,14 @@ static void SwitchContext(Thread* new_thread) {
210 new_thread->context.pc -= thumb_mode ? 2 : 4; 217 new_thread->context.pc -= thumb_mode ? 2 : 4;
211 } 218 }
212 219
220 // Clean up the thread's wait_objects, they'll be restored if needed during
221 // the svcWaitSynchronization call
222 for (int i = 0; i < new_thread->wait_objects.size(); ++i) {
223 SharedPtr<WaitObject> object = new_thread->wait_objects[i];
224 object->RemoveWaitingThread(new_thread);
225 }
226 new_thread->wait_objects.clear();
227
213 ready_queue.remove(new_thread->current_priority, new_thread); 228 ready_queue.remove(new_thread->current_priority, new_thread);
214 new_thread->status = THREADSTATUS_RUNNING; 229 new_thread->status = THREADSTATUS_RUNNING;
215 230
@@ -268,10 +283,6 @@ void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) {
268 thread->status = THREADSTATUS_WAIT_ARB; 283 thread->status = THREADSTATUS_WAIT_ARB;
269} 284}
270 285
271// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing
272// us to simply use a pool index or similar.
273static Kernel::HandleTable wakeup_callback_handle_table;
274
275/** 286/**
276 * Callback that will wake up the thread it was scheduled for 287 * Callback that will wake up the thread it was scheduled for
277 * @param thread_handle The handle of the thread that's been awoken 288 * @param thread_handle The handle of the thread that's been awoken
@@ -503,12 +514,16 @@ void ThreadingInit() {
503 514
504 current_thread = nullptr; 515 current_thread = nullptr;
505 next_thread_id = 1; 516 next_thread_id = 1;
506
507 thread_list.clear();
508 ready_queue.clear();
509} 517}
510 518
511void ThreadingShutdown() { 519void ThreadingShutdown() {
520 current_thread = nullptr;
521
522 for (auto& t : thread_list) {
523 t->Stop();
524 }
525 thread_list.clear();
526 ready_queue.clear();
512} 527}
513 528
514} // namespace 529} // namespace
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index b8160bb2c..1ff1d9b97 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -13,6 +13,7 @@
13 13
14#include "core/core.h" 14#include "core/core.h"
15 15
16#include "core/hle/hle.h"
16#include "core/hle/kernel/kernel.h" 17#include "core/hle/kernel/kernel.h"
17#include "core/hle/result.h" 18#include "core/hle/result.h"
18 19
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index b2dd21542..205cc7b53 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <iterator>
6
5#include "common/assert.h" 7#include "common/assert.h"
6 8
7#include "core/hle/kernel/vm_manager.h" 9#include "core/hle/kernel/vm_manager.h"
@@ -33,6 +35,10 @@ VMManager::VMManager() {
33 Reset(); 35 Reset();
34} 36}
35 37
38VMManager::~VMManager() {
39 Reset();
40}
41
36void VMManager::Reset() { 42void VMManager::Reset() {
37 vma_map.clear(); 43 vma_map.clear();
38 44
@@ -128,6 +134,16 @@ void VMManager::Reprotect(VMAHandle vma_handle, VMAPermission new_perms) {
128 MergeAdjacent(iter); 134 MergeAdjacent(iter);
129} 135}
130 136
137void VMManager::LogLayout() const {
138 for (const auto& p : vma_map) {
139 const VirtualMemoryArea& vma = p.second;
140 LOG_DEBUG(Kernel, "%08X - %08X size: %8X %c%c%c", vma.base, vma.base + vma.size, vma.size,
141 (u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-',
142 (u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-',
143 (u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-');
144 }
145}
146
131VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) { 147VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) {
132 // This uses a neat C++ trick to convert a const_iterator to a regular iterator, given 148 // This uses a neat C++ trick to convert a const_iterator to a regular iterator, given
133 // non-const access to its container. 149 // non-const access to its container.
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 22b724603..b3795a94a 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -6,7 +6,6 @@
6 6
7#include <map> 7#include <map>
8#include <memory> 8#include <memory>
9#include <string>
10#include <vector> 9#include <vector>
11 10
12#include "common/common_types.h" 11#include "common/common_types.h"
@@ -102,7 +101,7 @@ struct VirtualMemoryArea {
102 * - http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/ 101 * - http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/
103 * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/ 102 * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/
104 */ 103 */
105class VMManager { 104class VMManager final {
106 // TODO(yuriks): Make page tables switchable to support multiple VMManagers 105 // TODO(yuriks): Make page tables switchable to support multiple VMManagers
107public: 106public:
108 /** 107 /**
@@ -122,6 +121,7 @@ public:
122 using VMAHandle = decltype(vma_map)::const_iterator; 121 using VMAHandle = decltype(vma_map)::const_iterator;
123 122
124 VMManager(); 123 VMManager();
124 ~VMManager();
125 125
126 /// Clears the address space map, re-initializing with a single free area. 126 /// Clears the address space map, re-initializing with a single free area.
127 void Reset(); 127 void Reset();
@@ -169,6 +169,9 @@ public:
169 /// Changes the permissions of the given VMA. 169 /// Changes the permissions of the given VMA.
170 void Reprotect(VMAHandle vma, VMAPermission new_perms); 170 void Reprotect(VMAHandle vma, VMAPermission new_perms);
171 171
172 /// Dumps the address space layout to the log, for debugging
173 void LogLayout() const;
174
172private: 175private:
173 using VMAIter = decltype(vma_map)::iterator; 176 using VMAIter = decltype(vma_map)::iterator;
174 177
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index ce633d841..cb2d681e0 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -4,7 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <new>
8#include <type_traits> 8#include <type_traits>
9#include <utility> 9#include <utility>
10 10
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 57dc1ece7..7332478fb 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -38,6 +38,15 @@ void GetTitleIDList(Service::Interface* self) {
38 LOG_WARNING(Service_AM, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type); 38 LOG_WARNING(Service_AM, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type);
39} 39}
40 40
41void GetNumContentInfos(Service::Interface* self) {
42 u32* cmd_buff = Kernel::GetCommandBuffer();
43
44 cmd_buff[1] = RESULT_SUCCESS.raw;
45 cmd_buff[2] = 1; // Number of content infos plus one
46
47 LOG_WARNING(Service_AM, "(STUBBED) called");
48}
49
41void Init() { 50void Init() {
42 using namespace Kernel; 51 using namespace Kernel;
43 52
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 063b8bd09..0b78f5393 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -37,6 +37,19 @@ void TitleIDListGetTotal(Service::Interface* self);
37 */ 37 */
38void GetTitleIDList(Service::Interface* self); 38void GetTitleIDList(Service::Interface* self);
39 39
40/**
41 * AM::GetNumContentInfos service function
42 * Inputs:
43 * 0 : Command header (0x100100C0)
44 * 1 : Unknown
45 * 2 : Unknown
46 * 3 : Unknown
47 * Outputs:
48 * 1 : Result, 0 on success, otherwise error code
49 * 2 : Number of content infos plus one
50 */
51void GetNumContentInfos(Service::Interface* self);
52
40/// Initialize AM service 53/// Initialize AM service
41void Init(); 54void Init();
42 55
diff --git a/src/core/hle/service/am/am_app.cpp b/src/core/hle/service/am/am_app.cpp
index c6fc81bc3..f40a87cb4 100644
--- a/src/core/hle/service/am/am_app.cpp
+++ b/src/core/hle/service/am/am_app.cpp
@@ -9,11 +9,19 @@
9namespace Service { 9namespace Service {
10namespace AM { 10namespace AM {
11 11
12// Empty arrays are illegal -- commented out until an entry is added. 12const Interface::FunctionInfo FunctionTable[] = {
13//const Interface::FunctionInfo FunctionTable[] = { }; 13 {0x100100C0, GetNumContentInfos, "GetNumContentInfos"},
14 {0x10020104, nullptr, "FindContentInfos"},
15 {0x10030142, nullptr, "ListContentInfos"},
16 {0x10040102, nullptr, "DeleteContents"},
17 {0x10050084, nullptr, "GetDataTitleInfos"},
18 {0x10070102, nullptr, "ListDataTitleTicketInfos"},
19 {0x100900C0, nullptr, "IsDataTitleInUse"},
20 {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"},
21};
14 22
15AM_APP_Interface::AM_APP_Interface() { 23AM_APP_Interface::AM_APP_Interface() {
16 //Register(FunctionTable); 24 Register(FunctionTable);
17} 25}
18 26
19} // namespace AM 27} // namespace AM
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index b454a2709..7b6ab4ce0 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -6,6 +6,7 @@
6#include "common/file_util.h" 6#include "common/file_util.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8 8
9#include "core/hle/applets/applet.h"
9#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
10#include "core/hle/service/apt/apt.h" 11#include "core/hle/service/apt/apt.h"
11#include "core/hle/service/apt/apt_a.h" 12#include "core/hle/service/apt/apt_a.h"
@@ -34,12 +35,21 @@ static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
34 35
35static Kernel::SharedPtr<Kernel::Mutex> lock; 36static Kernel::SharedPtr<Kernel::Mutex> lock;
36static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event 37static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
37static Kernel::SharedPtr<Kernel::Event> start_event; ///< APT start event 38static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
38 39
39static std::vector<u8> shared_font; 40static std::vector<u8> shared_font;
40 41
41static u32 cpu_percent; ///< CPU time available to the running application 42static u32 cpu_percent; ///< CPU time available to the running application
42 43
44/// Parameter data to be returned in the next call to Glance/ReceiveParameter
45static MessageParameter next_parameter;
46
47void SendParameter(const MessageParameter& parameter) {
48 next_parameter = parameter;
49 // Signal the event to let the application know that a new parameter is ready to be read
50 parameter_event->Signal();
51}
52
43void Initialize(Service::Interface* self) { 53void Initialize(Service::Interface* self) {
44 u32* cmd_buff = Kernel::GetCommandBuffer(); 54 u32* cmd_buff = Kernel::GetCommandBuffer();
45 u32 app_id = cmd_buff[1]; 55 u32 app_id = cmd_buff[1];
@@ -47,18 +57,18 @@ void Initialize(Service::Interface* self) {
47 57
48 cmd_buff[2] = IPC::MoveHandleDesc(2); 58 cmd_buff[2] = IPC::MoveHandleDesc(2);
49 cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); 59 cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom();
50 cmd_buff[4] = Kernel::g_handle_table.Create(start_event).MoveFrom(); 60 cmd_buff[4] = Kernel::g_handle_table.Create(parameter_event).MoveFrom();
51 61
52 // TODO(bunnei): Check if these events are cleared every time Initialize is called. 62 // TODO(bunnei): Check if these events are cleared every time Initialize is called.
53 notification_event->Clear(); 63 notification_event->Clear();
54 start_event->Clear(); 64 parameter_event->Clear();
55 65
56 ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); 66 ASSERT_MSG((nullptr != lock), "Cannot initialize without lock");
57 lock->Release(); 67 lock->Release();
58 68
59 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 69 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
60 70
61 LOG_TRACE(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); 71 LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags);
62} 72}
63 73
64void GetSharedFont(Service::Interface* self) { 74void GetSharedFont(Service::Interface* self) {
@@ -85,9 +95,6 @@ void GetSharedFont(Service::Interface* self) {
85void NotifyToWait(Service::Interface* self) { 95void NotifyToWait(Service::Interface* self) {
86 u32* cmd_buff = Kernel::GetCommandBuffer(); 96 u32* cmd_buff = Kernel::GetCommandBuffer();
87 u32 app_id = cmd_buff[1]; 97 u32 app_id = cmd_buff[1];
88 // TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further.
89 start_event->Signal();
90
91 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 98 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
92 LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); 99 LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id);
93} 100}
@@ -100,7 +107,7 @@ void GetLockHandle(Service::Interface* self) {
100 107
101 // Not sure what these parameters are used for, but retail apps check that they are 0 after 108 // Not sure what these parameters are used for, but retail apps check that they are 0 after
102 // GetLockHandle has been called. 109 // GetLockHandle has been called.
103 cmd_buff[2] = 0; 110 cmd_buff[2] = 0; // Applet Attributes, this value is passed to Enable.
104 cmd_buff[3] = 0; 111 cmd_buff[3] = 0;
105 cmd_buff[4] = 0; 112 cmd_buff[4] = 0;
106 113
@@ -110,9 +117,10 @@ void GetLockHandle(Service::Interface* self) {
110 117
111void Enable(Service::Interface* self) { 118void Enable(Service::Interface* self) {
112 u32* cmd_buff = Kernel::GetCommandBuffer(); 119 u32* cmd_buff = Kernel::GetCommandBuffer();
113 u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for? 120 u32 attributes = cmd_buff[1];
114 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 121 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
115 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); 122 parameter_event->Signal(); // Let the application know that it has been started
123 LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes);
116} 124}
117 125
118void GetAppletManInfo(Service::Interface* self) { 126void GetAppletManInfo(Service::Interface* self) {
@@ -121,8 +129,8 @@ void GetAppletManInfo(Service::Interface* self) {
121 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 129 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
122 cmd_buff[2] = 0; 130 cmd_buff[2] = 0;
123 cmd_buff[3] = 0; 131 cmd_buff[3] = 0;
124 cmd_buff[4] = static_cast<u32>(AppID::HomeMenu); // Home menu AppID 132 cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID
125 cmd_buff[5] = static_cast<u32>(AppID::Application); // TODO(purpasmart96): Do this correctly 133 cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly
126 134
127 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); 135 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk);
128} 136}
@@ -131,7 +139,13 @@ void IsRegistered(Service::Interface* self) {
131 u32* cmd_buff = Kernel::GetCommandBuffer(); 139 u32* cmd_buff = Kernel::GetCommandBuffer();
132 u32 app_id = cmd_buff[1]; 140 u32 app_id = cmd_buff[1];
133 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 141 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
134 cmd_buff[2] = 1; // Set to registered 142 /// TODO(Subv): It is currently unknown what this value (0x400) means,
143 /// but i believe it is used as a global "LibraryApplet" id, to verify if there's
144 /// any LibApplet currently running. This is not verified.
145 if (app_id != 0x400)
146 cmd_buff[2] = 1; // Set to registered
147 else
148 cmd_buff[2] = 0; // Set to not registered
135 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); 149 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id);
136} 150}
137 151
@@ -145,50 +159,82 @@ void InquireNotification(Service::Interface* self) {
145 159
146void SendParameter(Service::Interface* self) { 160void SendParameter(Service::Interface* self) {
147 u32* cmd_buff = Kernel::GetCommandBuffer(); 161 u32* cmd_buff = Kernel::GetCommandBuffer();
148 u32 src_app_id = cmd_buff[1]; 162 u32 src_app_id = cmd_buff[1];
149 u32 dst_app_id = cmd_buff[2]; 163 u32 dst_app_id = cmd_buff[2];
150 u32 signal_type = cmd_buff[3]; 164 u32 signal_type = cmd_buff[3];
151 u32 buffer_size = cmd_buff[4]; 165 u32 buffer_size = cmd_buff[4];
152 u32 value = cmd_buff[5]; 166 u32 value = cmd_buff[5];
153 u32 handle = cmd_buff[6]; 167 u32 handle = cmd_buff[6];
154 u32 size = cmd_buff[7]; 168 u32 size = cmd_buff[7];
155 u32 in_param_buffer_ptr = cmd_buff[8]; 169 u32 buffer = cmd_buff[8];
170
171 std::shared_ptr<HLE::Applets::Applet> dest_applet = HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id));
172
173 if (dest_applet == nullptr) {
174 LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id);
175 cmd_buff[1] = -1; // TODO(Subv): Find the right error code
176 return;
177 }
156 178
157 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 179 MessageParameter param;
180 param.buffer_size = buffer_size;
181 param.destination_id = dst_app_id;
182 param.sender_id = src_app_id;
183 param.object = Kernel::g_handle_table.GetGeneric(handle);
184 param.signal = signal_type;
185 param.data = Memory::GetPointer(buffer);
186
187 cmd_buff[1] = dest_applet->ReceiveParameter(param).raw;
158 188
159 LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," 189 LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
160 "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X", 190 "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X",
161 src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, in_param_buffer_ptr); 191 src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer);
162} 192}
163 193
164void ReceiveParameter(Service::Interface* self) { 194void ReceiveParameter(Service::Interface* self) {
165 u32* cmd_buff = Kernel::GetCommandBuffer(); 195 u32* cmd_buff = Kernel::GetCommandBuffer();
166 u32 app_id = cmd_buff[1]; 196 u32 app_id = cmd_buff[1];
167 u32 buffer_size = cmd_buff[2]; 197 u32 buffer_size = cmd_buff[2];
198 VAddr buffer = cmd_buff[0x104 >> 2];
199
168 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 200 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
169 cmd_buff[2] = 0; 201 cmd_buff[2] = next_parameter.sender_id;
170 cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type 202 cmd_buff[3] = next_parameter.signal; // Signal type
171 cmd_buff[4] = 0x10; // Parameter buffer size (16) 203 cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
172 cmd_buff[5] = 0; 204 cmd_buff[5] = 0x10;
173 cmd_buff[6] = 0; 205 cmd_buff[6] = 0;
174 cmd_buff[7] = 0; 206 if (next_parameter.object != nullptr)
175 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); 207 cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
208 cmd_buff[7] = (next_parameter.buffer_size << 14) | 2;
209 cmd_buff[8] = buffer;
210
211 if (next_parameter.data)
212 memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size));
213
214 LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
176} 215}
177 216
178void GlanceParameter(Service::Interface* self) { 217void GlanceParameter(Service::Interface* self) {
179 u32* cmd_buff = Kernel::GetCommandBuffer(); 218 u32* cmd_buff = Kernel::GetCommandBuffer();
180 u32 app_id = cmd_buff[1]; 219 u32 app_id = cmd_buff[1];
181 u32 buffer_size = cmd_buff[2]; 220 u32 buffer_size = cmd_buff[2];
221 VAddr buffer = cmd_buff[0x104 >> 2];
182 222
183 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 223 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
184 cmd_buff[2] = 0; 224 cmd_buff[2] = next_parameter.sender_id;
185 cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type 225 cmd_buff[3] = next_parameter.signal; // Signal type
186 cmd_buff[4] = 0x10; // Parameter buffer size (16) 226 cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
187 cmd_buff[5] = 0; 227 cmd_buff[5] = 0x10;
188 cmd_buff[6] = 0; 228 cmd_buff[6] = 0;
189 cmd_buff[7] = 0; 229 if (next_parameter.object != nullptr)
230 cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
231 cmd_buff[7] = (next_parameter.buffer_size << 14) | 2;
232 cmd_buff[8] = buffer;
190 233
191 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); 234 if (next_parameter.data)
235 memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size));
236
237 LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
192} 238}
193 239
194void CancelParameter(Service::Interface* self) { 240void CancelParameter(Service::Interface* self) {
@@ -240,7 +286,7 @@ void AppletUtility(Service::Interface* self) {
240 u32* cmd_buff = Kernel::GetCommandBuffer(); 286 u32* cmd_buff = Kernel::GetCommandBuffer();
241 287
242 // These are from 3dbrew - I'm not really sure what they're used for. 288 // These are from 3dbrew - I'm not really sure what they're used for.
243 u32 unk = cmd_buff[1]; 289 u32 command = cmd_buff[1];
244 u32 buffer1_size = cmd_buff[2]; 290 u32 buffer1_size = cmd_buff[2];
245 u32 buffer2_size = cmd_buff[3]; 291 u32 buffer2_size = cmd_buff[3];
246 u32 buffer1_addr = cmd_buff[5]; 292 u32 buffer1_addr = cmd_buff[5];
@@ -248,8 +294,8 @@ void AppletUtility(Service::Interface* self) {
248 294
249 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 295 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
250 296
251 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, " 297 LOG_WARNING(Service_APT, "(STUBBED) called command=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, "
252 "buffer1_addr=0x%08X, buffer2_addr=0x%08X", unk, buffer1_size, buffer2_size, 298 "buffer1_addr=0x%08X, buffer2_addr=0x%08X", command, buffer1_size, buffer2_size,
253 buffer1_addr, buffer2_addr); 299 buffer1_addr, buffer2_addr);
254} 300}
255 301
@@ -281,11 +327,41 @@ void GetAppCpuTimeLimit(Service::Interface* self) {
281 LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value); 327 LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value);
282} 328}
283 329
330void PrepareToStartLibraryApplet(Service::Interface* self) {
331 u32* cmd_buff = Kernel::GetCommandBuffer();
332 AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
333 cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw;
334 LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
335}
336
337void StartLibraryApplet(Service::Interface* self) {
338 u32* cmd_buff = Kernel::GetCommandBuffer();
339 AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
340 std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(applet_id);
341
342 LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
343
344 if (applet == nullptr) {
345 LOG_ERROR(Service_APT, "unknown applet id=%08X", applet_id);
346 cmd_buff[1] = -1; // TODO(Subv): Find the right error code
347 return;
348 }
349
350 AppletStartupParameter parameter;
351 parameter.buffer_size = cmd_buff[2];
352 parameter.object = Kernel::g_handle_table.GetGeneric(cmd_buff[4]);
353 parameter.data = Memory::GetPointer(cmd_buff[6]);
354
355 cmd_buff[1] = applet->Start(parameter).raw;
356}
357
284void Init() { 358void Init() {
285 AddService(new APT_A_Interface); 359 AddService(new APT_A_Interface);
286 AddService(new APT_S_Interface); 360 AddService(new APT_S_Interface);
287 AddService(new APT_U_Interface); 361 AddService(new APT_U_Interface);
288 362
363 HLE::Applets::Init();
364
289 // Load the shared system font (if available). 365 // Load the shared system font (if available).
290 // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header 366 // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header
291 // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided 367 // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided
@@ -318,7 +394,10 @@ void Init() {
318 394
319 // TODO(bunnei): Check if these are created in Initialize or on APT process startup. 395 // TODO(bunnei): Check if these are created in Initialize or on APT process startup.
320 notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification"); 396 notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification");
321 start_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start"); 397 parameter_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start");
398
399 next_parameter.signal = static_cast<u32>(SignalType::AppJustStarted);
400 next_parameter.destination_id = 0x300;
322} 401}
323 402
324void Shutdown() { 403void Shutdown() {
@@ -326,7 +405,11 @@ void Shutdown() {
326 shared_font_mem = nullptr; 405 shared_font_mem = nullptr;
327 lock = nullptr; 406 lock = nullptr;
328 notification_event = nullptr; 407 notification_event = nullptr;
329 start_event = nullptr; 408 parameter_event = nullptr;
409
410 next_parameter.object = nullptr;
411
412 HLE::Applets::Shutdown();
330} 413}
331 414
332} // namespace APT 415} // namespace APT
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index a03e1712a..72972d05b 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -4,13 +4,33 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array> 7#include "common/common_types.h"
8#include "core/hle/result.h" 8
9#include "core/hle/service/service.h" 9#include "core/hle/kernel/kernel.h"
10 10
11namespace Service { 11namespace Service {
12
13class Interface;
14
12namespace APT { 15namespace APT {
13 16
17/// Holds information about the parameters used in Send/Glance/ReceiveParameter
18struct MessageParameter {
19 u32 sender_id = 0;
20 u32 destination_id = 0;
21 u32 signal = 0;
22 u32 buffer_size = 0;
23 Kernel::SharedPtr<Kernel::Object> object = nullptr;
24 u8* data = nullptr;
25};
26
27/// Holds information about the parameters used in StartLibraryApplet
28struct AppletStartupParameter {
29 u32 buffer_size = 0;
30 Kernel::SharedPtr<Kernel::Object> object = nullptr;
31 u8* data = nullptr;
32};
33
14/// Signals used by APT functions 34/// Signals used by APT functions
15enum class SignalType : u32 { 35enum class SignalType : u32 {
16 None = 0x0, 36 None = 0x0,
@@ -23,7 +43,7 @@ enum class SignalType : u32 {
23}; 43};
24 44
25/// App Id's used by APT functions 45/// App Id's used by APT functions
26enum class AppID : u32 { 46enum class AppletId : u32 {
27 HomeMenu = 0x101, 47 HomeMenu = 0x101,
28 AlternateMenu = 0x103, 48 AlternateMenu = 0x103,
29 Camera = 0x110, 49 Camera = 0x110,
@@ -45,6 +65,9 @@ enum class AppID : u32 {
45 SoftwareKeyboard2 = 0x401, 65 SoftwareKeyboard2 = 0x401,
46}; 66};
47 67
68/// Send a parameter to the currently-running application, which will read it via ReceiveParameter
69void SendParameter(const MessageParameter& parameter);
70
48/** 71/**
49 * APT::Initialize service function 72 * APT::Initialize service function
50 * Service function that initializes the APT process for the running application 73 * Service function that initializes the APT process for the running application
@@ -249,6 +272,33 @@ void SetAppCpuTimeLimit(Service::Interface* self);
249 */ 272 */
250void GetAppCpuTimeLimit(Service::Interface* self); 273void GetAppCpuTimeLimit(Service::Interface* self);
251 274
275/**
276 * APT::PrepareToStartLibraryApplet service function
277 * Inputs:
278 * 0 : Command header [0x00180040]
279 * 1 : Id of the applet to start
280 * Outputs:
281 * 0 : Return header
282 * 1 : Result of function, 0 on success, otherwise error code
283 */
284void PrepareToStartLibraryApplet(Service::Interface* self);
285
286/**
287 * APT::StartLibraryApplet service function
288 * Inputs:
289 * 0 : Command header [0x001E0084]
290 * 1 : Id of the applet to start
291 * 2 : Buffer size
292 * 3 : Always 0?
293 * 4 : Handle passed to the applet
294 * 5 : (Size << 14) | 2
295 * 6 : Input buffer virtual address
296 * Outputs:
297 * 0 : Return header
298 * 1 : Result of function, 0 on success, otherwise error code
299 */
300void StartLibraryApplet(Service::Interface* self);
301
252/// Initialize the APT service 302/// Initialize the APT service
253void Init(); 303void Init();
254 304
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp
index 864934245..88de339f9 100644
--- a/src/core/hle/service/apt/apt_a.cpp
+++ b/src/core/hle/service/apt/apt_a.cpp
@@ -10,19 +10,24 @@ namespace Service {
10namespace APT { 10namespace APT {
11 11
12const Interface::FunctionInfo FunctionTable[] = { 12const Interface::FunctionInfo FunctionTable[] = {
13 {0x00010040, GetLockHandle, "GetLockHandle?"}, 13 {0x00010040, GetLockHandle, "GetLockHandle?"},
14 {0x00020080, Initialize, "Initialize?"}, 14 {0x00020080, Initialize, "Initialize?"},
15 {0x00030040, Enable, "Enable?"}, 15 {0x00030040, Enable, "Enable?"},
16 {0x00040040, nullptr, "Finalize?"}, 16 {0x00040040, nullptr, "Finalize?"},
17 {0x00050040, nullptr, "GetAppletManInfo?"}, 17 {0x00050040, nullptr, "GetAppletManInfo?"},
18 {0x00060040, nullptr, "GetAppletInfo?"}, 18 {0x00060040, nullptr, "GetAppletInfo?"},
19 {0x000D0080, ReceiveParameter, "ReceiveParameter?"}, 19 {0x00090040, IsRegistered, "IsRegistered"},
20 {0x000E0080, GlanceParameter, "GlanceParameter?"}, 20 {0x000C0104, SendParameter, "SendParameter"},
21 {0x003B0040, nullptr, "CancelLibraryApplet?"}, 21 {0x000D0080, ReceiveParameter, "ReceiveParameter"},
22 {0x00430040, NotifyToWait, "NotifyToWait?"}, 22 {0x000E0080, GlanceParameter, "GlanceParameter"},
23 {0x00440000, GetSharedFont, "GetSharedFont?"}, 23 {0x000F0100, CancelParameter, "CancelParameter"},
24 {0x004B00C2, AppletUtility, "AppletUtility?"}, 24 {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
25 {0x00550040, nullptr, "WriteInputToNsState?"}, 25 {0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
26 {0x003B0040, nullptr, "CancelLibraryApplet?"},
27 {0x00430040, NotifyToWait, "NotifyToWait?"},
28 {0x00440000, GetSharedFont, "GetSharedFont?"},
29 {0x004B00C2, AppletUtility, "AppletUtility?"},
30 {0x00550040, nullptr, "WriteInputToNsState?"},
26}; 31};
27 32
28APT_A_Interface::APT_A_Interface() { 33APT_A_Interface::APT_A_Interface() {
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp
index d006b5930..b724cd72b 100644
--- a/src/core/hle/service/apt/apt_u.cpp
+++ b/src/core/hle/service/apt/apt_u.cpp
@@ -35,13 +35,13 @@ const Interface::FunctionInfo FunctionTable[] = {
35 {0x00150140, nullptr, "PrepareToStartApplication"}, 35 {0x00150140, nullptr, "PrepareToStartApplication"},
36 {0x00160040, nullptr, "PreloadLibraryApplet"}, 36 {0x00160040, nullptr, "PreloadLibraryApplet"},
37 {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, 37 {0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
38 {0x00180040, nullptr, "PrepareToStartLibraryApplet"}, 38 {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
39 {0x00190040, nullptr, "PrepareToStartSystemApplet"}, 39 {0x00190040, nullptr, "PrepareToStartSystemApplet"},
40 {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, 40 {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
41 {0x001B00C4, nullptr, "StartApplication"}, 41 {0x001B00C4, nullptr, "StartApplication"},
42 {0x001C0000, nullptr, "WakeupApplication"}, 42 {0x001C0000, nullptr, "WakeupApplication"},
43 {0x001D0000, nullptr, "CancelApplication"}, 43 {0x001D0000, nullptr, "CancelApplication"},
44 {0x001E0084, nullptr, "StartLibraryApplet"}, 44 {0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
45 {0x001F0084, nullptr, "StartSystemApplet"}, 45 {0x001F0084, nullptr, "StartSystemApplet"},
46 {0x00200044, nullptr, "StartNewestHomeMenu"}, 46 {0x00200044, nullptr, "StartNewestHomeMenu"},
47 {0x00210000, nullptr, "OrderToCloseApplication"}, 47 {0x00210000, nullptr, "OrderToCloseApplication"},
diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp
index af4adba84..a329514a6 100644
--- a/src/core/hle/service/cfg/cfg_s.cpp
+++ b/src/core/hle/service/cfg/cfg_s.cpp
@@ -11,7 +11,9 @@ namespace CFG {
11 11
12const Interface::FunctionInfo FunctionTable[] = { 12const Interface::FunctionInfo FunctionTable[] = {
13 {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"}, 13 {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"},
14 {0x00020000, nullptr, "SecureInfoGetRegion"}, 14 {0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"},
15 {0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"},
16 {0x00050000, GetSystemModel, "GetSystemModel"},
15 {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"}, 17 {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
16 {0x04020082, nullptr, "SetConfigInfoBlk4"}, 18 {0x04020082, nullptr, "SetConfigInfoBlk4"},
17 {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"}, 19 {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index fafb43a2f..a8cb15d60 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -310,4 +310,9 @@ Interface::Interface() {
310 Register(FunctionTable); 310 Register(FunctionTable);
311} 311}
312 312
313Interface::~Interface() {
314 semaphore_event = nullptr;
315 interrupt_event = nullptr;
316}
317
313} // namespace 318} // namespace
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h
index fa13bfb7c..b6f611db5 100644
--- a/src/core/hle/service/dsp_dsp.h
+++ b/src/core/hle/service/dsp_dsp.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <string>
8
7#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
8 10
9//////////////////////////////////////////////////////////////////////////////////////////////////// 11////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -14,6 +16,7 @@ namespace DSP_DSP {
14class Interface : public Service::Interface { 16class Interface : public Service::Interface {
15public: 17public:
16 Interface(); 18 Interface();
19 ~Interface() override;
17 20
18 std::string GetPortName() const override { 21 std::string GetPortName() const override {
19 return "dsp::DSP"; 22 return "dsp::DSP";
diff --git a/src/core/hle/service/frd/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp
index 439c7282e..3a5897d06 100644
--- a/src/core/hle/service/frd/frd_u.cpp
+++ b/src/core/hle/service/frd/frd_u.cpp
@@ -10,15 +10,26 @@ namespace Service {
10namespace FRD { 10namespace FRD {
11 11
12const Interface::FunctionInfo FunctionTable[] = { 12const Interface::FunctionInfo FunctionTable[] = {
13 {0x00010000, nullptr, "HasLoggedIn"},
14 {0x00030000, nullptr, "Login"},
15 {0x00040000, nullptr, "Logout"},
13 {0x00050000, nullptr, "GetFriendKey"}, 16 {0x00050000, nullptr, "GetFriendKey"},
14 {0x00080000, nullptr, "GetMyPresence"}, 17 {0x00080000, nullptr, "GetMyPresence"},
18 {0x00090000, nullptr, "GetMyScreenName"},
15 {0x00100040, nullptr, "GetPassword"}, 19 {0x00100040, nullptr, "GetPassword"},
20 {0x00110080, nullptr, "GetFriendKeyList"},
16 {0x00190042, nullptr, "GetFriendFavoriteGame"}, 21 {0x00190042, nullptr, "GetFriendFavoriteGame"},
17 {0x001A00C4, nullptr, "GetFriendInfo"}, 22 {0x001A00C4, nullptr, "GetFriendInfo"},
18 {0x001B0080, nullptr, "IsOnFriendList"}, 23 {0x001B0080, nullptr, "IsOnFriendList"},
19 {0x001C0042, nullptr, "DecodeLocalFriendCode"}, 24 {0x001C0042, nullptr, "DecodeLocalFriendCode"},
20 {0x001D0002, nullptr, "SetCurrentlyPlayingText"}, 25 {0x001D0002, nullptr, "SetCurrentlyPlayingText"},
21 {0x00320042, nullptr, "SetClientSdkVersion"} 26 {0x00230000, nullptr, "GetLastResponseResult"},
27 {0x00270040, nullptr, "ResultToErrorCode"},
28 {0x00280244, nullptr, "RequestGameAuthentication"},
29 {0x00290000, nullptr, "GetGameAuthenticationData"},
30 {0x002A0204, nullptr, "RequestServiceLocator"},
31 {0x002B0000, nullptr, "GetServiceLocatorData"},
32 {0x00320042, nullptr, "SetClientSdkVersion"},
22}; 33};
23 34
24FRD_U_Interface::FRD_U_Interface() { 35FRD_U_Interface::FRD_U_Interface() {
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index 4e275cb13..6c0df67c3 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -2,29 +2,35 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstddef>
6#include <system_error>
7#include <type_traits>
5#include <memory> 8#include <memory>
6#include <unordered_map> 9#include <unordered_map>
10#include <utility>
7 11
8#include <boost/container/flat_map.hpp> 12#include <boost/container/flat_map.hpp>
9 13
14#include "common/assert.h"
10#include "common/common_types.h" 15#include "common/common_types.h"
11#include "common/file_util.h" 16#include "common/file_util.h"
12#include "common/logging/log.h" 17#include "common/logging/log.h"
13#include "common/make_unique.h" 18#include "common/make_unique.h"
14#include "common/math_util.h"
15 19
16#include "core/file_sys/archive_backend.h" 20#include "core/file_sys/archive_backend.h"
17#include "core/file_sys/archive_extsavedata.h" 21#include "core/file_sys/archive_extsavedata.h"
18#include "core/file_sys/archive_romfs.h"
19#include "core/file_sys/archive_savedata.h" 22#include "core/file_sys/archive_savedata.h"
20#include "core/file_sys/archive_savedatacheck.h" 23#include "core/file_sys/archive_savedatacheck.h"
21#include "core/file_sys/archive_sdmc.h" 24#include "core/file_sys/archive_sdmc.h"
22#include "core/file_sys/archive_systemsavedata.h" 25#include "core/file_sys/archive_systemsavedata.h"
23#include "core/file_sys/directory_backend.h" 26#include "core/file_sys/directory_backend.h"
27#include "core/file_sys/file_backend.h"
28#include "core/hle/hle.h"
24#include "core/hle/service/service.h" 29#include "core/hle/service/service.h"
25#include "core/hle/service/fs/archive.h" 30#include "core/hle/service/fs/archive.h"
26#include "core/hle/service/fs/fs_user.h" 31#include "core/hle/service/fs/fs_user.h"
27#include "core/hle/result.h" 32#include "core/hle/result.h"
33#include "core/memory.h"
28 34
29// Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map. 35// Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map.
30// Workaroung for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970 36// Workaroung for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970
@@ -110,7 +116,7 @@ ResultVal<bool> File::SyncRequest() {
110 u32 address = cmd_buff[6]; 116 u32 address = cmd_buff[6];
111 LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", 117 LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
112 GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); 118 GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
113 cmd_buff[2] = static_cast<u32>(backend->Write(offset, length, flush, Memory::GetPointer(address))); 119 cmd_buff[2] = static_cast<u32>(backend->Write(offset, length, flush != 0, Memory::GetPointer(address)));
114 break; 120 break;
115 } 121 }
116 122
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index 357b6b096..f61125953 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -4,22 +4,25 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8#include <string>
9
7#include "common/common_types.h" 10#include "common/common_types.h"
8 11
9#include "core/file_sys/archive_backend.h" 12#include "core/file_sys/archive_backend.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/session.h" 13#include "core/hle/kernel/session.h"
12#include "core/hle/result.h" 14#include "core/hle/result.h"
13 15
16namespace FileSys {
17class DirectoryBackend;
18class FileBackend;
19}
20
14/// The unique system identifier hash, also known as ID0 21/// The unique system identifier hash, also known as ID0
15extern const std::string SYSTEM_ID; 22extern const std::string SYSTEM_ID;
16/// The scrambled SD card CID, also known as ID1 23/// The scrambled SD card CID, also known as ID1
17extern const std::string SDCARD_ID; 24extern const std::string SDCARD_ID;
18 25
19namespace Kernel {
20 class Session;
21}
22
23namespace Service { 26namespace Service {
24namespace FS { 27namespace FS {
25 28
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index 0ad44e55e..ae52083f9 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -115,7 +115,8 @@ static void OpenFileDirectly(Service::Interface* self) {
115 115
116 ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path); 116 ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path);
117 if (archive_handle.Failed()) { 117 if (archive_handle.Failed()) {
118 LOG_ERROR(Service_FS, "failed to get a handle for archive"); 118 LOG_ERROR(Service_FS, "failed to get a handle for archive archive_id=0x%08X archive_path=%s",
119 archive_id, archive_path.DebugStr().c_str());
119 cmd_buff[1] = archive_handle.Code().raw; 120 cmd_buff[1] = archive_handle.Code().raw;
120 cmd_buff[3] = 0; 121 cmd_buff[3] = 0;
121 return; 122 return;
@@ -128,7 +129,8 @@ static void OpenFileDirectly(Service::Interface* self) {
128 cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); 129 cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom();
129 } else { 130 } else {
130 cmd_buff[3] = 0; 131 cmd_buff[3] = 0;
131 LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); 132 LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%d",
133 file_path.DebugStr().c_str(), mode.hex, attributes);
132 } 134 }
133} 135}
134 136
@@ -347,7 +349,8 @@ static void OpenDirectory(Service::Interface* self) {
347 if (dir_res.Succeeded()) { 349 if (dir_res.Succeeded()) {
348 cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom(); 350 cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom();
349 } else { 351 } else {
350 LOG_ERROR(Service_FS, "failed to get a handle for directory"); 352 LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s",
353 dirname_type, dirname_size, dir_path.DebugStr().c_str());
351 } 354 }
352} 355}
353 356
@@ -382,7 +385,8 @@ static void OpenArchive(Service::Interface* self) {
382 cmd_buff[3] = (*handle >> 32) & 0xFFFFFFFF; 385 cmd_buff[3] = (*handle >> 32) & 0xFFFFFFFF;
383 } else { 386 } else {
384 cmd_buff[2] = cmd_buff[3] = 0; 387 cmd_buff[2] = cmd_buff[3] = 0;
385 LOG_ERROR(Service_FS, "failed to get a handle for archive"); 388 LOG_ERROR(Service_FS, "failed to get a handle for archive archive_id=0x%08X archive_path=%s",
389 archive_id, archive_path.DebugStr().c_str());
386 } 390 }
387} 391}
388 392
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 4b0b4229d..e93c1b436 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -9,14 +9,17 @@
9#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/event.h"
10#include "core/hle/kernel/shared_memory.h" 10#include "core/hle/kernel/shared_memory.h"
11#include "core/hle/result.h" 11#include "core/hle/result.h"
12#include "gsp_gpu.h"
13#include "core/hw/hw.h" 12#include "core/hw/hw.h"
14#include "core/hw/gpu.h" 13#include "core/hw/gpu.h"
15#include "core/hw/lcd.h" 14#include "core/hw/lcd.h"
16 15
17#include "video_core/gpu_debugger.h" 16#include "video_core/gpu_debugger.h"
17#include "video_core/debug_utils/debug_utils.h"
18#include "video_core/renderer_base.h"
18#include "video_core/video_core.h" 19#include "video_core/video_core.h"
19 20
21#include "gsp_gpu.h"
22
20// Main graphics debugger object - TODO: Here is probably not the best place for this 23// Main graphics debugger object - TODO: Here is probably not the best place for this
21GraphicsDebugger g_debugger; 24GraphicsDebugger g_debugger;
22 25
@@ -40,7 +43,7 @@ static inline u8* GetCommandBuffer(u32 thread_id) {
40 return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer))); 43 return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer)));
41} 44}
42 45
43static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { 46FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) {
44 DEBUG_ASSERT_MSG(screen_index < 2, "Invalid screen index"); 47 DEBUG_ASSERT_MSG(screen_index < 2, "Invalid screen index");
45 48
46 // For each thread there are two FrameBufferUpdate fields 49 // For each thread there are two FrameBufferUpdate fields
@@ -203,7 +206,7 @@ static void ReadHWRegs(Service::Interface* self) {
203 } 206 }
204} 207}
205 208
206static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { 209void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
207 u32 base_address = 0x400000; 210 u32 base_address = 0x400000;
208 PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); 211 PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left);
209 PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); 212 PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right);
@@ -224,6 +227,9 @@ static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
224 &info.format); 227 &info.format);
225 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4, 228 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4,
226 &info.shown_fb); 229 &info.shown_fb);
230
231 if (Pica::g_debug_context)
232 Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr);
227} 233}
228 234
229/** 235/**
@@ -347,7 +353,7 @@ void SignalInterrupt(InterruptId interrupt_id) {
347/// Executes the next GSP command 353/// Executes the next GSP command
348static void ExecuteCommand(const Command& command, u32 thread_id) { 354static void ExecuteCommand(const Command& command, u32 thread_id) {
349 // Utility function to convert register ID to address 355 // Utility function to convert register ID to address
350 auto WriteGPURegister = [](u32 id, u32 data) { 356 static auto WriteGPURegister = [](u32 id, u32 data) {
351 GPU::Write<u32>(0x1EF00000 + 4 * id, data); 357 GPU::Write<u32>(0x1EF00000 + 4 * id, data);
352 }; 358 };
353 359
@@ -389,19 +395,24 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
389 case CommandId::SET_MEMORY_FILL: 395 case CommandId::SET_MEMORY_FILL:
390 { 396 {
391 auto& params = command.memory_fill; 397 auto& params = command.memory_fill;
392 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_start)), 398
393 Memory::VirtualToPhysicalAddress(params.start1) >> 3); 399 if (params.start1 != 0) {
394 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_end)), 400 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_start)),
395 Memory::VirtualToPhysicalAddress(params.end1) >> 3); 401 Memory::VirtualToPhysicalAddress(params.start1) >> 3);
396 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].value_32bit)), params.value1); 402 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_end)),
397 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].control)), params.control1); 403 Memory::VirtualToPhysicalAddress(params.end1) >> 3);
398 404 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].value_32bit)), params.value1);
399 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_start)), 405 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].control)), params.control1);
400 Memory::VirtualToPhysicalAddress(params.start2) >> 3); 406 }
401 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_end)), 407
402 Memory::VirtualToPhysicalAddress(params.end2) >> 3); 408 if (params.start2 != 0) {
403 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].value_32bit)), params.value2); 409 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_start)),
404 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].control)), params.control2); 410 Memory::VirtualToPhysicalAddress(params.start2) >> 3);
411 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_end)),
412 Memory::VirtualToPhysicalAddress(params.end2) >> 3);
413 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].value_32bit)), params.value2);
414 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].control)), params.control2);
415 }
405 break; 416 break;
406 } 417 }
407 418
@@ -446,6 +457,9 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
446 default: 457 default:
447 LOG_ERROR(Service_GSP, "unknown command 0x%08X", (int)command.id.Value()); 458 LOG_ERROR(Service_GSP, "unknown command 0x%08X", (int)command.id.Value());
448 } 459 }
460
461 if (Pica::g_debug_context)
462 Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::GSPCommandProcessed, (void*)&command);
449} 463}
450 464
451/** 465/**
@@ -582,7 +596,7 @@ const Interface::FunctionInfo FunctionTable[] = {
582Interface::Interface() { 596Interface::Interface() {
583 Register(FunctionTable); 597 Register(FunctionTable);
584 598
585 g_interrupt_event = 0; 599 g_interrupt_event = nullptr;
586 600
587 using Kernel::MemoryPermission; 601 using Kernel::MemoryPermission;
588 g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, 602 g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
@@ -591,4 +605,9 @@ Interface::Interface() {
591 g_thread_id = 0; 605 g_thread_id = 0;
592} 606}
593 607
608Interface::~Interface() {
609 g_interrupt_event = nullptr;
610 g_shared_memory = nullptr;
611}
612
594} // namespace 613} // namespace
diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h
index a435d418a..c89d0a467 100644
--- a/src/core/hle/service/gsp_gpu.h
+++ b/src/core/hle/service/gsp_gpu.h
@@ -5,8 +5,11 @@
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <cstddef>
8#include <string>
8 9
9#include "common/bit_field.h" 10#include "common/bit_field.h"
11#include "common/common_types.h"
12
10#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
11 14
12//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -158,6 +161,7 @@ static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrec
158class Interface : public Service::Interface { 161class Interface : public Service::Interface {
159public: 162public:
160 Interface(); 163 Interface();
164 ~Interface() override;
161 165
162 std::string GetPortName() const override { 166 std::string GetPortName() const override {
163 return "gsp::Gpu"; 167 return "gsp::Gpu";
@@ -170,4 +174,14 @@ public:
170 */ 174 */
171void SignalInterrupt(InterruptId interrupt_id); 175void SignalInterrupt(InterruptId interrupt_id);
172 176
177void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info);
178
179/**
180 * Retrieves the framebuffer info stored in the GSP shared memory for the
181 * specified screen index and thread id.
182 * @param thread_id GSP thread id of the process that accesses the structure that we are requesting.
183 * @param screen_index Index of the screen we are requesting (Top = 0, Bottom = 1).
184 * @returns FramebufferUpdate Information about the specified framebuffer.
185 */
186FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index);
173} // namespace 187} // namespace
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index c7c1bb5ab..c35b13b25 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "common/emu_window.h"
6 7
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8#include "core/hle/service/hid/hid.h" 9#include "core/hle/service/hid/hid.h"
@@ -34,6 +35,16 @@ static Kernel::SharedPtr<Kernel::Event> event_debug_pad;
34static u32 next_pad_index; 35static u32 next_pad_index;
35static u32 next_touch_index; 36static u32 next_touch_index;
36 37
38const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping = {
39 Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y,
40 Service::HID::PAD_L, Service::HID::PAD_R, Service::HID::PAD_ZL, Service::HID::PAD_ZR,
41 Service::HID::PAD_START, Service::HID::PAD_SELECT, Service::HID::PAD_NONE,
42 Service::HID::PAD_UP, Service::HID::PAD_DOWN, Service::HID::PAD_LEFT, Service::HID::PAD_RIGHT,
43 Service::HID::PAD_CIRCLE_UP, Service::HID::PAD_CIRCLE_DOWN, Service::HID::PAD_CIRCLE_LEFT, Service::HID::PAD_CIRCLE_RIGHT,
44 Service::HID::PAD_C_UP, Service::HID::PAD_C_DOWN, Service::HID::PAD_C_LEFT, Service::HID::PAD_C_RIGHT
45};
46
47
37// TODO(peachum): 48// TODO(peachum):
38// Add a method for setting analog input from joystick device for the circle Pad. 49// Add a method for setting analog input from joystick device for the circle Pad.
39// 50//
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 68e2bcee0..517f4f2ae 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -6,16 +6,18 @@
6 6
7#include <array> 7#include <array>
8 8
9#include "core/hle/kernel/kernel.h" 9#ifndef _MSC_VER
10#include "core/hle/service/service.h" 10#include <cstddef>
11#endif
12#include "core/settings.h"
11#include "common/bit_field.h" 13#include "common/bit_field.h"
12 14#include "common/common_funcs.h"
13namespace Kernel { 15#include "common/common_types.h"
14 class SharedMemory;
15 class Event;
16}
17 16
18namespace Service { 17namespace Service {
18
19class Interface;
20
19namespace HID { 21namespace HID {
20 22
21/** 23/**
@@ -155,6 +157,9 @@ const PadState PAD_CIRCLE_LEFT = {{1u << 29}};
155const PadState PAD_CIRCLE_UP = {{1u << 30}}; 157const PadState PAD_CIRCLE_UP = {{1u << 30}};
156const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; 158const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
157 159
160
161extern const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping;
162
158/** 163/**
159 * HID::GetIPCHandles service function 164 * HID::GetIPCHandles service function
160 * Inputs: 165 * Inputs:
diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp
index 25b01860e..18b22956f 100644
--- a/src/core/hle/service/nwm_uds.cpp
+++ b/src/core/hle/service/nwm_uds.cpp
@@ -125,4 +125,8 @@ Interface::Interface() {
125 Register(FunctionTable); 125 Register(FunctionTable);
126} 126}
127 127
128Interface::~Interface() {
129 handle_event = nullptr;
130}
131
128} // namespace 132} // namespace
diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h
index 82abdff28..0ced2359c 100644
--- a/src/core/hle/service/nwm_uds.h
+++ b/src/core/hle/service/nwm_uds.h
@@ -16,6 +16,7 @@ namespace NWM_UDS {
16class Interface : public Service::Interface { 16class Interface : public Service::Interface {
17public: 17public:
18 Interface(); 18 Interface();
19 ~Interface() override;
19 20
20 std::string GetPortName() const override { 21 std::string GetPortName() const override {
21 return "nwm::UDS"; 22 return "nwm::UDS";
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index d681cc3dc..0de0b13a3 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -54,7 +54,7 @@ static std::string MakeFunctionString(const char* name, const char* port_name, c
54 54
55 std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name); 55 std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name);
56 for (int i = 1; i <= num_params; ++i) { 56 for (int i = 1; i <= num_params; ++i) {
57 function_string += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]); 57 function_string += Common::StringFromFormat(", cmd_buff[%i]=0x%X", i, cmd_buff[i]);
58 } 58 }
59 return function_string; 59 return function_string;
60} 60}
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 77bfb9ff1..f31135212 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
7#include <string> 8#include <string>
8#include <unordered_map> 9#include <unordered_map>
9 10
@@ -11,8 +12,8 @@
11 12
12#include "common/common_types.h" 13#include "common/common_types.h"
13 14
14#include "core/hle/kernel/kernel.h"
15#include "core/hle/kernel/session.h" 15#include "core/hle/kernel/session.h"
16#include "core/hle/result.h"
16 17
17//////////////////////////////////////////////////////////////////////////////////////////////////// 18////////////////////////////////////////////////////////////////////////////////////////////////////
18// Namespace Service 19// Namespace Service
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index 3f0c5e388..d768a3fc7 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -2,40 +2,47 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <cstring>
7#include <unordered_map>
8
9#include "common/assert.h"
10#include "common/bit_field.h"
11#include "common/common_types.h"
5#include "common/logging/log.h" 12#include "common/logging/log.h"
6#include "common/platform.h" 13#include "common/scope_exit.h"
7
8#if EMU_PLATFORM == PLATFORM_WINDOWS
9#include <winsock2.h>
10#include <ws2tcpip.h>
11
12// MinGW does not define several errno constants
13#ifndef _MSC_VER
14#define EBADMSG 104
15#define ENODATA 120
16#define ENOMSG 122
17#define ENOSR 124
18#define ENOSTR 125
19#define ETIME 137
20#define EIDRM 2001
21#define ENOLINK 2002
22#endif // _MSC_VER
23 14
15#include "core/hle/kernel/session.h"
16#include "core/hle/result.h"
17#include "core/hle/service/soc_u.h"
18#include "core/memory.h"
19
20#ifdef _WIN32
21 #include <winsock2.h>
22 #include <ws2tcpip.h>
23
24 // MinGW does not define several errno constants
25 #ifndef _MSC_VER
26 #define EBADMSG 104
27 #define ENODATA 120
28 #define ENOMSG 122
29 #define ENOSR 124
30 #define ENOSTR 125
31 #define ETIME 137
32 #define EIDRM 2001
33 #define ENOLINK 2002
34 #endif // _MSC_VER
24#else 35#else
25#include <sys/socket.h> 36 #include <cerrno>
26#include <netinet/in.h> 37 #include <fcntl.h>
27#include <netdb.h> 38 #include <netinet/in.h>
28#include <arpa/inet.h> 39 #include <netdb.h>
29#include <fcntl.h> 40 #include <poll.h>
30#include <poll.h> 41 #include <sys/socket.h>
42 #include <unistd.h>
31#endif 43#endif
32 44
33#include "common/scope_exit.h" 45#ifdef _WIN32
34#include "core/hle/hle.h"
35#include "core/hle/service/soc_u.h"
36#include <unordered_map>
37
38#if EMU_PLATFORM == PLATFORM_WINDOWS
39# define WSAEAGAIN WSAEWOULDBLOCK 46# define WSAEAGAIN WSAEWOULDBLOCK
40# define WSAEMULTIHOP -1 // Invalid dummy value 47# define WSAEMULTIHOP -1 // Invalid dummy value
41# define ERRNO(x) WSA##x 48# define ERRNO(x) WSA##x
@@ -328,6 +335,7 @@ static void Socket(Service::Interface* self) {
328 if ((s32)socket_handle == SOCKET_ERROR_VALUE) 335 if ((s32)socket_handle == SOCKET_ERROR_VALUE)
329 result = TranslateError(GET_ERRNO); 336 result = TranslateError(GET_ERRNO);
330 337
338 cmd_buffer[0] = IPC::MakeHeader(2, 2, 0);
331 cmd_buffer[1] = result; 339 cmd_buffer[1] = result;
332 cmd_buffer[2] = socket_handle; 340 cmd_buffer[2] = socket_handle;
333} 341}
@@ -351,8 +359,9 @@ static void Bind(Service::Interface* self) {
351 if (res != 0) 359 if (res != 0)
352 result = TranslateError(GET_ERRNO); 360 result = TranslateError(GET_ERRNO);
353 361
354 cmd_buffer[2] = res; 362 cmd_buffer[0] = IPC::MakeHeader(5, 2, 0);
355 cmd_buffer[1] = result; 363 cmd_buffer[1] = result;
364 cmd_buffer[2] = res;
356} 365}
357 366
358static void Fcntl(Service::Interface* self) { 367static void Fcntl(Service::Interface* self) {
@@ -369,7 +378,7 @@ static void Fcntl(Service::Interface* self) {
369 }); 378 });
370 379
371 if (ctr_cmd == 3) { // F_GETFL 380 if (ctr_cmd == 3) { // F_GETFL
372#if EMU_PLATFORM == PLATFORM_WINDOWS 381#ifdef _WIN32
373 posix_ret = 0; 382 posix_ret = 0;
374 auto iter = open_sockets.find(socket_handle); 383 auto iter = open_sockets.find(socket_handle);
375 if (iter != open_sockets.end() && iter->second.blocking == false) 384 if (iter != open_sockets.end() && iter->second.blocking == false)
@@ -386,7 +395,7 @@ static void Fcntl(Service::Interface* self) {
386 posix_ret |= 4; // O_NONBLOCK 395 posix_ret |= 4; // O_NONBLOCK
387#endif 396#endif
388 } else if (ctr_cmd == 4) { // F_SETFL 397 } else if (ctr_cmd == 4) { // F_SETFL
389#if EMU_PLATFORM == PLATFORM_WINDOWS 398#ifdef _WIN32
390 unsigned long tmp = (ctr_arg & 4 /* O_NONBLOCK */) ? 1 : 0; 399 unsigned long tmp = (ctr_arg & 4 /* O_NONBLOCK */) ? 1 : 0;
391 int ret = ioctlsocket(socket_handle, FIONBIO, &tmp); 400 int ret = ioctlsocket(socket_handle, FIONBIO, &tmp);
392 if (ret == SOCKET_ERROR_VALUE) { 401 if (ret == SOCKET_ERROR_VALUE) {
@@ -434,8 +443,9 @@ static void Listen(Service::Interface* self) {
434 if (ret != 0) 443 if (ret != 0)
435 result = TranslateError(GET_ERRNO); 444 result = TranslateError(GET_ERRNO);
436 445
437 cmd_buffer[2] = ret; 446 cmd_buffer[0] = IPC::MakeHeader(3, 2, 0);
438 cmd_buffer[1] = result; 447 cmd_buffer[1] = result;
448 cmd_buffer[2] = ret;
439} 449}
440 450
441static void Accept(Service::Interface* self) { 451static void Accept(Service::Interface* self) {
@@ -460,8 +470,10 @@ static void Accept(Service::Interface* self) {
460 Memory::WriteBlock(cmd_buffer[0x104 >> 2], (const u8*)&ctr_addr, max_addr_len); 470 Memory::WriteBlock(cmd_buffer[0x104 >> 2], (const u8*)&ctr_addr, max_addr_len);
461 } 471 }
462 472
463 cmd_buffer[2] = ret; 473 cmd_buffer[0] = IPC::MakeHeader(4, 2, 2);
464 cmd_buffer[1] = result; 474 cmd_buffer[1] = result;
475 cmd_buffer[2] = ret;
476 cmd_buffer[3] = IPC::StaticBufferDesc(static_cast<u32>(max_addr_len), 0);
465} 477}
466 478
467static void GetHostId(Service::Interface* self) { 479static void GetHostId(Service::Interface* self) {
@@ -675,26 +687,29 @@ static void Connect(Service::Interface* self) {
675 int result = 0; 687 int result = 0;
676 if (ret != 0) 688 if (ret != 0)
677 result = TranslateError(GET_ERRNO); 689 result = TranslateError(GET_ERRNO);
678 cmd_buffer[2] = ret; 690
691 cmd_buffer[0] = IPC::MakeHeader(6, 2, 0);
679 cmd_buffer[1] = result; 692 cmd_buffer[1] = result;
693 cmd_buffer[2] = ret;
680} 694}
681 695
682static void InitializeSockets(Service::Interface* self) { 696static void InitializeSockets(Service::Interface* self) {
683 // TODO(Subv): Implement 697 // TODO(Subv): Implement
684#if EMU_PLATFORM == PLATFORM_WINDOWS 698#ifdef _WIN32
685 WSADATA data; 699 WSADATA data;
686 WSAStartup(MAKEWORD(2, 2), &data); 700 WSAStartup(MAKEWORD(2, 2), &data);
687#endif 701#endif
688 702
689 u32* cmd_buffer = Kernel::GetCommandBuffer(); 703 u32* cmd_buffer = Kernel::GetCommandBuffer();
690 cmd_buffer[1] = 0; 704 cmd_buffer[0] = IPC::MakeHeader(1, 1, 0);
705 cmd_buffer[1] = RESULT_SUCCESS.raw;
691} 706}
692 707
693static void ShutdownSockets(Service::Interface* self) { 708static void ShutdownSockets(Service::Interface* self) {
694 // TODO(Subv): Implement 709 // TODO(Subv): Implement
695 CleanupSockets(); 710 CleanupSockets();
696 711
697#if EMU_PLATFORM == PLATFORM_WINDOWS 712#ifdef _WIN32
698 WSACleanup(); 713 WSACleanup();
699#endif 714#endif
700 715
@@ -745,7 +760,7 @@ Interface::Interface() {
745 760
746Interface::~Interface() { 761Interface::~Interface() {
747 CleanupSockets(); 762 CleanupSockets();
748#if EMU_PLATFORM == PLATFORM_WINDOWS 763#ifdef _WIN32
749 WSACleanup(); 764 WSACleanup();
750#endif 765#endif
751} 766}
diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h
index 483b3111b..a091f597c 100644
--- a/src/core/hle/service/soc_u.h
+++ b/src/core/hle/service/soc_u.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <string>
8
7#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
8 10
9//////////////////////////////////////////////////////////////////////////////////////////////////// 11////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index 6c49fa6cf..3b8c7c0e4 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -68,4 +68,8 @@ Interface::Interface() {
68 Register(FunctionTable); 68 Register(FunctionTable);
69} 69}
70 70
71Interface::~Interface() {
72 event_handle = nullptr;
73}
74
71} // namespace 75} // namespace
diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h
index 653aba5cb..96c89b025 100644
--- a/src/core/hle/service/srv.h
+++ b/src/core/hle/service/srv.h
@@ -13,6 +13,7 @@ namespace SRV {
13class Interface : public Service::Interface { 13class Interface : public Service::Interface {
14public: 14public:
15 Interface(); 15 Interface();
16 ~Interface() override;
16 17
17 std::string GetPortName() const override { 18 std::string GetPortName() const override {
18 return "srv:"; 19 return "srv:";
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp
index ac1967da8..6e7dafaad 100644
--- a/src/core/hle/service/y2r_u.cpp
+++ b/src/core/hle/service/y2r_u.cpp
@@ -12,6 +12,7 @@
12#include "core/hw/y2r.h" 12#include "core/hw/y2r.h"
13#include "core/mem_map.h" 13#include "core/mem_map.h"
14 14
15#include "video_core/renderer_base.h"
15#include "video_core/utils.h" 16#include "video_core/utils.h"
16#include "video_core/video_core.h" 17#include "video_core/video_core.h"
17 18
@@ -409,4 +410,8 @@ Interface::Interface() {
409 Register(FunctionTable); 410 Register(FunctionTable);
410} 411}
411 412
413Interface::~Interface() {
414 completion_event = nullptr;
415}
416
412} // namespace 417} // namespace
diff --git a/src/core/hle/service/y2r_u.h b/src/core/hle/service/y2r_u.h
index 7df47fcb9..3965a5545 100644
--- a/src/core/hle/service/y2r_u.h
+++ b/src/core/hle/service/y2r_u.h
@@ -5,9 +5,11 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <string>
8 9
9#include "common/common_types.h" 10#include "common/common_types.h"
10 11
12#include "core/hle/result.h"
11#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
12 14
13//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -110,6 +112,7 @@ struct ConversionConfiguration {
110class Interface : public Service::Interface { 112class Interface : public Service::Interface {
111public: 113public:
112 Interface(); 114 Interface();
115 ~Interface() override;
113 116
114 std::string GetPortName() const override { 117 std::string GetPortName() const override {
115 return "y2r:u"; 118 return "y2r:u";
diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp
index 4014eee98..26d87c7e2 100644
--- a/src/core/hle/shared_page.cpp
+++ b/src/core/hle/shared_page.cpp
@@ -4,12 +4,6 @@
4 4
5#include <cstring> 5#include <cstring>
6 6
7#include "common/common_types.h"
8#include "common/common_funcs.h"
9
10#include "core/core.h"
11#include "core/memory.h"
12#include "core/hle/config_mem.h"
13#include "core/hle/shared_page.h" 7#include "core/hle/shared_page.h"
14 8
15//////////////////////////////////////////////////////////////////////////////////////////////////// 9////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/shared_page.h b/src/core/hle/shared_page.h
index fd2ab66a2..db6a5340b 100644
--- a/src/core/hle/shared_page.h
+++ b/src/core/hle/shared_page.h
@@ -10,9 +10,12 @@
10 * write access, according to 3dbrew; this is not emulated) 10 * write access, according to 3dbrew; this is not emulated)
11 */ 11 */
12 12
13#include "common/common_funcs.h"
13#include "common/common_types.h" 14#include "common/common_types.h"
14#include "common/swap.h" 15#include "common/swap.h"
15 16
17#include "core/memory.h"
18
16//////////////////////////////////////////////////////////////////////////////////////////////////// 19////////////////////////////////////////////////////////////////////////////////////////////////////
17 20
18namespace SharedPage { 21namespace SharedPage {
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 6cde4fc87..bb64fdfb7 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -22,6 +22,7 @@
22#include "core/hle/kernel/shared_memory.h" 22#include "core/hle/kernel/shared_memory.h"
23#include "core/hle/kernel/thread.h" 23#include "core/hle/kernel/thread.h"
24#include "core/hle/kernel/timer.h" 24#include "core/hle/kernel/timer.h"
25#include "core/hle/kernel/vm_manager.h"
25 26
26#include "core/hle/function_wrappers.h" 27#include "core/hle/function_wrappers.h"
27#include "core/hle/result.h" 28#include "core/hle/result.h"
@@ -333,7 +334,7 @@ static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle
333 334
334/// Get resource limit current values 335/// Get resource limit current values
335static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit_handle, u32* names, 336static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit_handle, u32* names,
336 s32 name_count) { 337 u32 name_count) {
337 LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d", 338 LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
338 resource_limit_handle, names, name_count); 339 resource_limit_handle, names, name_count);
339 340
@@ -349,7 +350,7 @@ static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_lim
349 350
350/// Get resource limit max values 351/// Get resource limit max values
351static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit_handle, u32* names, 352static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit_handle, u32* names,
352 s32 name_count) { 353 u32 name_count) {
353 LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d", 354 LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
354 resource_limit_handle, names, name_count); 355 resource_limit_handle, names, name_count);
355 356
@@ -529,12 +530,33 @@ static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count)
529 return RESULT_SUCCESS; 530 return RESULT_SUCCESS;
530} 531}
531 532
532/// Query memory 533/// Query process memory
533static ResultCode QueryMemory(void* info, void* out, u32 addr) { 534static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info, Handle process_handle, u32 addr) {
534 LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr); 535 using Kernel::Process;
536 Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle);
537 if (process == nullptr)
538 return ERR_INVALID_HANDLE;
539
540 auto vma = process->address_space->FindVMA(addr);
541
542 if (vma == process->address_space->vma_map.end())
543 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
544
545 memory_info->base_address = vma->second.base;
546 memory_info->permission = static_cast<u32>(vma->second.permissions);
547 memory_info->size = vma->second.size;
548 memory_info->state = static_cast<u32>(vma->second.meminfo_state);
549
550 page_info->flags = 0;
551 LOG_TRACE(Kernel_SVC, "called process=0x%08X addr=0x%08X", process_handle, addr);
535 return RESULT_SUCCESS; 552 return RESULT_SUCCESS;
536} 553}
537 554
555/// Query memory
556static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32 addr) {
557 return QueryProcessMemory(memory_info, page_info, Kernel::CurrentProcess, addr);
558}
559
538/// Create an event 560/// Create an event
539static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { 561static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) {
540 using Kernel::Event; 562 using Kernel::Event;
@@ -806,13 +828,12 @@ static const FunctionDef SVC_Table[] = {
806 {0x7A, nullptr, "AddCodeSegment"}, 828 {0x7A, nullptr, "AddCodeSegment"},
807 {0x7B, nullptr, "Backdoor"}, 829 {0x7B, nullptr, "Backdoor"},
808 {0x7C, nullptr, "KernelSetState"}, 830 {0x7C, nullptr, "KernelSetState"},
809 {0x7D, nullptr, "QueryProcessMemory"}, 831 {0x7D, HLE::Wrap<QueryProcessMemory>, "QueryProcessMemory"},
810}; 832};
811 833
812Common::Profiling::TimingCategory profiler_svc("SVC Calls"); 834Common::Profiling::TimingCategory profiler_svc("SVC Calls");
813 835
814static const FunctionDef* GetSVCInfo(u32 opcode) { 836static const FunctionDef* GetSVCInfo(u32 func_num) {
815 u32 func_num = opcode & 0xFFFFFF; // 8 bits
816 if (func_num >= ARRAY_SIZE(SVC_Table)) { 837 if (func_num >= ARRAY_SIZE(SVC_Table)) {
817 LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num); 838 LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num);
818 return nullptr; 839 return nullptr;
@@ -820,10 +841,10 @@ static const FunctionDef* GetSVCInfo(u32 opcode) {
820 return &SVC_Table[func_num]; 841 return &SVC_Table[func_num];
821} 842}
822 843
823void CallSVC(u32 opcode) { 844void CallSVC(u32 immediate) {
824 Common::Profiling::ScopeTimer timer_svc(profiler_svc); 845 Common::Profiling::ScopeTimer timer_svc(profiler_svc);
825 846
826 const FunctionDef *info = GetSVCInfo(opcode); 847 const FunctionDef* info = GetSVCInfo(immediate);
827 if (info) { 848 if (info) {
828 if (info->func) { 849 if (info->func) {
829 info->func(); 850 info->func();
diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h
index 4389aa73d..12de9ffbe 100644
--- a/src/core/hle/svc.h
+++ b/src/core/hle/svc.h
@@ -41,6 +41,6 @@ enum ArbitrationType {
41 41
42namespace SVC { 42namespace SVC {
43 43
44void CallSVC(u32 opcode); 44void CallSVC(u32 immediate);
45 45
46} // namespace 46} // namespace
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 7471def57..3ccbc03b2 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -2,17 +2,18 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
6#include <type_traits>
7
5#include "common/color.h" 8#include "common/color.h"
6#include "common/common_types.h" 9#include "common/common_types.h"
7 10#include "common/logging/log.h"
8#include "core/arm/arm_interface.h" 11#include "common/vector_math.h"
9 12
10#include "core/settings.h" 13#include "core/settings.h"
11#include "core/core.h"
12#include "core/memory.h" 14#include "core/memory.h"
13#include "core/core_timing.h" 15#include "core/core_timing.h"
14 16
15#include "core/hle/hle.h"
16#include "core/hle/service/gsp_gpu.h" 17#include "core/hle/service/gsp_gpu.h"
17#include "core/hle/service/dsp_dsp.h" 18#include "core/hle/service/dsp_dsp.h"
18#include "core/hle/service/hid/hid.h" 19#include "core/hle/service/hid/hid.h"
@@ -20,10 +21,17 @@
20#include "core/hw/hw.h" 21#include "core/hw/hw.h"
21#include "core/hw/gpu.h" 22#include "core/hw/gpu.h"
22 23
24#include "core/tracer/recorder.h"
25
23#include "video_core/command_processor.h" 26#include "video_core/command_processor.h"
27#include "video_core/hwrasterizer_base.h"
28#include "video_core/renderer_base.h"
24#include "video_core/utils.h" 29#include "video_core/utils.h"
25#include "video_core/video_core.h" 30#include "video_core/video_core.h"
26 31
32#include "video_core/debug_utils/debug_utils.h"
33
34
27namespace GPU { 35namespace GPU {
28 36
29Regs g_regs; 37Regs g_regs;
@@ -53,6 +61,29 @@ inline void Read(T &var, const u32 raw_addr) {
53 var = g_regs[addr / 4]; 61 var = g_regs[addr / 4];
54} 62}
55 63
64static Math::Vec4<u8> DecodePixel(Regs::PixelFormat input_format, const u8* src_pixel) {
65 switch (input_format) {
66 case Regs::PixelFormat::RGBA8:
67 return Color::DecodeRGBA8(src_pixel);
68
69 case Regs::PixelFormat::RGB8:
70 return Color::DecodeRGB8(src_pixel);
71
72 case Regs::PixelFormat::RGB565:
73 return Color::DecodeRGB565(src_pixel);
74
75 case Regs::PixelFormat::RGB5A1:
76 return Color::DecodeRGB5A1(src_pixel);
77
78 case Regs::PixelFormat::RGBA4:
79 return Color::DecodeRGBA4(src_pixel);
80
81 default:
82 LOG_ERROR(HW_GPU, "Unknown source framebuffer format %x", input_format);
83 return {0, 0, 0, 0};
84 }
85}
86
56template <typename T> 87template <typename T>
57inline void Write(u32 addr, const T data) { 88inline void Write(u32 addr, const T data) {
58 addr -= HW::VADDR_GPU; 89 addr -= HW::VADDR_GPU;
@@ -75,39 +106,43 @@ inline void Write(u32 addr, const T data) {
75 const bool is_second_filler = (index != GPU_REG_INDEX(memory_fill_config[0].trigger)); 106 const bool is_second_filler = (index != GPU_REG_INDEX(memory_fill_config[0].trigger));
76 auto& config = g_regs.memory_fill_config[is_second_filler]; 107 auto& config = g_regs.memory_fill_config[is_second_filler];
77 108
78 if (config.address_start && config.trigger) { 109 if (config.trigger) {
79 u8* start = Memory::GetPhysicalPointer(config.GetStartAddress()); 110 if (config.address_start) { // Some games pass invalid values here
80 u8* end = Memory::GetPhysicalPointer(config.GetEndAddress()); 111 u8* start = Memory::GetPhysicalPointer(config.GetStartAddress());
81 112 u8* end = Memory::GetPhysicalPointer(config.GetEndAddress());
82 if (config.fill_24bit) { 113
83 // fill with 24-bit values 114 if (config.fill_24bit) {
84 for (u8* ptr = start; ptr < end; ptr += 3) { 115 // fill with 24-bit values
85 ptr[0] = config.value_24bit_r; 116 for (u8* ptr = start; ptr < end; ptr += 3) {
86 ptr[1] = config.value_24bit_g; 117 ptr[0] = config.value_24bit_r;
87 ptr[2] = config.value_24bit_b; 118 ptr[1] = config.value_24bit_g;
119 ptr[2] = config.value_24bit_b;
120 }
121 } else if (config.fill_32bit) {
122 // fill with 32-bit values
123 for (u32* ptr = (u32*)start; ptr < (u32*)end; ++ptr)
124 *ptr = config.value_32bit;
125 } else {
126 // fill with 16-bit values
127 for (u16* ptr = (u16*)start; ptr < (u16*)end; ++ptr)
128 *ptr = config.value_16bit;
88 } 129 }
89 } else if (config.fill_32bit) {
90 // fill with 32-bit values
91 for (u32* ptr = (u32*)start; ptr < (u32*)end; ++ptr)
92 *ptr = config.value_32bit;
93 } else {
94 // fill with 16-bit values
95 for (u16* ptr = (u16*)start; ptr < (u16*)end; ++ptr)
96 *ptr = config.value_16bit;
97 }
98 130
99 LOG_TRACE(HW_GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress()); 131 LOG_TRACE(HW_GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress());
100 132
101 config.trigger = 0; 133 if (!is_second_filler) {
102 config.finished = 1; 134 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC0);
135 } else {
136 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC1);
137 }
103 138
104 if (!is_second_filler) { 139 VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetStartAddress(), config.GetEndAddress() - config.GetStartAddress());
105 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC0);
106 } else {
107 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC1);
108 } 140 }
109 141
110 VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetStartAddress(), config.GetEndAddress() - config.GetStartAddress()); 142 // Reset "trigger" flag and set the "finish" flag
143 // NOTE: This was confirmed to happen on hardware even if "address_start" is zero.
144 config.trigger = 0;
145 config.finished = 1;
111 } 146 }
112 break; 147 break;
113 } 148 }
@@ -116,6 +151,10 @@ inline void Write(u32 addr, const T data) {
116 { 151 {
117 const auto& config = g_regs.display_transfer_config; 152 const auto& config = g_regs.display_transfer_config;
118 if (config.trigger & 1) { 153 if (config.trigger & 1) {
154
155 if (Pica::g_debug_context)
156 Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::IncomingDisplayTransfer, nullptr);
157
119 u8* src_pointer = Memory::GetPhysicalPointer(config.GetPhysicalInputAddress()); 158 u8* src_pointer = Memory::GetPhysicalPointer(config.GetPhysicalInputAddress());
120 u8* dst_pointer = Memory::GetPhysicalPointer(config.GetPhysicalOutputAddress()); 159 u8* dst_pointer = Memory::GetPhysicalPointer(config.GetPhysicalOutputAddress());
121 160
@@ -125,11 +164,18 @@ inline void Write(u32 addr, const T data) {
125 break; 164 break;
126 } 165 }
127 166
128 unsigned horizontal_scale = (config.scaling != config.NoScale) ? 2 : 1; 167 if (config.output_tiled &&
129 unsigned vertical_scale = (config.scaling == config.ScaleXY) ? 2 : 1; 168 (config.scaling == config.ScaleXY || config.scaling == config.ScaleX)) {
169 LOG_CRITICAL(HW_GPU, "Scaling is only implemented on tiled input");
170 UNIMPLEMENTED();
171 break;
172 }
130 173
131 u32 output_width = config.output_width / horizontal_scale; 174 bool horizontal_scale = config.scaling != config.NoScale;
132 u32 output_height = config.output_height / vertical_scale; 175 bool vertical_scale = config.scaling == config.ScaleXY;
176
177 u32 output_width = config.output_width >> horizontal_scale;
178 u32 output_height = config.output_height >> vertical_scale;
133 179
134 u32 input_size = config.input_width * config.input_height * GPU::Regs::BytesPerPixel(config.input_format); 180 u32 input_size = config.input_width * config.input_height * GPU::Regs::BytesPerPixel(config.input_format);
135 u32 output_size = output_width * output_height * GPU::Regs::BytesPerPixel(config.output_format); 181 u32 output_size = output_width * output_height * GPU::Regs::BytesPerPixel(config.output_format);
@@ -153,16 +199,14 @@ inline void Write(u32 addr, const T data) {
153 break; 199 break;
154 } 200 }
155 201
156 // TODO(Subv): Implement the box filter when scaling is enabled
157 // right now we're just skipping the extra pixels.
158 for (u32 y = 0; y < output_height; ++y) { 202 for (u32 y = 0; y < output_height; ++y) {
159 for (u32 x = 0; x < output_width; ++x) { 203 for (u32 x = 0; x < output_width; ++x) {
160 Math::Vec4<u8> src_color = { 0, 0, 0, 0 }; 204 Math::Vec4<u8> src_color;
161 205
162 // Calculate the [x,y] position of the input image 206 // Calculate the [x,y] position of the input image
163 // based on the current output position and the scale 207 // based on the current output position and the scale
164 u32 input_x = x * horizontal_scale; 208 u32 input_x = x << horizontal_scale;
165 u32 input_y = y * vertical_scale; 209 u32 input_y = y << vertical_scale;
166 210
167 if (config.flip_vertically) { 211 if (config.flip_vertically) {
168 // Flip the y value of the output data, 212 // Flip the y value of the output data,
@@ -177,46 +221,49 @@ inline void Write(u32 addr, const T data) {
177 u32 dst_offset; 221 u32 dst_offset;
178 222
179 if (config.output_tiled) { 223 if (config.output_tiled) {
180 // Interpret the input as linear and the output as tiled 224 if (!config.dont_swizzle) {
181 u32 coarse_y = y & ~7; 225 // Interpret the input as linear and the output as tiled
182 u32 stride = output_width * dst_bytes_per_pixel; 226 u32 coarse_y = y & ~7;
183 227 u32 stride = output_width * dst_bytes_per_pixel;
184 src_offset = (input_x + input_y * config.input_width) * src_bytes_per_pixel; 228
185 dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + coarse_y * stride; 229 src_offset = (input_x + input_y * config.input_width) * src_bytes_per_pixel;
230 dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + coarse_y * stride;
231 } else {
232 // Both input and output are linear
233 src_offset = (input_x + input_y * config.input_width) * src_bytes_per_pixel;
234 dst_offset = (x + y * output_width) * dst_bytes_per_pixel;
235 }
186 } else { 236 } else {
187 // Interpret the input as tiled and the output as linear 237 if (!config.dont_swizzle) {
188 u32 coarse_y = input_y & ~7; 238 // Interpret the input as tiled and the output as linear
189 u32 stride = config.input_width * src_bytes_per_pixel; 239 u32 coarse_y = input_y & ~7;
190 240 u32 stride = config.input_width * src_bytes_per_pixel;
191 src_offset = VideoCore::GetMortonOffset(input_x, input_y, src_bytes_per_pixel) + coarse_y * stride; 241
192 dst_offset = (x + y * output_width) * dst_bytes_per_pixel; 242 src_offset = VideoCore::GetMortonOffset(input_x, input_y, src_bytes_per_pixel) + coarse_y * stride;
243 dst_offset = (x + y * output_width) * dst_bytes_per_pixel;
244 } else {
245 // Both input and output are tiled
246 u32 out_coarse_y = y & ~7;
247 u32 out_stride = output_width * dst_bytes_per_pixel;
248
249 u32 in_coarse_y = input_y & ~7;
250 u32 in_stride = config.input_width * src_bytes_per_pixel;
251
252 src_offset = VideoCore::GetMortonOffset(input_x, input_y, src_bytes_per_pixel) + in_coarse_y * in_stride;
253 dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + out_coarse_y * out_stride;
254 }
193 } 255 }
194 256
195 const u8* src_pixel = src_pointer + src_offset; 257 const u8* src_pixel = src_pointer + src_offset;
196 switch (config.input_format) { 258 src_color = DecodePixel(config.input_format, src_pixel);
197 case Regs::PixelFormat::RGBA8: 259 if (config.scaling == config.ScaleX) {
198 src_color = Color::DecodeRGBA8(src_pixel); 260 Math::Vec4<u8> pixel = DecodePixel(config.input_format, src_pixel + src_bytes_per_pixel);
199 break; 261 src_color = ((src_color + pixel) / 2).Cast<u8>();
200 262 } else if (config.scaling == config.ScaleXY) {
201 case Regs::PixelFormat::RGB8: 263 Math::Vec4<u8> pixel1 = DecodePixel(config.input_format, src_pixel + 1 * src_bytes_per_pixel);
202 src_color = Color::DecodeRGB8(src_pixel); 264 Math::Vec4<u8> pixel2 = DecodePixel(config.input_format, src_pixel + 2 * src_bytes_per_pixel);
203 break; 265 Math::Vec4<u8> pixel3 = DecodePixel(config.input_format, src_pixel + 3 * src_bytes_per_pixel);
204 266 src_color = (((src_color + pixel1) + (pixel2 + pixel3)) / 4).Cast<u8>();
205 case Regs::PixelFormat::RGB565:
206 src_color = Color::DecodeRGB565(src_pixel);
207 break;
208
209 case Regs::PixelFormat::RGB5A1:
210 src_color = Color::DecodeRGB5A1(src_pixel);
211 break;
212
213 case Regs::PixelFormat::RGBA4:
214 src_color = Color::DecodeRGBA4(src_pixel);
215 break;
216
217 default:
218 LOG_ERROR(HW_GPU, "Unknown source framebuffer format %x", config.input_format.Value());
219 break;
220 } 267 }
221 268
222 u8* dst_pixel = dst_pointer + dst_offset; 269 u8* dst_pixel = dst_pointer + dst_offset;
@@ -254,6 +301,7 @@ inline void Write(u32 addr, const T data) {
254 config.GetPhysicalOutputAddress(), output_width, output_height, 301 config.GetPhysicalOutputAddress(), output_width, output_height,
255 config.output_format.Value(), config.flags); 302 config.output_format.Value(), config.flags);
256 303
304 g_regs.display_transfer_config.trigger = 0;
257 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF); 305 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF);
258 306
259 VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetPhysicalOutputAddress(), output_size); 307 VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetPhysicalOutputAddress(), output_size);
@@ -268,7 +316,14 @@ inline void Write(u32 addr, const T data) {
268 if (config.trigger & 1) 316 if (config.trigger & 1)
269 { 317 {
270 u32* buffer = (u32*)Memory::GetPhysicalPointer(config.GetPhysicalAddress()); 318 u32* buffer = (u32*)Memory::GetPhysicalPointer(config.GetPhysicalAddress());
319
320 if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
321 Pica::g_debug_context->recorder->MemoryAccessed((u8*)buffer, config.size * sizeof(u32), config.GetPhysicalAddress());
322 }
323
271 Pica::CommandProcessor::ProcessCommandList(buffer, config.size); 324 Pica::CommandProcessor::ProcessCommandList(buffer, config.size);
325
326 g_regs.command_processor_config.trigger = 0;
272 } 327 }
273 break; 328 break;
274 } 329 }
@@ -276,6 +331,13 @@ inline void Write(u32 addr, const T data) {
276 default: 331 default:
277 break; 332 break;
278 } 333 }
334
335 // Notify tracer about the register write
336 // This is happening *after* handling the write to make sure we properly catch all memory reads.
337 if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
338 // addr + GPU VBase - IO VBase + IO PBase
339 Pica::g_debug_context->recorder->RegisterWritten<T>(addr + 0x1EF00000 - 0x1EC00000 + 0x10100000, data);
340 }
279} 341}
280 342
281// Explicitly instantiate template functions because we aren't defining this in the header: 343// Explicitly instantiate template functions because we aren't defining this in the header:
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index 699bcd2a5..daad506fe 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <cstddef>
8#include <type_traits>
8 9
9#include "common/assert.h" 10#include "common/assert.h"
10#include "common/bit_field.h" 11#include "common/bit_field.h"
@@ -202,6 +203,7 @@ struct Regs {
202 BitField< 0, 1, u32> flip_vertically; // flips input data vertically 203 BitField< 0, 1, u32> flip_vertically; // flips input data vertically
203 BitField< 1, 1, u32> output_tiled; // Converts from linear to tiled format 204 BitField< 1, 1, u32> output_tiled; // Converts from linear to tiled format
204 BitField< 3, 1, u32> raw_copy; // Copies the data without performing any processing 205 BitField< 3, 1, u32> raw_copy; // Copies the data without performing any processing
206 BitField< 5, 1, u32> dont_swizzle;
205 BitField< 8, 3, PixelFormat> input_format; 207 BitField< 8, 3, PixelFormat> input_format;
206 BitField<12, 3, PixelFormat> output_format; 208 BitField<12, 3, PixelFormat> output_format;
207 209
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp
index c7006a498..b5fdbf9c1 100644
--- a/src/core/hw/hw.cpp
+++ b/src/core/hw/hw.cpp
@@ -15,6 +15,21 @@ template <typename T>
15inline void Read(T &var, const u32 addr) { 15inline void Read(T &var, const u32 addr) {
16 switch (addr & 0xFFFFF000) { 16 switch (addr & 0xFFFFF000) {
17 case VADDR_GPU: 17 case VADDR_GPU:
18 case VADDR_GPU + 0x1000:
19 case VADDR_GPU + 0x2000:
20 case VADDR_GPU + 0x3000:
21 case VADDR_GPU + 0x4000:
22 case VADDR_GPU + 0x5000:
23 case VADDR_GPU + 0x6000:
24 case VADDR_GPU + 0x7000:
25 case VADDR_GPU + 0x8000:
26 case VADDR_GPU + 0x9000:
27 case VADDR_GPU + 0xA000:
28 case VADDR_GPU + 0xB000:
29 case VADDR_GPU + 0xC000:
30 case VADDR_GPU + 0xD000:
31 case VADDR_GPU + 0xE000:
32 case VADDR_GPU + 0xF000:
18 GPU::Read(var, addr); 33 GPU::Read(var, addr);
19 break; 34 break;
20 case VADDR_LCD: 35 case VADDR_LCD:
@@ -29,6 +44,21 @@ template <typename T>
29inline void Write(u32 addr, const T data) { 44inline void Write(u32 addr, const T data) {
30 switch (addr & 0xFFFFF000) { 45 switch (addr & 0xFFFFF000) {
31 case VADDR_GPU: 46 case VADDR_GPU:
47 case VADDR_GPU + 0x1000:
48 case VADDR_GPU + 0x2000:
49 case VADDR_GPU + 0x3000:
50 case VADDR_GPU + 0x4000:
51 case VADDR_GPU + 0x5000:
52 case VADDR_GPU + 0x6000:
53 case VADDR_GPU + 0x7000:
54 case VADDR_GPU + 0x8000:
55 case VADDR_GPU + 0x9000:
56 case VADDR_GPU + 0xA000:
57 case VADDR_GPU + 0xB000:
58 case VADDR_GPU + 0xC000:
59 case VADDR_GPU + 0xD000:
60 case VADDR_GPU + 0xE000:
61 case VADDR_GPU + 0xF000:
32 GPU::Write(addr, data); 62 GPU::Write(addr, data);
33 break; 63 break;
34 case VADDR_LCD: 64 case VADDR_LCD:
diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp
index 963c8d981..6f93709e3 100644
--- a/src/core/hw/lcd.cpp
+++ b/src/core/hw/lcd.cpp
@@ -7,11 +7,12 @@
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9 9
10#include "core/arm/arm_interface.h"
11#include "core/hle/hle.h"
12#include "core/hw/hw.h" 10#include "core/hw/hw.h"
13#include "core/hw/lcd.h" 11#include "core/hw/lcd.h"
14 12
13#include "core/tracer/recorder.h"
14#include "video_core/debug_utils/debug_utils.h"
15
15namespace LCD { 16namespace LCD {
16 17
17Regs g_regs; 18Regs g_regs;
@@ -42,6 +43,13 @@ inline void Write(u32 addr, const T data) {
42 } 43 }
43 44
44 g_regs[index] = static_cast<u32>(data); 45 g_regs[index] = static_cast<u32>(data);
46
47 // Notify tracer about the register write
48 // This is happening *after* handling the write to make sure we properly catch all memory reads.
49 if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
50 // addr + GPU VBase - IO VBase + IO PBase
51 Pica::g_debug_context->recorder->RegisterWritten<T>(addr + HW::VADDR_LCD - 0x1EC00000 + 0x10100000, data);
52 }
45} 53}
46 54
47// Explicitly instantiate template functions because we aren't defining this in the header: 55// Explicitly instantiate template functions because we aren't defining this in the header:
diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h
index 8631eb201..bcce6d8cf 100644
--- a/src/core/hw/lcd.h
+++ b/src/core/hw/lcd.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <cstddef>
8#include <type_traits>
8 9
9#include "common/bit_field.h" 10#include "common/bit_field.h"
10#include "common/common_funcs.h" 11#include "common/common_funcs.h"
diff --git a/src/core/hw/y2r.cpp b/src/core/hw/y2r.cpp
index 5b7fb39e1..f80e26ecd 100644
--- a/src/core/hw/y2r.cpp
+++ b/src/core/hw/y2r.cpp
@@ -2,8 +2,10 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
5#include <array> 6#include <array>
6#include <numeric> 7#include <cstddef>
8#include <memory>
7 9
8#include "common/assert.h" 10#include "common/assert.h"
9#include "common/color.h" 11#include "common/color.h"
@@ -109,7 +111,7 @@ static void SendData(const u32* input, ConversionBuffer& buf, int amount_of_data
109 while (output < unit_end) { 111 while (output < unit_end) {
110 u32 color = *input++; 112 u32 color = *input++;
111 Math::Vec4<u8> col_vec{ 113 Math::Vec4<u8> col_vec{
112 (color >> 24) & 0xFF, (color >> 16) & 0xFF, (color >> 8) & 0xFF, alpha, 114 (u8)(color >> 24), (u8)(color >> 16), (u8)(color >> 8), alpha
113 }; 115 };
114 116
115 switch (output_format) { 117 switch (output_format) {
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index 14aeebebb..530837d08 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -19,7 +19,7 @@
19 19
20namespace Loader { 20namespace Loader {
21 21
22/** 22/*
23 * File layout: 23 * File layout:
24 * - File header 24 * - File header
25 * - Code, rodata and data relocation table headers 25 * - Code, rodata and data relocation table headers
@@ -39,13 +39,16 @@ namespace Loader {
39 * The entrypoint is always the start of the code segment. 39 * The entrypoint is always the start of the code segment.
40 * The BSS section must be cleared manually by the application. 40 * The BSS section must be cleared manually by the application.
41 */ 41 */
42
42enum THREEDSX_Error { 43enum THREEDSX_Error {
43 ERROR_NONE = 0, 44 ERROR_NONE = 0,
44 ERROR_READ = 1, 45 ERROR_READ = 1,
45 ERROR_FILE = 2, 46 ERROR_FILE = 2,
46 ERROR_ALLOC = 3 47 ERROR_ALLOC = 3
47}; 48};
49
48static const u32 RELOCBUFSIZE = 512; 50static const u32 RELOCBUFSIZE = 512;
51static const unsigned int NUM_SEGMENTS = 3;
49 52
50// File header 53// File header
51#pragma pack(1) 54#pragma pack(1)
@@ -98,7 +101,10 @@ static u32 TranslateAddr(u32 addr, const THREEloadinfo *loadinfo, u32* offsets)
98 return loadinfo->seg_addrs[2] + addr - offsets[1]; 101 return loadinfo->seg_addrs[2] + addr - offsets[1];
99} 102}
100 103
101static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr) 104using Kernel::SharedPtr;
105using Kernel::CodeSet;
106
107static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, SharedPtr<CodeSet>* out_codeset)
102{ 108{
103 if (!file.IsOpen()) 109 if (!file.IsOpen())
104 return ERROR_FILE; 110 return ERROR_FILE;
@@ -116,15 +122,13 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
116 loadinfo.seg_sizes[1] = (hdr.rodata_seg_size + 0xFFF) &~0xFFF; 122 loadinfo.seg_sizes[1] = (hdr.rodata_seg_size + 0xFFF) &~0xFFF;
117 loadinfo.seg_sizes[2] = (hdr.data_seg_size + 0xFFF) &~0xFFF; 123 loadinfo.seg_sizes[2] = (hdr.data_seg_size + 0xFFF) &~0xFFF;
118 u32 offsets[2] = { loadinfo.seg_sizes[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] }; 124 u32 offsets[2] = { loadinfo.seg_sizes[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] };
119 u32 data_load_size = (hdr.data_seg_size - hdr.bss_size + 0xFFF) &~0xFFF; 125 u32 n_reloc_tables = hdr.reloc_hdr_size / sizeof(u32);
120 u32 bss_load_size = loadinfo.seg_sizes[2] - data_load_size; 126 std::vector<u8> program_image(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2]);
121 u32 n_reloc_tables = hdr.reloc_hdr_size / 4;
122 std::vector<u8> all_mem(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2] + 3 * n_reloc_tables);
123 127
124 loadinfo.seg_addrs[0] = base_addr; 128 loadinfo.seg_addrs[0] = base_addr;
125 loadinfo.seg_addrs[1] = loadinfo.seg_addrs[0] + loadinfo.seg_sizes[0]; 129 loadinfo.seg_addrs[1] = loadinfo.seg_addrs[0] + loadinfo.seg_sizes[0];
126 loadinfo.seg_addrs[2] = loadinfo.seg_addrs[1] + loadinfo.seg_sizes[1]; 130 loadinfo.seg_addrs[2] = loadinfo.seg_addrs[1] + loadinfo.seg_sizes[1];
127 loadinfo.seg_ptrs[0] = &all_mem[0]; 131 loadinfo.seg_ptrs[0] = program_image.data();
128 loadinfo.seg_ptrs[1] = loadinfo.seg_ptrs[0] + loadinfo.seg_sizes[0]; 132 loadinfo.seg_ptrs[1] = loadinfo.seg_ptrs[0] + loadinfo.seg_sizes[0];
129 loadinfo.seg_ptrs[2] = loadinfo.seg_ptrs[1] + loadinfo.seg_sizes[1]; 133 loadinfo.seg_ptrs[2] = loadinfo.seg_ptrs[1] + loadinfo.seg_sizes[1];
130 134
@@ -132,10 +136,9 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
132 file.Seek(hdr.header_size, SEEK_SET); 136 file.Seek(hdr.header_size, SEEK_SET);
133 137
134 // Read the relocation headers 138 // Read the relocation headers
135 u32* relocs = (u32*)(loadinfo.seg_ptrs[2] + hdr.data_seg_size); 139 std::vector<u32> relocs(n_reloc_tables * NUM_SEGMENTS);
136 140 for (unsigned int current_segment = 0; current_segment < NUM_SEGMENTS; ++current_segment) {
137 for (unsigned current_segment : {0, 1, 2}) { 141 size_t size = n_reloc_tables * sizeof(u32);
138 size_t size = n_reloc_tables * 4;
139 if (file.ReadBytes(&relocs[current_segment * n_reloc_tables], size) != size) 142 if (file.ReadBytes(&relocs[current_segment * n_reloc_tables], size) != size)
140 return ERROR_READ; 143 return ERROR_READ;
141 } 144 }
@@ -152,7 +155,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
152 memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size); 155 memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size);
153 156
154 // Relocate the segments 157 // Relocate the segments
155 for (unsigned current_segment : {0, 1, 2}) { 158 for (unsigned int current_segment = 0; current_segment < NUM_SEGMENTS; ++current_segment) {
156 for (unsigned current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) { 159 for (unsigned current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) {
157 u32 n_relocs = relocs[current_segment * n_reloc_tables + current_segment_reloc_table]; 160 u32 n_relocs = relocs[current_segment * n_reloc_tables + current_segment_reloc_table];
158 if (current_segment_reloc_table >= 2) { 161 if (current_segment_reloc_table >= 2) {
@@ -160,7 +163,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
160 file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR); 163 file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR);
161 continue; 164 continue;
162 } 165 }
163 static THREEDSX_Reloc reloc_table[RELOCBUFSIZE]; 166 THREEDSX_Reloc reloc_table[RELOCBUFSIZE];
164 167
165 u32* pos = (u32*)loadinfo.seg_ptrs[current_segment]; 168 u32* pos = (u32*)loadinfo.seg_ptrs[current_segment];
166 const u32* end_pos = pos + (loadinfo.seg_sizes[current_segment] / 4); 169 const u32* end_pos = pos + (loadinfo.seg_sizes[current_segment] / 4);
@@ -179,7 +182,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
179 pos += table.skip; 182 pos += table.skip;
180 s32 num_patches = table.patch; 183 s32 num_patches = table.patch;
181 while (0 < num_patches && pos < end_pos) { 184 while (0 < num_patches && pos < end_pos) {
182 u32 in_addr = (char*)pos - (char*)&all_mem[0]; 185 u32 in_addr = (u8*)pos - program_image.data();
183 u32 addr = TranslateAddr(*pos, &loadinfo, offsets); 186 u32 addr = TranslateAddr(*pos, &loadinfo, offsets);
184 LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)\n", 187 LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)\n",
185 base_addr + in_addr, addr, current_segment_reloc_table, *pos); 188 base_addr + in_addr, addr, current_segment_reloc_table, *pos);
@@ -188,7 +191,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
188 *pos = (addr); 191 *pos = (addr);
189 break; 192 break;
190 case 1: 193 case 1:
191 *pos = (addr - in_addr); 194 *pos = static_cast<u32>(addr - in_addr);
192 break; 195 break;
193 default: 196 default:
194 break; //this should never happen 197 break; //this should never happen
@@ -201,14 +204,29 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
201 } 204 }
202 } 205 }
203 206
204 // Write the data 207 // Create the CodeSet
205 memcpy(Memory::GetPointer(base_addr), &all_mem[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2]); 208 SharedPtr<CodeSet> code_set = CodeSet::Create("", 0);
209
210 code_set->code.offset = loadinfo.seg_ptrs[0] - program_image.data();
211 code_set->code.addr = loadinfo.seg_addrs[0];
212 code_set->code.size = loadinfo.seg_sizes[0];
213
214 code_set->rodata.offset = loadinfo.seg_ptrs[1] - program_image.data();
215 code_set->rodata.addr = loadinfo.seg_addrs[1];
216 code_set->rodata.size = loadinfo.seg_sizes[1];
206 217
207 LOG_DEBUG(Loader, "CODE: %u pages\n", loadinfo.seg_sizes[0] / 0x1000); 218 code_set->data.offset = loadinfo.seg_ptrs[2] - program_image.data();
208 LOG_DEBUG(Loader, "RODATA: %u pages\n", loadinfo.seg_sizes[1] / 0x1000); 219 code_set->data.addr = loadinfo.seg_addrs[2];
209 LOG_DEBUG(Loader, "DATA: %u pages\n", data_load_size / 0x1000); 220 code_set->data.size = loadinfo.seg_sizes[2];
210 LOG_DEBUG(Loader, "BSS: %u pages\n", bss_load_size / 0x1000);
211 221
222 code_set->entrypoint = code_set->code.addr;
223 code_set->memory = std::make_shared<std::vector<u8>>(std::move(program_image));
224
225 LOG_DEBUG(Loader, "code size: 0x%X", loadinfo.seg_sizes[0]);
226 LOG_DEBUG(Loader, "rodata size: 0x%X", loadinfo.seg_sizes[1]);
227 LOG_DEBUG(Loader, "data size: 0x%X (including 0x%X of bss)", loadinfo.seg_sizes[2], hdr.bss_size);
228
229 *out_codeset = code_set;
212 return ERROR_NONE; 230 return ERROR_NONE;
213} 231}
214 232
@@ -228,19 +246,22 @@ ResultStatus AppLoader_THREEDSX::Load() {
228 if (is_loaded) 246 if (is_loaded)
229 return ResultStatus::ErrorAlreadyLoaded; 247 return ResultStatus::ErrorAlreadyLoaded;
230 248
231 if (!file->IsOpen()) 249 if (!file.IsOpen())
250 return ResultStatus::Error;
251
252 SharedPtr<CodeSet> codeset;
253 if (Load3DSXFile(file, Memory::PROCESS_IMAGE_VADDR, &codeset) != ERROR_NONE)
232 return ResultStatus::Error; 254 return ResultStatus::Error;
255 codeset->name = filename;
233 256
234 Kernel::g_current_process = Kernel::Process::Create(filename, 0); 257 Kernel::g_current_process = Kernel::Process::Create(std::move(codeset));
235 Kernel::g_current_process->svc_access_mask.set(); 258 Kernel::g_current_process->svc_access_mask.set();
236 Kernel::g_current_process->address_mappings = default_address_mappings; 259 Kernel::g_current_process->address_mappings = default_address_mappings;
237 260
238 // Attach the default resource limit (APPLICATION) to the process 261 // Attach the default resource limit (APPLICATION) to the process
239 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 262 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
240 263
241 Load3DSXFile(*file, Memory::PROCESS_IMAGE_VADDR); 264 Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE);
242
243 Kernel::g_current_process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE);
244 265
245 is_loaded = true; 266 is_loaded = true;
246 return ResultStatus::Success; 267 return ResultStatus::Success;
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h
index 096b3ec20..a0aa0c533 100644
--- a/src/core/loader/3dsx.h
+++ b/src/core/loader/3dsx.h
@@ -17,7 +17,7 @@ namespace Loader {
17/// Loads an 3DSX file 17/// Loads an 3DSX file
18class AppLoader_THREEDSX final : public AppLoader { 18class AppLoader_THREEDSX final : public AppLoader {
19public: 19public:
20 AppLoader_THREEDSX(std::unique_ptr<FileUtil::IOFile>&& file, std::string filename) 20 AppLoader_THREEDSX(FileUtil::IOFile&& file, std::string filename)
21 : AppLoader(std::move(file)), filename(std::move(filename)) {} 21 : AppLoader(std::move(file)), filename(std::move(filename)) {}
22 22
23 /** 23 /**
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index f00753a79..5d7264f12 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
5#include <string> 6#include <string>
6#include <memory> 7#include <memory>
7 8
@@ -10,11 +11,14 @@
10#include "common/logging/log.h" 11#include "common/logging/log.h"
11#include "common/symbols.h" 12#include "common/symbols.h"
12 13
13#include "core/hle/kernel/kernel.h" 14#include "core/hle/kernel/process.h"
14#include "core/hle/kernel/resource_limit.h" 15#include "core/hle/kernel/resource_limit.h"
15#include "core/loader/elf.h" 16#include "core/loader/elf.h"
16#include "core/memory.h" 17#include "core/memory.h"
17 18
19using Kernel::SharedPtr;
20using Kernel::CodeSet;
21
18//////////////////////////////////////////////////////////////////////////////////////////////////// 22////////////////////////////////////////////////////////////////////////////////////////////////////
19// ELF Header Constants 23// ELF Header Constants
20 24
@@ -96,6 +100,12 @@ enum ElfSectionFlags
96#define PT_LOPROC 0x70000000 100#define PT_LOPROC 0x70000000
97#define PT_HIPROC 0x7FFFFFFF 101#define PT_HIPROC 0x7FFFFFFF
98 102
103// Segment flags
104#define PF_X 0x1
105#define PF_W 0x2
106#define PF_R 0x4
107#define PF_MASKPROC 0xF0000000
108
99typedef unsigned int Elf32_Addr; 109typedef unsigned int Elf32_Addr;
100typedef unsigned short Elf32_Half; 110typedef unsigned short Elf32_Half;
101typedef unsigned int Elf32_Off; 111typedef unsigned int Elf32_Off;
@@ -192,7 +202,7 @@ public:
192 ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } 202 ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); }
193 u32 GetEntryPoint() const { return entryPoint; } 203 u32 GetEntryPoint() const { return entryPoint; }
194 u32 GetFlags() const { return (u32)(header->e_flags); } 204 u32 GetFlags() const { return (u32)(header->e_flags); }
195 void LoadInto(u32 vaddr); 205 SharedPtr<CodeSet> LoadInto(u32 vaddr);
196 bool LoadSymbols(); 206 bool LoadSymbols();
197 207
198 int GetNumSegments() const { return (int)(header->e_phnum); } 208 int GetNumSegments() const { return (int)(header->e_phnum); }
@@ -248,7 +258,7 @@ const char *ElfReader::GetSectionName(int section) const {
248 return nullptr; 258 return nullptr;
249} 259}
250 260
251void ElfReader::LoadInto(u32 vaddr) { 261SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
252 LOG_DEBUG(Loader, "String section: %i", header->e_shstrndx); 262 LOG_DEBUG(Loader, "String section: %i", header->e_shstrndx);
253 263
254 // Should we relocate? 264 // Should we relocate?
@@ -263,22 +273,63 @@ void ElfReader::LoadInto(u32 vaddr) {
263 LOG_DEBUG(Loader, "%i segments:", header->e_phnum); 273 LOG_DEBUG(Loader, "%i segments:", header->e_phnum);
264 274
265 // First pass : Get the bits into RAM 275 // First pass : Get the bits into RAM
266 u32 segment_addr[32];
267 u32 base_addr = relocate ? vaddr : 0; 276 u32 base_addr = relocate ? vaddr : 0;
268 277
269 for (unsigned i = 0; i < header->e_phnum; i++) { 278 u32 total_image_size = 0;
270 Elf32_Phdr* p = segments + i; 279 for (unsigned int i = 0; i < header->e_phnum; ++i) {
271 LOG_DEBUG(Loader, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, 280 Elf32_Phdr* p = &segments[i];
281 if (p->p_type == PT_LOAD) {
282 total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF;
283 }
284 }
285
286 std::vector<u8> program_image(total_image_size);
287 size_t current_image_position = 0;
288
289 SharedPtr<CodeSet> codeset = CodeSet::Create("", 0);
290
291 for (unsigned int i = 0; i < header->e_phnum; ++i) {
292 Elf32_Phdr* p = &segments[i];
293 LOG_DEBUG(Loader, "Type: %i Vaddr: %08X Filesz: %8X Memsz: %8X ", p->p_type, p->p_vaddr,
272 p->p_filesz, p->p_memsz); 294 p->p_filesz, p->p_memsz);
273 295
274 if (p->p_type == PT_LOAD) { 296 if (p->p_type == PT_LOAD) {
275 segment_addr[i] = base_addr + p->p_vaddr; 297 CodeSet::Segment* codeset_segment;
276 memcpy(Memory::GetPointer(segment_addr[i]), GetSegmentPtr(i), p->p_filesz); 298 u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X);
277 LOG_DEBUG(Loader, "Loadable Segment Copied to %08x, size %08x", segment_addr[i], 299 if (permission_flags == (PF_R | PF_X)) {
278 p->p_memsz); 300 codeset_segment = &codeset->code;
301 } else if (permission_flags == (PF_R)) {
302 codeset_segment = &codeset->rodata;
303 } else if (permission_flags == (PF_R | PF_W)) {
304 codeset_segment = &codeset->data;
305 } else {
306 LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id %u with flags %X", i, p->p_flags);
307 continue;
308 }
309
310 if (codeset_segment->size != 0) {
311 LOG_ERROR(Loader, "ELF has more than one segment of the same type. Skipping extra segment (id %i)", i);
312 continue;
313 }
314
315 u32 segment_addr = base_addr + p->p_vaddr;
316 u32 aligned_size = (p->p_memsz + 0xFFF) & ~0xFFF;
317
318 codeset_segment->offset = current_image_position;
319 codeset_segment->addr = segment_addr;
320 codeset_segment->size = aligned_size;
321
322 memcpy(&program_image[current_image_position], GetSegmentPtr(i), p->p_filesz);
323 current_image_position += aligned_size;
279 } 324 }
280 } 325 }
326
327 codeset->entrypoint = base_addr + header->e_entry;
328 codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image));
329
281 LOG_DEBUG(Loader, "Done loading."); 330 LOG_DEBUG(Loader, "Done loading.");
331
332 return codeset;
282} 333}
283 334
284SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const { 335SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const {
@@ -340,29 +391,29 @@ ResultStatus AppLoader_ELF::Load() {
340 if (is_loaded) 391 if (is_loaded)
341 return ResultStatus::ErrorAlreadyLoaded; 392 return ResultStatus::ErrorAlreadyLoaded;
342 393
343 if (!file->IsOpen()) 394 if (!file.IsOpen())
344 return ResultStatus::Error; 395 return ResultStatus::Error;
345 396
346 // Reset read pointer in case this file has been read before. 397 // Reset read pointer in case this file has been read before.
347 file->Seek(0, SEEK_SET); 398 file.Seek(0, SEEK_SET);
348 399
349 u32 size = static_cast<u32>(file->GetSize()); 400 size_t size = file.GetSize();
350 std::unique_ptr<u8[]> buffer(new u8[size]); 401 std::unique_ptr<u8[]> buffer(new u8[size]);
351 if (file->ReadBytes(&buffer[0], size) != size) 402 if (file.ReadBytes(&buffer[0], size) != size)
352 return ResultStatus::Error; 403 return ResultStatus::Error;
353 404
354 Kernel::g_current_process = Kernel::Process::Create(filename, 0); 405 ElfReader elf_reader(&buffer[0]);
406 SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
407 codeset->name = filename;
408
409 Kernel::g_current_process = Kernel::Process::Create(std::move(codeset));
355 Kernel::g_current_process->svc_access_mask.set(); 410 Kernel::g_current_process->svc_access_mask.set();
356 Kernel::g_current_process->address_mappings = default_address_mappings; 411 Kernel::g_current_process->address_mappings = default_address_mappings;
357 412
358 // Attach the default resource limit (APPLICATION) to the process 413 // Attach the default resource limit (APPLICATION) to the process
359 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 414 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
360 415
361 ElfReader elf_reader(&buffer[0]); 416 Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE);
362 elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
363 // TODO: Fill application title
364
365 Kernel::g_current_process->Run(elf_reader.GetEntryPoint(), 48, Kernel::DEFAULT_STACK_SIZE);
366 417
367 is_loaded = true; 418 is_loaded = true;
368 return ResultStatus::Success; 419 return ResultStatus::Success;
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 32841606a..c6a5ebe99 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -17,7 +17,7 @@ namespace Loader {
17/// Loads an ELF/AXF file 17/// Loads an ELF/AXF file
18class AppLoader_ELF final : public AppLoader { 18class AppLoader_ELF final : public AppLoader {
19public: 19public:
20 AppLoader_ELF(std::unique_ptr<FileUtil::IOFile>&& file, std::string filename) 20 AppLoader_ELF(FileUtil::IOFile&& file, std::string filename)
21 : AppLoader(std::move(file)), filename(std::move(filename)) { } 21 : AppLoader(std::move(file)), filename(std::move(filename)) { }
22 22
23 /** 23 /**
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 8b14edf00..f5b349a77 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -2,10 +2,12 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <memory>
5#include <string> 6#include <string>
6 7
7#include "common/logging/log.h" 8#include "common/logging/log.h"
8#include "common/make_unique.h" 9#include "common/make_unique.h"
10#include "common/string_util.h"
9 11
10#include "core/file_sys/archive_romfs.h" 12#include "core/file_sys/archive_romfs.h"
11#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
@@ -54,18 +56,18 @@ static FileType IdentifyFile(FileUtil::IOFile& file) {
54static FileType GuessFromExtension(const std::string& extension_) { 56static FileType GuessFromExtension(const std::string& extension_) {
55 std::string extension = Common::ToLower(extension_); 57 std::string extension = Common::ToLower(extension_);
56 58
57 if (extension == ".elf") 59 if (extension == ".elf" || extension == ".axf")
58 return FileType::ELF; 60 return FileType::ELF;
59 else if (extension == ".axf") 61
60 return FileType::ELF; 62 if (extension == ".cci" || extension == ".3ds")
61 else if (extension == ".cxi")
62 return FileType::CXI;
63 else if (extension == ".cci")
64 return FileType::CCI;
65 else if (extension == ".3ds")
66 return FileType::CCI; 63 return FileType::CCI;
67 else if (extension == ".3dsx") 64
65 if (extension == ".cxi")
66 return FileType::CXI;
67
68 if (extension == ".3dsx")
68 return FileType::THREEDSX; 69 return FileType::THREEDSX;
70
69 return FileType::Unknown; 71 return FileType::Unknown;
70} 72}
71 73
@@ -88,8 +90,8 @@ static const char* GetFileTypeString(FileType type) {
88} 90}
89 91
90ResultStatus LoadFile(const std::string& filename) { 92ResultStatus LoadFile(const std::string& filename) {
91 std::unique_ptr<FileUtil::IOFile> file(new FileUtil::IOFile(filename, "rb")); 93 FileUtil::IOFile file(filename, "rb");
92 if (!file->IsOpen()) { 94 if (!file.IsOpen()) {
93 LOG_ERROR(Loader, "Failed to load file %s", filename.c_str()); 95 LOG_ERROR(Loader, "Failed to load file %s", filename.c_str());
94 return ResultStatus::Error; 96 return ResultStatus::Error;
95 } 97 }
@@ -97,7 +99,7 @@ ResultStatus LoadFile(const std::string& filename) {
97 std::string filename_filename, filename_extension; 99 std::string filename_filename, filename_extension;
98 Common::SplitPath(filename, nullptr, &filename_filename, &filename_extension); 100 Common::SplitPath(filename, nullptr, &filename_filename, &filename_extension);
99 101
100 FileType type = IdentifyFile(*file); 102 FileType type = IdentifyFile(file);
101 FileType filename_type = GuessFromExtension(filename_extension); 103 FileType filename_type = GuessFromExtension(filename_extension);
102 104
103 if (type != filename_type) { 105 if (type != filename_type) {
@@ -122,7 +124,7 @@ ResultStatus LoadFile(const std::string& filename) {
122 case FileType::CXI: 124 case FileType::CXI:
123 case FileType::CCI: 125 case FileType::CCI:
124 { 126 {
125 AppLoader_NCCH app_loader(std::move(file)); 127 AppLoader_NCCH app_loader(std::move(file), filename);
126 128
127 // Load application and RomFS 129 // Load application and RomFS
128 if (ResultStatus::Success == app_loader.Load()) { 130 if (ResultStatus::Success == app_loader.Load()) {
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 87e16fb98..a37d3348c 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -4,12 +4,18 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <algorithm>
8#include <initializer_list>
9#include <memory>
10#include <string>
7#include <vector> 11#include <vector>
8 12
9#include "common/common_types.h" 13#include "common/common_types.h"
10#include "common/file_util.h" 14#include "common/file_util.h"
11 15
12#include "core/hle/kernel/process.h" 16namespace Kernel {
17struct AddressMapping;
18}
13 19
14//////////////////////////////////////////////////////////////////////////////////////////////////// 20////////////////////////////////////////////////////////////////////////////////////////////////////
15// Loader namespace 21// Loader namespace
@@ -46,7 +52,7 @@ static inline u32 MakeMagic(char a, char b, char c, char d) {
46/// Interface for loading an application 52/// Interface for loading an application
47class AppLoader : NonCopyable { 53class AppLoader : NonCopyable {
48public: 54public:
49 AppLoader(std::unique_ptr<FileUtil::IOFile>&& file) : file(std::move(file)) { } 55 AppLoader(FileUtil::IOFile&& file) : file(std::move(file)) { }
50 virtual ~AppLoader() { } 56 virtual ~AppLoader() { }
51 57
52 /** 58 /**
@@ -60,7 +66,7 @@ public:
60 * @param buffer Reference to buffer to store data 66 * @param buffer Reference to buffer to store data
61 * @return ResultStatus result of function 67 * @return ResultStatus result of function
62 */ 68 */
63 virtual ResultStatus ReadCode(std::vector<u8>& buffer) const { 69 virtual ResultStatus ReadCode(std::vector<u8>& buffer) {
64 return ResultStatus::ErrorNotImplemented; 70 return ResultStatus::ErrorNotImplemented;
65 } 71 }
66 72
@@ -69,7 +75,7 @@ public:
69 * @param buffer Reference to buffer to store data 75 * @param buffer Reference to buffer to store data
70 * @return ResultStatus result of function 76 * @return ResultStatus result of function
71 */ 77 */
72 virtual ResultStatus ReadIcon(std::vector<u8>& buffer) const { 78 virtual ResultStatus ReadIcon(std::vector<u8>& buffer) {
73 return ResultStatus::ErrorNotImplemented; 79 return ResultStatus::ErrorNotImplemented;
74 } 80 }
75 81
@@ -78,7 +84,7 @@ public:
78 * @param buffer Reference to buffer to store data 84 * @param buffer Reference to buffer to store data
79 * @return ResultStatus result of function 85 * @return ResultStatus result of function
80 */ 86 */
81 virtual ResultStatus ReadBanner(std::vector<u8>& buffer) const { 87 virtual ResultStatus ReadBanner(std::vector<u8>& buffer) {
82 return ResultStatus::ErrorNotImplemented; 88 return ResultStatus::ErrorNotImplemented;
83 } 89 }
84 90
@@ -87,22 +93,25 @@ public:
87 * @param buffer Reference to buffer to store data 93 * @param buffer Reference to buffer to store data
88 * @return ResultStatus result of function 94 * @return ResultStatus result of function
89 */ 95 */
90 virtual ResultStatus ReadLogo(std::vector<u8>& buffer) const { 96 virtual ResultStatus ReadLogo(std::vector<u8>& buffer) {
91 return ResultStatus::ErrorNotImplemented; 97 return ResultStatus::ErrorNotImplemented;
92 } 98 }
93 99
94 /** 100 /**
95 * Get the RomFS of the application 101 * Get the RomFS of the application
96 * @param buffer Reference to buffer to store data 102 * Since the RomFS can be huge, we return a file reference instead of copying to a buffer
103 * @param romfs_file The file containing the RomFS
104 * @param offset The offset the romfs begins on
105 * @param size The size of the romfs
97 * @return ResultStatus result of function 106 * @return ResultStatus result of function
98 */ 107 */
99 virtual ResultStatus ReadRomFS(std::vector<u8>& buffer) const { 108 virtual ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) {
100 return ResultStatus::ErrorNotImplemented; 109 return ResultStatus::ErrorNotImplemented;
101 } 110 }
102 111
103protected: 112protected:
104 std::unique_ptr<FileUtil::IOFile> file; 113 FileUtil::IOFile file;
105 bool is_loaded = false; 114 bool is_loaded = false;
106}; 115};
107 116
108/** 117/**
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 08993c4fa..094d74100 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cstring>
6#include <memory> 7#include <memory>
7 8
8#include "common/logging/log.h" 9#include "common/logging/log.h"
@@ -10,7 +11,7 @@
10#include "common/string_util.h" 11#include "common/string_util.h"
11#include "common/swap.h" 12#include "common/swap.h"
12 13
13#include "core/hle/kernel/kernel.h" 14#include "core/hle/kernel/process.h"
14#include "core/hle/kernel/resource_limit.h" 15#include "core/hle/kernel/resource_limit.h"
15#include "core/loader/ncch.h" 16#include "core/loader/ncch.h"
16#include "core/memory.h" 17#include "core/memory.h"
@@ -116,7 +117,10 @@ FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) {
116 return FileType::Error; 117 return FileType::Error;
117} 118}
118 119
119ResultStatus AppLoader_NCCH::LoadExec() const { 120ResultStatus AppLoader_NCCH::LoadExec() {
121 using Kernel::SharedPtr;
122 using Kernel::CodeSet;
123
120 if (!is_loaded) 124 if (!is_loaded)
121 return ResultStatus::ErrorNotLoaded; 125 return ResultStatus::ErrorNotLoaded;
122 126
@@ -125,7 +129,30 @@ ResultStatus AppLoader_NCCH::LoadExec() const {
125 std::string process_name = Common::StringFromFixedZeroTerminatedBuffer( 129 std::string process_name = Common::StringFromFixedZeroTerminatedBuffer(
126 (const char*)exheader_header.codeset_info.name, 8); 130 (const char*)exheader_header.codeset_info.name, 8);
127 u64 program_id = *reinterpret_cast<u64_le const*>(&ncch_header.program_id[0]); 131 u64 program_id = *reinterpret_cast<u64_le const*>(&ncch_header.program_id[0]);
128 Kernel::g_current_process = Kernel::Process::Create(process_name, program_id); 132
133 SharedPtr<CodeSet> codeset = CodeSet::Create(process_name, program_id);
134
135 codeset->code.offset = 0;
136 codeset->code.addr = exheader_header.codeset_info.text.address;
137 codeset->code.size = exheader_header.codeset_info.text.num_max_pages * Memory::PAGE_SIZE;
138
139 codeset->rodata.offset = codeset->code.offset + codeset->code.size;
140 codeset->rodata.addr = exheader_header.codeset_info.ro.address;
141 codeset->rodata.size = exheader_header.codeset_info.ro.num_max_pages * Memory::PAGE_SIZE;
142
143 // TODO(yuriks): Not sure if the bss size is added to the page-aligned .data size or just
144 // to the regular size. Playing it safe for now.
145 u32 bss_page_size = (exheader_header.codeset_info.bss_size + 0xFFF) & ~0xFFF;
146 code.resize(code.size() + bss_page_size, 0);
147
148 codeset->data.offset = codeset->rodata.offset + codeset->rodata.size;
149 codeset->data.addr = exheader_header.codeset_info.data.address;
150 codeset->data.size = exheader_header.codeset_info.data.num_max_pages * Memory::PAGE_SIZE + bss_page_size;
151
152 codeset->entrypoint = codeset->code.addr;
153 codeset->memory = std::make_shared<std::vector<u8>>(std::move(code));
154
155 Kernel::g_current_process = Kernel::Process::Create(std::move(codeset));
129 156
130 // Attach a resource limit to the process based on the resource limit category 157 // Attach a resource limit to the process based on the resource limit category
131 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory( 158 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(
@@ -136,18 +163,16 @@ ResultStatus AppLoader_NCCH::LoadExec() const {
136 std::copy_n(exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), begin(kernel_caps)); 163 std::copy_n(exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), begin(kernel_caps));
137 Kernel::g_current_process->ParseKernelCaps(kernel_caps.data(), kernel_caps.size()); 164 Kernel::g_current_process->ParseKernelCaps(kernel_caps.data(), kernel_caps.size());
138 165
139 Memory::WriteBlock(entry_point, &code[0], code.size());
140
141 s32 priority = exheader_header.arm11_system_local_caps.priority; 166 s32 priority = exheader_header.arm11_system_local_caps.priority;
142 u32 stack_size = exheader_header.codeset_info.stack_size; 167 u32 stack_size = exheader_header.codeset_info.stack_size;
143 Kernel::g_current_process->Run(entry_point, priority, stack_size); 168 Kernel::g_current_process->Run(priority, stack_size);
144 return ResultStatus::Success; 169 return ResultStatus::Success;
145 } 170 }
146 return ResultStatus::Error; 171 return ResultStatus::Error;
147} 172}
148 173
149ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const { 174ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) {
150 if (!file->IsOpen()) 175 if (!file.IsOpen())
151 return ResultStatus::Error; 176 return ResultStatus::Error;
152 177
153 LOG_DEBUG(Loader, "%d sections:", kMaxSections); 178 LOG_DEBUG(Loader, "%d sections:", kMaxSections);
@@ -161,7 +186,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>&
161 section.offset, section.size, section.name); 186 section.offset, section.size, section.name);
162 187
163 s64 section_offset = (section.offset + exefs_offset + sizeof(ExeFs_Header) + ncch_offset); 188 s64 section_offset = (section.offset + exefs_offset + sizeof(ExeFs_Header) + ncch_offset);
164 file->Seek(section_offset, SEEK_SET); 189 file.Seek(section_offset, SEEK_SET);
165 190
166 if (is_compressed) { 191 if (is_compressed) {
167 // Section is compressed, read compressed .code section... 192 // Section is compressed, read compressed .code section...
@@ -172,7 +197,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>&
172 return ResultStatus::ErrorMemoryAllocationFailed; 197 return ResultStatus::ErrorMemoryAllocationFailed;
173 } 198 }
174 199
175 if (file->ReadBytes(&temp_buffer[0], section.size) != section.size) 200 if (file.ReadBytes(&temp_buffer[0], section.size) != section.size)
176 return ResultStatus::Error; 201 return ResultStatus::Error;
177 202
178 // Decompress .code section... 203 // Decompress .code section...
@@ -183,7 +208,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>&
183 } else { 208 } else {
184 // Section is uncompressed... 209 // Section is uncompressed...
185 buffer.resize(section.size); 210 buffer.resize(section.size);
186 if (file->ReadBytes(&buffer[0], section.size) != section.size) 211 if (file.ReadBytes(&buffer[0], section.size) != section.size)
187 return ResultStatus::Error; 212 return ResultStatus::Error;
188 } 213 }
189 return ResultStatus::Success; 214 return ResultStatus::Success;
@@ -196,21 +221,21 @@ ResultStatus AppLoader_NCCH::Load() {
196 if (is_loaded) 221 if (is_loaded)
197 return ResultStatus::ErrorAlreadyLoaded; 222 return ResultStatus::ErrorAlreadyLoaded;
198 223
199 if (!file->IsOpen()) 224 if (!file.IsOpen())
200 return ResultStatus::Error; 225 return ResultStatus::Error;
201 226
202 // Reset read pointer in case this file has been read before. 227 // Reset read pointer in case this file has been read before.
203 file->Seek(0, SEEK_SET); 228 file.Seek(0, SEEK_SET);
204 229
205 if (file->ReadBytes(&ncch_header, sizeof(NCCH_Header)) != sizeof(NCCH_Header)) 230 if (file.ReadBytes(&ncch_header, sizeof(NCCH_Header)) != sizeof(NCCH_Header))
206 return ResultStatus::Error; 231 return ResultStatus::Error;
207 232
208 // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)... 233 // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)...
209 if (MakeMagic('N', 'C', 'S', 'D') == ncch_header.magic) { 234 if (MakeMagic('N', 'C', 'S', 'D') == ncch_header.magic) {
210 LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!"); 235 LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
211 ncch_offset = 0x4000; 236 ncch_offset = 0x4000;
212 file->Seek(ncch_offset, SEEK_SET); 237 file.Seek(ncch_offset, SEEK_SET);
213 file->ReadBytes(&ncch_header, sizeof(NCCH_Header)); 238 file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
214 } 239 }
215 240
216 // Verify we are loading the correct file type... 241 // Verify we are loading the correct file type...
@@ -219,7 +244,7 @@ ResultStatus AppLoader_NCCH::Load() {
219 244
220 // Read ExHeader... 245 // Read ExHeader...
221 246
222 if (file->ReadBytes(&exheader_header, sizeof(ExHeader_Header)) != sizeof(ExHeader_Header)) 247 if (file.ReadBytes(&exheader_header, sizeof(ExHeader_Header)) != sizeof(ExHeader_Header))
223 return ResultStatus::Error; 248 return ResultStatus::Error;
224 249
225 is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1; 250 is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1;
@@ -239,7 +264,6 @@ ResultStatus AppLoader_NCCH::Load() {
239 LOG_DEBUG(Loader, "Bss size: 0x%08X", bss_size); 264 LOG_DEBUG(Loader, "Bss size: 0x%08X", bss_size);
240 LOG_DEBUG(Loader, "Core version: %d" , core_version); 265 LOG_DEBUG(Loader, "Core version: %d" , core_version);
241 LOG_DEBUG(Loader, "Thread priority: 0x%X" , priority); 266 LOG_DEBUG(Loader, "Thread priority: 0x%X" , priority);
242 LOG_DEBUG(Loader, "Resource limit descriptor: 0x%08X", exheader_header.arm11_system_local_caps.resource_limit_descriptor);
243 LOG_DEBUG(Loader, "Resource limit category: %d" , resource_limit_category); 267 LOG_DEBUG(Loader, "Resource limit category: %d" , resource_limit_category);
244 268
245 // Read ExeFS... 269 // Read ExeFS...
@@ -250,8 +274,8 @@ ResultStatus AppLoader_NCCH::Load() {
250 LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset); 274 LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset);
251 LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size); 275 LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size);
252 276
253 file->Seek(exefs_offset + ncch_offset, SEEK_SET); 277 file.Seek(exefs_offset + ncch_offset, SEEK_SET);
254 if (file->ReadBytes(&exefs_header, sizeof(ExeFs_Header)) != sizeof(ExeFs_Header)) 278 if (file.ReadBytes(&exefs_header, sizeof(ExeFs_Header)) != sizeof(ExeFs_Header))
255 return ResultStatus::Error; 279 return ResultStatus::Error;
256 280
257 is_loaded = true; // Set state to loaded 281 is_loaded = true; // Set state to loaded
@@ -259,24 +283,24 @@ ResultStatus AppLoader_NCCH::Load() {
259 return LoadExec(); // Load the executable into memory for booting 283 return LoadExec(); // Load the executable into memory for booting
260} 284}
261 285
262ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) const { 286ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) {
263 return LoadSectionExeFS(".code", buffer); 287 return LoadSectionExeFS(".code", buffer);
264} 288}
265 289
266ResultStatus AppLoader_NCCH::ReadIcon(std::vector<u8>& buffer) const { 290ResultStatus AppLoader_NCCH::ReadIcon(std::vector<u8>& buffer) {
267 return LoadSectionExeFS("icon", buffer); 291 return LoadSectionExeFS("icon", buffer);
268} 292}
269 293
270ResultStatus AppLoader_NCCH::ReadBanner(std::vector<u8>& buffer) const { 294ResultStatus AppLoader_NCCH::ReadBanner(std::vector<u8>& buffer) {
271 return LoadSectionExeFS("banner", buffer); 295 return LoadSectionExeFS("banner", buffer);
272} 296}
273 297
274ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) const { 298ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) {
275 return LoadSectionExeFS("logo", buffer); 299 return LoadSectionExeFS("logo", buffer);
276} 300}
277 301
278ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const { 302ResultStatus AppLoader_NCCH::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) {
279 if (!file->IsOpen()) 303 if (!file.IsOpen())
280 return ResultStatus::Error; 304 return ResultStatus::Error;
281 305
282 // Check if the NCCH has a RomFS... 306 // Check if the NCCH has a RomFS...
@@ -287,12 +311,17 @@ ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
287 LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset); 311 LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset);
288 LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size); 312 LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size);
289 313
290 buffer.resize(romfs_size); 314 if (file.GetSize () < romfs_offset + romfs_size)
315 return ResultStatus::Error;
291 316
292 file->Seek(romfs_offset, SEEK_SET); 317 // We reopen the file, to allow its position to be independent from file's
293 if (file->ReadBytes(&buffer[0], romfs_size) != romfs_size) 318 romfs_file = std::make_shared<FileUtil::IOFile>(filepath, "rb");
319 if (!romfs_file->IsOpen())
294 return ResultStatus::Error; 320 return ResultStatus::Error;
295 321
322 offset = romfs_offset;
323 size = romfs_size;
324
296 return ResultStatus::Success; 325 return ResultStatus::Success;
297 } 326 }
298 LOG_DEBUG(Loader, "NCCH has no RomFS"); 327 LOG_DEBUG(Loader, "NCCH has no RomFS");
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index 29e39d2c0..b4374a476 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -163,7 +163,8 @@ namespace Loader {
163/// Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI) 163/// Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI)
164class AppLoader_NCCH final : public AppLoader { 164class AppLoader_NCCH final : public AppLoader {
165public: 165public:
166 AppLoader_NCCH(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { } 166 AppLoader_NCCH(FileUtil::IOFile&& file, const std::string& filepath)
167 : AppLoader(std::move(file)), filepath(filepath) { }
167 168
168 /** 169 /**
169 * Returns the type of the file 170 * Returns the type of the file
@@ -183,35 +184,35 @@ public:
183 * @param buffer Reference to buffer to store data 184 * @param buffer Reference to buffer to store data
184 * @return ResultStatus result of function 185 * @return ResultStatus result of function
185 */ 186 */
186 ResultStatus ReadCode(std::vector<u8>& buffer) const override; 187 ResultStatus ReadCode(std::vector<u8>& buffer) override;
187 188
188 /** 189 /**
189 * Get the icon (typically icon section) of the application 190 * Get the icon (typically icon section) of the application
190 * @param buffer Reference to buffer to store data 191 * @param buffer Reference to buffer to store data
191 * @return ResultStatus result of function 192 * @return ResultStatus result of function
192 */ 193 */
193 ResultStatus ReadIcon(std::vector<u8>& buffer) const override; 194 ResultStatus ReadIcon(std::vector<u8>& buffer) override;
194 195
195 /** 196 /**
196 * Get the banner (typically banner section) of the application 197 * Get the banner (typically banner section) of the application
197 * @param buffer Reference to buffer to store data 198 * @param buffer Reference to buffer to store data
198 * @return ResultStatus result of function 199 * @return ResultStatus result of function
199 */ 200 */
200 ResultStatus ReadBanner(std::vector<u8>& buffer) const override; 201 ResultStatus ReadBanner(std::vector<u8>& buffer) override;
201 202
202 /** 203 /**
203 * Get the logo (typically logo section) of the application 204 * Get the logo (typically logo section) of the application
204 * @param buffer Reference to buffer to store data 205 * @param buffer Reference to buffer to store data
205 * @return ResultStatus result of function 206 * @return ResultStatus result of function
206 */ 207 */
207 ResultStatus ReadLogo(std::vector<u8>& buffer) const override; 208 ResultStatus ReadLogo(std::vector<u8>& buffer) override;
208 209
209 /** 210 /**
210 * Get the RomFS of the application 211 * Get the RomFS of the application
211 * @param buffer Reference to buffer to store data 212 * @param buffer Reference to buffer to store data
212 * @return ResultStatus result of function 213 * @return ResultStatus result of function
213 */ 214 */
214 ResultStatus ReadRomFS(std::vector<u8>& buffer) const override; 215 ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) override;
215 216
216private: 217private:
217 218
@@ -221,13 +222,13 @@ private:
221 * @param buffer Vector to read data into 222 * @param buffer Vector to read data into
222 * @return ResultStatus result of function 223 * @return ResultStatus result of function
223 */ 224 */
224 ResultStatus LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const; 225 ResultStatus LoadSectionExeFS(const char* name, std::vector<u8>& buffer);
225 226
226 /** 227 /**
227 * Loads .code section into memory for booting 228 * Loads .code section into memory for booting
228 * @return ResultStatus result of function 229 * @return ResultStatus result of function
229 */ 230 */
230 ResultStatus LoadExec() const; 231 ResultStatus LoadExec();
231 232
232 bool is_compressed = false; 233 bool is_compressed = false;
233 234
@@ -244,6 +245,8 @@ private:
244 NCCH_Header ncch_header; 245 NCCH_Header ncch_header;
245 ExeFs_Header exefs_header; 246 ExeFs_Header exefs_header;
246 ExHeader_Header exheader_header; 247 ExHeader_Header exheader_header;
248
249 std::string filepath;
247}; 250};
248 251
249} // namespace Loader 252} // namespace Loader
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp
index bf814b945..cbe993fbe 100644
--- a/src/core/mem_map.cpp
+++ b/src/core/mem_map.cpp
@@ -3,13 +3,14 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map> 5#include <map>
6#include <memory>
7#include <utility>
8#include <vector>
6 9
7#include "common/common_types.h" 10#include "common/common_types.h"
8#include "common/logging/log.h" 11#include "common/logging/log.h"
9 12
10#include "core/hle/config_mem.h" 13#include "core/hle/config_mem.h"
11#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/shared_memory.h"
13#include "core/hle/kernel/vm_manager.h" 14#include "core/hle/kernel/vm_manager.h"
14#include "core/hle/result.h" 15#include "core/hle/result.h"
15#include "core/hle/shared_page.h" 16#include "core/hle/shared_page.h"
@@ -31,7 +32,6 @@ struct MemoryArea {
31 32
32// We don't declare the IO regions in here since its handled by other means. 33// We don't declare the IO regions in here since its handled by other means.
33static MemoryArea memory_areas[] = { 34static MemoryArea memory_areas[] = {
34 {PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE, "Process Image"}, // ExeFS:/.code is loaded here
35 {HEAP_VADDR, HEAP_SIZE, "Heap"}, // Application heap (main memory) 35 {HEAP_VADDR, HEAP_SIZE, "Heap"}, // Application heap (main memory)
36 {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory 36 {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory
37 {LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE, "Linear Heap"}, // Linear heap (main memory) 37 {LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE, "Linear Heap"}, // Linear heap (main memory)
@@ -131,13 +131,13 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) {
131 return addr | 0x80000000; 131 return addr | 0x80000000;
132} 132}
133 133
134// TODO(yuriks): Move this into Process
135static Kernel::VMManager address_space;
136
137void Init() { 134void Init() {
138 using namespace Kernel;
139
140 InitMemoryMap(); 135 InitMemoryMap();
136 LOG_DEBUG(HW_Memory, "initialized OK");
137}
138
139void InitLegacyAddressSpace(Kernel::VMManager& address_space) {
140 using namespace Kernel;
141 141
142 for (MemoryArea& area : memory_areas) { 142 for (MemoryArea& area : memory_areas) {
143 auto block = std::make_shared<std::vector<u8>>(area.size); 143 auto block = std::make_shared<std::vector<u8>>(area.size);
@@ -151,14 +151,11 @@ void Init() {
151 auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR, 151 auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR,
152 (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom(); 152 (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom();
153 address_space.Reprotect(shared_page_vma, VMAPermission::Read); 153 address_space.Reprotect(shared_page_vma, VMAPermission::Read);
154
155 LOG_DEBUG(HW_Memory, "initialized OK");
156} 154}
157 155
158void Shutdown() { 156void Shutdown() {
159 heap_map.clear(); 157 heap_map.clear();
160 heap_linear_map.clear(); 158 heap_linear_map.clear();
161 address_space.Reset();
162 159
163 LOG_DEBUG(HW_Memory, "shutdown OK"); 160 LOG_DEBUG(HW_Memory, "shutdown OK");
164} 161}
diff --git a/src/core/mem_map.h b/src/core/mem_map.h
index ba50914a8..229ef82c5 100644
--- a/src/core/mem_map.h
+++ b/src/core/mem_map.h
@@ -6,9 +6,14 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8 8
9namespace Kernel {
10class VMManager;
11}
12
9namespace Memory { 13namespace Memory {
10 14
11void Init(); 15void Init();
16void InitLegacyAddressSpace(Kernel::VMManager& address_space);
12void Shutdown(); 17void Shutdown();
13 18
14/** 19/**
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 28844a915..1f66bb27d 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -9,9 +9,6 @@
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/swap.h" 10#include "common/swap.h"
11 11
12#include "core/hle/config_mem.h"
13#include "core/hle/shared_page.h"
14#include "core/hw/hw.h"
15#include "core/mem_map.h" 12#include "core/mem_map.h"
16#include "core/memory.h" 13#include "core/memory.h"
17#include "core/memory_setup.h" 14#include "core/memory_setup.h"
@@ -62,14 +59,12 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) {
62 while (base != end) { 59 while (base != end) {
63 ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base); 60 ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base);
64 61
65 if (current_page_table->attributes[base] != PageType::Unmapped && type != PageType::Unmapped) {
66 LOG_ERROR(HW_Memory, "overlapping memory ranges at %08X", base * PAGE_SIZE);
67 }
68 current_page_table->attributes[base] = type; 62 current_page_table->attributes[base] = type;
69 current_page_table->pointers[base] = memory; 63 current_page_table->pointers[base] = memory;
70 64
71 base += 1; 65 base += 1;
72 memory += PAGE_SIZE; 66 if (memory != nullptr)
67 memory += PAGE_SIZE;
73 } 68 }
74} 69}
75 70
diff --git a/src/core/memory.h b/src/core/memory.h
index 0b8ff9ec4..418609de0 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8 10
9namespace Memory { 11namespace Memory {
diff --git a/src/core/settings.h b/src/core/settings.h
index 5a70d157a..2775ee257 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -5,34 +5,42 @@
5#pragma once 5#pragma once
6 6
7#include <string> 7#include <string>
8#include <array>
8 9
9namespace Settings { 10namespace Settings {
10 11
12namespace NativeInput {
13enum Values {
14 A, B, X, Y,
15 L, R, ZL, ZR,
16 START, SELECT, HOME,
17 DUP, DDOWN, DLEFT, DRIGHT,
18 SUP, SDOWN, SLEFT, SRIGHT,
19 CUP, CDOWN, CLEFT, CRIGHT,
20 NUM_INPUTS
21};
22static const std::array<const char*, NUM_INPUTS> Mapping = {
23 "pad_a", "pad_b", "pad_x", "pad_y",
24 "pad_l", "pad_r", "pad_zl", "pad_zr",
25 "pad_start", "pad_select", "pad_home",
26 "pad_dup", "pad_ddown", "pad_dleft", "pad_dright",
27 "pad_sup", "pad_sdown", "pad_sleft", "pad_sright",
28 "pad_cup", "pad_cdown", "pad_cleft", "pad_cright"
29};
30static const std::array<Values, NUM_INPUTS> All = {
31 A, B, X, Y,
32 L, R, ZL, ZR,
33 START, SELECT, HOME,
34 DUP, DDOWN, DLEFT, DRIGHT,
35 SUP, SDOWN, SLEFT, SRIGHT,
36 CUP, CDOWN, CLEFT, CRIGHT
37};
38}
39
40
11struct Values { 41struct Values {
12 // Controls 42 // Controls
13 int pad_a_key; 43 std::array<int, NativeInput::NUM_INPUTS> input_mappings;
14 int pad_b_key;
15 int pad_x_key;
16 int pad_y_key;
17 int pad_l_key;
18 int pad_r_key;
19 int pad_zl_key;
20 int pad_zr_key;
21 int pad_start_key;
22 int pad_select_key;
23 int pad_home_key;
24 int pad_dup_key;
25 int pad_ddown_key;
26 int pad_dleft_key;
27 int pad_dright_key;
28 int pad_sup_key;
29 int pad_sdown_key;
30 int pad_sleft_key;
31 int pad_sright_key;
32 int pad_cup_key;
33 int pad_cdown_key;
34 int pad_cleft_key;
35 int pad_cright_key;
36 44
37 // Core 45 // Core
38 int frame_skip; 46 int frame_skip;
diff --git a/src/core/tracer/citrace.h b/src/core/tracer/citrace.h
new file mode 100644
index 000000000..5deb6ce9e
--- /dev/null
+++ b/src/core/tracer/citrace.h
@@ -0,0 +1,101 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstdint>
8
9namespace CiTrace {
10
11// NOTE: Things are stored in little-endian
12
13#pragma pack(1)
14
15struct CTHeader {
16 static const char* ExpectedMagicWord() {
17 return "CiTr";
18 }
19
20 static uint32_t ExpectedVersion() {
21 return 1;
22 }
23
24 char magic[4];
25 uint32_t version;
26 uint32_t header_size;
27
28 struct {
29 // NOTE: Register range sizes are technically hardware-constants, but the actual limits
30 // aren't known. Hence we store the presumed limits along the offsets.
31 // Sizes are given in uint32_t units.
32 uint32_t gpu_registers;
33 uint32_t gpu_registers_size;
34 uint32_t lcd_registers;
35 uint32_t lcd_registers_size;
36 uint32_t pica_registers;
37 uint32_t pica_registers_size;
38 uint32_t default_attributes;
39 uint32_t default_attributes_size;
40 uint32_t vs_program_binary;
41 uint32_t vs_program_binary_size;
42 uint32_t vs_swizzle_data;
43 uint32_t vs_swizzle_data_size;
44 uint32_t vs_float_uniforms;
45 uint32_t vs_float_uniforms_size;
46 uint32_t gs_program_binary;
47 uint32_t gs_program_binary_size;
48 uint32_t gs_swizzle_data;
49 uint32_t gs_swizzle_data_size;
50 uint32_t gs_float_uniforms;
51 uint32_t gs_float_uniforms_size;
52
53 // Other things we might want to store here:
54 // - Initial framebuffer data, maybe even a full copy of FCRAM/VRAM
55 // - Lookup tables for fragment lighting
56 // - Lookup tables for procedural textures
57 } initial_state_offsets;
58
59 uint32_t stream_offset;
60 uint32_t stream_size;
61};
62
63enum CTStreamElementType : uint32_t {
64 FrameMarker = 0xE1,
65 MemoryLoad = 0xE2,
66 RegisterWrite = 0xE3,
67};
68
69struct CTMemoryLoad {
70 uint32_t file_offset;
71 uint32_t size;
72 uint32_t physical_address;
73 uint32_t pad;
74};
75
76struct CTRegisterWrite {
77 uint32_t physical_address;
78
79 enum : uint32_t {
80 SIZE_8 = 0xD1,
81 SIZE_16 = 0xD2,
82 SIZE_32 = 0xD3,
83 SIZE_64 = 0xD4
84 } size;
85
86 // TODO: Make it clearer which bits of this member are used for sizes other than 32 bits
87 uint64_t value;
88};
89
90struct CTStreamElement {
91 CTStreamElementType type;
92
93 union {
94 CTMemoryLoad memory_load;
95 CTRegisterWrite register_write;
96 };
97};
98
99#pragma pack()
100
101}
diff --git a/src/core/tracer/recorder.cpp b/src/core/tracer/recorder.cpp
new file mode 100644
index 000000000..656706c0c
--- /dev/null
+++ b/src/core/tracer/recorder.cpp
@@ -0,0 +1,187 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6
7#include "common/assert.h"
8#include "common/file_util.h"
9#include "common/logging/log.h"
10
11#include "recorder.h"
12
13namespace CiTrace {
14
15Recorder::Recorder(const InitialState& initial_state) : initial_state(initial_state) {
16
17}
18
19void Recorder::Finish(const std::string& filename) {
20 // Setup CiTrace header
21 CTHeader header;
22 std::memcpy(header.magic, CTHeader::ExpectedMagicWord(), 4);
23 header.version = CTHeader::ExpectedVersion();
24 header.header_size = sizeof(CTHeader);
25
26 // Calculate file offsets
27 auto& initial = header.initial_state_offsets;
28
29 initial.gpu_registers_size = initial_state.gpu_registers.size();
30 initial.lcd_registers_size = initial_state.lcd_registers.size();
31 initial.pica_registers_size = initial_state.pica_registers.size();
32 initial.default_attributes_size = initial_state.default_attributes.size();
33 initial.vs_program_binary_size = initial_state.vs_program_binary.size();
34 initial.vs_swizzle_data_size = initial_state.vs_swizzle_data.size();
35 initial.vs_float_uniforms_size = initial_state.vs_float_uniforms.size();
36 initial.gs_program_binary_size = initial_state.gs_program_binary.size();
37 initial.gs_swizzle_data_size = initial_state.gs_swizzle_data.size();
38 initial.gs_float_uniforms_size = initial_state.gs_float_uniforms.size();
39 header.stream_size = stream.size();
40
41 initial.gpu_registers = sizeof(header);
42 initial.lcd_registers = initial.gpu_registers + initial.gpu_registers_size * sizeof(u32);
43 initial.pica_registers = initial.lcd_registers + initial.lcd_registers_size * sizeof(u32);;
44 initial.default_attributes = initial.pica_registers + initial.pica_registers_size * sizeof(u32);
45 initial.vs_program_binary = initial.default_attributes + initial.default_attributes_size * sizeof(u32);
46 initial.vs_swizzle_data = initial.vs_program_binary + initial.vs_program_binary_size * sizeof(u32);
47 initial.vs_float_uniforms = initial.vs_swizzle_data + initial.vs_swizzle_data_size * sizeof(u32);
48 initial.gs_program_binary = initial.vs_float_uniforms + initial.vs_float_uniforms_size * sizeof(u32);
49 initial.gs_swizzle_data = initial.gs_program_binary + initial.gs_program_binary_size * sizeof(u32);
50 initial.gs_float_uniforms = initial.gs_swizzle_data + initial.gs_swizzle_data_size * sizeof(u32);
51 header.stream_offset = initial.gs_float_uniforms + initial.gs_float_uniforms_size * sizeof(u32);
52
53 // Iterate through stream elements, update relevant stream element data
54 for (auto& stream_element : stream) {
55 switch (stream_element.data.type) {
56 case MemoryLoad:
57 {
58 auto& file_offset = memory_regions[stream_element.hash];
59 if (!stream_element.uses_existing_data) {
60 file_offset = header.stream_offset;
61 }
62 stream_element.data.memory_load.file_offset = file_offset;
63 break;
64 }
65
66 default:
67 // Other commands don't use any extra data
68 DEBUG_ASSERT(stream_element.extra_data.size() == 0);
69 break;
70 }
71 header.stream_offset += stream_element.extra_data.size();
72 }
73
74 try {
75 // Open file and write header
76 FileUtil::IOFile file(filename, "wb");
77 size_t written = file.WriteObject(header);
78 if (written != 1 || file.Tell() != initial.gpu_registers)
79 throw "Failed to write header";
80
81 // Write initial state
82 written = file.WriteArray(initial_state.gpu_registers.data(), initial_state.gpu_registers.size());
83 if (written != initial_state.gpu_registers.size() || file.Tell() != initial.lcd_registers)
84 throw "Failed to write GPU registers";
85
86 written = file.WriteArray(initial_state.lcd_registers.data(), initial_state.lcd_registers.size());
87 if (written != initial_state.lcd_registers.size() || file.Tell() != initial.pica_registers)
88 throw "Failed to write LCD registers";
89
90 written = file.WriteArray(initial_state.pica_registers.data(), initial_state.pica_registers.size());
91 if (written != initial_state.pica_registers.size() || file.Tell() != initial.default_attributes)
92 throw "Failed to write Pica registers";
93
94 written = file.WriteArray(initial_state.default_attributes.data(), initial_state.default_attributes.size());
95 if (written != initial_state.default_attributes.size() || file.Tell() != initial.vs_program_binary)
96 throw "Failed to write default vertex attributes";
97
98 written = file.WriteArray(initial_state.vs_program_binary.data(), initial_state.vs_program_binary.size());
99 if (written != initial_state.vs_program_binary.size() || file.Tell() != initial.vs_swizzle_data)
100 throw "Failed to write vertex shader program binary";
101
102 written = file.WriteArray(initial_state.vs_swizzle_data.data(), initial_state.vs_swizzle_data.size());
103 if (written != initial_state.vs_swizzle_data.size() || file.Tell() != initial.vs_float_uniforms)
104 throw "Failed to write vertex shader swizzle data";
105
106 written = file.WriteArray(initial_state.vs_float_uniforms.data(), initial_state.vs_float_uniforms.size());
107 if (written != initial_state.vs_float_uniforms.size() || file.Tell() != initial.gs_program_binary)
108 throw "Failed to write vertex shader float uniforms";
109
110 written = file.WriteArray(initial_state.gs_program_binary.data(), initial_state.gs_program_binary.size());
111 if (written != initial_state.gs_program_binary.size() || file.Tell() != initial.gs_swizzle_data)
112 throw "Failed to write geomtry shader program binary";
113
114 written = file.WriteArray(initial_state.gs_swizzle_data.data(), initial_state.gs_swizzle_data.size());
115 if (written != initial_state.gs_swizzle_data.size() || file.Tell() != initial.gs_float_uniforms)
116 throw "Failed to write geometry shader swizzle data";
117
118 written = file.WriteArray(initial_state.gs_float_uniforms.data(), initial_state.gs_float_uniforms.size());
119 if (written != initial_state.gs_float_uniforms.size() || file.Tell() != initial.gs_float_uniforms + sizeof(u32) * initial.gs_float_uniforms_size)
120 throw "Failed to write geometry shader float uniforms";
121
122 // Iterate through stream elements, write "extra data"
123 for (const auto& stream_element : stream) {
124 if (stream_element.extra_data.size() == 0)
125 continue;
126
127 written = file.WriteBytes(stream_element.extra_data.data(), stream_element.extra_data.size());
128 if (written != stream_element.extra_data.size())
129 throw "Failed to write extra data";
130 }
131
132 if (file.Tell() != header.stream_offset)
133 throw "Unexpected end of extra data";
134
135 // Write actual stream elements
136 for (const auto& stream_element : stream) {
137 if (1 != file.WriteObject(stream_element.data))
138 throw "Failed to write stream element";
139 }
140 } catch(const char* str) {
141 LOG_ERROR(HW_GPU, "Writing CiTrace file failed: %s", str);
142 }
143}
144
145void Recorder::FrameFinished() {
146 stream.push_back( { FrameMarker } );
147}
148
149void Recorder::MemoryAccessed(const u8* data, u32 size, u32 physical_address) {
150 StreamElement element = { MemoryLoad };
151 element.data.memory_load.size = size;
152 element.data.memory_load.physical_address = physical_address;
153
154 // Compute hash over given memory region to check if the contents are already stored internally
155 boost::crc_32_type result;
156 result.process_bytes(data, size);
157 element.hash = result.checksum();
158
159 element.uses_existing_data = (memory_regions.find(element.hash) != memory_regions.end());
160 if (!element.uses_existing_data) {
161 element.extra_data.resize(size);
162 memcpy(element.extra_data.data(), data, size);
163 memory_regions.insert({element.hash, 0}); // file offset will be initialized in Finish()
164 }
165
166 stream.push_back(element);
167}
168
169template<typename T>
170void Recorder::RegisterWritten(u32 physical_address, T value) {
171 StreamElement element = { RegisterWrite };
172 element.data.register_write.size = (sizeof(T) == 1) ? CTRegisterWrite::SIZE_8
173 : (sizeof(T) == 2) ? CTRegisterWrite::SIZE_16
174 : (sizeof(T) == 4) ? CTRegisterWrite::SIZE_32
175 : CTRegisterWrite::SIZE_64;
176 element.data.register_write.physical_address = physical_address;
177 element.data.register_write.value = value;
178
179 stream.push_back(element);
180}
181
182template void Recorder::RegisterWritten(u32,u8);
183template void Recorder::RegisterWritten(u32,u16);
184template void Recorder::RegisterWritten(u32,u32);
185template void Recorder::RegisterWritten(u32,u64);
186
187}
diff --git a/src/core/tracer/recorder.h b/src/core/tracer/recorder.h
new file mode 100644
index 000000000..6e4b70015
--- /dev/null
+++ b/src/core/tracer/recorder.h
@@ -0,0 +1,90 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <unordered_map>
8#include <vector>
9
10#include <boost/crc.hpp>
11
12#include "common/common_types.h"
13
14#include "citrace.h"
15
16namespace CiTrace {
17
18class Recorder {
19public:
20 struct InitialState {
21 std::vector<u32> gpu_registers;
22 std::vector<u32> lcd_registers;
23 std::vector<u32> pica_registers;
24 std::vector<u32> default_attributes;
25 std::vector<u32> vs_program_binary;
26 std::vector<u32> vs_swizzle_data;
27 std::vector<u32> vs_float_uniforms;
28 std::vector<u32> gs_program_binary;
29 std::vector<u32> gs_swizzle_data;
30 std::vector<u32> gs_float_uniforms;
31 };
32
33 /**
34 * Recorder constructor
35 * @param default_attributes Pointer to an array of 32-bit-aligned 24-bit floating point values.
36 * @param vs_float_uniforms Pointer to an array of 32-bit-aligned 24-bit floating point values.
37 */
38 Recorder(const InitialState& initial_state);
39
40 /// Finish recording of this Citrace and save it using the given filename.
41 void Finish(const std::string& filename);
42
43 /// Mark end of a frame
44 void FrameFinished();
45
46 /**
47 * Store a copy of the given memory range in the recording.
48 * @note Use this whenever the GPU is about to access a particular memory region.
49 * @note The implementation will make sure to minimize redundant memory updates.
50 */
51 void MemoryAccessed(const u8* data, u32 size, u32 physical_address);
52
53 /**
54 * Record a register write.
55 * @note Use this whenever a GPU-related MMIO register has been written to.
56 */
57 template<typename T>
58 void RegisterWritten(u32 physical_address, T value);
59
60private:
61 // Initial state of recording start
62 InitialState initial_state;
63
64 // Command stream
65 struct StreamElement {
66 CTStreamElement data;
67
68 /**
69 * Extra data to store along "core" data.
70 * This is e.g. used for data used in MemoryUpdates.
71 */
72 std::vector<u8> extra_data;
73
74 /// Optional CRC hash (e.g. for hashing memory regions)
75 boost::crc_32_type::value_type hash;
76
77 /// If true, refer to data already written to the output file instead of extra_data
78 bool uses_existing_data;
79 };
80
81 std::vector<StreamElement> stream;
82
83 /**
84 * Internal cache which maps hashes of memory contents to file offsets at which those memory
85 * contents are stored.
86 */
87 std::unordered_map<boost::crc_32_type::value_type /*hash*/, u32 /*file_offset*/> memory_regions;
88};
89
90} // namespace
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 5c7f4ae18..162108301 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -2,7 +2,6 @@ set(SRCS
2 renderer_opengl/generated/gl_3_2_core.c 2 renderer_opengl/generated/gl_3_2_core.c
3 renderer_opengl/gl_rasterizer.cpp 3 renderer_opengl/gl_rasterizer.cpp
4 renderer_opengl/gl_rasterizer_cache.cpp 4 renderer_opengl/gl_rasterizer_cache.cpp
5 renderer_opengl/gl_resource_manager.cpp
6 renderer_opengl/gl_shader_util.cpp 5 renderer_opengl/gl_shader_util.cpp
7 renderer_opengl/gl_state.cpp 6 renderer_opengl/gl_state.cpp
8 renderer_opengl/renderer_opengl.cpp 7 renderer_opengl/renderer_opengl.cpp
diff --git a/src/video_core/clipper.cpp b/src/video_core/clipper.cpp
index 943f3eb35..558b49d60 100644
--- a/src/video_core/clipper.cpp
+++ b/src/video_core/clipper.cpp
@@ -94,7 +94,7 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) {
94 // NOTE: We clip against a w=epsilon plane to guarantee that the output has a positive w value. 94 // NOTE: We clip against a w=epsilon plane to guarantee that the output has a positive w value.
95 // TODO: Not sure if this is a valid approach. Also should probably instead use the smallest 95 // TODO: Not sure if this is a valid approach. Also should probably instead use the smallest
96 // epsilon possible within float24 accuracy. 96 // epsilon possible within float24 accuracy.
97 static const float24 EPSILON = float24::FromFloat32(0.00001); 97 static const float24 EPSILON = float24::FromFloat32(0.00001f);
98 static const float24 f0 = float24::FromFloat32(0.0); 98 static const float24 f0 = float24::FromFloat32(0.0);
99 static const float24 f1 = float24::FromFloat32(1.0); 99 static const float24 f1 = float24::FromFloat32(1.0);
100 static const std::array<ClippingEdge, 7> clipping_edges = {{ 100 static const std::array<ClippingEdge, 7> clipping_edges = {{
@@ -153,7 +153,7 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) {
153 "Triangle %lu/%lu at position (%.3f, %.3f, %.3f, %.3f), " 153 "Triangle %lu/%lu at position (%.3f, %.3f, %.3f, %.3f), "
154 "(%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and " 154 "(%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and "
155 "screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)", 155 "screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)",
156 i, output_list->size(), 156 i + 1, output_list->size() - 2,
157 vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(), 157 vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(),
158 vtx1.pos.x.ToFloat32(), vtx1.pos.y.ToFloat32(), vtx1.pos.z.ToFloat32(), vtx1.pos.w.ToFloat32(), 158 vtx1.pos.x.ToFloat32(), vtx1.pos.y.ToFloat32(), vtx1.pos.z.ToFloat32(), vtx1.pos.w.ToFloat32(),
159 vtx2.pos.x.ToFloat32(), vtx2.pos.y.ToFloat32(), vtx2.pos.z.ToFloat32(), vtx2.pos.w.ToFloat32(), 159 vtx2.pos.x.ToFloat32(), vtx2.pos.y.ToFloat32(), vtx2.pos.z.ToFloat32(), vtx2.pos.w.ToFloat32(),
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index b46fadd9f..ef9584abd 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -6,18 +6,20 @@
6 6
7#include "common/profiler.h" 7#include "common/profiler.h"
8 8
9#include "core/hle/service/gsp_gpu.h"
10#include "core/hw/gpu.h"
11#include "core/settings.h"
12
13#include "debug_utils/debug_utils.h"
14
9#include "clipper.h" 15#include "clipper.h"
10#include "command_processor.h" 16#include "command_processor.h"
11#include "math.h" 17#include "math.h"
12#include "pica.h" 18#include "pica.h"
13#include "primitive_assembly.h" 19#include "primitive_assembly.h"
20#include "renderer_base.h"
14#include "vertex_shader.h" 21#include "vertex_shader.h"
15#include "video_core.h" 22#include "video_core.h"
16#include "core/hle/service/gsp_gpu.h"
17#include "core/hw/gpu.h"
18#include "core/settings.h"
19
20#include "debug_utils/debug_utils.h"
21 23
22namespace Pica { 24namespace Pica {
23 25
@@ -43,12 +45,12 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
43 if (GPU::g_skip_frame && id != PICA_REG_INDEX(trigger_irq)) 45 if (GPU::g_skip_frame && id != PICA_REG_INDEX(trigger_irq))
44 return; 46 return;
45 47
46 // TODO: Figure out how register masking acts on e.g. vs_uniform_setup.set_value 48 // TODO: Figure out how register masking acts on e.g. vs.uniform_setup.set_value
47 u32 old_value = regs[id]; 49 u32 old_value = regs[id];
48 regs[id] = (old_value & ~mask) | (value & mask); 50 regs[id] = (old_value & ~mask) | (value & mask);
49 51
50 if (g_debug_context) 52 if (g_debug_context)
51 g_debug_context->OnEvent(DebugContext::Event::CommandLoaded, reinterpret_cast<void*>(&id)); 53 g_debug_context->OnEvent(DebugContext::Event::PicaCommandLoaded, reinterpret_cast<void*>(&id));
52 54
53 DebugUtils::OnPicaRegWrite(id, regs[id]); 55 DebugUtils::OnPicaRegWrite(id, regs[id]);
54 56
@@ -58,10 +60,50 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
58 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D); 60 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D);
59 break; 61 break;
60 62
63 // Load default vertex input attributes
64 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233):
65 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234):
66 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[2], 0x235):
67 {
68 // TODO: Does actual hardware indeed keep an intermediate buffer or does
69 // it directly write the values?
70 default_attr_write_buffer[default_attr_counter++] = value;
71
72 // Default attributes are written in a packed format such that four float24 values are encoded in
73 // three 32-bit numbers. We write to internal memory once a full such vector is
74 // written.
75 if (default_attr_counter >= 3) {
76 default_attr_counter = 0;
77
78 auto& setup = regs.vs_default_attributes_setup;
79
80 if (setup.index >= 16) {
81 LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index);
82 break;
83 }
84
85 Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index];
86
87 // NOTE: The destination component order indeed is "backwards"
88 attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8);
89 attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF));
90 attribute.y = float24::FromRawFloat24(((default_attr_write_buffer[1] & 0xFFFF) << 8) | ((default_attr_write_buffer[2] >> 24) & 0xFF));
91 attribute.x = float24::FromRawFloat24(default_attr_write_buffer[2] & 0xFFFFFF);
92
93 LOG_TRACE(HW_GPU, "Set default VS attribute %x to (%f %f %f %f)", (int)setup.index,
94 attribute.x.ToFloat32(), attribute.y.ToFloat32(), attribute.z.ToFloat32(),
95 attribute.w.ToFloat32());
96
97 // TODO: Verify that this actually modifies the register!
98 setup.index = setup.index + 1;
99 }
100 break;
101 }
102
61 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c): 103 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c):
62 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d): 104 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d):
63 { 105 {
64 unsigned index = id - PICA_REG_INDEX(command_buffer.trigger[0]); 106 unsigned index = static_cast<unsigned>(id - PICA_REG_INDEX(command_buffer.trigger[0]));
65 u32* head_ptr = (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index)); 107 u32* head_ptr = (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index));
66 g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr; 108 g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr;
67 g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32); 109 g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32);
@@ -74,7 +116,9 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
74 { 116 {
75 Common::Profiling::ScopeTimer scope_timer(category_drawing); 117 Common::Profiling::ScopeTimer scope_timer(category_drawing);
76 118
119#if PICA_LOG_TEV
77 DebugUtils::DumpTevStageConfig(regs.GetTevStages()); 120 DebugUtils::DumpTevStageConfig(regs.GetTevStages());
121#endif
78 122
79 if (g_debug_context) 123 if (g_debug_context)
80 g_debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr); 124 g_debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr);
@@ -117,9 +161,50 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
117 const u16* index_address_16 = (u16*)index_address_8; 161 const u16* index_address_16 = (u16*)index_address_8;
118 bool index_u16 = index_info.format != 0; 162 bool index_u16 = index_info.format != 0;
119 163
164#if PICA_DUMP_GEOMETRY
120 DebugUtils::GeometryDumper geometry_dumper; 165 DebugUtils::GeometryDumper geometry_dumper;
121 PrimitiveAssembler<VertexShader::OutputVertex> primitive_assembler(regs.triangle_topology.Value());
122 PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value()); 166 PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value());
167#endif
168 PrimitiveAssembler<VertexShader::OutputVertex> primitive_assembler(regs.triangle_topology.Value());
169
170 if (g_debug_context) {
171 for (int i = 0; i < 3; ++i) {
172 const auto texture = regs.GetTextures()[i];
173 if (!texture.enabled)
174 continue;
175
176 u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
177 if (g_debug_context && Pica::g_debug_context->recorder)
178 g_debug_context->recorder->MemoryAccessed(texture_data, Pica::Regs::NibblesPerPixel(texture.format) * texture.config.width / 2 * texture.config.height, texture.config.GetPhysicalAddress());
179 }
180 }
181
182 class {
183 /// Combine overlapping and close ranges
184 void SimplifyRanges() {
185 for (auto it = ranges.begin(); it != ranges.end(); ++it) {
186 // NOTE: We add 32 to the range end address to make sure "close" ranges are combined, too
187 auto it2 = std::next(it);
188 while (it2 != ranges.end() && it->first + it->second + 32 >= it2->first) {
189 it->second = std::max(it->second, it2->first + it2->second - it->first);
190 it2 = ranges.erase(it2);
191 }
192 }
193 }
194
195 public:
196 /// Record a particular memory access in the list
197 void AddAccess(u32 paddr, u32 size) {
198 // Create new range or extend existing one
199 ranges[paddr] = std::max(ranges[paddr], size);
200
201 // Simplify ranges...
202 SimplifyRanges();
203 }
204
205 /// Map of accessed ranges (mapping start address to range size)
206 std::map<u32, u32> ranges;
207 } memory_accesses;
123 208
124 for (unsigned int index = 0; index < regs.num_vertices; ++index) 209 for (unsigned int index = 0; index < regs.num_vertices; ++index)
125 { 210 {
@@ -127,6 +212,10 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
127 212
128 if (is_indexed) { 213 if (is_indexed) {
129 // TODO: Implement some sort of vertex cache! 214 // TODO: Implement some sort of vertex cache!
215 if (g_debug_context && Pica::g_debug_context->recorder) {
216 int size = index_u16 ? 2 : 1;
217 memory_accesses.AddAccess(base_address + index_info.offset + size * index, size);
218 }
130 } 219 }
131 220
132 // Initialize data for the current vertex 221 // Initialize data for the current vertex
@@ -149,7 +238,14 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
149 238
150 // Load per-vertex data from the loader arrays 239 // Load per-vertex data from the loader arrays
151 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 240 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
152 const u8* srcdata = Memory::GetPhysicalPointer(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]); 241 u32 source_addr = vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i];
242 const u8* srcdata = Memory::GetPhysicalPointer(source_addr);
243
244 if (g_debug_context && Pica::g_debug_context->recorder) {
245 memory_accesses.AddAccess(source_addr,
246 (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT) ? 4
247 : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? 2 : 1);
248 }
153 249
154 const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata : 250 const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata :
155 (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata : 251 (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata :
@@ -179,6 +275,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
179 if (g_debug_context) 275 if (g_debug_context)
180 g_debug_context->OnEvent(DebugContext::Event::VertexLoaded, (void*)&input); 276 g_debug_context->OnEvent(DebugContext::Event::VertexLoaded, (void*)&input);
181 277
278#if PICA_DUMP_GEOMETRY
182 // NOTE: When dumping geometry, we simply assume that the first input attribute 279 // NOTE: When dumping geometry, we simply assume that the first input attribute
183 // corresponds to the position for now. 280 // corresponds to the position for now.
184 DebugUtils::GeometryDumper::Vertex dumped_vertex = { 281 DebugUtils::GeometryDumper::Vertex dumped_vertex = {
@@ -188,9 +285,10 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
188 dumping_primitive_assembler.SubmitVertex(dumped_vertex, 285 dumping_primitive_assembler.SubmitVertex(dumped_vertex,
189 std::bind(&DebugUtils::GeometryDumper::AddTriangle, 286 std::bind(&DebugUtils::GeometryDumper::AddTriangle,
190 &geometry_dumper, _1, _2, _3)); 287 &geometry_dumper, _1, _2, _3));
288#endif
191 289
192 // Send to vertex shader 290 // Send to vertex shader
193 VertexShader::OutputVertex output = VertexShader::RunShader(input, attribute_config.GetNumTotalAttributes()); 291 VertexShader::OutputVertex output = VertexShader::RunShader(input, attribute_config.GetNumTotalAttributes(), g_state.regs.vs, g_state.vs);
194 292
195 if (is_indexed) { 293 if (is_indexed) {
196 // TODO: Add processed vertex to vertex cache! 294 // TODO: Add processed vertex to vertex cache!
@@ -211,47 +309,55 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
211 } 309 }
212 } 310 }
213 311
312 for (auto& range : memory_accesses.ranges) {
313 g_debug_context->recorder->MemoryAccessed(Memory::GetPhysicalPointer(range.first),
314 range.second, range.first);
315 }
316
214 if (Settings::values.use_hw_renderer) { 317 if (Settings::values.use_hw_renderer) {
215 VideoCore::g_renderer->hw_rasterizer->DrawTriangles(); 318 VideoCore::g_renderer->hw_rasterizer->DrawTriangles();
216 } 319 }
217 320
321#if PICA_DUMP_GEOMETRY
218 geometry_dumper.Dump(); 322 geometry_dumper.Dump();
323#endif
219 324
220 if (g_debug_context) 325 if (g_debug_context) {
221 g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr); 326 g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr);
327 }
222 328
223 break; 329 break;
224 } 330 }
225 331
226 case PICA_REG_INDEX(vs_bool_uniforms): 332 case PICA_REG_INDEX(vs.bool_uniforms):
227 for (unsigned i = 0; i < 16; ++i) 333 for (unsigned i = 0; i < 16; ++i)
228 g_state.vs.uniforms.b[i] = (regs.vs_bool_uniforms.Value() & (1 << i)) != 0; 334 g_state.vs.uniforms.b[i] = (regs.vs.bool_uniforms.Value() & (1 << i)) != 0;
229 335
230 break; 336 break;
231 337
232 case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[0], 0x2b1): 338 case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[0], 0x2b1):
233 case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[1], 0x2b2): 339 case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[1], 0x2b2):
234 case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[2], 0x2b3): 340 case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[2], 0x2b3):
235 case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[3], 0x2b4): 341 case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[3], 0x2b4):
236 { 342 {
237 int index = (id - PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[0], 0x2b1)); 343 int index = (id - PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[0], 0x2b1));
238 auto values = regs.vs_int_uniforms[index]; 344 auto values = regs.vs.int_uniforms[index];
239 g_state.vs.uniforms.i[index] = Math::Vec4<u8>(values.x, values.y, values.z, values.w); 345 g_state.vs.uniforms.i[index] = Math::Vec4<u8>(values.x, values.y, values.z, values.w);
240 LOG_TRACE(HW_GPU, "Set integer uniform %d to %02x %02x %02x %02x", 346 LOG_TRACE(HW_GPU, "Set integer uniform %d to %02x %02x %02x %02x",
241 index, values.x.Value(), values.y.Value(), values.z.Value(), values.w.Value()); 347 index, values.x.Value(), values.y.Value(), values.z.Value(), values.w.Value());
242 break; 348 break;
243 } 349 }
244 350
245 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[0], 0x2c1): 351 case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[0], 0x2c1):
246 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[1], 0x2c2): 352 case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[1], 0x2c2):
247 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[2], 0x2c3): 353 case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[2], 0x2c3):
248 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[3], 0x2c4): 354 case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[3], 0x2c4):
249 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[4], 0x2c5): 355 case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[4], 0x2c5):
250 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[5], 0x2c6): 356 case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[5], 0x2c6):
251 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[6], 0x2c7): 357 case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[6], 0x2c7):
252 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[7], 0x2c8): 358 case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[7], 0x2c8):
253 { 359 {
254 auto& uniform_setup = regs.vs_uniform_setup; 360 auto& uniform_setup = regs.vs.uniform_setup;
255 361
256 // TODO: Does actual hardware indeed keep an intermediate buffer or does 362 // TODO: Does actual hardware indeed keep an intermediate buffer or does
257 // it directly write the values? 363 // it directly write the values?
@@ -293,73 +399,33 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
293 break; 399 break;
294 } 400 }
295 401
296 // Load default vertex input attributes
297 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233):
298 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234):
299 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[2], 0x235):
300 {
301 // TODO: Does actual hardware indeed keep an intermediate buffer or does
302 // it directly write the values?
303 default_attr_write_buffer[default_attr_counter++] = value;
304
305 // Default attributes are written in a packed format such that four float24 values are encoded in
306 // three 32-bit numbers. We write to internal memory once a full such vector is
307 // written.
308 if (default_attr_counter >= 3) {
309 default_attr_counter = 0;
310
311 auto& setup = regs.vs_default_attributes_setup;
312
313 if (setup.index >= 16) {
314 LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index);
315 break;
316 }
317
318 Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index];
319
320 // NOTE: The destination component order indeed is "backwards"
321 attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8);
322 attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF));
323 attribute.y = float24::FromRawFloat24(((default_attr_write_buffer[1] & 0xFFFF) << 8) | ((default_attr_write_buffer[2] >> 24) & 0xFF));
324 attribute.x = float24::FromRawFloat24(default_attr_write_buffer[2] & 0xFFFFFF);
325
326 LOG_TRACE(HW_GPU, "Set default VS attribute %x to (%f %f %f %f)", (int)setup.index,
327 attribute.x.ToFloat32(), attribute.y.ToFloat32(), attribute.z.ToFloat32(),
328 attribute.w.ToFloat32());
329
330 // TODO: Verify that this actually modifies the register!
331 setup.index = setup.index + 1;
332 }
333 break;
334 }
335
336 // Load shader program code 402 // Load shader program code
337 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[0], 0x2cc): 403 case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[0], 0x2cc):
338 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[1], 0x2cd): 404 case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[1], 0x2cd):
339 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[2], 0x2ce): 405 case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[2], 0x2ce):
340 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[3], 0x2cf): 406 case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[3], 0x2cf):
341 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[4], 0x2d0): 407 case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[4], 0x2d0):
342 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[5], 0x2d1): 408 case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[5], 0x2d1):
343 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[6], 0x2d2): 409 case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[6], 0x2d2):
344 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[7], 0x2d3): 410 case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[7], 0x2d3):
345 { 411 {
346 g_state.vs.program_code[regs.vs_program.offset] = value; 412 g_state.vs.program_code[regs.vs.program.offset] = value;
347 regs.vs_program.offset++; 413 regs.vs.program.offset++;
348 break; 414 break;
349 } 415 }
350 416
351 // Load swizzle pattern data 417 // Load swizzle pattern data
352 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[0], 0x2d6): 418 case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[0], 0x2d6):
353 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[1], 0x2d7): 419 case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[1], 0x2d7):
354 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[2], 0x2d8): 420 case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[2], 0x2d8):
355 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[3], 0x2d9): 421 case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[3], 0x2d9):
356 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[4], 0x2da): 422 case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[4], 0x2da):
357 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[5], 0x2db): 423 case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[5], 0x2db):
358 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[6], 0x2dc): 424 case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[6], 0x2dc):
359 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[7], 0x2dd): 425 case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[7], 0x2dd):
360 { 426 {
361 g_state.vs.swizzle_data[regs.vs_swizzle_patterns.offset] = value; 427 g_state.vs.swizzle_data[regs.vs.swizzle_patterns.offset] = value;
362 regs.vs_swizzle_patterns.offset++; 428 regs.vs.swizzle_patterns.offset++;
363 break; 429 break;
364 } 430 }
365 431
@@ -370,7 +436,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
370 VideoCore::g_renderer->hw_rasterizer->NotifyPicaRegisterChanged(id); 436 VideoCore::g_renderer->hw_rasterizer->NotifyPicaRegisterChanged(id);
371 437
372 if (g_debug_context) 438 if (g_debug_context)
373 g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id)); 439 g_debug_context->OnEvent(DebugContext::Event::PicaCommandProcessed, reinterpret_cast<void*>(&id));
374} 440}
375 441
376void ProcessCommandList(const u32* list, u32 size) { 442void ProcessCommandList(const u32* list, u32 size) {
diff --git a/src/video_core/command_processor.h b/src/video_core/command_processor.h
index bb3d4150f..022a71f5e 100644
--- a/src/video_core/command_processor.h
+++ b/src/video_core/command_processor.h
@@ -4,11 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <type_traits>
8
7#include "common/bit_field.h" 9#include "common/bit_field.h"
8#include "common/common_types.h" 10#include "common/common_types.h"
9 11
10#include "pica.h"
11
12namespace Pica { 12namespace Pica {
13 13
14namespace CommandProcessor { 14namespace CommandProcessor {
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 7b8ab72b6..e9a858411 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -23,6 +23,7 @@
23#include "common/vector_math.h" 23#include "common/vector_math.h"
24 24
25#include "video_core/pica.h" 25#include "video_core/pica.h"
26#include "video_core/renderer_base.h"
26#include "video_core/utils.h" 27#include "video_core/utils.h"
27#include "video_core/video_core.h" 28#include "video_core/video_core.h"
28 29
@@ -84,15 +85,11 @@ void GeometryDumper::AddTriangle(Vertex& v0, Vertex& v1, Vertex& v2) {
84 vertices.push_back(v1); 85 vertices.push_back(v1);
85 vertices.push_back(v2); 86 vertices.push_back(v2);
86 87
87 int num_vertices = vertices.size(); 88 int num_vertices = (int)vertices.size();
88 faces.push_back({ num_vertices-3, num_vertices-2, num_vertices-1 }); 89 faces.push_back({ num_vertices-3, num_vertices-2, num_vertices-1 });
89} 90}
90 91
91void GeometryDumper::Dump() { 92void GeometryDumper::Dump() {
92 // NOTE: Permanently enabling this just trashes the hard disk for no reason.
93 // Hence, this is currently disabled.
94 return;
95
96 static int index = 0; 93 static int index = 0;
97 std::string filename = std::string("geometry_dump") + std::to_string(++index) + ".obj"; 94 std::string filename = std::string("geometry_dump") + std::to_string(++index) + ".obj";
98 95
@@ -115,10 +112,6 @@ void GeometryDumper::Dump() {
115void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data, u32 swizzle_size, 112void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data, u32 swizzle_size,
116 u32 main_offset, const Regs::VSOutputAttributes* output_attributes) 113 u32 main_offset, const Regs::VSOutputAttributes* output_attributes)
117{ 114{
118 // NOTE: Permanently enabling this just trashes hard disks for no reason.
119 // Hence, this is currently disabled.
120 return;
121
122 struct StuffToWrite { 115 struct StuffToWrite {
123 u8* pointer; 116 u8* pointer;
124 u32 size; 117 u32 size;
@@ -240,8 +233,8 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data
240 233
241 dvle.main_offset_words = main_offset; 234 dvle.main_offset_words = main_offset;
242 dvle.output_register_table_offset = write_offset - dvlb.dvle_offset; 235 dvle.output_register_table_offset = write_offset - dvlb.dvle_offset;
243 dvle.output_register_table_size = output_info_table.size(); 236 dvle.output_register_table_size = static_cast<uint32_t>(output_info_table.size());
244 QueueForWriting((u8*)output_info_table.data(), output_info_table.size() * sizeof(OutputRegisterInfo)); 237 QueueForWriting((u8*)output_info_table.data(), static_cast<u32>(output_info_table.size() * sizeof(OutputRegisterInfo)));
245 238
246 // TODO: Create a label table for "main" 239 // TODO: Create a label table for "main"
247 240
@@ -496,31 +489,31 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
496 // Lookup base value 489 // Lookup base value
497 Math::Vec3<int> ret; 490 Math::Vec3<int> ret;
498 if (differential_mode) { 491 if (differential_mode) {
499 ret.r() = differential.r; 492 ret.r() = static_cast<int>(differential.r);
500 ret.g() = differential.g; 493 ret.g() = static_cast<int>(differential.g);
501 ret.b() = differential.b; 494 ret.b() = static_cast<int>(differential.b);
502 if (x >= 2) { 495 if (x >= 2) {
503 ret.r() += differential.dr; 496 ret.r() += static_cast<int>(differential.dr);
504 ret.g() += differential.dg; 497 ret.g() += static_cast<int>(differential.dg);
505 ret.b() += differential.db; 498 ret.b() += static_cast<int>(differential.db);
506 } 499 }
507 ret.r() = Color::Convert5To8(ret.r()); 500 ret.r() = Color::Convert5To8(ret.r());
508 ret.g() = Color::Convert5To8(ret.g()); 501 ret.g() = Color::Convert5To8(ret.g());
509 ret.b() = Color::Convert5To8(ret.b()); 502 ret.b() = Color::Convert5To8(ret.b());
510 } else { 503 } else {
511 if (x < 2) { 504 if (x < 2) {
512 ret.r() = Color::Convert4To8(separate.r1); 505 ret.r() = Color::Convert4To8(static_cast<u8>(separate.r1));
513 ret.g() = Color::Convert4To8(separate.g1); 506 ret.g() = Color::Convert4To8(static_cast<u8>(separate.g1));
514 ret.b() = Color::Convert4To8(separate.b1); 507 ret.b() = Color::Convert4To8(static_cast<u8>(separate.b1));
515 } else { 508 } else {
516 ret.r() = Color::Convert4To8(separate.r2); 509 ret.r() = Color::Convert4To8(static_cast<u8>(separate.r2));
517 ret.g() = Color::Convert4To8(separate.g2); 510 ret.g() = Color::Convert4To8(static_cast<u8>(separate.g2));
518 ret.b() = Color::Convert4To8(separate.b2); 511 ret.b() = Color::Convert4To8(static_cast<u8>(separate.b2));
519 } 512 }
520 } 513 }
521 514
522 // Add modifier 515 // Add modifier
523 unsigned table_index = (x < 2) ? table_index_1.Value() : table_index_2.Value(); 516 unsigned table_index = static_cast<int>((x < 2) ? table_index_1.Value() : table_index_2.Value());
524 517
525 static const std::array<std::array<u8, 2>, 8> etc1_modifier_table = {{ 518 static const std::array<std::array<u8, 2>, 8> etc1_modifier_table = {{
526 { 2, 8 }, { 5, 17 }, { 9, 29 }, { 13, 42 }, 519 { 2, 8 }, { 5, 17 }, { 9, 29 }, { 13, 42 },
@@ -564,10 +557,6 @@ TextureInfo TextureInfo::FromPicaRegister(const Regs::TextureConfig& config,
564} 557}
565 558
566void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { 559void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
567 // NOTE: Permanently enabling this just trashes hard disks for no reason.
568 // Hence, this is currently disabled.
569 return;
570
571#ifndef HAVE_PNG 560#ifndef HAVE_PNG
572 return; 561 return;
573#else 562#else
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
index 7926d64ec..81eea30a9 100644
--- a/src/video_core/debug_utils/debug_utils.h
+++ b/src/video_core/debug_utils/debug_utils.h
@@ -14,6 +14,8 @@
14 14
15#include "common/vector_math.h" 15#include "common/vector_math.h"
16 16
17#include "core/tracer/recorder.h"
18
17#include "video_core/pica.h" 19#include "video_core/pica.h"
18 20
19namespace Pica { 21namespace Pica {
@@ -23,11 +25,14 @@ public:
23 enum class Event { 25 enum class Event {
24 FirstEvent = 0, 26 FirstEvent = 0,
25 27
26 CommandLoaded = FirstEvent, 28 PicaCommandLoaded = FirstEvent,
27 CommandProcessed, 29 PicaCommandProcessed,
28 IncomingPrimitiveBatch, 30 IncomingPrimitiveBatch,
29 FinishedPrimitiveBatch, 31 FinishedPrimitiveBatch,
30 VertexLoaded, 32 VertexLoaded,
33 IncomingDisplayTransfer,
34 GSPCommandProcessed,
35 BufferSwapped,
31 36
32 NumEvents 37 NumEvents
33 }; 38 };
@@ -129,6 +134,8 @@ public:
129 Event active_breakpoint; 134 Event active_breakpoint;
130 bool at_breakpoint = false; 135 bool at_breakpoint = false;
131 136
137 std::shared_ptr<CiTrace::Recorder> recorder = nullptr;
138
132private: 139private:
133 /** 140 /**
134 * Private default constructor to make sure people always construct this through Construct() 141 * Private default constructor to make sure people always construct this through Construct()
@@ -150,6 +157,11 @@ extern std::shared_ptr<DebugContext> g_debug_context; // TODO: Get rid of this g
150 157
151namespace DebugUtils { 158namespace DebugUtils {
152 159
160#define PICA_DUMP_GEOMETRY 0
161#define PICA_DUMP_SHADERS 0
162#define PICA_DUMP_TEXTURES 0
163#define PICA_LOG_TEV 0
164
153// Simple utility class for dumping geometry data to an OBJ file 165// Simple utility class for dumping geometry data to an OBJ file
154class GeometryDumper { 166class GeometryDumper {
155public: 167public:
diff --git a/src/video_core/hwrasterizer_base.h b/src/video_core/hwrasterizer_base.h
index dec193f8b..c8746c608 100644
--- a/src/video_core/hwrasterizer_base.h
+++ b/src/video_core/hwrasterizer_base.h
@@ -4,8 +4,13 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/emu_window.h" 7#include "common/common_types.h"
8#include "video_core/vertex_shader.h" 8
9namespace Pica {
10namespace VertexShader {
11struct OutputVertex;
12}
13}
9 14
10class HWRasterizer { 15class HWRasterizer {
11public: 16public:
diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp
index 543d9c443..17cb66780 100644
--- a/src/video_core/pica.cpp
+++ b/src/video_core/pica.cpp
@@ -2,7 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <string.h> 5#include <cstring>
6#include <unordered_map>
6 7
7#include "pica.h" 8#include "pica.h"
8 9
@@ -10,6 +11,75 @@ namespace Pica {
10 11
11State g_state; 12State g_state;
12 13
14std::string Regs::GetCommandName(int index) {
15 static std::unordered_map<u32, std::string> map;
16
17 if (map.empty()) {
18 #define ADD_FIELD(name) \
19 map.insert({static_cast<u32>(PICA_REG_INDEX(name)), #name}); \
20 /* TODO: change to Regs::name when VS2015 and other compilers support it */ \
21 for (u32 i = PICA_REG_INDEX(name) + 1; i < PICA_REG_INDEX(name) + sizeof(Regs().name) / 4; ++i) \
22 map.insert({i, #name + std::string("+") + std::to_string(i-PICA_REG_INDEX(name))}); \
23
24 ADD_FIELD(trigger_irq);
25 ADD_FIELD(cull_mode);
26 ADD_FIELD(viewport_size_x);
27 ADD_FIELD(viewport_size_y);
28 ADD_FIELD(viewport_depth_range);
29 ADD_FIELD(viewport_depth_far_plane);
30 ADD_FIELD(viewport_corner);
31 ADD_FIELD(texture0_enable);
32 ADD_FIELD(texture0);
33 ADD_FIELD(texture0_format);
34 ADD_FIELD(texture1);
35 ADD_FIELD(texture1_format);
36 ADD_FIELD(texture2);
37 ADD_FIELD(texture2_format);
38 ADD_FIELD(tev_stage0);
39 ADD_FIELD(tev_stage1);
40 ADD_FIELD(tev_stage2);
41 ADD_FIELD(tev_stage3);
42 ADD_FIELD(tev_combiner_buffer_input);
43 ADD_FIELD(tev_stage4);
44 ADD_FIELD(tev_stage5);
45 ADD_FIELD(tev_combiner_buffer_color);
46 ADD_FIELD(output_merger);
47 ADD_FIELD(framebuffer);
48 ADD_FIELD(vertex_attributes);
49 ADD_FIELD(index_array);
50 ADD_FIELD(num_vertices);
51 ADD_FIELD(trigger_draw);
52 ADD_FIELD(trigger_draw_indexed);
53 ADD_FIELD(vs_default_attributes_setup);
54 ADD_FIELD(command_buffer);
55 ADD_FIELD(triangle_topology);
56 ADD_FIELD(gs.bool_uniforms);
57 ADD_FIELD(gs.int_uniforms);
58 ADD_FIELD(gs.main_offset);
59 ADD_FIELD(gs.input_register_map);
60 ADD_FIELD(gs.uniform_setup);
61 ADD_FIELD(gs.program);
62 ADD_FIELD(gs.swizzle_patterns);
63 ADD_FIELD(vs.bool_uniforms);
64 ADD_FIELD(vs.int_uniforms);
65 ADD_FIELD(vs.main_offset);
66 ADD_FIELD(vs.input_register_map);
67 ADD_FIELD(vs.uniform_setup);
68 ADD_FIELD(vs.program);
69 ADD_FIELD(vs.swizzle_patterns);
70
71#undef ADD_FIELD
72 }
73
74 // Return empty string if no match is found
75 auto it = map.find(index);
76 if (it != map.end()) {
77 return it->second;
78 } else {
79 return std::string();
80 }
81}
82
13void Init() { 83void Init() {
14} 84}
15 85
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 9628a7589..34b02b2f8 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -5,10 +5,9 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <cmath>
8#include <cstddef> 9#include <cstddef>
9#include <initializer_list> 10#include <string>
10#include <map>
11#include <vector>
12 11
13#include "common/assert.h" 12#include "common/assert.h"
14#include "common/bit_field.h" 13#include "common/bit_field.h"
@@ -114,11 +113,22 @@ struct Regs {
114 struct TextureConfig { 113 struct TextureConfig {
115 enum WrapMode : u32 { 114 enum WrapMode : u32 {
116 ClampToEdge = 0, 115 ClampToEdge = 0,
116 ClampToBorder = 1,
117 Repeat = 2, 117 Repeat = 2,
118 MirroredRepeat = 3, 118 MirroredRepeat = 3,
119 }; 119 };
120 120
121 INSERT_PADDING_WORDS(0x1); 121 enum TextureFilter : u32 {
122 Nearest = 0,
123 Linear = 1
124 };
125
126 union {
127 BitField< 0, 8, u32> r;
128 BitField< 8, 8, u32> g;
129 BitField<16, 8, u32> b;
130 BitField<24, 8, u32> a;
131 } border_color;
122 132
123 union { 133 union {
124 BitField< 0, 16, u32> height; 134 BitField< 0, 16, u32> height;
@@ -126,8 +136,10 @@ struct Regs {
126 }; 136 };
127 137
128 union { 138 union {
129 BitField< 8, 2, WrapMode> wrap_s; 139 BitField< 1, 1, TextureFilter> mag_filter;
130 BitField<12, 2, WrapMode> wrap_t; 140 BitField< 2, 1, TextureFilter> min_filter;
141 BitField< 8, 2, WrapMode> wrap_t;
142 BitField<12, 2, WrapMode> wrap_s;
131 }; 143 };
132 144
133 INSERT_PADDING_WORDS(0x1); 145 INSERT_PADDING_WORDS(0x1);
@@ -194,6 +206,7 @@ struct Regs {
194 case TextureFormat::IA8: 206 case TextureFormat::IA8:
195 return 4; 207 return 4;
196 208
209 case TextureFormat::I4:
197 case TextureFormat::A4: 210 case TextureFormat::A4:
198 return 1; 211 return 1;
199 212
@@ -284,6 +297,7 @@ struct Regs {
284 AddSigned = 3, 297 AddSigned = 3,
285 Lerp = 4, 298 Lerp = 4,
286 Subtract = 5, 299 Subtract = 5,
300 Dot3_RGB = 6,
287 301
288 MultiplyThenAdd = 8, 302 MultiplyThenAdd = 8,
289 AddThenMultiply = 9, 303 AddThenMultiply = 9,
@@ -414,6 +428,11 @@ struct Regs {
414 GreaterThanOrEqual = 7, 428 GreaterThanOrEqual = 7,
415 }; 429 };
416 430
431 enum class StencilAction : u32 {
432 Keep = 0,
433 Xor = 5,
434 };
435
417 struct { 436 struct {
418 union { 437 union {
419 // If false, logic blending is used 438 // If false, logic blending is used
@@ -448,15 +467,35 @@ struct Regs {
448 BitField< 8, 8, u32> ref; 467 BitField< 8, 8, u32> ref;
449 } alpha_test; 468 } alpha_test;
450 469
451 union { 470 struct {
452 BitField< 0, 1, u32> stencil_test_enable; 471 union {
453 BitField< 4, 3, CompareFunc> stencil_test_func; 472 // If true, enable stencil testing
454 BitField< 8, 8, u32> stencil_replacement_value; 473 BitField< 0, 1, u32> enable;
455 BitField<16, 8, u32> stencil_reference_value;
456 BitField<24, 8, u32> stencil_mask;
457 } stencil_test;
458 474
459 INSERT_PADDING_WORDS(0x1); 475 // Comparison operation for stencil testing
476 BitField< 4, 3, CompareFunc> func;
477
478 // Value to calculate the new stencil value from
479 BitField< 8, 8, u32> replacement_value;
480
481 // Value to compare against for stencil testing
482 BitField<16, 8, u32> reference_value;
483
484 // Mask to apply on stencil test inputs
485 BitField<24, 8, u32> mask;
486 };
487
488 union {
489 // Action to perform when the stencil test fails
490 BitField< 0, 3, StencilAction> action_stencil_fail;
491
492 // Action to perform when stencil testing passed but depth testing fails
493 BitField< 4, 3, StencilAction> action_depth_fail;
494
495 // Action to perform when both stencil and depth testing pass
496 BitField< 8, 3, StencilAction> action_depth_pass;
497 };
498 } stencil_test;
460 499
461 union { 500 union {
462 BitField< 0, 1, u32> depth_test_enable; 501 BitField< 0, 1, u32> depth_test_enable;
@@ -506,7 +545,7 @@ struct Regs {
506 struct { 545 struct {
507 INSERT_PADDING_WORDS(0x6); 546 INSERT_PADDING_WORDS(0x6);
508 547
509 DepthFormat depth_format; 548 DepthFormat depth_format; // TODO: Should be a BitField!
510 BitField<16, 3, ColorFormat> color_format; 549 BitField<16, 3, ColorFormat> color_format;
511 550
512 INSERT_PADDING_WORDS(0x4); 551 INSERT_PADDING_WORDS(0x4);
@@ -752,171 +791,123 @@ struct Regs {
752 INSERT_PADDING_WORDS(0x20); 791 INSERT_PADDING_WORDS(0x20);
753 792
754 enum class TriangleTopology : u32 { 793 enum class TriangleTopology : u32 {
755 List = 0, 794 List = 0,
756 Strip = 1, 795 Strip = 1,
757 Fan = 2, 796 Fan = 2,
758 ListIndexed = 3, // TODO: No idea if this is correct 797 Shader = 3, // Programmable setup unit implemented in a geometry shader
759 }; 798 };
760 799
761 BitField<8, 2, TriangleTopology> triangle_topology; 800 BitField<8, 2, TriangleTopology> triangle_topology;
762 801
763 INSERT_PADDING_WORDS(0x51); 802 INSERT_PADDING_WORDS(0x21);
764 803
765 BitField<0, 16, u32> vs_bool_uniforms; 804 struct ShaderConfig {
766 union { 805 BitField<0, 16, u32> bool_uniforms;
767 BitField< 0, 8, u32> x;
768 BitField< 8, 8, u32> y;
769 BitField<16, 8, u32> z;
770 BitField<24, 8, u32> w;
771 } vs_int_uniforms[4];
772 806
773 INSERT_PADDING_WORDS(0x5); 807 union {
808 BitField< 0, 8, u32> x;
809 BitField< 8, 8, u32> y;
810 BitField<16, 8, u32> z;
811 BitField<24, 8, u32> w;
812 } int_uniforms[4];
774 813
775 // Offset to shader program entry point (in words) 814 INSERT_PADDING_WORDS(0x5);
776 BitField<0, 16, u32> vs_main_offset;
777 815
778 union { 816 // Offset to shader program entry point (in words)
779 BitField< 0, 4, u64> attribute0_register; 817 BitField<0, 16, u32> main_offset;
780 BitField< 4, 4, u64> attribute1_register; 818
781 BitField< 8, 4, u64> attribute2_register; 819 union {
782 BitField<12, 4, u64> attribute3_register; 820 BitField< 0, 4, u64> attribute0_register;
783 BitField<16, 4, u64> attribute4_register; 821 BitField< 4, 4, u64> attribute1_register;
784 BitField<20, 4, u64> attribute5_register; 822 BitField< 8, 4, u64> attribute2_register;
785 BitField<24, 4, u64> attribute6_register; 823 BitField<12, 4, u64> attribute3_register;
786 BitField<28, 4, u64> attribute7_register; 824 BitField<16, 4, u64> attribute4_register;
787 BitField<32, 4, u64> attribute8_register; 825 BitField<20, 4, u64> attribute5_register;
788 BitField<36, 4, u64> attribute9_register; 826 BitField<24, 4, u64> attribute6_register;
789 BitField<40, 4, u64> attribute10_register; 827 BitField<28, 4, u64> attribute7_register;
790 BitField<44, 4, u64> attribute11_register; 828 BitField<32, 4, u64> attribute8_register;
791 BitField<48, 4, u64> attribute12_register; 829 BitField<36, 4, u64> attribute9_register;
792 BitField<52, 4, u64> attribute13_register; 830 BitField<40, 4, u64> attribute10_register;
793 BitField<56, 4, u64> attribute14_register; 831 BitField<44, 4, u64> attribute11_register;
794 BitField<60, 4, u64> attribute15_register; 832 BitField<48, 4, u64> attribute12_register;
795 833 BitField<52, 4, u64> attribute13_register;
796 int GetRegisterForAttribute(int attribute_index) const { 834 BitField<56, 4, u64> attribute14_register;
797 u64 fields[] = { 835 BitField<60, 4, u64> attribute15_register;
798 attribute0_register, attribute1_register, attribute2_register, attribute3_register, 836
799 attribute4_register, attribute5_register, attribute6_register, attribute7_register, 837 int GetRegisterForAttribute(int attribute_index) const {
800 attribute8_register, attribute9_register, attribute10_register, attribute11_register, 838 u64 fields[] = {
801 attribute12_register, attribute13_register, attribute14_register, attribute15_register, 839 attribute0_register, attribute1_register, attribute2_register, attribute3_register,
840 attribute4_register, attribute5_register, attribute6_register, attribute7_register,
841 attribute8_register, attribute9_register, attribute10_register, attribute11_register,
842 attribute12_register, attribute13_register, attribute14_register, attribute15_register,
843 };
844 return (int)fields[attribute_index];
845 }
846 } input_register_map;
847
848 // OUTMAP_MASK, 0x28E, CODETRANSFER_END
849 INSERT_PADDING_WORDS(0x3);
850
851 struct {
852 enum Format : u32
853 {
854 FLOAT24 = 0,
855 FLOAT32 = 1
802 }; 856 };
803 return (int)fields[attribute_index];
804 }
805 } vs_input_register_map;
806 857
807 INSERT_PADDING_WORDS(0x3); 858 bool IsFloat32() const {
859 return format == FLOAT32;
860 }
808 861
809 struct { 862 union {
810 enum Format : u32 863 // Index of the next uniform to write to
811 { 864 // TODO: ctrulib uses 8 bits for this, however that seems to yield lots of invalid indices
812 FLOAT24 = 0, 865 // TODO: Maybe the uppermost index is for the geometry shader? Investigate!
813 FLOAT32 = 1 866 BitField<0, 7, u32> index;
814 };
815 867
816 bool IsFloat32() const { 868 BitField<31, 1, Format> format;
817 return format == FLOAT32; 869 };
818 }
819 870
820 union { 871 // Writing to these registers sets the current uniform.
821 // Index of the next uniform to write to 872 u32 set_value[8];
822 // TODO: ctrulib uses 8 bits for this, however that seems to yield lots of invalid indices
823 BitField<0, 7, u32> index;
824 873
825 BitField<31, 1, Format> format; 874 } uniform_setup;
826 };
827 875
828 // Writing to these registers sets the "current" uniform. 876 INSERT_PADDING_WORDS(0x2);
829 // TODO: It's not clear how the hardware stores what the "current" uniform is.
830 u32 set_value[8];
831 877
832 } vs_uniform_setup; 878 struct {
879 // Offset of the next instruction to write code to.
880 // Incremented with each instruction write.
881 u32 offset;
833 882
834 INSERT_PADDING_WORDS(0x2); 883 // Writing to these registers sets the "current" word in the shader program.
884 u32 set_word[8];
885 } program;
835 886
836 struct { 887 INSERT_PADDING_WORDS(0x1);
837 // Offset of the next instruction to write code to.
838 // Incremented with each instruction write.
839 u32 offset;
840 888
841 // Writing to these registers sets the "current" word in the shader program. 889 // This register group is used to load an internal table of swizzling patterns,
842 // TODO: It's not clear how the hardware stores what the "current" word is. 890 // which are indexed by each shader instruction to specify vector component swizzling.
843 u32 set_word[8]; 891 struct {
844 } vs_program; 892 // Offset of the next swizzle pattern to write code to.
893 // Incremented with each instruction write.
894 u32 offset;
845 895
846 INSERT_PADDING_WORDS(0x1); 896 // Writing to these registers sets the current swizzle pattern in the table.
897 u32 set_word[8];
898 } swizzle_patterns;
847 899
848 // This register group is used to load an internal table of swizzling patterns, 900 INSERT_PADDING_WORDS(0x2);
849 // which are indexed by each shader instruction to specify vector component swizzling. 901 };
850 struct {
851 // Offset of the next swizzle pattern to write code to.
852 // Incremented with each instruction write.
853 u32 offset;
854 902
855 // Writing to these registers sets the "current" swizzle pattern in the table. 903 ShaderConfig gs;
856 // TODO: It's not clear how the hardware stores what the "current" swizzle pattern is. 904 ShaderConfig vs;
857 u32 set_word[8];
858 } vs_swizzle_patterns;
859 905
860 INSERT_PADDING_WORDS(0x22); 906 INSERT_PADDING_WORDS(0x20);
861 907
862 // Map register indices to names readable by humans 908 // Map register indices to names readable by humans
863 // Used for debugging purposes, so performance is not an issue here 909 // Used for debugging purposes, so performance is not an issue here
864 static std::string GetCommandName(int index) { 910 static std::string GetCommandName(int index);
865 std::map<u32, std::string> map;
866
867 #define ADD_FIELD(name) \
868 do { \
869 map.insert({PICA_REG_INDEX(name), #name}); \
870 /* TODO: change to Regs::name when VS2015 and other compilers support it */ \
871 for (u32 i = PICA_REG_INDEX(name) + 1; i < PICA_REG_INDEX(name) + sizeof(Regs().name) / 4; ++i) \
872 map.insert({i, #name + std::string("+") + std::to_string(i-PICA_REG_INDEX(name))}); \
873 } while(false)
874
875 ADD_FIELD(trigger_irq);
876 ADD_FIELD(cull_mode);
877 ADD_FIELD(viewport_size_x);
878 ADD_FIELD(viewport_size_y);
879 ADD_FIELD(viewport_depth_range);
880 ADD_FIELD(viewport_depth_far_plane);
881 ADD_FIELD(viewport_corner);
882 ADD_FIELD(texture0_enable);
883 ADD_FIELD(texture0);
884 ADD_FIELD(texture0_format);
885 ADD_FIELD(texture1);
886 ADD_FIELD(texture1_format);
887 ADD_FIELD(texture2);
888 ADD_FIELD(texture2_format);
889 ADD_FIELD(tev_stage0);
890 ADD_FIELD(tev_stage1);
891 ADD_FIELD(tev_stage2);
892 ADD_FIELD(tev_stage3);
893 ADD_FIELD(tev_combiner_buffer_input);
894 ADD_FIELD(tev_stage4);
895 ADD_FIELD(tev_stage5);
896 ADD_FIELD(tev_combiner_buffer_color);
897 ADD_FIELD(output_merger);
898 ADD_FIELD(framebuffer);
899 ADD_FIELD(vertex_attributes);
900 ADD_FIELD(index_array);
901 ADD_FIELD(num_vertices);
902 ADD_FIELD(trigger_draw);
903 ADD_FIELD(trigger_draw_indexed);
904 ADD_FIELD(vs_default_attributes_setup);
905 ADD_FIELD(command_buffer);
906 ADD_FIELD(triangle_topology);
907 ADD_FIELD(vs_bool_uniforms);
908 ADD_FIELD(vs_int_uniforms);
909 ADD_FIELD(vs_main_offset);
910 ADD_FIELD(vs_input_register_map);
911 ADD_FIELD(vs_uniform_setup);
912 ADD_FIELD(vs_program);
913 ADD_FIELD(vs_swizzle_patterns);
914
915 #undef ADD_FIELD
916
917 // Return empty string if no match is found
918 return map[index];
919 }
920 911
921 static inline size_t NumIds() { 912 static inline size_t NumIds() {
922 return sizeof(Regs) / sizeof(u32); 913 return sizeof(Regs) / sizeof(u32);
@@ -982,17 +973,14 @@ ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f);
982ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232); 973ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232);
983ASSERT_REG_POSITION(command_buffer, 0x238); 974ASSERT_REG_POSITION(command_buffer, 0x238);
984ASSERT_REG_POSITION(triangle_topology, 0x25e); 975ASSERT_REG_POSITION(triangle_topology, 0x25e);
985ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0); 976ASSERT_REG_POSITION(gs, 0x280);
986ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1); 977ASSERT_REG_POSITION(vs, 0x2b0);
987ASSERT_REG_POSITION(vs_main_offset, 0x2ba);
988ASSERT_REG_POSITION(vs_input_register_map, 0x2bb);
989ASSERT_REG_POSITION(vs_uniform_setup, 0x2c0);
990ASSERT_REG_POSITION(vs_program, 0x2cb);
991ASSERT_REG_POSITION(vs_swizzle_patterns, 0x2d5);
992 978
993#undef ASSERT_REG_POSITION 979#undef ASSERT_REG_POSITION
994#endif // !defined(_MSC_VER) 980#endif // !defined(_MSC_VER)
995 981
982static_assert(sizeof(Regs::ShaderConfig) == 0x30 * sizeof(u32), "ShaderConfig structure has incorrect size");
983
996// The total number of registers is chosen arbitrarily, but let's make sure it's not some odd value anyway. 984// The total number of registers is chosen arbitrarily, but let's make sure it's not some odd value anyway.
997static_assert(sizeof(Regs) <= 0x300 * sizeof(u32), "Register set structure larger than it should be"); 985static_assert(sizeof(Regs) <= 0x300 * sizeof(u32), "Register set structure larger than it should be");
998static_assert(sizeof(Regs) >= 0x300 * sizeof(u32), "Register set structure smaller than it should be"); 986static_assert(sizeof(Regs) >= 0x300 * sizeof(u32), "Register set structure smaller than it should be");
@@ -1014,7 +1002,7 @@ struct float24 {
1014 u32 mantissa = hex & 0xFFFF; 1002 u32 mantissa = hex & 0xFFFF;
1015 u32 exponent = (hex >> 16) & 0x7F; 1003 u32 exponent = (hex >> 16) & 0x7F;
1016 u32 sign = hex >> 23; 1004 u32 sign = hex >> 23;
1017 ret.value = powf(2.0f, (float)exponent-63.0f) * (1.0f + mantissa * powf(2.0f, -16.f)); 1005 ret.value = std::pow(2.0f, (float)exponent-63.0f) * (1.0f + mantissa * std::pow(2.0f, -16.f));
1018 if (sign) 1006 if (sign)
1019 ret.value = -ret.value; 1007 ret.value = -ret.value;
1020 } 1008 }
@@ -1102,7 +1090,7 @@ struct State {
1102 Regs regs; 1090 Regs regs;
1103 1091
1104 /// Vertex shader memory 1092 /// Vertex shader memory
1105 struct { 1093 struct ShaderSetup {
1106 struct { 1094 struct {
1107 Math::Vec4<float24> f[96]; 1095 Math::Vec4<float24> f[96];
1108 std::array<bool, 16> b; 1096 std::array<bool, 16> b;
@@ -1113,7 +1101,10 @@ struct State {
1113 1101
1114 std::array<u32, 1024> program_code; 1102 std::array<u32, 1024> program_code;
1115 std::array<u32, 1024> swizzle_data; 1103 std::array<u32, 1024> swizzle_data;
1116 } vs; 1104 };
1105
1106 ShaderSetup vs;
1107 ShaderSetup gs;
1117 1108
1118 /// Current Pica command list 1109 /// Current Pica command list
1119 struct { 1110 struct {
diff --git a/src/video_core/primitive_assembly.cpp b/src/video_core/primitive_assembly.cpp
index 0120f2896..2f22bdcce 100644
--- a/src/video_core/primitive_assembly.cpp
+++ b/src/video_core/primitive_assembly.cpp
@@ -20,8 +20,9 @@ template<typename VertexType>
20void PrimitiveAssembler<VertexType>::SubmitVertex(VertexType& vtx, TriangleHandler triangle_handler) 20void PrimitiveAssembler<VertexType>::SubmitVertex(VertexType& vtx, TriangleHandler triangle_handler)
21{ 21{
22 switch (topology) { 22 switch (topology) {
23 // TODO: Figure out what's different with TriangleTopology::Shader.
23 case Regs::TriangleTopology::List: 24 case Regs::TriangleTopology::List:
24 case Regs::TriangleTopology::ListIndexed: 25 case Regs::TriangleTopology::Shader:
25 if (buffer_index < 2) { 26 if (buffer_index < 2) {
26 buffer[buffer_index++] = vtx; 27 buffer[buffer_index++] = vtx;
27 } else { 28 } else {
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 59d156ee7..68b7cc05d 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -126,6 +126,30 @@ static u32 GetDepth(int x, int y) {
126 } 126 }
127} 127}
128 128
129static u8 GetStencil(int x, int y) {
130 const auto& framebuffer = g_state.regs.framebuffer;
131 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
132 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
133
134 y = framebuffer.height - y;
135
136 const u32 coarse_y = y & ~7;
137 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format);
138 u32 stride = framebuffer.width * bytes_per_pixel;
139
140 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
141 u8* src_pixel = depth_buffer + src_offset;
142
143 switch (framebuffer.depth_format) {
144 case Regs::DepthFormat::D24S8:
145 return Color::DecodeD24S8(src_pixel).y;
146
147 default:
148 LOG_WARNING(HW_GPU, "GetStencil called for function which doesn't have a stencil component (format %u)", framebuffer.depth_format);
149 return 0;
150 }
151}
152
129static void SetDepth(int x, int y, u32 value) { 153static void SetDepth(int x, int y, u32 value) {
130 const auto& framebuffer = g_state.regs.framebuffer; 154 const auto& framebuffer = g_state.regs.framebuffer;
131 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); 155 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
@@ -144,13 +168,15 @@ static void SetDepth(int x, int y, u32 value) {
144 case Regs::DepthFormat::D16: 168 case Regs::DepthFormat::D16:
145 Color::EncodeD16(value, dst_pixel); 169 Color::EncodeD16(value, dst_pixel);
146 break; 170 break;
171
147 case Regs::DepthFormat::D24: 172 case Regs::DepthFormat::D24:
148 Color::EncodeD24(value, dst_pixel); 173 Color::EncodeD24(value, dst_pixel);
149 break; 174 break;
175
150 case Regs::DepthFormat::D24S8: 176 case Regs::DepthFormat::D24S8:
151 // TODO(Subv): Implement the stencil buffer 177 Color::EncodeD24X8(value, dst_pixel);
152 Color::EncodeD24S8(value, 0, dst_pixel);
153 break; 178 break;
179
154 default: 180 default:
155 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); 181 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
156 UNIMPLEMENTED(); 182 UNIMPLEMENTED();
@@ -158,6 +184,53 @@ static void SetDepth(int x, int y, u32 value) {
158 } 184 }
159} 185}
160 186
187static void SetStencil(int x, int y, u8 value) {
188 const auto& framebuffer = g_state.regs.framebuffer;
189 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
190 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
191
192 y = framebuffer.height - y;
193
194 const u32 coarse_y = y & ~7;
195 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format);
196 u32 stride = framebuffer.width * bytes_per_pixel;
197
198 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
199 u8* dst_pixel = depth_buffer + dst_offset;
200
201 switch (framebuffer.depth_format) {
202 case Pica::Regs::DepthFormat::D16:
203 case Pica::Regs::DepthFormat::D24:
204 // Nothing to do
205 break;
206
207 case Pica::Regs::DepthFormat::D24S8:
208 Color::EncodeX24S8(value, dst_pixel);
209 break;
210
211 default:
212 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
213 UNIMPLEMENTED();
214 break;
215 }
216}
217
218// TODO: Should the stencil mask be applied to the "dest" or "ref" operands? Most likely not!
219static u8 PerformStencilAction(Regs::StencilAction action, u8 dest, u8 ref) {
220 switch (action) {
221 case Regs::StencilAction::Keep:
222 return dest;
223
224 case Regs::StencilAction::Xor:
225 return dest ^ ref;
226
227 default:
228 LOG_CRITICAL(HW_GPU, "Unknown stencil action %x", (int)action);
229 UNIMPLEMENTED();
230 return 0;
231 }
232}
233
161// NOTE: Assuming that rasterizer coordinates are 12.4 fixed-point values 234// NOTE: Assuming that rasterizer coordinates are 12.4 fixed-point values
162struct Fix12P4 { 235struct Fix12P4 {
163 Fix12P4() {} 236 Fix12P4() {}
@@ -276,6 +349,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
276 auto textures = regs.GetTextures(); 349 auto textures = regs.GetTextures();
277 auto tev_stages = regs.GetTevStages(); 350 auto tev_stages = regs.GetTevStages();
278 351
352 bool stencil_action_enable = g_state.regs.output_merger.stencil_test.enable && g_state.regs.framebuffer.depth_format == Regs::DepthFormat::D24S8;
353 const auto stencil_test = g_state.regs.output_merger.stencil_test;
354
279 // Enter rasterization loop, starting at the center of the topleft bounding box corner. 355 // Enter rasterization loop, starting at the center of the topleft bounding box corner.
280 // TODO: Not sure if looping through x first might be faster 356 // TODO: Not sure if looping through x first might be faster
281 for (u16 y = min_y + 8; y < max_y; y += 0x10) { 357 for (u16 y = min_y + 8; y < max_y; y += 0x10) {
@@ -349,6 +425,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
349 val = std::min(val, (int)size - 1); 425 val = std::min(val, (int)size - 1);
350 return val; 426 return val;
351 427
428 case Regs::TextureConfig::ClampToBorder:
429 return val;
430
352 case Regs::TextureConfig::Repeat: 431 case Regs::TextureConfig::Repeat:
353 return (int)((unsigned)val % size); 432 return (int)((unsigned)val % size);
354 433
@@ -367,17 +446,26 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
367 } 446 }
368 }; 447 };
369 448
370 // Textures are laid out from bottom to top, hence we invert the t coordinate. 449 if ((texture.config.wrap_s == Regs::TextureConfig::ClampToBorder && (s < 0 || s >= texture.config.width))
371 // NOTE: This may not be the right place for the inversion. 450 || (texture.config.wrap_t == Regs::TextureConfig::ClampToBorder && (t < 0 || t >= texture.config.height))) {
372 // TODO: Check if this applies to ETC textures, too. 451 auto border_color = texture.config.border_color;
373 s = GetWrappedTexCoord(texture.config.wrap_s, s, texture.config.width); 452 texture_color[i] = { border_color.r, border_color.g, border_color.b, border_color.a };
374 t = texture.config.height - 1 - GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height); 453 } else {
375 454 // Textures are laid out from bottom to top, hence we invert the t coordinate.
376 u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress()); 455 // NOTE: This may not be the right place for the inversion.
377 auto info = DebugUtils::TextureInfo::FromPicaRegister(texture.config, texture.format); 456 // TODO: Check if this applies to ETC textures, too.
378 457 s = GetWrappedTexCoord(texture.config.wrap_s, s, texture.config.width);
379 texture_color[i] = DebugUtils::LookupTexture(texture_data, s, t, info); 458 t = texture.config.height - 1 - GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height);
380 DebugUtils::DumpTexture(texture.config, texture_data); 459
460 u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
461 auto info = DebugUtils::TextureInfo::FromPicaRegister(texture.config, texture.format);
462
463 // TODO: Apply the min and mag filters to the texture
464 texture_color[i] = DebugUtils::LookupTexture(texture_data, s, t, info);
465#if PICA_DUMP_TEXTURES
466 DebugUtils::DumpTexture(texture.config, texture_data);
467#endif
468 }
381 } 469 }
382 470
383 // Texture environment - consists of 6 stages of color and alpha combining. 471 // Texture environment - consists of 6 stages of color and alpha combining.
@@ -556,7 +644,18 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
556 result = (result * input[2].Cast<int>()) / 255; 644 result = (result * input[2].Cast<int>()) / 255;
557 return result.Cast<u8>(); 645 return result.Cast<u8>();
558 } 646 }
559 647 case Operation::Dot3_RGB:
648 {
649 // Not fully accurate.
650 // Worst case scenario seems to yield a +/-3 error
651 // Some HW results indicate that the per-component computation can't have a higher precision than 1/256,
652 // while dot3_rgb( (0x80,g0,b0),(0x7F,g1,b1) ) and dot3_rgb( (0x80,g0,b0),(0x80,g1,b1) ) give different results
653 int result = ((input[0].r() * 2 - 255) * (input[1].r() * 2 - 255) + 128) / 256 +
654 ((input[0].g() * 2 - 255) * (input[1].g() * 2 - 255) + 128) / 256 +
655 ((input[0].b() * 2 - 255) * (input[1].b() * 2 - 255) + 128) / 256;
656 result = std::max(0, std::min(255, result));
657 return { (u8)result, (u8)result, (u8)result };
658 }
560 default: 659 default:
561 LOG_ERROR(HW_GPU, "Unknown color combiner operation %d\n", (int)op); 660 LOG_ERROR(HW_GPU, "Unknown color combiner operation %d\n", (int)op);
562 UNIMPLEMENTED(); 661 UNIMPLEMENTED();
@@ -638,6 +737,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
638 } 737 }
639 738
640 const auto& output_merger = regs.output_merger; 739 const auto& output_merger = regs.output_merger;
740 // TODO: Does alpha testing happen before or after stencil?
641 if (output_merger.alpha_test.enable) { 741 if (output_merger.alpha_test.enable) {
642 bool pass = false; 742 bool pass = false;
643 743
@@ -679,6 +779,54 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
679 continue; 779 continue;
680 } 780 }
681 781
782 u8 old_stencil = 0;
783 if (stencil_action_enable) {
784 old_stencil = GetStencil(x >> 4, y >> 4);
785 u8 dest = old_stencil & stencil_test.mask;
786 u8 ref = stencil_test.reference_value & stencil_test.mask;
787
788 bool pass = false;
789 switch (stencil_test.func) {
790 case Regs::CompareFunc::Never:
791 pass = false;
792 break;
793
794 case Regs::CompareFunc::Always:
795 pass = true;
796 break;
797
798 case Regs::CompareFunc::Equal:
799 pass = (ref == dest);
800 break;
801
802 case Regs::CompareFunc::NotEqual:
803 pass = (ref != dest);
804 break;
805
806 case Regs::CompareFunc::LessThan:
807 pass = (ref < dest);
808 break;
809
810 case Regs::CompareFunc::LessThanOrEqual:
811 pass = (ref <= dest);
812 break;
813
814 case Regs::CompareFunc::GreaterThan:
815 pass = (ref > dest);
816 break;
817
818 case Regs::CompareFunc::GreaterThanOrEqual:
819 pass = (ref >= dest);
820 break;
821 }
822
823 if (!pass) {
824 u8 new_stencil = PerformStencilAction(stencil_test.action_stencil_fail, old_stencil, stencil_test.replacement_value);
825 SetStencil(x >> 4, y >> 4, new_stencil);
826 continue;
827 }
828 }
829
682 // TODO: Does depth indeed only get written even if depth testing is enabled? 830 // TODO: Does depth indeed only get written even if depth testing is enabled?
683 if (output_merger.depth_test_enable) { 831 if (output_merger.depth_test_enable) {
684 unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format); 832 unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format);
@@ -723,11 +871,22 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
723 break; 871 break;
724 } 872 }
725 873
726 if (!pass) 874 if (!pass) {
875 if (stencil_action_enable) {
876 u8 new_stencil = PerformStencilAction(stencil_test.action_depth_fail, old_stencil, stencil_test.replacement_value);
877 SetStencil(x >> 4, y >> 4, new_stencil);
878 }
727 continue; 879 continue;
880 }
728 881
729 if (output_merger.depth_write_enable) 882 if (output_merger.depth_write_enable)
730 SetDepth(x >> 4, y >> 4, z); 883 SetDepth(x >> 4, y >> 4, z);
884
885 if (stencil_action_enable) {
886 // TODO: What happens if stencil testing is enabled, but depth testing is not? Will stencil get updated anyway?
887 u8 new_stencil = PerformStencilAction(stencil_test.action_depth_pass, old_stencil, stencil_test.replacement_value);
888 SetStencil(x >> 4, y >> 4, new_stencil);
889 }
731 } 890 }
732 891
733 auto dest = GetPixel(x >> 4, y >> 4); 892 auto dest = GetPixel(x >> 4, y >> 4);
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 5757ac75d..6587bcf27 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -4,10 +4,14 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8 10
9#include "video_core/hwrasterizer_base.h" 11#include "video_core/hwrasterizer_base.h"
10 12
13class EmuWindow;
14
11class RendererBase : NonCopyable { 15class RendererBase : NonCopyable {
12public: 16public:
13 17
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 518f79331..2db845da6 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -2,10 +2,15 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
6#include <memory>
7
5#include "common/color.h" 8#include "common/color.h"
9#include "common/math_util.h"
6 10
7#include "core/settings.h"
8#include "core/hw/gpu.h" 11#include "core/hw/gpu.h"
12#include "core/memory.h"
13#include "core/settings.h"
9 14
10#include "video_core/pica.h" 15#include "video_core/pica.h"
11#include "video_core/utils.h" 16#include "video_core/utils.h"
@@ -16,8 +21,6 @@
16 21
17#include "generated/gl_3_2_core.h" 22#include "generated/gl_3_2_core.h"
18 23
19#include <memory>
20
21static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) { 24static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
22 return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace && 25 return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace &&
23 stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace && 26 stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace &&
@@ -813,12 +816,16 @@ void RasterizerOpenGL::ReloadColorBuffer() {
813} 816}
814 817
815void RasterizerOpenGL::ReloadDepthBuffer() { 818void RasterizerOpenGL::ReloadDepthBuffer() {
819 PAddr depth_buffer_addr = Pica::g_state.regs.framebuffer.GetDepthBufferPhysicalAddress();
820
821 if (depth_buffer_addr == 0)
822 return;
823
816 // TODO: Appears to work, but double-check endianness of depth values and order of depth-stencil 824 // TODO: Appears to work, but double-check endianness of depth values and order of depth-stencil
817 u8* depth_buffer = Memory::GetPhysicalPointer(Pica::g_state.regs.framebuffer.GetDepthBufferPhysicalAddress()); 825 u8* depth_buffer = Memory::GetPhysicalPointer(depth_buffer_addr);
818 826
819 if (depth_buffer == nullptr) { 827 if (depth_buffer == nullptr)
820 return; 828 return;
821 }
822 829
823 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format); 830 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format);
824 831
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index d7d422b1f..ae7b26fc6 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -4,7 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <vector>
8
9#include "common/common_types.h"
10
7#include "video_core/hwrasterizer_base.h" 11#include "video_core/hwrasterizer_base.h"
12#include "video_core/vertex_shader.h"
8 13
9#include "gl_state.h" 14#include "gl_state.h"
10#include "gl_rasterizer_cache.h" 15#include "gl_rasterizer_cache.h"
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 2e4110a88..dc3ffdf22 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -31,12 +31,18 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, unsigned text
31 state.texture_units[texture_unit].texture_2d = new_texture->texture.handle; 31 state.texture_units[texture_unit].texture_2d = new_texture->texture.handle;
32 state.Apply(); 32 state.Apply();
33 33
34 // TODO: Need to choose filters that correspond to PICA once register is declared 34 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, PicaToGL::TextureFilterMode(config.config.mag_filter));
35 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 35 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, PicaToGL::TextureFilterMode(config.config.min_filter));
36 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
37 36
38 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, PicaToGL::WrapMode(config.config.wrap_s)); 37 GLenum wrap_s = PicaToGL::WrapMode(config.config.wrap_s);
39 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, PicaToGL::WrapMode(config.config.wrap_t)); 38 GLenum wrap_t = PicaToGL::WrapMode(config.config.wrap_t);
39 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s);
40 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t);
41
42 if (wrap_s == GL_CLAMP_TO_BORDER || wrap_t == GL_CLAMP_TO_BORDER) {
43 auto border_color = PicaToGL::ColorRGBA8((u8*)&config.config.border_color.r);
44 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color.data());
45 }
40 46
41 const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format); 47 const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format);
42 48
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp
deleted file mode 100644
index 8f4ae28a4..000000000
--- a/src/video_core/renderer_opengl/gl_resource_manager.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "video_core/renderer_opengl/gl_resource_manager.h"
6#include "video_core/renderer_opengl/gl_shader_util.h"
7
8// Textures
9OGLTexture::OGLTexture() : handle(0) {
10}
11
12OGLTexture::~OGLTexture() {
13 Release();
14}
15
16void OGLTexture::Create() {
17 if (handle != 0) {
18 return;
19 }
20
21 glGenTextures(1, &handle);
22}
23
24void OGLTexture::Release() {
25 glDeleteTextures(1, &handle);
26 handle = 0;
27}
28
29// Shaders
30OGLShader::OGLShader() : handle(0) {
31}
32
33OGLShader::~OGLShader() {
34 Release();
35}
36
37void OGLShader::Create(const char* vert_shader, const char* frag_shader) {
38 if (handle != 0) {
39 return;
40 }
41
42 handle = ShaderUtil::LoadShaders(vert_shader, frag_shader);
43}
44
45void OGLShader::Release() {
46 glDeleteProgram(handle);
47 handle = 0;
48}
49
50// Buffer objects
51OGLBuffer::OGLBuffer() : handle(0) {
52}
53
54OGLBuffer::~OGLBuffer() {
55 Release();
56}
57
58void OGLBuffer::Create() {
59 if (handle != 0) {
60 return;
61 }
62
63 glGenBuffers(1, &handle);
64}
65
66void OGLBuffer::Release() {
67 glDeleteBuffers(1, &handle);
68 handle = 0;
69}
70
71// Vertex array objects
72OGLVertexArray::OGLVertexArray() : handle(0) {
73}
74
75OGLVertexArray::~OGLVertexArray() {
76 Release();
77}
78
79void OGLVertexArray::Create() {
80 if (handle != 0) {
81 return;
82 }
83
84 glGenVertexArrays(1, &handle);
85}
86
87void OGLVertexArray::Release() {
88 glDeleteVertexArrays(1, &handle);
89 handle = 0;
90}
91
92// Framebuffers
93OGLFramebuffer::OGLFramebuffer() : handle(0) {
94}
95
96OGLFramebuffer::~OGLFramebuffer() {
97 Release();
98}
99
100void OGLFramebuffer::Create() {
101 if (handle != 0) {
102 return;
103 }
104
105 glGenFramebuffers(1, &handle);
106}
107
108void OGLFramebuffer::Release() {
109 glDeleteFramebuffers(1, &handle);
110 handle = 0;
111}
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h
index 975720d0a..6f9dc012d 100644
--- a/src/video_core/renderer_opengl/gl_resource_manager.h
+++ b/src/video_core/renderer_opengl/gl_resource_manager.h
@@ -4,76 +4,124 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <utility>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8 10
9#include "generated/gl_3_2_core.h" 11#include "video_core/renderer_opengl/generated/gl_3_2_core.h"
12#include "video_core/renderer_opengl/gl_shader_util.h"
10 13
11class OGLTexture : public NonCopyable { 14class OGLTexture : private NonCopyable {
12public: 15public:
13 OGLTexture(); 16 OGLTexture() = default;
14 ~OGLTexture(); 17 OGLTexture(OGLTexture&& o) { std::swap(handle, o.handle); }
18 ~OGLTexture() { Release(); }
19 OGLTexture& operator=(OGLTexture&& o) { std::swap(handle, o.handle); return *this; }
15 20
16 /// Creates a new internal OpenGL resource and stores the handle 21 /// Creates a new internal OpenGL resource and stores the handle
17 void Create(); 22 void Create() {
23 if (handle != 0) return;
24 glGenTextures(1, &handle);
25 }
18 26
19 /// Deletes the internal OpenGL resource 27 /// Deletes the internal OpenGL resource
20 void Release(); 28 void Release() {
29 if (handle == 0) return;
30 glDeleteTextures(1, &handle);
31 handle = 0;
32 }
21 33
22 GLuint handle; 34 GLuint handle = 0;
23}; 35};
24 36
25class OGLShader : public NonCopyable { 37class OGLShader : private NonCopyable {
26public: 38public:
27 OGLShader(); 39 OGLShader() = default;
28 ~OGLShader(); 40 OGLShader(OGLShader&& o) { std::swap(handle, o.handle); }
41 ~OGLShader() { Release(); }
42 OGLShader& operator=(OGLShader&& o) { std::swap(handle, o.handle); return *this; }
29 43
30 /// Creates a new internal OpenGL resource and stores the handle 44 /// Creates a new internal OpenGL resource and stores the handle
31 void Create(const char* vert_shader, const char* frag_shader); 45 void Create(const char* vert_shader, const char* frag_shader) {
46 if (handle != 0) return;
47 handle = ShaderUtil::LoadShaders(vert_shader, frag_shader);
48 }
32 49
33 /// Deletes the internal OpenGL resource 50 /// Deletes the internal OpenGL resource
34 void Release(); 51 void Release() {
52 if (handle == 0) return;
53 glDeleteProgram(handle);
54 handle = 0;
55 }
35 56
36 GLuint handle; 57 GLuint handle = 0;
37}; 58};
38 59
39class OGLBuffer : public NonCopyable { 60class OGLBuffer : private NonCopyable {
40public: 61public:
41 OGLBuffer(); 62 OGLBuffer() = default;
42 ~OGLBuffer(); 63 OGLBuffer(OGLBuffer&& o) { std::swap(handle, o.handle); }
64 ~OGLBuffer() { Release(); }
65 OGLBuffer& operator=(OGLBuffer&& o) { std::swap(handle, o.handle); return *this; }
43 66
44 /// Creates a new internal OpenGL resource and stores the handle 67 /// Creates a new internal OpenGL resource and stores the handle
45 void Create(); 68 void Create() {
69 if (handle != 0) return;
70 glGenBuffers(1, &handle);
71 }
46 72
47 /// Deletes the internal OpenGL resource 73 /// Deletes the internal OpenGL resource
48 void Release(); 74 void Release() {
75 if (handle == 0) return;
76 glDeleteBuffers(1, &handle);
77 handle = 0;
78 }
49 79
50 GLuint handle; 80 GLuint handle = 0;
51}; 81};
52 82
53class OGLVertexArray : public NonCopyable { 83class OGLVertexArray : private NonCopyable {
54public: 84public:
55 OGLVertexArray(); 85 OGLVertexArray() = default;
56 ~OGLVertexArray(); 86 OGLVertexArray(OGLVertexArray&& o) { std::swap(handle, o.handle); }
87 ~OGLVertexArray() { Release(); }
88 OGLVertexArray& operator=(OGLVertexArray&& o) { std::swap(handle, o.handle); return *this; }
57 89
58 /// Creates a new internal OpenGL resource and stores the handle 90 /// Creates a new internal OpenGL resource and stores the handle
59 void Create(); 91 void Create() {
92 if (handle != 0) return;
93 glGenVertexArrays(1, &handle);
94 }
60 95
61 /// Deletes the internal OpenGL resource 96 /// Deletes the internal OpenGL resource
62 void Release(); 97 void Release() {
98 if (handle == 0) return;
99 glDeleteVertexArrays(1, &handle);
100 handle = 0;
101 }
63 102
64 GLuint handle; 103 GLuint handle = 0;
65}; 104};
66 105
67class OGLFramebuffer : public NonCopyable { 106class OGLFramebuffer : private NonCopyable {
68public: 107public:
69 OGLFramebuffer(); 108 OGLFramebuffer() = default;
70 ~OGLFramebuffer(); 109 OGLFramebuffer(OGLFramebuffer&& o) { std::swap(handle, o.handle); }
110 ~OGLFramebuffer() { Release(); }
111 OGLFramebuffer& operator=(OGLFramebuffer&& o) { std::swap(handle, o.handle); return *this; }
71 112
72 /// Creates a new internal OpenGL resource and stores the handle 113 /// Creates a new internal OpenGL resource and stores the handle
73 void Create(); 114 void Create() {
115 if (handle != 0) return;
116 glGenFramebuffers(1, &handle);
117 }
74 118
75 /// Deletes the internal OpenGL resource 119 /// Deletes the internal OpenGL resource
76 void Release(); 120 void Release() {
121 if (handle == 0) return;
122 glDeleteFramebuffers(1, &handle);
123 handle = 0;
124 }
77 125
78 GLuint handle; 126 GLuint handle = 0;
79}; 127};
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 3526e16d5..9efc15337 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -147,20 +147,17 @@ void OpenGLState::Apply() {
147 147
148 // Textures 148 // Textures
149 for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) { 149 for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) {
150 if (texture_units[texture_index].enabled_2d != cur_state.texture_units[texture_index].enabled_2d) { 150 if (texture_units[texture_index].enabled_2d != cur_state.texture_units[texture_index].enabled_2d ||
151 texture_units[texture_index].texture_2d != cur_state.texture_units[texture_index].texture_2d) {
152
151 glActiveTexture(GL_TEXTURE0 + texture_index); 153 glActiveTexture(GL_TEXTURE0 + texture_index);
152 154
153 if (texture_units[texture_index].enabled_2d) { 155 if (texture_units[texture_index].enabled_2d) {
154 glEnable(GL_TEXTURE_2D); 156 glBindTexture(GL_TEXTURE_2D, texture_units[texture_index].texture_2d);
155 } else { 157 } else {
156 glDisable(GL_TEXTURE_2D); 158 glBindTexture(GL_TEXTURE_2D, 0);
157 } 159 }
158 } 160 }
159
160 if (texture_units[texture_index].texture_2d != cur_state.texture_units[texture_index].texture_2d) {
161 glActiveTexture(GL_TEXTURE0 + texture_index);
162 glBindTexture(GL_TEXTURE_2D, texture_units[texture_index].texture_2d);
163 }
164 } 161 }
165 162
166 // Framebuffer 163 // Framebuffer
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h
index e566f9f7a..3b562da86 100644
--- a/src/video_core/renderer_opengl/pica_to_gl.h
+++ b/src/video_core/renderer_opengl/pica_to_gl.h
@@ -12,10 +12,37 @@
12 12
13namespace PicaToGL { 13namespace PicaToGL {
14 14
15inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) {
16 static const GLenum filter_mode_table[] = {
17 GL_NEAREST, // TextureFilter::Nearest
18 GL_LINEAR // TextureFilter::Linear
19 };
20
21 // Range check table for input
22 if (mode >= ARRAY_SIZE(filter_mode_table)) {
23 LOG_CRITICAL(Render_OpenGL, "Unknown texture filtering mode %d", mode);
24 UNREACHABLE();
25
26 return GL_LINEAR;
27 }
28
29 GLenum gl_mode = filter_mode_table[mode];
30
31 // Check for dummy values indicating an unknown mode
32 if (gl_mode == 0) {
33 LOG_CRITICAL(Render_OpenGL, "Unknown texture filtering mode %d", mode);
34 UNIMPLEMENTED();
35
36 return GL_LINEAR;
37 }
38
39 return gl_mode;
40}
41
15inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) { 42inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) {
16 static const GLenum wrap_mode_table[] = { 43 static const GLenum wrap_mode_table[] = {
17 GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge 44 GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge
18 0, // Unknown 45 GL_CLAMP_TO_BORDER,// WrapMode::ClampToBorder
19 GL_REPEAT, // WrapMode::Repeat 46 GL_REPEAT, // WrapMode::Repeat
20 GL_MIRRORED_REPEAT // WrapMode::MirroredRepeat 47 GL_MIRRORED_REPEAT // WrapMode::MirroredRepeat
21 }; 48 };
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 3399ca123..96e12839a 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -2,22 +2,27 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <cstddef>
7#include <cstdlib>
8
9#include "common/assert.h"
10#include "common/emu_window.h"
11#include "common/logging/log.h"
12#include "common/profiler_reporting.h"
13
5#include "core/hw/gpu.h" 14#include "core/hw/gpu.h"
6#include "core/hw/hw.h" 15#include "core/hw/hw.h"
7#include "core/hw/lcd.h" 16#include "core/hw/lcd.h"
8#include "core/memory.h" 17#include "core/memory.h"
9#include "core/settings.h" 18#include "core/settings.h"
10 19
11#include "common/emu_window.h"
12#include "common/logging/log.h"
13#include "common/profiler_reporting.h"
14
15#include "video_core/video_core.h" 20#include "video_core/video_core.h"
16#include "video_core/renderer_opengl/renderer_opengl.h" 21#include "video_core/renderer_opengl/renderer_opengl.h"
17#include "video_core/renderer_opengl/gl_shader_util.h" 22#include "video_core/renderer_opengl/gl_shader_util.h"
18#include "video_core/renderer_opengl/gl_shaders.h" 23#include "video_core/renderer_opengl/gl_shaders.h"
19 24
20#include <algorithm> 25#include "video_core/debug_utils/debug_utils.h"
21 26
22/** 27/**
23 * Vertex structure that the drawn screen rectangles are composed of. 28 * Vertex structure that the drawn screen rectangles are composed of.
@@ -126,6 +131,10 @@ void RendererOpenGL::SwapBuffers() {
126 hw_rasterizer->Reset(); 131 hw_rasterizer->Reset();
127 } 132 }
128 } 133 }
134
135 if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
136 Pica::g_debug_context->recorder->FrameFinished();
137 }
129} 138}
130 139
131/** 140/**
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp
index 87006a832..960ae5779 100644
--- a/src/video_core/vertex_shader.cpp
+++ b/src/video_core/vertex_shader.cpp
@@ -2,8 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <stack> 5#include <boost/container/static_vector.hpp>
6
7#include <boost/range/algorithm.hpp> 6#include <boost/range/algorithm.hpp>
8 7
9#include <common/file_util.h> 8#include <common/file_util.h>
@@ -27,7 +26,7 @@ namespace Pica {
27namespace VertexShader { 26namespace VertexShader {
28 27
29struct VertexShaderState { 28struct VertexShaderState {
30 const u32* program_counter; 29 u32 program_counter;
31 30
32 const float24* input_register_table[16]; 31 const float24* input_register_table[16];
33 Math::Vec4<float24> output_registers[16]; 32 Math::Vec4<float24> output_registers[16];
@@ -53,7 +52,7 @@ struct VertexShaderState {
53 }; 52 };
54 53
55 // TODO: Is there a maximal size for this? 54 // TODO: Is there a maximal size for this?
56 std::stack<CallStackElement> call_stack; 55 boost::container::static_vector<CallStackElement, 16> call_stack;
57 56
58 struct { 57 struct {
59 u32 max_offset; // maximum program counter ever reached 58 u32 max_offset; // maximum program counter ever reached
@@ -71,15 +70,15 @@ static void ProcessShaderCode(VertexShaderState& state) {
71 70
72 while (true) { 71 while (true) {
73 if (!state.call_stack.empty()) { 72 if (!state.call_stack.empty()) {
74 auto& top = state.call_stack.top(); 73 auto& top = state.call_stack.back();
75 if (state.program_counter - program_code.data() == top.final_address) { 74 if (state.program_counter == top.final_address) {
76 state.address_registers[2] += top.loop_increment; 75 state.address_registers[2] += top.loop_increment;
77 76
78 if (top.repeat_counter-- == 0) { 77 if (top.repeat_counter-- == 0) {
79 state.program_counter = &program_code[top.return_address]; 78 state.program_counter = top.return_address;
80 state.call_stack.pop(); 79 state.call_stack.pop_back();
81 } else { 80 } else {
82 state.program_counter = &program_code[top.loop_address]; 81 state.program_counter = top.loop_address;
83 } 82 }
84 83
85 // TODO: Is "trying again" accurate to hardware? 84 // TODO: Is "trying again" accurate to hardware?
@@ -88,17 +87,16 @@ static void ProcessShaderCode(VertexShaderState& state) {
88 } 87 }
89 88
90 bool exit_loop = false; 89 bool exit_loop = false;
91 const Instruction& instr = *(const Instruction*)state.program_counter; 90 const Instruction instr = { program_code[state.program_counter] };
92 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id]; 91 const SwizzlePattern swizzle = { swizzle_data[instr.common.operand_desc_id] };
93 92
94 static auto call = [&program_code](VertexShaderState& state, u32 offset, u32 num_instructions, 93 static auto call = [](VertexShaderState& state, u32 offset, u32 num_instructions,
95 u32 return_offset, u8 repeat_count, u8 loop_increment) { 94 u32 return_offset, u8 repeat_count, u8 loop_increment) {
96 state.program_counter = &program_code[offset] - 1; // -1 to make sure when incrementing the PC we end up at the correct offset 95 state.program_counter = offset - 1; // -1 to make sure when incrementing the PC we end up at the correct offset
97 state.call_stack.push({ offset + num_instructions, return_offset, repeat_count, loop_increment, offset }); 96 ASSERT(state.call_stack.size() < state.call_stack.capacity());
97 state.call_stack.push_back({ offset + num_instructions, return_offset, repeat_count, loop_increment, offset });
98 }; 98 };
99 u32 binary_offset = state.program_counter - program_code.data(); 99 state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + state.program_counter);
100
101 state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + binary_offset);
102 100
103 auto LookupSourceRegister = [&](const SourceRegister& source_reg) -> const float24* { 101 auto LookupSourceRegister = [&](const SourceRegister& source_reg) -> const float24* {
104 switch (source_reg.GetRegisterType()) { 102 switch (source_reg.GetRegisterType()) {
@@ -221,7 +219,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
221 for (int i = 0; i < num_components; ++i) 219 for (int i = 0; i < num_components; ++i)
222 dot = dot + src1[i] * src2[i]; 220 dot = dot + src1[i] * src2[i];
223 221
224 for (int i = 0; i < num_components; ++i) { 222 for (int i = 0; i < 4; ++i) {
225 if (!swizzle.DestComponentEnabled(i)) 223 if (!swizzle.DestComponentEnabled(i))
226 continue; 224 continue;
227 225
@@ -442,13 +440,13 @@ static void ProcessShaderCode(VertexShaderState& state) {
442 440
443 case OpCode::Id::JMPC: 441 case OpCode::Id::JMPC:
444 if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) { 442 if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) {
445 state.program_counter = &program_code[instr.flow_control.dest_offset] - 1; 443 state.program_counter = instr.flow_control.dest_offset - 1;
446 } 444 }
447 break; 445 break;
448 446
449 case OpCode::Id::JMPU: 447 case OpCode::Id::JMPU:
450 if (uniforms.b[instr.flow_control.bool_uniform_id]) { 448 if (uniforms.b[instr.flow_control.bool_uniform_id]) {
451 state.program_counter = &program_code[instr.flow_control.dest_offset] - 1; 449 state.program_counter = instr.flow_control.dest_offset - 1;
452 } 450 }
453 break; 451 break;
454 452
@@ -456,7 +454,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
456 call(state, 454 call(state,
457 instr.flow_control.dest_offset, 455 instr.flow_control.dest_offset,
458 instr.flow_control.num_instructions, 456 instr.flow_control.num_instructions,
459 binary_offset + 1, 0, 0); 457 state.program_counter + 1, 0, 0);
460 break; 458 break;
461 459
462 case OpCode::Id::CALLU: 460 case OpCode::Id::CALLU:
@@ -464,7 +462,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
464 call(state, 462 call(state,
465 instr.flow_control.dest_offset, 463 instr.flow_control.dest_offset,
466 instr.flow_control.num_instructions, 464 instr.flow_control.num_instructions,
467 binary_offset + 1, 0, 0); 465 state.program_counter + 1, 0, 0);
468 } 466 }
469 break; 467 break;
470 468
@@ -473,7 +471,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
473 call(state, 471 call(state,
474 instr.flow_control.dest_offset, 472 instr.flow_control.dest_offset,
475 instr.flow_control.num_instructions, 473 instr.flow_control.num_instructions,
476 binary_offset + 1, 0, 0); 474 state.program_counter + 1, 0, 0);
477 } 475 }
478 break; 476 break;
479 477
@@ -483,8 +481,8 @@ static void ProcessShaderCode(VertexShaderState& state) {
483 case OpCode::Id::IFU: 481 case OpCode::Id::IFU:
484 if (uniforms.b[instr.flow_control.bool_uniform_id]) { 482 if (uniforms.b[instr.flow_control.bool_uniform_id]) {
485 call(state, 483 call(state,
486 binary_offset + 1, 484 state.program_counter + 1,
487 instr.flow_control.dest_offset - binary_offset - 1, 485 instr.flow_control.dest_offset - state.program_counter - 1,
488 instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0); 486 instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0);
489 } else { 487 } else {
490 call(state, 488 call(state,
@@ -501,8 +499,8 @@ static void ProcessShaderCode(VertexShaderState& state) {
501 499
502 if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) { 500 if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) {
503 call(state, 501 call(state,
504 binary_offset + 1, 502 state.program_counter + 1,
505 instr.flow_control.dest_offset - binary_offset - 1, 503 instr.flow_control.dest_offset - state.program_counter - 1,
506 instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0); 504 instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0);
507 } else { 505 } else {
508 call(state, 506 call(state,
@@ -519,8 +517,8 @@ static void ProcessShaderCode(VertexShaderState& state) {
519 state.address_registers[2] = uniforms.i[instr.flow_control.int_uniform_id].y; 517 state.address_registers[2] = uniforms.i[instr.flow_control.int_uniform_id].y;
520 518
521 call(state, 519 call(state,
522 binary_offset + 1, 520 state.program_counter + 1,
523 instr.flow_control.dest_offset - binary_offset + 1, 521 instr.flow_control.dest_offset - state.program_counter + 1,
524 instr.flow_control.dest_offset + 1, 522 instr.flow_control.dest_offset + 1,
525 uniforms.i[instr.flow_control.int_uniform_id].x, 523 uniforms.i[instr.flow_control.int_uniform_id].x,
526 uniforms.i[instr.flow_control.int_uniform_id].z); 524 uniforms.i[instr.flow_control.int_uniform_id].z);
@@ -546,20 +544,17 @@ static void ProcessShaderCode(VertexShaderState& state) {
546 544
547static Common::Profiling::TimingCategory shader_category("Vertex Shader"); 545static Common::Profiling::TimingCategory shader_category("Vertex Shader");
548 546
549OutputVertex RunShader(const InputVertex& input, int num_attributes) { 547OutputVertex RunShader(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const State::ShaderSetup& setup) {
550 Common::Profiling::ScopeTimer timer(shader_category); 548 Common::Profiling::ScopeTimer timer(shader_category);
551 549
552 const auto& regs = g_state.regs;
553 const auto& vs = g_state.vs;
554 VertexShaderState state; 550 VertexShaderState state;
555 551
556 const u32* main = &vs.program_code[regs.vs_main_offset]; 552 state.program_counter = config.main_offset;
557 state.program_counter = (u32*)main;
558 state.debug.max_offset = 0; 553 state.debug.max_offset = 0;
559 state.debug.max_opdesc_id = 0; 554 state.debug.max_opdesc_id = 0;
560 555
561 // Setup input register table 556 // Setup input register table
562 const auto& attribute_register_map = regs.vs_input_register_map; 557 const auto& attribute_register_map = config.input_register_map;
563 float24 dummy_register; 558 float24 dummy_register;
564 boost::fill(state.input_register_table, &dummy_register); 559 boost::fill(state.input_register_table, &dummy_register);
565 560
@@ -584,16 +579,18 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes) {
584 state.conditional_code[1] = false; 579 state.conditional_code[1] = false;
585 580
586 ProcessShaderCode(state); 581 ProcessShaderCode(state);
587 DebugUtils::DumpShader(vs.program_code.data(), state.debug.max_offset, vs.swizzle_data.data(), 582#if PICA_DUMP_SHADERS
588 state.debug.max_opdesc_id, regs.vs_main_offset, 583 DebugUtils::DumpShader(setup.program_code.data(), state.debug.max_offset, setup.swizzle_data.data(),
589 regs.vs_output_attributes); 584 state.debug.max_opdesc_id, config.main_offset,
585 g_state.regs.vs_output_attributes); // TODO: Don't hardcode VS here
586#endif
590 587
591 // Setup output data 588 // Setup output data
592 OutputVertex ret; 589 OutputVertex ret;
593 // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to 590 // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to
594 // figure out what those circumstances are and enable the remaining outputs then. 591 // figure out what those circumstances are and enable the remaining outputs then.
595 for (int i = 0; i < 7; ++i) { 592 for (int i = 0; i < 7; ++i) {
596 const auto& output_register_map = regs.vs_output_attributes[i]; 593 const auto& output_register_map = g_state.regs.vs_output_attributes[i]; // TODO: Don't hardcode VS here
597 594
598 u32 semantics[4] = { 595 u32 semantics[4] = {
599 output_register_map.map_x, output_register_map.map_y, 596 output_register_map.map_x, output_register_map.map_y,
diff --git a/src/video_core/vertex_shader.h b/src/video_core/vertex_shader.h
index 7471a6de8..97f9250dd 100644
--- a/src/video_core/vertex_shader.h
+++ b/src/video_core/vertex_shader.h
@@ -4,11 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <initializer_list> 7#include <type_traits>
8 8
9#include <common/common_types.h> 9#include "common/vector_math.h"
10 10
11#include "math.h"
12#include "pica.h" 11#include "pica.h"
13 12
14namespace Pica { 13namespace Pica {
@@ -66,7 +65,7 @@ struct OutputVertex {
66static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); 65static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD");
67static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size"); 66static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size");
68 67
69OutputVertex RunShader(const InputVertex& input, int num_attributes); 68OutputVertex RunShader(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const State::ShaderSetup& setup);
70 69
71} // namespace 70} // namespace
72 71
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h
index 3f24df7bd..14b33c9dd 100644
--- a/src/video_core/video_core.h
+++ b/src/video_core/video_core.h
@@ -4,12 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/emu_window.h"
8
9#include "renderer_base.h"
10
11#include <atomic> 7#include <atomic>
12 8
9class EmuWindow;
10class RendererBase;
11
13//////////////////////////////////////////////////////////////////////////////////////////////////// 12////////////////////////////////////////////////////////////////////////////////////////////////////
14// Video Core namespace 13// Video Core namespace
15 14