aboutsummaryrefslogtreecommitdiffhomepage
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 713f4919..91868731 100644
--- a/src/citra/CMakeLists.txt
+++ b/src/citra/CMakeLists.txt
@@ -16,6 +16,11 @@ create_directory_groups(${SRCS} ${HEADERS})
add_executable(citra ${SRCS} ${HEADERS})
target_link_libraries(citra core common video_core)
target_link_libraries(citra ${GLFW_LIBRARIES} ${OPENGL_gl_LIBRARY} inih)
+if (MSVC)
+ target_link_libraries(citra getopt)
+endif()
target_link_libraries(citra ${PLATFORM_LIBRARIES})
-#install(TARGETS citra RUNTIME DESTINATION ${bindir})
+if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|FreeBSD|OpenBSD|NetBSD")
+ install(TARGETS citra RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
+endif() \ No newline at end of file
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp
index ce8d7dd2..182646f4 100644
--- a/src/citra/citra.cpp
+++ b/src/citra/citra.cpp
@@ -2,13 +2,20 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <string>
#include <thread>
+#include <iostream>
+
+#ifdef _MSC_VER
+#include <getopt.h>
+#else
+#include <unistd.h>
+#include <getopt.h>
+#endif
#include "common/logging/log.h"
-#include "common/logging/text_formatter.h"
#include "common/logging/backend.h"
#include "common/logging/filter.h"
-#include "common/scope_exit.h"
#include "core/settings.h"
#include "core/system.h"
@@ -20,12 +27,39 @@
#include "video_core/video_core.h"
+
+static void PrintHelp()
+{
+ std::cout << "Usage: citra <filename>" << std::endl;
+}
+
/// Application entry point
int main(int argc, char **argv) {
+ int option_index = 0;
+ std::string boot_filename;
+ static struct option long_options[] = {
+ { "help", no_argument, 0, 'h' },
+ { 0, 0, 0, 0 }
+ };
+
+ while (optind < argc) {
+ char arg = getopt_long(argc, argv, ":h", long_options, &option_index);
+ if (arg != -1) {
+ switch (arg) {
+ case 'h':
+ PrintHelp();
+ return 0;
+ }
+ } else {
+ boot_filename = argv[optind];
+ optind++;
+ }
+ }
+
Log::Filter log_filter(Log::Level::Debug);
Log::SetFilter(&log_filter);
- if (argc < 2) {
+ if (boot_filename.empty()) {
LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified");
return -1;
}
@@ -33,7 +67,7 @@ int main(int argc, char **argv) {
Config config;
log_filter.ParseFilterString(Settings::values.log_filter);
- std::string boot_filename = argv[1];
+
EmuWindow_GLFW* emu_window = new EmuWindow_GLFW;
VideoCore::g_hw_renderer_enabled = Settings::values.use_hw_renderer;
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index 1378567c..2c1407a6 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -2,7 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
+#include <inih/cpp/INIReader.h>
#include "citra/default_ini.h"
@@ -10,7 +12,6 @@
#include "common/logging/log.h"
#include "core/settings.h"
-#include "core/core.h"
#include "config.h"
@@ -39,31 +40,21 @@ bool Config::LoadINI(INIReader* config, const char* location, const std::string&
return true;
}
+static const std::array<int, Settings::NativeInput::NUM_INPUTS> defaults = {
+ GLFW_KEY_A, GLFW_KEY_S, GLFW_KEY_Z, GLFW_KEY_X,
+ GLFW_KEY_Q, GLFW_KEY_W, GLFW_KEY_1, GLFW_KEY_2,
+ GLFW_KEY_M, GLFW_KEY_N, GLFW_KEY_B,
+ GLFW_KEY_T, GLFW_KEY_G, GLFW_KEY_F, GLFW_KEY_H,
+ GLFW_KEY_UP, GLFW_KEY_DOWN, GLFW_KEY_LEFT, GLFW_KEY_RIGHT,
+ GLFW_KEY_I, GLFW_KEY_K, GLFW_KEY_J, GLFW_KEY_L
+};
+
void Config::ReadValues() {
// Controls
- Settings::values.pad_a_key = glfw_config->GetInteger("Controls", "pad_a", GLFW_KEY_A);
- Settings::values.pad_b_key = glfw_config->GetInteger("Controls", "pad_b", GLFW_KEY_S);
- Settings::values.pad_x_key = glfw_config->GetInteger("Controls", "pad_x", GLFW_KEY_Z);
- Settings::values.pad_y_key = glfw_config->GetInteger("Controls", "pad_y", GLFW_KEY_X);
- Settings::values.pad_l_key = glfw_config->GetInteger("Controls", "pad_l", GLFW_KEY_Q);
- Settings::values.pad_r_key = glfw_config->GetInteger("Controls", "pad_r", GLFW_KEY_W);
- Settings::values.pad_zl_key = glfw_config->GetInteger("Controls", "pad_zl", GLFW_KEY_1);
- Settings::values.pad_zr_key = glfw_config->GetInteger("Controls", "pad_zr", GLFW_KEY_2);
- Settings::values.pad_start_key = glfw_config->GetInteger("Controls", "pad_start", GLFW_KEY_M);
- Settings::values.pad_select_key = glfw_config->GetInteger("Controls", "pad_select", GLFW_KEY_N);
- Settings::values.pad_home_key = glfw_config->GetInteger("Controls", "pad_home", GLFW_KEY_B);
- Settings::values.pad_dup_key = glfw_config->GetInteger("Controls", "pad_dup", GLFW_KEY_T);
- Settings::values.pad_ddown_key = glfw_config->GetInteger("Controls", "pad_ddown", GLFW_KEY_G);
- Settings::values.pad_dleft_key = glfw_config->GetInteger("Controls", "pad_dleft", GLFW_KEY_F);
- Settings::values.pad_dright_key = glfw_config->GetInteger("Controls", "pad_dright", GLFW_KEY_H);
- Settings::values.pad_sup_key = glfw_config->GetInteger("Controls", "pad_sup", GLFW_KEY_UP);
- Settings::values.pad_sdown_key = glfw_config->GetInteger("Controls", "pad_sdown", GLFW_KEY_DOWN);
- Settings::values.pad_sleft_key = glfw_config->GetInteger("Controls", "pad_sleft", GLFW_KEY_LEFT);
- Settings::values.pad_sright_key = glfw_config->GetInteger("Controls", "pad_sright", GLFW_KEY_RIGHT);
- Settings::values.pad_cup_key = glfw_config->GetInteger("Controls", "pad_cup", GLFW_KEY_I);
- Settings::values.pad_cdown_key = glfw_config->GetInteger("Controls", "pad_cdown", GLFW_KEY_K);
- Settings::values.pad_cleft_key = glfw_config->GetInteger("Controls", "pad_cleft", GLFW_KEY_J);
- Settings::values.pad_cright_key = glfw_config->GetInteger("Controls", "pad_cright", GLFW_KEY_L);
+ for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
+ Settings::values.input_mappings[Settings::NativeInput::All[i]] =
+ glfw_config->GetInteger("Controls", Settings::NativeInput::Mapping[i], defaults[i]);
+ }
// Core
Settings::values.frame_skip = glfw_config->GetInteger("Core", "frame_skip", 0);
diff --git a/src/citra/config.h b/src/citra/config.h
index 0eb176c7..c326ec66 100644
--- a/src/citra/config.h
+++ b/src/citra/config.h
@@ -4,11 +4,9 @@
#pragma once
-#include <map>
+#include <string>
-#include <inih/cpp/INIReader.h>
-
-#include "common/common_types.h"
+class INIReader;
class Config {
INIReader* glfw_config;
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index fd5a90d5..1925bece 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -33,10 +33,6 @@ pad_cleft =
pad_cright =
[Core]
-# The refresh rate for the GPU
-# Defaults to 30
-gpu_refresh_rate =
-
# The applied frameskip amount. Must be a power of two.
# 0 (default): No frameskip, 1: x2 frameskip, 2: x4 frameskip, 3: x8 frameskip, etc.
frame_skip =
diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp
index 341b48d2..6d6656b5 100644
--- a/src/citra/emu_window/emu_window_glfw.cpp
+++ b/src/citra/emu_window/emu_window_glfw.cpp
@@ -2,13 +2,25 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+#include <cstdlib>
+#include <string>
+
+// Let’s use our own GL header, instead of one from GLFW.
+#include "video_core/renderer_opengl/generated/gl_3_2_core.h"
+#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>
+#include "common/assert.h"
+#include "common/key_map.h"
#include "common/logging/log.h"
+#include "common/scm_rev.h"
+#include "common/string_util.h"
#include "video_core/video_core.h"
#include "core/settings.h"
+#include "core/hle/service/hid/hid.h"
#include "citra/emu_window/emu_window_glfw.h"
@@ -138,32 +150,9 @@ void EmuWindow_GLFW::DoneCurrent() {
}
void EmuWindow_GLFW::ReloadSetKeymaps() {
- KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, Service::HID::PAD_A);
- KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, Service::HID::PAD_B);
- KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, Service::HID::PAD_SELECT);
- KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, Service::HID::PAD_START);
- KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, Service::HID::PAD_RIGHT);
- KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, Service::HID::PAD_LEFT);
- KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, Service::HID::PAD_UP);
- KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, Service::HID::PAD_DOWN);
- KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, Service::HID::PAD_R);
- KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, Service::HID::PAD_L);
- KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, Service::HID::PAD_X);
- KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, Service::HID::PAD_Y);
-
- KeyMap::SetKeyMapping({Settings::values.pad_zl_key, keyboard_id}, Service::HID::PAD_ZL);
- KeyMap::SetKeyMapping({Settings::values.pad_zr_key, keyboard_id}, Service::HID::PAD_ZR);
-
- // KeyMap::SetKeyMapping({Settings::values.pad_touch_key, keyboard_id}, Service::HID::PAD_TOUCH);
-
- KeyMap::SetKeyMapping({Settings::values.pad_cright_key, keyboard_id}, Service::HID::PAD_C_RIGHT);
- KeyMap::SetKeyMapping({Settings::values.pad_cleft_key, keyboard_id}, Service::HID::PAD_C_LEFT);
- KeyMap::SetKeyMapping({Settings::values.pad_cup_key, keyboard_id}, Service::HID::PAD_C_UP);
- KeyMap::SetKeyMapping({Settings::values.pad_cdown_key, keyboard_id}, Service::HID::PAD_C_DOWN);
- KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, Service::HID::PAD_CIRCLE_RIGHT);
- KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, Service::HID::PAD_CIRCLE_LEFT);
- KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, Service::HID::PAD_CIRCLE_UP);
- KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, Service::HID::PAD_CIRCLE_DOWN);
+ for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
+ KeyMap::SetKeyMapping({Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id}, Service::HID::pad_mapping[i]);
+ }
}
void 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 16c109b7..7ccd5e6a 100644
--- a/src/citra/emu_window/emu_window_glfw.h
+++ b/src/citra/emu_window/emu_window_glfw.h
@@ -4,6 +4,8 @@
#pragma once
+#include <utility>
+
#include "common/emu_window.h"
struct GLFWwindow;
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index c2d1ad24..47aaeca2 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -12,6 +12,7 @@ set(SRCS
debugger/graphics_breakpoints.cpp
debugger/graphics_cmdlists.cpp
debugger/graphics_framebuffer.cpp
+ debugger/graphics_tracing.cpp
debugger/graphics_vertex_shader.cpp
debugger/profiler.cpp
debugger/ramview.cpp
@@ -35,6 +36,7 @@ set(HEADERS
debugger/graphics_breakpoints_p.h
debugger/graphics_cmdlists.h
debugger/graphics_framebuffer.h
+ debugger/graphics_tracing.h
debugger/graphics_vertex_shader.h
debugger/profiler.h
debugger/ramview.h
@@ -73,7 +75,9 @@ target_link_libraries(citra-qt core common video_core qhexedit)
target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS})
target_link_libraries(citra-qt ${PLATFORM_LIBRARIES})
-#install(TARGETS citra-qt RUNTIME DESTINATION ${bindir})
+if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|FreeBSD|OpenBSD|NetBSD")
+ install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
+endif()
if (Qt5_FOUND AND MSVC)
set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin")
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 3db09c65..b12bd858 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -11,6 +11,10 @@
#include "bootmanager.h"
#include "main.h"
+#include "common/string_util.h"
+#include "common/scm_rev.h"
+#include "common/key_map.h"
+
#include "core/core.h"
#include "core/settings.h"
#include "core/system.h"
@@ -61,7 +65,7 @@ void EmuThread::run() {
was_active = false;
} else {
std::unique_lock<std::mutex> lock(running_mutex);
- running_cv.wait(lock, [this]{ return IsRunning() || stop_run; });
+ running_cv.wait(lock, [this]{ return IsRunning() || exec_step || stop_run; });
}
}
@@ -244,32 +248,9 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent *event)
void GRenderWindow::ReloadSetKeymaps()
{
- KeyMap::SetKeyMapping({Settings::values.pad_a_key, keyboard_id}, Service::HID::PAD_A);
- KeyMap::SetKeyMapping({Settings::values.pad_b_key, keyboard_id}, Service::HID::PAD_B);
- KeyMap::SetKeyMapping({Settings::values.pad_select_key, keyboard_id}, Service::HID::PAD_SELECT);
- KeyMap::SetKeyMapping({Settings::values.pad_start_key, keyboard_id}, Service::HID::PAD_START);
- KeyMap::SetKeyMapping({Settings::values.pad_dright_key, keyboard_id}, Service::HID::PAD_RIGHT);
- KeyMap::SetKeyMapping({Settings::values.pad_dleft_key, keyboard_id}, Service::HID::PAD_LEFT);
- KeyMap::SetKeyMapping({Settings::values.pad_dup_key, keyboard_id}, Service::HID::PAD_UP);
- KeyMap::SetKeyMapping({Settings::values.pad_ddown_key, keyboard_id}, Service::HID::PAD_DOWN);
- KeyMap::SetKeyMapping({Settings::values.pad_r_key, keyboard_id}, Service::HID::PAD_R);
- KeyMap::SetKeyMapping({Settings::values.pad_l_key, keyboard_id}, Service::HID::PAD_L);
- KeyMap::SetKeyMapping({Settings::values.pad_x_key, keyboard_id}, Service::HID::PAD_X);
- KeyMap::SetKeyMapping({Settings::values.pad_y_key, keyboard_id}, Service::HID::PAD_Y);
-
- KeyMap::SetKeyMapping({Settings::values.pad_zl_key, keyboard_id}, Service::HID::PAD_ZL);
- KeyMap::SetKeyMapping({Settings::values.pad_zr_key, keyboard_id}, Service::HID::PAD_ZR);
-
- // KeyMap::SetKeyMapping({Settings::values.pad_touch_key, keyboard_id}, Service::HID::PAD_TOUCH);
-
- KeyMap::SetKeyMapping({Settings::values.pad_cright_key, keyboard_id}, Service::HID::PAD_C_RIGHT);
- KeyMap::SetKeyMapping({Settings::values.pad_cleft_key, keyboard_id}, Service::HID::PAD_C_LEFT);
- KeyMap::SetKeyMapping({Settings::values.pad_cup_key, keyboard_id}, Service::HID::PAD_C_UP);
- KeyMap::SetKeyMapping({Settings::values.pad_cdown_key, keyboard_id}, Service::HID::PAD_C_DOWN);
- KeyMap::SetKeyMapping({Settings::values.pad_sright_key, keyboard_id}, Service::HID::PAD_CIRCLE_RIGHT);
- KeyMap::SetKeyMapping({Settings::values.pad_sleft_key, keyboard_id}, Service::HID::PAD_CIRCLE_LEFT);
- KeyMap::SetKeyMapping({Settings::values.pad_sup_key, keyboard_id}, Service::HID::PAD_CIRCLE_UP);
- KeyMap::SetKeyMapping({Settings::values.pad_sdown_key, keyboard_id}, Service::HID::PAD_CIRCLE_DOWN);
+ for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
+ KeyMap::SetKeyMapping({Settings::values.input_mappings[Settings::NativeInput::All[i]], keyboard_id}, Service::HID::pad_mapping[i]);
+ }
}
void GRenderWindow::OnClientAreaResized(unsigned width, unsigned height)
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h
index 47512431..1a1e0e6a 100644
--- a/src/citra_qt/bootmanager.h
+++ b/src/citra_qt/bootmanager.h
@@ -35,7 +35,10 @@ public:
* Steps the emulation thread by a single CPU instruction (if the CPU is not already running)
* @note This function is thread-safe
*/
- void ExecStep() { exec_step = true; }
+ void ExecStep() {
+ exec_step = true;
+ running_cv.notify_all();
+ }
/**
* Sets whether the emulation thread is running or not
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index 2a9af1f3..5716634e 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -2,11 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <QSettings>
#include <QString>
#include <QStringList>
#include "core/settings.h"
-#include "core/core.h"
#include "common/file_util.h"
#include "config.h"
@@ -21,31 +21,21 @@ Config::Config() {
Reload();
}
+static const std::array<QVariant, Settings::NativeInput::NUM_INPUTS> defaults = {
+ Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X,
+ Qt::Key_Q, Qt::Key_W, Qt::Key_1, Qt::Key_2,
+ Qt::Key_M, Qt::Key_N, Qt::Key_B,
+ Qt::Key_T, Qt::Key_G, Qt::Key_F, Qt::Key_H,
+ Qt::Key_Up, Qt::Key_Down, Qt::Key_Left, Qt::Key_Right,
+ Qt::Key_I, Qt::Key_K, Qt::Key_J, Qt::Key_L
+};
+
void Config::ReadValues() {
qt_config->beginGroup("Controls");
- Settings::values.pad_a_key = qt_config->value("pad_a", Qt::Key_A).toInt();
- Settings::values.pad_b_key = qt_config->value("pad_b", Qt::Key_S).toInt();
- Settings::values.pad_x_key = qt_config->value("pad_x", Qt::Key_Z).toInt();
- Settings::values.pad_y_key = qt_config->value("pad_y", Qt::Key_X).toInt();
- Settings::values.pad_l_key = qt_config->value("pad_l", Qt::Key_Q).toInt();
- Settings::values.pad_r_key = qt_config->value("pad_r", Qt::Key_W).toInt();
- Settings::values.pad_zl_key = qt_config->value("pad_zl", Qt::Key_1).toInt();
- Settings::values.pad_zr_key = qt_config->value("pad_zr", Qt::Key_2).toInt();
- Settings::values.pad_start_key = qt_config->value("pad_start", Qt::Key_M).toInt();
- Settings::values.pad_select_key = qt_config->value("pad_select", Qt::Key_N).toInt();
- Settings::values.pad_home_key = qt_config->value("pad_home", Qt::Key_B).toInt();
- Settings::values.pad_dup_key = qt_config->value("pad_dup", Qt::Key_T).toInt();
- Settings::values.pad_ddown_key = qt_config->value("pad_ddown", Qt::Key_G).toInt();
- Settings::values.pad_dleft_key = qt_config->value("pad_dleft", Qt::Key_F).toInt();
- Settings::values.pad_dright_key = qt_config->value("pad_dright", Qt::Key_H).toInt();
- Settings::values.pad_sup_key = qt_config->value("pad_sup", Qt::Key_Up).toInt();
- Settings::values.pad_sdown_key = qt_config->value("pad_sdown", Qt::Key_Down).toInt();
- Settings::values.pad_sleft_key = qt_config->value("pad_sleft", Qt::Key_Left).toInt();
- Settings::values.pad_sright_key = qt_config->value("pad_sright", Qt::Key_Right).toInt();
- Settings::values.pad_cup_key = qt_config->value("pad_cup", Qt::Key_I).toInt();
- Settings::values.pad_cdown_key = qt_config->value("pad_cdown", Qt::Key_K).toInt();
- Settings::values.pad_cleft_key = qt_config->value("pad_cleft", Qt::Key_J).toInt();
- Settings::values.pad_cright_key = qt_config->value("pad_cright", Qt::Key_L).toInt();
+ for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
+ Settings::values.input_mappings[Settings::NativeInput::All[i]] =
+ qt_config->value(QString::fromStdString(Settings::NativeInput::Mapping[i]), defaults[i]).toInt();
+ }
qt_config->endGroup();
qt_config->beginGroup("Core");
@@ -75,29 +65,10 @@ void Config::ReadValues() {
void Config::SaveValues() {
qt_config->beginGroup("Controls");
- qt_config->setValue("pad_a", Settings::values.pad_a_key);
- qt_config->setValue("pad_b", Settings::values.pad_b_key);
- qt_config->setValue("pad_x", Settings::values.pad_x_key);
- qt_config->setValue("pad_y", Settings::values.pad_y_key);
- qt_config->setValue("pad_l", Settings::values.pad_l_key);
- qt_config->setValue("pad_r", Settings::values.pad_r_key);
- qt_config->setValue("pad_zl", Settings::values.pad_zl_key);
- qt_config->setValue("pad_zr", Settings::values.pad_zr_key);
- qt_config->setValue("pad_start", Settings::values.pad_start_key);
- qt_config->setValue("pad_select", Settings::values.pad_select_key);
- qt_config->setValue("pad_home", Settings::values.pad_home_key);
- qt_config->setValue("pad_dup", Settings::values.pad_dup_key);
- qt_config->setValue("pad_ddown", Settings::values.pad_ddown_key);
- qt_config->setValue("pad_dleft", Settings::values.pad_dleft_key);
- qt_config->setValue("pad_dright", Settings::values.pad_dright_key);
- qt_config->setValue("pad_sup", Settings::values.pad_sup_key);
- qt_config->setValue("pad_sdown", Settings::values.pad_sdown_key);
- qt_config->setValue("pad_sleft", Settings::values.pad_sleft_key);
- qt_config->setValue("pad_sright", Settings::values.pad_sright_key);
- qt_config->setValue("pad_cup", Settings::values.pad_cup_key);
- qt_config->setValue("pad_cdown", Settings::values.pad_cdown_key);
- qt_config->setValue("pad_cleft", Settings::values.pad_cleft_key);
- qt_config->setValue("pad_cright", Settings::values.pad_cright_key);
+ for (int i = 0; i < Settings::NativeInput::NUM_INPUTS; ++i) {
+ qt_config->setValue(QString::fromStdString(Settings::NativeInput::Mapping[i]),
+ Settings::values.input_mappings[Settings::NativeInput::All[i]]);
+ }
qt_config->endGroup();
qt_config->beginGroup("Core");
diff --git a/src/citra_qt/config.h b/src/citra_qt/config.h
index 4485cae7..dd0b2ef0 100644
--- a/src/citra_qt/config.h
+++ b/src/citra_qt/config.h
@@ -4,9 +4,9 @@
#pragma once
-#include <QSettings>
+#include <string>
-#include "common/common_types.h"
+class QSettings;
class Config {
QSettings* qt_config;
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp
index e99ec1b3..1e5ef529 100644
--- a/src/citra_qt/debugger/disassembler.cpp
+++ b/src/citra_qt/debugger/disassembler.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <QShortcut>
+
#include "disassembler.h"
#include "../bootmanager.h"
@@ -13,7 +15,6 @@
#include "common/break_points.h"
#include "common/symbols.h"
#include "core/arm/arm_interface.h"
-#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/disassembler/arm_disasm.h"
@@ -217,7 +218,7 @@ void DisassemblerWidget::OnToggleStartStop() {
}
void DisassemblerWidget::OnDebugModeEntered() {
- ARMword next_instr = Core::g_app_core->GetPC();
+ u32 next_instr = Core::g_app_core->GetPC();
if (model->GetBreakPoints().IsAddressBreakPoint(next_instr))
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 f0d3361f..02a0f4f4 100644
--- a/src/citra_qt/debugger/graphics_breakpoint_observer.h
+++ b/src/citra_qt/debugger/graphics_breakpoint_observer.h
@@ -13,7 +13,7 @@
* This is because the Pica breakpoint callbacks are called from a non-GUI thread, while
* the widget usually wants to perform reactions in the GUI thread.
*/
-class BreakPointObserverDock : public QDockWidget, private Pica::DebugContext::BreakPointObserver {
+class BreakPointObserverDock : public QDockWidget, protected Pica::DebugContext::BreakPointObserver {
Q_OBJECT
public:
diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp
index 1da64f61..5202c168 100644
--- a/src/citra_qt/debugger/graphics_breakpoints.cpp
+++ b/src/citra_qt/debugger/graphics_breakpoints.cpp
@@ -4,7 +4,7 @@
#include <QMetaType>
#include <QPushButton>
-#include <QTreeWidget>
+#include <QTreeView>
#include <QVBoxLayout>
#include <QLabel>
@@ -23,7 +23,7 @@ BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_conte
int BreakPointModel::columnCount(const QModelIndex& parent) const
{
- return 2;
+ return 1;
}
int BreakPointModel::rowCount(const QModelIndex& parent) const
@@ -38,29 +38,29 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const
switch (role) {
case Qt::DisplayRole:
{
- switch (index.column()) {
- case 0:
- {
+ if (index.column() == 0) {
static const std::map<Pica::DebugContext::Event, QString> map = {
- { Pica::DebugContext::Event::CommandLoaded, tr("Pica command loaded") },
- { Pica::DebugContext::Event::CommandProcessed, tr("Pica command processed") },
+ { Pica::DebugContext::Event::PicaCommandLoaded, tr("Pica command loaded") },
+ { Pica::DebugContext::Event::PicaCommandProcessed, tr("Pica command processed") },
{ Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch") },
{ Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch") },
- { Pica::DebugContext::Event::VertexLoaded, tr("Vertex loaded") }
+ { Pica::DebugContext::Event::VertexLoaded, tr("Vertex loaded") },
+ { Pica::DebugContext::Event::IncomingDisplayTransfer, tr("Incoming display transfer") },
+ { Pica::DebugContext::Event::GSPCommandProcessed, tr("GSP command processed") },
+ { Pica::DebugContext::Event::BufferSwapped, tr("Buffers swapped") }
};
DEBUG_ASSERT(map.size() == static_cast<size_t>(Pica::DebugContext::Event::NumEvents));
-
return (map.find(event) != map.end()) ? map.at(event) : QString();
}
- case 1:
- return data(index, Role_IsEnabled).toBool() ? tr("Enabled") : tr("Disabled");
-
- default:
- break;
- }
+ break;
+ }
+ case Qt::CheckStateRole:
+ {
+ if (index.column() == 0)
+ return data(index, Role_IsEnabled).toBool() ? Qt::Checked : Qt::Unchecked;
break;
}
@@ -84,37 +84,34 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const
return QVariant();
}
-QVariant BreakPointModel::headerData(int section, Qt::Orientation orientation, int role) const
+Qt::ItemFlags BreakPointModel::flags(const QModelIndex &index) const
{
- switch(role) {
- case Qt::DisplayRole:
- {
- if (section == 0) {
- return tr("Event");
- } else if (section == 1) {
- return tr("Status");
- }
-
- break;
- }
- }
+ if (!index.isValid())
+ return 0;
- return QVariant();
+ Qt::ItemFlags flags = Qt::ItemIsEnabled;
+ if (index.column() == 0)
+ flags |= Qt::ItemIsUserCheckable;
+ return flags;
}
+
bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
const auto event = static_cast<Pica::DebugContext::Event>(index.row());
switch (role) {
- case Role_IsEnabled:
+ case Qt::CheckStateRole:
{
+ if (index.column() != 0)
+ return false;
+
auto context = context_weak.lock();
if (!context)
return false;
- context->breakpoints[event].enabled = value.toBool();
- QModelIndex changed_index = createIndex(index.row(), 1);
+ context->breakpoints[event].enabled = value == Qt::Checked;
+ QModelIndex changed_index = createIndex(index.row(), 0);
emit dataChanged(changed_index, changed_index);
return true;
}
@@ -133,7 +130,7 @@ void BreakPointModel::OnBreakPointHit(Pica::DebugContext::Event event)
active_breakpoint = context->active_breakpoint;
at_breakpoint = context->at_breakpoint;
emit dataChanged(createIndex(static_cast<int>(event), 0),
- createIndex(static_cast<int>(event), 1));
+ createIndex(static_cast<int>(event), 0));
}
void BreakPointModel::OnResumed()
@@ -144,7 +141,7 @@ void BreakPointModel::OnResumed()
at_breakpoint = context->at_breakpoint;
emit dataChanged(createIndex(static_cast<int>(active_breakpoint), 0),
- createIndex(static_cast<int>(active_breakpoint), 1));
+ createIndex(static_cast<int>(active_breakpoint), 0));
active_breakpoint = context->active_breakpoint;
}
@@ -162,13 +159,15 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::Debug
breakpoint_model = new BreakPointModel(debug_context, this);
breakpoint_list = new QTreeView;
+ breakpoint_list->setRootIsDecorated(false);
+ breakpoint_list->setHeaderHidden(true);
breakpoint_list->setModel(breakpoint_model);
- toggle_breakpoint_button = new QPushButton(tr("Enable"));
- toggle_breakpoint_button->setEnabled(false);
-
qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event");
+ connect(breakpoint_list, SIGNAL(doubleClicked(const QModelIndex&)),
+ this, SLOT(OnItemDoubleClicked(const QModelIndex&)));
+
connect(resume_button, SIGNAL(clicked()), this, SLOT(OnResumeRequested()));
connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)),
@@ -184,11 +183,6 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::Debug
connect(this, SIGNAL(BreakPointsChanged(const QModelIndex&,const QModelIndex&)),
breakpoint_model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)));
- connect(breakpoint_list->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
- this, SLOT(OnBreakpointSelectionChanged(QModelIndex)));
-
- connect(toggle_breakpoint_button, SIGNAL(clicked()), this, SLOT(OnToggleBreakpointEnabled()));
-
QWidget* main_widget = new QWidget;
auto main_layout = new QVBoxLayout;
{
@@ -198,7 +192,6 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::Debug
main_layout->addLayout(sub_layout);
}
main_layout->addWidget(breakpoint_list);
- main_layout->addWidget(toggle_breakpoint_button);
main_widget->setLayout(main_layout);
setWidget(main_widget);
@@ -234,32 +227,15 @@ void GraphicsBreakPointsWidget::OnResumeRequested()
context->Resume();
}
-void GraphicsBreakPointsWidget::OnBreakpointSelectionChanged(const QModelIndex& index)
+void GraphicsBreakPointsWidget::OnItemDoubleClicked(const QModelIndex& index)
{
- if (!index.isValid()) {
- toggle_breakpoint_button->setEnabled(false);
+ if (!index.isValid())
return;
- }
- toggle_breakpoint_button->setEnabled(true);
- UpdateToggleBreakpointButton(index);
-}
-
-void GraphicsBreakPointsWidget::OnToggleBreakpointEnabled()
-{
- QModelIndex index = breakpoint_list->selectionModel()->currentIndex();
- bool new_state = !(breakpoint_model->data(index, BreakPointModel::Role_IsEnabled).toBool());
-
- breakpoint_model->setData(index, new_state,
- BreakPointModel::Role_IsEnabled);
- UpdateToggleBreakpointButton(index);
-}
-
-void GraphicsBreakPointsWidget::UpdateToggleBreakpointButton(const QModelIndex& index)
-{
- if (true == breakpoint_model->data(index, BreakPointModel::Role_IsEnabled).toBool()) {
- toggle_breakpoint_button->setText(tr("Disable"));
- } else {
- toggle_breakpoint_button->setText(tr("Enable"));
- }
+ QModelIndex check_index = breakpoint_list->model()->index(index.row(), 0);
+ QVariant enabled = breakpoint_list->model()->data(check_index, Qt::CheckStateRole);
+ QVariant new_state = Qt::Unchecked;
+ if (enabled == Qt::Unchecked)
+ new_state = Qt::Checked;
+ breakpoint_list->model()->setData(check_index, new_state, Qt::CheckStateRole);
}
diff --git a/src/citra_qt/debugger/graphics_breakpoints.h b/src/citra_qt/debugger/graphics_breakpoints.h
index 5b9ba324..d900729d 100644
--- a/src/citra_qt/debugger/graphics_breakpoints.h
+++ b/src/citra_qt/debugger/graphics_breakpoints.h
@@ -31,10 +31,9 @@ public:
public slots:
void OnBreakPointHit(Pica::DebugContext::Event event, void* data);
+ void OnItemDoubleClicked(const QModelIndex&);
void OnResumeRequested();
void OnResumed();
- void OnBreakpointSelectionChanged(const QModelIndex&);
- void OnToggleBreakpointEnabled();
signals:
void Resumed();
@@ -42,11 +41,8 @@ signals:
void BreakPointsChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
private:
- void UpdateToggleBreakpointButton(const QModelIndex& index);
-
QLabel* status_text;
QPushButton* resume_button;
- QPushButton* toggle_breakpoint_button;
BreakPointModel* breakpoint_model;
QTreeView* breakpoint_list;
diff --git a/src/citra_qt/debugger/graphics_breakpoints_p.h b/src/citra_qt/debugger/graphics_breakpoints_p.h
index 34e72e85..00d8d510 100644
--- a/src/citra_qt/debugger/graphics_breakpoints_p.h
+++ b/src/citra_qt/debugger/graphics_breakpoints_p.h
@@ -23,7 +23,7 @@ public:
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
- QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
+ Qt::ItemFlags flags(const QModelIndex &index) const;
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp
index cabf5fe0..7ac3ea54 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.cpp
+++ b/src/citra_qt/debugger/graphics_cmdlists.cpp
@@ -2,12 +2,15 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <QApplication>
+#include <QClipboard>
#include <QLabel>
#include <QListView>
#include <QMainWindow>
#include <QPushButton>
#include <QVBoxLayout>
#include <QTreeView>
+#include <QHeaderView>
#include <QSpinBox>
#include <QComboBox>
@@ -74,7 +77,7 @@ TextureInfoDockWidget::TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo
format_choice->addItem(tr("I8"));
format_choice->addItem(tr("A8"));
format_choice->addItem(tr("IA4"));
- format_choice->addItem(tr("UNK10"));
+ format_choice->addItem(tr("I4"));
format_choice->addItem(tr("A4"));
format_choice->addItem(tr("ETC1"));
format_choice->addItem(tr("ETC1A4"));
@@ -168,11 +171,11 @@ GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(p
}
int GPUCommandListModel::rowCount(const QModelIndex& parent) const {
- return pica_trace.writes.size();
+ return static_cast<int>(pica_trace.writes.size());
}
int GPUCommandListModel::columnCount(const QModelIndex& parent) const {
- return 2;
+ return 3;
}
QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const {
@@ -185,14 +188,13 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const {
if (role == Qt::DisplayRole) {
QString content;
- if (index.column() == 0) {
- QString content = QString::fromLatin1(Pica::Regs::GetCommandName(cmd.cmd_id).c_str());
- content.append(" ");
- return content;
- } else if (index.column() == 1) {
- QString content = QString("%1 ").arg(cmd.hex, 8, 16, QLatin1Char('0'));
- content.append(QString("%1 ").arg(val, 8, 16, QLatin1Char('0')));
- return content;
+ switch ( index.column() ) {
+ case 0:
+ return QString::fromLatin1(Pica::Regs::GetCommandName(cmd.cmd_id).c_str());
+ case 1:
+ return QString("%1").arg(cmd.cmd_id, 3, 16, QLatin1Char('0'));
+ case 2:
+ return QString("%1").arg(val, 8, 16, QLatin1Char('0'));
}
} else if (role == CommandIdRole) {
return QVariant::fromValue<int>(cmd.cmd_id.Value());
@@ -205,10 +207,13 @@ QVariant GPUCommandListModel::headerData(int section, Qt::Orientation orientatio
switch(role) {
case Qt::DisplayRole:
{
- if (section == 0) {
+ switch (section) {
+ case 0:
return tr("Command Name");
- } else if (section == 1) {
- return tr("Data");
+ case 1:
+ return tr("Register");
+ case 2:
+ return tr("New Value");
}
break;
@@ -297,6 +302,13 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi
list_widget->setModel(model);
list_widget->setFont(QFont("monospace"));
list_widget->setRootIsDecorated(false);
+ list_widget->setUniformRowHeights(true);
+
+#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
+ list_widget->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
+#else
+ list_widget->header()->setResizeMode(QHeaderView::ResizeToContents);
+#endif
connect(list_widget->selectionModel(), SIGNAL(currentChanged(const QModelIndex&,const QModelIndex&)),
this, SLOT(SetCommandInfo(const QModelIndex&)));
@@ -304,16 +316,24 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi
this, SLOT(OnCommandDoubleClicked(const QModelIndex&)));
toggle_tracing = new QPushButton(tr("Start Tracing"));
+ QPushButton* copy_all = new QPushButton(tr("Copy All"));
connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing()));
connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)),
model, SLOT(OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&)));
+ connect(copy_all, SIGNAL(clicked()), this, SLOT(CopyAllToClipboard()));
+
command_info_widget = new QWidget;
QVBoxLayout* main_layout = new QVBoxLayout;
main_layout->addWidget(list_widget);
- main_layout->addWidget(toggle_tracing);
+ {
+ QHBoxLayout* sub_layout = new QHBoxLayout;
+ sub_layout->addWidget(toggle_tracing);
+ sub_layout->addWidget(copy_all);
+ main_layout->addLayout(sub_layout);
+ }
main_layout->addWidget(command_info_widget);
main_widget->setLayout(main_layout);
@@ -330,3 +350,21 @@ void GPUCommandListWidget::OnToggleTracing() {
toggle_tracing->setText(tr("Start Tracing"));
}
}
+
+void GPUCommandListWidget::CopyAllToClipboard() {
+ QClipboard* clipboard = QApplication::clipboard();
+ QString text;
+
+ QAbstractItemModel* model = static_cast<QAbstractListModel*>(list_widget->model());
+
+ for (int row = 0; row < model->rowCount({}); ++row) {
+ for (int col = 0; col < model->columnCount({}); ++col) {
+ QModelIndex index = model->index(row, col);
+ text += model->data(index).value<QString>();
+ text += '\t';
+ }
+ text += '\n';
+ }
+
+ clipboard->setText(text);
+}
diff --git a/src/citra_qt/debugger/graphics_cmdlists.h b/src/citra_qt/debugger/graphics_cmdlists.h
index a465d044..4859b6ec 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.h
+++ b/src/citra_qt/debugger/graphics_cmdlists.h
@@ -49,6 +49,8 @@ public slots:
void SetCommandInfo(const QModelIndex&);
+ void CopyAllToClipboard();
+
signals:
void TracingFinished(const Pica::DebugUtils::PicaTrace&);
diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp
index 6bbe7572..39eefbf7 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
framebuffer_format_control->addItem(tr("RGBA4"));
framebuffer_format_control->addItem(tr("D16"));
framebuffer_format_control->addItem(tr("D24"));
- framebuffer_format_control->addItem(tr("D24S8"));
+ framebuffer_format_control->addItem(tr("D24X8"));
+ framebuffer_format_control->addItem(tr("X24S8"));
+ framebuffer_format_control->addItem(tr("(unknown)"));
// TODO: This QLabel should shrink the image to the available space rather than just expanding...
framebuffer_picture_label = new QLabel;
@@ -184,8 +186,32 @@ void GraphicsFramebufferWidget::OnUpdate()
framebuffer_address = framebuffer.GetColorBufferPhysicalAddress();
framebuffer_width = framebuffer.GetWidth();
framebuffer_height = framebuffer.GetHeight();
- // TODO: It's unknown how this format is actually specified
- framebuffer_format = Format::RGBA8;
+
+ switch (framebuffer.color_format) {
+ case Pica::Regs::ColorFormat::RGBA8:
+ framebuffer_format = Format::RGBA8;
+ break;
+
+ case Pica::Regs::ColorFormat::RGB8:
+ framebuffer_format = Format::RGB8;
+ break;
+
+ case Pica::Regs::ColorFormat::RGB5A1:
+ framebuffer_format = Format::RGB5A1;
+ break;
+
+ case Pica::Regs::ColorFormat::RGB565:
+ framebuffer_format = Format::RGB565;
+ break;
+
+ case Pica::Regs::ColorFormat::RGBA4:
+ framebuffer_format = Format::RGBA4;
+ break;
+
+ default:
+ framebuffer_format = Format::Unknown;
+ break;
+ }
break;
}
@@ -197,7 +223,24 @@ void GraphicsFramebufferWidget::OnUpdate()
framebuffer_address = framebuffer.GetDepthBufferPhysicalAddress();
framebuffer_width = framebuffer.GetWidth();
framebuffer_height = framebuffer.GetHeight();
- framebuffer_format = Format::D16;
+
+ switch (framebuffer.depth_format) {
+ case Pica::Regs::DepthFormat::D16:
+ framebuffer_format = Format::D16;
+ break;
+
+ case Pica::Regs::DepthFormat::D24:
+ framebuffer_format = Format::D24;
+ break;
+
+ case Pica::Regs::DepthFormat::D24S8:
+ framebuffer_format = Format::D24X8;
+ break;
+
+ default:
+ framebuffer_format = Format::Unknown;
+ break;
+ }
break;
}
@@ -258,7 +301,7 @@ void GraphicsFramebufferWidget::OnUpdate()
color.b() = (data >> 16) & 0xFF;
break;
}
- case Format::D24S8:
+ case Format::D24X8:
{
Math::Vec2<u32> data = Color::DecodeD24S8(pixel);
color.r() = data.x & 0xFF;
@@ -266,6 +309,12 @@ void GraphicsFramebufferWidget::OnUpdate()
color.b() = (data.x >> 16) & 0xFF;
break;
}
+ case Format::X24S8:
+ {
+ Math::Vec2<u32> data = Color::DecodeD24S8(pixel);
+ color.r() = color.g() = color.b() = data.y;
+ break;
+ }
default:
qDebug() << "Unknown fb color format " << static_cast<int>(framebuffer_format);
break;
@@ -286,7 +335,8 @@ void GraphicsFramebufferWidget::OnUpdate()
u32 GraphicsFramebufferWidget::BytesPerPixel(GraphicsFramebufferWidget::Format format) {
switch (format) {
case Format::RGBA8:
- case Format::D24S8:
+ case Format::D24X8:
+ case Format::X24S8:
return 4;
case Format::RGB8:
case Format::D24:
diff --git a/src/citra_qt/debugger/graphics_framebuffer.h b/src/citra_qt/debugger/graphics_framebuffer.h
index 4cb396ff..e9eae679 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 {
RGBA4 = 4,
D16 = 5,
D24 = 6,
- D24S8 = 7
+ D24X8 = 7,
+ X24S8 = 8,
+ Unknown = 9
};
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 00000000..3f20f149
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_tracing.cpp
@@ -0,0 +1,170 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <memory>
+
+#include <QBoxLayout>
+#include <QComboBox>
+#include <QFileDialog>
+#include <QLabel>
+#include <QMessageBox>
+#include <QPushButton>
+#include <QSpinBox>
+
+#include <boost/range/algorithm/copy.hpp>
+
+#include "core/hw/gpu.h"
+#include "core/hw/lcd.h"
+
+#include "video_core/pica.h"
+
+#include "nihstro/float24.h"
+
+#include "graphics_tracing.h"
+
+GraphicsTracingWidget::GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context,
+ QWidget* parent)
+ : BreakPointObserverDock(debug_context, tr("CiTrace Recorder"), parent) {
+
+ setObjectName("CiTracing");
+
+ QPushButton* start_recording = new QPushButton(tr("Start Recording"));
+ QPushButton* stop_recording = new QPushButton(QIcon::fromTheme("document-save"), tr("Stop and Save"));
+ QPushButton* abort_recording = new QPushButton(tr("Abort Recording"));
+
+ connect(this, SIGNAL(SetStartTracingButtonEnabled(bool)), start_recording, SLOT(setVisible(bool)));
+ connect(this, SIGNAL(SetStopTracingButtonEnabled(bool)), stop_recording, SLOT(setVisible(bool)));
+ connect(this, SIGNAL(SetAbortTracingButtonEnabled(bool)), abort_recording, SLOT(setVisible(bool)));
+ connect(start_recording, SIGNAL(clicked()), this, SLOT(StartRecording()));
+ connect(stop_recording, SIGNAL(clicked()), this, SLOT(StopRecording()));
+ connect(abort_recording, SIGNAL(clicked()), this, SLOT(AbortRecording()));
+
+ stop_recording->setVisible(false);
+ abort_recording->setVisible(false);
+
+ auto main_widget = new QWidget;
+ auto main_layout = new QVBoxLayout;
+ {
+ auto sub_layout = new QHBoxLayout;
+ sub_layout->addWidget(start_recording);
+ sub_layout->addWidget(stop_recording);
+ sub_layout->addWidget(abort_recording);
+ main_layout->addLayout(sub_layout);
+ }
+ main_widget->setLayout(main_layout);
+ setWidget(main_widget);
+}
+
+void GraphicsTracingWidget::StartRecording() {
+ auto context = context_weak.lock();
+ if (!context)
+ return;
+
+ auto shader_binary = Pica::g_state.vs.program_code;
+ auto swizzle_data = Pica::g_state.vs.swizzle_data;
+
+ // Encode floating point numbers to 24-bit values
+ // TODO: Drop this explicit conversion once we store float24 values bit-correctly internally.
+ std::array<uint32_t, 4 * 16> default_attributes;
+ for (unsigned i = 0; i < 16; ++i) {
+ for (unsigned comp = 0; comp < 3; ++comp) {
+ default_attributes[4 * i + comp] = nihstro::to_float24(Pica::g_state.vs.default_attributes[i][comp].ToFloat32());
+ }
+ }
+
+ std::array<uint32_t, 4 * 96> vs_float_uniforms;
+ for (unsigned i = 0; i < 96; ++i)
+ for (unsigned comp = 0; comp < 3; ++comp)
+ vs_float_uniforms[4 * i + comp] = nihstro::to_float24(Pica::g_state.vs.uniforms.f[i][comp].ToFloat32());
+
+ CiTrace::Recorder::InitialState state;
+ std::copy_n((u32*)&GPU::g_regs, sizeof(GPU::g_regs) / sizeof(u32), std::back_inserter(state.gpu_registers));
+ std::copy_n((u32*)&LCD::g_regs, sizeof(LCD::g_regs) / sizeof(u32), std::back_inserter(state.lcd_registers));
+ std::copy_n((u32*)&Pica::g_state.regs, sizeof(Pica::g_state.regs) / sizeof(u32), std::back_inserter(state.pica_registers));
+ boost::copy(default_attributes, std::back_inserter(state.default_attributes));
+ boost::copy(shader_binary, std::back_inserter(state.vs_program_binary));
+ boost::copy(swizzle_data, std::back_inserter(state.vs_swizzle_data));
+ boost::copy(vs_float_uniforms, std::back_inserter(state.vs_float_uniforms));
+ //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_program_binary));
+ //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_swizzle_data));
+ //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_float_uniforms));
+
+ auto recorder = new CiTrace::Recorder(state);
+ context->recorder = std::shared_ptr<CiTrace::Recorder>(recorder);
+
+ emit SetStartTracingButtonEnabled(false);
+ emit SetStopTracingButtonEnabled(true);
+ emit SetAbortTracingButtonEnabled(true);
+}
+
+void GraphicsTracingWidget::StopRecording() {
+ auto context = context_weak.lock();
+ if (!context)
+ return;
+
+ QString filename = QFileDialog::getSaveFileName(this, tr("Save CiTrace"), "citrace.ctf",
+ tr("CiTrace File (*.ctf)"));
+
+ if (filename.isEmpty()) {
+ // If the user canceled the dialog, keep recording
+ return;
+ }
+
+ context->recorder->Finish(filename.toStdString());
+ context->recorder = nullptr;
+
+ emit SetStopTracingButtonEnabled(false);
+ emit SetAbortTracingButtonEnabled(false);
+ emit SetStartTracingButtonEnabled(true);
+}
+
+void GraphicsTracingWidget::AbortRecording() {
+ auto context = context_weak.lock();
+ if (!context)
+ return;
+
+ context->recorder = nullptr;
+
+ emit SetStopTracingButtonEnabled(false);
+ emit SetAbortTracingButtonEnabled(false);
+ emit SetStartTracingButtonEnabled(true);
+}
+
+void GraphicsTracingWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) {
+ widget()->setEnabled(true);
+}
+
+void GraphicsTracingWidget::OnResumed() {
+ widget()->setEnabled(false);
+}
+
+void GraphicsTracingWidget::OnEmulationStarting(EmuThread* emu_thread) {
+ // Disable tracing starting/stopping until a GPU breakpoint is reached
+ widget()->setEnabled(false);
+}
+
+void GraphicsTracingWidget::OnEmulationStopping() {
+ // TODO: Is it safe to access the context here?
+
+ auto context = context_weak.lock();
+ if (!context)
+ return;
+
+
+ if (context->recorder) {
+ auto reply = QMessageBox::question(this, tr("CiTracing still active"),
+ tr("A CiTrace is still being recorded. Do you want to save it? If not, all recorded data will be discarded."),
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
+
+ if (reply == QMessageBox::Yes) {
+ StopRecording();
+ } else {
+ AbortRecording();
+ }
+ }
+
+ // If the widget was disabled before, enable it now to allow starting
+ // tracing before starting the next emulation session
+ widget()->setEnabled(true);
+}
diff --git a/src/citra_qt/debugger/graphics_tracing.h b/src/citra_qt/debugger/graphics_tracing.h
new file mode 100644
index 00000000..2a0e4819
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_tracing.h
@@ -0,0 +1,32 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "graphics_breakpoint_observer.h"
+
+class EmuThread;
+
+class GraphicsTracingWidget : public BreakPointObserverDock {
+ Q_OBJECT
+
+public:
+ GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent = nullptr);
+
+private slots:
+ void StartRecording();
+ void StopRecording();
+ void AbortRecording();
+
+ void OnBreakPointHit(Pica::DebugContext::Event event, void* data) override;
+ void OnResumed() override;
+
+ void OnEmulationStarting(EmuThread* emu_thread);
+ void OnEmulationStopping();
+
+signals:
+ void SetStartTracingButtonEnabled(bool enable);
+ void SetStopTracingButtonEnabled(bool enable);
+ void SetAbortTracingButtonEnabled(bool enable);
+};
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp
index 14d3f8f3..f42a2f4c 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 {
}
int GraphicsVertexShaderModel::rowCount(const QModelIndex& parent) const {
- return info.code.size();
+ return static_cast<int>(info.code.size());
}
QVariant GraphicsVertexShaderModel::headerData(int section, Qt::Orientation orientation, int role) const {
@@ -259,7 +259,7 @@ void GraphicsVertexShaderModel::OnUpdate()
for (auto pattern : Pica::g_state.vs.swizzle_data)
info.swizzle_info.push_back({pattern});
- info.labels.insert({ Pica::g_state.regs.vs_main_offset, "main" });
+ info.labels.insert({ Pica::g_state.regs.vs.main_offset, "main" });
endResetModel();
}
diff --git a/src/citra_qt/debugger/profiler.cpp b/src/citra_qt/debugger/profiler.cpp
index 2ac1748b..89b28c2f 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
if (parent.isValid()) {
return 0;
} else {
- return results.time_per_category.size() + 2;
+ return static_cast<int>(results.time_per_category.size() + 2);
}
}
diff --git a/src/citra_qt/hotkeys.cpp b/src/citra_qt/hotkeys.cpp
index 322c25c9..5ed6cf0b 100644
--- a/src/citra_qt/hotkeys.cpp
+++ b/src/citra_qt/hotkeys.cpp
@@ -2,10 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <map>
+
#include <QKeySequence>
#include <QSettings>
+#include <QShortcut>
+
#include "hotkeys.h"
-#include <map>
struct Hotkey
{
diff --git a/src/citra_qt/hotkeys.h b/src/citra_qt/hotkeys.h
index 75c7cc62..2317f818 100644
--- a/src/citra_qt/hotkeys.h
+++ b/src/citra_qt/hotkeys.h
@@ -2,12 +2,12 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <QShortcut>
-#include <QDialog>
#include "ui_hotkeys.h"
+class QDialog;
class QKeySequence;
class QSettings;
+class QShortcut;
/**
* Register a hotkey.
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 8041816a..34831f2e 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -10,18 +10,16 @@
#include "qhexedit.h"
#include "main.h"
+#include "common/string_util.h"
#include "common/logging/text_formatter.h"
#include "common/logging/log.h"
#include "common/logging/backend.h"
#include "common/logging/filter.h"
#include "common/make_unique.h"
#include "common/platform.h"
+#include "common/scm_rev.h"
#include "common/scope_exit.h"
-#if EMU_PLATFORM == PLATFORM_LINUX
-#include <unistd.h>
-#endif
-
#include "bootmanager.h"
#include "hotkeys.h"
@@ -34,6 +32,7 @@
#include "debugger/graphics_breakpoints.h"
#include "debugger/graphics_cmdlists.h"
#include "debugger/graphics_framebuffer.h"
+#include "debugger/graphics_tracing.h"
#include "debugger/graphics_vertex_shader.h"
#include "debugger/profiler.h"
@@ -96,6 +95,10 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
addDockWidget(Qt::RightDockWidgetArea, graphicsVertexShaderWidget);
graphicsVertexShaderWidget->hide();
+ auto graphicsTracingWidget = new GraphicsTracingWidget(Pica::g_debug_context, this);
+ addDockWidget(Qt::RightDockWidgetArea, graphicsTracingWidget);
+ graphicsTracingWidget->hide();
+
QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging"));
debug_menu->addAction(profilerWidget->toggleViewAction());
debug_menu->addAction(disasmWidget->toggleViewAction());
@@ -106,6 +109,7 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction());
debug_menu->addAction(graphicsFramebufferWidget->toggleViewAction());
debug_menu->addAction(graphicsVertexShaderWidget->toggleViewAction());
+ debug_menu->addAction(graphicsTracingWidget->toggleViewAction());
// Set default UI state
// 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)
connect(this, SIGNAL(EmulationStopping()), registersWidget, SLOT(OnEmulationStopping()));
connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window, SLOT(OnEmulationStarting(EmuThread*)));
connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping()));
+ connect(this, SIGNAL(EmulationStarting(EmuThread*)), graphicsTracingWidget, SLOT(OnEmulationStarting(EmuThread*)));
+ connect(this, SIGNAL(EmulationStopping()), graphicsTracingWidget, SLOT(OnEmulationStopping()));
+
// Setup hotkeys
RegisterHotkey("Main Window", "Load File", QKeySequence::Open);
@@ -256,6 +263,7 @@ void GMainWindow::ShutdownGame() {
// Update the GUI
ui.action_Start->setEnabled(false);
+ ui.action_Start->setText(tr("Start"));
ui.action_Pause->setEnabled(false);
ui.action_Stop->setEnabled(false);
render_window->hide();
@@ -284,6 +292,8 @@ void GMainWindow::OnStartGame()
emu_thread->SetRunning(true);
ui.action_Start->setEnabled(false);
+ ui.action_Start->setText(tr("Continue"));
+
ui.action_Pause->setEnabled(true);
ui.action_Stop->setEnabled(true);
}
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index e78f4f14..4c086cd2 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -31,7 +31,6 @@ set(HEADERS
cpu_detect.h
debug_interface.h
emu_window.h
- fifo_queue.h
file_util.h
key_map.h
linear_disk_cache.h
@@ -53,7 +52,6 @@ set(HEADERS
synchronized_wrapper.h
thread.h
thread_queue_list.h
- thunk.h
timer.h
vector_math.h
)
diff --git a/src/common/assert.h b/src/common/assert.h
index 7b7d8bf2..6849778b 100644
--- a/src/common/assert.h
+++ b/src/common/assert.h
@@ -4,7 +4,6 @@
#pragma once
-#include <cstdio>
#include <cstdlib>
#include "common/common_funcs.h"
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 1f3ecf84..f64ebdaf 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -32,6 +32,7 @@
#pragma once
+#include <cstddef>
#include <limits>
#include <type_traits>
@@ -160,7 +161,7 @@ public:
if (std::numeric_limits<T>::is_signed)
{
std::size_t shift = 8 * sizeof(T)-bits;
- return (T)(((storage & GetMask()) << (shift - position)) >> shift);
+ return (T)((storage << (shift - position)) >> shift);
}
else
{
@@ -188,7 +189,7 @@ private:
__forceinline StorageType GetMask() const
{
- return ((~(StorageTypeU)0) >> (8 * sizeof(T)-bits)) << position;
+ return (((StorageTypeU)~0) >> (8 * sizeof(T)-bits)) << position;
}
StorageType storage;
diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h
index dcd80525..8be0b110 100644
--- a/src/common/chunk_file.h
+++ b/src/common/chunk_file.h
@@ -26,16 +26,18 @@
// - Zero backwards/forwards compatibility
// - Serialization code for anything complex has to be manually written.
-#include <map>
-#include <vector>
+#include <cstring>
#include <deque>
-#include <string>
#include <list>
+#include <map>
#include <set>
+#include <string>
#include <type_traits>
+#include <utility>
+#include <vector>
+#include "common/assert.h"
#include "common/common_types.h"
-#include "common/file_util.h"
#include "common/logging/log.h"
template <class T>
diff --git a/src/common/color.h b/src/common/color.h
index 422fdc8a..9dafdca0 100644
--- a/src/common/color.h
+++ b/src/common/color.h
@@ -208,7 +208,32 @@ inline void EncodeD24(u32 value, u8* bytes) {
* @param bytes Pointer where to store the encoded value
*/
inline void EncodeD24S8(u32 depth, u8 stencil, u8* bytes) {
- *reinterpret_cast<u32_le*>(bytes) = (stencil << 24) | depth;
+ bytes[0] = depth & 0xFF;
+ bytes[1] = (depth >> 8) & 0xFF;
+ bytes[2] = (depth >> 16) & 0xFF;
+ bytes[3] = stencil;
+}
+
+/**
+ * Encode a 24 bit depth value as D24X8 format (32 bits per pixel with 8 bits unused)
+ * @param depth 24 bit source depth value to encode
+ * @param bytes Pointer where to store the encoded value
+ * @note unused bits will not be modified
+ */
+inline void EncodeD24X8(u32 depth, u8* bytes) {
+ bytes[0] = depth & 0xFF;
+ bytes[1] = (depth >> 8) & 0xFF;
+ bytes[2] = (depth >> 16) & 0xFF;
+}
+
+/**
+ * Encode an 8 bit stencil value as X24S8 format (32 bits per pixel with 24 bits unused)
+ * @param stencil 8 bit source stencil value to encode
+ * @param bytes Pointer where to store the encoded value
+ * @note unused bits will not be modified
+ */
+inline void EncodeX24S8(u8 stencil, u8* bytes) {
+ bytes[3] = stencil;
}
} // namespace
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 91b74c6b..59bd16db 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -5,15 +5,6 @@
#pragma once
#include "common_types.h"
-#include <cstdlib>
-
-
-#define b2(x) ( (x) | ( (x) >> 1) )
-#define b4(x) ( b2(x) | ( b2(x) >> 2) )
-#define b8(x) ( b4(x) | ( b4(x) >> 4) )
-#define b16(x) ( b8(x) | ( b8(x) >> 8) )
-#define b32(x) (b16(x) | (b16(x) >>16) )
-#define ROUND_UP_POW2(x) (b32(x - 1) + 1)
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
@@ -43,8 +34,6 @@
#ifndef _MSC_VER
-#include <errno.h>
-
#if defined(__x86_64__) || defined(_M_X64)
#define Crash() __asm__ __volatile__("int $3")
#elif defined(_M_ARM)
@@ -80,8 +69,10 @@ inline u64 _rotr64(u64 x, unsigned int shift){
}
#else // _MSC_VER
- // Function Cross-Compatibility
- #define snprintf _snprintf
+ #if (_MSC_VER < 1900)
+ // Function Cross-Compatibility
+ #define snprintf _snprintf
+ #endif
// Locale Cross-Compatibility
#define locale_t _locale_t
diff --git a/src/common/common_types.h b/src/common/common_types.h
index f6de0adf..fa3e0b8d 100644
--- a/src/common/common_types.h
+++ b/src/common/common_types.h
@@ -24,9 +24,7 @@
#pragma once
-#include <cmath>
#include <cstdint>
-#include <cstdlib>
#ifdef _MSC_VER
#ifndef __func__
@@ -52,32 +50,6 @@ typedef double f64; ///< 64-bit floating point
typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space.
typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space.
-/// Union for fast 16-bit type casting
-union t16 {
- u8 _u8[2]; ///< 8-bit unsigned char(s)
- u16 _u16; ///< 16-bit unsigned shorts(s)
-};
-
-/// Union for fast 32-bit type casting
-union t32 {
- f32 _f32; ///< 32-bit floating point(s)
- u32 _u32; ///< 32-bit unsigned int(s)
- s32 _s32; ///< 32-bit signed int(s)
- u16 _u16[2]; ///< 16-bit unsigned shorts(s)
- u8 _u8[4]; ///< 8-bit unsigned char(s)
-};
-
-/// Union for fast 64-bit type casting
-union t64 {
- f64 _f64; ///< 64-bit floating point
- u64 _u64; ///< 64-bit unsigned long
- f32 _f32[2]; ///< 32-bit floating point(s)
- u32 _u32[2]; ///< 32-bit unsigned int(s)
- s32 _s32[2]; ///< 32-bit signed int(s)
- u16 _u16[4]; ///< 16-bit unsigned shorts(s)
- u8 _u8[8]; ///< 8-bit unsigned char(s)
-};
-
// An inheritable class to disallow the copy constructor and operator= functions
class NonCopyable {
protected:
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index 43facb85..b69b05cb 100644
--- a/src/common/emu_window.cpp
+++ b/src/common/emu_window.cpp
@@ -2,6 +2,12 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+#include <cmath>
+
+#include "common/assert.h"
+#include "common/key_map.h"
+
#include "emu_window.h"
#include "video_core/video_core.h"
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index 8eca6b5d..a0ae4c9f 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -4,11 +4,17 @@
#pragma once
+#include <tuple>
+#include <utility>
+
#include "common/common_types.h"
-#include "common/key_map.h"
#include "common/math_util.h"
-#include "common/scm_rev.h"
-#include "common/string_util.h"
+
+#include "core/hle/service/hid/hid.h"
+
+namespace KeyMap {
+struct HostDeviceKey;
+}
/**
* 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 b426e659..00000000
--- a/src/common/fifo_queue.h
+++ /dev/null
@@ -1,111 +0,0 @@
-#pragma once
-
-// a simple lockless thread-safe,
-// single reader, single writer queue
-
-#include "common/atomic.h"
-
-namespace Common
-{
-
-template <typename T>
-class FifoQueue
-{
-public:
- FifoQueue() : m_size(0)
- {
- m_write_ptr = m_read_ptr = new ElementPtr();
- }
-
- ~FifoQueue()
- {
- // this will empty out the whole queue
- delete m_read_ptr;
- }
-
- u32 Size() const
- {
- return m_size;
- }
-
- bool Empty() const
- {
- //return (m_read_ptr == m_write_ptr);
- return (0 == m_size);
- }
-
- T& Front() const
- {
- return *m_read_ptr->current;
- }
-
- template <typename Arg>
- void Push(Arg&& t)
- {
- // create the element, add it to the queue
- m_write_ptr->current = new T(std::forward<Arg>(t));
- // set the next pointer to a new element ptr
- // then advance the write pointer
- m_write_ptr = m_write_ptr->next = new ElementPtr();
- Common::AtomicIncrement(m_size);
- }
-
- void Pop()
- {
- Common::AtomicDecrement(m_size);
- ElementPtr *const tmpptr = m_read_ptr;
- // advance the read pointer
- m_read_ptr = m_read_ptr->next;
- // set the next element to NULL to stop the recursive deletion
- tmpptr->next = nullptr;
- delete tmpptr; // this also deletes the element
- }
-
- bool Pop(T& t)
- {
- if (Empty())
- return false;
-
- t = std::move(Front());
- Pop();
-
- return true;
- }
-
- // not thread-safe
- void Clear()
- {
- m_size = 0;
- delete m_read_ptr;
- m_write_ptr = m_read_ptr = new ElementPtr();
- }
-
-private:
- // stores a pointer to element
- // and a pointer to the next ElementPtr
- class ElementPtr
- {
- public:
- ElementPtr() : current(nullptr), next(nullptr) {}
-
- ~ElementPtr()
- {
- if (current)
- {
- delete current;
- // recusion ftw
- if (next)
- delete next;
- }
- }
-
- T *volatile current;
- ElementPtr *volatile next;
- };
-
- ElementPtr *volatile m_write_ptr;
- ElementPtr *volatile m_read_ptr;
- volatile u32 m_size;
-};
-
-}
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 24648ea3..836b58d5 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -17,6 +17,8 @@
#include <direct.h> // getcwd
#include <tchar.h>
+ #include "common/string_util.h"
+
// 64 bit offsets for windows
#define fseeko _fseeki64
#define ftello _ftelli64
@@ -25,8 +27,13 @@
#define fstat64 _fstat64
#define fileno _fileno
#else
- #include <sys/param.h>
- #include <sys/types.h>
+ #ifdef __APPLE__
+ #include <sys/param.h>
+ #endif
+ #include <cctype>
+ #include <cerrno>
+ #include <cstdlib>
+ #include <cstring>
#include <dirent.h>
#include <pwd.h>
#include <unistd.h>
diff --git a/src/common/file_util.h b/src/common/file_util.h
index b6582929..d0dccdf6 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -6,13 +6,12 @@
#include <array>
#include <fstream>
+#include <cstddef>
#include <cstdio>
-#include <cstring>
#include <string>
#include <vector>
#include "common/common_types.h"
-#include "common/string_util.h"
// User directory indices for GetUserPath
enum {
@@ -117,9 +116,6 @@ bool SetCurrentDir(const std::string &directory);
// directory. To be used in "multi-user" mode (that is, installed).
const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath="");
-// probably doesn't belong here
-//std::string GetThemeDir(const std::string& theme_name);
-
// Returns the path to where the sys file are
std::string GetSysDirectory();
@@ -182,6 +178,10 @@ public:
template <typename T>
size_t WriteArray(const T* data, size_t length)
{
+ static_assert(std::is_standard_layout<T>::value, "Given array does not consist of standard layout objects");
+ // TODO: gcc 4.8 does not support is_trivially_copyable, but we really should check for it here.
+ //static_assert(std::is_trivially_copyable<T>::value, "Given array does not consist of trivially copyable objects");
+
if (!IsOpen()) {
m_good = false;
return -1;
@@ -204,6 +204,12 @@ public:
return WriteArray(reinterpret_cast<const char*>(data), length);
}
+ template<typename T>
+ size_t WriteObject(const T& object) {
+ static_assert(!std::is_pointer<T>::value, "Given object is a pointer");
+ return WriteArray(&object, 1);
+ }
+
bool IsOpen() { return nullptr != m_file; }
// 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 0b71ea3b..a2b4eca4 100644
--- a/src/common/logging/filter.h
+++ b/src/common/logging/filter.h
@@ -5,6 +5,7 @@
#pragma once
#include <array>
+#include <cstddef>
#include <string>
#include "common/logging/log.h"
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 5b3a731e..e16dde7f 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -4,10 +4,6 @@
#pragma once
-#include <cassert>
-#include <chrono>
-#include <string>
-
#include "common/common_types.h"
namespace Log {
diff --git a/src/common/make_unique.h b/src/common/make_unique.h
index 2a7b7641..f6e7f017 100644
--- a/src/common/make_unique.h
+++ b/src/common/make_unique.h
@@ -4,6 +4,7 @@
#pragma once
+#include <algorithm>
#include <memory>
namespace Common {
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp
index 20b791a1..2b3ace52 100644
--- a/src/common/memory_util.cpp
+++ b/src/common/memory_util.cpp
@@ -3,14 +3,17 @@
// Refer to the license.txt file included.
-#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "common/memory_util.h"
-#include "common/string_util.h"
#ifdef _WIN32
-#include <windows.h>
-#include <psapi.h>
+ #include <windows.h>
+ #include <psapi.h>
+ #include "common/common_funcs.h"
+ #include "common/string_util.h"
+#else
+ #include <cstdlib>
+ #include <sys/mman.h>
#endif
#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
diff --git a/src/common/memory_util.h b/src/common/memory_util.h
index 9fdbf1f1..9bf37c44 100644
--- a/src/common/memory_util.h
+++ b/src/common/memory_util.h
@@ -4,9 +4,7 @@
#pragma once
-#ifndef _WIN32
-#include <sys/mman.h>
-#endif
+#include <cstddef>
#include <string>
void* AllocateExecutableMemory(size_t size, bool low = true);
diff --git a/src/common/misc.cpp b/src/common/misc.cpp
index 53cacf37..d2a049b6 100644
--- a/src/common/misc.cpp
+++ b/src/common/misc.cpp
@@ -2,12 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/common_funcs.h"
+#include <cstddef>
#ifdef _WIN32
#include <windows.h>
#else
-#include <string.h>
+#include <cerrno>
+#include <cstring>
#endif
// Neither Android nor OS X support TLS
diff --git a/src/common/platform.h b/src/common/platform.h
index df780ac6..0a912dda 100644
--- a/src/common/platform.h
+++ b/src/common/platform.h
@@ -24,66 +24,11 @@
#pragma once
-#include "common/common_types.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Platform definitions
-
-/// Enumeration for defining the supported platforms
-#define PLATFORM_NULL 0
-#define PLATFORM_WINDOWS 1
-#define PLATFORM_MACOSX 2
-#define PLATFORM_LINUX 3
-#define PLATFORM_ANDROID 4
-
////////////////////////////////////////////////////////////////////////////////////////////////////
// Platform detection
-#ifndef EMU_PLATFORM
-
-#if defined( __WIN32__ ) || defined( _WIN32 )
-#define EMU_PLATFORM PLATFORM_WINDOWS
-
-#elif defined( __APPLE__ ) || defined( __APPLE_CC__ )
-#define EMU_PLATFORM PLATFORM_MACOSX
-
-#elif defined(__linux__)
-#define EMU_PLATFORM PLATFORM_LINUX
-
-#else // Assume linux otherwise
-#define EMU_PLATFORM PLATFORM_LINUX
-
-#endif
-
-#endif
-
#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__)
#define EMU_ARCH_BITS 64
#elif defined(__i386) || defined(_M_IX86) || defined(__arm__) || defined(_M_ARM)
#define EMU_ARCH_BITS 32
#endif
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Feature detection
-
-#if defined _M_GENERIC
-# define _M_SSE 0x0
-#elif defined __GNUC__
-# if defined __SSE4_2__
-# define _M_SSE 0x402
-# elif defined __SSE4_1__
-# define _M_SSE 0x401
-# elif defined __SSSE3__
-# define _M_SSE 0x301
-# elif defined __SSE3__
-# define _M_SSE 0x300
-# endif
-#elif (_MSC_VER >= 1500) || __INTEL_COMPILER // Visual Studio 2008
-# define _M_SSE 0x402
-#endif
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Compiler-Specific Definitions
-
-#define GCC_VERSION_AVAILABLE(major, minor) (defined(__GNUC__) && (__GNUC__ > (major) || \
- (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))))
diff --git a/src/common/profiler.cpp b/src/common/profiler.cpp
index cf6b6b25..7792edd2 100644
--- a/src/common/profiler.cpp
+++ b/src/common/profiler.cpp
@@ -2,13 +2,18 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+#include <cstddef>
+#include <vector>
+
+#include "common/assert.h"
#include "common/profiler.h"
#include "common/profiler_reporting.h"
-#include "common/assert.h"
+#include "common/synchronized_wrapper.h"
#if defined(_MSC_VER) && _MSC_VER <= 1800 // MSVC 2013.
-#define WIN32_LEAN_AND_MEAN
-#include <Windows.h> // For QueryPerformanceCounter/Frequency
+ #define WIN32_LEAN_AND_MEAN
+ #include <Windows.h> // For QueryPerformanceCounter/Frequency
#endif
namespace Common {
diff --git a/src/common/profiler_reporting.h b/src/common/profiler_reporting.h
index 3abb7331..df98e05b 100644
--- a/src/common/profiler_reporting.h
+++ b/src/common/profiler_reporting.h
@@ -4,10 +4,7 @@
#pragma once
-#include <array>
-#include <chrono>
-#include <mutex>
-#include <utility>
+#include <cstddef>
#include <vector>
#include "common/profiler.h"
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 7dc0ba7b..b2f7f7b1 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -2,9 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <boost/range/algorithm.hpp>
+#include <cctype>
+#include <cerrno>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <boost/range/algorithm/transform.hpp>
-#include "common/common_funcs.h"
#include "common/common_paths.h"
#include "common/logging/log.h"
#include "common/string_util.h"
@@ -12,6 +16,7 @@
#ifdef _MSC_VER
#include <Windows.h>
#include <codecvt>
+ #include "common/common_funcs.h"
#else
#include <iconv.h>
#endif
@@ -308,7 +313,7 @@ static std::string UTF16ToUTF8(const std::wstring& input)
std::string output;
output.resize(size);
- if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), &output[0], output.size(), nullptr, nullptr))
+ if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), &output[0], static_cast<int>(output.size()), nullptr, nullptr))
output.clear();
return output;
diff --git a/src/common/string_util.h b/src/common/string_util.h
index fdc41049..c5c474c6 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -5,9 +5,10 @@
#pragma once
#include <cstdarg>
+#include <cstddef>
#include <iomanip>
-#include <string>
#include <sstream>
+#include <string>
#include <vector>
#include "common/common_types.h"
diff --git a/src/common/swap.h b/src/common/swap.h
index 588cebc7..b92e5bfa 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -17,12 +17,16 @@
#pragma once
-#if defined(__linux__)
-#include <byteswap.h>
+#if defined(_MSC_VER)
+ #include <cstdlib>
+#elif defined(__linux__)
+ #include <byteswap.h>
#elif defined(__FreeBSD__)
-#include <sys/endian.h>
+ #include <sys/endian.h>
#endif
+#include "common/common_types.h"
+
// GCC 4.6+
#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
diff --git a/src/common/synchronized_wrapper.h b/src/common/synchronized_wrapper.h
index 946252b8..ae5e8b1e 100644
--- a/src/common/synchronized_wrapper.h
+++ b/src/common/synchronized_wrapper.h
@@ -4,6 +4,7 @@
#pragma once
+#include <algorithm>
#include <mutex>
namespace Common {
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 8bf00585..7bbf080b 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -5,11 +5,20 @@
#include "common/thread.h"
#ifdef __APPLE__
-#include <mach/mach.h>
-#elif defined(BSD4_4) || defined(__OpenBSD__)
-#include <pthread_np.h>
+ #include <mach/mach.h>
#elif defined(_WIN32)
-#include <Windows.h>
+ #include <Windows.h>
+#else
+ #if defined(BSD4_4) || defined(__OpenBSD__)
+ #include <pthread_np.h>
+ #else
+ #include <pthread.h>
+ #endif
+ #include <sched.h>
+#endif
+
+#ifndef _WIN32
+ #include <unistd.h>
#endif
namespace Common
diff --git a/src/common/thread.h b/src/common/thread.h
index 7bc41949..8255ee6d 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -4,24 +4,12 @@
#pragma once
-#include "common/common_types.h"
-#include <cstdio>
-#include <cstring>
+#include <cstddef>
#include <thread>
#include <condition_variable>
#include <mutex>
-// This may not be defined outside _WIN32
-#ifndef _WIN32
-#ifndef INFINITE
-#define INFINITE 0xffffffff
-#endif
-
-//for gettimeofday and struct time(spec|val)
-#include <time.h>
-#include <sys/time.h>
-#include <unistd.h>
-#endif
+#include "common/common_types.h"
// Support for C++11's thread_local keyword was surprisingly spotty in compilers until very
// 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 53348005..00000000
--- a/src/common/thunk.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include <map>
-
-#include "common/common_types.h"
-
-// This simple class creates a wrapper around a C/C++ function that saves all fp state
-// before entering it, and restores it upon exit. This is required to be able to selectively
-// call functions from generated code, without inflicting the performance hit and increase
-// of complexity that it means to protect the generated code from this problem.
-
-// This process is called thunking.
-
-// There will only ever be one level of thunking on the stack, plus,
-// we don't want to pollute the stack, so we store away regs somewhere global.
-// NOT THREAD SAFE. This may only be used from the CPU thread.
-// Any other thread using this stuff will be FATAL.
-
-class ThunkManager : public Gen::XCodeBlock
-{
- std::map<void *, const u8 *> thunks;
-
- const u8 *save_regs;
- const u8 *load_regs;
-
-public:
- ThunkManager() {
- Init();
- }
- ~ThunkManager() {
- Shutdown();
- }
- void *ProtectFunction(void *function, int num_params);
-private:
- void Init();
- void Shutdown();
- void Reset();
-};
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 4fcda487..6cc60fd5 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -4,10 +4,9 @@ set(SRCS
arm/dyncom/arm_dyncom.cpp
arm/dyncom/arm_dyncom_dec.cpp
arm/dyncom/arm_dyncom_interpreter.cpp
- arm/dyncom/arm_dyncom_run.cpp
arm/dyncom/arm_dyncom_thumb.cpp
- arm/interpreter/arminit.cpp
- arm/interpreter/armsupp.cpp
+ arm/skyeye_common/armstate.cpp
+ arm/skyeye_common/armsupp.cpp
arm/skyeye_common/vfp/vfp.cpp
arm/skyeye_common/vfp/vfpdouble.cpp
arm/skyeye_common/vfp/vfpinstr.cpp
@@ -25,6 +24,8 @@ set(SRCS
file_sys/ivfc_archive.cpp
hle/config_mem.cpp
hle/hle.cpp
+ hle/applets/applet.cpp
+ hle/applets/swkbd.cpp
hle/kernel/address_arbiter.cpp
hle/kernel/event.cpp
hle/kernel/kernel.cpp
@@ -113,6 +114,7 @@ set(SRCS
loader/elf.cpp
loader/loader.cpp
loader/ncch.cpp
+ tracer/recorder.cpp
mem_map.cpp
memory.cpp
settings.cpp
@@ -129,8 +131,8 @@ set(HEADERS
arm/dyncom/arm_dyncom_run.h
arm/dyncom/arm_dyncom_thumb.h
arm/skyeye_common/arm_regformat.h
- arm/skyeye_common/armdefs.h
- arm/skyeye_common/armmmu.h
+ arm/skyeye_common/armstate.h
+ arm/skyeye_common/armsupp.h
arm/skyeye_common/vfp/asm_vfp.h
arm/skyeye_common/vfp/vfp.h
arm/skyeye_common/vfp/vfp_helper.h
@@ -150,6 +152,8 @@ set(HEADERS
hle/config_mem.h
hle/function_wrappers.h
hle/hle.h
+ hle/applets/applet.h
+ hle/applets/swkbd.h
hle/kernel/address_arbiter.h
hle/kernel/event.h
hle/kernel/kernel.h
@@ -239,6 +243,8 @@ set(HEADERS
loader/elf.h
loader/loader.h
loader/ncch.h
+ tracer/recorder.h
+ tracer/citrace.h
mem_map.h
memory.h
memory_setup.h
diff --git a/src/core/arm/disassembler/load_symbol_map.cpp b/src/core/arm/disassembler/load_symbol_map.cpp
index 13d26d17..eb20bf6f 100644
--- a/src/core/arm/disassembler/load_symbol_map.cpp
+++ b/src/core/arm/disassembler/load_symbol_map.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <sstream>
#include <string>
#include <vector>
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index 529c4ac7..c665f706 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -6,7 +6,8 @@
#include "common/make_unique.h"
-#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/armstate.h"
+#include "core/arm/skyeye_common/armsupp.h"
#include "core/arm/skyeye_common/vfp/vfp.h"
#include "core/arm/dyncom/arm_dyncom.h"
@@ -17,26 +18,7 @@
#include "core/core_timing.h"
ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) {
- state = Common::make_unique<ARMul_State>();
-
- ARMul_NewState(state.get());
- ARMul_SelectProcessor(state.get(), ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop);
-
- state->abort_model = ABORT_BASE_RESTORED;
-
- state->bigendSig = LOW;
- state->lateabtSig = LOW;
- state->NirqSig = HIGH;
-
- // Reset the core to initial state
- ARMul_Reset(state.get());
- state->Emulate = RUN;
-
- // Switch to the desired privilege mode.
- switch_mode(state.get(), initial_mode);
-
- state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack
- state->Reg[15] = 0x00000000;
+ state = Common::make_unique<ARMul_State>(initial_mode);
}
ARM_DynCom::~ARM_DynCom() {
@@ -100,8 +82,8 @@ void ARM_DynCom::ResetContext(Core::ThreadContext& context, u32 stack_top, u32 e
}
void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) {
- memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers));
- memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers));
+ memcpy(ctx.cpu_registers, state->Reg.data(), sizeof(ctx.cpu_registers));
+ memcpy(ctx.fpu_registers, state->ExtReg.data(), sizeof(ctx.fpu_registers));
ctx.sp = state->Reg[13];
ctx.lr = state->Reg[14];
@@ -113,8 +95,8 @@ void ARM_DynCom::SaveContext(Core::ThreadContext& ctx) {
}
void ARM_DynCom::LoadContext(const Core::ThreadContext& ctx) {
- memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers));
- memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers));
+ memcpy(state->Reg.data(), ctx.cpu_registers, sizeof(ctx.cpu_registers));
+ memcpy(state->ExtReg.data(), ctx.fpu_registers, sizeof(ctx.fpu_registers));
state->Reg[13] = ctx.sp;
state->Reg[14] = ctx.lr;
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index 2488c879..87ab6908 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -9,7 +9,12 @@
#include "common/common_types.h"
#include "core/arm/arm_interface.h"
-#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/arm_regformat.h"
+#include "core/arm/skyeye_common/armstate.h"
+
+namespace Core {
+struct ThreadContext;
+}
class ARM_DynCom final : virtual public ARM_Interface {
public:
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.cpp b/src/core/arm/dyncom/arm_dyncom_dec.cpp
index 697be955..ee428831 100644
--- a/src/core/arm/dyncom/arm_dyncom_dec.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_dec.cpp
@@ -2,10 +2,10 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "core/arm/skyeye_common/armdefs.h"
#include "core/arm/dyncom/arm_dyncom_dec.h"
+#include "core/arm/skyeye_common/armsupp.h"
-const ISEITEM arm_instruction[] = {
+const InstructionSetEncodingItem arm_instruction[] = {
{ "vmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 4, 4, 0 }},
{ "vmls", 7, ARMVFP2, { 28, 31, 0xF, 25, 27, 0x1, 23, 23, 1, 11, 11, 0, 8, 9, 0x2, 6, 6, 1, 4, 4, 0 }},
{ "vnmla", 4, ARMVFP2, { 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 4, 4, 0 }},
@@ -207,7 +207,7 @@ const ISEITEM arm_instruction[] = {
{ "bbl", 1, 0, { 25, 27, 0x00000005 }},
};
-const ISEITEM arm_exclusion_code[] = {
+const InstructionSetEncodingItem arm_exclusion_code[] = {
{ "vmla", 0, ARMVFP2, { 0 }},
{ "vmls", 0, ARMVFP2, { 0 }},
{ "vnmla", 0, ARMVFP2, { 0 }},
@@ -414,14 +414,13 @@ const ISEITEM arm_exclusion_code[] = {
{ "invalid", 0, INVALID, { 0 }}
};
-int decode_arm_instr(uint32_t instr, int32_t *idx) {
+ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx) {
int n = 0;
int base = 0;
- int ret = DECODE_FAILURE;
- int i = 0;
- int instr_slots = sizeof(arm_instruction) / sizeof(ISEITEM);
+ int instr_slots = sizeof(arm_instruction) / sizeof(InstructionSetEncodingItem);
+ ARMDecodeStatus ret = ARMDecodeStatus::FAILURE;
- for (i = 0; i < instr_slots; i++) {
+ for (int i = 0; i < instr_slots; i++) {
n = arm_instruction[i].attribute_value;
base = 0;
@@ -438,11 +437,11 @@ int decode_arm_instr(uint32_t instr, int32_t *idx) {
n--;
}
- // All conditions is satisfied.
+ // All conditions are satisfied.
if (n == 0)
- ret = DECODE_SUCCESS;
+ ret = ARMDecodeStatus::SUCCESS;
- if (ret == DECODE_SUCCESS) {
+ if (ret == ARMDecodeStatus::SUCCESS) {
n = arm_exclusion_code[i].attribute_value;
if (n != 0) {
base = 0;
@@ -454,13 +453,13 @@ int decode_arm_instr(uint32_t instr, int32_t *idx) {
n--;
}
- // All conditions is satisfied.
+ // All conditions are satisfied.
if (n == 0)
- ret = DECODE_FAILURE;
+ ret = ARMDecodeStatus::FAILURE;
}
}
- if (ret == DECODE_SUCCESS) {
+ if (ret == ARMDecodeStatus::SUCCESS) {
*idx = i;
return ret;
}
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.h b/src/core/arm/dyncom/arm_dyncom_dec.h
index 4b5f5ad7..d7170e0f 100644
--- a/src/core/arm/dyncom/arm_dyncom_dec.h
+++ b/src/core/arm/dyncom/arm_dyncom_dec.h
@@ -4,22 +4,22 @@
#pragma once
-int decode_arm_instr(uint32_t instr, int32_t *idx);
+#include "common/common_types.h"
-enum DECODE_STATUS {
- DECODE_SUCCESS,
- DECODE_FAILURE
+enum class ARMDecodeStatus {
+ SUCCESS,
+ FAILURE
};
-struct instruction_set_encoding_item {
+ARMDecodeStatus DecodeARMInstruction(u32 instr, s32* idx);
+
+struct InstructionSetEncodingItem {
const char *name;
int attribute_value;
int version;
u32 content[21];
};
-typedef struct instruction_set_encoding_item ISEITEM;
-
// ARM versions
enum {
INVALID = 0,
@@ -36,4 +36,4 @@ enum {
ARMV6K,
};
-extern const ISEITEM arm_instruction[];
+extern 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 b00eb49a..d022546e 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -17,8 +17,8 @@
#include "core/arm/dyncom/arm_dyncom_interpreter.h"
#include "core/arm/dyncom/arm_dyncom_thumb.h"
#include "core/arm/dyncom/arm_dyncom_run.h"
-#include "core/arm/skyeye_common/armdefs.h"
-#include "core/arm/skyeye_common/armmmu.h"
+#include "core/arm/skyeye_common/armstate.h"
+#include "core/arm/skyeye_common/armsupp.h"
#include "core/arm/skyeye_common/vfp/vfp.h"
Common::Profiling::TimingCategory profile_execute("DynCom::Execute");
@@ -47,28 +47,6 @@ enum {
typedef unsigned int (*shtop_fp_t)(ARMul_State* cpu, unsigned int sht_oper);
-// Defines a reservation granule of 2 words, which protects the first 2 words starting at the tag.
-// This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough to
-// support LDR/STREXD.
-static const ARMword RESERVATION_GRANULE_MASK = 0xFFFFFFF8;
-
-// Exclusive memory access
-static int exclusive_detect(ARMul_State* state, ARMword addr) {
- if(state->exclusive_tag == (addr & RESERVATION_GRANULE_MASK))
- return 0;
- else
- return -1;
-}
-
-static void add_exclusive_addr(ARMul_State* state, ARMword addr){
- state->exclusive_tag = addr & RESERVATION_GRANULE_MASK;
- return;
-}
-
-static void remove_exclusive(ARMul_State* state, ARMword addr){
- state->exclusive_tag = 0xFFFFFFFF;
-}
-
static int CondPassed(ARMul_State* cpu, unsigned int cond) {
const u32 NFLAG = cpu->NFlag;
const u32 ZFLAG = cpu->ZFlag;
@@ -3490,21 +3468,15 @@ enum {
FETCH_FAILURE
};
-static tdstate decode_thumb_instr(u32 inst, u32 addr, u32* arm_inst, u32* inst_size, ARM_INST_PTR* ptr_inst_base) {
+static ThumbDecodeStatus DecodeThumbInstruction(u32 inst, u32 addr, u32* arm_inst, u32* inst_size, ARM_INST_PTR* ptr_inst_base) {
// Check if in Thumb mode
- tdstate ret = thumb_translate (addr, inst, arm_inst, inst_size);
- if(ret == t_branch){
- // TODO: FIXME, endian should be judged
- u32 tinstr;
- if((addr & 0x3) != 0)
- tinstr = inst >> 16;
- else
- tinstr = inst & 0xFFFF;
-
+ ThumbDecodeStatus ret = TranslateThumbInstruction (addr, inst, arm_inst, inst_size);
+ if (ret == ThumbDecodeStatus::BRANCH) {
int inst_index;
int table_length = sizeof(arm_instruction_trans) / sizeof(transop_fp_t);
+ u32 tinstr = GetThumbInstruction(inst, addr);
- switch((tinstr & 0xF800) >> 11){
+ switch ((tinstr & 0xF800) >> 11) {
case 26:
case 27:
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
*ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
break;
default:
- ret = t_undefined;
+ ret = ThumbDecodeStatus::UNDEFINED;
break;
}
}
@@ -3549,10 +3521,6 @@ enum {
FETCH_EXCEPTION
};
-typedef struct instruction_set_encoding_item ISEITEM;
-
-extern const ISEITEM arm_instruction[];
-
static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) {
Common::Profiling::ScopeTimer timer_decode(profile_decode);
@@ -3574,20 +3542,19 @@ static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) {
inst = Memory::Read32(phys_addr & 0xFFFFFFFC);
size++;
- // If we are in thumb instruction, we will translate one thumb to one corresponding arm instruction
+ // If we are in Thumb mode, we'll translate one Thumb instruction to the corresponding ARM instruction
if (cpu->TFlag) {
uint32_t arm_inst;
- tdstate state = decode_thumb_instr(inst, phys_addr, &arm_inst, &inst_size, &inst_base);
+ ThumbDecodeStatus state = DecodeThumbInstruction(inst, phys_addr, &arm_inst, &inst_size, &inst_base);
- // We have translated the branch instruction of thumb in thumb decoder
- if(state == t_branch){
+ // We have translated the Thumb branch instruction in the Thumb decoder
+ if (state == ThumbDecodeStatus::BRANCH) {
goto translated;
}
inst = arm_inst;
}
- ret = decode_arm_instr(inst, &idx);
- if (ret == DECODE_FAILURE) {
+ if (DecodeARMInstruction(inst, &idx) == ARMDecodeStatus::FAILURE) {
std::string disasm = ARM_Disasm::Disassemble(phys_addr, inst);
LOG_ERROR(Core_ARM11, "Decode failure.\tPC : [0x%x]\tInstruction : %s [%x]", phys_addr, disasm.c_str(), inst);
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) {
if (inst_cream->S && (inst_cream->Rd == 15)) {
if (CurrentModeHasSPSR) {
cpu->Cpsr = cpu->Spsr_copy;
- switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
LOAD_NZCVT;
}
} else if (inst_cream->S) {
@@ -3978,7 +3945,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(adc_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -3990,7 +3957,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
u32 rn_val = RN;
if (inst_cream->Rn == 15)
- rn_val += 2 * GET_INST_SIZE(cpu);
+ rn_val += 2 * cpu->GetInstructionSize();
bool carry;
bool overflow;
@@ -3999,7 +3966,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
if (inst_cream->S && (inst_cream->Rd == 15)) {
if (CurrentModeHasSPSR) {
cpu->Cpsr = cpu->Spsr_copy;
- switch_mode(cpu, cpu->Cpsr & 0x1f);
+ cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F);
LOAD_NZCVT;
}
} else if (inst_cream->S) {
@@ -4013,7 +3980,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(add_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4028,7 +3995,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
if (inst_cream->S && (inst_cream->Rd == 15)) {
if (CurrentModeHasSPSR) {
cpu->Cpsr = cpu->Spsr_copy;
- switch_mode(cpu, cpu->Cpsr & 0x1f);
+ cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F);
LOAD_NZCVT;
}
} else if (inst_cream->S) {
@@ -4041,7 +4008,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(and_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4057,7 +4024,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
INC_PC(sizeof(bbl_inst));
goto DISPATCH;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(bbl_inst));
goto DISPATCH;
}
@@ -4067,14 +4034,14 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
u32 lop = RN;
if (inst_cream->Rn == 15) {
- lop += 2 * GET_INST_SIZE(cpu);
+ lop += 2 * cpu->GetInstructionSize();
}
u32 rop = SHIFTER_OPERAND;
RD = lop & (~rop);
if ((inst_cream->S) && (inst_cream->Rd == 15)) {
if (CurrentModeHasSPSR) {
cpu->Cpsr = cpu->Spsr_copy;
- switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
LOAD_NZCVT;
}
} else if (inst_cream->S) {
@@ -4087,7 +4054,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(bic_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4098,7 +4065,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
bkpt_inst* const inst_cream = (bkpt_inst*)inst_base->component;
LOG_DEBUG(Core_ARM11, "Breakpoint instruction hit. Immediate: 0x%08X", inst_cream->imm);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(bkpt_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4109,13 +4076,13 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
unsigned int inst = inst_cream->inst;
if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) {
- cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu));
+ cpu->Reg[14] = (cpu->Reg[15] + cpu->GetInstructionSize());
if(cpu->TFlag)
cpu->Reg[14] |= 0x1;
cpu->Reg[15] = cpu->Reg[inst_cream->val.Rm] & 0xfffffffe;
cpu->TFlag = cpu->Reg[inst_cream->val.Rm] & 0x1;
} else {
- cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu));
+ cpu->Reg[14] = (cpu->Reg[15] + cpu->GetInstructionSize());
cpu->TFlag = 0x1;
int signed_int = inst_cream->val.signed_immed_24;
signed_int = (signed_int & 0x800000) ? (0x3F000000 | signed_int) : signed_int;
@@ -4125,7 +4092,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
INC_PC(sizeof(blx_inst));
goto DISPATCH;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(blx_inst));
goto DISPATCH;
}
@@ -4144,16 +4111,18 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
bx_inst* const inst_cream = (bx_inst*)inst_base->component;
+ u32 address = RM;
+
if (inst_cream->Rm == 15)
- LOG_WARNING(Core_ARM11, "BX at pc %x: use of Rm = R15 is discouraged", cpu->Reg[15]);
+ address += 2 * cpu->GetInstructionSize();
- cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1;
- cpu->Reg[15] = cpu->Reg[inst_cream->Rm] & 0xfffffffe;
+ cpu->TFlag = address & 1;
+ cpu->Reg[15] = address & 0xfffffffe;
INC_PC(sizeof(bx_inst));
goto DISPATCH;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(bx_inst));
goto DISPATCH;
}
@@ -4165,7 +4134,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
cpu->NumInstrsToExecute = 0;
return num_instrs;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(cdp_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4173,10 +4142,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
CLREX_INST:
{
- remove_exclusive(cpu, 0);
- cpu->exclusive_state = 0;
-
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->UnsetExclusiveMemoryAddress();
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(clrex_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4187,7 +4154,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
clz_inst* inst_cream = (clz_inst*)inst_base->component;
RD = clz(RM);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(clz_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4206,7 +4173,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
cpu->CFlag = carry;
cpu->VFlag = overflow;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(cmn_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4218,7 +4185,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
u32 rn_val = RN;
if (inst_cream->Rn == 15)
- rn_val += 2 * GET_INST_SIZE(cpu);
+ rn_val += 2 * cpu->GetInstructionSize();
bool carry;
bool overflow;
@@ -4229,7 +4196,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
cpu->CFlag = carry;
cpu->VFlag = overflow;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(cmp_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4239,7 +4206,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
cps_inst *inst_cream = (cps_inst *)inst_base->component;
uint32_t aif_val = 0;
uint32_t aif_mask = 0;
- if (InAPrivilegedMode(cpu)) {
+ if (cpu->InAPrivilegedMode()) {
if (inst_cream->imod1) {
if (inst_cream->A) {
aif_val |= (inst_cream->imod0 << 8);
@@ -4258,10 +4225,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
}
if (inst_cream->mmod) {
cpu->Cpsr = (cpu->Cpsr & 0xffffffe0) | inst_cream->mode;
- switch_mode(cpu, inst_cream->mode);
+ cpu->ChangePrivilegeMode(inst_cream->mode);
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(cps_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4277,7 +4244,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(mov_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4289,14 +4256,14 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
u32 lop = RN;
if (inst_cream->Rn == 15) {
- lop += 2 * GET_INST_SIZE(cpu);
+ lop += 2 * cpu->GetInstructionSize();
}
u32 rop = SHIFTER_OPERAND;
RD = lop ^ rop;
if (inst_cream->S && (inst_cream->Rd == 15)) {
if (CurrentModeHasSPSR) {
cpu->Cpsr = cpu->Spsr_copy;
- switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
LOAD_NZCVT;
}
} else if (inst_cream->S) {
@@ -4309,7 +4276,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(eor_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4318,7 +4285,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
{
// Instruction not implemented
//LOG_CRITICAL(Core_ARM11, "unimplemented instruction");
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldc_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4333,30 +4300,30 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
if (BIT(inst, 22) && !BIT(inst, 15)) {
for (int i = 0; i < 13; i++) {
if(BIT(inst, i)) {
- cpu->Reg[i] = ReadMemory32(cpu, addr);
+ cpu->Reg[i] = cpu->ReadMemory32(addr);
addr += 4;
}
}
if (BIT(inst, 13)) {
if (cpu->Mode == USER32MODE)
- cpu->Reg[13] = ReadMemory32(cpu, addr);
+ cpu->Reg[13] = cpu->ReadMemory32(addr);
else
- cpu->Reg_usr[0] = ReadMemory32(cpu, addr);
+ cpu->Reg_usr[0] = cpu->ReadMemory32(addr);
addr += 4;
}
if (BIT(inst, 14)) {
if (cpu->Mode == USER32MODE)
- cpu->Reg[14] = ReadMemory32(cpu, addr);
+ cpu->Reg[14] = cpu->ReadMemory32(addr);
else
- cpu->Reg_usr[1] = ReadMemory32(cpu, addr);
+ cpu->Reg_usr[1] = cpu->ReadMemory32(addr);
addr += 4;
}
} else if (!BIT(inst, 22)) {
for(int i = 0; i < 16; i++ ){
if(BIT(inst, i)){
- unsigned int ret = ReadMemory32(cpu, addr);
+ unsigned int ret = cpu->ReadMemory32(addr);
// For armv5t, should enter thumb when bits[0] is non-zero.
if(i == 15){
@@ -4371,18 +4338,18 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
} else if (BIT(inst, 22) && BIT(inst, 15)) {
for(int i = 0; i < 15; i++ ){
if(BIT(inst, i)){
- cpu->Reg[i] = ReadMemory32(cpu, addr);
+ cpu->Reg[i] = cpu->ReadMemory32(addr);
addr += 4;
}
}
if (CurrentModeHasSPSR) {
cpu->Cpsr = cpu->Spsr_copy;
- switch_mode(cpu, cpu->Cpsr & 0x1f);
+ cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F);
LOAD_NZCVT;
}
- cpu->Reg[15] = ReadMemory32(cpu, addr);
+ cpu->Reg[15] = cpu->ReadMemory32(addr);
}
if (BIT(inst, 15)) {
@@ -4390,7 +4357,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4408,7 +4375,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
}
RD = operand2;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(sxth_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4418,7 +4385,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
inst_cream->get_addr(cpu, inst_cream->inst, addr);
- unsigned int value = ReadMemory32(cpu, addr);
+ unsigned int value = cpu->ReadMemory32(addr);
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
@@ -4429,7 +4396,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4440,7 +4407,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
inst_cream->get_addr(cpu, inst_cream->inst, addr);
- unsigned int value = ReadMemory32(cpu, addr);
+ unsigned int value = cpu->ReadMemory32(addr);
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
@@ -4451,7 +4418,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4462,7 +4429,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
uxth_inst* inst_cream = (uxth_inst*)inst_base->component;
RD = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(uxth_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4475,7 +4442,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
RD = RN + operand2;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(uxtah_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4493,7 +4460,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4511,7 +4478,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4525,8 +4492,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
// The 3DS doesn't have LPAE (Large Physical Access Extension), so it
// wouldn't do this as a single read.
- cpu->Reg[BITS(inst_cream->inst, 12, 15) + 0] = ReadMemory32(cpu, addr);
- cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1] = ReadMemory32(cpu, addr + 4);
+ cpu->Reg[BITS(inst_cream->inst, 12, 15) + 0] = cpu->ReadMemory32(addr);
+ cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1] = cpu->ReadMemory32(addr + 4);
// No dispatch since this operation should not modify R15
}
@@ -4542,16 +4509,15 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
unsigned int read_addr = RN;
- add_exclusive_addr(cpu, read_addr);
- cpu->exclusive_state = 1;
+ cpu->SetExclusiveMemoryAddress(read_addr);
- RD = ReadMemory32(cpu, read_addr);
+ RD = cpu->ReadMemory32(read_addr);
if (inst_cream->Rd == 15) {
INC_PC(sizeof(generic_arm_inst));
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4562,8 +4528,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
unsigned int read_addr = RN;
- add_exclusive_addr(cpu, read_addr);
- cpu->exclusive_state = 1;
+ cpu->SetExclusiveMemoryAddress(read_addr);
RD = Memory::Read8(read_addr);
if (inst_cream->Rd == 15) {
@@ -4571,7 +4536,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4582,16 +4547,15 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
unsigned int read_addr = RN;
- add_exclusive_addr(cpu, read_addr);
- cpu->exclusive_state = 1;
+ cpu->SetExclusiveMemoryAddress(read_addr);
- RD = ReadMemory16(cpu, read_addr);
+ RD = cpu->ReadMemory16(read_addr);
if (inst_cream->Rd == 15) {
INC_PC(sizeof(generic_arm_inst));
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4602,18 +4566,17 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
unsigned int read_addr = RN;
- add_exclusive_addr(cpu, read_addr);
- cpu->exclusive_state = 1;
+ cpu->SetExclusiveMemoryAddress(read_addr);
- RD = ReadMemory32(cpu, read_addr);
- RD2 = ReadMemory32(cpu, read_addr + 4);
+ RD = cpu->ReadMemory32(read_addr);
+ RD2 = cpu->ReadMemory32(read_addr + 4);
if (inst_cream->Rd == 15) {
INC_PC(sizeof(generic_arm_inst));
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4624,13 +4587,13 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
inst_cream->get_addr(cpu, inst_cream->inst, addr);
- cpu->Reg[BITS(inst_cream->inst, 12, 15)] = ReadMemory16(cpu, addr);
+ cpu->Reg[BITS(inst_cream->inst, 12, 15)] = cpu->ReadMemory16(addr);
if (BITS(inst_cream->inst, 12, 15) == 15) {
INC_PC(sizeof(ldst_inst));
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4650,7 +4613,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4661,7 +4624,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
inst_cream->get_addr(cpu, inst_cream->inst, addr);
- unsigned int value = ReadMemory16(cpu, addr);
+ unsigned int value = cpu->ReadMemory16(addr);
if (BIT(value, 15)) {
value |= 0xffff0000;
}
@@ -4671,7 +4634,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4682,7 +4645,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
ldst_inst* inst_cream = (ldst_inst*)inst_base->component;
inst_cream->get_addr(cpu, inst_cream->inst, addr);
- unsigned int value = ReadMemory32(cpu, addr);
+ unsigned int value = cpu->ReadMemory32(addr);
cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
if (BITS(inst_cream->inst, 12, 15) == 15) {
@@ -4690,7 +4653,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4705,10 +4668,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
DEBUG_MSG;
} else {
if (inst_cream->cp_num == 15)
- WriteCP15Register(cpu, RD, CRn, OPCODE_1, CRm, OPCODE_2);
+ cpu->WriteCP15Register(RD, CRn, OPCODE_1, CRm, OPCODE_2);
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(mcr_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4725,7 +4688,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
inst_cream->cp_num, inst_cream->crm, inst_cream->opcode_1, inst_cream->rt, inst_cream->rt2);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(mcrr_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4750,7 +4713,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(mla_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4764,7 +4727,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
if (inst_cream->S && (inst_cream->Rd == 15)) {
if (CurrentModeHasSPSR) {
cpu->Cpsr = cpu->Spsr_copy;
- switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
LOAD_NZCVT;
}
} else if (inst_cream->S) {
@@ -4777,7 +4740,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(mov_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4798,10 +4761,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto END;
} else {
if (inst_cream->cp_num == 15)
- RD = ReadCP15Register(cpu, CRn, OPCODE_1, CRm, OPCODE_2);
+ RD = cpu->ReadCP15Register(CRn, OPCODE_1, CRm, OPCODE_2);
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(mrc_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4818,7 +4781,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
inst_cream->cp_num, inst_cream->crm, inst_cream->opcode_1, inst_cream->rt, inst_cream->rt2);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(mcrr_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4836,7 +4799,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
RD = cpu->Cpsr;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(mrs_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4859,7 +4822,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
| (BIT(inst, 18) ? 0xff0000 : 0) | (BIT(inst, 19) ? 0xff000000 : 0);
uint32_t mask = 0;
if (!inst_cream->R) {
- if (InAPrivilegedMode(cpu)) {
+ if (cpu->InAPrivilegedMode()) {
if ((operand & StateMask) != 0) {
/// UNPREDICTABLE
DEBUG_MSG;
@@ -4871,7 +4834,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
SAVE_NZCVT;
cpu->Cpsr = (cpu->Cpsr & ~mask) | (operand & mask);
- switch_mode(cpu, cpu->Cpsr & 0x1f);
+ cpu->ChangePrivilegeMode(cpu->Cpsr & 0x1F);
LOAD_NZCVT;
} else {
if (CurrentModeHasSPSR) {
@@ -4880,7 +4843,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
}
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(msr_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4902,7 +4865,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(mul_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4917,7 +4880,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
if (inst_cream->S && (inst_cream->Rd == 15)) {
if (CurrentModeHasSPSR) {
cpu->Cpsr = cpu->Spsr_copy;
- switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
LOAD_NZCVT;
}
} else if (inst_cream->S) {
@@ -4930,7 +4893,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(mvn_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4947,7 +4910,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
if (inst_cream->S && (inst_cream->Rd == 15)) {
if (CurrentModeHasSPSR) {
cpu->Cpsr = cpu->Spsr_copy;
- switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
LOAD_NZCVT;
}
} else if (inst_cream->S) {
@@ -4960,7 +4923,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(orr_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4968,7 +4931,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
NOP_INST:
{
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC_STUB;
FETCH_INST;
GOTO_NEXT_INST;
@@ -4980,7 +4943,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
pkh_inst *inst_cream = (pkh_inst *)inst_base->component;
RD = (RN & 0xFFFF) | ((RM << inst_cream->imm) & 0xFFFF0000);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(pkh_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -4993,7 +4956,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
int shift_imm = inst_cream->imm ? inst_cream->imm : 31;
RD = ((static_cast<s32>(RM) >> shift_imm) & 0xFFFF) | (RN & 0xFFFF0000);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(pkh_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5003,7 +4966,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
{
// Not implemented. PLD is a hint instruction, so it's optional.
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(pld_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5076,7 +5039,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
RD = result;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5138,7 +5101,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5171,7 +5134,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(rev_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5185,8 +5148,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
u32 address = 0;
inst_cream->get_addr(cpu, inst_cream->inst, address);
- cpu->Cpsr = ReadMemory32(cpu, address);
- cpu->Reg[15] = ReadMemory32(cpu, address + 4);
+ cpu->Cpsr = cpu->ReadMemory32(address);
+ cpu->Reg[15] = cpu->ReadMemory32(address + 4);
INC_PC(sizeof(ldst_inst));
goto DISPATCH;
@@ -5199,7 +5162,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
u32 rn_val = RN;
if (inst_cream->Rn == 15)
- rn_val += 2 * GET_INST_SIZE(cpu);
+ rn_val += 2 * cpu->GetInstructionSize();
bool carry;
bool overflow;
@@ -5208,7 +5171,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
if (inst_cream->S && (inst_cream->Rd == 15)) {
if (CurrentModeHasSPSR) {
cpu->Cpsr = cpu->Spsr_copy;
- switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
LOAD_NZCVT;
}
} else if (inst_cream->S) {
@@ -5222,7 +5185,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(rsb_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5239,7 +5202,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
if (inst_cream->S && (inst_cream->Rd == 15)) {
if (CurrentModeHasSPSR) {
cpu->Cpsr = cpu->Spsr_copy;
- switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
LOAD_NZCVT;
}
} else if (inst_cream->S) {
@@ -5253,7 +5216,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(rsc_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5361,7 +5324,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5379,7 +5342,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
if (inst_cream->S && (inst_cream->Rd == 15)) {
if (CurrentModeHasSPSR) {
cpu->Cpsr = cpu->Spsr_copy;
- switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
LOAD_NZCVT;
}
} else if (inst_cream->S) {
@@ -5393,7 +5356,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(sbc_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5432,7 +5395,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
RD = result;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5451,7 +5414,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
LOG_WARNING(Core_ARM11, "SETEND %s executed", big_endian ? "BE" : "LE");
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(setend_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5464,7 +5427,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
LOG_TRACE(Core_ARM11, "SEV executed.");
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC_STUB;
FETCH_INST;
GOTO_NEXT_INST;
@@ -5536,7 +5499,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5561,7 +5524,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
if (AddOverflow(operand1 * operand2, RN, RD))
cpu->Cpsr |= (1 << 27);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(smla_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5617,7 +5580,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(smlad_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5646,7 +5609,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
cpu->ZFlag = (RDHI == 0 && RDLO == 0);
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(umlal_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5676,7 +5639,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
RDHI = ((dest >> 32) & 0xFFFFFFFF);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(smlalxy_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5695,13 +5658,13 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
const s16 operand2 = (high) ? ((rm_val >> 16) & 0xFFFF) : (rm_val & 0xFFFF);
const s64 result = (s64)(s32)rn_val * (s64)(s32)operand2 + ((s64)(s32)ra_val << 16);
- RD = (result & (0xFFFFFFFFFFFFFFFFLL >> 15)) >> 16;
+ RD = BITS(result, 16, 47);
if ((result >> 16) != (s32)RD)
cpu->Cpsr |= (1 << 27);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(smlad_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5739,7 +5702,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
RDHI = ((result >> 32) & 0xFFFFFFFF);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(smlald_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5775,7 +5738,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
RD = ((result >> 32) & 0xFFFFFFFF);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(smlad_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5797,7 +5760,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31);
RD = operand1 * operand2;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(smul_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5823,7 +5786,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
cpu->ZFlag = (RDHI == 0 && RDLO == 0);
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(umull_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5839,7 +5802,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
s64 result = (s64)rm * (s64)(s32)RN;
RD = BITS(result, 16, 47);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(smlad_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5853,10 +5816,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
u32 address = 0;
inst_cream->get_addr(cpu, inst_cream->inst, address);
- WriteMemory32(cpu, address + 0, cpu->Reg[14]);
- WriteMemory32(cpu, address + 4, cpu->Spsr_copy);
+ cpu->WriteMemory32(address + 0, cpu->Reg[14]);
+ cpu->WriteMemory32(address + 4, cpu->Spsr_copy);
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5889,7 +5852,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
RD = rn_val;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ssat_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5911,7 +5874,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
cpu->Cpsr |= (1 << 27);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ssat_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5921,7 +5884,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
{
// Instruction not implemented
//LOG_CRITICAL(Core_ARM11, "unimplemented instruction");
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(stc_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5939,36 +5902,36 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
if (BIT(inst_cream->inst, 22) == 1) {
for (int i = 0; i < 13; i++) {
if (BIT(inst_cream->inst, i)) {
- WriteMemory32(cpu, addr, cpu->Reg[i]);
+ cpu->WriteMemory32(addr, cpu->Reg[i]);
addr += 4;
}
}
if (BIT(inst_cream->inst, 13)) {
if (cpu->Mode == USER32MODE)
- WriteMemory32(cpu, addr, cpu->Reg[13]);
+ cpu->WriteMemory32(addr, cpu->Reg[13]);
else
- WriteMemory32(cpu, addr, cpu->Reg_usr[0]);
+ cpu->WriteMemory32(addr, cpu->Reg_usr[0]);
addr += 4;
}
if (BIT(inst_cream->inst, 14)) {
if (cpu->Mode == USER32MODE)
- WriteMemory32(cpu, addr, cpu->Reg[14]);
+ cpu->WriteMemory32(addr, cpu->Reg[14]);
else
- WriteMemory32(cpu, addr, cpu->Reg_usr[1]);
+ cpu->WriteMemory32(addr, cpu->Reg_usr[1]);
addr += 4;
}
if (BIT(inst_cream->inst, 15)) {
- WriteMemory32(cpu, addr, cpu->Reg_usr[1] + 8);
+ cpu->WriteMemory32(addr, cpu->Reg_usr[1] + 8);
}
} else {
for (int i = 0; i < 15; i++) {
if (BIT(inst_cream->inst, i)) {
if (i == Rn)
- WriteMemory32(cpu, addr, old_RN);
+ cpu->WriteMemory32(addr, old_RN);
else
- WriteMemory32(cpu, addr, cpu->Reg[i]);
+ cpu->WriteMemory32(addr, cpu->Reg[i]);
addr += 4;
}
@@ -5976,10 +5939,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
// Check PC reg
if (BIT(inst_cream->inst, 15))
- WriteMemory32(cpu, addr, cpu->Reg_usr[1] + 8);
+ cpu->WriteMemory32(addr, cpu->Reg_usr[1] + 8);
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -5997,7 +5960,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
}
RD = operand2;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(sxtb_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6009,9 +5972,9 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
inst_cream->get_addr(cpu, inst_cream->inst, addr);
unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)];
- WriteMemory32(cpu, addr, value);
+ cpu->WriteMemory32(addr, value);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6022,7 +5985,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
uxtb_inst* inst_cream = (uxtb_inst*)inst_base->component;
RD = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(uxtb_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6035,7 +5998,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff;
RD = RN + operand2;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(uxtab_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6048,7 +6011,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff;
Memory::Write8(addr, value);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6061,7 +6024,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff;
Memory::Write8(addr, value);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6074,10 +6037,10 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
// The 3DS doesn't have the Large Physical Access Extension (LPAE)
// so STRD wouldn't store these as a single write.
- WriteMemory32(cpu, addr + 0, cpu->Reg[BITS(inst_cream->inst, 12, 15)]);
- WriteMemory32(cpu, addr + 4, cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1]);
+ cpu->WriteMemory32(addr + 0, cpu->Reg[BITS(inst_cream->inst, 12, 15)]);
+ cpu->WriteMemory32(addr + 4, cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1]);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6088,18 +6051,16 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
unsigned int write_addr = cpu->Reg[inst_cream->Rn];
- if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) {
- remove_exclusive(cpu, write_addr);
- cpu->exclusive_state = 0;
-
- WriteMemory32(cpu, write_addr, RM);
+ if (cpu->IsExclusiveMemoryAccess(write_addr)) {
+ cpu->UnsetExclusiveMemoryAddress();
+ cpu->WriteMemory32(write_addr, RM);
RD = 0;
} else {
// Failed to write due to mutex access
RD = 1;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6110,10 +6071,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
unsigned int write_addr = cpu->Reg[inst_cream->Rn];
- if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) {
- remove_exclusive(cpu, write_addr);
- cpu->exclusive_state = 0;
-
+ if (cpu->IsExclusiveMemoryAccess(write_addr)) {
+ cpu->UnsetExclusiveMemoryAddress();
Memory::Write8(write_addr, cpu->Reg[inst_cream->Rm]);
RD = 0;
} else {
@@ -6121,7 +6080,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
RD = 1;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6132,20 +6091,19 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
unsigned int write_addr = cpu->Reg[inst_cream->Rn];
- if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) {
- remove_exclusive(cpu, write_addr);
- cpu->exclusive_state = 0;
+ if (cpu->IsExclusiveMemoryAccess(write_addr)) {
+ cpu->UnsetExclusiveMemoryAddress();
const u32 rt = cpu->Reg[inst_cream->Rm + 0];
const u32 rt2 = cpu->Reg[inst_cream->Rm + 1];
u64 value;
- if (InBigEndianMode(cpu))
+ if (cpu->InBigEndianMode())
value = (((u64)rt << 32) | rt2);
else
value = (((u64)rt2 << 32) | rt);
- WriteMemory64(cpu, write_addr, value);
+ cpu->WriteMemory64(write_addr, value);
RD = 0;
}
else {
@@ -6153,7 +6111,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
RD = 1;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6164,18 +6122,16 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
unsigned int write_addr = cpu->Reg[inst_cream->Rn];
- if ((exclusive_detect(cpu, write_addr) == 0) && (cpu->exclusive_state == 1)) {
- remove_exclusive(cpu, write_addr);
- cpu->exclusive_state = 0;
-
- WriteMemory16(cpu, write_addr, RM);
+ if (cpu->IsExclusiveMemoryAccess(write_addr)) {
+ cpu->UnsetExclusiveMemoryAddress();
+ cpu->WriteMemory16(write_addr, RM);
RD = 0;
} else {
// Failed to write due to mutex access
RD = 1;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6187,9 +6143,9 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
inst_cream->get_addr(cpu, inst_cream->inst, addr);
unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xffff;
- WriteMemory16(cpu, addr, value);
+ cpu->WriteMemory16(addr, value);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6201,9 +6157,9 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
inst_cream->get_addr(cpu, inst_cream->inst, addr);
unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)];
- WriteMemory32(cpu, addr, value);
+ cpu->WriteMemory32(addr, value);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ldst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6224,7 +6180,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
if (inst_cream->S && (inst_cream->Rd == 15)) {
if (CurrentModeHasSPSR) {
cpu->Cpsr = cpu->Spsr_copy;
- switch_mode(cpu, cpu->Spsr_copy & 0x1f);
+ cpu->ChangePrivilegeMode(cpu->Spsr_copy & 0x1F);
LOAD_NZCVT;
}
} else if (inst_cream->S) {
@@ -6238,7 +6194,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
goto DISPATCH;
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(sub_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6246,10 +6202,11 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
SWI_INST:
{
if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
- SVC::CallSVC(Memory::Read32(cpu->Reg[15]));
+ swi_inst* const inst_cream = (swi_inst*)inst_base->component;
+ SVC::CallSVC(inst_cream->num & 0xFFFF);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(swi_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6260,12 +6217,12 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
swp_inst* inst_cream = (swp_inst*)inst_base->component;
addr = RN;
- unsigned int value = ReadMemory32(cpu, addr);
- WriteMemory32(cpu, addr, RM);
+ unsigned int value = cpu->ReadMemory32(addr);
+ cpu->WriteMemory32(addr, RM);
RD = value;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(swp_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6279,7 +6236,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
Memory::Write8(addr, (RM & 0xFF));
RD = value;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(swp_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6295,7 +6252,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
operand2 = (0x80 & operand2)? (0xFFFFFF00 | operand2):operand2;
RD = RN + operand2;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(uxtab_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6328,7 +6285,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(sxtab_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6344,7 +6301,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
operand2 = (0x8000 & operand2) ? (0xFFFF0000 | operand2) : operand2;
RD = RN + operand2;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(sxtah_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6359,7 +6316,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
u32 rop = SHIFTER_OPERAND;
if (inst_cream->Rn == 15)
- lop += GET_INST_SIZE(cpu) * 2;
+ lop += cpu->GetInstructionSize() * 2;
u32 result = lop ^ rop;
@@ -6367,7 +6324,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
UPDATE_ZFLAG(result);
UPDATE_CFLAG_WITH_SC;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(teq_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6381,7 +6338,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
u32 rop = SHIFTER_OPERAND;
if (inst_cream->Rn == 15)
- lop += GET_INST_SIZE(cpu) * 2;
+ lop += cpu->GetInstructionSize() * 2;
u32 result = lop & rop;
@@ -6389,7 +6346,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
UPDATE_ZFLAG(result);
UPDATE_CFLAG_WITH_SC;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(tst_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6560,7 +6517,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6640,7 +6597,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6659,7 +6616,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
RDLO = (result & 0xFFFFFFFF);
RDHI = ((result >> 32) & 0xFFFFFFFF);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(umaal_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6682,7 +6639,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
cpu->ZFlag = (RDHI == 0 && RDLO == 0);
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(umlal_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6702,7 +6659,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
cpu->ZFlag = (RDHI == 0 && RDLO == 0);
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(umull_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6730,7 +6687,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
{
bl_1_thumb* inst_cream = (bl_1_thumb*)inst_base->component;
cpu->Reg[14] = cpu->Reg[15] + 4 + inst_cream->imm;
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(bl_1_thumb));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6811,7 +6768,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
RD = ((lo_val & 0xFFFF) | hi_val << 16);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6841,7 +6798,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
RD = finalDif;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(generic_arm_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6874,7 +6831,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
RD = rn_val;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ssat_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6896,7 +6853,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
cpu->Cpsr |= (1 << 27);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(ssat_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6927,7 +6884,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(uxtab_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -6940,7 +6897,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
LOG_TRACE(Core_ARM11, "WFE executed.");
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC_STUB;
FETCH_INST;
GOTO_NEXT_INST;
@@ -6953,7 +6910,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
LOG_TRACE(Core_ARM11, "WFI executed.");
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC_STUB;
FETCH_INST;
GOTO_NEXT_INST;
@@ -6966,7 +6923,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
LOG_TRACE(Core_ARM11, "YIELD executed.");
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC_STUB;
FETCH_INST;
GOTO_NEXT_INST;
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.h b/src/core/arm/dyncom/arm_dyncom_interpreter.h
index 1c324d29..7a46dcc9 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.h
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.h
@@ -4,6 +4,6 @@
#pragma once
-#include "core/arm/skyeye_common/armdefs.h"
+struct ARMul_State;
unsigned 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 5a9a6a78..00000000
--- a/src/core/arm/dyncom/arm_dyncom_run.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2012 Michael Kang, 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/arm/dyncom/arm_dyncom_run.h"
-#include "core/arm/skyeye_common/armdefs.h"
-
-void switch_mode(ARMul_State* core, uint32_t mode) {
- if (core->Mode == mode)
- return;
-
- if (mode != USERBANK) {
- switch (core->Mode) {
- case SYSTEM32MODE: // Shares registers with user mode
- case USER32MODE:
- core->Reg_usr[0] = core->Reg[13];
- core->Reg_usr[1] = core->Reg[14];
- break;
- case IRQ32MODE:
- core->Reg_irq[0] = core->Reg[13];
- core->Reg_irq[1] = core->Reg[14];
- core->Spsr[IRQBANK] = core->Spsr_copy;
- break;
- case SVC32MODE:
- core->Reg_svc[0] = core->Reg[13];
- core->Reg_svc[1] = core->Reg[14];
- core->Spsr[SVCBANK] = core->Spsr_copy;
- break;
- case ABORT32MODE:
- core->Reg_abort[0] = core->Reg[13];
- core->Reg_abort[1] = core->Reg[14];
- core->Spsr[ABORTBANK] = core->Spsr_copy;
- break;
- case UNDEF32MODE:
- core->Reg_undef[0] = core->Reg[13];
- core->Reg_undef[1] = core->Reg[14];
- core->Spsr[UNDEFBANK] = core->Spsr_copy;
- break;
- case FIQ32MODE:
- core->Reg_firq[0] = core->Reg[13];
- core->Reg_firq[1] = core->Reg[14];
- core->Spsr[FIQBANK] = core->Spsr_copy;
- break;
- }
-
- switch (mode) {
- case USER32MODE:
- core->Reg[13] = core->Reg_usr[0];
- core->Reg[14] = core->Reg_usr[1];
- core->Bank = USERBANK;
- break;
- case IRQ32MODE:
- core->Reg[13] = core->Reg_irq[0];
- core->Reg[14] = core->Reg_irq[1];
- core->Spsr_copy = core->Spsr[IRQBANK];
- core->Bank = IRQBANK;
- break;
- case SVC32MODE:
- core->Reg[13] = core->Reg_svc[0];
- core->Reg[14] = core->Reg_svc[1];
- core->Spsr_copy = core->Spsr[SVCBANK];
- core->Bank = SVCBANK;
- break;
- case ABORT32MODE:
- core->Reg[13] = core->Reg_abort[0];
- core->Reg[14] = core->Reg_abort[1];
- core->Spsr_copy = core->Spsr[ABORTBANK];
- core->Bank = ABORTBANK;
- break;
- case UNDEF32MODE:
- core->Reg[13] = core->Reg_undef[0];
- core->Reg[14] = core->Reg_undef[1];
- core->Spsr_copy = core->Spsr[UNDEFBANK];
- core->Bank = UNDEFBANK;
- break;
- case FIQ32MODE:
- core->Reg[13] = core->Reg_firq[0];
- core->Reg[14] = core->Reg_firq[1];
- core->Spsr_copy = core->Spsr[FIQBANK];
- core->Bank = FIQBANK;
- break;
- case SYSTEM32MODE: // Shares registers with user mode.
- core->Reg[13] = core->Reg_usr[0];
- core->Reg[14] = core->Reg_usr[1];
- core->Bank = SYSTEMBANK;
- break;
- }
-
- // Set the mode bits in the APSR
- core->Cpsr = (core->Cpsr & ~core->Mode) | mode;
- core->Mode = mode;
- }
-}
diff --git a/src/core/arm/dyncom/arm_dyncom_run.h b/src/core/arm/dyncom/arm_dyncom_run.h
index 85774c56..13bef17f 100644
--- a/src/core/arm/dyncom/arm_dyncom_run.h
+++ b/src/core/arm/dyncom/arm_dyncom_run.h
@@ -18,40 +18,31 @@
#pragma once
-#include "core/arm/skyeye_common/armdefs.h"
-
-void switch_mode(ARMul_State* core, uint32_t mode);
-
-// Note that for the 3DS, a Thumb instruction will only ever be
-// two bytes in size. Thus we don't need to worry about ThumbEE
-// or Thumb-2 where instructions can be 4 bytes in length.
-static inline u32 GET_INST_SIZE(ARMul_State* core) {
- return core->TFlag? 2 : 4;
-}
+#include "core/arm/skyeye_common/armstate.h"
/**
* Checks if the PC is being read, and if so, word-aligns it.
* Used with address calculations.
*
- * @param core The ARM CPU state instance.
+ * @param cpu The ARM CPU state instance.
* @param Rn The register being read.
*
* @return If the PC is being read, then the word-aligned PC value is returned.
* If the PC is not being read, then the value stored in the register is returned.
*/
-static inline u32 CHECK_READ_REG15_WA(ARMul_State* core, int Rn) {
- return (Rn == 15) ? ((core->Reg[15] & ~0x3) + GET_INST_SIZE(core) * 2) : core->Reg[Rn];
+static inline u32 CHECK_READ_REG15_WA(ARMul_State* cpu, int Rn) {
+ return (Rn == 15) ? ((cpu->Reg[15] & ~0x3) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn];
}
/**
* Reads the PC. Used for data processing operations that use the PC.
*
- * @param core The ARM CPU state instance.
+ * @param cpu The ARM CPU state instance.
* @param Rn The register being read.
*
* @return If the PC is being read, then the incremented PC value is returned.
* If the PC is not being read, then the values stored in the register is returned.
*/
-static inline u32 CHECK_READ_REG15(ARMul_State* core, int Rn) {
- return (Rn == 15) ? ((core->Reg[15] & ~0x1) + GET_INST_SIZE(core) * 2) : core->Reg[Rn];
+static inline u32 CHECK_READ_REG15(ARMul_State* cpu, int Rn) {
+ return (Rn == 15) ? ((cpu->Reg[15] & ~0x1) + cpu->GetInstructionSize() * 2) : cpu->Reg[Rn];
}
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
index 3e79c44c..29272fd5 100644
--- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
@@ -6,20 +6,15 @@
// ARM instruction, and using the existing ARM simulator.
#include "core/arm/dyncom/arm_dyncom_thumb.h"
+#include "core/arm/skyeye_common/armsupp.h"
// Decode a 16bit Thumb instruction. The instruction is in the low 16-bits of the tinstr field,
// with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions
// allows easier simulation of the special dual BL instruction.
-tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
- tdstate valid = t_uninitialized;
- ARMword tinstr = instr;
-
- // The endian should be judge here
- if((addr & 0x3) != 0)
- tinstr = instr >> 16;
- else
- tinstr &= 0xFFFF;
+ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
+ ThumbDecodeStatus valid = ThumbDecodeStatus::UNINITIALIZED;
+ u32 tinstr = GetThumbInstruction(instr, addr);
*ainstr = 0xDEADC0DE; // Debugging to catch non updates
@@ -36,7 +31,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
case 3: // ADD/SUB
{
- static const ARMword subset[4] = {
+ static const u32 subset[4] = {
0xE0900000, // ADDS Rd,Rs,Rn
0xE0500000, // SUBS Rd,Rs,Rn
0xE2900000, // ADDS Rd,Rs,#imm3
@@ -55,7 +50,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
case 6: // ADD
case 7: // SUB
{
- static const ARMword subset[4] = {
+ static const u32 subset[4] = {
0xE3B00000, // MOVS Rd,#imm8
0xE3500000, // CMP Rd,#imm8
0xE2900000, // ADDS Rd,Rd,#imm8
@@ -84,7 +79,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
};
static const struct {
- ARMword opcode;
+ u32 opcode;
otype type;
} subset[16] = {
{ 0xE0100000, t_norm }, // ANDS Rd,Rd,Rs
@@ -129,15 +124,14 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
break;
}
} else {
- ARMword Rd = ((tinstr & 0x0007) >> 0);
- ARMword Rs = ((tinstr & 0x0038) >> 3);
+ u32 Rd = ((tinstr & 0x0007) >> 0);
+ u32 Rs = ((tinstr & 0x0078) >> 3);
if (tinstr & (1 << 7))
Rd += 8;
- if (tinstr & (1 << 6))
- Rs += 8;
switch ((tinstr & 0x03C0) >> 6) {
+ case 0x0: // ADD Rd,Rd,Rs
case 0x1: // ADD Rd,Rd,Hs
case 0x2: // ADD Hd,Hd,Rs
case 0x3: // ADD Hd,Hd,Hs
@@ -146,19 +140,19 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
|(Rd << 12) // Rd
|(Rs << 0); // Rm
break;
+ case 0x4: // CMP Rd,Rs
case 0x5: // CMP Rd,Hs
case 0x6: // CMP Hd,Rs
case 0x7: // CMP Hd,Hs
*ainstr = 0xE1500000 // base
| (Rd << 16) // Rn
- |(Rd << 12) // Rd
|(Rs << 0); // Rm
break;
+ case 0x8: // MOV Rd,Rs
case 0x9: // MOV Rd,Hs
case 0xA: // MOV Hd,Rs
case 0xB: // MOV Hd,Hs
*ainstr = 0xE1A00000 // base
- | (Rd << 16) // Rn
|(Rd << 12) // Rd
|(Rs << 0); // Rm
break;
@@ -167,11 +161,6 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
*ainstr = 0xE12FFF10 // base
| ((tinstr & 0x0078) >> 3); // Rd
break;
- case 0x0: // UNDEFINED
- case 0x4: // UNDEFINED
- case 0x8: // UNDEFINED
- valid = t_undefined;
- break;
case 0xE: // BLX
case 0xF: // BLX
*ainstr = 0xE1200030 // base
@@ -190,7 +179,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
case 10:
case 11:
{
- static const ARMword subset[8] = {
+ static const u32 subset[8] = {
0xE7800000, // STR Rd,[Rb,Ro]
0xE18000B0, // STRH Rd,[Rb,Ro]
0xE7C00000, // STRB Rd,[Rb,Ro]
@@ -213,7 +202,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
case 14: // STRB Rd,[Rb,#imm5]
case 15: // LDRB Rd,[Rb,#imm5]
{
- static const ARMword subset[4] = {
+ static const u32 subset[4] = {
0xE5800000, // STR Rd,[Rb,#imm5]
0xE5900000, // LDR Rd,[Rb,#imm5]
0xE5C00000, // STRB Rd,[Rb,#imm5]
@@ -280,7 +269,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
| BITS(tinstr, 0, 3) // imm4 field;
| (BITS(tinstr, 4, 7) << 8); // beginning 4 bits of imm12
} else if ((tinstr & 0x0F00) == 0x0200) {
- static const ARMword subset[4] = {
+ static const u32 subset[4] = {
0xE6BF0070, // SXTH
0xE6AF0070, // SXTB
0xE6FF0070, // UXTH
@@ -304,7 +293,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
| (BIT(tinstr, 4) << 18); // enable bit
}
} else if ((tinstr & 0x0F00) == 0x0a00) {
- static const ARMword subset[3] = {
+ static const u32 subset[3] = {
0xE6BF0F30, // REV
0xE6BF0FB0, // REV16
0xE6FF0FB0, // REVSH
@@ -314,7 +303,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
| (BITS(tinstr, 0, 2) << 12) // Rd
| BITS(tinstr, 3, 5); // Rm
} else {
- static const ARMword subset[4] = {
+ static const u32 subset[4] = {
0xE92D0000, // STMDB sp!,{rlist}
0xE92D4000, // STMDB sp!,{rlist,lr}
0xE8BD0000, // LDMIA sp!,{rlist}
@@ -362,21 +351,21 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
else
*ainstr |= (tinstr & 0x00FF);
} else if ((tinstr & 0x0F00) != 0x0E00)
- valid = t_branch;
+ valid = ThumbDecodeStatus::BRANCH;
else // UNDEFINED : cc=1110(AL) uses different format
- valid = t_undefined;
+ valid = ThumbDecodeStatus::UNDEFINED;
break;
case 28: // B
- valid = t_branch;
+ valid = ThumbDecodeStatus::BRANCH;
break;
case 29:
- if(tinstr & 0x1)
- valid = t_undefined;
+ if (tinstr & 0x1)
+ valid = ThumbDecodeStatus::UNDEFINED;
else
- valid = t_branch;
+ valid = ThumbDecodeStatus::BRANCH;
break;
case 30: // BL instruction 1
@@ -385,7 +374,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
// simulation simple (from the user perspective) we check if the following instruction is
// the second half of this BL, and if it is we simulate it immediately
- valid = t_branch;
+ valid = ThumbDecodeStatus::BRANCH;
break;
case 31: // BL instruction 2
@@ -394,7 +383,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
// ever be matched with the fmt19 "BL instruction 1" instruction. However, we do allow the
// simulation of it on its own, with undefined results if r14 is not suitably initialised.
- valid = t_branch;
+ valid = ThumbDecodeStatus::BRANCH;
break;
}
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.h b/src/core/arm/dyncom/arm_dyncom_thumb.h
index 8394ff15..44797436 100644
--- a/src/core/arm/dyncom/arm_dyncom_thumb.h
+++ b/src/core/arm/dyncom/arm_dyncom_thumb.h
@@ -26,22 +26,24 @@
#pragma once
-#include "core/arm/skyeye_common/armdefs.h"
+#include "common/common_types.h"
-enum tdstate {
- t_undefined, // Undefined Thumb instruction
- t_decoded, // Instruction decoded to ARM equivalent
- t_branch, // Thumb branch (already processed)
- t_uninitialized,
+enum class ThumbDecodeStatus {
+ UNDEFINED, // Undefined Thumb instruction
+ DECODED, // Instruction decoded to ARM equivalent
+ BRANCH, // Thumb branch (already processed)
+ UNINITIALIZED,
};
-tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size);
+// Translates a Thumb mode instruction into its ARM equivalent.
+ThumbDecodeStatus TranslateThumbInstruction(u32 addr, u32 instr, u32* ainstr, u32* inst_size);
-static inline u32 get_thumb_instr(u32 instr, u32 pc) {
- u32 tinstr;
- if ((pc & 0x3) != 0)
- tinstr = instr >> 16;
- else
- tinstr = instr & 0xFFFF;
- return tinstr;
+static inline u32 GetThumbInstruction(u32 instr, u32 address) {
+ // Normally you would need to handle instruction endianness,
+ // however, it is fixed to little-endian on the MPCore, so
+ // there's no need to check for this beforehand.
+ if ((address & 0x3) != 0)
+ return instr >> 16;
+
+ return instr & 0xFFFF;
}
diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp
deleted file mode 100644
index 4f7a48fa..00000000
--- a/src/core/arm/interpreter/arminit.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/* arminit.c -- ARMulator initialization: ARM6 Instruction Emulator.
- Copyright (C) 1994 Advanced RISC Machines Ltd.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#include <cstring>
-#include "core/arm/skyeye_common/armdefs.h"
-#include "core/arm/skyeye_common/vfp/vfp.h"
-
-/***************************************************************************\
-* Returns a new instantiation of the ARMulator's state *
-\***************************************************************************/
-ARMul_State* ARMul_NewState(ARMul_State* state)
-{
- state->Emulate = RUN;
- state->Mode = USER32MODE;
-
- state->lateabtSig = HIGH;
- state->bigendSig = LOW;
-
- return state;
-}
-
-/***************************************************************************\
-* Call this routine to set ARMulator to model a certain processor *
-\***************************************************************************/
-
-void ARMul_SelectProcessor(ARMul_State* state, unsigned properties)
-{
- state->is_v4 = (properties & (ARM_v4_Prop | ARM_v5_Prop)) != 0;
- state->is_v5 = (properties & ARM_v5_Prop) != 0;
- state->is_v5e = (properties & ARM_v5e_Prop) != 0;
- state->is_v6 = (properties & ARM_v6_Prop) != 0;
- state->is_v7 = (properties & ARM_v7_Prop) != 0;
-}
-
-// Resets certain MPCore CP15 values to their ARM-defined reset values.
-static void ResetMPCoreCP15Registers(ARMul_State* cpu)
-{
- // c0
- cpu->CP15[CP15_MAIN_ID] = 0x410FB024;
- cpu->CP15[CP15_TLB_TYPE] = 0x00000800;
- cpu->CP15[CP15_PROCESSOR_FEATURE_0] = 0x00000111;
- cpu->CP15[CP15_PROCESSOR_FEATURE_1] = 0x00000001;
- cpu->CP15[CP15_DEBUG_FEATURE_0] = 0x00000002;
- cpu->CP15[CP15_MEMORY_MODEL_FEATURE_0] = 0x01100103;
- cpu->CP15[CP15_MEMORY_MODEL_FEATURE_1] = 0x10020302;
- cpu->CP15[CP15_MEMORY_MODEL_FEATURE_2] = 0x01222000;
- cpu->CP15[CP15_MEMORY_MODEL_FEATURE_3] = 0x00000000;
- cpu->CP15[CP15_ISA_FEATURE_0] = 0x00100011;
- cpu->CP15[CP15_ISA_FEATURE_1] = 0x12002111;
- cpu->CP15[CP15_ISA_FEATURE_2] = 0x11221011;
- cpu->CP15[CP15_ISA_FEATURE_3] = 0x01102131;
- cpu->CP15[CP15_ISA_FEATURE_4] = 0x00000141;
-
- // c1
- cpu->CP15[CP15_CONTROL] = 0x00054078;
- cpu->CP15[CP15_AUXILIARY_CONTROL] = 0x0000000F;
- cpu->CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = 0x00000000;
-
- // c2
- cpu->CP15[CP15_TRANSLATION_BASE_TABLE_0] = 0x00000000;
- cpu->CP15[CP15_TRANSLATION_BASE_TABLE_1] = 0x00000000;
- cpu->CP15[CP15_TRANSLATION_BASE_CONTROL] = 0x00000000;
-
- // c3
- cpu->CP15[CP15_DOMAIN_ACCESS_CONTROL] = 0x00000000;
-
- // c7
- cpu->CP15[CP15_PHYS_ADDRESS] = 0x00000000;
-
- // c9
- cpu->CP15[CP15_DATA_CACHE_LOCKDOWN] = 0xFFFFFFF0;
-
- // c10
- cpu->CP15[CP15_TLB_LOCKDOWN] = 0x00000000;
- cpu->CP15[CP15_PRIMARY_REGION_REMAP] = 0x00098AA4;
- cpu->CP15[CP15_NORMAL_REGION_REMAP] = 0x44E048E0;
-
- // c13
- cpu->CP15[CP15_PID] = 0x00000000;
- cpu->CP15[CP15_CONTEXT_ID] = 0x00000000;
- cpu->CP15[CP15_THREAD_UPRW] = 0x00000000;
- cpu->CP15[CP15_THREAD_URO] = 0x00000000;
- cpu->CP15[CP15_THREAD_PRW] = 0x00000000;
-
- // c15
- cpu->CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = 0x00000000;
- cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = 0x00000000;
- cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = 0x00000000;
- cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = 0x00000000;
- cpu->CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000;
-}
-
-/***************************************************************************\
-* Call this routine to set up the initial machine state (or perform a RESET *
-\***************************************************************************/
-void ARMul_Reset(ARMul_State* state)
-{
- VFPInit(state);
-
- state->Reg[15] = 0;
- state->Cpsr = INTBITS | SVC32MODE;
- state->Mode = SVC32MODE;
- state->Bank = SVCBANK;
-
- ResetMPCoreCP15Registers(state);
-
- state->NresetSig = HIGH;
- state->NfiqSig = HIGH;
- state->NirqSig = HIGH;
- state->NtransSig = (state->Mode & 3) ? HIGH : LOW;
- state->abortSig = LOW;
-
- state->NumInstrs = 0;
-}
diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp
deleted file mode 100644
index 83f7f3e2..00000000
--- a/src/core/arm/interpreter/armsupp.cpp
+++ /dev/null
@@ -1,637 +0,0 @@
-/* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator.
- Copyright (C) 1994 Advanced RISC Machines Ltd.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#include "common/logging/log.h"
-
-#include "core/mem_map.h"
-#include "core/arm/skyeye_common/armdefs.h"
-#include "core/arm/skyeye_common/arm_regformat.h"
-
-// Unsigned sum of absolute difference
-u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right)
-{
- if (left > right)
- return left - right;
-
- return right - left;
-}
-
-// Add with carry, indicates if a carry-out or signed overflow occurred.
-u32 AddWithCarry(u32 left, u32 right, u32 carry_in, bool* carry_out_occurred, bool* overflow_occurred)
-{
- u64 unsigned_sum = (u64)left + (u64)right + (u64)carry_in;
- s64 signed_sum = (s64)(s32)left + (s64)(s32)right + (s64)carry_in;
- u64 result = (unsigned_sum & 0xFFFFFFFF);
-
- if (carry_out_occurred)
- *carry_out_occurred = (result != unsigned_sum);
-
- if (overflow_occurred)
- *overflow_occurred = ((s64)(s32)result != signed_sum);
-
- return (u32)result;
-}
-
-// Compute whether an addition of A and B, giving RESULT, overflowed.
-bool AddOverflow(ARMword a, ARMword b, ARMword result)
-{
- return ((NEG(a) && NEG(b) && POS(result)) ||
- (POS(a) && POS(b) && NEG(result)));
-}
-
-// Compute whether a subtraction of A and B, giving RESULT, overflowed.
-bool SubOverflow(ARMword a, ARMword b, ARMword result)
-{
- return ((NEG(a) && POS(b) && POS(result)) ||
- (POS(a) && NEG(b) && NEG(result)));
-}
-
-// Returns true if the Q flag should be set as a result of overflow.
-bool ARMul_AddOverflowQ(ARMword a, ARMword b)
-{
- u32 result = a + b;
- if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0)
- return true;
-
- return false;
-}
-
-// 8-bit signed saturated addition
-u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right)
-{
- u8 result = left + right;
-
- if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) == 0) {
- if (left & 0x80)
- result = 0x80;
- else
- result = 0x7F;
- }
-
- return result;
-}
-
-// 8-bit signed saturated subtraction
-u8 ARMul_SignedSaturatedSub8(u8 left, u8 right)
-{
- u8 result = left - right;
-
- if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) != 0) {
- if (left & 0x80)
- result = 0x80;
- else
- result = 0x7F;
- }
-
- return result;
-}
-
-// 16-bit signed saturated addition
-u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right)
-{
- u16 result = left + right;
-
- if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) == 0) {
- if (left & 0x8000)
- result = 0x8000;
- else
- result = 0x7FFF;
- }
-
- return result;
-}
-
-// 16-bit signed saturated subtraction
-u16 ARMul_SignedSaturatedSub16(u16 left, u16 right)
-{
- u16 result = left - right;
-
- if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) != 0) {
- if (left & 0x8000)
- result = 0x8000;
- else
- result = 0x7FFF;
- }
-
- return result;
-}
-
-// 8-bit unsigned saturated addition
-u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right)
-{
- u8 result = left + right;
-
- if (result < left)
- result = 0xFF;
-
- return result;
-}
-
-// 16-bit unsigned saturated addition
-u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right)
-{
- u16 result = left + right;
-
- if (result < left)
- result = 0xFFFF;
-
- return result;
-}
-
-// 8-bit unsigned saturated subtraction
-u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right)
-{
- if (left <= right)
- return 0;
-
- return left - right;
-}
-
-// 16-bit unsigned saturated subtraction
-u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right)
-{
- if (left <= right)
- return 0;
-
- return left - right;
-}
-
-// Signed saturation.
-u32 ARMul_SignedSatQ(s32 value, u8 shift, bool* saturation_occurred)
-{
- const u32 max = (1 << shift) - 1;
- const s32 top = (value >> shift);
-
- if (top > 0) {
- *saturation_occurred = true;
- return max;
- }
- else if (top < -1) {
- *saturation_occurred = true;
- return ~max;
- }
-
- *saturation_occurred = false;
- return (u32)value;
-}
-
-// Unsigned saturation
-u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred)
-{
- const u32 max = (1 << shift) - 1;
-
- if (value < 0) {
- *saturation_occurred = true;
- return 0;
- } else if ((u32)value > max) {
- *saturation_occurred = true;
- return max;
- }
-
- *saturation_occurred = false;
- return (u32)value;
-}
-
-// Whether or not the given CPU is in big endian mode (E bit is set)
-bool InBigEndianMode(ARMul_State* cpu)
-{
- return (cpu->Cpsr & (1 << 9)) != 0;
-}
-
-// Whether or not the given CPU is in a mode other than user mode.
-bool InAPrivilegedMode(ARMul_State* cpu)
-{
- return (cpu->Mode != USER32MODE);
-}
-
-// Reads from the CP15 registers. Used with implementation of the MRC instruction.
-// Note that since the 3DS does not have the hypervisor extensions, these registers
-// are not implemented.
-u32 ReadCP15Register(ARMul_State* cpu, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
-{
- // Unprivileged registers
- if (crn == 13 && opcode_1 == 0 && crm == 0)
- {
- if (opcode_2 == 2)
- return cpu->CP15[CP15_THREAD_UPRW];
-
- if (opcode_2 == 3)
- return cpu->CP15[CP15_THREAD_URO];
- }
-
- if (InAPrivilegedMode(cpu))
- {
- if (crn == 0 && opcode_1 == 0)
- {
- if (crm == 0)
- {
- if (opcode_2 == 0)
- return cpu->CP15[CP15_MAIN_ID];
-
- if (opcode_2 == 1)
- return cpu->CP15[CP15_CACHE_TYPE];
-
- if (opcode_2 == 3)
- return cpu->CP15[CP15_TLB_TYPE];
-
- if (opcode_2 == 5)
- return cpu->CP15[CP15_CPU_ID];
- }
- else if (crm == 1)
- {
- if (opcode_2 == 0)
- return cpu->CP15[CP15_PROCESSOR_FEATURE_0];
-
- if (opcode_2 == 1)
- return cpu->CP15[CP15_PROCESSOR_FEATURE_1];
-
- if (opcode_2 == 2)
- return cpu->CP15[CP15_DEBUG_FEATURE_0];
-
- if (opcode_2 == 4)
- return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_0];
-
- if (opcode_2 == 5)
- return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_1];
-
- if (opcode_2 == 6)
- return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_2];
-
- if (opcode_2 == 7)
- return cpu->CP15[CP15_MEMORY_MODEL_FEATURE_3];
- }
- else if (crm == 2)
- {
- if (opcode_2 == 0)
- return cpu->CP15[CP15_ISA_FEATURE_0];
-
- if (opcode_2 == 1)
- return cpu->CP15[CP15_ISA_FEATURE_1];
-
- if (opcode_2 == 2)
- return cpu->CP15[CP15_ISA_FEATURE_2];
-
- if (opcode_2 == 3)
- return cpu->CP15[CP15_ISA_FEATURE_3];
-
- if (opcode_2 == 4)
- return cpu->CP15[CP15_ISA_FEATURE_4];
- }
- }
-
- if (crn == 1 && opcode_1 == 0 && crm == 0)
- {
- if (opcode_2 == 0)
- return cpu->CP15[CP15_CONTROL];
-
- if (opcode_2 == 1)
- return cpu->CP15[CP15_AUXILIARY_CONTROL];
-
- if (opcode_2 == 2)
- return cpu->CP15[CP15_COPROCESSOR_ACCESS_CONTROL];
- }
-
- if (crn == 2 && opcode_1 == 0 && crm == 0)
- {
- if (opcode_2 == 0)
- return cpu->CP15[CP15_TRANSLATION_BASE_TABLE_0];
-
- if (opcode_2 == 1)
- return cpu->CP15[CP15_TRANSLATION_BASE_TABLE_1];
-
- if (opcode_2 == 2)
- return cpu->CP15[CP15_TRANSLATION_BASE_CONTROL];
- }
-
- if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
- return cpu->CP15[CP15_DOMAIN_ACCESS_CONTROL];
-
- if (crn == 5 && opcode_1 == 0 && crm == 0)
- {
- if (opcode_2 == 0)
- return cpu->CP15[CP15_FAULT_STATUS];
-
- if (opcode_2 == 1)
- return cpu->CP15[CP15_INSTR_FAULT_STATUS];
- }
-
- if (crn == 6 && opcode_1 == 0 && crm == 0)
- {
- if (opcode_2 == 0)
- return cpu->CP15[CP15_FAULT_ADDRESS];
-
- if (opcode_2 == 1)
- return cpu->CP15[CP15_WFAR];
- }
-
- if (crn == 7 && opcode_1 == 0 && crm == 4 && opcode_2 == 0)
- return cpu->CP15[CP15_PHYS_ADDRESS];
-
- if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
- return cpu->CP15[CP15_DATA_CACHE_LOCKDOWN];
-
- if (crn == 10 && opcode_1 == 0)
- {
- if (crm == 0 && opcode_2 == 0)
- return cpu->CP15[CP15_TLB_LOCKDOWN];
-
- if (crm == 2)
- {
- if (opcode_2 == 0)
- return cpu->CP15[CP15_PRIMARY_REGION_REMAP];
-
- if (opcode_2 == 1)
- return cpu->CP15[CP15_NORMAL_REGION_REMAP];
- }
- }
-
- if (crn == 13 && crm == 0)
- {
- if (opcode_2 == 0)
- return cpu->CP15[CP15_PID];
-
- if (opcode_2 == 1)
- return cpu->CP15[CP15_CONTEXT_ID];
-
- if (opcode_2 == 4)
- return cpu->CP15[CP15_THREAD_PRW];
- }
-
- if (crn == 15)
- {
- if (opcode_1 == 0 && crm == 12)
- {
- if (opcode_2 == 0)
- return cpu->CP15[CP15_PERFORMANCE_MONITOR_CONTROL];
-
- if (opcode_2 == 1)
- return cpu->CP15[CP15_CYCLE_COUNTER];
-
- if (opcode_2 == 2)
- return cpu->CP15[CP15_COUNT_0];
-
- if (opcode_2 == 3)
- return cpu->CP15[CP15_COUNT_1];
- }
-
- if (opcode_1 == 5 && opcode_2 == 2)
- {
- if (crm == 5)
- return cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS];
-
- if (crm == 6)
- return cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS];
-
- if (crm == 7)
- return cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE];
- }
-
- if (opcode_1 == 7 && crm == 1 && opcode_2 == 0)
- return cpu->CP15[CP15_TLB_DEBUG_CONTROL];
- }
- }
-
- LOG_ERROR(Core_ARM11, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.", crn, crm, opcode_1, opcode_2);
- return 0;
-}
-
-// Write to the CP15 registers. Used with implementation of the MCR instruction.
-// Note that since the 3DS does not have the hypervisor extensions, these registers
-// are not implemented.
-void WriteCP15Register(ARMul_State* cpu, u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
-{
- if (InAPrivilegedMode(cpu))
- {
- if (crn == 1 && opcode_1 == 0 && crm == 0)
- {
- if (opcode_2 == 0)
- cpu->CP15[CP15_CONTROL] = value;
- else if (opcode_2 == 1)
- cpu->CP15[CP15_AUXILIARY_CONTROL] = value;
- else if (opcode_2 == 2)
- cpu->CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = value;
- }
- else if (crn == 2 && opcode_1 == 0 && crm == 0)
- {
- if (opcode_2 == 0)
- cpu->CP15[CP15_TRANSLATION_BASE_TABLE_0] = value;
- else if (opcode_2 == 1)
- cpu->CP15[CP15_TRANSLATION_BASE_TABLE_1] = value;
- else if (opcode_2 == 2)
- cpu->CP15[CP15_TRANSLATION_BASE_CONTROL] = value;
- }
- else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
- {
- cpu->CP15[CP15_DOMAIN_ACCESS_CONTROL] = value;
- }
- else if (crn == 5 && opcode_1 == 0 && crm == 0)
- {
- if (opcode_2 == 0)
- cpu->CP15[CP15_FAULT_STATUS] = value;
- else if (opcode_2 == 1)
- cpu->CP15[CP15_INSTR_FAULT_STATUS] = value;
- }
- else if (crn == 6 && opcode_1 == 0 && crm == 0)
- {
- if (opcode_2 == 0)
- cpu->CP15[CP15_FAULT_ADDRESS] = value;
- else if (opcode_2 == 1)
- cpu->CP15[CP15_WFAR] = value;
- }
- else if (crn == 7 && opcode_1 == 0)
- {
- if (crm == 0 && opcode_2 == 4)
- {
- cpu->CP15[CP15_WAIT_FOR_INTERRUPT] = value;
- }
- else if (crm == 4 && opcode_2 == 0)
- {
- // NOTE: Not entirely accurate. This should do permission checks.
- cpu->CP15[CP15_PHYS_ADDRESS] = Memory::VirtualToPhysicalAddress(value);
- }
- else if (crm == 5)
- {
- if (opcode_2 == 0)
- cpu->CP15[CP15_INVALIDATE_INSTR_CACHE] = value;
- else if (opcode_2 == 1)
- cpu->CP15[CP15_INVALIDATE_INSTR_CACHE_USING_MVA] = value;
- else if (opcode_2 == 2)
- cpu->CP15[CP15_INVALIDATE_INSTR_CACHE_USING_INDEX] = value;
- else if (opcode_2 == 6)
- cpu->CP15[CP15_FLUSH_BRANCH_TARGET_CACHE] = value;
- else if (opcode_2 == 7)
- cpu->CP15[CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY] = value;
- }
- else if (crm == 6)
- {
- if (opcode_2 == 0)
- cpu->CP15[CP15_INVALIDATE_DATA_CACHE] = value;
- else if (opcode_2 == 1)
- cpu->CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value;
- else if (opcode_2 == 2)
- cpu->CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value;
- }
- else if (crm == 7 && opcode_2 == 0)
- {
- cpu->CP15[CP15_INVALIDATE_DATA_AND_INSTR_CACHE] = value;
- }
- else if (crm == 10)
- {
- if (opcode_2 == 0)
- cpu->CP15[CP15_CLEAN_DATA_CACHE] = value;
- else if (opcode_2 == 1)
- cpu->CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_MVA] = value;
- else if (opcode_2 == 2)
- cpu->CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX] = value;
- }
- else if (crm == 14)
- {
- if (opcode_2 == 0)
- cpu->CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE] = value;
- else if (opcode_2 == 1)
- cpu->CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value;
- else if (opcode_2 == 2)
- cpu->CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value;
- }
- }
- else if (crn == 8 && opcode_1 == 0)
- {
- LOG_WARNING(Core_ARM11, "TLB operations not fully implemented.");
-
- if (crm == 5)
- {
- if (opcode_2 == 0)
- cpu->CP15[CP15_INVALIDATE_ITLB] = value;
- else if (opcode_2 == 1)
- cpu->CP15[CP15_INVALIDATE_ITLB_SINGLE_ENTRY] = value;
- else if (opcode_2 == 2)
- cpu->CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH] = value;
- else if (opcode_2 == 3)
- cpu->CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_MVA] = value;
- }
- else if (crm == 6)
- {
- if (opcode_2 == 0)
- cpu->CP15[CP15_INVALIDATE_DTLB] = value;
- else if (opcode_2 == 1)
- cpu->CP15[CP15_INVALIDATE_DTLB_SINGLE_ENTRY] = value;
- else if (opcode_2 == 2)
- cpu->CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH] = value;
- else if (opcode_2 == 3)
- cpu->CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_MVA] = value;
- }
- else if (crm == 7)
- {
- if (opcode_2 == 0)
- cpu->CP15[CP15_INVALIDATE_UTLB] = value;
- else if (opcode_2 == 1)
- cpu->CP15[CP15_INVALIDATE_UTLB_SINGLE_ENTRY] = value;
- else if (opcode_2 == 2)
- cpu->CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH] = value;
- else if (opcode_2 == 3)
- cpu->CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_MVA] = value;
- }
- }
- else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
- {
- cpu->CP15[CP15_DATA_CACHE_LOCKDOWN] = value;
- }
- else if (crn == 10 && opcode_1 == 0)
- {
- if (crm == 0 && opcode_2 == 0)
- {
- cpu->CP15[CP15_TLB_LOCKDOWN] = value;
- }
- else if (crm == 2)
- {
- if (opcode_2 == 0)
- cpu->CP15[CP15_PRIMARY_REGION_REMAP] = value;
- else if (opcode_2 == 1)
- cpu->CP15[CP15_NORMAL_REGION_REMAP] = value;
- }
- }
- else if (crn == 13 && opcode_1 == 0 && crm == 0)
- {
- if (opcode_2 == 0)
- cpu->CP15[CP15_PID] = value;
- else if (opcode_2 == 1)
- cpu->CP15[CP15_CONTEXT_ID] = value;
- else if (opcode_2 == 3)
- cpu->CP15[CP15_THREAD_URO] = value;
- else if (opcode_2 == 4)
- cpu->CP15[CP15_THREAD_PRW] = value;
- }
- else if (crn == 15)
- {
- if (opcode_1 == 0 && crm == 12)
- {
- if (opcode_2 == 0)
- cpu->CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = value;
- else if (opcode_2 == 1)
- cpu->CP15[CP15_CYCLE_COUNTER] = value;
- else if (opcode_2 == 2)
- cpu->CP15[CP15_COUNT_0] = value;
- else if (opcode_2 == 3)
- cpu->CP15[CP15_COUNT_1] = value;
- }
- else if (opcode_1 == 5)
- {
- if (crm == 4)
- {
- if (opcode_2 == 2)
- cpu->CP15[CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY] = value;
- else if (opcode_2 == 4)
- cpu->CP15[CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY] = value;
- }
- else if (crm == 5 && opcode_2 == 2)
- {
- cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = value;
- }
- else if (crm == 6 && opcode_2 == 2)
- {
- cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = value;
- }
- else if (crm == 7 && opcode_2 == 2)
- {
- cpu->CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = value;
- }
- }
- else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0)
- {
- cpu->CP15[CP15_TLB_DEBUG_CONTROL] = value;
- }
- }
- }
-
- // Unprivileged registers
- if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4)
- {
- cpu->CP15[CP15_FLUSH_PREFETCH_BUFFER] = value;
- }
- else if (crn == 7 && opcode_1 == 0 && crm == 10)
- {
- if (opcode_2 == 4)
- cpu->CP15[CP15_DATA_SYNC_BARRIER] = value;
- else if (opcode_2 == 5)
- cpu->CP15[CP15_DATA_MEMORY_BARRIER] = value;
-
- }
- else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2)
- {
- cpu->CP15[CP15_THREAD_UPRW] = value;
- }
-}
diff --git a/src/core/arm/skyeye_common/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h
index a92effbb..d1c72180 100644
--- a/src/core/arm/skyeye_common/arm_regformat.h
+++ b/src/core/arm/skyeye_common/arm_regformat.h
@@ -59,6 +59,8 @@ enum {
VFP_FPSID,
VFP_FPSCR,
VFP_FPEXC,
+ VFP_FPINST,
+ VFP_FPINST2,
VFP_MVFR0,
VFP_MVFR1,
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h
deleted file mode 100644
index d2c90110..00000000
--- a/src/core/arm/skyeye_common/armdefs.h
+++ /dev/null
@@ -1,318 +0,0 @@
-/* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator.
- Copyright (C) 1994 Advanced RISC Machines Ltd.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-#pragma once
-
-#include <unordered_map>
-
-#include "common/common_types.h"
-#include "core/arm/skyeye_common/arm_regformat.h"
-
-#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1))
-#define BIT(s, n) ((s >> (n)) & 1)
-
-// Signal levels
-enum {
- LOW = 0,
- HIGH = 1,
- LOWHIGH = 1,
- HIGHLOW = 2
-};
-
-// Cache types
-enum {
- NONCACHE = 0,
- DATACACHE = 1,
- INSTCACHE = 2,
-};
-
-// Abort models
-enum {
- ABORT_BASE_RESTORED = 0,
- ABORT_EARLY = 1,
- ABORT_BASE_UPDATED = 2
-};
-
-#define POS(i) ( (~(i)) >> 31 )
-#define NEG(i) ( (i) >> 31 )
-
-typedef u64 ARMdword; // must be 64 bits wide
-typedef u32 ARMword; // must be 32 bits wide
-typedef u16 ARMhword; // must be 16 bits wide
-typedef u8 ARMbyte; // must be 8 bits wide
-
-#define VFP_REG_NUM 64
-struct ARMul_State
-{
- ARMword Emulate; // To start and stop emulation
-
- // Order of the following register should not be modified
- ARMword Reg[16]; // The current register file
- ARMword Cpsr; // The current PSR
- ARMword Spsr_copy;
- ARMword phys_pc;
- ARMword Reg_usr[2];
- ARMword Reg_svc[2]; // R13_SVC R14_SVC
- ARMword Reg_abort[2]; // R13_ABORT R14_ABORT
- ARMword Reg_undef[2]; // R13 UNDEF R14 UNDEF
- ARMword Reg_irq[2]; // R13_IRQ R14_IRQ
- ARMword Reg_firq[7]; // R8---R14 FIRQ
- ARMword Spsr[7]; // The exception psr's
- ARMword Mode; // The current mode
- ARMword Bank; // The current register bank
- ARMword exclusive_tag; // The address for which the local monitor is in exclusive access mode
- ARMword exclusive_state;
- ARMword exclusive_result;
- ARMword CP15[CP15_REGISTER_COUNT];
-
- // FPSID, FPSCR, and FPEXC
- ARMword VFP[VFP_SYSTEM_REGISTER_COUNT];
- // VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31).
- // VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31),
- // and only 32 singleword registers are accessible (S0-S31).
- ARMword ExtReg[VFP_REG_NUM];
- /* ---- End of the ordered registers ---- */
-
- ARMword NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed
- unsigned int shifter_carry_out;
-
- // Add armv6 flags dyf:2010-08-09
- ARMword GEFlag, EFlag, AFlag, QFlag;
-
- ARMword TFlag; // Thumb state
-
- unsigned long long NumInstrs; // The number of instructions executed
- unsigned NumInstrsToExecute;
-
- unsigned NresetSig; // Reset the processor
- unsigned NfiqSig;
- unsigned NirqSig;
-
- unsigned abortSig;
- unsigned NtransSig;
- unsigned bigendSig;
- unsigned syscallSig;
-
-/* 2004-05-09 chy
-----------------------------------------------------------
-read ARM Architecture Reference Manual
-2.6.5 Data Abort
-There are three Abort Model in ARM arch.
-
-Early Abort Model: used in some ARMv3 and earlier implementations. In this
-model, base register wirteback occurred for LDC,LDM,STC,STM instructions, and
-the base register was unchanged for all other instructions. (oldest)
-
-Base Restored Abort Model: If a Data Abort occurs in an instruction which
-specifies base register writeback, the value in the base register is
-unchanged. (strongarm, xscale)
-
-Base Updated Abort Model: If a Data Abort occurs in an instruction which
-specifies base register writeback, the base register writeback still occurs.
-(arm720T)
-
-read PART B
-chap2 The System Control Coprocessor CP15
-2.4 Register1:control register
-L(bit 6): in some ARMv3 and earlier implementations, the abort model of the
-processor could be configured:
-0=early Abort Model Selected(now obsolete)
-1=Late Abort Model selceted(same as Base Updated Abort Model)
-
-on later processors, this bit reads as 1 and ignores writes.
--------------------------------------------------------------
-So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model)
- if lateabtSig=0, then it means Base Restored Abort Model
-*/
- unsigned lateabtSig;
-
- // For differentiating ARM core emulaiton.
- bool is_v4; // Are we emulating a v4 architecture (or higher)?
- bool is_v5; // Are we emulating a v5 architecture?
- bool is_v5e; // Are we emulating a v5e architecture?
- bool is_v6; // Are we emulating a v6 architecture?
- bool is_v7; // Are we emulating a v7 architecture?
-
- // ARM_ARM A2-18
- // 0 Base Restored Abort Model, 1 the Early Abort Model, 2 Base Updated Abort Model
- int abort_model;
-
- // TODO(bunnei): Move this cache to a better place - it should be per codeset (likely per
- // process for our purposes), not per ARMul_State (which tracks CPU core state).
- std::unordered_map<u32, int> instruction_cache;
-};
-
-/***************************************************************************\
-* Types of ARM we know about *
-\***************************************************************************/
-
-enum {
- ARM_v4_Prop = 0x01,
- ARM_v5_Prop = 0x02,
- ARM_v5e_Prop = 0x04,
- ARM_v6_Prop = 0x08,
- ARM_v7_Prop = 0x10,
-};
-
-/***************************************************************************\
-* The hardware vector addresses *
-\***************************************************************************/
-
-enum {
- ARMResetV = 0,
- ARMUndefinedInstrV = 4,
- ARMSWIV = 8,
- ARMPrefetchAbortV = 12,
- ARMDataAbortV = 16,
- ARMAddrExceptnV = 20,
- ARMIRQV = 24,
- ARMFIQV = 28,
- ARMErrorV = 32, // This is an offset, not an address!
-
- ARMul_ResetV = ARMResetV,
- ARMul_UndefinedInstrV = ARMUndefinedInstrV,
- ARMul_SWIV = ARMSWIV,
- ARMul_PrefetchAbortV = ARMPrefetchAbortV,
- ARMul_DataAbortV = ARMDataAbortV,
- ARMul_AddrExceptnV = ARMAddrExceptnV,
- ARMul_IRQV = ARMIRQV,
- ARMul_FIQV = ARMFIQV
-};
-
-/***************************************************************************\
-* Mode and Bank Constants *
-\***************************************************************************/
-
-enum PrivilegeMode {
- USER32MODE = 16,
- FIQ32MODE = 17,
- IRQ32MODE = 18,
- SVC32MODE = 19,
- ABORT32MODE = 23,
- UNDEF32MODE = 27,
- SYSTEM32MODE = 31
-};
-
-enum {
- USERBANK = 0,
- FIQBANK = 1,
- IRQBANK = 2,
- SVCBANK = 3,
- ABORTBANK = 4,
- UNDEFBANK = 5,
- DUMMYBANK = 6,
- SYSTEMBANK = 7
-};
-
-/***************************************************************************\
-* Definitons of things in the emulator *
-\***************************************************************************/
-extern void ARMul_Reset(ARMul_State* state);
-extern ARMul_State* ARMul_NewState(ARMul_State* state);
-
-/***************************************************************************\
-* Definitons of things in the co-processor interface *
-\***************************************************************************/
-
-enum {
- ARMul_FIRST = 0,
- ARMul_TRANSFER = 1,
- ARMul_BUSY = 2,
- ARMul_DATA = 3,
- ARMul_INTERRUPT = 4,
- ARMul_DONE = 0,
- ARMul_CANT = 1,
- ARMul_INC = 3
-};
-
-/***************************************************************************\
-* Definitons of things in the host environment *
-\***************************************************************************/
-
-enum ConditionCode {
- EQ = 0,
- NE = 1,
- CS = 2,
- CC = 3,
- MI = 4,
- PL = 5,
- VS = 6,
- VC = 7,
- HI = 8,
- LS = 9,
- GE = 10,
- LT = 11,
- GT = 12,
- LE = 13,
- AL = 14,
- NV = 15,
-};
-
-// Flags for use with the APSR.
-enum : u32 {
- NBIT = (1U << 31U),
- ZBIT = (1 << 30),
- CBIT = (1 << 29),
- VBIT = (1 << 28),
- QBIT = (1 << 27),
- JBIT = (1 << 24),
- EBIT = (1 << 9),
- ABIT = (1 << 8),
- IBIT = (1 << 7),
- FBIT = (1 << 6),
- TBIT = (1 << 5),
-
- // Masks for groups of bits in the APSR.
- MODEBITS = 0x1F,
- INTBITS = 0x1C0,
-};
-
-// Values for Emulate.
-enum {
- STOP = 0, // Stop
- CHANGEMODE = 1, // Change mode
- ONCE = 2, // Execute just one iteration
- RUN = 3 // Continuous execution
-};
-
-
-extern bool AddOverflow(ARMword, ARMword, ARMword);
-extern bool SubOverflow(ARMword, ARMword, ARMword);
-
-extern void ARMul_SelectProcessor(ARMul_State*, unsigned);
-
-extern u32 AddWithCarry(u32, u32, u32, bool*, bool*);
-extern bool ARMul_AddOverflowQ(ARMword, ARMword);
-
-extern u8 ARMul_SignedSaturatedAdd8(u8, u8);
-extern u8 ARMul_SignedSaturatedSub8(u8, u8);
-extern u16 ARMul_SignedSaturatedAdd16(u16, u16);
-extern u16 ARMul_SignedSaturatedSub16(u16, u16);
-
-extern u8 ARMul_UnsignedSaturatedAdd8(u8, u8);
-extern u16 ARMul_UnsignedSaturatedAdd16(u16, u16);
-extern u8 ARMul_UnsignedSaturatedSub8(u8, u8);
-extern u16 ARMul_UnsignedSaturatedSub16(u16, u16);
-extern u8 ARMul_UnsignedAbsoluteDifference(u8, u8);
-extern u32 ARMul_SignedSatQ(s32, u8, bool*);
-extern u32 ARMul_UnsignedSatQ(s32, u8, bool*);
-
-extern bool InBigEndianMode(ARMul_State*);
-extern bool InAPrivilegedMode(ARMul_State*);
-
-extern u32 ReadCP15Register(ARMul_State* cpu, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2);
-extern 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 c67d7209..00000000
--- a/src/core/arm/skyeye_common/armmmu.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- armmmu.c - Memory Management Unit emulation.
- ARMulator extensions for the ARM7100 family.
- Copyright (C) 1999 Ben Williamson
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#pragma once
-
-#include "common/swap.h"
-
-#include "core/memory.h"
-#include "core/arm/skyeye_common/armdefs.h"
-
-// Register numbers in the MMU
-enum
-{
- MMU_ID = 0,
- MMU_CONTROL = 1,
- MMU_TRANSLATION_TABLE_BASE = 2,
- MMU_DOMAIN_ACCESS_CONTROL = 3,
- MMU_FAULT_STATUS = 5,
- MMU_FAULT_ADDRESS = 6,
- MMU_CACHE_OPS = 7,
- MMU_TLB_OPS = 8,
- MMU_CACHE_LOCKDOWN = 9,
- MMU_TLB_LOCKDOWN = 10,
- MMU_PID = 13,
-
- // MMU_V4
- MMU_V4_CACHE_OPS = 7,
- MMU_V4_TLB_OPS = 8,
-
- // MMU_V3
- MMU_V3_FLUSH_TLB = 5,
- MMU_V3_FLUSH_TLB_ENTRY = 6,
- MMU_V3_FLUSH_CACHE = 7,
-};
-
-// Reads data in big/little endian format based on the
-// state of the E (endian) bit in the emulated CPU's APSR.
-inline u16 ReadMemory16(ARMul_State* cpu, u32 address) {
- u16 data = Memory::Read16(address);
-
- if (InBigEndianMode(cpu))
- data = Common::swap16(data);
-
- return data;
-}
-
-inline u32 ReadMemory32(ARMul_State* cpu, u32 address) {
- u32 data = Memory::Read32(address);
-
- if (InBigEndianMode(cpu))
- data = Common::swap32(data);
-
- return data;
-}
-
-inline u64 ReadMemory64(ARMul_State* cpu, u32 address) {
- u64 data = Memory::Read64(address);
-
- if (InBigEndianMode(cpu))
- data = Common::swap64(data);
-
- return data;
-}
-
-// Writes data in big/little endian format based on the
-// state of the E (endian) bit in the emulated CPU's APSR.
-inline void WriteMemory16(ARMul_State* cpu, u32 address, u16 data) {
- if (InBigEndianMode(cpu))
- data = Common::swap16(data);
-
- Memory::Write16(address, data);
-}
-
-inline void WriteMemory32(ARMul_State* cpu, u32 address, u32 data) {
- if (InBigEndianMode(cpu))
- data = Common::swap32(data);
-
- Memory::Write32(address, data);
-}
-
-inline void WriteMemory64(ARMul_State* cpu, u32 address, u64 data) {
- if (InBigEndianMode(cpu))
- data = Common::swap64(data);
-
- Memory::Write64(address, data);
-}
diff --git a/src/core/arm/skyeye_common/armstate.cpp b/src/core/arm/skyeye_common/armstate.cpp
new file mode 100644
index 00000000..ccb2eb0e
--- /dev/null
+++ b/src/core/arm/skyeye_common/armstate.cpp
@@ -0,0 +1,657 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/swap.h"
+#include "common/logging/log.h"
+#include "core/mem_map.h"
+#include "core/memory.h"
+#include "core/arm/skyeye_common/armstate.h"
+#include "core/arm/skyeye_common/vfp/vfp.h"
+
+ARMul_State::ARMul_State(PrivilegeMode initial_mode)
+{
+ Reset();
+ ChangePrivilegeMode(initial_mode);
+}
+
+void ARMul_State::ChangePrivilegeMode(u32 new_mode)
+{
+ if (Mode == new_mode)
+ return;
+
+ if (new_mode != USERBANK) {
+ switch (Mode) {
+ case SYSTEM32MODE: // Shares registers with user mode
+ case USER32MODE:
+ Reg_usr[0] = Reg[13];
+ Reg_usr[1] = Reg[14];
+ break;
+ case IRQ32MODE:
+ Reg_irq[0] = Reg[13];
+ Reg_irq[1] = Reg[14];
+ Spsr[IRQBANK] = Spsr_copy;
+ break;
+ case SVC32MODE:
+ Reg_svc[0] = Reg[13];
+ Reg_svc[1] = Reg[14];
+ Spsr[SVCBANK] = Spsr_copy;
+ break;
+ case ABORT32MODE:
+ Reg_abort[0] = Reg[13];
+ Reg_abort[1] = Reg[14];
+ Spsr[ABORTBANK] = Spsr_copy;
+ break;
+ case UNDEF32MODE:
+ Reg_undef[0] = Reg[13];
+ Reg_undef[1] = Reg[14];
+ Spsr[UNDEFBANK] = Spsr_copy;
+ break;
+ case FIQ32MODE:
+ Reg_firq[0] = Reg[13];
+ Reg_firq[1] = Reg[14];
+ Spsr[FIQBANK] = Spsr_copy;
+ break;
+ }
+
+ switch (new_mode) {
+ case USER32MODE:
+ Reg[13] = Reg_usr[0];
+ Reg[14] = Reg_usr[1];
+ Bank = USERBANK;
+ break;
+ case IRQ32MODE:
+ Reg[13] = Reg_irq[0];
+ Reg[14] = Reg_irq[1];
+ Spsr_copy = Spsr[IRQBANK];
+ Bank = IRQBANK;
+ break;
+ case SVC32MODE:
+ Reg[13] = Reg_svc[0];
+ Reg[14] = Reg_svc[1];
+ Spsr_copy = Spsr[SVCBANK];
+ Bank = SVCBANK;
+ break;
+ case ABORT32MODE:
+ Reg[13] = Reg_abort[0];
+ Reg[14] = Reg_abort[1];
+ Spsr_copy = Spsr[ABORTBANK];
+ Bank = ABORTBANK;
+ break;
+ case UNDEF32MODE:
+ Reg[13] = Reg_undef[0];
+ Reg[14] = Reg_undef[1];
+ Spsr_copy = Spsr[UNDEFBANK];
+ Bank = UNDEFBANK;
+ break;
+ case FIQ32MODE:
+ Reg[13] = Reg_firq[0];
+ Reg[14] = Reg_firq[1];
+ Spsr_copy = Spsr[FIQBANK];
+ Bank = FIQBANK;
+ break;
+ case SYSTEM32MODE: // Shares registers with user mode.
+ Reg[13] = Reg_usr[0];
+ Reg[14] = Reg_usr[1];
+ Bank = SYSTEMBANK;
+ break;
+ }
+
+ // Set the mode bits in the APSR
+ Cpsr = (Cpsr & ~Mode) | new_mode;
+ Mode = new_mode;
+ }
+}
+
+// Performs a reset
+void ARMul_State::Reset()
+{
+ VFPInit(this);
+
+ // Set stack pointer to the top of the stack
+ Reg[13] = 0x10000000;
+ Reg[15] = 0;
+
+ Cpsr = INTBITS | SVC32MODE;
+ Mode = SVC32MODE;
+ Bank = SVCBANK;
+
+ ResetMPCoreCP15Registers();
+
+ NresetSig = HIGH;
+ NfiqSig = HIGH;
+ NirqSig = HIGH;
+ NtransSig = (Mode & 3) ? HIGH : LOW;
+ abortSig = LOW;
+
+ NumInstrs = 0;
+ Emulate = RUN;
+}
+
+// Resets certain MPCore CP15 values to their ARM-defined reset values.
+void ARMul_State::ResetMPCoreCP15Registers()
+{
+ // c0
+ CP15[CP15_MAIN_ID] = 0x410FB024;
+ CP15[CP15_TLB_TYPE] = 0x00000800;
+ CP15[CP15_PROCESSOR_FEATURE_0] = 0x00000111;
+ CP15[CP15_PROCESSOR_FEATURE_1] = 0x00000001;
+ CP15[CP15_DEBUG_FEATURE_0] = 0x00000002;
+ CP15[CP15_MEMORY_MODEL_FEATURE_0] = 0x01100103;
+ CP15[CP15_MEMORY_MODEL_FEATURE_1] = 0x10020302;
+ CP15[CP15_MEMORY_MODEL_FEATURE_2] = 0x01222000;
+ CP15[CP15_MEMORY_MODEL_FEATURE_3] = 0x00000000;
+ CP15[CP15_ISA_FEATURE_0] = 0x00100011;
+ CP15[CP15_ISA_FEATURE_1] = 0x12002111;
+ CP15[CP15_ISA_FEATURE_2] = 0x11221011;
+ CP15[CP15_ISA_FEATURE_3] = 0x01102131;
+ CP15[CP15_ISA_FEATURE_4] = 0x00000141;
+
+ // c1
+ CP15[CP15_CONTROL] = 0x00054078;
+ CP15[CP15_AUXILIARY_CONTROL] = 0x0000000F;
+ CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = 0x00000000;
+
+ // c2
+ CP15[CP15_TRANSLATION_BASE_TABLE_0] = 0x00000000;
+ CP15[CP15_TRANSLATION_BASE_TABLE_1] = 0x00000000;
+ CP15[CP15_TRANSLATION_BASE_CONTROL] = 0x00000000;
+
+ // c3
+ CP15[CP15_DOMAIN_ACCESS_CONTROL] = 0x00000000;
+
+ // c7
+ CP15[CP15_PHYS_ADDRESS] = 0x00000000;
+
+ // c9
+ CP15[CP15_DATA_CACHE_LOCKDOWN] = 0xFFFFFFF0;
+
+ // c10
+ CP15[CP15_TLB_LOCKDOWN] = 0x00000000;
+ CP15[CP15_PRIMARY_REGION_REMAP] = 0x00098AA4;
+ CP15[CP15_NORMAL_REGION_REMAP] = 0x44E048E0;
+
+ // c13
+ CP15[CP15_PID] = 0x00000000;
+ CP15[CP15_CONTEXT_ID] = 0x00000000;
+ CP15[CP15_THREAD_UPRW] = 0x00000000;
+ CP15[CP15_THREAD_URO] = 0x00000000;
+ CP15[CP15_THREAD_PRW] = 0x00000000;
+
+ // c15
+ CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = 0x00000000;
+ CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = 0x00000000;
+ CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = 0x00000000;
+ CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = 0x00000000;
+ CP15[CP15_TLB_DEBUG_CONTROL] = 0x00000000;
+}
+
+u16 ARMul_State::ReadMemory16(u32 address) const
+{
+ u16 data = Memory::Read16(address);
+
+ if (InBigEndianMode())
+ data = Common::swap16(data);
+
+ return data;
+}
+
+u32 ARMul_State::ReadMemory32(u32 address) const
+{
+ u32 data = Memory::Read32(address);
+
+ if (InBigEndianMode())
+ data = Common::swap32(data);
+
+ return data;
+}
+
+u64 ARMul_State::ReadMemory64(u32 address) const
+{
+ u64 data = Memory::Read64(address);
+
+ if (InBigEndianMode())
+ data = Common::swap64(data);
+
+ return data;
+}
+
+void ARMul_State::WriteMemory16(u32 address, u16 data)
+{
+ if (InBigEndianMode())
+ data = Common::swap16(data);
+
+ Memory::Write16(address, data);
+}
+
+void ARMul_State::WriteMemory32(u32 address, u32 data)
+{
+ if (InBigEndianMode())
+ data = Common::swap32(data);
+
+ Memory::Write32(address, data);
+}
+
+void ARMul_State::WriteMemory64(u32 address, u64 data)
+{
+ if (InBigEndianMode())
+ data = Common::swap64(data);
+
+ Memory::Write64(address, data);
+}
+
+
+// Reads from the CP15 registers. Used with implementation of the MRC instruction.
+// Note that since the 3DS does not have the hypervisor extensions, these registers
+// are not implemented.
+u32 ARMul_State::ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const
+{
+ // Unprivileged registers
+ if (crn == 13 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 2)
+ return CP15[CP15_THREAD_UPRW];
+
+ if (opcode_2 == 3)
+ return CP15[CP15_THREAD_URO];
+ }
+
+ if (InAPrivilegedMode())
+ {
+ if (crn == 0 && opcode_1 == 0)
+ {
+ if (crm == 0)
+ {
+ if (opcode_2 == 0)
+ return CP15[CP15_MAIN_ID];
+
+ if (opcode_2 == 1)
+ return CP15[CP15_CACHE_TYPE];
+
+ if (opcode_2 == 3)
+ return CP15[CP15_TLB_TYPE];
+
+ if (opcode_2 == 5)
+ return CP15[CP15_CPU_ID];
+ }
+ else if (crm == 1)
+ {
+ if (opcode_2 == 0)
+ return CP15[CP15_PROCESSOR_FEATURE_0];
+
+ if (opcode_2 == 1)
+ return CP15[CP15_PROCESSOR_FEATURE_1];
+
+ if (opcode_2 == 2)
+ return CP15[CP15_DEBUG_FEATURE_0];
+
+ if (opcode_2 == 4)
+ return CP15[CP15_MEMORY_MODEL_FEATURE_0];
+
+ if (opcode_2 == 5)
+ return CP15[CP15_MEMORY_MODEL_FEATURE_1];
+
+ if (opcode_2 == 6)
+ return CP15[CP15_MEMORY_MODEL_FEATURE_2];
+
+ if (opcode_2 == 7)
+ return CP15[CP15_MEMORY_MODEL_FEATURE_3];
+ }
+ else if (crm == 2)
+ {
+ if (opcode_2 == 0)
+ return CP15[CP15_ISA_FEATURE_0];
+
+ if (opcode_2 == 1)
+ return CP15[CP15_ISA_FEATURE_1];
+
+ if (opcode_2 == 2)
+ return CP15[CP15_ISA_FEATURE_2];
+
+ if (opcode_2 == 3)
+ return CP15[CP15_ISA_FEATURE_3];
+
+ if (opcode_2 == 4)
+ return CP15[CP15_ISA_FEATURE_4];
+ }
+ }
+
+ if (crn == 1 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ return CP15[CP15_CONTROL];
+
+ if (opcode_2 == 1)
+ return CP15[CP15_AUXILIARY_CONTROL];
+
+ if (opcode_2 == 2)
+ return CP15[CP15_COPROCESSOR_ACCESS_CONTROL];
+ }
+
+ if (crn == 2 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ return CP15[CP15_TRANSLATION_BASE_TABLE_0];
+
+ if (opcode_2 == 1)
+ return CP15[CP15_TRANSLATION_BASE_TABLE_1];
+
+ if (opcode_2 == 2)
+ return CP15[CP15_TRANSLATION_BASE_CONTROL];
+ }
+
+ if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
+ return CP15[CP15_DOMAIN_ACCESS_CONTROL];
+
+ if (crn == 5 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ return CP15[CP15_FAULT_STATUS];
+
+ if (opcode_2 == 1)
+ return CP15[CP15_INSTR_FAULT_STATUS];
+ }
+
+ if (crn == 6 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ return CP15[CP15_FAULT_ADDRESS];
+
+ if (opcode_2 == 1)
+ return CP15[CP15_WFAR];
+ }
+
+ if (crn == 7 && opcode_1 == 0 && crm == 4 && opcode_2 == 0)
+ return CP15[CP15_PHYS_ADDRESS];
+
+ if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
+ return CP15[CP15_DATA_CACHE_LOCKDOWN];
+
+ if (crn == 10 && opcode_1 == 0)
+ {
+ if (crm == 0 && opcode_2 == 0)
+ return CP15[CP15_TLB_LOCKDOWN];
+
+ if (crm == 2)
+ {
+ if (opcode_2 == 0)
+ return CP15[CP15_PRIMARY_REGION_REMAP];
+
+ if (opcode_2 == 1)
+ return CP15[CP15_NORMAL_REGION_REMAP];
+ }
+ }
+
+ if (crn == 13 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ return CP15[CP15_PID];
+
+ if (opcode_2 == 1)
+ return CP15[CP15_CONTEXT_ID];
+
+ if (opcode_2 == 4)
+ return CP15[CP15_THREAD_PRW];
+ }
+
+ if (crn == 15)
+ {
+ if (opcode_1 == 0 && crm == 12)
+ {
+ if (opcode_2 == 0)
+ return CP15[CP15_PERFORMANCE_MONITOR_CONTROL];
+
+ if (opcode_2 == 1)
+ return CP15[CP15_CYCLE_COUNTER];
+
+ if (opcode_2 == 2)
+ return CP15[CP15_COUNT_0];
+
+ if (opcode_2 == 3)
+ return CP15[CP15_COUNT_1];
+ }
+
+ if (opcode_1 == 5 && opcode_2 == 2)
+ {
+ if (crm == 5)
+ return CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS];
+
+ if (crm == 6)
+ return CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS];
+
+ if (crm == 7)
+ return CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE];
+ }
+
+ if (opcode_1 == 7 && crm == 1 && opcode_2 == 0)
+ return CP15[CP15_TLB_DEBUG_CONTROL];
+ }
+ }
+
+ LOG_ERROR(Core_ARM11, "MRC CRn=%u, CRm=%u, OP1=%u OP2=%u is not implemented. Returning zero.", crn, crm, opcode_1, opcode_2);
+ return 0;
+}
+
+// Write to the CP15 registers. Used with implementation of the MCR instruction.
+// Note that since the 3DS does not have the hypervisor extensions, these registers
+// are not implemented.
+void ARMul_State::WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2)
+{
+ if (InAPrivilegedMode())
+ {
+ if (crn == 1 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ CP15[CP15_CONTROL] = value;
+ else if (opcode_2 == 1)
+ CP15[CP15_AUXILIARY_CONTROL] = value;
+ else if (opcode_2 == 2)
+ CP15[CP15_COPROCESSOR_ACCESS_CONTROL] = value;
+ }
+ else if (crn == 2 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ CP15[CP15_TRANSLATION_BASE_TABLE_0] = value;
+ else if (opcode_2 == 1)
+ CP15[CP15_TRANSLATION_BASE_TABLE_1] = value;
+ else if (opcode_2 == 2)
+ CP15[CP15_TRANSLATION_BASE_CONTROL] = value;
+ }
+ else if (crn == 3 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
+ {
+ CP15[CP15_DOMAIN_ACCESS_CONTROL] = value;
+ }
+ else if (crn == 5 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ CP15[CP15_FAULT_STATUS] = value;
+ else if (opcode_2 == 1)
+ CP15[CP15_INSTR_FAULT_STATUS] = value;
+ }
+ else if (crn == 6 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ CP15[CP15_FAULT_ADDRESS] = value;
+ else if (opcode_2 == 1)
+ CP15[CP15_WFAR] = value;
+ }
+ else if (crn == 7 && opcode_1 == 0)
+ {
+ if (crm == 0 && opcode_2 == 4)
+ {
+ CP15[CP15_WAIT_FOR_INTERRUPT] = value;
+ }
+ else if (crm == 4 && opcode_2 == 0)
+ {
+ // NOTE: Not entirely accurate. This should do permission checks.
+ CP15[CP15_PHYS_ADDRESS] = Memory::VirtualToPhysicalAddress(value);
+ }
+ else if (crm == 5)
+ {
+ if (opcode_2 == 0)
+ CP15[CP15_INVALIDATE_INSTR_CACHE] = value;
+ else if (opcode_2 == 1)
+ CP15[CP15_INVALIDATE_INSTR_CACHE_USING_MVA] = value;
+ else if (opcode_2 == 2)
+ CP15[CP15_INVALIDATE_INSTR_CACHE_USING_INDEX] = value;
+ else if (opcode_2 == 6)
+ CP15[CP15_FLUSH_BRANCH_TARGET_CACHE] = value;
+ else if (opcode_2 == 7)
+ CP15[CP15_FLUSH_BRANCH_TARGET_CACHE_ENTRY] = value;
+ }
+ else if (crm == 6)
+ {
+ if (opcode_2 == 0)
+ CP15[CP15_INVALIDATE_DATA_CACHE] = value;
+ else if (opcode_2 == 1)
+ CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value;
+ else if (opcode_2 == 2)
+ CP15[CP15_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value;
+ }
+ else if (crm == 7 && opcode_2 == 0)
+ {
+ CP15[CP15_INVALIDATE_DATA_AND_INSTR_CACHE] = value;
+ }
+ else if (crm == 10)
+ {
+ if (opcode_2 == 0)
+ CP15[CP15_CLEAN_DATA_CACHE] = value;
+ else if (opcode_2 == 1)
+ CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_MVA] = value;
+ else if (opcode_2 == 2)
+ CP15[CP15_CLEAN_DATA_CACHE_LINE_USING_INDEX] = value;
+ }
+ else if (crm == 14)
+ {
+ if (opcode_2 == 0)
+ CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE] = value;
+ else if (opcode_2 == 1)
+ CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_MVA] = value;
+ else if (opcode_2 == 2)
+ CP15[CP15_CLEAN_AND_INVALIDATE_DATA_CACHE_LINE_USING_INDEX] = value;
+ }
+ }
+ else if (crn == 8 && opcode_1 == 0)
+ {
+ if (crm == 5)
+ {
+ if (opcode_2 == 0)
+ CP15[CP15_INVALIDATE_ITLB] = value;
+ else if (opcode_2 == 1)
+ CP15[CP15_INVALIDATE_ITLB_SINGLE_ENTRY] = value;
+ else if (opcode_2 == 2)
+ CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_ASID_MATCH] = value;
+ else if (opcode_2 == 3)
+ CP15[CP15_INVALIDATE_ITLB_ENTRY_ON_MVA] = value;
+ }
+ else if (crm == 6)
+ {
+ if (opcode_2 == 0)
+ CP15[CP15_INVALIDATE_DTLB] = value;
+ else if (opcode_2 == 1)
+ CP15[CP15_INVALIDATE_DTLB_SINGLE_ENTRY] = value;
+ else if (opcode_2 == 2)
+ CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_ASID_MATCH] = value;
+ else if (opcode_2 == 3)
+ CP15[CP15_INVALIDATE_DTLB_ENTRY_ON_MVA] = value;
+ }
+ else if (crm == 7)
+ {
+ if (opcode_2 == 0)
+ CP15[CP15_INVALIDATE_UTLB] = value;
+ else if (opcode_2 == 1)
+ CP15[CP15_INVALIDATE_UTLB_SINGLE_ENTRY] = value;
+ else if (opcode_2 == 2)
+ CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_ASID_MATCH] = value;
+ else if (opcode_2 == 3)
+ CP15[CP15_INVALIDATE_UTLB_ENTRY_ON_MVA] = value;
+ }
+ }
+ else if (crn == 9 && opcode_1 == 0 && crm == 0 && opcode_2 == 0)
+ {
+ CP15[CP15_DATA_CACHE_LOCKDOWN] = value;
+ }
+ else if (crn == 10 && opcode_1 == 0)
+ {
+ if (crm == 0 && opcode_2 == 0)
+ {
+ CP15[CP15_TLB_LOCKDOWN] = value;
+ }
+ else if (crm == 2)
+ {
+ if (opcode_2 == 0)
+ CP15[CP15_PRIMARY_REGION_REMAP] = value;
+ else if (opcode_2 == 1)
+ CP15[CP15_NORMAL_REGION_REMAP] = value;
+ }
+ }
+ else if (crn == 13 && opcode_1 == 0 && crm == 0)
+ {
+ if (opcode_2 == 0)
+ CP15[CP15_PID] = value;
+ else if (opcode_2 == 1)
+ CP15[CP15_CONTEXT_ID] = value;
+ else if (opcode_2 == 3)
+ CP15[CP15_THREAD_URO] = value;
+ else if (opcode_2 == 4)
+ CP15[CP15_THREAD_PRW] = value;
+ }
+ else if (crn == 15)
+ {
+ if (opcode_1 == 0 && crm == 12)
+ {
+ if (opcode_2 == 0)
+ CP15[CP15_PERFORMANCE_MONITOR_CONTROL] = value;
+ else if (opcode_2 == 1)
+ CP15[CP15_CYCLE_COUNTER] = value;
+ else if (opcode_2 == 2)
+ CP15[CP15_COUNT_0] = value;
+ else if (opcode_2 == 3)
+ CP15[CP15_COUNT_1] = value;
+ }
+ else if (opcode_1 == 5)
+ {
+ if (crm == 4)
+ {
+ if (opcode_2 == 2)
+ CP15[CP15_READ_MAIN_TLB_LOCKDOWN_ENTRY] = value;
+ else if (opcode_2 == 4)
+ CP15[CP15_WRITE_MAIN_TLB_LOCKDOWN_ENTRY] = value;
+ }
+ else if (crm == 5 && opcode_2 == 2)
+ {
+ CP15[CP15_MAIN_TLB_LOCKDOWN_VIRT_ADDRESS] = value;
+ }
+ else if (crm == 6 && opcode_2 == 2)
+ {
+ CP15[CP15_MAIN_TLB_LOCKDOWN_PHYS_ADDRESS] = value;
+ }
+ else if (crm == 7 && opcode_2 == 2)
+ {
+ CP15[CP15_MAIN_TLB_LOCKDOWN_ATTRIBUTE] = value;
+ }
+ }
+ else if (opcode_1 == 7 && crm == 1 && opcode_2 == 0)
+ {
+ CP15[CP15_TLB_DEBUG_CONTROL] = value;
+ }
+ }
+ }
+
+ // Unprivileged registers
+ if (crn == 7 && opcode_1 == 0 && crm == 5 && opcode_2 == 4)
+ {
+ CP15[CP15_FLUSH_PREFETCH_BUFFER] = value;
+ }
+ else if (crn == 7 && opcode_1 == 0 && crm == 10)
+ {
+ if (opcode_2 == 4)
+ CP15[CP15_DATA_SYNC_BARRIER] = value;
+ else if (opcode_2 == 5)
+ CP15[CP15_DATA_MEMORY_BARRIER] = value;
+ }
+ else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2)
+ {
+ CP15[CP15_THREAD_UPRW] = value;
+ }
+}
diff --git a/src/core/arm/skyeye_common/armstate.h b/src/core/arm/skyeye_common/armstate.h
new file mode 100644
index 00000000..b364e262
--- /dev/null
+++ b/src/core/arm/skyeye_common/armstate.h
@@ -0,0 +1,252 @@
+/* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator.
+ Copyright (C) 1994 Advanced RISC Machines Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#pragma once
+
+#include <array>
+#include <unordered_map>
+
+#include "common/common_types.h"
+#include "core/arm/skyeye_common/arm_regformat.h"
+
+// Signal levels
+enum {
+ LOW = 0,
+ HIGH = 1,
+ LOWHIGH = 1,
+ HIGHLOW = 2
+};
+
+// Cache types
+enum {
+ NONCACHE = 0,
+ DATACACHE = 1,
+ INSTCACHE = 2,
+};
+
+// ARM privilege modes
+enum PrivilegeMode {
+ USER32MODE = 16,
+ FIQ32MODE = 17,
+ IRQ32MODE = 18,
+ SVC32MODE = 19,
+ ABORT32MODE = 23,
+ UNDEF32MODE = 27,
+ SYSTEM32MODE = 31
+};
+
+// ARM privilege mode register banks
+enum {
+ USERBANK = 0,
+ FIQBANK = 1,
+ IRQBANK = 2,
+ SVCBANK = 3,
+ ABORTBANK = 4,
+ UNDEFBANK = 5,
+ DUMMYBANK = 6,
+ SYSTEMBANK = 7
+};
+
+// Hardware vector addresses
+enum {
+ ARMResetV = 0,
+ ARMUndefinedInstrV = 4,
+ ARMSWIV = 8,
+ ARMPrefetchAbortV = 12,
+ ARMDataAbortV = 16,
+ ARMAddrExceptnV = 20,
+ ARMIRQV = 24,
+ ARMFIQV = 28,
+ ARMErrorV = 32, // This is an offset, not an address!
+
+ ARMul_ResetV = ARMResetV,
+ ARMul_UndefinedInstrV = ARMUndefinedInstrV,
+ ARMul_SWIV = ARMSWIV,
+ ARMul_PrefetchAbortV = ARMPrefetchAbortV,
+ ARMul_DataAbortV = ARMDataAbortV,
+ ARMul_AddrExceptnV = ARMAddrExceptnV,
+ ARMul_IRQV = ARMIRQV,
+ ARMul_FIQV = ARMFIQV
+};
+
+// Coprocessor status values
+enum {
+ ARMul_FIRST = 0,
+ ARMul_TRANSFER = 1,
+ ARMul_BUSY = 2,
+ ARMul_DATA = 3,
+ ARMul_INTERRUPT = 4,
+ ARMul_DONE = 0,
+ ARMul_CANT = 1,
+ ARMul_INC = 3
+};
+
+// Instruction condition codes
+enum ConditionCode {
+ EQ = 0,
+ NE = 1,
+ CS = 2,
+ CC = 3,
+ MI = 4,
+ PL = 5,
+ VS = 6,
+ VC = 7,
+ HI = 8,
+ LS = 9,
+ GE = 10,
+ LT = 11,
+ GT = 12,
+ LE = 13,
+ AL = 14,
+ NV = 15,
+};
+
+// Flags for use with the APSR.
+enum : u32 {
+ NBIT = (1U << 31U),
+ ZBIT = (1 << 30),
+ CBIT = (1 << 29),
+ VBIT = (1 << 28),
+ QBIT = (1 << 27),
+ JBIT = (1 << 24),
+ EBIT = (1 << 9),
+ ABIT = (1 << 8),
+ IBIT = (1 << 7),
+ FBIT = (1 << 6),
+ TBIT = (1 << 5),
+
+ // Masks for groups of bits in the APSR.
+ MODEBITS = 0x1F,
+ INTBITS = 0x1C0,
+};
+
+// Values for Emulate.
+enum {
+ STOP = 0, // Stop
+ CHANGEMODE = 1, // Change mode
+ ONCE = 2, // Execute just one iteration
+ RUN = 3 // Continuous execution
+};
+
+
+struct ARMul_State final
+{
+public:
+ explicit ARMul_State(PrivilegeMode initial_mode);
+
+ void ChangePrivilegeMode(u32 new_mode);
+ void Reset();
+
+ // Reads/writes data in big/little endian format based on the
+ // state of the E (endian) bit in the APSR.
+ u16 ReadMemory16(u32 address) const;
+ u32 ReadMemory32(u32 address) const;
+ u64 ReadMemory64(u32 address) const;
+ void WriteMemory16(u32 address, u16 data);
+ void WriteMemory32(u32 address, u32 data);
+ void WriteMemory64(u32 address, u64 data);
+
+ u32 ReadCP15Register(u32 crn, u32 opcode_1, u32 crm, u32 opcode_2) const;
+ void WriteCP15Register(u32 value, u32 crn, u32 opcode_1, u32 crm, u32 opcode_2);
+
+ // Exclusive memory access functions
+ bool IsExclusiveMemoryAccess(u32 address) const {
+ return exclusive_state && exclusive_tag == (address & RESERVATION_GRANULE_MASK);
+ }
+ void SetExclusiveMemoryAddress(u32 address) {
+ exclusive_tag = address & RESERVATION_GRANULE_MASK;
+ exclusive_state = true;
+ }
+ void UnsetExclusiveMemoryAddress() {
+ exclusive_tag = 0xFFFFFFFF;
+ exclusive_state = false;
+ }
+
+ // Whether or not the given CPU is in big endian mode (E bit is set)
+ bool InBigEndianMode() const {
+ return (Cpsr & (1 << 9)) != 0;
+ }
+ // Whether or not the given CPU is in a mode other than user mode.
+ bool InAPrivilegedMode() const {
+ return (Mode != USER32MODE);
+ }
+ // Note that for the 3DS, a Thumb instruction will only ever be
+ // two bytes in size. Thus we don't need to worry about ThumbEE
+ // or Thumb-2 where instructions can be 4 bytes in length.
+ u32 GetInstructionSize() const {
+ return TFlag ? 2 : 4;
+ }
+
+ std::array<u32, 16> Reg; // The current register file
+ std::array<u32, 2> Reg_usr;
+ std::array<u32, 2> Reg_svc; // R13_SVC R14_SVC
+ std::array<u32, 2> Reg_abort; // R13_ABORT R14_ABORT
+ std::array<u32, 2> Reg_undef; // R13 UNDEF R14 UNDEF
+ std::array<u32, 2> Reg_irq; // R13_IRQ R14_IRQ
+ std::array<u32, 7> Reg_firq; // R8---R14 FIRQ
+ std::array<u32, 7> Spsr; // The exception psr's
+ std::array<u32, CP15_REGISTER_COUNT> CP15;
+
+ // FPSID, FPSCR, and FPEXC
+ std::array<u32, VFP_SYSTEM_REGISTER_COUNT> VFP;
+
+ // VFPv2 and VFPv3-D16 has 16 doubleword registers (D0-D16 or S0-S31).
+ // VFPv3-D32/ASIMD may have up to 32 doubleword registers (D0-D31),
+ // and only 32 singleword registers are accessible (S0-S31).
+ std::array<u32, 64> ExtReg;
+
+ u32 Emulate; // To start and stop emulation
+ u32 Cpsr; // The current PSR
+ u32 Spsr_copy;
+ u32 phys_pc;
+
+ u32 Mode; // The current mode
+ u32 Bank; // The current register bank
+
+ u32 NFlag, ZFlag, CFlag, VFlag, IFFlags; // Dummy flags for speed
+ unsigned int shifter_carry_out;
+
+ u32 TFlag; // Thumb state
+
+ unsigned long long NumInstrs; // The number of instructions executed
+ unsigned NumInstrsToExecute;
+
+ unsigned NresetSig; // Reset the processor
+ unsigned NfiqSig;
+ unsigned NirqSig;
+
+ unsigned abortSig;
+ unsigned NtransSig;
+ unsigned bigendSig;
+ unsigned syscallSig;
+
+ // TODO(bunnei): Move this cache to a better place - it should be per codeset (likely per
+ // process for our purposes), not per ARMul_State (which tracks CPU core state).
+ std::unordered_map<u32, int> instruction_cache;
+
+private:
+ void ResetMPCoreCP15Registers();
+
+ // Defines a reservation granule of 2 words, which protects the first 2 words starting at the tag.
+ // This is the smallest granule allowed by the v7 spec, and is coincidentally just large enough to
+ // support LDR/STREXD.
+ static const u32 RESERVATION_GRANULE_MASK = 0xFFFFFFF8;
+
+ u32 exclusive_tag; // The address for which the local monitor is in exclusive access mode
+ u32 exclusive_result;
+ bool exclusive_state;
+};
diff --git a/src/core/arm/skyeye_common/armsupp.cpp b/src/core/arm/skyeye_common/armsupp.cpp
new file mode 100644
index 00000000..d31fb944
--- /dev/null
+++ b/src/core/arm/skyeye_common/armsupp.cpp
@@ -0,0 +1,208 @@
+/* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator.
+ Copyright (C) 1994 Advanced RISC Machines Ltd.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "common/logging/log.h"
+
+#include "core/mem_map.h"
+#include "core/arm/skyeye_common/arm_regformat.h"
+#include "core/arm/skyeye_common/armstate.h"
+#include "core/arm/skyeye_common/armsupp.h"
+
+// Unsigned sum of absolute difference
+u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right)
+{
+ if (left > right)
+ return left - right;
+
+ return right - left;
+}
+
+// Add with carry, indicates if a carry-out or signed overflow occurred.
+u32 AddWithCarry(u32 left, u32 right, u32 carry_in, bool* carry_out_occurred, bool* overflow_occurred)
+{
+ u64 unsigned_sum = (u64)left + (u64)right + (u64)carry_in;
+ s64 signed_sum = (s64)(s32)left + (s64)(s32)right + (s64)carry_in;
+ u64 result = (unsigned_sum & 0xFFFFFFFF);
+
+ if (carry_out_occurred)
+ *carry_out_occurred = (result != unsigned_sum);
+
+ if (overflow_occurred)
+ *overflow_occurred = ((s64)(s32)result != signed_sum);
+
+ return (u32)result;
+}
+
+// Compute whether an addition of A and B, giving RESULT, overflowed.
+bool AddOverflow(u32 a, u32 b, u32 result)
+{
+ return ((NEG(a) && NEG(b) && POS(result)) ||
+ (POS(a) && POS(b) && NEG(result)));
+}
+
+// Compute whether a subtraction of A and B, giving RESULT, overflowed.
+bool SubOverflow(u32 a, u32 b, u32 result)
+{
+ return ((NEG(a) && POS(b) && POS(result)) ||
+ (POS(a) && NEG(b) && NEG(result)));
+}
+
+// Returns true if the Q flag should be set as a result of overflow.
+bool ARMul_AddOverflowQ(u32 a, u32 b)
+{
+ u32 result = a + b;
+ if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0)
+ return true;
+
+ return false;
+}
+
+// 8-bit signed saturated addition
+u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right)
+{
+ u8 result = left + right;
+
+ if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) == 0) {
+ if (left & 0x80)
+ result = 0x80;
+ else
+ result = 0x7F;
+ }
+
+ return result;
+}
+
+// 8-bit signed saturated subtraction
+u8 ARMul_SignedSaturatedSub8(u8 left, u8 right)
+{
+ u8 result = left - right;
+
+ if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) != 0) {
+ if (left & 0x80)
+ result = 0x80;
+ else
+ result = 0x7F;
+ }
+
+ return result;
+}
+
+// 16-bit signed saturated addition
+u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right)
+{
+ u16 result = left + right;
+
+ if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) == 0) {
+ if (left & 0x8000)
+ result = 0x8000;
+ else
+ result = 0x7FFF;
+ }
+
+ return result;
+}
+
+// 16-bit signed saturated subtraction
+u16 ARMul_SignedSaturatedSub16(u16 left, u16 right)
+{
+ u16 result = left - right;
+
+ if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) != 0) {
+ if (left & 0x8000)
+ result = 0x8000;
+ else
+ result = 0x7FFF;
+ }
+
+ return result;
+}
+
+// 8-bit unsigned saturated addition
+u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right)
+{
+ u8 result = left + right;
+
+ if (result < left)
+ result = 0xFF;
+
+ return result;
+}
+
+// 16-bit unsigned saturated addition
+u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right)
+{
+ u16 result = left + right;
+
+ if (result < left)
+ result = 0xFFFF;
+
+ return result;
+}
+
+// 8-bit unsigned saturated subtraction
+u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right)
+{
+ if (left <= right)
+ return 0;
+
+ return left - right;
+}
+
+// 16-bit unsigned saturated subtraction
+u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right)
+{
+ if (left <= right)
+ return 0;
+
+ return left - right;
+}
+
+// Signed saturation.
+u32 ARMul_SignedSatQ(s32 value, u8 shift, bool* saturation_occurred)
+{
+ const u32 max = (1 << shift) - 1;
+ const s32 top = (value >> shift);
+
+ if (top > 0) {
+ *saturation_occurred = true;
+ return max;
+ }
+ else if (top < -1) {
+ *saturation_occurred = true;
+ return ~max;
+ }
+
+ *saturation_occurred = false;
+ return (u32)value;
+}
+
+// Unsigned saturation
+u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred)
+{
+ const u32 max = (1 << shift) - 1;
+
+ if (value < 0) {
+ *saturation_occurred = true;
+ return 0;
+ } else if ((u32)value > max) {
+ *saturation_occurred = true;
+ return max;
+ }
+
+ *saturation_occurred = false;
+ return (u32)value;
+}
diff --git a/src/core/arm/skyeye_common/armsupp.h b/src/core/arm/skyeye_common/armsupp.h
new file mode 100644
index 00000000..391309fa
--- /dev/null
+++ b/src/core/arm/skyeye_common/armsupp.h
@@ -0,0 +1,32 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1))
+#define BIT(s, n) ((s >> (n)) & 1)
+
+#define POS(i) ( (~(i)) >> 31 )
+#define NEG(i) ( (i) >> 31 )
+
+bool AddOverflow(u32, u32, u32);
+bool SubOverflow(u32, u32, u32);
+
+u32 AddWithCarry(u32, u32, u32, bool*, bool*);
+bool ARMul_AddOverflowQ(u32, u32);
+
+u8 ARMul_SignedSaturatedAdd8(u8, u8);
+u8 ARMul_SignedSaturatedSub8(u8, u8);
+u16 ARMul_SignedSaturatedAdd16(u16, u16);
+u16 ARMul_SignedSaturatedSub16(u16, u16);
+
+u8 ARMul_UnsignedSaturatedAdd8(u8, u8);
+u16 ARMul_UnsignedSaturatedAdd16(u16, u16);
+u8 ARMul_UnsignedSaturatedSub8(u8, u8);
+u16 ARMul_UnsignedSaturatedSub16(u16, u16);
+u8 ARMul_UnsignedAbsoluteDifference(u8, u8);
+u32 ARMul_SignedSatQ(s32, u8, bool*);
+u32 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 571d6c2f..26f303de 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfp.cpp
@@ -20,39 +20,30 @@
/* Note: this file handles interface with arm core and vfp registers */
+#include "common/common_funcs.h"
#include "common/logging/log.h"
-#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/armstate.h"
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
#include "core/arm/skyeye_common/vfp/vfp.h"
-unsigned VFPInit(ARMul_State* state)
+void VFPInit(ARMul_State* state)
{
state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
state->VFP[VFP_FPEXC] = 0;
state->VFP[VFP_FPSCR] = 0;
+ // ARM11 MPCore instruction register reset values.
+ state->VFP[VFP_FPINST] = 0xEE000A00;
+ state->VFP[VFP_FPINST2] = 0;
+
// ARM11 MPCore feature register values.
state->VFP[VFP_MVFR0] = 0x11111111;
state->VFP[VFP_MVFR1] = 0;
-
- return 0;
-}
-
-void VMSR(ARMul_State* state, ARMword reg, ARMword Rt)
-{
- if (reg == 1)
- {
- state->VFP[VFP_FPSCR] = state->Reg[Rt];
- }
- else if (reg == 8)
- {
- state->VFP[VFP_FPEXC] = state->Reg[Rt];
- }
}
-void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value)
+void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value)
{
if (to_arm)
{
@@ -64,7 +55,7 @@ void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword*
}
}
-void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2)
+void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2)
{
if (to_arm)
{
@@ -77,7 +68,7 @@ void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword
state->ExtReg[n*2] = *value1;
}
}
-void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2)
+void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2)
{
if (to_arm)
{
@@ -91,7 +82,7 @@ void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMwor
}
}
-void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm)
+void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm)
{
if (single)
{
@@ -104,7 +95,7 @@ void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm)
state->ExtReg[d*2] = 0;
}
}
-void VMOVR(ARMul_State* state, ARMword single, ARMword d, ARMword m)
+void VMOVR(ARMul_State* state, u32 single, u32 d, u32 m)
{
if (single)
{
@@ -153,9 +144,8 @@ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpsc
LOG_TRACE(Core_ARM11, "VFP: raising exceptions %08x\n", exceptions);
if (exceptions == VFP_EXCEPTION_ERROR) {
- LOG_TRACE(Core_ARM11, "unhandled bounce %x\n", inst);
- exit(-1);
- return;
+ LOG_CRITICAL(Core_ARM11, "unhandled bounce %x\n", inst);
+ Crash();
}
/*
diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h
index acefae9b..88908da9 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.h
+++ b/src/core/arm/skyeye_common/vfp/vfp.h
@@ -26,7 +26,7 @@
#define CHECK_VFP_ENABLED
#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
-unsigned VFPInit(ARMul_State* state);
+void VFPInit(ARMul_State* state);
s32 vfp_get_float(ARMul_State* state, u32 reg);
void 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
u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
-void VMSR(ARMul_State* state, ARMword reg, ARMword Rt);
-void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value);
-void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2);
-void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2);
-void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm);
-void VMOVR(ARMul_State* state, ARMword single, ARMword d, ARMword imm);
-
+void VMOVBRS(ARMul_State* state, u32 to_arm, u32 t, u32 n, u32* value);
+void VMOVBRRD(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2);
+void VMOVBRRSS(ARMul_State* state, u32 to_arm, u32 t, u32 t2, u32 n, u32* value1, u32* value2);
+void VMOVI(ARMul_State* state, u32 single, u32 d, u32 imm);
+void VMOVR(ARMul_State* state, u32 single, u32 d, u32 imm);
diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h
index 2007d6dc..91a8d4d5 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 @@
#include <cstdio>
#include "common/common_types.h"
-#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/armstate.h"
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
#define do_div(n, base) {n/=base;}
@@ -415,7 +415,7 @@ struct op {
u32 flags;
};
-static inline u32 fls(ARMword x)
+static inline u32 fls(u32 x)
{
int r = 32;
diff --git a/src/core/arm/skyeye_common/vfp/vfpdouble.cpp b/src/core/arm/skyeye_common/vfp/vfpdouble.cpp
index f9104958..1d844a66 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)
static void vfp_double_normalise_denormal(struct vfp_double *vd)
{
- int bits = 31 - fls((ARMword)(vd->significand >> 32));
+ int bits = 31 - fls((u32)(vd->significand >> 32));
if (bits == 31)
- bits = 63 - fls((ARMword)vd->significand);
+ bits = 63 - fls((u32)vd->significand);
vfp_double_dump("normalise_denormal: in", vd);
@@ -109,9 +109,9 @@ u32 vfp_double_normaliseround(ARMul_State* state, int dd, struct vfp_double *vd,
exponent = vd->exponent;
significand = vd->significand;
- shift = 32 - fls((ARMword)(significand >> 32));
+ shift = 32 - fls((u32)(significand >> 32));
if (shift == 32)
- shift = 64 - fls((ARMword)significand);
+ shift = 64 - fls((u32)significand);
if (shift) {
exponent -= shift;
significand <<= shift;
@@ -566,7 +566,7 @@ static u32 vfp_double_ftoui(ARMul_State* state, int sd, int unused, int dm, u32
/*
* 2^0 <= m < 2^32-2^8
*/
- d = (ARMword)((vdm.significand << 1) >> shift);
+ d = (u32)((vdm.significand << 1) >> shift);
rem = vdm.significand << (65 - shift);
if (rmode == FPSCR_ROUND_NEAREST) {
@@ -647,7 +647,7 @@ static u32 vfp_double_ftosi(ARMul_State* state, int sd, int unused, int dm, u32
int shift = 1023 + 63 - vdm.exponent; /* 58 */
u64 rem, incr = 0;
- d = (ARMword)((vdm.significand << 1) >> shift);
+ d = (u32)((vdm.significand << 1) >> shift);
rem = vdm.significand << (65 - shift);
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 67fe63aa..9b99fc5b 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:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmla_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -100,7 +100,7 @@ VMLS_INST:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmls_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -149,7 +149,7 @@ VNMLA_INST:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vnmla_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -199,7 +199,7 @@ VNMLS_INST:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vnmls_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -248,7 +248,7 @@ VNMUL_INST:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vnmul_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -297,7 +297,7 @@ VMUL_INST:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmul_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -346,7 +346,7 @@ VADD_INST:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vadd_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -395,7 +395,7 @@ VSUB_INST:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vsub_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -444,7 +444,7 @@ VDIV_INST:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vdiv_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -492,7 +492,7 @@ VMOVI_INST:
VMOVI(cpu, inst_cream->single, inst_cream->d, inst_cream->imm);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmovi_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -536,7 +536,7 @@ VMOVR_INST:
VMOVR(cpu, inst_cream->single, inst_cream->d, inst_cream->m);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmovr_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -585,7 +585,7 @@ VABS_INST:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vabs_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -635,7 +635,7 @@ VNEG_INST:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vneg_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -684,7 +684,7 @@ VSQRT_INST:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vsqrt_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -733,7 +733,7 @@ VCMP_INST:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vcmp_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -782,7 +782,7 @@ VCMP2_INST:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vcmp2_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -831,7 +831,7 @@ VCVTBDS_INST:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vcvtbds_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -882,7 +882,7 @@ VCVTBFF_INST:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vcvtbff_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -931,7 +931,7 @@ VCVTBFI_INST:
CHECK_VFP_CDP_RET;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vcvtbfi_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -981,7 +981,7 @@ VMOVBRS_INST:
VMOVBRS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->n, &(cpu->Reg[inst_cream->t]));
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmovbrs_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -995,7 +995,7 @@ VMOVBRS_INST:
#ifdef VFP_INTERPRETER_STRUCT
struct vmsr_inst {
unsigned int reg;
- unsigned int Rd;
+ unsigned int Rt;
};
#endif
#ifdef VFP_INTERPRETER_TRANS
@@ -1009,7 +1009,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index)
inst_base->br = NON_BRANCH;
inst_cream->reg = BITS(inst, 16, 19);
- inst_cream->Rd = BITS(inst, 12, 15);
+ inst_cream->Rt = BITS(inst, 12, 15);
return inst_base;
}
@@ -1017,17 +1017,32 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index)
#ifdef VFP_INTERPRETER_IMPL
VMSR_INST:
{
- if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
/* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled ,
and in privileged mode */
/* Exceptions must be checked, according to v7 ref manual */
CHECK_VFP_ENABLED;
- vmsr_inst *inst_cream = (vmsr_inst *)inst_base->component;
+ vmsr_inst* const inst_cream = (vmsr_inst*)inst_base->component;
+
+ unsigned int reg = inst_cream->reg;
+ unsigned int rt = inst_cream->Rt;
- VMSR(cpu, inst_cream->reg, inst_cream->Rd);
+ if (reg == 1)
+ {
+ cpu->VFP[VFP_FPSCR] = cpu->Reg[rt];
+ }
+ else if (cpu->InAPrivilegedMode())
+ {
+ if (reg == 8)
+ cpu->VFP[VFP_FPEXC] = cpu->Reg[rt];
+ else if (reg == 9)
+ cpu->VFP[VFP_FPINST] = cpu->Reg[rt];
+ else if (reg == 10)
+ cpu->VFP[VFP_FPINST2] = cpu->Reg[rt];
+ }
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmsr_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -1075,7 +1090,7 @@ VMOVBRC_INST:
cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index] = cpu->Reg[inst_cream->t];
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmovbrc_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -1111,19 +1126,22 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmrs)(unsigned int inst, int index)
#ifdef VFP_INTERPRETER_IMPL
VMRS_INST:
{
- if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
+ if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
/* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled,
and in privileged mode */
/* Exceptions must be checked, according to v7 ref manual */
CHECK_VFP_ENABLED;
- vmrs_inst *inst_cream = (vmrs_inst *)inst_base->component;
+ vmrs_inst* const inst_cream = (vmrs_inst*)inst_base->component;
- if (inst_cream->reg == 1) /* FPSCR */
+ unsigned int reg = inst_cream->reg;
+ unsigned int rt = inst_cream->Rt;
+
+ if (reg == 1) // FPSCR
{
- if (inst_cream->Rt != 15)
+ if (rt != 15)
{
- cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSCR];
+ cpu->Reg[rt] = cpu->VFP[VFP_FPSCR];
}
else
{
@@ -1133,28 +1151,29 @@ VMRS_INST:
cpu->VFlag = (cpu->VFP[VFP_FPSCR] >> 28) & 1;
}
}
- else
+ else if (reg == 0)
{
- switch (inst_cream->reg)
- {
- case 0:
- cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSID];
- break;
- case 6:
- cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR1];
- break;
- case 7:
- cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR0];
- break;
- case 8:
- cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPEXC];
- break;
- default:
- break;
- }
+ cpu->Reg[rt] = cpu->VFP[VFP_FPSID];
+ }
+ else if (reg == 6)
+ {
+ cpu->Reg[rt] = cpu->VFP[VFP_MVFR1];
+ }
+ else if (reg == 7)
+ {
+ cpu->Reg[rt] = cpu->VFP[VFP_MVFR0];
+ }
+ else if (cpu->InAPrivilegedMode())
+ {
+ if (reg == 8)
+ cpu->Reg[rt] = cpu->VFP[VFP_FPEXC];
+ else if (reg == 9)
+ cpu->Reg[rt] = cpu->VFP[VFP_FPINST];
+ else if (reg == 10)
+ cpu->Reg[rt] = cpu->VFP[VFP_FPINST2];
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmrs_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -1202,7 +1221,7 @@ VMOVBCR_INST:
cpu->Reg[inst_cream->t] = cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index];
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmovbcr_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -1255,7 +1274,7 @@ VMOVBRRSS_INST:
VMOVBRRSS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m,
&cpu->Reg[inst_cream->t], &cpu->Reg[inst_cream->t2]);
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmovbrrss_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -1303,7 +1322,7 @@ VMOVBRRD_INST:
VMOVBRRD(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m,
&(cpu->Reg[inst_cream->t]), &(cpu->Reg[inst_cream->t2]));
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vmovbrrd_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -1359,23 +1378,23 @@ VSTR_INST:
if (inst_cream->single)
{
- WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d]);
+ cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d]);
}
else
{
const u32 word1 = cpu->ExtReg[inst_cream->d*2+0];
const u32 word2 = cpu->ExtReg[inst_cream->d*2+1];
- if (InBigEndianMode(cpu)) {
- WriteMemory32(cpu, addr + 0, word2);
- WriteMemory32(cpu, addr + 4, word1);
+ if (cpu->InBigEndianMode()) {
+ cpu->WriteMemory32(addr + 0, word2);
+ cpu->WriteMemory32(addr + 4, word1);
} else {
- WriteMemory32(cpu, addr + 0, word1);
- WriteMemory32(cpu, addr + 4, word2);
+ cpu->WriteMemory32(addr + 0, word1);
+ cpu->WriteMemory32(addr + 4, word2);
}
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vstr_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -1425,7 +1444,7 @@ VPUSH_INST:
{
if (inst_cream->single)
{
- WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d+i]);
+ cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d+i]);
addr += 4;
}
else
@@ -1433,12 +1452,12 @@ VPUSH_INST:
const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0];
const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1];
- if (InBigEndianMode(cpu)) {
- WriteMemory32(cpu, addr + 0, word2);
- WriteMemory32(cpu, addr + 4, word1);
+ if (cpu->InBigEndianMode()) {
+ cpu->WriteMemory32(addr + 0, word2);
+ cpu->WriteMemory32(addr + 4, word1);
} else {
- WriteMemory32(cpu, addr + 0, word1);
- WriteMemory32(cpu, addr + 4, word2);
+ cpu->WriteMemory32(addr + 0, word1);
+ cpu->WriteMemory32(addr + 4, word2);
}
addr += 8;
@@ -1447,7 +1466,7 @@ VPUSH_INST:
cpu->Reg[R13] -= inst_cream->imm32;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vpush_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -1503,7 +1522,7 @@ VSTM_INST: /* encoding 1 */
{
if (inst_cream->single)
{
- WriteMemory32(cpu, addr, cpu->ExtReg[inst_cream->d+i]);
+ cpu->WriteMemory32(addr, cpu->ExtReg[inst_cream->d+i]);
addr += 4;
}
else
@@ -1511,12 +1530,12 @@ VSTM_INST: /* encoding 1 */
const u32 word1 = cpu->ExtReg[(inst_cream->d+i)*2+0];
const u32 word2 = cpu->ExtReg[(inst_cream->d+i)*2+1];
- if (InBigEndianMode(cpu)) {
- WriteMemory32(cpu, addr + 0, word2);
- WriteMemory32(cpu, addr + 4, word1);
+ if (cpu->InBigEndianMode()) {
+ cpu->WriteMemory32(addr + 0, word2);
+ cpu->WriteMemory32(addr + 4, word1);
} else {
- WriteMemory32(cpu, addr + 0, word1);
- WriteMemory32(cpu, addr + 4, word2);
+ cpu->WriteMemory32(addr + 0, word1);
+ cpu->WriteMemory32(addr + 4, word2);
}
addr += 8;
@@ -1578,15 +1597,15 @@ VPOP_INST:
{
if (inst_cream->single)
{
- cpu->ExtReg[inst_cream->d+i] = ReadMemory32(cpu, addr);
+ cpu->ExtReg[inst_cream->d+i] = cpu->ReadMemory32(addr);
addr += 4;
}
else
{
- const u32 word1 = ReadMemory32(cpu, addr + 0);
- const u32 word2 = ReadMemory32(cpu, addr + 4);
+ const u32 word1 = cpu->ReadMemory32(addr + 0);
+ const u32 word2 = cpu->ReadMemory32(addr + 4);
- if (InBigEndianMode(cpu)) {
+ if (cpu->InBigEndianMode()) {
cpu->ExtReg[(inst_cream->d+i)*2+0] = word2;
cpu->ExtReg[(inst_cream->d+i)*2+1] = word1;
} else {
@@ -1599,7 +1618,7 @@ VPOP_INST:
}
cpu->Reg[R13] += inst_cream->imm32;
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vpop_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -1651,14 +1670,14 @@ VLDR_INST:
if (inst_cream->single)
{
- cpu->ExtReg[inst_cream->d] = ReadMemory32(cpu, addr);
+ cpu->ExtReg[inst_cream->d] = cpu->ReadMemory32(addr);
}
else
{
- const u32 word1 = ReadMemory32(cpu, addr + 0);
- const u32 word2 = ReadMemory32(cpu, addr + 4);
+ const u32 word1 = cpu->ReadMemory32(addr + 0);
+ const u32 word2 = cpu->ReadMemory32(addr + 4);
- if (InBigEndianMode(cpu)) {
+ if (cpu->InBigEndianMode()) {
cpu->ExtReg[inst_cream->d*2+0] = word2;
cpu->ExtReg[inst_cream->d*2+1] = word1;
} else {
@@ -1667,7 +1686,7 @@ VLDR_INST:
}
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vldr_inst));
FETCH_INST;
GOTO_NEXT_INST;
@@ -1723,15 +1742,15 @@ VLDM_INST:
{
if (inst_cream->single)
{
- cpu->ExtReg[inst_cream->d+i] = ReadMemory32(cpu, addr);
+ cpu->ExtReg[inst_cream->d+i] = cpu->ReadMemory32(addr);
addr += 4;
}
else
{
- const u32 word1 = ReadMemory32(cpu, addr + 0);
- const u32 word2 = ReadMemory32(cpu, addr + 4);
+ const u32 word1 = cpu->ReadMemory32(addr + 0);
+ const u32 word2 = cpu->ReadMemory32(addr + 4);
- if (InBigEndianMode(cpu)) {
+ if (cpu->InBigEndianMode()) {
cpu->ExtReg[(inst_cream->d+i)*2+0] = word2;
cpu->ExtReg[(inst_cream->d+i)*2+1] = word1;
} else {
@@ -1747,7 +1766,7 @@ VLDM_INST:
cpu->Reg[inst_cream->n] - inst_cream->imm32);
}
}
- cpu->Reg[15] += GET_INST_SIZE(cpu);
+ cpu->Reg[15] += cpu->GetInstructionSize();
INC_PC(sizeof(vldm_inst));
FETCH_INST;
GOTO_NEXT_INST;
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
index 5a655a6f..e5d33925 100644
--- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
@@ -53,6 +53,8 @@
#include <cinttypes>
+#include "common/common_funcs.h"
+#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/arm/skyeye_common/vfp/vfp_helper.h"
@@ -1246,7 +1248,7 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
if (!fop->fn) {
LOG_CRITICAL(Core_ARM11, "could not find single op %d, inst=0x%x@0x%x", FEXT_TO_IDX(inst), inst, state->Reg[15]);
- exit(-1);
+ Crash();
goto invalid;
}
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 79038cd5..dddc1670 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -2,15 +2,12 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/core_timing.h"
-#include "core/settings.h"
#include "core/arm/arm_interface.h"
-#include "core/arm/disassembler/arm_disasm.h"
#include "core/arm/dyncom/arm_dyncom.h"
#include "core/hle/hle.h"
#include "core/hle/kernel/thread.h"
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index e53c2e60..20f2da0f 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -3,12 +3,12 @@
// Refer to the license.txt file included.
#include <atomic>
-#include <cstdio>
#include <mutex>
#include <vector>
-#include "common/assert.h"
#include "common/chunk_file.h"
+#include "common/logging/log.h"
+#include "common/string_util.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
@@ -502,7 +502,7 @@ void Advance() {
Core::g_app_core->down_count += diff;
}
if (advance_callback)
- advance_callback(cycles_executed);
+ advance_callback(static_cast<int>(cycles_executed));
}
void LogPendingEvents() {
diff --git a/src/core/file_sys/archive_backend.cpp b/src/core/file_sys/archive_backend.cpp
index 45a559ce..3f81447d 100644
--- a/src/core/file_sys/archive_backend.cpp
+++ b/src/core/file_sys/archive_backend.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstddef>
+#include <iomanip>
#include <sstream>
#include "common/logging/log.h"
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index e50c58a5..92dad8e6 100644
--- a/src/core/file_sys/archive_extsavedata.cpp
+++ b/src/core/file_sys/archive_extsavedata.cpp
@@ -2,17 +2,18 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <sys/stat.h>
+#include <algorithm>
+#include <vector>
#include "common/common_types.h"
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/make_unique.h"
+#include "common/string_util.h"
#include "core/file_sys/archive_extsavedata.h"
#include "core/file_sys/disk_archive.h"
#include "core/hle/service/fs/archive.h"
-#include "core/settings.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h
index ef0b27bd..ec8d770f 100644
--- a/src/core/file_sys/archive_extsavedata.h
+++ b/src/core/file_sys/archive_extsavedata.h
@@ -4,10 +4,13 @@
#pragma once
+#include <memory>
+#include <string>
+
#include "common/common_types.h"
-#include "core/file_sys/disk_archive.h"
-#include "core/loader/loader.h"
+#include "core/file_sys/archive_backend.h"
+#include "core/hle/result.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp
index d4a12ed1..696b51a9 100644
--- a/src/core/file_sys/archive_romfs.cpp
+++ b/src/core/file_sys/archive_romfs.cpp
@@ -2,30 +2,30 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
#include <memory>
#include "common/common_types.h"
-#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/make_unique.h"
#include "core/file_sys/archive_romfs.h"
+#include "core/file_sys/ivfc_archive.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
namespace FileSys {
-ArchiveFactory_RomFS::ArchiveFactory_RomFS(const Loader::AppLoader& app_loader)
- : romfs_data(std::make_shared<std::vector<u8>>()) {
+ArchiveFactory_RomFS::ArchiveFactory_RomFS(Loader::AppLoader& app_loader) {
// Load the RomFS from the app
- if (Loader::ResultStatus::Success != app_loader.ReadRomFS(*romfs_data)) {
+ if (Loader::ResultStatus::Success != app_loader.ReadRomFS(romfs_file, data_offset, data_size)) {
LOG_ERROR(Service_FS, "Unable to read RomFS!");
}
}
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_RomFS::Open(const Path& path) {
- auto archive = Common::make_unique<IVFCArchive>(romfs_data);
+ auto archive = Common::make_unique<IVFCArchive>(romfs_file, data_offset, data_size);
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
}
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h
index 409bc670..2bedfa9c 100644
--- a/src/core/file_sys/archive_romfs.h
+++ b/src/core/file_sys/archive_romfs.h
@@ -5,11 +5,13 @@
#pragma once
#include <memory>
+#include <string>
#include <vector>
#include "common/common_types.h"
-#include "core/file_sys/ivfc_archive.h"
+#include "core/file_sys/archive_backend.h"
+#include "core/hle/result.h"
#include "core/loader/loader.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -20,14 +22,16 @@ namespace FileSys {
/// File system interface to the RomFS archive
class ArchiveFactory_RomFS final : public ArchiveFactory {
public:
- ArchiveFactory_RomFS(const Loader::AppLoader& app_loader);
+ ArchiveFactory_RomFS(Loader::AppLoader& app_loader);
std::string GetName() const override { return "RomFS"; }
ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
ResultCode Format(const Path& path) override;
private:
- std::shared_ptr<std::vector<u8>> romfs_data;
+ std::shared_ptr<FileUtil::IOFile> romfs_file;
+ u64 data_offset;
+ u64 data_size;
};
} // namespace FileSys
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
index a9230937..12876899 100644
--- a/src/core/file_sys/archive_savedata.cpp
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -2,18 +2,18 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <sys/stat.h>
+#include <algorithm>
#include "common/common_types.h"
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/make_unique.h"
+#include "common/string_util.h"
#include "core/file_sys/archive_savedata.h"
#include "core/file_sys/disk_archive.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/fs/archive.h"
-#include "core/settings.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
@@ -37,7 +37,7 @@ ArchiveFactory_SaveData::ArchiveFactory_SaveData(const std::string& sdmc_directo
}
ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) {
- std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->program_id);
+ std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id);
if (!FileUtil::Exists(concrete_mount_point)) {
// When a SaveData archive is created for the first time, it is not yet formatted
// 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
}
ResultCode ArchiveFactory_SaveData::Format(const Path& path) {
- std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->program_id);
+ std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id);
FileUtil::DeleteDirRecursively(concrete_mount_point);
FileUtil::CreateFullPath(concrete_mount_point);
return RESULT_SUCCESS;
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h
index db17afc9..1f65297d 100644
--- a/src/core/file_sys/archive_savedata.h
+++ b/src/core/file_sys/archive_savedata.h
@@ -4,10 +4,11 @@
#pragma once
-#include "common/common_types.h"
+#include <memory>
+#include <string>
-#include "core/file_sys/disk_archive.h"
-#include "core/loader/loader.h"
+#include "core/file_sys/archive_backend.h"
+#include "core/hle/result.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
diff --git a/src/core/file_sys/archive_savedatacheck.cpp b/src/core/file_sys/archive_savedatacheck.cpp
index e7e4fbf1..ea1dfe2c 100644
--- a/src/core/file_sys/archive_savedatacheck.cpp
+++ b/src/core/file_sys/archive_savedatacheck.cpp
@@ -2,11 +2,17 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+#include <vector>
+
+#include "common/common_types.h"
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/make_unique.h"
+#include "common/string_util.h"
#include "core/file_sys/archive_savedatacheck.h"
+#include "core/file_sys/ivfc_archive.h"
#include "core/hle/service/fs/archive.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -31,17 +37,14 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveDataCheck::Open(co
auto vec = path.AsBinary();
const u32* data = reinterpret_cast<u32*>(vec.data());
std::string file_path = GetSaveDataCheckPath(mount_point, data[1], data[0]);
- FileUtil::IOFile file(file_path, "rb");
+ auto file = std::make_shared<FileUtil::IOFile>(file_path, "rb");
- if (!file.IsOpen()) {
+ if (!file->IsOpen()) {
return ResultCode(-1); // TODO(Subv): Find the right error code
}
- auto size = file.GetSize();
- auto raw_data = std::make_shared<std::vector<u8>>(size);
- file.ReadBytes(raw_data->data(), size);
- file.Close();
+ auto size = file->GetSize();
- auto archive = Common::make_unique<IVFCArchive>(std::move(raw_data));
+ auto archive = Common::make_unique<IVFCArchive>(file, 0, size);
return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
}
diff --git a/src/core/file_sys/archive_savedatacheck.h b/src/core/file_sys/archive_savedatacheck.h
index f78a6f02..b14aefe8 100644
--- a/src/core/file_sys/archive_savedatacheck.h
+++ b/src/core/file_sys/archive_savedatacheck.h
@@ -4,12 +4,11 @@
#pragma once
-#include <vector>
+#include <memory>
+#include <string>
-#include "common/common_types.h"
-
-#include "core/file_sys/ivfc_archive.h"
-#include "core/loader/loader.h"
+#include "core/file_sys/archive_backend.h"
+#include "core/hle/result.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index c1234a18..5c825f42 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -2,9 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <sys/stat.h>
+#include <algorithm>
-#include "common/common_types.h"
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/make_unique.h"
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index 1becf6c0..10b273bd 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -4,10 +4,11 @@
#pragma once
-#include "common/common_types.h"
+#include <memory>
+#include <string>
-#include "core/file_sys/disk_archive.h"
-#include "core/loader/loader.h"
+#include "core/file_sys/archive_backend.h"
+#include "core/hle/result.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp
index 4fe785c9..896f8952 100644
--- a/src/core/file_sys/archive_systemsavedata.cpp
+++ b/src/core/file_sys/archive_systemsavedata.cpp
@@ -2,15 +2,17 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <sys/stat.h>
+#include <algorithm>
+#include <vector>
#include "common/common_types.h"
#include "common/file_util.h"
#include "common/make_unique.h"
+#include "common/string_util.h"
#include "core/file_sys/archive_systemsavedata.h"
+#include "core/file_sys/disk_archive.h"
#include "core/hle/service/fs/archive.h"
-#include "core/settings.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h
index 3431fed8..afc68984 100644
--- a/src/core/file_sys/archive_systemsavedata.h
+++ b/src/core/file_sys/archive_systemsavedata.h
@@ -4,10 +4,13 @@
#pragma once
+#include <memory>
+#include <string>
+
#include "common/common_types.h"
-#include "core/file_sys/disk_archive.h"
-#include "core/loader/loader.h"
+#include "core/file_sys/archive_backend.h"
+#include "core/hle/result.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp
index 9980cced..1096fd34 100644
--- a/src/core/file_sys/disk_archive.cpp
+++ b/src/core/file_sys/disk_archive.cpp
@@ -2,7 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <sys/stat.h>
+#include <algorithm>
+#include <cstdio>
#include "common/common_types.h"
#include "common/file_util.h"
@@ -10,7 +11,6 @@
#include "common/make_unique.h"
#include "core/file_sys/disk_archive.h"
-#include "core/settings.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
@@ -105,12 +105,12 @@ bool DiskFile::Open() {
return true;
}
-size_t DiskFile::Read(const u64 offset, const u32 length, u8* buffer) const {
+size_t DiskFile::Read(const u64 offset, const size_t length, u8* buffer) const {
file->Seek(offset, SEEK_SET);
return file->ReadBytes(buffer, length);
}
-size_t DiskFile::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const {
+size_t DiskFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const {
file->Seek(offset, SEEK_SET);
size_t written = file->WriteBytes(buffer, length);
if (flush)
@@ -118,8 +118,8 @@ size_t DiskFile::Write(const u64 offset, const u32 length, const u32 flush, cons
return written;
}
-size_t DiskFile::GetSize() const {
- return static_cast<size_t>(file->GetSize());
+u64 DiskFile::GetSize() const {
+ return file->GetSize();
}
bool 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 a22d3837..c5da0750 100644
--- a/src/core/file_sys/disk_archive.h
+++ b/src/core/file_sys/disk_archive.h
@@ -4,13 +4,18 @@
#pragma once
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <vector>
+
#include "common/common_types.h"
#include "common/file_util.h"
#include "core/file_sys/archive_backend.h"
#include "core/file_sys/directory_backend.h"
#include "core/file_sys/file_backend.h"
-#include "core/loader/loader.h"
+#include "core/hle/result.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
@@ -50,10 +55,10 @@ public:
DiskFile(const DiskArchive& archive, const Path& path, const Mode mode);
bool Open() override;
- size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
- size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override;
- size_t GetSize() const override;
- bool SetSize(const u64 size) const override;
+ size_t Read(u64 offset, size_t length, u8* buffer) const override;
+ size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const override;
+ u64 GetSize() const override;
+ bool SetSize(u64 size) const override;
bool Close() const override;
void Flush() const override {
diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h
index 0fcff184..df7165df 100644
--- a/src/core/file_sys/file_backend.h
+++ b/src/core/file_sys/file_backend.h
@@ -4,6 +4,8 @@
#pragma once
+#include <cstddef>
+
#include "common/common_types.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -29,7 +31,7 @@ public:
* @param buffer Buffer to read data into
* @return Number of bytes read
*/
- virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0;
+ virtual size_t Read(u64 offset, size_t length, u8* buffer) const = 0;
/**
* Write data to the file
@@ -39,20 +41,20 @@ public:
* @param buffer Buffer to read data from
* @return Number of bytes written
*/
- virtual size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const = 0;
+ virtual size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const = 0;
/**
* Get the size of the file in bytes
* @return Size of the file in bytes
*/
- virtual size_t GetSize() const = 0;
+ virtual u64 GetSize() const = 0;
/**
* Set the size of the file in bytes
* @param size New size of the file
* @return true if successful
*/
- virtual bool SetSize(const u64 size) const = 0;
+ virtual bool SetSize(u64 size) const = 0;
/**
* Close the file
diff --git a/src/core/file_sys/ivfc_archive.cpp b/src/core/file_sys/ivfc_archive.cpp
index 2d2509d1..e16aa149 100644
--- a/src/core/file_sys/ivfc_archive.cpp
+++ b/src/core/file_sys/ivfc_archive.cpp
@@ -2,10 +2,10 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
#include <memory>
#include "common/common_types.h"
-#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/make_unique.h"
@@ -16,15 +16,12 @@
namespace FileSys {
-IVFCArchive::IVFCArchive(std::shared_ptr<const std::vector<u8>> data) : data(data) {
-}
-
std::string IVFCArchive::GetName() const {
return "IVFC";
}
std::unique_ptr<FileBackend> IVFCArchive::OpenFile(const Path& path, const Mode mode) const {
- return Common::make_unique<IVFCFile>(data);
+ return Common::make_unique<IVFCFile>(romfs_file, data_offset, data_size);
}
bool IVFCArchive::DeleteFile(const Path& path) const {
@@ -64,19 +61,21 @@ std::unique_ptr<DirectoryBackend> IVFCArchive::OpenDirectory(const Path& path) c
////////////////////////////////////////////////////////////////////////////////////////////////////
-size_t IVFCFile::Read(const u64 offset, const u32 length, u8* buffer) const {
+size_t IVFCFile::Read(const u64 offset, const size_t length, u8* buffer) const {
LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length);
- memcpy(buffer, data->data() + offset, length);
- return length;
+ romfs_file->Seek(data_offset + offset, SEEK_SET);
+ size_t read_length = (size_t)std::min((u64)length, data_size - offset);
+
+ return romfs_file->ReadBytes(buffer, read_length);
}
-size_t IVFCFile::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const {
+size_t IVFCFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const {
LOG_ERROR(Service_FS, "Attempted to write to IVFC file");
return 0;
}
-size_t IVFCFile::GetSize() const {
- return sizeof(u8) * data->size();
+u64 IVFCFile::GetSize() const {
+ return data_size;
}
bool 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 10415798..c15a6c4a 100644
--- a/src/core/file_sys/ivfc_archive.h
+++ b/src/core/file_sys/ivfc_archive.h
@@ -4,15 +4,18 @@
#pragma once
+#include <cstddef>
#include <memory>
+#include <string>
#include <vector>
#include "common/common_types.h"
+#include "common/file_util.h"
#include "core/file_sys/archive_backend.h"
#include "core/file_sys/directory_backend.h"
#include "core/file_sys/file_backend.h"
-#include "core/loader/loader.h"
+#include "core/hle/result.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// FileSys namespace
@@ -26,7 +29,8 @@ namespace FileSys {
*/
class IVFCArchive : public ArchiveBackend {
public:
- IVFCArchive(std::shared_ptr<const std::vector<u8>> data);
+ IVFCArchive(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)
+ : romfs_file(file), data_offset(offset), data_size(size) {}
std::string GetName() const override;
@@ -40,23 +44,28 @@ public:
std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
protected:
- std::shared_ptr<const std::vector<u8>> data;
+ std::shared_ptr<FileUtil::IOFile> romfs_file;
+ u64 data_offset;
+ u64 data_size;
};
class IVFCFile : public FileBackend {
public:
- IVFCFile(std::shared_ptr<const std::vector<u8>> data) : data(data) {}
+ IVFCFile(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)
+ : romfs_file(file), data_offset(offset), data_size(size) {}
bool Open() override { return true; }
- size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
- size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override;
- size_t GetSize() const override;
- bool SetSize(const u64 size) const override;
+ size_t Read(u64 offset, size_t length, u8* buffer) const override;
+ size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const override;
+ u64 GetSize() const override;
+ bool SetSize(u64 size) const override;
bool Close() const override { return false; }
void Flush() const override { }
private:
- std::shared_ptr<const std::vector<u8>> data;
+ std::shared_ptr<FileUtil::IOFile> romfs_file;
+ u64 data_offset;
+ u64 data_size;
};
class IVFCDirectory : public DirectoryBackend {
diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp
new file mode 100644
index 00000000..826f6cbb
--- /dev/null
+++ b/src/core/hle/applets/applet.cpp
@@ -0,0 +1,101 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <cstddef>
+#include <memory>
+#include <type_traits>
+#include <unordered_map>
+
+#include "common/assert.h"
+#include "common/common_types.h"
+
+#include "core/core_timing.h"
+#include "core/hle/applets/applet.h"
+#include "core/hle/applets/swkbd.h"
+#include "core/hle/result.h"
+#include "core/hle/service/apt/apt.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// Specializes std::hash for AppletId, so that we can use it in std::unordered_map.
+// Workaround for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970
+namespace std {
+ template <>
+ struct hash<Service::APT::AppletId> {
+ typedef Service::APT::AppletId argument_type;
+ typedef std::size_t result_type;
+
+ result_type operator()(const argument_type& id_code) const {
+ typedef std::underlying_type<argument_type>::type Type;
+ return std::hash<Type>()(static_cast<Type>(id_code));
+ }
+ };
+}
+
+namespace HLE {
+namespace Applets {
+
+static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> applets;
+static u32 applet_update_event = -1; ///< The CoreTiming event identifier for the Applet update callback.
+/// The interval at which the Applet update callback will be called, 16.6ms
+static const u64 applet_update_interval_us = 16666;
+
+ResultCode Applet::Create(Service::APT::AppletId id) {
+ switch (id) {
+ case Service::APT::AppletId::SoftwareKeyboard1:
+ case Service::APT::AppletId::SoftwareKeyboard2:
+ applets[id] = std::make_shared<SoftwareKeyboard>(id);
+ break;
+ default:
+ // TODO(Subv): Find the right error code
+ return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported, ErrorLevel::Permanent);
+ }
+
+ return RESULT_SUCCESS;
+}
+
+std::shared_ptr<Applet> Applet::Get(Service::APT::AppletId id) {
+ auto itr = applets.find(id);
+ if (itr != applets.end())
+ return itr->second;
+ return nullptr;
+}
+
+/// Handles updating the current Applet every time it's called.
+static void AppletUpdateEvent(u64 applet_id, int cycles_late) {
+ Service::APT::AppletId id = static_cast<Service::APT::AppletId>(applet_id);
+ std::shared_ptr<Applet> applet = Applet::Get(id);
+ ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id=%08X", id);
+
+ applet->Update();
+
+ // If the applet is still running after the last update, reschedule the event
+ if (applet->IsRunning()) {
+ CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late,
+ applet_update_event, applet_id);
+ } else {
+ // Otherwise the applet has terminated, in which case we should clean it up
+ applets[id] = nullptr;
+ }
+}
+
+ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) {
+ ResultCode result = StartImpl(parameter);
+ if (result.IsError())
+ return result;
+ // Schedule the update event
+ CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event, static_cast<u64>(id));
+ return result;
+}
+
+void Init() {
+ // Register the applet update callback
+ applet_update_event = CoreTiming::RegisterEvent("HLE Applet Update Event", AppletUpdateEvent);
+}
+
+void Shutdown() {
+}
+
+}
+} // namespace
diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h
new file mode 100644
index 00000000..b235d0b8
--- /dev/null
+++ b/src/core/hle/applets/applet.h
@@ -0,0 +1,77 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+
+#include "core/hle/result.h"
+#include "core/hle/service/apt/apt.h"
+
+namespace HLE {
+namespace Applets {
+
+class Applet {
+public:
+ virtual ~Applet() { }
+ Applet(Service::APT::AppletId id) : id(id) { }
+
+ /**
+ * Creates an instance of the Applet subclass identified by the parameter.
+ * and stores it in a global map.
+ * @param id Id of the applet to create.
+ * @returns ResultCode Whether the operation was successful or not.
+ */
+ static ResultCode Create(Service::APT::AppletId id);
+
+ /**
+ * Retrieves the Applet instance identified by the specified id.
+ * @param id Id of the Applet to retrieve.
+ * @returns Requested Applet or nullptr if not found.
+ */
+ static std::shared_ptr<Applet> Get(Service::APT::AppletId id);
+
+ /**
+ * Handles a parameter from the application.
+ * @param parameter Parameter data to handle.
+ * @returns ResultCode Whether the operation was successful or not.
+ */
+ virtual ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) = 0;
+
+ /**
+ * Handles the Applet start event, triggered from the application.
+ * @param parameter Parameter data to handle.
+ * @returns ResultCode Whether the operation was successful or not.
+ */
+ ResultCode Start(const Service::APT::AppletStartupParameter& parameter);
+
+ /**
+ * Whether the applet is currently executing instead of the host application or not.
+ */
+ virtual bool IsRunning() const = 0;
+
+ /**
+ * Handles an update tick for the Applet, lets it update the screen, send commands, etc.
+ */
+ virtual void Update() = 0;
+
+protected:
+ /**
+ * Handles the Applet start event, triggered from the application.
+ * @param parameter Parameter data to handle.
+ * @returns ResultCode Whether the operation was successful or not.
+ */
+ virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0;
+
+ Service::APT::AppletId id; ///< Id of this Applet
+};
+
+/// Initializes the HLE applets
+void Init();
+
+/// Shuts down the HLE applets
+void Shutdown();
+
+}
+} // namespace
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp
new file mode 100644
index 00000000..1db6b5a1
--- /dev/null
+++ b/src/core/hle/applets/swkbd.cpp
@@ -0,0 +1,113 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <cstring>
+#include <string>
+
+#include "common/assert.h"
+#include "common/logging/log.h"
+#include "common/string_util.h"
+
+#include "core/hle/applets/swkbd.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/service/hid/hid.h"
+#include "core/hle/service/gsp_gpu.h"
+#include "core/hle/result.h"
+#include "core/memory.h"
+
+#include "video_core/video_core.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace HLE {
+namespace Applets {
+
+SoftwareKeyboard::SoftwareKeyboard(Service::APT::AppletId id) : Applet(id), started(false) {
+ // Create the SharedMemory that will hold the framebuffer data
+ // TODO(Subv): What size should we use here?
+ using Kernel::MemoryPermission;
+ framebuffer_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "SoftwareKeyboard Memory");
+}
+
+ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) {
+ if (parameter.signal != static_cast<u32>(Service::APT::SignalType::LibAppJustStarted)) {
+ LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal);
+ UNIMPLEMENTED();
+ // TODO(Subv): Find the right error code
+ return ResultCode(-1);
+ }
+
+ Service::APT::MessageParameter result;
+ // The buffer passed in parameter contains the data returned by GSPGPU::ImportDisplayCaptureInfo
+ result.signal = static_cast<u32>(Service::APT::SignalType::LibAppFinished);
+ result.data = nullptr;
+ result.buffer_size = 0;
+ result.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
+ result.sender_id = static_cast<u32>(id);
+ result.object = framebuffer_memory;
+
+ Service::APT::SendParameter(result);
+ return RESULT_SUCCESS;
+}
+
+ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter const& parameter) {
+ ASSERT_MSG(parameter.buffer_size == sizeof(config), "The size of the parameter (SoftwareKeyboardConfig) is wrong");
+
+ memcpy(&config, parameter.data, parameter.buffer_size);
+ text_memory = boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object);
+
+ // TODO(Subv): Verify if this is the correct behavior
+ memset(text_memory->GetPointer(), 0, text_memory->size);
+
+ DrawScreenKeyboard();
+
+ started = true;
+ return RESULT_SUCCESS;
+}
+
+void SoftwareKeyboard::Update() {
+ // TODO(Subv): Handle input using the touch events from the HID module
+
+ // TODO(Subv): Remove this hardcoded text
+ std::u16string text = Common::UTF8ToUTF16("Citra");
+ memcpy(text_memory->GetPointer(), text.c_str(), text.length() * sizeof(char16_t));
+
+ // TODO(Subv): Ask for input and write it to the shared memory
+ // TODO(Subv): Find out what are the possible values for the return code,
+ // some games seem to check for a hardcoded 2
+ config.return_code = 2;
+ config.text_length = 6;
+ config.text_offset = 0;
+
+ // TODO(Subv): We're finalizing the applet immediately after it's started,
+ // but we should defer this call until after all the input has been collected.
+ Finalize();
+}
+
+void SoftwareKeyboard::DrawScreenKeyboard() {
+ auto bottom_screen = GSP_GPU::GetFrameBufferInfo(0, 1);
+ auto info = bottom_screen->framebuffer_info[bottom_screen->index];
+
+ // TODO(Subv): Draw the HLE keyboard, for now just zero-fill the framebuffer
+ memset(Memory::GetPointer(info.address_left), 0, info.stride * 320);
+
+ GSP_GPU::SetBufferSwap(1, info);
+}
+
+void SoftwareKeyboard::Finalize() {
+ // Let the application know that we're closing
+ Service::APT::MessageParameter message;
+ message.buffer_size = sizeof(SoftwareKeyboardConfig);
+ message.data = reinterpret_cast<u8*>(&config);
+ message.signal = static_cast<u32>(Service::APT::SignalType::LibAppClosed);
+ message.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
+ message.sender_id = static_cast<u32>(id);
+ Service::APT::SendParameter(message);
+
+ started = false;
+}
+
+}
+} // namespace
diff --git a/src/core/hle/applets/swkbd.h b/src/core/hle/applets/swkbd.h
new file mode 100644
index 00000000..cb95b8d9
--- /dev/null
+++ b/src/core/hle/applets/swkbd.h
@@ -0,0 +1,90 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+#include "common/common_funcs.h"
+
+#include "core/hle/applets/applet.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/result.h"
+#include "core/hle/service/apt/apt.h"
+
+namespace HLE {
+namespace Applets {
+
+struct SoftwareKeyboardConfig {
+ INSERT_PADDING_WORDS(0x8);
+
+ u16 max_text_length; ///< Maximum length of the input text
+
+ INSERT_PADDING_BYTES(0x6E);
+
+ char16_t display_text[65]; ///< Text to display when asking the user for input
+
+ INSERT_PADDING_BYTES(0xE);
+
+ u32 default_text_offset; ///< Offset of the default text in the output SharedMemory
+
+ INSERT_PADDING_WORDS(0x3);
+
+ u32 shared_memory_size; ///< Size of the SharedMemory
+
+ INSERT_PADDING_WORDS(0x1);
+
+ u32 return_code; ///< Return code of the SoftwareKeyboard, usually 2, other values are unknown
+
+ INSERT_PADDING_WORDS(0x2);
+
+ u32 text_offset; ///< Offset in the SharedMemory where the output text starts
+ u16 text_length; ///< Length in characters of the output text
+
+ INSERT_PADDING_BYTES(0x2B6);
+};
+
+/**
+ * The size of this structure (0x400) has been verified via reverse engineering of multiple games
+ * that use the software keyboard.
+ */
+static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config size is wrong");
+
+class SoftwareKeyboard final : public Applet {
+public:
+ SoftwareKeyboard(Service::APT::AppletId id);
+ ~SoftwareKeyboard() {}
+
+ ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
+ ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
+ void Update() override;
+ bool IsRunning() const override { return started; }
+
+ /**
+ * Draws a keyboard to the current bottom screen framebuffer.
+ */
+ void DrawScreenKeyboard();
+
+ /**
+ * Sends the LibAppletClosing signal to the application,
+ * along with the relevant data buffers.
+ */
+ void Finalize();
+
+ /// TODO(Subv): Find out what this is actually used for.
+ /// It is believed that the application stores the current screen image here.
+ Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
+
+ /// SharedMemory where the output text will be stored
+ Kernel::SharedPtr<Kernel::SharedMemory> text_memory;
+
+ /// Configuration of this instance of the SoftwareKeyboard, as received from the application
+ SoftwareKeyboardConfig config;
+
+ /// Whether this applet is currently running instead of the host application or not.
+ bool started;
+};
+
+}
+} // namespace
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 5949cb47..1a051892 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() {
}
}
-template<ResultCode func(void*, void*, u32)> void Wrap(){
- FuncReturn(func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2)).raw);
+template<ResultCode func(MemoryInfo*, PageInfo*, u32)> void Wrap() {
+ MemoryInfo memory_info = {};
+ PageInfo page_info = {};
+ u32 retval = func(&memory_info, &page_info, PARAM(2)).raw;
+ Core::g_app_core->SetReg(1, memory_info.base_address);
+ Core::g_app_core->SetReg(2, memory_info.size);
+ Core::g_app_core->SetReg(3, memory_info.permission);
+ Core::g_app_core->SetReg(4, memory_info.state);
+ Core::g_app_core->SetReg(5, page_info.flags);
+ FuncReturn(retval);
+}
+
+template<ResultCode func(MemoryInfo*, PageInfo*, Handle, u32)> void Wrap() {
+ MemoryInfo memory_info = {};
+ PageInfo page_info = {};
+ u32 retval = func(&memory_info, &page_info, PARAM(2), PARAM(3)).raw;
+ Core::g_app_core->SetReg(1, memory_info.base_address);
+ Core::g_app_core->SetReg(2, memory_info.size);
+ Core::g_app_core->SetReg(3, memory_info.permission);
+ Core::g_app_core->SetReg(4, memory_info.state);
+ Core::g_app_core->SetReg(5, page_info.flags);
+ FuncReturn(retval);
}
template<ResultCode func(s32*, u32)> void Wrap(){
@@ -113,7 +133,7 @@ template<ResultCode func(u32)> void Wrap() {
FuncReturn(func(PARAM(0)).raw);
}
-template<ResultCode func(s64*, u32, u32*, s32)> void Wrap(){
+template<ResultCode func(s64*, u32, u32*, u32)> void Wrap(){
FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), (u32*)Memory::GetPointer(PARAM(2)),
(s32)PARAM(3)).raw);
}
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
index fdeb9a02..cd0a400d 100644
--- a/src/core/hle/hle.cpp
+++ b/src/core/hle/hle.cpp
@@ -10,7 +10,6 @@
#include "core/hle/hle.h"
#include "core/hle/config_mem.h"
#include "core/hle/shared_page.h"
-#include "core/hle/kernel/thread.h"
#include "core/hle/service/service.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index f338f326..53feebbc 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) {
SharedPtr<Event> evt(new Event);
evt->signaled = false;
- evt->reset_type = evt->intitial_reset_type = reset_type;
+ evt->reset_type = reset_type;
evt->name = std::move(name);
return evt;
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index fba960d2..89d40523 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -26,7 +26,6 @@ public:
static const HandleType HANDLE_TYPE = HandleType::Event;
HandleType GetHandleType() const override { return HANDLE_TYPE; }
- ResetType intitial_reset_type; ///< ResetType specified at Event initialization
ResetType reset_type; ///< Current ResetType
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 20e11da1..5711c040 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -7,8 +7,6 @@
#include "common/assert.h"
#include "common/logging/log.h"
-#include "core/arm/arm_interface.h"
-#include "core/core.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/process.h"
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 64595f75..4d4276f7 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -4,10 +4,11 @@
#pragma once
-#include <boost/intrusive_ptr.hpp>
+#include <boost/smart_ptr/intrusive_ptr.hpp>
+#include <algorithm>
#include <array>
-#include <memory>
+#include <cstddef>
#include <string>
#include <vector>
@@ -16,8 +17,6 @@
#include "core/hle/hle.h"
#include "core/hle/result.h"
-struct ApplicationInfo;
-
namespace Kernel {
class Thread;
@@ -48,6 +47,7 @@ enum class HandleType : u32 {
Semaphore = 10,
Timer = 11,
ResourceLimit = 12,
+ CodeSet = 13,
};
enum {
@@ -86,6 +86,7 @@ public:
case HandleType::Process:
case HandleType::AddressArbiter:
case HandleType::ResourceLimit:
+ case HandleType::CodeSet:
return false;
}
}
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index b0e75ba5..a7892c65 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -5,24 +5,39 @@
#include "common/assert.h"
#include "common/common_funcs.h"
#include "common/logging/log.h"
+#include "common/make_unique.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/vm_manager.h"
+#include "core/mem_map.h"
#include "core/memory.h"
namespace Kernel {
+SharedPtr<CodeSet> CodeSet::Create(std::string name, u64 program_id) {
+ SharedPtr<CodeSet> codeset(new CodeSet);
+
+ codeset->name = std::move(name);
+ codeset->program_id = program_id;
+
+ return codeset;
+}
+
+CodeSet::CodeSet() {}
+CodeSet::~CodeSet() {}
+
u32 Process::next_process_id;
-SharedPtr<Process> Process::Create(std::string name, u64 program_id) {
+SharedPtr<Process> Process::Create(SharedPtr<CodeSet> code_set) {
SharedPtr<Process> process(new Process);
- process->name = std::move(name);
- process->program_id = program_id;
-
+ process->codeset = std::move(code_set);
process->flags.raw = 0;
process->flags.memory_region = MemoryRegion::APPLICATION;
+ process->address_space = Common::make_unique<VMManager>();
+ Memory::InitLegacyAddressSpace(*process->address_space);
return process;
}
@@ -87,8 +102,19 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
}
}
-void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
- Kernel::SetupMainThread(entry_point, main_thread_priority);
+void Process::Run(s32 main_thread_priority, u32 stack_size) {
+ auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) {
+ auto vma = address_space->MapMemoryBlock(segment.addr, codeset->memory,
+ segment.offset, segment.size, memory_state).Unwrap();
+ address_space->Reprotect(vma, permissions);
+ };
+
+ MapSegment(codeset->code, VMAPermission::ReadExecute, MemoryState::Code);
+ MapSegment(codeset->rodata, VMAPermission::Read, MemoryState::Code);
+ MapSegment(codeset->data, VMAPermission::ReadWrite, MemoryState::Private);
+
+ address_space->LogLayout();
+ Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority);
}
Kernel::Process::Process() {}
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 7b8a6861..83d3acea 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -5,6 +5,9 @@
#pragma once
#include <bitset>
+#include <cstddef>
+#include <memory>
+#include <string>
#include <boost/container/static_vector.hpp>
@@ -12,7 +15,6 @@
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/result.h"
namespace Kernel {
@@ -46,23 +48,51 @@ union ProcessFlags {
};
class ResourceLimit;
+class VMManager;
+
+struct CodeSet final : public Object {
+ static SharedPtr<CodeSet> Create(std::string name, u64 program_id);
+
+ std::string GetTypeName() const override { return "CodeSet"; }
+ std::string GetName() const override { return name; }
+
+ static const HandleType HANDLE_TYPE = HandleType::CodeSet;
+ HandleType GetHandleType() const override { return HANDLE_TYPE; }
+
+ /// Name of the process
+ std::string name;
+ /// Title ID corresponding to the process
+ u64 program_id;
+
+ std::shared_ptr<std::vector<u8>> memory;
+
+ struct Segment {
+ size_t offset = 0;
+ VAddr addr = 0;
+ u32 size = 0;
+ };
+
+ Segment code, rodata, data;
+ VAddr entrypoint;
+
+private:
+ CodeSet();
+ ~CodeSet() override;
+};
class Process final : public Object {
public:
- static SharedPtr<Process> Create(std::string name, u64 program_id);
+ static SharedPtr<Process> Create(SharedPtr<CodeSet> code_set);
std::string GetTypeName() const override { return "Process"; }
- std::string GetName() const override { return name; }
+ std::string GetName() const override { return codeset->name; }
static const HandleType HANDLE_TYPE = HandleType::Process;
HandleType GetHandleType() const override { return HANDLE_TYPE; }
static u32 next_process_id;
- /// Name of the process
- std::string name;
- /// Title ID corresponding to the process
- u64 program_id;
+ SharedPtr<CodeSet> codeset;
/// Resource limit descriptor for this process
SharedPtr<ResourceLimit> resource_limit;
@@ -80,6 +110,7 @@ public:
/// Bitmask of the used TLS slots
std::bitset<300> used_tls_slots;
+ std::unique_ptr<VMManager> address_space;
/**
* Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
@@ -90,7 +121,7 @@ public:
/**
* Applies address space changes and launches the process main thread.
*/
- void Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size);
+ void Run(s32 main_thread_priority, u32 stack_size);
private:
Process();
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index 257da910..adaffcaf 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -4,8 +4,14 @@
#pragma once
+#include <string>
+
+#include "common/assert.h"
+#include "common/common_types.h"
+
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/thread.h"
+#include "core/hle/result.h"
#include "core/memory.h"
namespace IPC {
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 20426689..7a292277 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -4,9 +4,12 @@
#pragma once
+#include <string>
+
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/result.h"
namespace Kernel {
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 4729a7fe..29ea6d53 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -13,7 +13,7 @@
#include "common/thread_queue_list.h"
#include "core/arm/arm_interface.h"
-#include "core/arm/skyeye_common/armdefs.h"
+#include "core/arm/skyeye_common/armstate.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/hle.h"
@@ -37,6 +37,10 @@ void Thread::Acquire() {
ASSERT_MSG(!ShouldWait(), "object unavailable!");
}
+// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing
+// us to simply use a pool index or similar.
+static Kernel::HandleTable wakeup_callback_handle_table;
+
// Lists all thread ids that aren't deleted/etc.
static std::vector<SharedPtr<Thread>> thread_list;
@@ -93,6 +97,8 @@ void Thread::Stop() {
// Cancel any outstanding wakeup events for this thread
CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
+ wakeup_callback_handle_table.Close(callback_handle);
+ callback_handle = 0;
// Clean up thread from ready queue
// This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
@@ -108,6 +114,7 @@ void Thread::Stop() {
for (auto& wait_object : wait_objects) {
wait_object->RemoveWaitingThread(this);
}
+ wait_objects.clear();
Kernel::g_current_process->used_tls_slots[tls_index] = false;
@@ -210,6 +217,14 @@ static void SwitchContext(Thread* new_thread) {
new_thread->context.pc -= thumb_mode ? 2 : 4;
}
+ // Clean up the thread's wait_objects, they'll be restored if needed during
+ // the svcWaitSynchronization call
+ for (int i = 0; i < new_thread->wait_objects.size(); ++i) {
+ SharedPtr<WaitObject> object = new_thread->wait_objects[i];
+ object->RemoveWaitingThread(new_thread);
+ }
+ new_thread->wait_objects.clear();
+
ready_queue.remove(new_thread->current_priority, new_thread);
new_thread->status = THREADSTATUS_RUNNING;
@@ -268,10 +283,6 @@ void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) {
thread->status = THREADSTATUS_WAIT_ARB;
}
-// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing
-// us to simply use a pool index or similar.
-static Kernel::HandleTable wakeup_callback_handle_table;
-
/**
* Callback that will wake up the thread it was scheduled for
* @param thread_handle The handle of the thread that's been awoken
@@ -503,12 +514,16 @@ void ThreadingInit() {
current_thread = nullptr;
next_thread_id = 1;
-
- thread_list.clear();
- ready_queue.clear();
}
void ThreadingShutdown() {
+ current_thread = nullptr;
+
+ for (auto& t : thread_list) {
+ t->Stop();
+ }
+ thread_list.clear();
+ ready_queue.clear();
}
} // namespace
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index b8160bb2..1ff1d9b9 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -13,6 +13,7 @@
#include "core/core.h"
+#include "core/hle/hle.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/result.h"
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index b2dd2154..205cc7b5 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <iterator>
+
#include "common/assert.h"
#include "core/hle/kernel/vm_manager.h"
@@ -33,6 +35,10 @@ VMManager::VMManager() {
Reset();
}
+VMManager::~VMManager() {
+ Reset();
+}
+
void VMManager::Reset() {
vma_map.clear();
@@ -128,6 +134,16 @@ void VMManager::Reprotect(VMAHandle vma_handle, VMAPermission new_perms) {
MergeAdjacent(iter);
}
+void VMManager::LogLayout() const {
+ for (const auto& p : vma_map) {
+ const VirtualMemoryArea& vma = p.second;
+ LOG_DEBUG(Kernel, "%08X - %08X size: %8X %c%c%c", vma.base, vma.base + vma.size, vma.size,
+ (u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-',
+ (u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-',
+ (u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-');
+ }
+}
+
VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) {
// This uses a neat C++ trick to convert a const_iterator to a regular iterator, given
// 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 22b72460..b3795a94 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -6,7 +6,6 @@
#include <map>
#include <memory>
-#include <string>
#include <vector>
#include "common/common_types.h"
@@ -102,7 +101,7 @@ struct VirtualMemoryArea {
* - http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/
* - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/
*/
-class VMManager {
+class VMManager final {
// TODO(yuriks): Make page tables switchable to support multiple VMManagers
public:
/**
@@ -122,6 +121,7 @@ public:
using VMAHandle = decltype(vma_map)::const_iterator;
VMManager();
+ ~VMManager();
/// Clears the address space map, re-initializing with a single free area.
void Reset();
@@ -169,6 +169,9 @@ public:
/// Changes the permissions of the given VMA.
void Reprotect(VMAHandle vma, VMAPermission new_perms);
+ /// Dumps the address space layout to the log, for debugging
+ void LogLayout() const;
+
private:
using VMAIter = decltype(vma_map)::iterator;
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index ce633d84..cb2d681e 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -4,7 +4,7 @@
#pragma once
-#include <cstddef>
+#include <new>
#include <type_traits>
#include <utility>
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 57dc1ece..7332478f 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) {
LOG_WARNING(Service_AM, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type);
}
+void GetNumContentInfos(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 1; // Number of content infos plus one
+
+ LOG_WARNING(Service_AM, "(STUBBED) called");
+}
+
void Init() {
using namespace Kernel;
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 063b8bd0..0b78f539 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);
*/
void GetTitleIDList(Service::Interface* self);
+/**
+ * AM::GetNumContentInfos service function
+ * Inputs:
+ * 0 : Command header (0x100100C0)
+ * 1 : Unknown
+ * 2 : Unknown
+ * 3 : Unknown
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ * 2 : Number of content infos plus one
+ */
+void GetNumContentInfos(Service::Interface* self);
+
/// Initialize AM service
void Init();
diff --git a/src/core/hle/service/am/am_app.cpp b/src/core/hle/service/am/am_app.cpp
index c6fc81bc..f40a87cb 100644
--- a/src/core/hle/service/am/am_app.cpp
+++ b/src/core/hle/service/am/am_app.cpp
@@ -9,11 +9,19 @@
namespace Service {
namespace AM {
-// Empty arrays are illegal -- commented out until an entry is added.
-//const Interface::FunctionInfo FunctionTable[] = { };
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x100100C0, GetNumContentInfos, "GetNumContentInfos"},
+ {0x10020104, nullptr, "FindContentInfos"},
+ {0x10030142, nullptr, "ListContentInfos"},
+ {0x10040102, nullptr, "DeleteContents"},
+ {0x10050084, nullptr, "GetDataTitleInfos"},
+ {0x10070102, nullptr, "ListDataTitleTicketInfos"},
+ {0x100900C0, nullptr, "IsDataTitleInUse"},
+ {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"},
+};
AM_APP_Interface::AM_APP_Interface() {
- //Register(FunctionTable);
+ Register(FunctionTable);
}
} // namespace AM
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index b454a270..7b6ab4ce 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -6,6 +6,7 @@
#include "common/file_util.h"
#include "common/logging/log.h"
+#include "core/hle/applets/applet.h"
#include "core/hle/service/service.h"
#include "core/hle/service/apt/apt.h"
#include "core/hle/service/apt/apt_a.h"
@@ -34,12 +35,21 @@ static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
static Kernel::SharedPtr<Kernel::Mutex> lock;
static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
-static Kernel::SharedPtr<Kernel::Event> start_event; ///< APT start event
+static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
static std::vector<u8> shared_font;
static u32 cpu_percent; ///< CPU time available to the running application
+/// Parameter data to be returned in the next call to Glance/ReceiveParameter
+static MessageParameter next_parameter;
+
+void SendParameter(const MessageParameter& parameter) {
+ next_parameter = parameter;
+ // Signal the event to let the application know that a new parameter is ready to be read
+ parameter_event->Signal();
+}
+
void Initialize(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 app_id = cmd_buff[1];
@@ -47,18 +57,18 @@ void Initialize(Service::Interface* self) {
cmd_buff[2] = IPC::MoveHandleDesc(2);
cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom();
- cmd_buff[4] = Kernel::g_handle_table.Create(start_event).MoveFrom();
+ cmd_buff[4] = Kernel::g_handle_table.Create(parameter_event).MoveFrom();
// TODO(bunnei): Check if these events are cleared every time Initialize is called.
notification_event->Clear();
- start_event->Clear();
+ parameter_event->Clear();
ASSERT_MSG((nullptr != lock), "Cannot initialize without lock");
lock->Release();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- LOG_TRACE(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags);
+ LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags);
}
void GetSharedFont(Service::Interface* self) {
@@ -85,9 +95,6 @@ void GetSharedFont(Service::Interface* self) {
void NotifyToWait(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 app_id = cmd_buff[1];
- // TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further.
- start_event->Signal();
-
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id);
}
@@ -100,7 +107,7 @@ void GetLockHandle(Service::Interface* self) {
// Not sure what these parameters are used for, but retail apps check that they are 0 after
// GetLockHandle has been called.
- cmd_buff[2] = 0;
+ cmd_buff[2] = 0; // Applet Attributes, this value is passed to Enable.
cmd_buff[3] = 0;
cmd_buff[4] = 0;
@@ -110,9 +117,10 @@ void GetLockHandle(Service::Interface* self) {
void Enable(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for?
+ u32 attributes = cmd_buff[1];
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk);
+ parameter_event->Signal(); // Let the application know that it has been started
+ LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes);
}
void GetAppletManInfo(Service::Interface* self) {
@@ -121,8 +129,8 @@ void GetAppletManInfo(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = 0;
cmd_buff[3] = 0;
- cmd_buff[4] = static_cast<u32>(AppID::HomeMenu); // Home menu AppID
- cmd_buff[5] = static_cast<u32>(AppID::Application); // TODO(purpasmart96): Do this correctly
+ cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID
+ cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly
LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk);
}
@@ -131,7 +139,13 @@ void IsRegistered(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 app_id = cmd_buff[1];
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- cmd_buff[2] = 1; // Set to registered
+ /// TODO(Subv): It is currently unknown what this value (0x400) means,
+ /// but i believe it is used as a global "LibraryApplet" id, to verify if there's
+ /// any LibApplet currently running. This is not verified.
+ if (app_id != 0x400)
+ cmd_buff[2] = 1; // Set to registered
+ else
+ cmd_buff[2] = 0; // Set to not registered
LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id);
}
@@ -145,50 +159,82 @@ void InquireNotification(Service::Interface* self) {
void SendParameter(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 src_app_id = cmd_buff[1];
- u32 dst_app_id = cmd_buff[2];
- u32 signal_type = cmd_buff[3];
- u32 buffer_size = cmd_buff[4];
- u32 value = cmd_buff[5];
- u32 handle = cmd_buff[6];
- u32 size = cmd_buff[7];
- u32 in_param_buffer_ptr = cmd_buff[8];
+ u32 src_app_id = cmd_buff[1];
+ u32 dst_app_id = cmd_buff[2];
+ u32 signal_type = cmd_buff[3];
+ u32 buffer_size = cmd_buff[4];
+ u32 value = cmd_buff[5];
+ u32 handle = cmd_buff[6];
+ u32 size = cmd_buff[7];
+ u32 buffer = cmd_buff[8];
+
+ std::shared_ptr<HLE::Applets::Applet> dest_applet = HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id));
+
+ if (dest_applet == nullptr) {
+ LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id);
+ cmd_buff[1] = -1; // TODO(Subv): Find the right error code
+ return;
+ }
- cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+ MessageParameter param;
+ param.buffer_size = buffer_size;
+ param.destination_id = dst_app_id;
+ param.sender_id = src_app_id;
+ param.object = Kernel::g_handle_table.GetGeneric(handle);
+ param.signal = signal_type;
+ param.data = Memory::GetPointer(buffer);
+
+ cmd_buff[1] = dest_applet->ReceiveParameter(param).raw;
LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
"buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X",
- src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, in_param_buffer_ptr);
+ src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer);
}
void ReceiveParameter(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 app_id = cmd_buff[1];
u32 buffer_size = cmd_buff[2];
+ VAddr buffer = cmd_buff[0x104 >> 2];
+
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- cmd_buff[2] = 0;
- cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
- cmd_buff[4] = 0x10; // Parameter buffer size (16)
- cmd_buff[5] = 0;
+ cmd_buff[2] = next_parameter.sender_id;
+ cmd_buff[3] = next_parameter.signal; // Signal type
+ cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
+ cmd_buff[5] = 0x10;
cmd_buff[6] = 0;
- cmd_buff[7] = 0;
- LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
+ if (next_parameter.object != nullptr)
+ cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
+ cmd_buff[7] = (next_parameter.buffer_size << 14) | 2;
+ cmd_buff[8] = buffer;
+
+ if (next_parameter.data)
+ memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size));
+
+ LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
}
void GlanceParameter(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 app_id = cmd_buff[1];
u32 buffer_size = cmd_buff[2];
+ VAddr buffer = cmd_buff[0x104 >> 2];
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- cmd_buff[2] = 0;
- cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type
- cmd_buff[4] = 0x10; // Parameter buffer size (16)
- cmd_buff[5] = 0;
+ cmd_buff[2] = next_parameter.sender_id;
+ cmd_buff[3] = next_parameter.signal; // Signal type
+ cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
+ cmd_buff[5] = 0x10;
cmd_buff[6] = 0;
- cmd_buff[7] = 0;
+ if (next_parameter.object != nullptr)
+ cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
+ cmd_buff[7] = (next_parameter.buffer_size << 14) | 2;
+ cmd_buff[8] = buffer;
- LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
+ if (next_parameter.data)
+ memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size));
+
+ LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
}
void CancelParameter(Service::Interface* self) {
@@ -240,7 +286,7 @@ void AppletUtility(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
// These are from 3dbrew - I'm not really sure what they're used for.
- u32 unk = cmd_buff[1];
+ u32 command = cmd_buff[1];
u32 buffer1_size = cmd_buff[2];
u32 buffer2_size = cmd_buff[3];
u32 buffer1_addr = cmd_buff[5];
@@ -248,8 +294,8 @@ void AppletUtility(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, "
- "buffer1_addr=0x%08X, buffer2_addr=0x%08X", unk, buffer1_size, buffer2_size,
+ LOG_WARNING(Service_APT, "(STUBBED) called command=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, "
+ "buffer1_addr=0x%08X, buffer2_addr=0x%08X", command, buffer1_size, buffer2_size,
buffer1_addr, buffer2_addr);
}
@@ -281,11 +327,41 @@ void GetAppCpuTimeLimit(Service::Interface* self) {
LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value);
}
+void PrepareToStartLibraryApplet(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
+ cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw;
+ LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
+}
+
+void StartLibraryApplet(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
+ std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(applet_id);
+
+ LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
+
+ if (applet == nullptr) {
+ LOG_ERROR(Service_APT, "unknown applet id=%08X", applet_id);
+ cmd_buff[1] = -1; // TODO(Subv): Find the right error code
+ return;
+ }
+
+ AppletStartupParameter parameter;
+ parameter.buffer_size = cmd_buff[2];
+ parameter.object = Kernel::g_handle_table.GetGeneric(cmd_buff[4]);
+ parameter.data = Memory::GetPointer(cmd_buff[6]);
+
+ cmd_buff[1] = applet->Start(parameter).raw;
+}
+
void Init() {
AddService(new APT_A_Interface);
AddService(new APT_S_Interface);
AddService(new APT_U_Interface);
+ HLE::Applets::Init();
+
// Load the shared system font (if available).
// The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header
// 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() {
// TODO(bunnei): Check if these are created in Initialize or on APT process startup.
notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification");
- start_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start");
+ parameter_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start");
+
+ next_parameter.signal = static_cast<u32>(SignalType::AppJustStarted);
+ next_parameter.destination_id = 0x300;
}
void Shutdown() {
@@ -326,7 +405,11 @@ void Shutdown() {
shared_font_mem = nullptr;
lock = nullptr;
notification_event = nullptr;
- start_event = nullptr;
+ parameter_event = nullptr;
+
+ next_parameter.object = nullptr;
+
+ HLE::Applets::Shutdown();
}
} // namespace APT
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index a03e1712..72972d05 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -4,13 +4,33 @@
#pragma once
-#include <array>
-#include "core/hle/result.h"
-#include "core/hle/service/service.h"
+#include "common/common_types.h"
+
+#include "core/hle/kernel/kernel.h"
namespace Service {
+
+class Interface;
+
namespace APT {
+/// Holds information about the parameters used in Send/Glance/ReceiveParameter
+struct MessageParameter {
+ u32 sender_id = 0;
+ u32 destination_id = 0;
+ u32 signal = 0;
+ u32 buffer_size = 0;
+ Kernel::SharedPtr<Kernel::Object> object = nullptr;
+ u8* data = nullptr;
+};
+
+/// Holds information about the parameters used in StartLibraryApplet
+struct AppletStartupParameter {
+ u32 buffer_size = 0;
+ Kernel::SharedPtr<Kernel::Object> object = nullptr;
+ u8* data = nullptr;
+};
+
/// Signals used by APT functions
enum class SignalType : u32 {
None = 0x0,
@@ -23,7 +43,7 @@ enum class SignalType : u32 {
};
/// App Id's used by APT functions
-enum class AppID : u32 {
+enum class AppletId : u32 {
HomeMenu = 0x101,
AlternateMenu = 0x103,
Camera = 0x110,
@@ -45,6 +65,9 @@ enum class AppID : u32 {
SoftwareKeyboard2 = 0x401,
};
+/// Send a parameter to the currently-running application, which will read it via ReceiveParameter
+void SendParameter(const MessageParameter& parameter);
+
/**
* APT::Initialize service function
* Service function that initializes the APT process for the running application
@@ -249,6 +272,33 @@ void SetAppCpuTimeLimit(Service::Interface* self);
*/
void GetAppCpuTimeLimit(Service::Interface* self);
+/**
+ * APT::PrepareToStartLibraryApplet service function
+ * Inputs:
+ * 0 : Command header [0x00180040]
+ * 1 : Id of the applet to start
+ * Outputs:
+ * 0 : Return header
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+void PrepareToStartLibraryApplet(Service::Interface* self);
+
+/**
+ * APT::StartLibraryApplet service function
+ * Inputs:
+ * 0 : Command header [0x001E0084]
+ * 1 : Id of the applet to start
+ * 2 : Buffer size
+ * 3 : Always 0?
+ * 4 : Handle passed to the applet
+ * 5 : (Size << 14) | 2
+ * 6 : Input buffer virtual address
+ * Outputs:
+ * 0 : Return header
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+void StartLibraryApplet(Service::Interface* self);
+
/// Initialize the APT service
void Init();
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp
index 86493424..88de339f 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 {
namespace APT {
const Interface::FunctionInfo FunctionTable[] = {
- {0x00010040, GetLockHandle, "GetLockHandle?"},
- {0x00020080, Initialize, "Initialize?"},
- {0x00030040, Enable, "Enable?"},
- {0x00040040, nullptr, "Finalize?"},
- {0x00050040, nullptr, "GetAppletManInfo?"},
- {0x00060040, nullptr, "GetAppletInfo?"},
- {0x000D0080, ReceiveParameter, "ReceiveParameter?"},
- {0x000E0080, GlanceParameter, "GlanceParameter?"},
- {0x003B0040, nullptr, "CancelLibraryApplet?"},
- {0x00430040, NotifyToWait, "NotifyToWait?"},
- {0x00440000, GetSharedFont, "GetSharedFont?"},
- {0x004B00C2, AppletUtility, "AppletUtility?"},
- {0x00550040, nullptr, "WriteInputToNsState?"},
+ {0x00010040, GetLockHandle, "GetLockHandle?"},
+ {0x00020080, Initialize, "Initialize?"},
+ {0x00030040, Enable, "Enable?"},
+ {0x00040040, nullptr, "Finalize?"},
+ {0x00050040, nullptr, "GetAppletManInfo?"},
+ {0x00060040, nullptr, "GetAppletInfo?"},
+ {0x00090040, IsRegistered, "IsRegistered"},
+ {0x000C0104, SendParameter, "SendParameter"},
+ {0x000D0080, ReceiveParameter, "ReceiveParameter"},
+ {0x000E0080, GlanceParameter, "GlanceParameter"},
+ {0x000F0100, CancelParameter, "CancelParameter"},
+ {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
+ {0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
+ {0x003B0040, nullptr, "CancelLibraryApplet?"},
+ {0x00430040, NotifyToWait, "NotifyToWait?"},
+ {0x00440000, GetSharedFont, "GetSharedFont?"},
+ {0x004B00C2, AppletUtility, "AppletUtility?"},
+ {0x00550040, nullptr, "WriteInputToNsState?"},
};
APT_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 d006b593..b724cd72 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[] = {
{0x00150140, nullptr, "PrepareToStartApplication"},
{0x00160040, nullptr, "PreloadLibraryApplet"},
{0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
- {0x00180040, nullptr, "PrepareToStartLibraryApplet"},
+ {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
{0x00190040, nullptr, "PrepareToStartSystemApplet"},
{0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
{0x001B00C4, nullptr, "StartApplication"},
{0x001C0000, nullptr, "WakeupApplication"},
{0x001D0000, nullptr, "CancelApplication"},
- {0x001E0084, nullptr, "StartLibraryApplet"},
+ {0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
{0x001F0084, nullptr, "StartSystemApplet"},
{0x00200044, nullptr, "StartNewestHomeMenu"},
{0x00210000, nullptr, "OrderToCloseApplication"},
diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp
index af4adba8..a329514a 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 {
const Interface::FunctionInfo FunctionTable[] = {
{0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"},
- {0x00020000, nullptr, "SecureInfoGetRegion"},
+ {0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"},
+ {0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"},
+ {0x00050000, GetSystemModel, "GetSystemModel"},
{0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
{0x04020082, nullptr, "SetConfigInfoBlk4"},
{0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index fafb43a2..a8cb15d6 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -310,4 +310,9 @@ Interface::Interface() {
Register(FunctionTable);
}
+Interface::~Interface() {
+ semaphore_event = nullptr;
+ interrupt_event = nullptr;
+}
+
} // namespace
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h
index fa13bfb7..b6f611db 100644
--- a/src/core/hle/service/dsp_dsp.h
+++ b/src/core/hle/service/dsp_dsp.h
@@ -4,6 +4,8 @@
#pragma once
+#include <string>
+
#include "core/hle/service/service.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -14,6 +16,7 @@ namespace DSP_DSP {
class Interface : public Service::Interface {
public:
Interface();
+ ~Interface() override;
std::string GetPortName() const override {
return "dsp::DSP";
diff --git a/src/core/hle/service/frd/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp
index 439c7282..3a5897d0 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 {
namespace FRD {
const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010000, nullptr, "HasLoggedIn"},
+ {0x00030000, nullptr, "Login"},
+ {0x00040000, nullptr, "Logout"},
{0x00050000, nullptr, "GetFriendKey"},
{0x00080000, nullptr, "GetMyPresence"},
+ {0x00090000, nullptr, "GetMyScreenName"},
{0x00100040, nullptr, "GetPassword"},
+ {0x00110080, nullptr, "GetFriendKeyList"},
{0x00190042, nullptr, "GetFriendFavoriteGame"},
{0x001A00C4, nullptr, "GetFriendInfo"},
{0x001B0080, nullptr, "IsOnFriendList"},
{0x001C0042, nullptr, "DecodeLocalFriendCode"},
{0x001D0002, nullptr, "SetCurrentlyPlayingText"},
- {0x00320042, nullptr, "SetClientSdkVersion"}
+ {0x00230000, nullptr, "GetLastResponseResult"},
+ {0x00270040, nullptr, "ResultToErrorCode"},
+ {0x00280244, nullptr, "RequestGameAuthentication"},
+ {0x00290000, nullptr, "GetGameAuthenticationData"},
+ {0x002A0204, nullptr, "RequestServiceLocator"},
+ {0x002B0000, nullptr, "GetServiceLocatorData"},
+ {0x00320042, nullptr, "SetClientSdkVersion"},
};
FRD_U_Interface::FRD_U_Interface() {
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index 4e275cb1..6c0df67c 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -2,29 +2,35 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstddef>
+#include <system_error>
+#include <type_traits>
#include <memory>
#include <unordered_map>
+#include <utility>
#include <boost/container/flat_map.hpp>
+#include "common/assert.h"
#include "common/common_types.h"
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/make_unique.h"
-#include "common/math_util.h"
#include "core/file_sys/archive_backend.h"
#include "core/file_sys/archive_extsavedata.h"
-#include "core/file_sys/archive_romfs.h"
#include "core/file_sys/archive_savedata.h"
#include "core/file_sys/archive_savedatacheck.h"
#include "core/file_sys/archive_sdmc.h"
#include "core/file_sys/archive_systemsavedata.h"
#include "core/file_sys/directory_backend.h"
+#include "core/file_sys/file_backend.h"
+#include "core/hle/hle.h"
#include "core/hle/service/service.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/fs/fs_user.h"
#include "core/hle/result.h"
+#include "core/memory.h"
// Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map.
// Workaroung for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970
@@ -110,7 +116,7 @@ ResultVal<bool> File::SyncRequest() {
u32 address = cmd_buff[6];
LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
- cmd_buff[2] = static_cast<u32>(backend->Write(offset, length, flush, Memory::GetPointer(address)));
+ cmd_buff[2] = static_cast<u32>(backend->Write(offset, length, flush != 0, Memory::GetPointer(address)));
break;
}
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index 357b6b09..f6112595 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -4,22 +4,25 @@
#pragma once
+#include <memory>
+#include <string>
+
#include "common/common_types.h"
#include "core/file_sys/archive_backend.h"
-#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/session.h"
#include "core/hle/result.h"
+namespace FileSys {
+class DirectoryBackend;
+class FileBackend;
+}
+
/// The unique system identifier hash, also known as ID0
extern const std::string SYSTEM_ID;
/// The scrambled SD card CID, also known as ID1
extern const std::string SDCARD_ID;
-namespace Kernel {
- class Session;
-}
-
namespace Service {
namespace FS {
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index 0ad44e55..ae52083f 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) {
ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path);
if (archive_handle.Failed()) {
- LOG_ERROR(Service_FS, "failed to get a handle for archive");
+ LOG_ERROR(Service_FS, "failed to get a handle for archive archive_id=0x%08X archive_path=%s",
+ archive_id, archive_path.DebugStr().c_str());
cmd_buff[1] = archive_handle.Code().raw;
cmd_buff[3] = 0;
return;
@@ -128,7 +129,8 @@ static void OpenFileDirectly(Service::Interface* self) {
cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom();
} else {
cmd_buff[3] = 0;
- LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str());
+ LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%d",
+ file_path.DebugStr().c_str(), mode.hex, attributes);
}
}
@@ -347,7 +349,8 @@ static void OpenDirectory(Service::Interface* self) {
if (dir_res.Succeeded()) {
cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom();
} else {
- LOG_ERROR(Service_FS, "failed to get a handle for directory");
+ LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s",
+ dirname_type, dirname_size, dir_path.DebugStr().c_str());
}
}
@@ -382,7 +385,8 @@ static void OpenArchive(Service::Interface* self) {
cmd_buff[3] = (*handle >> 32) & 0xFFFFFFFF;
} else {
cmd_buff[2] = cmd_buff[3] = 0;
- LOG_ERROR(Service_FS, "failed to get a handle for archive");
+ LOG_ERROR(Service_FS, "failed to get a handle for archive archive_id=0x%08X archive_path=%s",
+ archive_id, archive_path.DebugStr().c_str());
}
}
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 4b0b4229..e93c1b43 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -9,14 +9,17 @@
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/result.h"
-#include "gsp_gpu.h"
#include "core/hw/hw.h"
#include "core/hw/gpu.h"
#include "core/hw/lcd.h"
#include "video_core/gpu_debugger.h"
+#include "video_core/debug_utils/debug_utils.h"
+#include "video_core/renderer_base.h"
#include "video_core/video_core.h"
+#include "gsp_gpu.h"
+
// Main graphics debugger object - TODO: Here is probably not the best place for this
GraphicsDebugger g_debugger;
@@ -40,7 +43,7 @@ static inline u8* GetCommandBuffer(u32 thread_id) {
return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer)));
}
-static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) {
+FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) {
DEBUG_ASSERT_MSG(screen_index < 2, "Invalid screen index");
// For each thread there are two FrameBufferUpdate fields
@@ -203,7 +206,7 @@ static void ReadHWRegs(Service::Interface* self) {
}
}
-static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
+void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
u32 base_address = 0x400000;
PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left);
PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right);
@@ -224,6 +227,9 @@ static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
&info.format);
WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4,
&info.shown_fb);
+
+ if (Pica::g_debug_context)
+ Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr);
}
/**
@@ -347,7 +353,7 @@ void SignalInterrupt(InterruptId interrupt_id) {
/// Executes the next GSP command
static void ExecuteCommand(const Command& command, u32 thread_id) {
// Utility function to convert register ID to address
- auto WriteGPURegister = [](u32 id, u32 data) {
+ static auto WriteGPURegister = [](u32 id, u32 data) {
GPU::Write<u32>(0x1EF00000 + 4 * id, data);
};
@@ -389,19 +395,24 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
case CommandId::SET_MEMORY_FILL:
{
auto& params = command.memory_fill;
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_start)),
- Memory::VirtualToPhysicalAddress(params.start1) >> 3);
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_end)),
- Memory::VirtualToPhysicalAddress(params.end1) >> 3);
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].value_32bit)), params.value1);
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].control)), params.control1);
-
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_start)),
- Memory::VirtualToPhysicalAddress(params.start2) >> 3);
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_end)),
- Memory::VirtualToPhysicalAddress(params.end2) >> 3);
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].value_32bit)), params.value2);
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].control)), params.control2);
+
+ if (params.start1 != 0) {
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_start)),
+ Memory::VirtualToPhysicalAddress(params.start1) >> 3);
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_end)),
+ Memory::VirtualToPhysicalAddress(params.end1) >> 3);
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].value_32bit)), params.value1);
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].control)), params.control1);
+ }
+
+ if (params.start2 != 0) {
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_start)),
+ Memory::VirtualToPhysicalAddress(params.start2) >> 3);
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_end)),
+ Memory::VirtualToPhysicalAddress(params.end2) >> 3);
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].value_32bit)), params.value2);
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].control)), params.control2);
+ }
break;
}
@@ -446,6 +457,9 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
default:
LOG_ERROR(Service_GSP, "unknown command 0x%08X", (int)command.id.Value());
}
+
+ if (Pica::g_debug_context)
+ Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::GSPCommandProcessed, (void*)&command);
}
/**
@@ -582,7 +596,7 @@ const Interface::FunctionInfo FunctionTable[] = {
Interface::Interface() {
Register(FunctionTable);
- g_interrupt_event = 0;
+ g_interrupt_event = nullptr;
using Kernel::MemoryPermission;
g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
@@ -591,4 +605,9 @@ Interface::Interface() {
g_thread_id = 0;
}
+Interface::~Interface() {
+ g_interrupt_event = nullptr;
+ g_shared_memory = nullptr;
+}
+
} // namespace
diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h
index a435d418..c89d0a46 100644
--- a/src/core/hle/service/gsp_gpu.h
+++ b/src/core/hle/service/gsp_gpu.h
@@ -5,8 +5,11 @@
#pragma once
#include <cstddef>
+#include <string>
#include "common/bit_field.h"
+#include "common/common_types.h"
+
#include "core/hle/service/service.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -158,6 +161,7 @@ static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrec
class Interface : public Service::Interface {
public:
Interface();
+ ~Interface() override;
std::string GetPortName() const override {
return "gsp::Gpu";
@@ -170,4 +174,14 @@ public:
*/
void SignalInterrupt(InterruptId interrupt_id);
+void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info);
+
+/**
+ * Retrieves the framebuffer info stored in the GSP shared memory for the
+ * specified screen index and thread id.
+ * @param thread_id GSP thread id of the process that accesses the structure that we are requesting.
+ * @param screen_index Index of the screen we are requesting (Top = 0, Bottom = 1).
+ * @returns FramebufferUpdate Information about the specified framebuffer.
+ */
+FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index);
} // namespace
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index c7c1bb5a..c35b13b2 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "common/logging/log.h"
+#include "common/emu_window.h"
#include "core/hle/service/service.h"
#include "core/hle/service/hid/hid.h"
@@ -34,6 +35,16 @@ static Kernel::SharedPtr<Kernel::Event> event_debug_pad;
static u32 next_pad_index;
static u32 next_touch_index;
+const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping = {
+ Service::HID::PAD_A, Service::HID::PAD_B, Service::HID::PAD_X, Service::HID::PAD_Y,
+ Service::HID::PAD_L, Service::HID::PAD_R, Service::HID::PAD_ZL, Service::HID::PAD_ZR,
+ Service::HID::PAD_START, Service::HID::PAD_SELECT, Service::HID::PAD_NONE,
+ Service::HID::PAD_UP, Service::HID::PAD_DOWN, Service::HID::PAD_LEFT, Service::HID::PAD_RIGHT,
+ Service::HID::PAD_CIRCLE_UP, Service::HID::PAD_CIRCLE_DOWN, Service::HID::PAD_CIRCLE_LEFT, Service::HID::PAD_CIRCLE_RIGHT,
+ Service::HID::PAD_C_UP, Service::HID::PAD_C_DOWN, Service::HID::PAD_C_LEFT, Service::HID::PAD_C_RIGHT
+};
+
+
// TODO(peachum):
// Add a method for setting analog input from joystick device for the circle Pad.
//
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 68e2bcee..517f4f2a 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -6,16 +6,18 @@
#include <array>
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/service/service.h"
+#ifndef _MSC_VER
+#include <cstddef>
+#endif
+#include "core/settings.h"
#include "common/bit_field.h"
-
-namespace Kernel {
- class SharedMemory;
- class Event;
-}
+#include "common/common_funcs.h"
+#include "common/common_types.h"
namespace Service {
+
+class Interface;
+
namespace HID {
/**
@@ -155,6 +157,9 @@ const PadState PAD_CIRCLE_LEFT = {{1u << 29}};
const PadState PAD_CIRCLE_UP = {{1u << 30}};
const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
+
+extern const std::array<Service::HID::PadState, Settings::NativeInput::NUM_INPUTS> pad_mapping;
+
/**
* HID::GetIPCHandles service function
* Inputs:
diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp
index 25b01860..18b22956 100644
--- a/src/core/hle/service/nwm_uds.cpp
+++ b/src/core/hle/service/nwm_uds.cpp
@@ -125,4 +125,8 @@ Interface::Interface() {
Register(FunctionTable);
}
+Interface::~Interface() {
+ handle_event = nullptr;
+}
+
} // namespace
diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h
index 82abdff2..0ced2359 100644
--- a/src/core/hle/service/nwm_uds.h
+++ b/src/core/hle/service/nwm_uds.h
@@ -16,6 +16,7 @@ namespace NWM_UDS {
class Interface : public Service::Interface {
public:
Interface();
+ ~Interface() override;
std::string GetPortName() const override {
return "nwm::UDS";
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index d681cc3d..0de0b13a 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
std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name);
for (int i = 1; i <= num_params; ++i) {
- function_string += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]);
+ function_string += Common::StringFromFormat(", cmd_buff[%i]=0x%X", i, cmd_buff[i]);
}
return function_string;
}
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 77bfb9ff..f3113521 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -4,6 +4,7 @@
#pragma once
+#include <cstddef>
#include <string>
#include <unordered_map>
@@ -11,8 +12,8 @@
#include "common/common_types.h"
-#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/session.h"
+#include "core/hle/result.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace Service
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index 3f0c5e38..d768a3fc 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -2,40 +2,47 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+#include <cstring>
+#include <unordered_map>
+
+#include "common/assert.h"
+#include "common/bit_field.h"
+#include "common/common_types.h"
#include "common/logging/log.h"
-#include "common/platform.h"
-
-#if EMU_PLATFORM == PLATFORM_WINDOWS
-#include <winsock2.h>
-#include <ws2tcpip.h>
-
-// MinGW does not define several errno constants
-#ifndef _MSC_VER
-#define EBADMSG 104
-#define ENODATA 120
-#define ENOMSG 122
-#define ENOSR 124
-#define ENOSTR 125
-#define ETIME 137
-#define EIDRM 2001
-#define ENOLINK 2002
-#endif // _MSC_VER
+#include "common/scope_exit.h"
+#include "core/hle/kernel/session.h"
+#include "core/hle/result.h"
+#include "core/hle/service/soc_u.h"
+#include "core/memory.h"
+
+#ifdef _WIN32
+ #include <winsock2.h>
+ #include <ws2tcpip.h>
+
+ // MinGW does not define several errno constants
+ #ifndef _MSC_VER
+ #define EBADMSG 104
+ #define ENODATA 120
+ #define ENOMSG 122
+ #define ENOSR 124
+ #define ENOSTR 125
+ #define ETIME 137
+ #define EIDRM 2001
+ #define ENOLINK 2002
+ #endif // _MSC_VER
#else
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <poll.h>
+ #include <cerrno>
+ #include <fcntl.h>
+ #include <netinet/in.h>
+ #include <netdb.h>
+ #include <poll.h>
+ #include <sys/socket.h>
+ #include <unistd.h>
#endif
-#include "common/scope_exit.h"
-#include "core/hle/hle.h"
-#include "core/hle/service/soc_u.h"
-#include <unordered_map>
-
-#if EMU_PLATFORM == PLATFORM_WINDOWS
+#ifdef _WIN32
# define WSAEAGAIN WSAEWOULDBLOCK
# define WSAEMULTIHOP -1 // Invalid dummy value
# define ERRNO(x) WSA##x
@@ -328,6 +335,7 @@ static void Socket(Service::Interface* self) {
if ((s32)socket_handle == SOCKET_ERROR_VALUE)
result = TranslateError(GET_ERRNO);
+ cmd_buffer[0] = IPC::MakeHeader(2, 2, 0);
cmd_buffer[1] = result;
cmd_buffer[2] = socket_handle;
}
@@ -351,8 +359,9 @@ static void Bind(Service::Interface* self) {
if (res != 0)
result = TranslateError(GET_ERRNO);
- cmd_buffer[2] = res;
+ cmd_buffer[0] = IPC::MakeHeader(5, 2, 0);
cmd_buffer[1] = result;
+ cmd_buffer[2] = res;
}
static void Fcntl(Service::Interface* self) {
@@ -369,7 +378,7 @@ static void Fcntl(Service::Interface* self) {
});
if (ctr_cmd == 3) { // F_GETFL
-#if EMU_PLATFORM == PLATFORM_WINDOWS
+#ifdef _WIN32
posix_ret = 0;
auto iter = open_sockets.find(socket_handle);
if (iter != open_sockets.end() && iter->second.blocking == false)
@@ -386,7 +395,7 @@ static void Fcntl(Service::Interface* self) {
posix_ret |= 4; // O_NONBLOCK
#endif
} else if (ctr_cmd == 4) { // F_SETFL
-#if EMU_PLATFORM == PLATFORM_WINDOWS
+#ifdef _WIN32
unsigned long tmp = (ctr_arg & 4 /* O_NONBLOCK */) ? 1 : 0;
int ret = ioctlsocket(socket_handle, FIONBIO, &tmp);
if (ret == SOCKET_ERROR_VALUE) {
@@ -434,8 +443,9 @@ static void Listen(Service::Interface* self) {
if (ret != 0)
result = TranslateError(GET_ERRNO);
- cmd_buffer[2] = ret;
+ cmd_buffer[0] = IPC::MakeHeader(3, 2, 0);
cmd_buffer[1] = result;
+ cmd_buffer[2] = ret;
}
static void Accept(Service::Interface* self) {
@@ -460,8 +470,10 @@ static void Accept(Service::Interface* self) {
Memory::WriteBlock(cmd_buffer[0x104 >> 2], (const u8*)&ctr_addr, max_addr_len);
}
- cmd_buffer[2] = ret;
+ cmd_buffer[0] = IPC::MakeHeader(4, 2, 2);
cmd_buffer[1] = result;
+ cmd_buffer[2] = ret;
+ cmd_buffer[3] = IPC::StaticBufferDesc(static_cast<u32>(max_addr_len), 0);
}
static void GetHostId(Service::Interface* self) {
@@ -675,26 +687,29 @@ static void Connect(Service::Interface* self) {
int result = 0;
if (ret != 0)
result = TranslateError(GET_ERRNO);
- cmd_buffer[2] = ret;
+
+ cmd_buffer[0] = IPC::MakeHeader(6, 2, 0);
cmd_buffer[1] = result;
+ cmd_buffer[2] = ret;
}
static void InitializeSockets(Service::Interface* self) {
// TODO(Subv): Implement
-#if EMU_PLATFORM == PLATFORM_WINDOWS
+#ifdef _WIN32
WSADATA data;
WSAStartup(MAKEWORD(2, 2), &data);
#endif
u32* cmd_buffer = Kernel::GetCommandBuffer();
- cmd_buffer[1] = 0;
+ cmd_buffer[0] = IPC::MakeHeader(1, 1, 0);
+ cmd_buffer[1] = RESULT_SUCCESS.raw;
}
static void ShutdownSockets(Service::Interface* self) {
// TODO(Subv): Implement
CleanupSockets();
-#if EMU_PLATFORM == PLATFORM_WINDOWS
+#ifdef _WIN32
WSACleanup();
#endif
@@ -745,7 +760,7 @@ Interface::Interface() {
Interface::~Interface() {
CleanupSockets();
-#if EMU_PLATFORM == PLATFORM_WINDOWS
+#ifdef _WIN32
WSACleanup();
#endif
}
diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h
index 483b3111..a091f597 100644
--- a/src/core/hle/service/soc_u.h
+++ b/src/core/hle/service/soc_u.h
@@ -4,6 +4,8 @@
#pragma once
+#include <string>
+
#include "core/hle/service/service.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index 6c49fa6c..3b8c7c0e 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -68,4 +68,8 @@ Interface::Interface() {
Register(FunctionTable);
}
+Interface::~Interface() {
+ event_handle = nullptr;
+}
+
} // namespace
diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h
index 653aba5c..96c89b02 100644
--- a/src/core/hle/service/srv.h
+++ b/src/core/hle/service/srv.h
@@ -13,6 +13,7 @@ namespace SRV {
class Interface : public Service::Interface {
public:
Interface();
+ ~Interface() override;
std::string GetPortName() const override {
return "srv:";
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp
index ac1967da..6e7dafaa 100644
--- a/src/core/hle/service/y2r_u.cpp
+++ b/src/core/hle/service/y2r_u.cpp
@@ -12,6 +12,7 @@
#include "core/hw/y2r.h"
#include "core/mem_map.h"
+#include "video_core/renderer_base.h"
#include "video_core/utils.h"
#include "video_core/video_core.h"
@@ -409,4 +410,8 @@ Interface::Interface() {
Register(FunctionTable);
}
+Interface::~Interface() {
+ completion_event = nullptr;
+}
+
} // namespace
diff --git a/src/core/hle/service/y2r_u.h b/src/core/hle/service/y2r_u.h
index 7df47fcb..3965a554 100644
--- a/src/core/hle/service/y2r_u.h
+++ b/src/core/hle/service/y2r_u.h
@@ -5,9 +5,11 @@
#pragma once
#include <array>
+#include <string>
#include "common/common_types.h"
+#include "core/hle/result.h"
#include "core/hle/service/service.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -110,6 +112,7 @@ struct ConversionConfiguration {
class Interface : public Service::Interface {
public:
Interface();
+ ~Interface() override;
std::string GetPortName() const override {
return "y2r:u";
diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp
index 4014eee9..26d87c7e 100644
--- a/src/core/hle/shared_page.cpp
+++ b/src/core/hle/shared_page.cpp
@@ -4,12 +4,6 @@
#include <cstring>
-#include "common/common_types.h"
-#include "common/common_funcs.h"
-
-#include "core/core.h"
-#include "core/memory.h"
-#include "core/hle/config_mem.h"
#include "core/hle/shared_page.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/shared_page.h b/src/core/hle/shared_page.h
index fd2ab66a..db6a5340 100644
--- a/src/core/hle/shared_page.h
+++ b/src/core/hle/shared_page.h
@@ -10,9 +10,12 @@
* write access, according to 3dbrew; this is not emulated)
*/
+#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
+#include "core/memory.h"
+
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace SharedPage {
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 6cde4fc8..bb64fdfb 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -22,6 +22,7 @@
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h"
+#include "core/hle/kernel/vm_manager.h"
#include "core/hle/function_wrappers.h"
#include "core/hle/result.h"
@@ -333,7 +334,7 @@ static ResultCode GetResourceLimit(Handle* resource_limit, Handle process_handle
/// Get resource limit current values
static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit_handle, u32* names,
- s32 name_count) {
+ u32 name_count) {
LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
resource_limit_handle, names, name_count);
@@ -349,7 +350,7 @@ static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_lim
/// Get resource limit max values
static ResultCode GetResourceLimitLimitValues(s64* values, Handle resource_limit_handle, u32* names,
- s32 name_count) {
+ u32 name_count) {
LOG_TRACE(Kernel_SVC, "called resource_limit=%08X, names=%p, name_count=%d",
resource_limit_handle, names, name_count);
@@ -529,12 +530,33 @@ static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count)
return RESULT_SUCCESS;
}
-/// Query memory
-static ResultCode QueryMemory(void* info, void* out, u32 addr) {
- LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr);
+/// Query process memory
+static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info, Handle process_handle, u32 addr) {
+ using Kernel::Process;
+ Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle);
+ if (process == nullptr)
+ return ERR_INVALID_HANDLE;
+
+ auto vma = process->address_space->FindVMA(addr);
+
+ if (vma == process->address_space->vma_map.end())
+ return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+
+ memory_info->base_address = vma->second.base;
+ memory_info->permission = static_cast<u32>(vma->second.permissions);
+ memory_info->size = vma->second.size;
+ memory_info->state = static_cast<u32>(vma->second.meminfo_state);
+
+ page_info->flags = 0;
+ LOG_TRACE(Kernel_SVC, "called process=0x%08X addr=0x%08X", process_handle, addr);
return RESULT_SUCCESS;
}
+/// Query memory
+static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32 addr) {
+ return QueryProcessMemory(memory_info, page_info, Kernel::CurrentProcess, addr);
+}
+
/// Create an event
static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) {
using Kernel::Event;
@@ -806,13 +828,12 @@ static const FunctionDef SVC_Table[] = {
{0x7A, nullptr, "AddCodeSegment"},
{0x7B, nullptr, "Backdoor"},
{0x7C, nullptr, "KernelSetState"},
- {0x7D, nullptr, "QueryProcessMemory"},
+ {0x7D, HLE::Wrap<QueryProcessMemory>, "QueryProcessMemory"},
};
Common::Profiling::TimingCategory profiler_svc("SVC Calls");
-static const FunctionDef* GetSVCInfo(u32 opcode) {
- u32 func_num = opcode & 0xFFFFFF; // 8 bits
+static const FunctionDef* GetSVCInfo(u32 func_num) {
if (func_num >= ARRAY_SIZE(SVC_Table)) {
LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num);
return nullptr;
@@ -820,10 +841,10 @@ static const FunctionDef* GetSVCInfo(u32 opcode) {
return &SVC_Table[func_num];
}
-void CallSVC(u32 opcode) {
+void CallSVC(u32 immediate) {
Common::Profiling::ScopeTimer timer_svc(profiler_svc);
- const FunctionDef *info = GetSVCInfo(opcode);
+ const FunctionDef* info = GetSVCInfo(immediate);
if (info) {
if (info->func) {
info->func();
diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h
index 4389aa73..12de9ffb 100644
--- a/src/core/hle/svc.h
+++ b/src/core/hle/svc.h
@@ -41,6 +41,6 @@ enum ArbitrationType {
namespace SVC {
-void CallSVC(u32 opcode);
+void CallSVC(u32 immediate);
} // namespace
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 7471def5..3ccbc03b 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -2,17 +2,18 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
+#include <type_traits>
+
#include "common/color.h"
#include "common/common_types.h"
-
-#include "core/arm/arm_interface.h"
+#include "common/logging/log.h"
+#include "common/vector_math.h"
#include "core/settings.h"
-#include "core/core.h"
#include "core/memory.h"
#include "core/core_timing.h"
-#include "core/hle/hle.h"
#include "core/hle/service/gsp_gpu.h"
#include "core/hle/service/dsp_dsp.h"
#include "core/hle/service/hid/hid.h"
@@ -20,10 +21,17 @@
#include "core/hw/hw.h"
#include "core/hw/gpu.h"
+#include "core/tracer/recorder.h"
+
#include "video_core/command_processor.h"
+#include "video_core/hwrasterizer_base.h"
+#include "video_core/renderer_base.h"
#include "video_core/utils.h"
#include "video_core/video_core.h"
+#include "video_core/debug_utils/debug_utils.h"
+
+
namespace GPU {
Regs g_regs;
@@ -53,6 +61,29 @@ inline void Read(T &var, const u32 raw_addr) {
var = g_regs[addr / 4];
}
+static Math::Vec4<u8> DecodePixel(Regs::PixelFormat input_format, const u8* src_pixel) {
+ switch (input_format) {
+ case Regs::PixelFormat::RGBA8:
+ return Color::DecodeRGBA8(src_pixel);
+
+ case Regs::PixelFormat::RGB8:
+ return Color::DecodeRGB8(src_pixel);
+
+ case Regs::PixelFormat::RGB565:
+ return Color::DecodeRGB565(src_pixel);
+
+ case Regs::PixelFormat::RGB5A1:
+ return Color::DecodeRGB5A1(src_pixel);
+
+ case Regs::PixelFormat::RGBA4:
+ return Color::DecodeRGBA4(src_pixel);
+
+ default:
+ LOG_ERROR(HW_GPU, "Unknown source framebuffer format %x", input_format);
+ return {0, 0, 0, 0};
+ }
+}
+
template <typename T>
inline void Write(u32 addr, const T data) {
addr -= HW::VADDR_GPU;
@@ -75,39 +106,43 @@ inline void Write(u32 addr, const T data) {
const bool is_second_filler = (index != GPU_REG_INDEX(memory_fill_config[0].trigger));
auto& config = g_regs.memory_fill_config[is_second_filler];
- if (config.address_start && config.trigger) {
- u8* start = Memory::GetPhysicalPointer(config.GetStartAddress());
- u8* end = Memory::GetPhysicalPointer(config.GetEndAddress());
-
- if (config.fill_24bit) {
- // fill with 24-bit values
- for (u8* ptr = start; ptr < end; ptr += 3) {
- ptr[0] = config.value_24bit_r;
- ptr[1] = config.value_24bit_g;
- ptr[2] = config.value_24bit_b;
+ if (config.trigger) {
+ if (config.address_start) { // Some games pass invalid values here
+ u8* start = Memory::GetPhysicalPointer(config.GetStartAddress());
+ u8* end = Memory::GetPhysicalPointer(config.GetEndAddress());
+
+ if (config.fill_24bit) {
+ // fill with 24-bit values
+ for (u8* ptr = start; ptr < end; ptr += 3) {
+ ptr[0] = config.value_24bit_r;
+ ptr[1] = config.value_24bit_g;
+ ptr[2] = config.value_24bit_b;
+ }
+ } else if (config.fill_32bit) {
+ // fill with 32-bit values
+ for (u32* ptr = (u32*)start; ptr < (u32*)end; ++ptr)
+ *ptr = config.value_32bit;
+ } else {
+ // fill with 16-bit values
+ for (u16* ptr = (u16*)start; ptr < (u16*)end; ++ptr)
+ *ptr = config.value_16bit;
}
- } else if (config.fill_32bit) {
- // fill with 32-bit values
- for (u32* ptr = (u32*)start; ptr < (u32*)end; ++ptr)
- *ptr = config.value_32bit;
- } else {
- // fill with 16-bit values
- for (u16* ptr = (u16*)start; ptr < (u16*)end; ++ptr)
- *ptr = config.value_16bit;
- }
- LOG_TRACE(HW_GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress());
+ LOG_TRACE(HW_GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress());
- config.trigger = 0;
- config.finished = 1;
+ if (!is_second_filler) {
+ GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC0);
+ } else {
+ GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC1);
+ }
- if (!is_second_filler) {
- GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC0);
- } else {
- GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC1);
+ VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetStartAddress(), config.GetEndAddress() - config.GetStartAddress());
}
- VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetStartAddress(), config.GetEndAddress() - config.GetStartAddress());
+ // Reset "trigger" flag and set the "finish" flag
+ // NOTE: This was confirmed to happen on hardware even if "address_start" is zero.
+ config.trigger = 0;
+ config.finished = 1;
}
break;
}
@@ -116,6 +151,10 @@ inline void Write(u32 addr, const T data) {
{
const auto& config = g_regs.display_transfer_config;
if (config.trigger & 1) {
+
+ if (Pica::g_debug_context)
+ Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::IncomingDisplayTransfer, nullptr);
+
u8* src_pointer = Memory::GetPhysicalPointer(config.GetPhysicalInputAddress());
u8* dst_pointer = Memory::GetPhysicalPointer(config.GetPhysicalOutputAddress());
@@ -125,11 +164,18 @@ inline void Write(u32 addr, const T data) {
break;
}
- unsigned horizontal_scale = (config.scaling != config.NoScale) ? 2 : 1;
- unsigned vertical_scale = (config.scaling == config.ScaleXY) ? 2 : 1;
+ if (config.output_tiled &&
+ (config.scaling == config.ScaleXY || config.scaling == config.ScaleX)) {
+ LOG_CRITICAL(HW_GPU, "Scaling is only implemented on tiled input");
+ UNIMPLEMENTED();
+ break;
+ }
- u32 output_width = config.output_width / horizontal_scale;
- u32 output_height = config.output_height / vertical_scale;
+ bool horizontal_scale = config.scaling != config.NoScale;
+ bool vertical_scale = config.scaling == config.ScaleXY;
+
+ u32 output_width = config.output_width >> horizontal_scale;
+ u32 output_height = config.output_height >> vertical_scale;
u32 input_size = config.input_width * config.input_height * GPU::Regs::BytesPerPixel(config.input_format);
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) {
break;
}
- // TODO(Subv): Implement the box filter when scaling is enabled
- // right now we're just skipping the extra pixels.
for (u32 y = 0; y < output_height; ++y) {
for (u32 x = 0; x < output_width; ++x) {
- Math::Vec4<u8> src_color = { 0, 0, 0, 0 };
+ Math::Vec4<u8> src_color;
// Calculate the [x,y] position of the input image
// based on the current output position and the scale
- u32 input_x = x * horizontal_scale;
- u32 input_y = y * vertical_scale;
+ u32 input_x = x << horizontal_scale;
+ u32 input_y = y << vertical_scale;
if (config.flip_vertically) {
// Flip the y value of the output data,
@@ -177,46 +221,49 @@ inline void Write(u32 addr, const T data) {
u32 dst_offset;
if (config.output_tiled) {
- // Interpret the input as linear and the output as tiled
- u32 coarse_y = y & ~7;
- u32 stride = output_width * dst_bytes_per_pixel;
-
- src_offset = (input_x + input_y * config.input_width) * src_bytes_per_pixel;
- dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + coarse_y * stride;
+ if (!config.dont_swizzle) {
+ // Interpret the input as linear and the output as tiled
+ u32 coarse_y = y & ~7;
+ u32 stride = output_width * dst_bytes_per_pixel;
+
+ src_offset = (input_x + input_y * config.input_width) * src_bytes_per_pixel;
+ dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + coarse_y * stride;
+ } else {
+ // Both input and output are linear
+ src_offset = (input_x + input_y * config.input_width) * src_bytes_per_pixel;
+ dst_offset = (x + y * output_width) * dst_bytes_per_pixel;
+ }
} else {
- // Interpret the input as tiled and the output as linear
- u32 coarse_y = input_y & ~7;
- u32 stride = config.input_width * src_bytes_per_pixel;
-
- src_offset = VideoCore::GetMortonOffset(input_x, input_y, src_bytes_per_pixel) + coarse_y * stride;
- dst_offset = (x + y * output_width) * dst_bytes_per_pixel;
+ if (!config.dont_swizzle) {
+ // Interpret the input as tiled and the output as linear
+ u32 coarse_y = input_y & ~7;
+ u32 stride = config.input_width * src_bytes_per_pixel;
+
+ src_offset = VideoCore::GetMortonOffset(input_x, input_y, src_bytes_per_pixel) + coarse_y * stride;
+ dst_offset = (x + y * output_width) * dst_bytes_per_pixel;
+ } else {
+ // Both input and output are tiled
+ u32 out_coarse_y = y & ~7;
+ u32 out_stride = output_width * dst_bytes_per_pixel;
+
+ u32 in_coarse_y = input_y & ~7;
+ u32 in_stride = config.input_width * src_bytes_per_pixel;
+
+ src_offset = VideoCore::GetMortonOffset(input_x, input_y, src_bytes_per_pixel) + in_coarse_y * in_stride;
+ dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + out_coarse_y * out_stride;
+ }
}
const u8* src_pixel = src_pointer + src_offset;
- switch (config.input_format) {
- case Regs::PixelFormat::RGBA8:
- src_color = Color::DecodeRGBA8(src_pixel);
- break;
-
- case Regs::PixelFormat::RGB8:
- src_color = Color::DecodeRGB8(src_pixel);
- break;
-
- case Regs::PixelFormat::RGB565:
- src_color = Color::DecodeRGB565(src_pixel);
- break;
-
- case Regs::PixelFormat::RGB5A1:
- src_color = Color::DecodeRGB5A1(src_pixel);
- break;
-
- case Regs::PixelFormat::RGBA4:
- src_color = Color::DecodeRGBA4(src_pixel);
- break;
-
- default:
- LOG_ERROR(HW_GPU, "Unknown source framebuffer format %x", config.input_format.Value());
- break;
+ src_color = DecodePixel(config.input_format, src_pixel);
+ if (config.scaling == config.ScaleX) {
+ Math::Vec4<u8> pixel = DecodePixel(config.input_format, src_pixel + src_bytes_per_pixel);
+ src_color = ((src_color + pixel) / 2).Cast<u8>();
+ } else if (config.scaling == config.ScaleXY) {
+ Math::Vec4<u8> pixel1 = DecodePixel(config.input_format, src_pixel + 1 * src_bytes_per_pixel);
+ Math::Vec4<u8> pixel2 = DecodePixel(config.input_format, src_pixel + 2 * src_bytes_per_pixel);
+ Math::Vec4<u8> pixel3 = DecodePixel(config.input_format, src_pixel + 3 * src_bytes_per_pixel);
+ src_color = (((src_color + pixel1) + (pixel2 + pixel3)) / 4).Cast<u8>();
}
u8* dst_pixel = dst_pointer + dst_offset;
@@ -254,6 +301,7 @@ inline void Write(u32 addr, const T data) {
config.GetPhysicalOutputAddress(), output_width, output_height,
config.output_format.Value(), config.flags);
+ g_regs.display_transfer_config.trigger = 0;
GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF);
VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetPhysicalOutputAddress(), output_size);
@@ -268,7 +316,14 @@ inline void Write(u32 addr, const T data) {
if (config.trigger & 1)
{
u32* buffer = (u32*)Memory::GetPhysicalPointer(config.GetPhysicalAddress());
+
+ if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
+ Pica::g_debug_context->recorder->MemoryAccessed((u8*)buffer, config.size * sizeof(u32), config.GetPhysicalAddress());
+ }
+
Pica::CommandProcessor::ProcessCommandList(buffer, config.size);
+
+ g_regs.command_processor_config.trigger = 0;
}
break;
}
@@ -276,6 +331,13 @@ inline void Write(u32 addr, const T data) {
default:
break;
}
+
+ // Notify tracer about the register write
+ // This is happening *after* handling the write to make sure we properly catch all memory reads.
+ if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
+ // addr + GPU VBase - IO VBase + IO PBase
+ Pica::g_debug_context->recorder->RegisterWritten<T>(addr + 0x1EF00000 - 0x1EC00000 + 0x10100000, data);
+ }
}
// 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 699bcd2a..daad506f 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -5,6 +5,7 @@
#pragma once
#include <cstddef>
+#include <type_traits>
#include "common/assert.h"
#include "common/bit_field.h"
@@ -202,6 +203,7 @@ struct Regs {
BitField< 0, 1, u32> flip_vertically; // flips input data vertically
BitField< 1, 1, u32> output_tiled; // Converts from linear to tiled format
BitField< 3, 1, u32> raw_copy; // Copies the data without performing any processing
+ BitField< 5, 1, u32> dont_swizzle;
BitField< 8, 3, PixelFormat> input_format;
BitField<12, 3, PixelFormat> output_format;
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp
index c7006a49..b5fdbf9c 100644
--- a/src/core/hw/hw.cpp
+++ b/src/core/hw/hw.cpp
@@ -15,6 +15,21 @@ template <typename T>
inline void Read(T &var, const u32 addr) {
switch (addr & 0xFFFFF000) {
case VADDR_GPU:
+ case VADDR_GPU + 0x1000:
+ case VADDR_GPU + 0x2000:
+ case VADDR_GPU + 0x3000:
+ case VADDR_GPU + 0x4000:
+ case VADDR_GPU + 0x5000:
+ case VADDR_GPU + 0x6000:
+ case VADDR_GPU + 0x7000:
+ case VADDR_GPU + 0x8000:
+ case VADDR_GPU + 0x9000:
+ case VADDR_GPU + 0xA000:
+ case VADDR_GPU + 0xB000:
+ case VADDR_GPU + 0xC000:
+ case VADDR_GPU + 0xD000:
+ case VADDR_GPU + 0xE000:
+ case VADDR_GPU + 0xF000:
GPU::Read(var, addr);
break;
case VADDR_LCD:
@@ -29,6 +44,21 @@ template <typename T>
inline void Write(u32 addr, const T data) {
switch (addr & 0xFFFFF000) {
case VADDR_GPU:
+ case VADDR_GPU + 0x1000:
+ case VADDR_GPU + 0x2000:
+ case VADDR_GPU + 0x3000:
+ case VADDR_GPU + 0x4000:
+ case VADDR_GPU + 0x5000:
+ case VADDR_GPU + 0x6000:
+ case VADDR_GPU + 0x7000:
+ case VADDR_GPU + 0x8000:
+ case VADDR_GPU + 0x9000:
+ case VADDR_GPU + 0xA000:
+ case VADDR_GPU + 0xB000:
+ case VADDR_GPU + 0xC000:
+ case VADDR_GPU + 0xD000:
+ case VADDR_GPU + 0xE000:
+ case VADDR_GPU + 0xF000:
GPU::Write(addr, data);
break;
case VADDR_LCD:
diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp
index 963c8d98..6f93709e 100644
--- a/src/core/hw/lcd.cpp
+++ b/src/core/hw/lcd.cpp
@@ -7,11 +7,12 @@
#include "common/common_types.h"
#include "common/logging/log.h"
-#include "core/arm/arm_interface.h"
-#include "core/hle/hle.h"
#include "core/hw/hw.h"
#include "core/hw/lcd.h"
+#include "core/tracer/recorder.h"
+#include "video_core/debug_utils/debug_utils.h"
+
namespace LCD {
Regs g_regs;
@@ -42,6 +43,13 @@ inline void Write(u32 addr, const T data) {
}
g_regs[index] = static_cast<u32>(data);
+
+ // Notify tracer about the register write
+ // This is happening *after* handling the write to make sure we properly catch all memory reads.
+ if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
+ // addr + GPU VBase - IO VBase + IO PBase
+ Pica::g_debug_context->recorder->RegisterWritten<T>(addr + HW::VADDR_LCD - 0x1EC00000 + 0x10100000, data);
+ }
}
// 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 8631eb20..bcce6d8c 100644
--- a/src/core/hw/lcd.h
+++ b/src/core/hw/lcd.h
@@ -5,6 +5,7 @@
#pragma once
#include <cstddef>
+#include <type_traits>
#include "common/bit_field.h"
#include "common/common_funcs.h"
diff --git a/src/core/hw/y2r.cpp b/src/core/hw/y2r.cpp
index 5b7fb39e..f80e26ec 100644
--- a/src/core/hw/y2r.cpp
+++ b/src/core/hw/y2r.cpp
@@ -2,8 +2,10 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
#include <array>
-#include <numeric>
+#include <cstddef>
+#include <memory>
#include "common/assert.h"
#include "common/color.h"
@@ -109,7 +111,7 @@ static void SendData(const u32* input, ConversionBuffer& buf, int amount_of_data
while (output < unit_end) {
u32 color = *input++;
Math::Vec4<u8> col_vec{
- (color >> 24) & 0xFF, (color >> 16) & 0xFF, (color >> 8) & 0xFF, alpha,
+ (u8)(color >> 24), (u8)(color >> 16), (u8)(color >> 8), alpha
};
switch (output_format) {
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index 14aeebeb..530837d0 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -19,7 +19,7 @@
namespace Loader {
-/**
+/*
* File layout:
* - File header
* - Code, rodata and data relocation table headers
@@ -39,13 +39,16 @@ namespace Loader {
* The entrypoint is always the start of the code segment.
* The BSS section must be cleared manually by the application.
*/
+
enum THREEDSX_Error {
ERROR_NONE = 0,
ERROR_READ = 1,
ERROR_FILE = 2,
ERROR_ALLOC = 3
};
+
static const u32 RELOCBUFSIZE = 512;
+static const unsigned int NUM_SEGMENTS = 3;
// File header
#pragma pack(1)
@@ -98,7 +101,10 @@ static u32 TranslateAddr(u32 addr, const THREEloadinfo *loadinfo, u32* offsets)
return loadinfo->seg_addrs[2] + addr - offsets[1];
}
-static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
+using Kernel::SharedPtr;
+using Kernel::CodeSet;
+
+static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, SharedPtr<CodeSet>* out_codeset)
{
if (!file.IsOpen())
return ERROR_FILE;
@@ -116,15 +122,13 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
loadinfo.seg_sizes[1] = (hdr.rodata_seg_size + 0xFFF) &~0xFFF;
loadinfo.seg_sizes[2] = (hdr.data_seg_size + 0xFFF) &~0xFFF;
u32 offsets[2] = { loadinfo.seg_sizes[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] };
- u32 data_load_size = (hdr.data_seg_size - hdr.bss_size + 0xFFF) &~0xFFF;
- u32 bss_load_size = loadinfo.seg_sizes[2] - data_load_size;
- u32 n_reloc_tables = hdr.reloc_hdr_size / 4;
- std::vector<u8> all_mem(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2] + 3 * n_reloc_tables);
+ u32 n_reloc_tables = hdr.reloc_hdr_size / sizeof(u32);
+ std::vector<u8> program_image(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2]);
loadinfo.seg_addrs[0] = base_addr;
loadinfo.seg_addrs[1] = loadinfo.seg_addrs[0] + loadinfo.seg_sizes[0];
loadinfo.seg_addrs[2] = loadinfo.seg_addrs[1] + loadinfo.seg_sizes[1];
- loadinfo.seg_ptrs[0] = &all_mem[0];
+ loadinfo.seg_ptrs[0] = program_image.data();
loadinfo.seg_ptrs[1] = loadinfo.seg_ptrs[0] + loadinfo.seg_sizes[0];
loadinfo.seg_ptrs[2] = loadinfo.seg_ptrs[1] + loadinfo.seg_sizes[1];
@@ -132,10 +136,9 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
file.Seek(hdr.header_size, SEEK_SET);
// Read the relocation headers
- u32* relocs = (u32*)(loadinfo.seg_ptrs[2] + hdr.data_seg_size);
-
- for (unsigned current_segment : {0, 1, 2}) {
- size_t size = n_reloc_tables * 4;
+ std::vector<u32> relocs(n_reloc_tables * NUM_SEGMENTS);
+ for (unsigned int current_segment = 0; current_segment < NUM_SEGMENTS; ++current_segment) {
+ size_t size = n_reloc_tables * sizeof(u32);
if (file.ReadBytes(&relocs[current_segment * n_reloc_tables], size) != size)
return ERROR_READ;
}
@@ -152,7 +155,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size);
// Relocate the segments
- for (unsigned current_segment : {0, 1, 2}) {
+ for (unsigned int current_segment = 0; current_segment < NUM_SEGMENTS; ++current_segment) {
for (unsigned current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) {
u32 n_relocs = relocs[current_segment * n_reloc_tables + current_segment_reloc_table];
if (current_segment_reloc_table >= 2) {
@@ -160,7 +163,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR);
continue;
}
- static THREEDSX_Reloc reloc_table[RELOCBUFSIZE];
+ THREEDSX_Reloc reloc_table[RELOCBUFSIZE];
u32* pos = (u32*)loadinfo.seg_ptrs[current_segment];
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)
pos += table.skip;
s32 num_patches = table.patch;
while (0 < num_patches && pos < end_pos) {
- u32 in_addr = (char*)pos - (char*)&all_mem[0];
+ u32 in_addr = (u8*)pos - program_image.data();
u32 addr = TranslateAddr(*pos, &loadinfo, offsets);
LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)\n",
base_addr + in_addr, addr, current_segment_reloc_table, *pos);
@@ -188,7 +191,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
*pos = (addr);
break;
case 1:
- *pos = (addr - in_addr);
+ *pos = static_cast<u32>(addr - in_addr);
break;
default:
break; //this should never happen
@@ -201,14 +204,29 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
}
}
- // Write the data
- memcpy(Memory::GetPointer(base_addr), &all_mem[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2]);
+ // Create the CodeSet
+ SharedPtr<CodeSet> code_set = CodeSet::Create("", 0);
+
+ code_set->code.offset = loadinfo.seg_ptrs[0] - program_image.data();
+ code_set->code.addr = loadinfo.seg_addrs[0];
+ code_set->code.size = loadinfo.seg_sizes[0];
+
+ code_set->rodata.offset = loadinfo.seg_ptrs[1] - program_image.data();
+ code_set->rodata.addr = loadinfo.seg_addrs[1];
+ code_set->rodata.size = loadinfo.seg_sizes[1];
- LOG_DEBUG(Loader, "CODE: %u pages\n", loadinfo.seg_sizes[0] / 0x1000);
- LOG_DEBUG(Loader, "RODATA: %u pages\n", loadinfo.seg_sizes[1] / 0x1000);
- LOG_DEBUG(Loader, "DATA: %u pages\n", data_load_size / 0x1000);
- LOG_DEBUG(Loader, "BSS: %u pages\n", bss_load_size / 0x1000);
+ code_set->data.offset = loadinfo.seg_ptrs[2] - program_image.data();
+ code_set->data.addr = loadinfo.seg_addrs[2];
+ code_set->data.size = loadinfo.seg_sizes[2];
+ code_set->entrypoint = code_set->code.addr;
+ code_set->memory = std::make_shared<std::vector<u8>>(std::move(program_image));
+
+ LOG_DEBUG(Loader, "code size: 0x%X", loadinfo.seg_sizes[0]);
+ LOG_DEBUG(Loader, "rodata size: 0x%X", loadinfo.seg_sizes[1]);
+ LOG_DEBUG(Loader, "data size: 0x%X (including 0x%X of bss)", loadinfo.seg_sizes[2], hdr.bss_size);
+
+ *out_codeset = code_set;
return ERROR_NONE;
}
@@ -228,19 +246,22 @@ ResultStatus AppLoader_THREEDSX::Load() {
if (is_loaded)
return ResultStatus::ErrorAlreadyLoaded;
- if (!file->IsOpen())
+ if (!file.IsOpen())
+ return ResultStatus::Error;
+
+ SharedPtr<CodeSet> codeset;
+ if (Load3DSXFile(file, Memory::PROCESS_IMAGE_VADDR, &codeset) != ERROR_NONE)
return ResultStatus::Error;
+ codeset->name = filename;
- Kernel::g_current_process = Kernel::Process::Create(filename, 0);
+ Kernel::g_current_process = Kernel::Process::Create(std::move(codeset));
Kernel::g_current_process->svc_access_mask.set();
Kernel::g_current_process->address_mappings = default_address_mappings;
// Attach the default resource limit (APPLICATION) to the process
Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
- Load3DSXFile(*file, Memory::PROCESS_IMAGE_VADDR);
-
- Kernel::g_current_process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE);
+ Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE);
is_loaded = true;
return ResultStatus::Success;
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h
index 096b3ec2..a0aa0c53 100644
--- a/src/core/loader/3dsx.h
+++ b/src/core/loader/3dsx.h
@@ -17,7 +17,7 @@ namespace Loader {
/// Loads an 3DSX file
class AppLoader_THREEDSX final : public AppLoader {
public:
- AppLoader_THREEDSX(std::unique_ptr<FileUtil::IOFile>&& file, std::string filename)
+ AppLoader_THREEDSX(FileUtil::IOFile&& file, std::string filename)
: AppLoader(std::move(file)), filename(std::move(filename)) {}
/**
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index f00753a7..5d7264f1 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
#include <string>
#include <memory>
@@ -10,11 +11,14 @@
#include "common/logging/log.h"
#include "common/symbols.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/loader/elf.h"
#include "core/memory.h"
+using Kernel::SharedPtr;
+using Kernel::CodeSet;
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// ELF Header Constants
@@ -96,6 +100,12 @@ enum ElfSectionFlags
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7FFFFFFF
+// Segment flags
+#define PF_X 0x1
+#define PF_W 0x2
+#define PF_R 0x4
+#define PF_MASKPROC 0xF0000000
+
typedef unsigned int Elf32_Addr;
typedef unsigned short Elf32_Half;
typedef unsigned int Elf32_Off;
@@ -192,7 +202,7 @@ public:
ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); }
u32 GetEntryPoint() const { return entryPoint; }
u32 GetFlags() const { return (u32)(header->e_flags); }
- void LoadInto(u32 vaddr);
+ SharedPtr<CodeSet> LoadInto(u32 vaddr);
bool LoadSymbols();
int GetNumSegments() const { return (int)(header->e_phnum); }
@@ -248,7 +258,7 @@ const char *ElfReader::GetSectionName(int section) const {
return nullptr;
}
-void ElfReader::LoadInto(u32 vaddr) {
+SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
LOG_DEBUG(Loader, "String section: %i", header->e_shstrndx);
// Should we relocate?
@@ -263,22 +273,63 @@ void ElfReader::LoadInto(u32 vaddr) {
LOG_DEBUG(Loader, "%i segments:", header->e_phnum);
// First pass : Get the bits into RAM
- u32 segment_addr[32];
u32 base_addr = relocate ? vaddr : 0;
- for (unsigned i = 0; i < header->e_phnum; i++) {
- Elf32_Phdr* p = segments + i;
- LOG_DEBUG(Loader, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr,
+ u32 total_image_size = 0;
+ for (unsigned int i = 0; i < header->e_phnum; ++i) {
+ Elf32_Phdr* p = &segments[i];
+ if (p->p_type == PT_LOAD) {
+ total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF;
+ }
+ }
+
+ std::vector<u8> program_image(total_image_size);
+ size_t current_image_position = 0;
+
+ SharedPtr<CodeSet> codeset = CodeSet::Create("", 0);
+
+ for (unsigned int i = 0; i < header->e_phnum; ++i) {
+ Elf32_Phdr* p = &segments[i];
+ LOG_DEBUG(Loader, "Type: %i Vaddr: %08X Filesz: %8X Memsz: %8X ", p->p_type, p->p_vaddr,
p->p_filesz, p->p_memsz);
if (p->p_type == PT_LOAD) {
- segment_addr[i] = base_addr + p->p_vaddr;
- memcpy(Memory::GetPointer(segment_addr[i]), GetSegmentPtr(i), p->p_filesz);
- LOG_DEBUG(Loader, "Loadable Segment Copied to %08x, size %08x", segment_addr[i],
- p->p_memsz);
+ CodeSet::Segment* codeset_segment;
+ u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X);
+ if (permission_flags == (PF_R | PF_X)) {
+ codeset_segment = &codeset->code;
+ } else if (permission_flags == (PF_R)) {
+ codeset_segment = &codeset->rodata;
+ } else if (permission_flags == (PF_R | PF_W)) {
+ codeset_segment = &codeset->data;
+ } else {
+ LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id %u with flags %X", i, p->p_flags);
+ continue;
+ }
+
+ if (codeset_segment->size != 0) {
+ LOG_ERROR(Loader, "ELF has more than one segment of the same type. Skipping extra segment (id %i)", i);
+ continue;
+ }
+
+ u32 segment_addr = base_addr + p->p_vaddr;
+ u32 aligned_size = (p->p_memsz + 0xFFF) & ~0xFFF;
+
+ codeset_segment->offset = current_image_position;
+ codeset_segment->addr = segment_addr;
+ codeset_segment->size = aligned_size;
+
+ memcpy(&program_image[current_image_position], GetSegmentPtr(i), p->p_filesz);
+ current_image_position += aligned_size;
}
}
+
+ codeset->entrypoint = base_addr + header->e_entry;
+ codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image));
+
LOG_DEBUG(Loader, "Done loading.");
+
+ return codeset;
}
SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const {
@@ -340,29 +391,29 @@ ResultStatus AppLoader_ELF::Load() {
if (is_loaded)
return ResultStatus::ErrorAlreadyLoaded;
- if (!file->IsOpen())
+ if (!file.IsOpen())
return ResultStatus::Error;
// Reset read pointer in case this file has been read before.
- file->Seek(0, SEEK_SET);
+ file.Seek(0, SEEK_SET);
- u32 size = static_cast<u32>(file->GetSize());
+ size_t size = file.GetSize();
std::unique_ptr<u8[]> buffer(new u8[size]);
- if (file->ReadBytes(&buffer[0], size) != size)
+ if (file.ReadBytes(&buffer[0], size) != size)
return ResultStatus::Error;
- Kernel::g_current_process = Kernel::Process::Create(filename, 0);
+ ElfReader elf_reader(&buffer[0]);
+ SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
+ codeset->name = filename;
+
+ Kernel::g_current_process = Kernel::Process::Create(std::move(codeset));
Kernel::g_current_process->svc_access_mask.set();
Kernel::g_current_process->address_mappings = default_address_mappings;
// Attach the default resource limit (APPLICATION) to the process
Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
- ElfReader elf_reader(&buffer[0]);
- elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
- // TODO: Fill application title
-
- Kernel::g_current_process->Run(elf_reader.GetEntryPoint(), 48, Kernel::DEFAULT_STACK_SIZE);
+ Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE);
is_loaded = true;
return ResultStatus::Success;
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 32841606..c6a5ebe9 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -17,7 +17,7 @@ namespace Loader {
/// Loads an ELF/AXF file
class AppLoader_ELF final : public AppLoader {
public:
- AppLoader_ELF(std::unique_ptr<FileUtil::IOFile>&& file, std::string filename)
+ AppLoader_ELF(FileUtil::IOFile&& file, std::string filename)
: AppLoader(std::move(file)), filename(std::move(filename)) { }
/**
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 8b14edf0..f5b349a7 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -2,10 +2,12 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <memory>
#include <string>
#include "common/logging/log.h"
#include "common/make_unique.h"
+#include "common/string_util.h"
#include "core/file_sys/archive_romfs.h"
#include "core/hle/kernel/process.h"
@@ -54,18 +56,18 @@ static FileType IdentifyFile(FileUtil::IOFile& file) {
static FileType GuessFromExtension(const std::string& extension_) {
std::string extension = Common::ToLower(extension_);
- if (extension == ".elf")
+ if (extension == ".elf" || extension == ".axf")
return FileType::ELF;
- else if (extension == ".axf")
- return FileType::ELF;
- else if (extension == ".cxi")
- return FileType::CXI;
- else if (extension == ".cci")
- return FileType::CCI;
- else if (extension == ".3ds")
+
+ if (extension == ".cci" || extension == ".3ds")
return FileType::CCI;
- else if (extension == ".3dsx")
+
+ if (extension == ".cxi")
+ return FileType::CXI;
+
+ if (extension == ".3dsx")
return FileType::THREEDSX;
+
return FileType::Unknown;
}
@@ -88,8 +90,8 @@ static const char* GetFileTypeString(FileType type) {
}
ResultStatus LoadFile(const std::string& filename) {
- std::unique_ptr<FileUtil::IOFile> file(new FileUtil::IOFile(filename, "rb"));
- if (!file->IsOpen()) {
+ FileUtil::IOFile file(filename, "rb");
+ if (!file.IsOpen()) {
LOG_ERROR(Loader, "Failed to load file %s", filename.c_str());
return ResultStatus::Error;
}
@@ -97,7 +99,7 @@ ResultStatus LoadFile(const std::string& filename) {
std::string filename_filename, filename_extension;
Common::SplitPath(filename, nullptr, &filename_filename, &filename_extension);
- FileType type = IdentifyFile(*file);
+ FileType type = IdentifyFile(file);
FileType filename_type = GuessFromExtension(filename_extension);
if (type != filename_type) {
@@ -122,7 +124,7 @@ ResultStatus LoadFile(const std::string& filename) {
case FileType::CXI:
case FileType::CCI:
{
- AppLoader_NCCH app_loader(std::move(file));
+ AppLoader_NCCH app_loader(std::move(file), filename);
// Load application and RomFS
if (ResultStatus::Success == app_loader.Load()) {
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 87e16fb9..a37d3348 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -4,12 +4,18 @@
#pragma once
+#include <algorithm>
+#include <initializer_list>
+#include <memory>
+#include <string>
#include <vector>
#include "common/common_types.h"
#include "common/file_util.h"
-#include "core/hle/kernel/process.h"
+namespace Kernel {
+struct AddressMapping;
+}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Loader namespace
@@ -46,7 +52,7 @@ static inline u32 MakeMagic(char a, char b, char c, char d) {
/// Interface for loading an application
class AppLoader : NonCopyable {
public:
- AppLoader(std::unique_ptr<FileUtil::IOFile>&& file) : file(std::move(file)) { }
+ AppLoader(FileUtil::IOFile&& file) : file(std::move(file)) { }
virtual ~AppLoader() { }
/**
@@ -60,7 +66,7 @@ public:
* @param buffer Reference to buffer to store data
* @return ResultStatus result of function
*/
- virtual ResultStatus ReadCode(std::vector<u8>& buffer) const {
+ virtual ResultStatus ReadCode(std::vector<u8>& buffer) {
return ResultStatus::ErrorNotImplemented;
}
@@ -69,7 +75,7 @@ public:
* @param buffer Reference to buffer to store data
* @return ResultStatus result of function
*/
- virtual ResultStatus ReadIcon(std::vector<u8>& buffer) const {
+ virtual ResultStatus ReadIcon(std::vector<u8>& buffer) {
return ResultStatus::ErrorNotImplemented;
}
@@ -78,7 +84,7 @@ public:
* @param buffer Reference to buffer to store data
* @return ResultStatus result of function
*/
- virtual ResultStatus ReadBanner(std::vector<u8>& buffer) const {
+ virtual ResultStatus ReadBanner(std::vector<u8>& buffer) {
return ResultStatus::ErrorNotImplemented;
}
@@ -87,22 +93,25 @@ public:
* @param buffer Reference to buffer to store data
* @return ResultStatus result of function
*/
- virtual ResultStatus ReadLogo(std::vector<u8>& buffer) const {
+ virtual ResultStatus ReadLogo(std::vector<u8>& buffer) {
return ResultStatus::ErrorNotImplemented;
}
/**
* Get the RomFS of the application
- * @param buffer Reference to buffer to store data
+ * Since the RomFS can be huge, we return a file reference instead of copying to a buffer
+ * @param romfs_file The file containing the RomFS
+ * @param offset The offset the romfs begins on
+ * @param size The size of the romfs
* @return ResultStatus result of function
*/
- virtual ResultStatus ReadRomFS(std::vector<u8>& buffer) const {
+ virtual ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) {
return ResultStatus::ErrorNotImplemented;
}
protected:
- std::unique_ptr<FileUtil::IOFile> file;
- bool is_loaded = false;
+ FileUtil::IOFile file;
+ bool is_loaded = false;
};
/**
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 08993c4f..094d7410 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <algorithm>
+#include <cstring>
#include <memory>
#include "common/logging/log.h"
@@ -10,7 +11,7 @@
#include "common/string_util.h"
#include "common/swap.h"
-#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/loader/ncch.h"
#include "core/memory.h"
@@ -116,7 +117,10 @@ FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) {
return FileType::Error;
}
-ResultStatus AppLoader_NCCH::LoadExec() const {
+ResultStatus AppLoader_NCCH::LoadExec() {
+ using Kernel::SharedPtr;
+ using Kernel::CodeSet;
+
if (!is_loaded)
return ResultStatus::ErrorNotLoaded;
@@ -125,7 +129,30 @@ ResultStatus AppLoader_NCCH::LoadExec() const {
std::string process_name = Common::StringFromFixedZeroTerminatedBuffer(
(const char*)exheader_header.codeset_info.name, 8);
u64 program_id = *reinterpret_cast<u64_le const*>(&ncch_header.program_id[0]);
- Kernel::g_current_process = Kernel::Process::Create(process_name, program_id);
+
+ SharedPtr<CodeSet> codeset = CodeSet::Create(process_name, program_id);
+
+ codeset->code.offset = 0;
+ codeset->code.addr = exheader_header.codeset_info.text.address;
+ codeset->code.size = exheader_header.codeset_info.text.num_max_pages * Memory::PAGE_SIZE;
+
+ codeset->rodata.offset = codeset->code.offset + codeset->code.size;
+ codeset->rodata.addr = exheader_header.codeset_info.ro.address;
+ codeset->rodata.size = exheader_header.codeset_info.ro.num_max_pages * Memory::PAGE_SIZE;
+
+ // TODO(yuriks): Not sure if the bss size is added to the page-aligned .data size or just
+ // to the regular size. Playing it safe for now.
+ u32 bss_page_size = (exheader_header.codeset_info.bss_size + 0xFFF) & ~0xFFF;
+ code.resize(code.size() + bss_page_size, 0);
+
+ codeset->data.offset = codeset->rodata.offset + codeset->rodata.size;
+ codeset->data.addr = exheader_header.codeset_info.data.address;
+ codeset->data.size = exheader_header.codeset_info.data.num_max_pages * Memory::PAGE_SIZE + bss_page_size;
+
+ codeset->entrypoint = codeset->code.addr;
+ codeset->memory = std::make_shared<std::vector<u8>>(std::move(code));
+
+ Kernel::g_current_process = Kernel::Process::Create(std::move(codeset));
// Attach a resource limit to the process based on the resource limit category
Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(
@@ -136,18 +163,16 @@ ResultStatus AppLoader_NCCH::LoadExec() const {
std::copy_n(exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), begin(kernel_caps));
Kernel::g_current_process->ParseKernelCaps(kernel_caps.data(), kernel_caps.size());
- Memory::WriteBlock(entry_point, &code[0], code.size());
-
s32 priority = exheader_header.arm11_system_local_caps.priority;
u32 stack_size = exheader_header.codeset_info.stack_size;
- Kernel::g_current_process->Run(entry_point, priority, stack_size);
+ Kernel::g_current_process->Run(priority, stack_size);
return ResultStatus::Success;
}
return ResultStatus::Error;
}
-ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const {
- if (!file->IsOpen())
+ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) {
+ if (!file.IsOpen())
return ResultStatus::Error;
LOG_DEBUG(Loader, "%d sections:", kMaxSections);
@@ -161,7 +186,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>&
section.offset, section.size, section.name);
s64 section_offset = (section.offset + exefs_offset + sizeof(ExeFs_Header) + ncch_offset);
- file->Seek(section_offset, SEEK_SET);
+ file.Seek(section_offset, SEEK_SET);
if (is_compressed) {
// Section is compressed, read compressed .code section...
@@ -172,7 +197,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>&
return ResultStatus::ErrorMemoryAllocationFailed;
}
- if (file->ReadBytes(&temp_buffer[0], section.size) != section.size)
+ if (file.ReadBytes(&temp_buffer[0], section.size) != section.size)
return ResultStatus::Error;
// Decompress .code section...
@@ -183,7 +208,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>&
} else {
// Section is uncompressed...
buffer.resize(section.size);
- if (file->ReadBytes(&buffer[0], section.size) != section.size)
+ if (file.ReadBytes(&buffer[0], section.size) != section.size)
return ResultStatus::Error;
}
return ResultStatus::Success;
@@ -196,21 +221,21 @@ ResultStatus AppLoader_NCCH::Load() {
if (is_loaded)
return ResultStatus::ErrorAlreadyLoaded;
- if (!file->IsOpen())
+ if (!file.IsOpen())
return ResultStatus::Error;
// Reset read pointer in case this file has been read before.
- file->Seek(0, SEEK_SET);
+ file.Seek(0, SEEK_SET);
- if (file->ReadBytes(&ncch_header, sizeof(NCCH_Header)) != sizeof(NCCH_Header))
+ if (file.ReadBytes(&ncch_header, sizeof(NCCH_Header)) != sizeof(NCCH_Header))
return ResultStatus::Error;
// Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)...
if (MakeMagic('N', 'C', 'S', 'D') == ncch_header.magic) {
LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
ncch_offset = 0x4000;
- file->Seek(ncch_offset, SEEK_SET);
- file->ReadBytes(&ncch_header, sizeof(NCCH_Header));
+ file.Seek(ncch_offset, SEEK_SET);
+ file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
}
// Verify we are loading the correct file type...
@@ -219,7 +244,7 @@ ResultStatus AppLoader_NCCH::Load() {
// Read ExHeader...
- if (file->ReadBytes(&exheader_header, sizeof(ExHeader_Header)) != sizeof(ExHeader_Header))
+ if (file.ReadBytes(&exheader_header, sizeof(ExHeader_Header)) != sizeof(ExHeader_Header))
return ResultStatus::Error;
is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1;
@@ -239,7 +264,6 @@ ResultStatus AppLoader_NCCH::Load() {
LOG_DEBUG(Loader, "Bss size: 0x%08X", bss_size);
LOG_DEBUG(Loader, "Core version: %d" , core_version);
LOG_DEBUG(Loader, "Thread priority: 0x%X" , priority);
- LOG_DEBUG(Loader, "Resource limit descriptor: 0x%08X", exheader_header.arm11_system_local_caps.resource_limit_descriptor);
LOG_DEBUG(Loader, "Resource limit category: %d" , resource_limit_category);
// Read ExeFS...
@@ -250,8 +274,8 @@ ResultStatus AppLoader_NCCH::Load() {
LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset);
LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size);
- file->Seek(exefs_offset + ncch_offset, SEEK_SET);
- if (file->ReadBytes(&exefs_header, sizeof(ExeFs_Header)) != sizeof(ExeFs_Header))
+ file.Seek(exefs_offset + ncch_offset, SEEK_SET);
+ if (file.ReadBytes(&exefs_header, sizeof(ExeFs_Header)) != sizeof(ExeFs_Header))
return ResultStatus::Error;
is_loaded = true; // Set state to loaded
@@ -259,24 +283,24 @@ ResultStatus AppLoader_NCCH::Load() {
return LoadExec(); // Load the executable into memory for booting
}
-ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) const {
+ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) {
return LoadSectionExeFS(".code", buffer);
}
-ResultStatus AppLoader_NCCH::ReadIcon(std::vector<u8>& buffer) const {
+ResultStatus AppLoader_NCCH::ReadIcon(std::vector<u8>& buffer) {
return LoadSectionExeFS("icon", buffer);
}
-ResultStatus AppLoader_NCCH::ReadBanner(std::vector<u8>& buffer) const {
+ResultStatus AppLoader_NCCH::ReadBanner(std::vector<u8>& buffer) {
return LoadSectionExeFS("banner", buffer);
}
-ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) const {
+ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) {
return LoadSectionExeFS("logo", buffer);
}
-ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
- if (!file->IsOpen())
+ResultStatus AppLoader_NCCH::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) {
+ if (!file.IsOpen())
return ResultStatus::Error;
// Check if the NCCH has a RomFS...
@@ -287,12 +311,17 @@ ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset);
LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size);
- buffer.resize(romfs_size);
+ if (file.GetSize () < romfs_offset + romfs_size)
+ return ResultStatus::Error;
- file->Seek(romfs_offset, SEEK_SET);
- if (file->ReadBytes(&buffer[0], romfs_size) != romfs_size)
+ // We reopen the file, to allow its position to be independent from file's
+ romfs_file = std::make_shared<FileUtil::IOFile>(filepath, "rb");
+ if (!romfs_file->IsOpen())
return ResultStatus::Error;
+ offset = romfs_offset;
+ size = romfs_size;
+
return ResultStatus::Success;
}
LOG_DEBUG(Loader, "NCCH has no RomFS");
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index 29e39d2c..b4374a47 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -163,7 +163,8 @@ namespace Loader {
/// Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI)
class AppLoader_NCCH final : public AppLoader {
public:
- AppLoader_NCCH(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { }
+ AppLoader_NCCH(FileUtil::IOFile&& file, const std::string& filepath)
+ : AppLoader(std::move(file)), filepath(filepath) { }
/**
* Returns the type of the file
@@ -183,35 +184,35 @@ public:
* @param buffer Reference to buffer to store data
* @return ResultStatus result of function
*/
- ResultStatus ReadCode(std::vector<u8>& buffer) const override;
+ ResultStatus ReadCode(std::vector<u8>& buffer) override;
/**
* Get the icon (typically icon section) of the application
* @param buffer Reference to buffer to store data
* @return ResultStatus result of function
*/
- ResultStatus ReadIcon(std::vector<u8>& buffer) const override;
+ ResultStatus ReadIcon(std::vector<u8>& buffer) override;
/**
* Get the banner (typically banner section) of the application
* @param buffer Reference to buffer to store data
* @return ResultStatus result of function
*/
- ResultStatus ReadBanner(std::vector<u8>& buffer) const override;
+ ResultStatus ReadBanner(std::vector<u8>& buffer) override;
/**
* Get the logo (typically logo section) of the application
* @param buffer Reference to buffer to store data
* @return ResultStatus result of function
*/
- ResultStatus ReadLogo(std::vector<u8>& buffer) const override;
+ ResultStatus ReadLogo(std::vector<u8>& buffer) override;
/**
* Get the RomFS of the application
* @param buffer Reference to buffer to store data
* @return ResultStatus result of function
*/
- ResultStatus ReadRomFS(std::vector<u8>& buffer) const override;
+ ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) override;
private:
@@ -221,13 +222,13 @@ private:
* @param buffer Vector to read data into
* @return ResultStatus result of function
*/
- ResultStatus LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const;
+ ResultStatus LoadSectionExeFS(const char* name, std::vector<u8>& buffer);
/**
* Loads .code section into memory for booting
* @return ResultStatus result of function
*/
- ResultStatus LoadExec() const;
+ ResultStatus LoadExec();
bool is_compressed = false;
@@ -244,6 +245,8 @@ private:
NCCH_Header ncch_header;
ExeFs_Header exefs_header;
ExHeader_Header exheader_header;
+
+ std::string filepath;
};
} // namespace Loader
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp
index bf814b94..cbe993fb 100644
--- a/src/core/mem_map.cpp
+++ b/src/core/mem_map.cpp
@@ -3,13 +3,14 @@
// Refer to the license.txt file included.
#include <map>
+#include <memory>
+#include <utility>
+#include <vector>
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/hle/config_mem.h"
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/hle/result.h"
#include "core/hle/shared_page.h"
@@ -31,7 +32,6 @@ struct MemoryArea {
// We don't declare the IO regions in here since its handled by other means.
static MemoryArea memory_areas[] = {
- {PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE, "Process Image"}, // ExeFS:/.code is loaded here
{HEAP_VADDR, HEAP_SIZE, "Heap"}, // Application heap (main memory)
{SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory
{LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE, "Linear Heap"}, // Linear heap (main memory)
@@ -131,13 +131,13 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) {
return addr | 0x80000000;
}
-// TODO(yuriks): Move this into Process
-static Kernel::VMManager address_space;
-
void Init() {
- using namespace Kernel;
-
InitMemoryMap();
+ LOG_DEBUG(HW_Memory, "initialized OK");
+}
+
+void InitLegacyAddressSpace(Kernel::VMManager& address_space) {
+ using namespace Kernel;
for (MemoryArea& area : memory_areas) {
auto block = std::make_shared<std::vector<u8>>(area.size);
@@ -151,14 +151,11 @@ void Init() {
auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR,
(u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom();
address_space.Reprotect(shared_page_vma, VMAPermission::Read);
-
- LOG_DEBUG(HW_Memory, "initialized OK");
}
void Shutdown() {
heap_map.clear();
heap_linear_map.clear();
- address_space.Reset();
LOG_DEBUG(HW_Memory, "shutdown OK");
}
diff --git a/src/core/mem_map.h b/src/core/mem_map.h
index ba50914a..229ef82c 100644
--- a/src/core/mem_map.h
+++ b/src/core/mem_map.h
@@ -6,9 +6,14 @@
#include "common/common_types.h"
+namespace Kernel {
+class VMManager;
+}
+
namespace Memory {
void Init();
+void InitLegacyAddressSpace(Kernel::VMManager& address_space);
void Shutdown();
/**
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 28844a91..1f66bb27 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -9,9 +9,6 @@
#include "common/logging/log.h"
#include "common/swap.h"
-#include "core/hle/config_mem.h"
-#include "core/hle/shared_page.h"
-#include "core/hw/hw.h"
#include "core/mem_map.h"
#include "core/memory.h"
#include "core/memory_setup.h"
@@ -62,14 +59,12 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) {
while (base != end) {
ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base);
- if (current_page_table->attributes[base] != PageType::Unmapped && type != PageType::Unmapped) {
- LOG_ERROR(HW_Memory, "overlapping memory ranges at %08X", base * PAGE_SIZE);
- }
current_page_table->attributes[base] = type;
current_page_table->pointers[base] = memory;
base += 1;
- memory += PAGE_SIZE;
+ if (memory != nullptr)
+ memory += PAGE_SIZE;
}
}
diff --git a/src/core/memory.h b/src/core/memory.h
index 0b8ff9ec..418609de 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -4,6 +4,8 @@
#pragma once
+#include <cstddef>
+
#include "common/common_types.h"
namespace Memory {
diff --git a/src/core/settings.h b/src/core/settings.h
index 5a70d157..2775ee25 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -5,34 +5,42 @@
#pragma once
#include <string>
+#include <array>
namespace Settings {
+namespace NativeInput {
+enum Values {
+ A, B, X, Y,
+ L, R, ZL, ZR,
+ START, SELECT, HOME,
+ DUP, DDOWN, DLEFT, DRIGHT,
+ SUP, SDOWN, SLEFT, SRIGHT,
+ CUP, CDOWN, CLEFT, CRIGHT,
+ NUM_INPUTS
+};
+static const std::array<const char*, NUM_INPUTS> Mapping = {
+ "pad_a", "pad_b", "pad_x", "pad_y",
+ "pad_l", "pad_r", "pad_zl", "pad_zr",
+ "pad_start", "pad_select", "pad_home",
+ "pad_dup", "pad_ddown", "pad_dleft", "pad_dright",
+ "pad_sup", "pad_sdown", "pad_sleft", "pad_sright",
+ "pad_cup", "pad_cdown", "pad_cleft", "pad_cright"
+};
+static const std::array<Values, NUM_INPUTS> All = {
+ A, B, X, Y,
+ L, R, ZL, ZR,
+ START, SELECT, HOME,
+ DUP, DDOWN, DLEFT, DRIGHT,
+ SUP, SDOWN, SLEFT, SRIGHT,
+ CUP, CDOWN, CLEFT, CRIGHT
+};
+}
+
+
struct Values {
// Controls
- int pad_a_key;
- int pad_b_key;
- int pad_x_key;
- int pad_y_key;
- int pad_l_key;
- int pad_r_key;
- int pad_zl_key;
- int pad_zr_key;
- int pad_start_key;
- int pad_select_key;
- int pad_home_key;
- int pad_dup_key;
- int pad_ddown_key;
- int pad_dleft_key;
- int pad_dright_key;
- int pad_sup_key;
- int pad_sdown_key;
- int pad_sleft_key;
- int pad_sright_key;
- int pad_cup_key;
- int pad_cdown_key;
- int pad_cleft_key;
- int pad_cright_key;
+ std::array<int, NativeInput::NUM_INPUTS> input_mappings;
// Core
int frame_skip;
diff --git a/src/core/tracer/citrace.h b/src/core/tracer/citrace.h
new file mode 100644
index 00000000..5deb6ce9
--- /dev/null
+++ b/src/core/tracer/citrace.h
@@ -0,0 +1,101 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <cstdint>
+
+namespace CiTrace {
+
+// NOTE: Things are stored in little-endian
+
+#pragma pack(1)
+
+struct CTHeader {
+ static const char* ExpectedMagicWord() {
+ return "CiTr";
+ }
+
+ static uint32_t ExpectedVersion() {
+ return 1;
+ }
+
+ char magic[4];
+ uint32_t version;
+ uint32_t header_size;
+
+ struct {
+ // NOTE: Register range sizes are technically hardware-constants, but the actual limits
+ // aren't known. Hence we store the presumed limits along the offsets.
+ // Sizes are given in uint32_t units.
+ uint32_t gpu_registers;
+ uint32_t gpu_registers_size;
+ uint32_t lcd_registers;
+ uint32_t lcd_registers_size;
+ uint32_t pica_registers;
+ uint32_t pica_registers_size;
+ uint32_t default_attributes;
+ uint32_t default_attributes_size;
+ uint32_t vs_program_binary;
+ uint32_t vs_program_binary_size;
+ uint32_t vs_swizzle_data;
+ uint32_t vs_swizzle_data_size;
+ uint32_t vs_float_uniforms;
+ uint32_t vs_float_uniforms_size;
+ uint32_t gs_program_binary;
+ uint32_t gs_program_binary_size;
+ uint32_t gs_swizzle_data;
+ uint32_t gs_swizzle_data_size;
+ uint32_t gs_float_uniforms;
+ uint32_t gs_float_uniforms_size;
+
+ // Other things we might want to store here:
+ // - Initial framebuffer data, maybe even a full copy of FCRAM/VRAM
+ // - Lookup tables for fragment lighting
+ // - Lookup tables for procedural textures
+ } initial_state_offsets;
+
+ uint32_t stream_offset;
+ uint32_t stream_size;
+};
+
+enum CTStreamElementType : uint32_t {
+ FrameMarker = 0xE1,
+ MemoryLoad = 0xE2,
+ RegisterWrite = 0xE3,
+};
+
+struct CTMemoryLoad {
+ uint32_t file_offset;
+ uint32_t size;
+ uint32_t physical_address;
+ uint32_t pad;
+};
+
+struct CTRegisterWrite {
+ uint32_t physical_address;
+
+ enum : uint32_t {
+ SIZE_8 = 0xD1,
+ SIZE_16 = 0xD2,
+ SIZE_32 = 0xD3,
+ SIZE_64 = 0xD4
+ } size;
+
+ // TODO: Make it clearer which bits of this member are used for sizes other than 32 bits
+ uint64_t value;
+};
+
+struct CTStreamElement {
+ CTStreamElementType type;
+
+ union {
+ CTMemoryLoad memory_load;
+ CTRegisterWrite register_write;
+ };
+};
+
+#pragma pack()
+
+}
diff --git a/src/core/tracer/recorder.cpp b/src/core/tracer/recorder.cpp
new file mode 100644
index 00000000..656706c0
--- /dev/null
+++ b/src/core/tracer/recorder.cpp
@@ -0,0 +1,187 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <cstring>
+
+#include "common/assert.h"
+#include "common/file_util.h"
+#include "common/logging/log.h"
+
+#include "recorder.h"
+
+namespace CiTrace {
+
+Recorder::Recorder(const InitialState& initial_state) : initial_state(initial_state) {
+
+}
+
+void Recorder::Finish(const std::string& filename) {
+ // Setup CiTrace header
+ CTHeader header;
+ std::memcpy(header.magic, CTHeader::ExpectedMagicWord(), 4);
+ header.version = CTHeader::ExpectedVersion();
+ header.header_size = sizeof(CTHeader);
+
+ // Calculate file offsets
+ auto& initial = header.initial_state_offsets;
+
+ initial.gpu_registers_size = initial_state.gpu_registers.size();
+ initial.lcd_registers_size = initial_state.lcd_registers.size();
+ initial.pica_registers_size = initial_state.pica_registers.size();
+ initial.default_attributes_size = initial_state.default_attributes.size();
+ initial.vs_program_binary_size = initial_state.vs_program_binary.size();
+ initial.vs_swizzle_data_size = initial_state.vs_swizzle_data.size();
+ initial.vs_float_uniforms_size = initial_state.vs_float_uniforms.size();
+ initial.gs_program_binary_size = initial_state.gs_program_binary.size();
+ initial.gs_swizzle_data_size = initial_state.gs_swizzle_data.size();
+ initial.gs_float_uniforms_size = initial_state.gs_float_uniforms.size();
+ header.stream_size = stream.size();
+
+ initial.gpu_registers = sizeof(header);
+ initial.lcd_registers = initial.gpu_registers + initial.gpu_registers_size * sizeof(u32);
+ initial.pica_registers = initial.lcd_registers + initial.lcd_registers_size * sizeof(u32);;
+ initial.default_attributes = initial.pica_registers + initial.pica_registers_size * sizeof(u32);
+ initial.vs_program_binary = initial.default_attributes + initial.default_attributes_size * sizeof(u32);
+ initial.vs_swizzle_data = initial.vs_program_binary + initial.vs_program_binary_size * sizeof(u32);
+ initial.vs_float_uniforms = initial.vs_swizzle_data + initial.vs_swizzle_data_size * sizeof(u32);
+ initial.gs_program_binary = initial.vs_float_uniforms + initial.vs_float_uniforms_size * sizeof(u32);
+ initial.gs_swizzle_data = initial.gs_program_binary + initial.gs_program_binary_size * sizeof(u32);
+ initial.gs_float_uniforms = initial.gs_swizzle_data + initial.gs_swizzle_data_size * sizeof(u32);
+ header.stream_offset = initial.gs_float_uniforms + initial.gs_float_uniforms_size * sizeof(u32);
+
+ // Iterate through stream elements, update relevant stream element data
+ for (auto& stream_element : stream) {
+ switch (stream_element.data.type) {
+ case MemoryLoad:
+ {
+ auto& file_offset = memory_regions[stream_element.hash];
+ if (!stream_element.uses_existing_data) {
+ file_offset = header.stream_offset;
+ }
+ stream_element.data.memory_load.file_offset = file_offset;
+ break;
+ }
+
+ default:
+ // Other commands don't use any extra data
+ DEBUG_ASSERT(stream_element.extra_data.size() == 0);
+ break;
+ }
+ header.stream_offset += stream_element.extra_data.size();
+ }
+
+ try {
+ // Open file and write header
+ FileUtil::IOFile file(filename, "wb");
+ size_t written = file.WriteObject(header);
+ if (written != 1 || file.Tell() != initial.gpu_registers)
+ throw "Failed to write header";
+
+ // Write initial state
+ written = file.WriteArray(initial_state.gpu_registers.data(), initial_state.gpu_registers.size());
+ if (written != initial_state.gpu_registers.size() || file.Tell() != initial.lcd_registers)
+ throw "Failed to write GPU registers";
+
+ written = file.WriteArray(initial_state.lcd_registers.data(), initial_state.lcd_registers.size());
+ if (written != initial_state.lcd_registers.size() || file.Tell() != initial.pica_registers)
+ throw "Failed to write LCD registers";
+
+ written = file.WriteArray(initial_state.pica_registers.data(), initial_state.pica_registers.size());
+ if (written != initial_state.pica_registers.size() || file.Tell() != initial.default_attributes)
+ throw "Failed to write Pica registers";
+
+ written = file.WriteArray(initial_state.default_attributes.data(), initial_state.default_attributes.size());
+ if (written != initial_state.default_attributes.size() || file.Tell() != initial.vs_program_binary)
+ throw "Failed to write default vertex attributes";
+
+ written = file.WriteArray(initial_state.vs_program_binary.data(), initial_state.vs_program_binary.size());
+ if (written != initial_state.vs_program_binary.size() || file.Tell() != initial.vs_swizzle_data)
+ throw "Failed to write vertex shader program binary";
+
+ written = file.WriteArray(initial_state.vs_swizzle_data.data(), initial_state.vs_swizzle_data.size());
+ if (written != initial_state.vs_swizzle_data.size() || file.Tell() != initial.vs_float_uniforms)
+ throw "Failed to write vertex shader swizzle data";
+
+ written = file.WriteArray(initial_state.vs_float_uniforms.data(), initial_state.vs_float_uniforms.size());
+ if (written != initial_state.vs_float_uniforms.size() || file.Tell() != initial.gs_program_binary)
+ throw "Failed to write vertex shader float uniforms";
+
+ written = file.WriteArray(initial_state.gs_program_binary.data(), initial_state.gs_program_binary.size());
+ if (written != initial_state.gs_program_binary.size() || file.Tell() != initial.gs_swizzle_data)
+ throw "Failed to write geomtry shader program binary";
+
+ written = file.WriteArray(initial_state.gs_swizzle_data.data(), initial_state.gs_swizzle_data.size());
+ if (written != initial_state.gs_swizzle_data.size() || file.Tell() != initial.gs_float_uniforms)
+ throw "Failed to write geometry shader swizzle data";
+
+ written = file.WriteArray(initial_state.gs_float_uniforms.data(), initial_state.gs_float_uniforms.size());
+ if (written != initial_state.gs_float_uniforms.size() || file.Tell() != initial.gs_float_uniforms + sizeof(u32) * initial.gs_float_uniforms_size)
+ throw "Failed to write geometry shader float uniforms";
+
+ // Iterate through stream elements, write "extra data"
+ for (const auto& stream_element : stream) {
+ if (stream_element.extra_data.size() == 0)
+ continue;
+
+ written = file.WriteBytes(stream_element.extra_data.data(), stream_element.extra_data.size());
+ if (written != stream_element.extra_data.size())
+ throw "Failed to write extra data";
+ }
+
+ if (file.Tell() != header.stream_offset)
+ throw "Unexpected end of extra data";
+
+ // Write actual stream elements
+ for (const auto& stream_element : stream) {
+ if (1 != file.WriteObject(stream_element.data))
+ throw "Failed to write stream element";
+ }
+ } catch(const char* str) {
+ LOG_ERROR(HW_GPU, "Writing CiTrace file failed: %s", str);
+ }
+}
+
+void Recorder::FrameFinished() {
+ stream.push_back( { FrameMarker } );
+}
+
+void Recorder::MemoryAccessed(const u8* data, u32 size, u32 physical_address) {
+ StreamElement element = { MemoryLoad };
+ element.data.memory_load.size = size;
+ element.data.memory_load.physical_address = physical_address;
+
+ // Compute hash over given memory region to check if the contents are already stored internally
+ boost::crc_32_type result;
+ result.process_bytes(data, size);
+ element.hash = result.checksum();
+
+ element.uses_existing_data = (memory_regions.find(element.hash) != memory_regions.end());
+ if (!element.uses_existing_data) {
+ element.extra_data.resize(size);
+ memcpy(element.extra_data.data(), data, size);
+ memory_regions.insert({element.hash, 0}); // file offset will be initialized in Finish()
+ }
+
+ stream.push_back(element);
+}
+
+template<typename T>
+void Recorder::RegisterWritten(u32 physical_address, T value) {
+ StreamElement element = { RegisterWrite };
+ element.data.register_write.size = (sizeof(T) == 1) ? CTRegisterWrite::SIZE_8
+ : (sizeof(T) == 2) ? CTRegisterWrite::SIZE_16
+ : (sizeof(T) == 4) ? CTRegisterWrite::SIZE_32
+ : CTRegisterWrite::SIZE_64;
+ element.data.register_write.physical_address = physical_address;
+ element.data.register_write.value = value;
+
+ stream.push_back(element);
+}
+
+template void Recorder::RegisterWritten(u32,u8);
+template void Recorder::RegisterWritten(u32,u16);
+template void Recorder::RegisterWritten(u32,u32);
+template void Recorder::RegisterWritten(u32,u64);
+
+}
diff --git a/src/core/tracer/recorder.h b/src/core/tracer/recorder.h
new file mode 100644
index 00000000..6e4b7001
--- /dev/null
+++ b/src/core/tracer/recorder.h
@@ -0,0 +1,90 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <unordered_map>
+#include <vector>
+
+#include <boost/crc.hpp>
+
+#include "common/common_types.h"
+
+#include "citrace.h"
+
+namespace CiTrace {
+
+class Recorder {
+public:
+ struct InitialState {
+ std::vector<u32> gpu_registers;
+ std::vector<u32> lcd_registers;
+ std::vector<u32> pica_registers;
+ std::vector<u32> default_attributes;
+ std::vector<u32> vs_program_binary;
+ std::vector<u32> vs_swizzle_data;
+ std::vector<u32> vs_float_uniforms;
+ std::vector<u32> gs_program_binary;
+ std::vector<u32> gs_swizzle_data;
+ std::vector<u32> gs_float_uniforms;
+ };
+
+ /**
+ * Recorder constructor
+ * @param default_attributes Pointer to an array of 32-bit-aligned 24-bit floating point values.
+ * @param vs_float_uniforms Pointer to an array of 32-bit-aligned 24-bit floating point values.
+ */
+ Recorder(const InitialState& initial_state);
+
+ /// Finish recording of this Citrace and save it using the given filename.
+ void Finish(const std::string& filename);
+
+ /// Mark end of a frame
+ void FrameFinished();
+
+ /**
+ * Store a copy of the given memory range in the recording.
+ * @note Use this whenever the GPU is about to access a particular memory region.
+ * @note The implementation will make sure to minimize redundant memory updates.
+ */
+ void MemoryAccessed(const u8* data, u32 size, u32 physical_address);
+
+ /**
+ * Record a register write.
+ * @note Use this whenever a GPU-related MMIO register has been written to.
+ */
+ template<typename T>
+ void RegisterWritten(u32 physical_address, T value);
+
+private:
+ // Initial state of recording start
+ InitialState initial_state;
+
+ // Command stream
+ struct StreamElement {
+ CTStreamElement data;
+
+ /**
+ * Extra data to store along "core" data.
+ * This is e.g. used for data used in MemoryUpdates.
+ */
+ std::vector<u8> extra_data;
+
+ /// Optional CRC hash (e.g. for hashing memory regions)
+ boost::crc_32_type::value_type hash;
+
+ /// If true, refer to data already written to the output file instead of extra_data
+ bool uses_existing_data;
+ };
+
+ std::vector<StreamElement> stream;
+
+ /**
+ * Internal cache which maps hashes of memory contents to file offsets at which those memory
+ * contents are stored.
+ */
+ std::unordered_map<boost::crc_32_type::value_type /*hash*/, u32 /*file_offset*/> memory_regions;
+};
+
+} // namespace
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt
index 5c7f4ae1..16210830 100644
--- a/src/video_core/CMakeLists.txt
+++ b/src/video_core/CMakeLists.txt
@@ -2,7 +2,6 @@ set(SRCS
renderer_opengl/generated/gl_3_2_core.c
renderer_opengl/gl_rasterizer.cpp
renderer_opengl/gl_rasterizer_cache.cpp
- renderer_opengl/gl_resource_manager.cpp
renderer_opengl/gl_shader_util.cpp
renderer_opengl/gl_state.cpp
renderer_opengl/renderer_opengl.cpp
diff --git a/src/video_core/clipper.cpp b/src/video_core/clipper.cpp
index 943f3eb3..558b49d6 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) {
// NOTE: We clip against a w=epsilon plane to guarantee that the output has a positive w value.
// TODO: Not sure if this is a valid approach. Also should probably instead use the smallest
// epsilon possible within float24 accuracy.
- static const float24 EPSILON = float24::FromFloat32(0.00001);
+ static const float24 EPSILON = float24::FromFloat32(0.00001f);
static const float24 f0 = float24::FromFloat32(0.0);
static const float24 f1 = float24::FromFloat32(1.0);
static const std::array<ClippingEdge, 7> clipping_edges = {{
@@ -153,7 +153,7 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) {
"Triangle %lu/%lu at position (%.3f, %.3f, %.3f, %.3f), "
"(%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and "
"screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)",
- i, output_list->size(),
+ i + 1, output_list->size() - 2,
vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(),
vtx1.pos.x.ToFloat32(), vtx1.pos.y.ToFloat32(), vtx1.pos.z.ToFloat32(), vtx1.pos.w.ToFloat32(),
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 b46fadd9..ef9584ab 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -6,18 +6,20 @@
#include "common/profiler.h"
+#include "core/hle/service/gsp_gpu.h"
+#include "core/hw/gpu.h"
+#include "core/settings.h"
+
+#include "debug_utils/debug_utils.h"
+
#include "clipper.h"
#include "command_processor.h"
#include "math.h"
#include "pica.h"
#include "primitive_assembly.h"
+#include "renderer_base.h"
#include "vertex_shader.h"
#include "video_core.h"
-#include "core/hle/service/gsp_gpu.h"
-#include "core/hw/gpu.h"
-#include "core/settings.h"
-
-#include "debug_utils/debug_utils.h"
namespace Pica {
@@ -43,12 +45,12 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
if (GPU::g_skip_frame && id != PICA_REG_INDEX(trigger_irq))
return;
- // TODO: Figure out how register masking acts on e.g. vs_uniform_setup.set_value
+ // TODO: Figure out how register masking acts on e.g. vs.uniform_setup.set_value
u32 old_value = regs[id];
regs[id] = (old_value & ~mask) | (value & mask);
if (g_debug_context)
- g_debug_context->OnEvent(DebugContext::Event::CommandLoaded, reinterpret_cast<void*>(&id));
+ g_debug_context->OnEvent(DebugContext::Event::PicaCommandLoaded, reinterpret_cast<void*>(&id));
DebugUtils::OnPicaRegWrite(id, regs[id]);
@@ -58,10 +60,50 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D);
break;
+ // Load default vertex input attributes
+ case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233):
+ case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234):
+ case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[2], 0x235):
+ {
+ // TODO: Does actual hardware indeed keep an intermediate buffer or does
+ // it directly write the values?
+ default_attr_write_buffer[default_attr_counter++] = value;
+
+ // Default attributes are written in a packed format such that four float24 values are encoded in
+ // three 32-bit numbers. We write to internal memory once a full such vector is
+ // written.
+ if (default_attr_counter >= 3) {
+ default_attr_counter = 0;
+
+ auto& setup = regs.vs_default_attributes_setup;
+
+ if (setup.index >= 16) {
+ LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index);
+ break;
+ }
+
+ Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index];
+
+ // NOTE: The destination component order indeed is "backwards"
+ attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8);
+ attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF));
+ attribute.y = float24::FromRawFloat24(((default_attr_write_buffer[1] & 0xFFFF) << 8) | ((default_attr_write_buffer[2] >> 24) & 0xFF));
+ attribute.x = float24::FromRawFloat24(default_attr_write_buffer[2] & 0xFFFFFF);
+
+ LOG_TRACE(HW_GPU, "Set default VS attribute %x to (%f %f %f %f)", (int)setup.index,
+ attribute.x.ToFloat32(), attribute.y.ToFloat32(), attribute.z.ToFloat32(),
+ attribute.w.ToFloat32());
+
+ // TODO: Verify that this actually modifies the register!
+ setup.index = setup.index + 1;
+ }
+ break;
+ }
+
case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c):
case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d):
{
- unsigned index = id - PICA_REG_INDEX(command_buffer.trigger[0]);
+ unsigned index = static_cast<unsigned>(id - PICA_REG_INDEX(command_buffer.trigger[0]));
u32* head_ptr = (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index));
g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr;
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) {
{
Common::Profiling::ScopeTimer scope_timer(category_drawing);
+#if PICA_LOG_TEV
DebugUtils::DumpTevStageConfig(regs.GetTevStages());
+#endif
if (g_debug_context)
g_debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr);
@@ -117,9 +161,50 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
const u16* index_address_16 = (u16*)index_address_8;
bool index_u16 = index_info.format != 0;
+#if PICA_DUMP_GEOMETRY
DebugUtils::GeometryDumper geometry_dumper;
- PrimitiveAssembler<VertexShader::OutputVertex> primitive_assembler(regs.triangle_topology.Value());
PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value());
+#endif
+ PrimitiveAssembler<VertexShader::OutputVertex> primitive_assembler(regs.triangle_topology.Value());
+
+ if (g_debug_context) {
+ for (int i = 0; i < 3; ++i) {
+ const auto texture = regs.GetTextures()[i];
+ if (!texture.enabled)
+ continue;
+
+ u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
+ if (g_debug_context && Pica::g_debug_context->recorder)
+ g_debug_context->recorder->MemoryAccessed(texture_data, Pica::Regs::NibblesPerPixel(texture.format) * texture.config.width / 2 * texture.config.height, texture.config.GetPhysicalAddress());
+ }
+ }
+
+ class {
+ /// Combine overlapping and close ranges
+ void SimplifyRanges() {
+ for (auto it = ranges.begin(); it != ranges.end(); ++it) {
+ // NOTE: We add 32 to the range end address to make sure "close" ranges are combined, too
+ auto it2 = std::next(it);
+ while (it2 != ranges.end() && it->first + it->second + 32 >= it2->first) {
+ it->second = std::max(it->second, it2->first + it2->second - it->first);
+ it2 = ranges.erase(it2);
+ }
+ }
+ }
+
+ public:
+ /// Record a particular memory access in the list
+ void AddAccess(u32 paddr, u32 size) {
+ // Create new range or extend existing one
+ ranges[paddr] = std::max(ranges[paddr], size);
+
+ // Simplify ranges...
+ SimplifyRanges();
+ }
+
+ /// Map of accessed ranges (mapping start address to range size)
+ std::map<u32, u32> ranges;
+ } memory_accesses;
for (unsigned int index = 0; index < regs.num_vertices; ++index)
{
@@ -127,6 +212,10 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
if (is_indexed) {
// TODO: Implement some sort of vertex cache!
+ if (g_debug_context && Pica::g_debug_context->recorder) {
+ int size = index_u16 ? 2 : 1;
+ memory_accesses.AddAccess(base_address + index_info.offset + size * index, size);
+ }
}
// Initialize data for the current vertex
@@ -149,7 +238,14 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
// Load per-vertex data from the loader arrays
for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
- const u8* srcdata = Memory::GetPhysicalPointer(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]);
+ u32 source_addr = vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i];
+ const u8* srcdata = Memory::GetPhysicalPointer(source_addr);
+
+ if (g_debug_context && Pica::g_debug_context->recorder) {
+ memory_accesses.AddAccess(source_addr,
+ (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT) ? 4
+ : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? 2 : 1);
+ }
const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata :
(vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata :
@@ -179,6 +275,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
if (g_debug_context)
g_debug_context->OnEvent(DebugContext::Event::VertexLoaded, (void*)&input);
+#if PICA_DUMP_GEOMETRY
// NOTE: When dumping geometry, we simply assume that the first input attribute
// corresponds to the position for now.
DebugUtils::GeometryDumper::Vertex dumped_vertex = {
@@ -188,9 +285,10 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
dumping_primitive_assembler.SubmitVertex(dumped_vertex,
std::bind(&DebugUtils::GeometryDumper::AddTriangle,
&geometry_dumper, _1, _2, _3));
+#endif
// Send to vertex shader
- VertexShader::OutputVertex output = VertexShader::RunShader(input, attribute_config.GetNumTotalAttributes());
+ VertexShader::OutputVertex output = VertexShader::RunShader(input, attribute_config.GetNumTotalAttributes(), g_state.regs.vs, g_state.vs);
if (is_indexed) {
// TODO: Add processed vertex to vertex cache!
@@ -211,47 +309,55 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
}
}
+ for (auto& range : memory_accesses.ranges) {
+ g_debug_context->recorder->MemoryAccessed(Memory::GetPhysicalPointer(range.first),
+ range.second, range.first);
+ }
+
if (Settings::values.use_hw_renderer) {
VideoCore::g_renderer->hw_rasterizer->DrawTriangles();
}
+#if PICA_DUMP_GEOMETRY
geometry_dumper.Dump();
+#endif
- if (g_debug_context)
+ if (g_debug_context) {
g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr);
+ }
break;
}
- case PICA_REG_INDEX(vs_bool_uniforms):
+ case PICA_REG_INDEX(vs.bool_uniforms):
for (unsigned i = 0; i < 16; ++i)
- g_state.vs.uniforms.b[i] = (regs.vs_bool_uniforms.Value() & (1 << i)) != 0;
+ g_state.vs.uniforms.b[i] = (regs.vs.bool_uniforms.Value() & (1 << i)) != 0;
break;
- case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[0], 0x2b1):
- case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[1], 0x2b2):
- case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[2], 0x2b3):
- case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[3], 0x2b4):
+ case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[0], 0x2b1):
+ case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[1], 0x2b2):
+ case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[2], 0x2b3):
+ case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[3], 0x2b4):
{
- int index = (id - PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[0], 0x2b1));
- auto values = regs.vs_int_uniforms[index];
+ int index = (id - PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[0], 0x2b1));
+ auto values = regs.vs.int_uniforms[index];
g_state.vs.uniforms.i[index] = Math::Vec4<u8>(values.x, values.y, values.z, values.w);
LOG_TRACE(HW_GPU, "Set integer uniform %d to %02x %02x %02x %02x",
index, values.x.Value(), values.y.Value(), values.z.Value(), values.w.Value());
break;
}
- case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[0], 0x2c1):
- case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[1], 0x2c2):
- case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[2], 0x2c3):
- case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[3], 0x2c4):
- case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[4], 0x2c5):
- case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[5], 0x2c6):
- case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[6], 0x2c7):
- case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[7], 0x2c8):
+ case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[0], 0x2c1):
+ case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[1], 0x2c2):
+ case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[2], 0x2c3):
+ case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[3], 0x2c4):
+ case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[4], 0x2c5):
+ case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[5], 0x2c6):
+ case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[6], 0x2c7):
+ case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[7], 0x2c8):
{
- auto& uniform_setup = regs.vs_uniform_setup;
+ auto& uniform_setup = regs.vs.uniform_setup;
// TODO: Does actual hardware indeed keep an intermediate buffer or does
// it directly write the values?
@@ -293,73 +399,33 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
break;
}
- // Load default vertex input attributes
- case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233):
- case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234):
- case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[2], 0x235):
- {
- // TODO: Does actual hardware indeed keep an intermediate buffer or does
- // it directly write the values?
- default_attr_write_buffer[default_attr_counter++] = value;
-
- // Default attributes are written in a packed format such that four float24 values are encoded in
- // three 32-bit numbers. We write to internal memory once a full such vector is
- // written.
- if (default_attr_counter >= 3) {
- default_attr_counter = 0;
-
- auto& setup = regs.vs_default_attributes_setup;
-
- if (setup.index >= 16) {
- LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index);
- break;
- }
-
- Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index];
-
- // NOTE: The destination component order indeed is "backwards"
- attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8);
- attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF));
- attribute.y = float24::FromRawFloat24(((default_attr_write_buffer[1] & 0xFFFF) << 8) | ((default_attr_write_buffer[2] >> 24) & 0xFF));
- attribute.x = float24::FromRawFloat24(default_attr_write_buffer[2] & 0xFFFFFF);
-
- LOG_TRACE(HW_GPU, "Set default VS attribute %x to (%f %f %f %f)", (int)setup.index,
- attribute.x.ToFloat32(), attribute.y.ToFloat32(), attribute.z.ToFloat32(),
- attribute.w.ToFloat32());
-
- // TODO: Verify that this actually modifies the register!
- setup.index = setup.index + 1;
- }
- break;
- }
-
// Load shader program code
- case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[0], 0x2cc):
- case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[1], 0x2cd):
- case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[2], 0x2ce):
- case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[3], 0x2cf):
- case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[4], 0x2d0):
- case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[5], 0x2d1):
- case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[6], 0x2d2):
- case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[7], 0x2d3):
+ case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[0], 0x2cc):
+ case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[1], 0x2cd):
+ case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[2], 0x2ce):
+ case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[3], 0x2cf):
+ case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[4], 0x2d0):
+ case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[5], 0x2d1):
+ case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[6], 0x2d2):
+ case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[7], 0x2d3):
{
- g_state.vs.program_code[regs.vs_program.offset] = value;
- regs.vs_program.offset++;
+ g_state.vs.program_code[regs.vs.program.offset] = value;
+ regs.vs.program.offset++;
break;
}
// Load swizzle pattern data
- case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[0], 0x2d6):
- case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[1], 0x2d7):
- case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[2], 0x2d8):
- case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[3], 0x2d9):
- case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[4], 0x2da):
- case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[5], 0x2db):
- case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[6], 0x2dc):
- case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[7], 0x2dd):
+ case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[0], 0x2d6):
+ case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[1], 0x2d7):
+ case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[2], 0x2d8):
+ case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[3], 0x2d9):
+ case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[4], 0x2da):
+ case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[5], 0x2db):
+ case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[6], 0x2dc):
+ case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[7], 0x2dd):
{
- g_state.vs.swizzle_data[regs.vs_swizzle_patterns.offset] = value;
- regs.vs_swizzle_patterns.offset++;
+ g_state.vs.swizzle_data[regs.vs.swizzle_patterns.offset] = value;
+ regs.vs.swizzle_patterns.offset++;
break;
}
@@ -370,7 +436,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
VideoCore::g_renderer->hw_rasterizer->NotifyPicaRegisterChanged(id);
if (g_debug_context)
- g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id));
+ g_debug_context->OnEvent(DebugContext::Event::PicaCommandProcessed, reinterpret_cast<void*>(&id));
}
void ProcessCommandList(const u32* list, u32 size) {
diff --git a/src/video_core/command_processor.h b/src/video_core/command_processor.h
index bb3d4150..022a71f5 100644
--- a/src/video_core/command_processor.h
+++ b/src/video_core/command_processor.h
@@ -4,11 +4,11 @@
#pragma once
+#include <type_traits>
+
#include "common/bit_field.h"
#include "common/common_types.h"
-#include "pica.h"
-
namespace Pica {
namespace CommandProcessor {
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 7b8ab72b..e9a85841 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -23,6 +23,7 @@
#include "common/vector_math.h"
#include "video_core/pica.h"
+#include "video_core/renderer_base.h"
#include "video_core/utils.h"
#include "video_core/video_core.h"
@@ -84,15 +85,11 @@ void GeometryDumper::AddTriangle(Vertex& v0, Vertex& v1, Vertex& v2) {
vertices.push_back(v1);
vertices.push_back(v2);
- int num_vertices = vertices.size();
+ int num_vertices = (int)vertices.size();
faces.push_back({ num_vertices-3, num_vertices-2, num_vertices-1 });
}
void GeometryDumper::Dump() {
- // NOTE: Permanently enabling this just trashes the hard disk for no reason.
- // Hence, this is currently disabled.
- return;
-
static int index = 0;
std::string filename = std::string("geometry_dump") + std::to_string(++index) + ".obj";
@@ -115,10 +112,6 @@ void GeometryDumper::Dump() {
void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data, u32 swizzle_size,
u32 main_offset, const Regs::VSOutputAttributes* output_attributes)
{
- // NOTE: Permanently enabling this just trashes hard disks for no reason.
- // Hence, this is currently disabled.
- return;
-
struct StuffToWrite {
u8* pointer;
u32 size;
@@ -240,8 +233,8 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data
dvle.main_offset_words = main_offset;
dvle.output_register_table_offset = write_offset - dvlb.dvle_offset;
- dvle.output_register_table_size = output_info_table.size();
- QueueForWriting((u8*)output_info_table.data(), output_info_table.size() * sizeof(OutputRegisterInfo));
+ dvle.output_register_table_size = static_cast<uint32_t>(output_info_table.size());
+ QueueForWriting((u8*)output_info_table.data(), static_cast<u32>(output_info_table.size() * sizeof(OutputRegisterInfo)));
// TODO: Create a label table for "main"
@@ -496,31 +489,31 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
// Lookup base value
Math::Vec3<int> ret;
if (differential_mode) {
- ret.r() = differential.r;
- ret.g() = differential.g;
- ret.b() = differential.b;
+ ret.r() = static_cast<int>(differential.r);
+ ret.g() = static_cast<int>(differential.g);
+ ret.b() = static_cast<int>(differential.b);
if (x >= 2) {
- ret.r() += differential.dr;
- ret.g() += differential.dg;
- ret.b() += differential.db;
+ ret.r() += static_cast<int>(differential.dr);
+ ret.g() += static_cast<int>(differential.dg);
+ ret.b() += static_cast<int>(differential.db);
}
ret.r() = Color::Convert5To8(ret.r());
ret.g() = Color::Convert5To8(ret.g());
ret.b() = Color::Convert5To8(ret.b());
} else {
if (x < 2) {
- ret.r() = Color::Convert4To8(separate.r1);
- ret.g() = Color::Convert4To8(separate.g1);
- ret.b() = Color::Convert4To8(separate.b1);
+ ret.r() = Color::Convert4To8(static_cast<u8>(separate.r1));
+ ret.g() = Color::Convert4To8(static_cast<u8>(separate.g1));
+ ret.b() = Color::Convert4To8(static_cast<u8>(separate.b1));
} else {
- ret.r() = Color::Convert4To8(separate.r2);
- ret.g() = Color::Convert4To8(separate.g2);
- ret.b() = Color::Convert4To8(separate.b2);
+ ret.r() = Color::Convert4To8(static_cast<u8>(separate.r2));
+ ret.g() = Color::Convert4To8(static_cast<u8>(separate.g2));
+ ret.b() = Color::Convert4To8(static_cast<u8>(separate.b2));
}
}
// Add modifier
- unsigned table_index = (x < 2) ? table_index_1.Value() : table_index_2.Value();
+ unsigned table_index = static_cast<int>((x < 2) ? table_index_1.Value() : table_index_2.Value());
static const std::array<std::array<u8, 2>, 8> etc1_modifier_table = {{
{ 2, 8 }, { 5, 17 }, { 9, 29 }, { 13, 42 },
@@ -564,10 +557,6 @@ TextureInfo TextureInfo::FromPicaRegister(const Regs::TextureConfig& config,
}
void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
- // NOTE: Permanently enabling this just trashes hard disks for no reason.
- // Hence, this is currently disabled.
- return;
-
#ifndef HAVE_PNG
return;
#else
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
index 7926d64e..81eea30a 100644
--- a/src/video_core/debug_utils/debug_utils.h
+++ b/src/video_core/debug_utils/debug_utils.h
@@ -14,6 +14,8 @@
#include "common/vector_math.h"
+#include "core/tracer/recorder.h"
+
#include "video_core/pica.h"
namespace Pica {
@@ -23,11 +25,14 @@ public:
enum class Event {
FirstEvent = 0,
- CommandLoaded = FirstEvent,
- CommandProcessed,
+ PicaCommandLoaded = FirstEvent,
+ PicaCommandProcessed,
IncomingPrimitiveBatch,
FinishedPrimitiveBatch,
VertexLoaded,
+ IncomingDisplayTransfer,
+ GSPCommandProcessed,
+ BufferSwapped,
NumEvents
};
@@ -129,6 +134,8 @@ public:
Event active_breakpoint;
bool at_breakpoint = false;
+ std::shared_ptr<CiTrace::Recorder> recorder = nullptr;
+
private:
/**
* 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
namespace DebugUtils {
+#define PICA_DUMP_GEOMETRY 0
+#define PICA_DUMP_SHADERS 0
+#define PICA_DUMP_TEXTURES 0
+#define PICA_LOG_TEV 0
+
// Simple utility class for dumping geometry data to an OBJ file
class GeometryDumper {
public:
diff --git a/src/video_core/hwrasterizer_base.h b/src/video_core/hwrasterizer_base.h
index dec193f8..c8746c60 100644
--- a/src/video_core/hwrasterizer_base.h
+++ b/src/video_core/hwrasterizer_base.h
@@ -4,8 +4,13 @@
#pragma once
-#include "common/emu_window.h"
-#include "video_core/vertex_shader.h"
+#include "common/common_types.h"
+
+namespace Pica {
+namespace VertexShader {
+struct OutputVertex;
+}
+}
class HWRasterizer {
public:
diff --git a/src/video_core/pica.cpp b/src/video_core/pica.cpp
index 543d9c44..17cb6678 100644
--- a/src/video_core/pica.cpp
+++ b/src/video_core/pica.cpp
@@ -2,7 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <string.h>
+#include <cstring>
+#include <unordered_map>
#include "pica.h"
@@ -10,6 +11,75 @@ namespace Pica {
State g_state;
+std::string Regs::GetCommandName(int index) {
+ static std::unordered_map<u32, std::string> map;
+
+ if (map.empty()) {
+ #define ADD_FIELD(name) \
+ map.insert({static_cast<u32>(PICA_REG_INDEX(name)), #name}); \
+ /* TODO: change to Regs::name when VS2015 and other compilers support it */ \
+ for (u32 i = PICA_REG_INDEX(name) + 1; i < PICA_REG_INDEX(name) + sizeof(Regs().name) / 4; ++i) \
+ map.insert({i, #name + std::string("+") + std::to_string(i-PICA_REG_INDEX(name))}); \
+
+ ADD_FIELD(trigger_irq);
+ ADD_FIELD(cull_mode);
+ ADD_FIELD(viewport_size_x);
+ ADD_FIELD(viewport_size_y);
+ ADD_FIELD(viewport_depth_range);
+ ADD_FIELD(viewport_depth_far_plane);
+ ADD_FIELD(viewport_corner);
+ ADD_FIELD(texture0_enable);
+ ADD_FIELD(texture0);
+ ADD_FIELD(texture0_format);
+ ADD_FIELD(texture1);
+ ADD_FIELD(texture1_format);
+ ADD_FIELD(texture2);
+ ADD_FIELD(texture2_format);
+ ADD_FIELD(tev_stage0);
+ ADD_FIELD(tev_stage1);
+ ADD_FIELD(tev_stage2);
+ ADD_FIELD(tev_stage3);
+ ADD_FIELD(tev_combiner_buffer_input);
+ ADD_FIELD(tev_stage4);
+ ADD_FIELD(tev_stage5);
+ ADD_FIELD(tev_combiner_buffer_color);
+ ADD_FIELD(output_merger);
+ ADD_FIELD(framebuffer);
+ ADD_FIELD(vertex_attributes);
+ ADD_FIELD(index_array);
+ ADD_FIELD(num_vertices);
+ ADD_FIELD(trigger_draw);
+ ADD_FIELD(trigger_draw_indexed);
+ ADD_FIELD(vs_default_attributes_setup);
+ ADD_FIELD(command_buffer);
+ ADD_FIELD(triangle_topology);
+ ADD_FIELD(gs.bool_uniforms);
+ ADD_FIELD(gs.int_uniforms);
+ ADD_FIELD(gs.main_offset);
+ ADD_FIELD(gs.input_register_map);
+ ADD_FIELD(gs.uniform_setup);
+ ADD_FIELD(gs.program);
+ ADD_FIELD(gs.swizzle_patterns);
+ ADD_FIELD(vs.bool_uniforms);
+ ADD_FIELD(vs.int_uniforms);
+ ADD_FIELD(vs.main_offset);
+ ADD_FIELD(vs.input_register_map);
+ ADD_FIELD(vs.uniform_setup);
+ ADD_FIELD(vs.program);
+ ADD_FIELD(vs.swizzle_patterns);
+
+#undef ADD_FIELD
+ }
+
+ // Return empty string if no match is found
+ auto it = map.find(index);
+ if (it != map.end()) {
+ return it->second;
+ } else {
+ return std::string();
+ }
+}
+
void Init() {
}
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 9628a758..34b02b2f 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -5,10 +5,9 @@
#pragma once
#include <array>
+#include <cmath>
#include <cstddef>
-#include <initializer_list>
-#include <map>
-#include <vector>
+#include <string>
#include "common/assert.h"
#include "common/bit_field.h"
@@ -114,11 +113,22 @@ struct Regs {
struct TextureConfig {
enum WrapMode : u32 {
ClampToEdge = 0,
+ ClampToBorder = 1,
Repeat = 2,
MirroredRepeat = 3,
};
- INSERT_PADDING_WORDS(0x1);
+ enum TextureFilter : u32 {
+ Nearest = 0,
+ Linear = 1
+ };
+
+ union {
+ BitField< 0, 8, u32> r;
+ BitField< 8, 8, u32> g;
+ BitField<16, 8, u32> b;
+ BitField<24, 8, u32> a;
+ } border_color;
union {
BitField< 0, 16, u32> height;
@@ -126,8 +136,10 @@ struct Regs {
};
union {
- BitField< 8, 2, WrapMode> wrap_s;
- BitField<12, 2, WrapMode> wrap_t;
+ BitField< 1, 1, TextureFilter> mag_filter;
+ BitField< 2, 1, TextureFilter> min_filter;
+ BitField< 8, 2, WrapMode> wrap_t;
+ BitField<12, 2, WrapMode> wrap_s;
};
INSERT_PADDING_WORDS(0x1);
@@ -194,6 +206,7 @@ struct Regs {
case TextureFormat::IA8:
return 4;
+ case TextureFormat::I4:
case TextureFormat::A4:
return 1;
@@ -284,6 +297,7 @@ struct Regs {
AddSigned = 3,
Lerp = 4,
Subtract = 5,
+ Dot3_RGB = 6,
MultiplyThenAdd = 8,
AddThenMultiply = 9,
@@ -414,6 +428,11 @@ struct Regs {
GreaterThanOrEqual = 7,
};
+ enum class StencilAction : u32 {
+ Keep = 0,
+ Xor = 5,
+ };
+
struct {
union {
// If false, logic blending is used
@@ -448,15 +467,35 @@ struct Regs {
BitField< 8, 8, u32> ref;
} alpha_test;
- union {
- BitField< 0, 1, u32> stencil_test_enable;
- BitField< 4, 3, CompareFunc> stencil_test_func;
- BitField< 8, 8, u32> stencil_replacement_value;
- BitField<16, 8, u32> stencil_reference_value;
- BitField<24, 8, u32> stencil_mask;
- } stencil_test;
+ struct {
+ union {
+ // If true, enable stencil testing
+ BitField< 0, 1, u32> enable;
- INSERT_PADDING_WORDS(0x1);
+ // Comparison operation for stencil testing
+ BitField< 4, 3, CompareFunc> func;
+
+ // Value to calculate the new stencil value from
+ BitField< 8, 8, u32> replacement_value;
+
+ // Value to compare against for stencil testing
+ BitField<16, 8, u32> reference_value;
+
+ // Mask to apply on stencil test inputs
+ BitField<24, 8, u32> mask;
+ };
+
+ union {
+ // Action to perform when the stencil test fails
+ BitField< 0, 3, StencilAction> action_stencil_fail;
+
+ // Action to perform when stencil testing passed but depth testing fails
+ BitField< 4, 3, StencilAction> action_depth_fail;
+
+ // Action to perform when both stencil and depth testing pass
+ BitField< 8, 3, StencilAction> action_depth_pass;
+ };
+ } stencil_test;
union {
BitField< 0, 1, u32> depth_test_enable;
@@ -506,7 +545,7 @@ struct Regs {
struct {
INSERT_PADDING_WORDS(0x6);
- DepthFormat depth_format;
+ DepthFormat depth_format; // TODO: Should be a BitField!
BitField<16, 3, ColorFormat> color_format;
INSERT_PADDING_WORDS(0x4);
@@ -752,171 +791,123 @@ struct Regs {
INSERT_PADDING_WORDS(0x20);
enum class TriangleTopology : u32 {
- List = 0,
- Strip = 1,
- Fan = 2,
- ListIndexed = 3, // TODO: No idea if this is correct
+ List = 0,
+ Strip = 1,
+ Fan = 2,
+ Shader = 3, // Programmable setup unit implemented in a geometry shader
};
BitField<8, 2, TriangleTopology> triangle_topology;
- INSERT_PADDING_WORDS(0x51);
+ INSERT_PADDING_WORDS(0x21);
- BitField<0, 16, u32> vs_bool_uniforms;
- union {
- BitField< 0, 8, u32> x;
- BitField< 8, 8, u32> y;
- BitField<16, 8, u32> z;
- BitField<24, 8, u32> w;
- } vs_int_uniforms[4];
+ struct ShaderConfig {
+ BitField<0, 16, u32> bool_uniforms;
- INSERT_PADDING_WORDS(0x5);
+ union {
+ BitField< 0, 8, u32> x;
+ BitField< 8, 8, u32> y;
+ BitField<16, 8, u32> z;
+ BitField<24, 8, u32> w;
+ } int_uniforms[4];
- // Offset to shader program entry point (in words)
- BitField<0, 16, u32> vs_main_offset;
+ INSERT_PADDING_WORDS(0x5);
- union {
- BitField< 0, 4, u64> attribute0_register;
- BitField< 4, 4, u64> attribute1_register;
- BitField< 8, 4, u64> attribute2_register;
- BitField<12, 4, u64> attribute3_register;
- BitField<16, 4, u64> attribute4_register;
- BitField<20, 4, u64> attribute5_register;
- BitField<24, 4, u64> attribute6_register;
- BitField<28, 4, u64> attribute7_register;
- BitField<32, 4, u64> attribute8_register;
- BitField<36, 4, u64> attribute9_register;
- BitField<40, 4, u64> attribute10_register;
- BitField<44, 4, u64> attribute11_register;
- BitField<48, 4, u64> attribute12_register;
- BitField<52, 4, u64> attribute13_register;
- BitField<56, 4, u64> attribute14_register;
- BitField<60, 4, u64> attribute15_register;
-
- int GetRegisterForAttribute(int attribute_index) const {
- u64 fields[] = {
- attribute0_register, attribute1_register, attribute2_register, attribute3_register,
- attribute4_register, attribute5_register, attribute6_register, attribute7_register,
- attribute8_register, attribute9_register, attribute10_register, attribute11_register,
- attribute12_register, attribute13_register, attribute14_register, attribute15_register,
+ // Offset to shader program entry point (in words)
+ BitField<0, 16, u32> main_offset;
+
+ union {
+ BitField< 0, 4, u64> attribute0_register;
+ BitField< 4, 4, u64> attribute1_register;
+ BitField< 8, 4, u64> attribute2_register;
+ BitField<12, 4, u64> attribute3_register;
+ BitField<16, 4, u64> attribute4_register;
+ BitField<20, 4, u64> attribute5_register;
+ BitField<24, 4, u64> attribute6_register;
+ BitField<28, 4, u64> attribute7_register;
+ BitField<32, 4, u64> attribute8_register;
+ BitField<36, 4, u64> attribute9_register;
+ BitField<40, 4, u64> attribute10_register;
+ BitField<44, 4, u64> attribute11_register;
+ BitField<48, 4, u64> attribute12_register;
+ BitField<52, 4, u64> attribute13_register;
+ BitField<56, 4, u64> attribute14_register;
+ BitField<60, 4, u64> attribute15_register;
+
+ int GetRegisterForAttribute(int attribute_index) const {
+ u64 fields[] = {
+ attribute0_register, attribute1_register, attribute2_register, attribute3_register,
+ attribute4_register, attribute5_register, attribute6_register, attribute7_register,
+ attribute8_register, attribute9_register, attribute10_register, attribute11_register,
+ attribute12_register, attribute13_register, attribute14_register, attribute15_register,
+ };
+ return (int)fields[attribute_index];
+ }
+ } input_register_map;
+
+ // OUTMAP_MASK, 0x28E, CODETRANSFER_END
+ INSERT_PADDING_WORDS(0x3);
+
+ struct {
+ enum Format : u32
+ {
+ FLOAT24 = 0,
+ FLOAT32 = 1
};
- return (int)fields[attribute_index];
- }
- } vs_input_register_map;
- INSERT_PADDING_WORDS(0x3);
+ bool IsFloat32() const {
+ return format == FLOAT32;
+ }
- struct {
- enum Format : u32
- {
- FLOAT24 = 0,
- FLOAT32 = 1
- };
+ union {
+ // Index of the next uniform to write to
+ // TODO: ctrulib uses 8 bits for this, however that seems to yield lots of invalid indices
+ // TODO: Maybe the uppermost index is for the geometry shader? Investigate!
+ BitField<0, 7, u32> index;
- bool IsFloat32() const {
- return format == FLOAT32;
- }
+ BitField<31, 1, Format> format;
+ };
- union {
- // Index of the next uniform to write to
- // TODO: ctrulib uses 8 bits for this, however that seems to yield lots of invalid indices
- BitField<0, 7, u32> index;
+ // Writing to these registers sets the current uniform.
+ u32 set_value[8];
- BitField<31, 1, Format> format;
- };
+ } uniform_setup;
- // Writing to these registers sets the "current" uniform.
- // TODO: It's not clear how the hardware stores what the "current" uniform is.
- u32 set_value[8];
+ INSERT_PADDING_WORDS(0x2);
- } vs_uniform_setup;
+ struct {
+ // Offset of the next instruction to write code to.
+ // Incremented with each instruction write.
+ u32 offset;
- INSERT_PADDING_WORDS(0x2);
+ // Writing to these registers sets the "current" word in the shader program.
+ u32 set_word[8];
+ } program;
- struct {
- // Offset of the next instruction to write code to.
- // Incremented with each instruction write.
- u32 offset;
+ INSERT_PADDING_WORDS(0x1);
- // Writing to these registers sets the "current" word in the shader program.
- // TODO: It's not clear how the hardware stores what the "current" word is.
- u32 set_word[8];
- } vs_program;
+ // This register group is used to load an internal table of swizzling patterns,
+ // which are indexed by each shader instruction to specify vector component swizzling.
+ struct {
+ // Offset of the next swizzle pattern to write code to.
+ // Incremented with each instruction write.
+ u32 offset;
- INSERT_PADDING_WORDS(0x1);
+ // Writing to these registers sets the current swizzle pattern in the table.
+ u32 set_word[8];
+ } swizzle_patterns;
- // This register group is used to load an internal table of swizzling patterns,
- // which are indexed by each shader instruction to specify vector component swizzling.
- struct {
- // Offset of the next swizzle pattern to write code to.
- // Incremented with each instruction write.
- u32 offset;
+ INSERT_PADDING_WORDS(0x2);
+ };
- // Writing to these registers sets the "current" swizzle pattern in the table.
- // TODO: It's not clear how the hardware stores what the "current" swizzle pattern is.
- u32 set_word[8];
- } vs_swizzle_patterns;
+ ShaderConfig gs;
+ ShaderConfig vs;
- INSERT_PADDING_WORDS(0x22);
+ INSERT_PADDING_WORDS(0x20);
// Map register indices to names readable by humans
// Used for debugging purposes, so performance is not an issue here
- static std::string GetCommandName(int index) {
- std::map<u32, std::string> map;
-
- #define ADD_FIELD(name) \
- do { \
- map.insert({PICA_REG_INDEX(name), #name}); \
- /* TODO: change to Regs::name when VS2015 and other compilers support it */ \
- for (u32 i = PICA_REG_INDEX(name) + 1; i < PICA_REG_INDEX(name) + sizeof(Regs().name) / 4; ++i) \
- map.insert({i, #name + std::string("+") + std::to_string(i-PICA_REG_INDEX(name))}); \
- } while(false)
-
- ADD_FIELD(trigger_irq);
- ADD_FIELD(cull_mode);
- ADD_FIELD(viewport_size_x);
- ADD_FIELD(viewport_size_y);
- ADD_FIELD(viewport_depth_range);
- ADD_FIELD(viewport_depth_far_plane);
- ADD_FIELD(viewport_corner);
- ADD_FIELD(texture0_enable);
- ADD_FIELD(texture0);
- ADD_FIELD(texture0_format);
- ADD_FIELD(texture1);
- ADD_FIELD(texture1_format);
- ADD_FIELD(texture2);
- ADD_FIELD(texture2_format);
- ADD_FIELD(tev_stage0);
- ADD_FIELD(tev_stage1);
- ADD_FIELD(tev_stage2);
- ADD_FIELD(tev_stage3);
- ADD_FIELD(tev_combiner_buffer_input);
- ADD_FIELD(tev_stage4);
- ADD_FIELD(tev_stage5);
- ADD_FIELD(tev_combiner_buffer_color);
- ADD_FIELD(output_merger);
- ADD_FIELD(framebuffer);
- ADD_FIELD(vertex_attributes);
- ADD_FIELD(index_array);
- ADD_FIELD(num_vertices);
- ADD_FIELD(trigger_draw);
- ADD_FIELD(trigger_draw_indexed);
- ADD_FIELD(vs_default_attributes_setup);
- ADD_FIELD(command_buffer);
- ADD_FIELD(triangle_topology);
- ADD_FIELD(vs_bool_uniforms);
- ADD_FIELD(vs_int_uniforms);
- ADD_FIELD(vs_main_offset);
- ADD_FIELD(vs_input_register_map);
- ADD_FIELD(vs_uniform_setup);
- ADD_FIELD(vs_program);
- ADD_FIELD(vs_swizzle_patterns);
-
- #undef ADD_FIELD
-
- // Return empty string if no match is found
- return map[index];
- }
+ static std::string GetCommandName(int index);
static inline size_t NumIds() {
return sizeof(Regs) / sizeof(u32);
@@ -982,17 +973,14 @@ ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f);
ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232);
ASSERT_REG_POSITION(command_buffer, 0x238);
ASSERT_REG_POSITION(triangle_topology, 0x25e);
-ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0);
-ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1);
-ASSERT_REG_POSITION(vs_main_offset, 0x2ba);
-ASSERT_REG_POSITION(vs_input_register_map, 0x2bb);
-ASSERT_REG_POSITION(vs_uniform_setup, 0x2c0);
-ASSERT_REG_POSITION(vs_program, 0x2cb);
-ASSERT_REG_POSITION(vs_swizzle_patterns, 0x2d5);
+ASSERT_REG_POSITION(gs, 0x280);
+ASSERT_REG_POSITION(vs, 0x2b0);
#undef ASSERT_REG_POSITION
#endif // !defined(_MSC_VER)
+static_assert(sizeof(Regs::ShaderConfig) == 0x30 * sizeof(u32), "ShaderConfig structure has incorrect size");
+
// The total number of registers is chosen arbitrarily, but let's make sure it's not some odd value anyway.
static_assert(sizeof(Regs) <= 0x300 * sizeof(u32), "Register set structure larger than it should be");
static_assert(sizeof(Regs) >= 0x300 * sizeof(u32), "Register set structure smaller than it should be");
@@ -1014,7 +1002,7 @@ struct float24 {
u32 mantissa = hex & 0xFFFF;
u32 exponent = (hex >> 16) & 0x7F;
u32 sign = hex >> 23;
- ret.value = powf(2.0f, (float)exponent-63.0f) * (1.0f + mantissa * powf(2.0f, -16.f));
+ ret.value = std::pow(2.0f, (float)exponent-63.0f) * (1.0f + mantissa * std::pow(2.0f, -16.f));
if (sign)
ret.value = -ret.value;
}
@@ -1102,7 +1090,7 @@ struct State {
Regs regs;
/// Vertex shader memory
- struct {
+ struct ShaderSetup {
struct {
Math::Vec4<float24> f[96];
std::array<bool, 16> b;
@@ -1113,7 +1101,10 @@ struct State {
std::array<u32, 1024> program_code;
std::array<u32, 1024> swizzle_data;
- } vs;
+ };
+
+ ShaderSetup vs;
+ ShaderSetup gs;
/// Current Pica command list
struct {
diff --git a/src/video_core/primitive_assembly.cpp b/src/video_core/primitive_assembly.cpp
index 0120f289..2f22bdcc 100644
--- a/src/video_core/primitive_assembly.cpp
+++ b/src/video_core/primitive_assembly.cpp
@@ -20,8 +20,9 @@ template<typename VertexType>
void PrimitiveAssembler<VertexType>::SubmitVertex(VertexType& vtx, TriangleHandler triangle_handler)
{
switch (topology) {
+ // TODO: Figure out what's different with TriangleTopology::Shader.
case Regs::TriangleTopology::List:
- case Regs::TriangleTopology::ListIndexed:
+ case Regs::TriangleTopology::Shader:
if (buffer_index < 2) {
buffer[buffer_index++] = vtx;
} else {
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 59d156ee..68b7cc05 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -126,6 +126,30 @@ static u32 GetDepth(int x, int y) {
}
}
+static u8 GetStencil(int x, int y) {
+ const auto& framebuffer = g_state.regs.framebuffer;
+ const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
+ u8* depth_buffer = Memory::GetPhysicalPointer(addr);
+
+ y = framebuffer.height - y;
+
+ const u32 coarse_y = y & ~7;
+ u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format);
+ u32 stride = framebuffer.width * bytes_per_pixel;
+
+ u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
+ u8* src_pixel = depth_buffer + src_offset;
+
+ switch (framebuffer.depth_format) {
+ case Regs::DepthFormat::D24S8:
+ return Color::DecodeD24S8(src_pixel).y;
+
+ default:
+ LOG_WARNING(HW_GPU, "GetStencil called for function which doesn't have a stencil component (format %u)", framebuffer.depth_format);
+ return 0;
+ }
+}
+
static void SetDepth(int x, int y, u32 value) {
const auto& framebuffer = g_state.regs.framebuffer;
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
@@ -144,13 +168,15 @@ static void SetDepth(int x, int y, u32 value) {
case Regs::DepthFormat::D16:
Color::EncodeD16(value, dst_pixel);
break;
+
case Regs::DepthFormat::D24:
Color::EncodeD24(value, dst_pixel);
break;
+
case Regs::DepthFormat::D24S8:
- // TODO(Subv): Implement the stencil buffer
- Color::EncodeD24S8(value, 0, dst_pixel);
+ Color::EncodeD24X8(value, dst_pixel);
break;
+
default:
LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
UNIMPLEMENTED();
@@ -158,6 +184,53 @@ static void SetDepth(int x, int y, u32 value) {
}
}
+static void SetStencil(int x, int y, u8 value) {
+ const auto& framebuffer = g_state.regs.framebuffer;
+ const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
+ u8* depth_buffer = Memory::GetPhysicalPointer(addr);
+
+ y = framebuffer.height - y;
+
+ const u32 coarse_y = y & ~7;
+ u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format);
+ u32 stride = framebuffer.width * bytes_per_pixel;
+
+ u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
+ u8* dst_pixel = depth_buffer + dst_offset;
+
+ switch (framebuffer.depth_format) {
+ case Pica::Regs::DepthFormat::D16:
+ case Pica::Regs::DepthFormat::D24:
+ // Nothing to do
+ break;
+
+ case Pica::Regs::DepthFormat::D24S8:
+ Color::EncodeX24S8(value, dst_pixel);
+ break;
+
+ default:
+ LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
+ UNIMPLEMENTED();
+ break;
+ }
+}
+
+// TODO: Should the stencil mask be applied to the "dest" or "ref" operands? Most likely not!
+static u8 PerformStencilAction(Regs::StencilAction action, u8 dest, u8 ref) {
+ switch (action) {
+ case Regs::StencilAction::Keep:
+ return dest;
+
+ case Regs::StencilAction::Xor:
+ return dest ^ ref;
+
+ default:
+ LOG_CRITICAL(HW_GPU, "Unknown stencil action %x", (int)action);
+ UNIMPLEMENTED();
+ return 0;
+ }
+}
+
// NOTE: Assuming that rasterizer coordinates are 12.4 fixed-point values
struct Fix12P4 {
Fix12P4() {}
@@ -276,6 +349,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
auto textures = regs.GetTextures();
auto tev_stages = regs.GetTevStages();
+ bool stencil_action_enable = g_state.regs.output_merger.stencil_test.enable && g_state.regs.framebuffer.depth_format == Regs::DepthFormat::D24S8;
+ const auto stencil_test = g_state.regs.output_merger.stencil_test;
+
// Enter rasterization loop, starting at the center of the topleft bounding box corner.
// TODO: Not sure if looping through x first might be faster
for (u16 y = min_y + 8; y < max_y; y += 0x10) {
@@ -349,6 +425,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
val = std::min(val, (int)size - 1);
return val;
+ case Regs::TextureConfig::ClampToBorder:
+ return val;
+
case Regs::TextureConfig::Repeat:
return (int)((unsigned)val % size);
@@ -367,17 +446,26 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
}
};
- // Textures are laid out from bottom to top, hence we invert the t coordinate.
- // NOTE: This may not be the right place for the inversion.
- // TODO: Check if this applies to ETC textures, too.
- s = GetWrappedTexCoord(texture.config.wrap_s, s, texture.config.width);
- t = texture.config.height - 1 - GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height);
-
- u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
- auto info = DebugUtils::TextureInfo::FromPicaRegister(texture.config, texture.format);
-
- texture_color[i] = DebugUtils::LookupTexture(texture_data, s, t, info);
- DebugUtils::DumpTexture(texture.config, texture_data);
+ if ((texture.config.wrap_s == Regs::TextureConfig::ClampToBorder && (s < 0 || s >= texture.config.width))
+ || (texture.config.wrap_t == Regs::TextureConfig::ClampToBorder && (t < 0 || t >= texture.config.height))) {
+ auto border_color = texture.config.border_color;
+ texture_color[i] = { border_color.r, border_color.g, border_color.b, border_color.a };
+ } else {
+ // Textures are laid out from bottom to top, hence we invert the t coordinate.
+ // NOTE: This may not be the right place for the inversion.
+ // TODO: Check if this applies to ETC textures, too.
+ s = GetWrappedTexCoord(texture.config.wrap_s, s, texture.config.width);
+ t = texture.config.height - 1 - GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height);
+
+ u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
+ auto info = DebugUtils::TextureInfo::FromPicaRegister(texture.config, texture.format);
+
+ // TODO: Apply the min and mag filters to the texture
+ texture_color[i] = DebugUtils::LookupTexture(texture_data, s, t, info);
+#if PICA_DUMP_TEXTURES
+ DebugUtils::DumpTexture(texture.config, texture_data);
+#endif
+ }
}
// Texture environment - consists of 6 stages of color and alpha combining.
@@ -556,7 +644,18 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
result = (result * input[2].Cast<int>()) / 255;
return result.Cast<u8>();
}
-
+ case Operation::Dot3_RGB:
+ {
+ // Not fully accurate.
+ // Worst case scenario seems to yield a +/-3 error
+ // Some HW results indicate that the per-component computation can't have a higher precision than 1/256,
+ // while dot3_rgb( (0x80,g0,b0),(0x7F,g1,b1) ) and dot3_rgb( (0x80,g0,b0),(0x80,g1,b1) ) give different results
+ int result = ((input[0].r() * 2 - 255) * (input[1].r() * 2 - 255) + 128) / 256 +
+ ((input[0].g() * 2 - 255) * (input[1].g() * 2 - 255) + 128) / 256 +
+ ((input[0].b() * 2 - 255) * (input[1].b() * 2 - 255) + 128) / 256;
+ result = std::max(0, std::min(255, result));
+ return { (u8)result, (u8)result, (u8)result };
+ }
default:
LOG_ERROR(HW_GPU, "Unknown color combiner operation %d\n", (int)op);
UNIMPLEMENTED();
@@ -638,6 +737,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
}
const auto& output_merger = regs.output_merger;
+ // TODO: Does alpha testing happen before or after stencil?
if (output_merger.alpha_test.enable) {
bool pass = false;
@@ -679,6 +779,54 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
continue;
}
+ u8 old_stencil = 0;
+ if (stencil_action_enable) {
+ old_stencil = GetStencil(x >> 4, y >> 4);
+ u8 dest = old_stencil & stencil_test.mask;
+ u8 ref = stencil_test.reference_value & stencil_test.mask;
+
+ bool pass = false;
+ switch (stencil_test.func) {
+ case Regs::CompareFunc::Never:
+ pass = false;
+ break;
+
+ case Regs::CompareFunc::Always:
+ pass = true;
+ break;
+
+ case Regs::CompareFunc::Equal:
+ pass = (ref == dest);
+ break;
+
+ case Regs::CompareFunc::NotEqual:
+ pass = (ref != dest);
+ break;
+
+ case Regs::CompareFunc::LessThan:
+ pass = (ref < dest);
+ break;
+
+ case Regs::CompareFunc::LessThanOrEqual:
+ pass = (ref <= dest);
+ break;
+
+ case Regs::CompareFunc::GreaterThan:
+ pass = (ref > dest);
+ break;
+
+ case Regs::CompareFunc::GreaterThanOrEqual:
+ pass = (ref >= dest);
+ break;
+ }
+
+ if (!pass) {
+ u8 new_stencil = PerformStencilAction(stencil_test.action_stencil_fail, old_stencil, stencil_test.replacement_value);
+ SetStencil(x >> 4, y >> 4, new_stencil);
+ continue;
+ }
+ }
+
// TODO: Does depth indeed only get written even if depth testing is enabled?
if (output_merger.depth_test_enable) {
unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format);
@@ -723,11 +871,22 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
break;
}
- if (!pass)
+ if (!pass) {
+ if (stencil_action_enable) {
+ u8 new_stencil = PerformStencilAction(stencil_test.action_depth_fail, old_stencil, stencil_test.replacement_value);
+ SetStencil(x >> 4, y >> 4, new_stencil);
+ }
continue;
+ }
if (output_merger.depth_write_enable)
SetDepth(x >> 4, y >> 4, z);
+
+ if (stencil_action_enable) {
+ // TODO: What happens if stencil testing is enabled, but depth testing is not? Will stencil get updated anyway?
+ u8 new_stencil = PerformStencilAction(stencil_test.action_depth_pass, old_stencil, stencil_test.replacement_value);
+ SetStencil(x >> 4, y >> 4, new_stencil);
+ }
}
auto dest = GetPixel(x >> 4, y >> 4);
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 5757ac75..6587bcf2 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -4,10 +4,14 @@
#pragma once
+#include <memory>
+
#include "common/common_types.h"
#include "video_core/hwrasterizer_base.h"
+class EmuWindow;
+
class RendererBase : NonCopyable {
public:
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 518f7933..2db845da 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -2,10 +2,15 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
+#include <memory>
+
#include "common/color.h"
+#include "common/math_util.h"
-#include "core/settings.h"
#include "core/hw/gpu.h"
+#include "core/memory.h"
+#include "core/settings.h"
#include "video_core/pica.h"
#include "video_core/utils.h"
@@ -16,8 +21,6 @@
#include "generated/gl_3_2_core.h"
-#include <memory>
-
static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace &&
stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace &&
@@ -813,12 +816,16 @@ void RasterizerOpenGL::ReloadColorBuffer() {
}
void RasterizerOpenGL::ReloadDepthBuffer() {
+ PAddr depth_buffer_addr = Pica::g_state.regs.framebuffer.GetDepthBufferPhysicalAddress();
+
+ if (depth_buffer_addr == 0)
+ return;
+
// TODO: Appears to work, but double-check endianness of depth values and order of depth-stencil
- u8* depth_buffer = Memory::GetPhysicalPointer(Pica::g_state.regs.framebuffer.GetDepthBufferPhysicalAddress());
+ u8* depth_buffer = Memory::GetPhysicalPointer(depth_buffer_addr);
- if (depth_buffer == nullptr) {
+ if (depth_buffer == nullptr)
return;
- }
u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index d7d422b1..ae7b26fc 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -4,7 +4,12 @@
#pragma once
+#include <vector>
+
+#include "common/common_types.h"
+
#include "video_core/hwrasterizer_base.h"
+#include "video_core/vertex_shader.h"
#include "gl_state.h"
#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 2e4110a8..dc3ffdf2 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
state.texture_units[texture_unit].texture_2d = new_texture->texture.handle;
state.Apply();
- // TODO: Need to choose filters that correspond to PICA once register is declared
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, PicaToGL::TextureFilterMode(config.config.mag_filter));
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, PicaToGL::TextureFilterMode(config.config.min_filter));
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, PicaToGL::WrapMode(config.config.wrap_s));
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, PicaToGL::WrapMode(config.config.wrap_t));
+ GLenum wrap_s = PicaToGL::WrapMode(config.config.wrap_s);
+ GLenum wrap_t = PicaToGL::WrapMode(config.config.wrap_t);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t);
+
+ if (wrap_s == GL_CLAMP_TO_BORDER || wrap_t == GL_CLAMP_TO_BORDER) {
+ auto border_color = PicaToGL::ColorRGBA8((u8*)&config.config.border_color.r);
+ glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color.data());
+ }
const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format);
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 8f4ae28a..00000000
--- a/src/video_core/renderer_opengl/gl_resource_manager.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "video_core/renderer_opengl/gl_resource_manager.h"
-#include "video_core/renderer_opengl/gl_shader_util.h"
-
-// Textures
-OGLTexture::OGLTexture() : handle(0) {
-}
-
-OGLTexture::~OGLTexture() {
- Release();
-}
-
-void OGLTexture::Create() {
- if (handle != 0) {
- return;
- }
-
- glGenTextures(1, &handle);
-}
-
-void OGLTexture::Release() {
- glDeleteTextures(1, &handle);
- handle = 0;
-}
-
-// Shaders
-OGLShader::OGLShader() : handle(0) {
-}
-
-OGLShader::~OGLShader() {
- Release();
-}
-
-void OGLShader::Create(const char* vert_shader, const char* frag_shader) {
- if (handle != 0) {
- return;
- }
-
- handle = ShaderUtil::LoadShaders(vert_shader, frag_shader);
-}
-
-void OGLShader::Release() {
- glDeleteProgram(handle);
- handle = 0;
-}
-
-// Buffer objects
-OGLBuffer::OGLBuffer() : handle(0) {
-}
-
-OGLBuffer::~OGLBuffer() {
- Release();
-}
-
-void OGLBuffer::Create() {
- if (handle != 0) {
- return;
- }
-
- glGenBuffers(1, &handle);
-}
-
-void OGLBuffer::Release() {
- glDeleteBuffers(1, &handle);
- handle = 0;
-}
-
-// Vertex array objects
-OGLVertexArray::OGLVertexArray() : handle(0) {
-}
-
-OGLVertexArray::~OGLVertexArray() {
- Release();
-}
-
-void OGLVertexArray::Create() {
- if (handle != 0) {
- return;
- }
-
- glGenVertexArrays(1, &handle);
-}
-
-void OGLVertexArray::Release() {
- glDeleteVertexArrays(1, &handle);
- handle = 0;
-}
-
-// Framebuffers
-OGLFramebuffer::OGLFramebuffer() : handle(0) {
-}
-
-OGLFramebuffer::~OGLFramebuffer() {
- Release();
-}
-
-void OGLFramebuffer::Create() {
- if (handle != 0) {
- return;
- }
-
- glGenFramebuffers(1, &handle);
-}
-
-void OGLFramebuffer::Release() {
- glDeleteFramebuffers(1, &handle);
- handle = 0;
-}
diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h
index 975720d0..6f9dc012 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 @@
#pragma once
+#include <utility>
+
#include "common/common_types.h"
-#include "generated/gl_3_2_core.h"
+#include "video_core/renderer_opengl/generated/gl_3_2_core.h"
+#include "video_core/renderer_opengl/gl_shader_util.h"
-class OGLTexture : public NonCopyable {
+class OGLTexture : private NonCopyable {
public:
- OGLTexture();
- ~OGLTexture();
+ OGLTexture() = default;
+ OGLTexture(OGLTexture&& o) { std::swap(handle, o.handle); }
+ ~OGLTexture() { Release(); }
+ OGLTexture& operator=(OGLTexture&& o) { std::swap(handle, o.handle); return *this; }
/// Creates a new internal OpenGL resource and stores the handle
- void Create();
+ void Create() {
+ if (handle != 0) return;
+ glGenTextures(1, &handle);
+ }
/// Deletes the internal OpenGL resource
- void Release();
+ void Release() {
+ if (handle == 0) return;
+ glDeleteTextures(1, &handle);
+ handle = 0;
+ }
- GLuint handle;
+ GLuint handle = 0;
};
-class OGLShader : public NonCopyable {
+class OGLShader : private NonCopyable {
public:
- OGLShader();
- ~OGLShader();
+ OGLShader() = default;
+ OGLShader(OGLShader&& o) { std::swap(handle, o.handle); }
+ ~OGLShader() { Release(); }
+ OGLShader& operator=(OGLShader&& o) { std::swap(handle, o.handle); return *this; }
/// Creates a new internal OpenGL resource and stores the handle
- void Create(const char* vert_shader, const char* frag_shader);
+ void Create(const char* vert_shader, const char* frag_shader) {
+ if (handle != 0) return;
+ handle = ShaderUtil::LoadShaders(vert_shader, frag_shader);
+ }
/// Deletes the internal OpenGL resource
- void Release();
+ void Release() {
+ if (handle == 0) return;
+ glDeleteProgram(handle);
+ handle = 0;
+ }
- GLuint handle;
+ GLuint handle = 0;
};
-class OGLBuffer : public NonCopyable {
+class OGLBuffer : private NonCopyable {
public:
- OGLBuffer();
- ~OGLBuffer();
+ OGLBuffer() = default;
+ OGLBuffer(OGLBuffer&& o) { std::swap(handle, o.handle); }
+ ~OGLBuffer() { Release(); }
+ OGLBuffer& operator=(OGLBuffer&& o) { std::swap(handle, o.handle); return *this; }
/// Creates a new internal OpenGL resource and stores the handle
- void Create();
+ void Create() {
+ if (handle != 0) return;
+ glGenBuffers(1, &handle);
+ }
/// Deletes the internal OpenGL resource
- void Release();
+ void Release() {
+ if (handle == 0) return;
+ glDeleteBuffers(1, &handle);
+ handle = 0;
+ }
- GLuint handle;
+ GLuint handle = 0;
};
-class OGLVertexArray : public NonCopyable {
+class OGLVertexArray : private NonCopyable {
public:
- OGLVertexArray();
- ~OGLVertexArray();
+ OGLVertexArray() = default;
+ OGLVertexArray(OGLVertexArray&& o) { std::swap(handle, o.handle); }
+ ~OGLVertexArray() { Release(); }
+ OGLVertexArray& operator=(OGLVertexArray&& o) { std::swap(handle, o.handle); return *this; }
/// Creates a new internal OpenGL resource and stores the handle
- void Create();
+ void Create() {
+ if (handle != 0) return;
+ glGenVertexArrays(1, &handle);
+ }
/// Deletes the internal OpenGL resource
- void Release();
+ void Release() {
+ if (handle == 0) return;
+ glDeleteVertexArrays(1, &handle);
+ handle = 0;
+ }
- GLuint handle;
+ GLuint handle = 0;
};
-class OGLFramebuffer : public NonCopyable {
+class OGLFramebuffer : private NonCopyable {
public:
- OGLFramebuffer();
- ~OGLFramebuffer();
+ OGLFramebuffer() = default;
+ OGLFramebuffer(OGLFramebuffer&& o) { std::swap(handle, o.handle); }
+ ~OGLFramebuffer() { Release(); }
+ OGLFramebuffer& operator=(OGLFramebuffer&& o) { std::swap(handle, o.handle); return *this; }
/// Creates a new internal OpenGL resource and stores the handle
- void Create();
+ void Create() {
+ if (handle != 0) return;
+ glGenFramebuffers(1, &handle);
+ }
/// Deletes the internal OpenGL resource
- void Release();
+ void Release() {
+ if (handle == 0) return;
+ glDeleteFramebuffers(1, &handle);
+ handle = 0;
+ }
- GLuint handle;
+ GLuint handle = 0;
};
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 3526e16d..9efc1533 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() {
// Textures
for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) {
- if (texture_units[texture_index].enabled_2d != cur_state.texture_units[texture_index].enabled_2d) {
+ if (texture_units[texture_index].enabled_2d != cur_state.texture_units[texture_index].enabled_2d ||
+ texture_units[texture_index].texture_2d != cur_state.texture_units[texture_index].texture_2d) {
+
glActiveTexture(GL_TEXTURE0 + texture_index);
if (texture_units[texture_index].enabled_2d) {
- glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, texture_units[texture_index].texture_2d);
} else {
- glDisable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, 0);
}
}
-
- if (texture_units[texture_index].texture_2d != cur_state.texture_units[texture_index].texture_2d) {
- glActiveTexture(GL_TEXTURE0 + texture_index);
- glBindTexture(GL_TEXTURE_2D, texture_units[texture_index].texture_2d);
- }
}
// Framebuffer
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h
index e566f9f7..3b562da8 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 @@
namespace PicaToGL {
+inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) {
+ static const GLenum filter_mode_table[] = {
+ GL_NEAREST, // TextureFilter::Nearest
+ GL_LINEAR // TextureFilter::Linear
+ };
+
+ // Range check table for input
+ if (mode >= ARRAY_SIZE(filter_mode_table)) {
+ LOG_CRITICAL(Render_OpenGL, "Unknown texture filtering mode %d", mode);
+ UNREACHABLE();
+
+ return GL_LINEAR;
+ }
+
+ GLenum gl_mode = filter_mode_table[mode];
+
+ // Check for dummy values indicating an unknown mode
+ if (gl_mode == 0) {
+ LOG_CRITICAL(Render_OpenGL, "Unknown texture filtering mode %d", mode);
+ UNIMPLEMENTED();
+
+ return GL_LINEAR;
+ }
+
+ return gl_mode;
+}
+
inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) {
static const GLenum wrap_mode_table[] = {
GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge
- 0, // Unknown
+ GL_CLAMP_TO_BORDER,// WrapMode::ClampToBorder
GL_REPEAT, // WrapMode::Repeat
GL_MIRRORED_REPEAT // WrapMode::MirroredRepeat
};
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 3399ca12..96e12839 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -2,22 +2,27 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+#include <cstddef>
+#include <cstdlib>
+
+#include "common/assert.h"
+#include "common/emu_window.h"
+#include "common/logging/log.h"
+#include "common/profiler_reporting.h"
+
#include "core/hw/gpu.h"
#include "core/hw/hw.h"
#include "core/hw/lcd.h"
#include "core/memory.h"
#include "core/settings.h"
-#include "common/emu_window.h"
-#include "common/logging/log.h"
-#include "common/profiler_reporting.h"
-
#include "video_core/video_core.h"
#include "video_core/renderer_opengl/renderer_opengl.h"
#include "video_core/renderer_opengl/gl_shader_util.h"
#include "video_core/renderer_opengl/gl_shaders.h"
-#include <algorithm>
+#include "video_core/debug_utils/debug_utils.h"
/**
* Vertex structure that the drawn screen rectangles are composed of.
@@ -126,6 +131,10 @@ void RendererOpenGL::SwapBuffers() {
hw_rasterizer->Reset();
}
}
+
+ if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
+ Pica::g_debug_context->recorder->FrameFinished();
+ }
}
/**
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp
index 87006a83..960ae577 100644
--- a/src/video_core/vertex_shader.cpp
+++ b/src/video_core/vertex_shader.cpp
@@ -2,8 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <stack>
-
+#include <boost/container/static_vector.hpp>
#include <boost/range/algorithm.hpp>
#include <common/file_util.h>
@@ -27,7 +26,7 @@ namespace Pica {
namespace VertexShader {
struct VertexShaderState {
- const u32* program_counter;
+ u32 program_counter;
const float24* input_register_table[16];
Math::Vec4<float24> output_registers[16];
@@ -53,7 +52,7 @@ struct VertexShaderState {
};
// TODO: Is there a maximal size for this?
- std::stack<CallStackElement> call_stack;
+ boost::container::static_vector<CallStackElement, 16> call_stack;
struct {
u32 max_offset; // maximum program counter ever reached
@@ -71,15 +70,15 @@ static void ProcessShaderCode(VertexShaderState& state) {
while (true) {
if (!state.call_stack.empty()) {
- auto& top = state.call_stack.top();
- if (state.program_counter - program_code.data() == top.final_address) {
+ auto& top = state.call_stack.back();
+ if (state.program_counter == top.final_address) {
state.address_registers[2] += top.loop_increment;
if (top.repeat_counter-- == 0) {
- state.program_counter = &program_code[top.return_address];
- state.call_stack.pop();
+ state.program_counter = top.return_address;
+ state.call_stack.pop_back();
} else {
- state.program_counter = &program_code[top.loop_address];
+ state.program_counter = top.loop_address;
}
// TODO: Is "trying again" accurate to hardware?
@@ -88,17 +87,16 @@ static void ProcessShaderCode(VertexShaderState& state) {
}
bool exit_loop = false;
- const Instruction& instr = *(const Instruction*)state.program_counter;
- const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id];
+ const Instruction instr = { program_code[state.program_counter] };
+ const SwizzlePattern swizzle = { swizzle_data[instr.common.operand_desc_id] };
- static auto call = [&program_code](VertexShaderState& state, u32 offset, u32 num_instructions,
+ static auto call = [](VertexShaderState& state, u32 offset, u32 num_instructions,
u32 return_offset, u8 repeat_count, u8 loop_increment) {
- state.program_counter = &program_code[offset] - 1; // -1 to make sure when incrementing the PC we end up at the correct offset
- state.call_stack.push({ offset + num_instructions, return_offset, repeat_count, loop_increment, offset });
+ state.program_counter = offset - 1; // -1 to make sure when incrementing the PC we end up at the correct offset
+ ASSERT(state.call_stack.size() < state.call_stack.capacity());
+ state.call_stack.push_back({ offset + num_instructions, return_offset, repeat_count, loop_increment, offset });
};
- u32 binary_offset = state.program_counter - program_code.data();
-
- state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + binary_offset);
+ state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + state.program_counter);
auto LookupSourceRegister = [&](const SourceRegister& source_reg) -> const float24* {
switch (source_reg.GetRegisterType()) {
@@ -221,7 +219,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
for (int i = 0; i < num_components; ++i)
dot = dot + src1[i] * src2[i];
- for (int i = 0; i < num_components; ++i) {
+ for (int i = 0; i < 4; ++i) {
if (!swizzle.DestComponentEnabled(i))
continue;
@@ -442,13 +440,13 @@ static void ProcessShaderCode(VertexShaderState& state) {
case OpCode::Id::JMPC:
if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) {
- state.program_counter = &program_code[instr.flow_control.dest_offset] - 1;
+ state.program_counter = instr.flow_control.dest_offset - 1;
}
break;
case OpCode::Id::JMPU:
if (uniforms.b[instr.flow_control.bool_uniform_id]) {
- state.program_counter = &program_code[instr.flow_control.dest_offset] - 1;
+ state.program_counter = instr.flow_control.dest_offset - 1;
}
break;
@@ -456,7 +454,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
call(state,
instr.flow_control.dest_offset,
instr.flow_control.num_instructions,
- binary_offset + 1, 0, 0);
+ state.program_counter + 1, 0, 0);
break;
case OpCode::Id::CALLU:
@@ -464,7 +462,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
call(state,
instr.flow_control.dest_offset,
instr.flow_control.num_instructions,
- binary_offset + 1, 0, 0);
+ state.program_counter + 1, 0, 0);
}
break;
@@ -473,7 +471,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
call(state,
instr.flow_control.dest_offset,
instr.flow_control.num_instructions,
- binary_offset + 1, 0, 0);
+ state.program_counter + 1, 0, 0);
}
break;
@@ -483,8 +481,8 @@ static void ProcessShaderCode(VertexShaderState& state) {
case OpCode::Id::IFU:
if (uniforms.b[instr.flow_control.bool_uniform_id]) {
call(state,
- binary_offset + 1,
- instr.flow_control.dest_offset - binary_offset - 1,
+ state.program_counter + 1,
+ instr.flow_control.dest_offset - state.program_counter - 1,
instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0);
} else {
call(state,
@@ -501,8 +499,8 @@ static void ProcessShaderCode(VertexShaderState& state) {
if (evaluate_condition(state, instr.flow_control.refx, instr.flow_control.refy, instr.flow_control)) {
call(state,
- binary_offset + 1,
- instr.flow_control.dest_offset - binary_offset - 1,
+ state.program_counter + 1,
+ instr.flow_control.dest_offset - state.program_counter - 1,
instr.flow_control.dest_offset + instr.flow_control.num_instructions, 0, 0);
} else {
call(state,
@@ -519,8 +517,8 @@ static void ProcessShaderCode(VertexShaderState& state) {
state.address_registers[2] = uniforms.i[instr.flow_control.int_uniform_id].y;
call(state,
- binary_offset + 1,
- instr.flow_control.dest_offset - binary_offset + 1,
+ state.program_counter + 1,
+ instr.flow_control.dest_offset - state.program_counter + 1,
instr.flow_control.dest_offset + 1,
uniforms.i[instr.flow_control.int_uniform_id].x,
uniforms.i[instr.flow_control.int_uniform_id].z);
@@ -546,20 +544,17 @@ static void ProcessShaderCode(VertexShaderState& state) {
static Common::Profiling::TimingCategory shader_category("Vertex Shader");
-OutputVertex RunShader(const InputVertex& input, int num_attributes) {
+OutputVertex RunShader(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const State::ShaderSetup& setup) {
Common::Profiling::ScopeTimer timer(shader_category);
- const auto& regs = g_state.regs;
- const auto& vs = g_state.vs;
VertexShaderState state;
- const u32* main = &vs.program_code[regs.vs_main_offset];
- state.program_counter = (u32*)main;
+ state.program_counter = config.main_offset;
state.debug.max_offset = 0;
state.debug.max_opdesc_id = 0;
// Setup input register table
- const auto& attribute_register_map = regs.vs_input_register_map;
+ const auto& attribute_register_map = config.input_register_map;
float24 dummy_register;
boost::fill(state.input_register_table, &dummy_register);
@@ -584,16 +579,18 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes) {
state.conditional_code[1] = false;
ProcessShaderCode(state);
- DebugUtils::DumpShader(vs.program_code.data(), state.debug.max_offset, vs.swizzle_data.data(),
- state.debug.max_opdesc_id, regs.vs_main_offset,
- regs.vs_output_attributes);
+#if PICA_DUMP_SHADERS
+ DebugUtils::DumpShader(setup.program_code.data(), state.debug.max_offset, setup.swizzle_data.data(),
+ state.debug.max_opdesc_id, config.main_offset,
+ g_state.regs.vs_output_attributes); // TODO: Don't hardcode VS here
+#endif
// Setup output data
OutputVertex ret;
// TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to
// figure out what those circumstances are and enable the remaining outputs then.
for (int i = 0; i < 7; ++i) {
- const auto& output_register_map = regs.vs_output_attributes[i];
+ const auto& output_register_map = g_state.regs.vs_output_attributes[i]; // TODO: Don't hardcode VS here
u32 semantics[4] = {
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 7471a6de..97f9250d 100644
--- a/src/video_core/vertex_shader.h
+++ b/src/video_core/vertex_shader.h
@@ -4,11 +4,10 @@
#pragma once
-#include <initializer_list>
+#include <type_traits>
-#include <common/common_types.h>
+#include "common/vector_math.h"
-#include "math.h"
#include "pica.h"
namespace Pica {
@@ -66,7 +65,7 @@ struct OutputVertex {
static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD");
static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size");
-OutputVertex RunShader(const InputVertex& input, int num_attributes);
+OutputVertex RunShader(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const State::ShaderSetup& setup);
} // namespace
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h
index 3f24df7b..14b33c9d 100644
--- a/src/video_core/video_core.h
+++ b/src/video_core/video_core.h
@@ -4,12 +4,11 @@
#pragma once
-#include "common/emu_window.h"
-
-#include "renderer_base.h"
-
#include <atomic>
+class EmuWindow;
+class RendererBase;
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// Video Core namespace