summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/citra/CMakeLists.txt14
-rw-r--r--src/citra/citra.cpp25
-rw-r--r--src/citra/config.cpp30
-rw-r--r--src/citra/config.h7
-rw-r--r--src/citra/default_ini.h7
-rw-r--r--src/citra/emu_window/emu_window_glfw.cpp26
-rw-r--r--src/citra/emu_window/emu_window_glfw.h2
-rw-r--r--src/citra_qt/CMakeLists.txt11
-rw-r--r--src/citra_qt/bootmanager.cpp23
-rw-r--r--src/citra_qt/config.cpp58
-rw-r--r--src/citra_qt/config.h13
-rw-r--r--src/citra_qt/debugger/callstack.cpp4
-rw-r--r--src/citra_qt/debugger/disassembler.cpp4
-rw-r--r--src/citra_qt/debugger/graphics.cpp2
-rw-r--r--src/citra_qt/debugger/graphics.hxx2
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints.cpp263
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints.hxx53
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints_p.hxx38
-rw-r--r--src/citra_qt/debugger/graphics_cmdlists.cpp275
-rw-r--r--src/citra_qt/debugger/graphics_cmdlists.hxx39
-rw-r--r--src/citra_qt/debugger/graphics_framebuffer.cpp283
-rw-r--r--src/citra_qt/debugger/graphics_framebuffer.hxx92
-rw-r--r--src/citra_qt/hotkeys.cpp4
-rw-r--r--src/citra_qt/main.cpp64
-rw-r--r--src/citra_qt/util/spinbox.cpp303
-rw-r--r--src/citra_qt/util/spinbox.hxx88
-rw-r--r--src/common/CMakeLists.txt14
-rw-r--r--src/common/bit_field.h14
-rw-r--r--src/common/break_points.cpp6
-rw-r--r--src/common/break_points.h4
-rw-r--r--src/common/chunk_file.h59
-rw-r--r--src/common/common.h4
-rw-r--r--src/common/common_funcs.h11
-rw-r--r--src/common/common_paths.h23
-rw-r--r--src/common/common_types.h2
-rw-r--r--src/common/concurrent_ring_buffer.h164
-rw-r--r--src/common/console_listener.cpp319
-rw-r--r--src/common/console_listener.h38
-rw-r--r--src/common/cpu_detect.h4
-rw-r--r--src/common/emu_window.cpp2
-rw-r--r--src/common/emu_window.h2
-rw-r--r--src/common/extended_trace.cpp24
-rw-r--r--src/common/fifo_queue.h4
-rw-r--r--src/common/file_search.cpp4
-rw-r--r--src/common/file_search.h4
-rw-r--r--src/common/file_util.cpp130
-rw-r--r--src/common/file_util.h11
-rw-r--r--src/common/hash.cpp4
-rw-r--r--src/common/hash.h4
-rw-r--r--src/common/key_map.cpp2
-rw-r--r--src/common/key_map.h2
-rw-r--r--src/common/linear_disk_cache.h6
-rw-r--r--src/common/log.h133
-rw-r--r--src/common/log_manager.cpp199
-rw-r--r--src/common/log_manager.h166
-rw-r--r--src/common/logging/backend.cpp151
-rw-r--r--src/common/logging/backend.h134
-rw-r--r--src/common/logging/filter.cpp132
-rw-r--r--src/common/logging/filter.h63
-rw-r--r--src/common/logging/log.h115
-rw-r--r--src/common/logging/text_formatter.cpp136
-rw-r--r--src/common/logging/text_formatter.h41
-rw-r--r--src/common/make_unique.h16
-rw-r--r--src/common/math_util.cpp4
-rw-r--r--src/common/math_util.h4
-rw-r--r--src/common/mem_arena.cpp34
-rw-r--r--src/common/memory_util.cpp16
-rw-r--r--src/common/memory_util.h4
-rw-r--r--src/common/misc.cpp8
-rw-r--r--src/common/msg_handler.cpp6
-rw-r--r--src/common/msg_handler.h4
-rw-r--r--src/common/platform.h2
-rw-r--r--src/common/scm_rev.h2
-rw-r--r--src/common/scope_exit.h37
-rw-r--r--src/common/string_util.cpp32
-rw-r--r--src/common/string_util.h19
-rw-r--r--src/common/symbols.cpp2
-rw-r--r--src/common/symbols.h2
-rw-r--r--src/common/thread.cpp4
-rw-r--r--src/common/thread.h5
-rw-r--r--src/common/thread_queue_list.h14
-rw-r--r--src/common/thunk.h4
-rw-r--r--src/common/timer.cpp10
-rw-r--r--src/common/timer.h4
-rw-r--r--src/common/utf8.cpp24
-rw-r--r--src/core/CMakeLists.txt57
-rw-r--r--src/core/arm/arm_interface.h8
-rw-r--r--src/core/arm/disassembler/load_symbol_map.cpp2
-rw-r--r--src/core/arm/disassembler/load_symbol_map.h2
-rw-r--r--src/core/arm/dyncom/arm_dyncom.cpp51
-rw-r--r--src/core/arm/dyncom/arm_dyncom.h16
-rw-r--r--src/core/arm/dyncom/arm_dyncom_dec.cpp817
-rw-r--r--src/core/arm/dyncom/arm_dyncom_dec.h2
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp11064
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.h2
-rw-r--r--src/core/arm/dyncom/arm_dyncom_run.cpp46
-rw-r--r--src/core/arm/dyncom/arm_dyncom_thumb.cpp863
-rw-r--r--src/core/arm/interpreter/arm_interpreter.cpp53
-rw-r--r--src/core/arm/interpreter/arm_interpreter.h8
-rw-r--r--src/core/arm/interpreter/armemu.cpp1412
-rw-r--r--src/core/arm/interpreter/armsupp.cpp166
-rw-r--r--src/core/arm/interpreter/thumbemu.cpp2
-rw-r--r--src/core/arm/skyeye_common/armdefs.h491
-rw-r--r--src/core/arm/skyeye_common/armemu.h12
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.cpp663
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.h6
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpinstr.cpp1957
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpsingle.cpp14
-rw-r--r--src/core/core.cpp6
-rw-r--r--src/core/core.h2
-rw-r--r--src/core/core_timing.cpp24
-rw-r--r--src/core/core_timing.h4
-rw-r--r--src/core/file_sys/archive.h246
-rw-r--r--src/core/file_sys/archive_backend.h243
-rw-r--r--src/core/file_sys/archive_romfs.cpp101
-rw-r--r--src/core/file_sys/archive_romfs.h77
-rw-r--r--src/core/file_sys/archive_savedata.cpp33
-rw-r--r--src/core/file_sys/archive_savedata.h31
-rw-r--r--src/core/file_sys/archive_sdmc.cpp122
-rw-r--r--src/core/file_sys/archive_sdmc.h88
-rw-r--r--src/core/file_sys/archive_systemsavedata.cpp39
-rw-r--r--src/core/file_sys/archive_systemsavedata.h33
-rw-r--r--src/core/file_sys/directory_backend.h (renamed from src/core/file_sys/directory.h)14
-rw-r--r--src/core/file_sys/directory_romfs.cpp16
-rw-r--r--src/core/file_sys/directory_romfs.h12
-rw-r--r--src/core/file_sys/directory_sdmc.cpp81
-rw-r--r--src/core/file_sys/directory_sdmc.h48
-rw-r--r--src/core/file_sys/disk_archive.cpp188
-rw-r--r--src/core/file_sys/disk_archive.h103
-rw-r--r--src/core/file_sys/file_backend.h (renamed from src/core/file_sys/file.h)13
-rw-r--r--src/core/file_sys/file_romfs.cpp53
-rw-r--r--src/core/file_sys/file_romfs.h16
-rw-r--r--src/core/file_sys/file_sdmc.cpp107
-rw-r--r--src/core/file_sys/file_sdmc.h75
-rw-r--r--src/core/hle/config_mem.cpp5
-rw-r--r--src/core/hle/config_mem.h2
-rw-r--r--src/core/hle/coprocessor.cpp2
-rw-r--r--src/core/hle/function_wrappers.h16
-rw-r--r--src/core/hle/hle.cpp28
-rw-r--r--src/core/hle/hle.h2
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp19
-rw-r--r--src/core/hle/kernel/address_arbiter.h2
-rw-r--r--src/core/hle/kernel/archive.cpp429
-rw-r--r--src/core/hle/kernel/archive.h85
-rw-r--r--src/core/hle/kernel/event.cpp17
-rw-r--r--src/core/hle/kernel/event.h2
-rw-r--r--src/core/hle/kernel/kernel.cpp139
-rw-r--r--src/core/hle/kernel/kernel.h217
-rw-r--r--src/core/hle/kernel/mutex.cpp108
-rw-r--r--src/core/hle/kernel/mutex.h8
-rw-r--r--src/core/hle/kernel/semaphore.cpp95
-rw-r--r--src/core/hle/kernel/semaphore.h32
-rw-r--r--src/core/hle/kernel/session.h58
-rw-r--r--src/core/hle/kernel/shared_memory.cpp23
-rw-r--r--src/core/hle/kernel/shared_memory.h16
-rw-r--r--src/core/hle/kernel/thread.cpp136
-rw-r--r--src/core/hle/kernel/thread.h22
-rw-r--r--src/core/hle/result.h4
-rw-r--r--src/core/hle/service/ac_u.cpp25
-rw-r--r--src/core/hle/service/ac_u.h8
-rw-r--r--src/core/hle/service/act_u.cpp24
-rw-r--r--src/core/hle/service/act_u.h23
-rw-r--r--src/core/hle/service/am_app.cpp24
-rw-r--r--src/core/hle/service/am_app.h23
-rw-r--r--src/core/hle/service/am_net.cpp5
-rw-r--r--src/core/hle/service/am_net.h8
-rw-r--r--src/core/hle/service/apt_a.cpp34
-rw-r--r--src/core/hle/service/apt_a.h23
-rw-r--r--src/core/hle/service/apt_u.cpp165
-rw-r--r--src/core/hle/service/apt_u.h9
-rw-r--r--src/core/hle/service/boss_u.cpp21
-rw-r--r--src/core/hle/service/boss_u.h22
-rw-r--r--src/core/hle/service/cecd_u.cpp24
-rw-r--r--src/core/hle/service/cecd_u.h23
-rw-r--r--src/core/hle/service/cfg/cfg.cpp202
-rw-r--r--src/core/hle/service/cfg/cfg.h144
-rw-r--r--src/core/hle/service/cfg/cfg_i.cpp110
-rw-r--r--src/core/hle/service/cfg/cfg_i.h (renamed from src/core/hle/service/cfg_i.h)8
-rw-r--r--src/core/hle/service/cfg/cfg_u.cpp192
-rw-r--r--src/core/hle/service/cfg/cfg_u.h (renamed from src/core/hle/service/cfg_u.h)8
-rw-r--r--src/core/hle/service/cfg_i.cpp59
-rw-r--r--src/core/hle/service/cfg_u.cpp36
-rw-r--r--src/core/hle/service/csnd_snd.cpp5
-rw-r--r--src/core/hle/service/csnd_snd.h8
-rw-r--r--src/core/hle/service/dsp_dsp.cpp199
-rw-r--r--src/core/hle/service/dsp_dsp.h10
-rw-r--r--src/core/hle/service/err_f.cpp20
-rw-r--r--src/core/hle/service/err_f.h22
-rw-r--r--src/core/hle/service/frd_u.cpp36
-rw-r--r--src/core/hle/service/frd_u.h22
-rw-r--r--src/core/hle/service/fs/archive.cpp442
-rw-r--r--src/core/hle/service/fs/archive.h134
-rw-r--r--src/core/hle/service/fs/fs_user.cpp601
-rw-r--r--src/core/hle/service/fs/fs_user.h (renamed from src/core/hle/service/fs_user.h)19
-rw-r--r--src/core/hle/service/fs_user.cpp409
-rw-r--r--src/core/hle/service/gsp_gpu.cpp78
-rw-r--r--src/core/hle/service/gsp_gpu.h10
-rw-r--r--src/core/hle/service/hid_user.cpp14
-rw-r--r--src/core/hle/service/hid_user.h14
-rw-r--r--src/core/hle/service/http_c.cpp64
-rw-r--r--src/core/hle/service/http_c.h23
-rw-r--r--src/core/hle/service/ir_rst.cpp5
-rw-r--r--src/core/hle/service/ir_rst.h10
-rw-r--r--src/core/hle/service/ir_u.cpp5
-rw-r--r--src/core/hle/service/ir_u.h8
-rw-r--r--src/core/hle/service/ldr_ro.cpp29
-rw-r--r--src/core/hle/service/ldr_ro.h23
-rw-r--r--src/core/hle/service/mic_u.cpp5
-rw-r--r--src/core/hle/service/mic_u.h8
-rw-r--r--src/core/hle/service/ndm_u.cpp5
-rw-r--r--src/core/hle/service/ndm_u.h10
-rw-r--r--src/core/hle/service/news_u.cpp25
-rw-r--r--src/core/hle/service/news_u.h23
-rw-r--r--src/core/hle/service/nim_aoc.cpp31
-rw-r--r--src/core/hle/service/nim_aoc.h23
-rw-r--r--src/core/hle/service/nwm_uds.cpp5
-rw-r--r--src/core/hle/service/nwm_uds.h8
-rw-r--r--src/core/hle/service/pm_app.cpp5
-rw-r--r--src/core/hle/service/pm_app.h8
-rw-r--r--src/core/hle/service/ptm_u.cpp99
-rw-r--r--src/core/hle/service/ptm_u.h8
-rw-r--r--src/core/hle/service/service.cpp35
-rw-r--r--src/core/hle/service/service.h63
-rw-r--r--src/core/hle/service/soc_u.cpp5
-rw-r--r--src/core/hle/service/soc_u.h8
-rw-r--r--src/core/hle/service/srv.cpp19
-rw-r--r--src/core/hle/service/srv.h11
-rw-r--r--src/core/hle/service/ssl_c.cpp5
-rw-r--r--src/core/hle/service/ssl_c.h10
-rw-r--r--src/core/hle/svc.cpp126
-rw-r--r--src/core/hle/svc.h2
-rw-r--r--src/core/hw/gpu.cpp96
-rw-r--r--src/core/hw/gpu.h5
-rw-r--r--src/core/hw/hw.cpp23
-rw-r--r--src/core/hw/hw.h2
-rw-r--r--src/core/hw/ndma.cpp47
-rw-r--r--src/core/hw/ndma.h26
-rw-r--r--src/core/loader/3dsx.cpp234
-rw-r--r--src/core/loader/3dsx.h32
-rw-r--r--src/core/loader/elf.cpp20
-rw-r--r--src/core/loader/elf.h4
-rw-r--r--src/core/loader/loader.cpp24
-rw-r--r--src/core/loader/loader.h3
-rw-r--r--src/core/loader/ncch.cpp40
-rw-r--r--src/core/loader/ncch.h8
-rw-r--r--src/core/mem_map.cpp24
-rw-r--r--src/core/mem_map.h151
-rw-r--r--src/core/mem_map_funcs.cpp92
-rw-r--r--src/core/settings.cpp2
-rw-r--r--src/core/settings.h7
-rw-r--r--src/core/system.cpp14
-rw-r--r--src/core/system.h2
-rw-r--r--src/video_core/clipper.cpp81
-rw-r--r--src/video_core/clipper.h2
-rw-r--r--src/video_core/command_processor.cpp70
-rw-r--r--src/video_core/command_processor.h2
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp370
-rw-r--r--src/video_core/debug_utils/debug_utils.h157
-rw-r--r--src/video_core/gpu_debugger.h6
-rw-r--r--src/video_core/math.h2
-rw-r--r--src/video_core/pica.h168
-rw-r--r--src/video_core/primitive_assembly.cpp25
-rw-r--r--src/video_core/primitive_assembly.h3
-rw-r--r--src/video_core/rasterizer.cpp202
-rw-r--r--src/video_core/rasterizer.h2
-rw-r--r--src/video_core/renderer_base.h2
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.cpp36
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.h2
-rw-r--r--src/video_core/renderer_opengl/gl_shaders.h2
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp20
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h2
-rw-r--r--src/video_core/utils.cpp2
-rw-r--r--src/video_core/utils.h2
-rw-r--r--src/video_core/vertex_shader.cpp358
-rw-r--r--src/video_core/vertex_shader.h225
-rw-r--r--src/video_core/video_core.cpp10
-rw-r--r--src/video_core/video_core.h2
277 files changed, 17511 insertions, 14149 deletions
diff --git a/src/citra/CMakeLists.txt b/src/citra/CMakeLists.txt
index c4cbf9fea..0e03212d7 100644
--- a/src/citra/CMakeLists.txt
+++ b/src/citra/CMakeLists.txt
@@ -12,25 +12,23 @@ set(HEADERS
12 12
13create_directory_groups(${SRCS} ${HEADERS}) 13create_directory_groups(${SRCS} ${HEADERS})
14 14
15# NOTE: This is a workaround for CMake bug 0006976 (missing X11_xf86vmode_LIB variable)
16if (NOT X11_xf86vmode_LIB)
17 set(X11_xv86vmode_LIB Xxf86vm)
18endif()
19
20add_executable(citra ${SRCS} ${HEADERS}) 15add_executable(citra ${SRCS} ${HEADERS})
21target_link_libraries(citra core common video_core) 16target_link_libraries(citra core common video_core)
22target_link_libraries(citra ${GLFW_LIBRARIES} ${OPENGL_gl_LIBRARY} inih) 17target_link_libraries(citra ${GLFW_LIBRARIES} ${OPENGL_gl_LIBRARY} inih)
23 18
19if (UNIX)
20 target_link_libraries(citra -pthread)
21endif()
22
24if (APPLE) 23if (APPLE)
25 target_link_libraries(citra iconv pthread ${COREFOUNDATION_LIBRARY}) 24 target_link_libraries(citra iconv ${COREFOUNDATION_LIBRARY})
26elseif (WIN32) 25elseif (WIN32)
27 target_link_libraries(citra winmm) 26 target_link_libraries(citra winmm)
28 if (MINGW) 27 if (MINGW)
29 target_link_libraries(citra iconv) 28 target_link_libraries(citra iconv)
30 endif() 29 endif()
31else() # Unix 30else() # Unix
32 target_link_libraries(citra pthread rt) 31 target_link_libraries(citra rt)
33 target_link_libraries(citra ${X11_X11_LIB} ${X11_Xi_LIB} ${X11_Xcursor_LIB} ${X11_Xrandr_LIB} ${X11_xv86vmode_LIB})
34endif() 32endif()
35 33
36#install(TARGETS citra RUNTIME DESTINATION ${bindir}) 34#install(TARGETS citra RUNTIME DESTINATION ${bindir})
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp
index f2aeb510e..f6a52758b 100644
--- a/src/citra/citra.cpp
+++ b/src/citra/citra.cpp
@@ -1,9 +1,14 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <thread>
6
5#include "common/common.h" 7#include "common/common.h"
6#include "common/log_manager.h" 8#include "common/logging/text_formatter.h"
9#include "common/logging/backend.h"
10#include "common/logging/filter.h"
11#include "common/scope_exit.h"
7 12
8#include "core/settings.h" 13#include "core/settings.h"
9#include "core/system.h" 14#include "core/system.h"
@@ -15,17 +20,21 @@
15 20
16/// Application entry point 21/// Application entry point
17int __cdecl main(int argc, char **argv) { 22int __cdecl main(int argc, char **argv) {
18 LogManager::Init(); 23 std::shared_ptr<Log::Logger> logger = Log::InitGlobalLogger();
24 Log::Filter log_filter(Log::Level::Debug);
25 std::thread logging_thread(Log::TextLoggingLoop, logger, &log_filter);
26 SCOPE_EXIT({
27 logger->Close();
28 logging_thread.join();
29 });
19 30
20 if (argc < 2) { 31 if (argc < 2) {
21 ERROR_LOG(BOOT, "Failed to load ROM: No ROM specified"); 32 LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified");
22 return -1; 33 return -1;
23 } 34 }
24 35
25 Config config; 36 Config config;
26 37 log_filter.ParseFilterString(Settings::values.log_filter);
27 if (!Settings::values.enable_log)
28 LogManager::Shutdown();
29 38
30 std::string boot_filename = argv[1]; 39 std::string boot_filename = argv[1];
31 EmuWindow_GLFW* emu_window = new EmuWindow_GLFW; 40 EmuWindow_GLFW* emu_window = new EmuWindow_GLFW;
@@ -34,7 +43,7 @@ int __cdecl main(int argc, char **argv) {
34 43
35 Loader::ResultStatus load_result = Loader::LoadFile(boot_filename); 44 Loader::ResultStatus load_result = Loader::LoadFile(boot_filename);
36 if (Loader::ResultStatus::Success != load_result) { 45 if (Loader::ResultStatus::Success != load_result) {
37 ERROR_LOG(BOOT, "Failed to load ROM (Error %i)!", load_result); 46 LOG_CRITICAL(Frontend, "Failed to load ROM (Error %i)!", load_result);
38 return -1; 47 return -1;
39 } 48 }
40 49
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index f45d09fc2..2bf0dff35 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <GLFW/glfw3.h> 5#include <GLFW/glfw3.h>
@@ -22,21 +22,22 @@ Config::Config() {
22bool Config::LoadINI(INIReader* config, const char* location, const std::string& default_contents, bool retry) { 22bool Config::LoadINI(INIReader* config, const char* location, const std::string& default_contents, bool retry) {
23 if (config->ParseError() < 0) { 23 if (config->ParseError() < 0) {
24 if (retry) { 24 if (retry) {
25 ERROR_LOG(CONFIG, "Failed to load %s. Creating file from defaults...", location); 25 LOG_WARNING(Config, "Failed to load %s. Creating file from defaults...", location);
26 FileUtil::CreateFullPath(location); 26 FileUtil::CreateFullPath(location);
27 FileUtil::WriteStringToFile(true, default_contents, location); 27 FileUtil::WriteStringToFile(true, default_contents, location);
28 *config = INIReader(location); // Reopen file 28 *config = INIReader(location); // Reopen file
29 29
30 return LoadINI(config, location, default_contents, false); 30 return LoadINI(config, location, default_contents, false);
31 } 31 }
32 ERROR_LOG(CONFIG, "Failed."); 32 LOG_ERROR(Config, "Failed.");
33 return false; 33 return false;
34 } 34 }
35 INFO_LOG(CONFIG, "Successfully loaded %s", location); 35 LOG_INFO(Config, "Successfully loaded %s", location);
36 return true; 36 return true;
37} 37}
38 38
39void Config::ReadControls() { 39void Config::ReadValues() {
40 // Controls
40 Settings::values.pad_a_key = glfw_config->GetInteger("Controls", "pad_a", GLFW_KEY_A); 41 Settings::values.pad_a_key = glfw_config->GetInteger("Controls", "pad_a", GLFW_KEY_A);
41 Settings::values.pad_b_key = glfw_config->GetInteger("Controls", "pad_b", GLFW_KEY_S); 42 Settings::values.pad_b_key = glfw_config->GetInteger("Controls", "pad_b", GLFW_KEY_S);
42 Settings::values.pad_x_key = glfw_config->GetInteger("Controls", "pad_x", GLFW_KEY_Z); 43 Settings::values.pad_x_key = glfw_config->GetInteger("Controls", "pad_x", GLFW_KEY_Z);
@@ -54,27 +55,22 @@ void Config::ReadControls() {
54 Settings::values.pad_sdown_key = glfw_config->GetInteger("Controls", "pad_sdown", GLFW_KEY_DOWN); 55 Settings::values.pad_sdown_key = glfw_config->GetInteger("Controls", "pad_sdown", GLFW_KEY_DOWN);
55 Settings::values.pad_sleft_key = glfw_config->GetInteger("Controls", "pad_sleft", GLFW_KEY_LEFT); 56 Settings::values.pad_sleft_key = glfw_config->GetInteger("Controls", "pad_sleft", GLFW_KEY_LEFT);
56 Settings::values.pad_sright_key = glfw_config->GetInteger("Controls", "pad_sright", GLFW_KEY_RIGHT); 57 Settings::values.pad_sright_key = glfw_config->GetInteger("Controls", "pad_sright", GLFW_KEY_RIGHT);
57}
58 58
59void Config::ReadCore() { 59 // Core
60 Settings::values.cpu_core = glfw_config->GetInteger("Core", "cpu_core", Core::CPU_Interpreter); 60 Settings::values.cpu_core = glfw_config->GetInteger("Core", "cpu_core", Core::CPU_Interpreter);
61 Settings::values.gpu_refresh_rate = glfw_config->GetInteger("Core", "gpu_refresh_rate", 60); 61 Settings::values.gpu_refresh_rate = glfw_config->GetInteger("Core", "gpu_refresh_rate", 30);
62} 62 Settings::values.frame_skip = glfw_config->GetInteger("Core", "frame_skip", 0);
63 63
64void Config::ReadData() { 64 // Data Storage
65 Settings::values.use_virtual_sd = glfw_config->GetBoolean("Data Storage", "use_virtual_sd", true); 65 Settings::values.use_virtual_sd = glfw_config->GetBoolean("Data Storage", "use_virtual_sd", true);
66}
67 66
68void Config::ReadMiscellaneous() { 67 // Miscellaneous
69 Settings::values.enable_log = glfw_config->GetBoolean("Miscellaneous", "enable_log", true); 68 Settings::values.log_filter = glfw_config->Get("Miscellaneous", "log_filter", "*:Info");
70} 69}
71 70
72void Config::Reload() { 71void Config::Reload() {
73 LoadINI(glfw_config, glfw_config_loc.c_str(), DefaultINI::glfw_config_file); 72 LoadINI(glfw_config, glfw_config_loc.c_str(), DefaultINI::glfw_config_file);
74 ReadControls(); 73 ReadValues();
75 ReadCore();
76 ReadData();
77 ReadMiscellaneous();
78} 74}
79 75
80Config::~Config() { 76Config::~Config() {
diff --git a/src/citra/config.h b/src/citra/config.h
index 19bb83700..0eb176c7d 100644
--- a/src/citra/config.h
+++ b/src/citra/config.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -15,10 +15,7 @@ class Config {
15 std::string glfw_config_loc; 15 std::string glfw_config_loc;
16 16
17 bool LoadINI(INIReader* config, const char* location, const std::string& default_contents="", bool retry=true); 17 bool LoadINI(INIReader* config, const char* location, const std::string& default_contents="", bool retry=true);
18 void ReadControls(); 18 void ReadValues();
19 void ReadCore();
20 void ReadData();
21 void ReadMiscellaneous();
22public: 19public:
23 Config(); 20 Config();
24 ~Config(); 21 ~Config();
diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h
index f1f626eed..f41020f7b 100644
--- a/src/citra/default_ini.h
+++ b/src/citra/default_ini.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -28,13 +28,14 @@ pad_sright =
28 28
29[Core] 29[Core]
30cpu_core = ## 0: Interpreter (default), 1: FastInterpreter (experimental) 30cpu_core = ## 0: Interpreter (default), 1: FastInterpreter (experimental)
31gpu_refresh_rate = ## 60 (default) 31gpu_refresh_rate = ## 30 (default)
32frame_skip = ## 0: No frameskip (default), 1 : 2x frameskip, 2 : 4x frameskip, etc.
32 33
33[Data Storage] 34[Data Storage]
34use_virtual_sd = 35use_virtual_sd =
35 36
36[Miscellaneous] 37[Miscellaneous]
37enable_log = 38log_filter = *:Info ## Examples: *:Debug Kernel.SVC:Trace Service.*:Critical
38)"; 39)";
39 40
40} 41}
diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp
index 8efb39e2e..a6282809b 100644
--- a/src/citra/emu_window/emu_window_glfw.cpp
+++ b/src/citra/emu_window/emu_window_glfw.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <GLFW/glfw3.h> 5#include <GLFW/glfw3.h>
@@ -36,15 +36,15 @@ const bool EmuWindow_GLFW::IsOpen() {
36} 36}
37 37
38void EmuWindow_GLFW::OnFramebufferResizeEvent(GLFWwindow* win, int width, int height) { 38void EmuWindow_GLFW::OnFramebufferResizeEvent(GLFWwindow* win, int width, int height) {
39 _dbg_assert_(GUI, width > 0); 39 _dbg_assert_(Frontend, width > 0);
40 _dbg_assert_(GUI, height > 0); 40 _dbg_assert_(Frontend, height > 0);
41 41
42 GetEmuWindow(win)->NotifyFramebufferSizeChanged(std::pair<unsigned,unsigned>(width, height)); 42 GetEmuWindow(win)->NotifyFramebufferSizeChanged(std::pair<unsigned,unsigned>(width, height));
43} 43}
44 44
45void EmuWindow_GLFW::OnClientAreaResizeEvent(GLFWwindow* win, int width, int height) { 45void EmuWindow_GLFW::OnClientAreaResizeEvent(GLFWwindow* win, int width, int height) {
46 _dbg_assert_(GUI, width > 0); 46 _dbg_assert_(Frontend, width > 0);
47 _dbg_assert_(GUI, height > 0); 47 _dbg_assert_(Frontend, height > 0);
48 48
49 // NOTE: GLFW provides no proper way to set a minimal window size. 49 // NOTE: GLFW provides no proper way to set a minimal window size.
50 // Hence, we just ignore the corresponding EmuWindow hint. 50 // Hence, we just ignore the corresponding EmuWindow hint.
@@ -58,9 +58,13 @@ EmuWindow_GLFW::EmuWindow_GLFW() {
58 58
59 ReloadSetKeymaps(); 59 ReloadSetKeymaps();
60 60
61 glfwSetErrorCallback([](int error, const char *desc){
62 LOG_ERROR(Frontend, "GLFW 0x%08x: %s", error, desc);
63 });
64
61 // Initialize the window 65 // Initialize the window
62 if(glfwInit() != GL_TRUE) { 66 if(glfwInit() != GL_TRUE) {
63 printf("Failed to initialize GLFW! Exiting..."); 67 LOG_CRITICAL(Frontend, "Failed to initialize GLFW! Exiting...");
64 exit(1); 68 exit(1);
65 } 69 }
66 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); 70 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
@@ -72,10 +76,10 @@ EmuWindow_GLFW::EmuWindow_GLFW() {
72 std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc); 76 std::string window_title = Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc);
73 m_render_window = glfwCreateWindow(VideoCore::kScreenTopWidth, 77 m_render_window = glfwCreateWindow(VideoCore::kScreenTopWidth,
74 (VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight), 78 (VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight),
75 window_title.c_str(), NULL, NULL); 79 window_title.c_str(), nullptr, nullptr);
76 80
77 if (m_render_window == NULL) { 81 if (m_render_window == nullptr) {
78 printf("Failed to create GLFW window! Exiting..."); 82 LOG_CRITICAL(Frontend, "Failed to create GLFW window! Exiting...");
79 exit(1); 83 exit(1);
80 } 84 }
81 85
@@ -119,7 +123,7 @@ void EmuWindow_GLFW::MakeCurrent() {
119 123
120/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread 124/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
121void EmuWindow_GLFW::DoneCurrent() { 125void EmuWindow_GLFW::DoneCurrent() {
122 glfwMakeContextCurrent(NULL); 126 glfwMakeContextCurrent(nullptr);
123} 127}
124 128
125void EmuWindow_GLFW::ReloadSetKeymaps() { 129void EmuWindow_GLFW::ReloadSetKeymaps() {
@@ -145,7 +149,7 @@ void EmuWindow_GLFW::OnMinimalClientAreaChangeRequest(const std::pair<unsigned,u
145 std::pair<int,int> current_size; 149 std::pair<int,int> current_size;
146 glfwGetWindowSize(m_render_window, &current_size.first, &current_size.second); 150 glfwGetWindowSize(m_render_window, &current_size.first, &current_size.second);
147 151
148 _dbg_assert_(GUI, (int)minimal_size.first > 0 && (int)minimal_size.second > 0); 152 _dbg_assert_(Frontend, (int)minimal_size.first > 0 && (int)minimal_size.second > 0);
149 int new_width = std::max(current_size.first, (int)minimal_size.first); 153 int new_width = std::max(current_size.first, (int)minimal_size.first);
150 int new_height = std::max(current_size.second, (int)minimal_size.second); 154 int new_height = std::max(current_size.second, (int)minimal_size.second);
151 155
diff --git a/src/citra/emu_window/emu_window_glfw.h b/src/citra/emu_window/emu_window_glfw.h
index 5b04e87bb..5252fccc8 100644
--- a/src/citra/emu_window/emu_window_glfw.h
+++ b/src/citra/emu_window/emu_window_glfw.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index 98a48a69a..54d0a1271 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -8,9 +8,12 @@ set(SRCS
8 debugger/callstack.cpp 8 debugger/callstack.cpp
9 debugger/disassembler.cpp 9 debugger/disassembler.cpp
10 debugger/graphics.cpp 10 debugger/graphics.cpp
11 debugger/graphics_breakpoints.cpp
11 debugger/graphics_cmdlists.cpp 12 debugger/graphics_cmdlists.cpp
13 debugger/graphics_framebuffer.cpp
12 debugger/ramview.cpp 14 debugger/ramview.cpp
13 debugger/registers.cpp 15 debugger/registers.cpp
16 util/spinbox.cpp
14 bootmanager.cpp 17 bootmanager.cpp
15 hotkeys.cpp 18 hotkeys.cpp
16 main.cpp 19 main.cpp
@@ -23,9 +26,13 @@ set(HEADERS
23 debugger/callstack.hxx 26 debugger/callstack.hxx
24 debugger/disassembler.hxx 27 debugger/disassembler.hxx
25 debugger/graphics.hxx 28 debugger/graphics.hxx
29 debugger/graphics_breakpoints.hxx
30 debugger/graphics_breakpoints_p.hxx
26 debugger/graphics_cmdlists.hxx 31 debugger/graphics_cmdlists.hxx
32 debugger/graphics_framebuffer.hxx
27 debugger/ramview.hxx 33 debugger/ramview.hxx
28 debugger/registers.hxx 34 debugger/registers.hxx
35 util/spinbox.hxx
29 bootmanager.hxx 36 bootmanager.hxx
30 hotkeys.hxx 37 hotkeys.hxx
31 main.hxx 38 main.hxx
@@ -53,6 +60,10 @@ add_executable(citra-qt ${SRCS} ${HEADERS} ${UI_HDRS})
53target_link_libraries(citra-qt core common video_core qhexedit) 60target_link_libraries(citra-qt core common video_core qhexedit)
54target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) 61target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS})
55 62
63if (UNIX)
64 target_link_libraries(citra-qt -pthread)
65endif()
66
56if (APPLE) 67if (APPLE)
57 target_link_libraries(citra-qt iconv ${COREFOUNDATION_LIBRARY}) 68 target_link_libraries(citra-qt iconv ${COREFOUNDATION_LIBRARY})
58elseif (WIN32) 69elseif (WIN32)
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 9bf079919..6d08d6afc 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -14,6 +14,8 @@
14#include "core/core.h" 14#include "core/core.h"
15#include "core/settings.h" 15#include "core/settings.h"
16 16
17#include "video_core/debug_utils/debug_utils.h"
18
17#include "video_core/video_core.h" 19#include "video_core/video_core.h"
18 20
19#include "citra_qt/version.h" 21#include "citra_qt/version.h"
@@ -60,26 +62,33 @@ void EmuThread::Stop()
60{ 62{
61 if (!isRunning()) 63 if (!isRunning())
62 { 64 {
63 INFO_LOG(MASTER_LOG, "EmuThread::Stop called while emu thread wasn't running, returning..."); 65 LOG_WARNING(Frontend, "EmuThread::Stop called while emu thread wasn't running, returning...");
64 return; 66 return;
65 } 67 }
66 stop_run = true; 68 stop_run = true;
67 69
70 // Release emu threads from any breakpoints, so that this doesn't hang forever.
71 Pica::g_debug_context->ClearBreakpoints();
72
68 //core::g_state = core::SYS_DIE; 73 //core::g_state = core::SYS_DIE;
69 74
70 wait(500); 75 // TODO: Waiting here is just a bad workaround for retarded shutdown logic.
76 wait(1000);
71 if (isRunning()) 77 if (isRunning())
72 { 78 {
73 WARN_LOG(MASTER_LOG, "EmuThread still running, terminating..."); 79 LOG_WARNING(Frontend, "EmuThread still running, terminating...");
74 quit(); 80 quit();
75 wait(1000); 81
82 // TODO: Waiting 50 seconds can be necessary if the logging subsystem has a lot of spam
83 // queued... This should be fixed.
84 wait(50000);
76 if (isRunning()) 85 if (isRunning())
77 { 86 {
78 WARN_LOG(MASTER_LOG, "EmuThread STILL running, something is wrong here..."); 87 LOG_CRITICAL(Frontend, "EmuThread STILL running, something is wrong here...");
79 terminate(); 88 terminate();
80 } 89 }
81 } 90 }
82 INFO_LOG(MASTER_LOG, "EmuThread stopped"); 91 LOG_INFO(Frontend, "EmuThread stopped");
83} 92}
84 93
85 94
@@ -230,7 +239,7 @@ QByteArray GRenderWindow::saveGeometry()
230{ 239{
231 // If we are a top-level widget, store the current geometry 240 // If we are a top-level widget, store the current geometry
232 // otherwise, store the last backup 241 // otherwise, store the last backup
233 if (parent() == NULL) 242 if (parent() == nullptr)
234 return ((QGLWidget*)this)->saveGeometry(); 243 return ((QGLWidget*)this)->saveGeometry();
235 else 244 else
236 return geometry; 245 return geometry;
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index 09fce4d6f..1596c08d7 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <QString> 5#include <QString>
@@ -21,7 +21,7 @@ Config::Config() {
21 Reload(); 21 Reload();
22} 22}
23 23
24void Config::ReadControls() { 24void Config::ReadValues() {
25 qt_config->beginGroup("Controls"); 25 qt_config->beginGroup("Controls");
26 Settings::values.pad_a_key = qt_config->value("pad_a", Qt::Key_A).toInt(); 26 Settings::values.pad_a_key = qt_config->value("pad_a", Qt::Key_A).toInt();
27 Settings::values.pad_b_key = qt_config->value("pad_b", Qt::Key_S).toInt(); 27 Settings::values.pad_b_key = qt_config->value("pad_b", Qt::Key_S).toInt();
@@ -41,9 +41,23 @@ void Config::ReadControls() {
41 Settings::values.pad_sleft_key = qt_config->value("pad_sleft", Qt::Key_Left).toInt(); 41 Settings::values.pad_sleft_key = qt_config->value("pad_sleft", Qt::Key_Left).toInt();
42 Settings::values.pad_sright_key = qt_config->value("pad_sright", Qt::Key_Right).toInt(); 42 Settings::values.pad_sright_key = qt_config->value("pad_sright", Qt::Key_Right).toInt();
43 qt_config->endGroup(); 43 qt_config->endGroup();
44
45 qt_config->beginGroup("Core");
46 Settings::values.cpu_core = qt_config->value("cpu_core", Core::CPU_Interpreter).toInt();
47 Settings::values.gpu_refresh_rate = qt_config->value("gpu_refresh_rate", 30).toInt();
48 Settings::values.frame_skip = qt_config->value("frame_skip", 0).toInt();
49 qt_config->endGroup();
50
51 qt_config->beginGroup("Data Storage");
52 Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool();
53 qt_config->endGroup();
54
55 qt_config->beginGroup("Miscellaneous");
56 Settings::values.log_filter = qt_config->value("log_filter", "*:Info").toString().toStdString();
57 qt_config->endGroup();
44} 58}
45 59
46void Config::SaveControls() { 60void Config::SaveValues() {
47 qt_config->beginGroup("Controls"); 61 qt_config->beginGroup("Controls");
48 qt_config->setValue("pad_a", Settings::values.pad_a_key); 62 qt_config->setValue("pad_a", Settings::values.pad_a_key);
49 qt_config->setValue("pad_b", Settings::values.pad_b_key); 63 qt_config->setValue("pad_b", Settings::values.pad_b_key);
@@ -63,58 +77,28 @@ void Config::SaveControls() {
63 qt_config->setValue("pad_sleft", Settings::values.pad_sleft_key); 77 qt_config->setValue("pad_sleft", Settings::values.pad_sleft_key);
64 qt_config->setValue("pad_sright", Settings::values.pad_sright_key); 78 qt_config->setValue("pad_sright", Settings::values.pad_sright_key);
65 qt_config->endGroup(); 79 qt_config->endGroup();
66}
67
68void Config::ReadCore() {
69 qt_config->beginGroup("Core");
70 Settings::values.cpu_core = qt_config->value("cpu_core", Core::CPU_Interpreter).toInt();
71 Settings::values.gpu_refresh_rate = qt_config->value("gpu_refresh_rate", 60).toInt();
72 qt_config->endGroup();
73}
74 80
75void Config::SaveCore() {
76 qt_config->beginGroup("Core"); 81 qt_config->beginGroup("Core");
77 qt_config->setValue("cpu_core", Settings::values.cpu_core); 82 qt_config->setValue("cpu_core", Settings::values.cpu_core);
78 qt_config->setValue("gpu_refresh_rate", Settings::values.gpu_refresh_rate); 83 qt_config->setValue("gpu_refresh_rate", Settings::values.gpu_refresh_rate);
84 qt_config->setValue("frame_skip", Settings::values.frame_skip);
79 qt_config->endGroup(); 85 qt_config->endGroup();
80}
81
82void Config::ReadData() {
83 qt_config->beginGroup("Data Storage");
84 Settings::values.use_virtual_sd = qt_config->value("use_virtual_sd", true).toBool();
85 qt_config->endGroup();
86}
87 86
88void Config::SaveData() {
89 qt_config->beginGroup("Data Storage"); 87 qt_config->beginGroup("Data Storage");
90 qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd); 88 qt_config->setValue("use_virtual_sd", Settings::values.use_virtual_sd);
91 qt_config->endGroup(); 89 qt_config->endGroup();
92}
93
94void Config::ReadMiscellaneous() {
95 qt_config->beginGroup("Miscellaneous");
96 Settings::values.enable_log = qt_config->value("enable_log", true).toBool();
97 qt_config->endGroup();
98}
99 90
100void Config::SaveMiscellaneous() {
101 qt_config->beginGroup("Miscellaneous"); 91 qt_config->beginGroup("Miscellaneous");
102 qt_config->setValue("enable_log", Settings::values.enable_log); 92 qt_config->setValue("log_filter", QString::fromStdString(Settings::values.log_filter));
103 qt_config->endGroup(); 93 qt_config->endGroup();
104} 94}
105 95
106void Config::Reload() { 96void Config::Reload() {
107 ReadControls(); 97 ReadValues();
108 ReadCore();
109 ReadData();
110 ReadMiscellaneous();
111} 98}
112 99
113void Config::Save() { 100void Config::Save() {
114 SaveControls(); 101 SaveValues();
115 SaveCore();
116 SaveData();
117 SaveMiscellaneous();
118} 102}
119 103
120Config::~Config() { 104Config::~Config() {
diff --git a/src/citra_qt/config.h b/src/citra_qt/config.h
index 8c6568cb2..4485cae73 100644
--- a/src/citra_qt/config.h
+++ b/src/citra_qt/config.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -12,15 +12,8 @@ class Config {
12 QSettings* qt_config; 12 QSettings* qt_config;
13 std::string qt_config_loc; 13 std::string qt_config_loc;
14 14
15 void ReadControls(); 15 void ReadValues();
16 void SaveControls(); 16 void SaveValues();
17 void ReadCore();
18 void SaveCore();
19 void ReadData();
20 void SaveData();
21
22 void ReadMiscellaneous();
23 void SaveMiscellaneous();
24public: 17public:
25 Config(); 18 Config();
26 ~Config(); 19 ~Config();
diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp
index 895851be3..a9ec2f7fe 100644
--- a/src/citra_qt/debugger/callstack.cpp
+++ b/src/citra_qt/debugger/callstack.cpp
@@ -27,10 +27,10 @@ void CallstackWidget::OnCPUStepped()
27 ARM_Interface* app_core = Core::g_app_core; 27 ARM_Interface* app_core = Core::g_app_core;
28 28
29 u32 sp = app_core->GetReg(13); //stack pointer 29 u32 sp = app_core->GetReg(13); //stack pointer
30 u32 addr, ret_addr, call_addr, func_addr; 30 u32 ret_addr, call_addr, func_addr;
31 31
32 int counter = 0; 32 int counter = 0;
33 for (int addr = 0x10000000; addr >= sp; addr -= 4) 33 for (u32 addr = 0x10000000; addr >= sp; addr -= 4)
34 { 34 {
35 ret_addr = Memory::Read32(addr); 35 ret_addr = Memory::Read32(addr);
36 call_addr = ret_addr - 4; //get call address??? 36 call_addr = ret_addr - 4; //get call address???
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp
index 2ee877743..14745f3bb 100644
--- a/src/citra_qt/debugger/disassembler.cpp
+++ b/src/citra_qt/debugger/disassembler.cpp
@@ -220,7 +220,9 @@ void DisassemblerWidget::OnPause()
220 emu_thread.SetCpuRunning(false); 220 emu_thread.SetCpuRunning(false);
221 221
222 // TODO: By now, the CPU might not have actually stopped... 222 // TODO: By now, the CPU might not have actually stopped...
223 model->SetNextInstruction(Core::g_app_core->GetPC()); 223 if (Core::g_app_core) {
224 model->SetNextInstruction(Core::g_app_core->GetPC());
225 }
224} 226}
225 227
226void DisassemblerWidget::OnToggleStartStop() 228void DisassemblerWidget::OnToggleStartStop()
diff --git a/src/citra_qt/debugger/graphics.cpp b/src/citra_qt/debugger/graphics.cpp
index a86a55404..6ff4c290d 100644
--- a/src/citra_qt/debugger/graphics.cpp
+++ b/src/citra_qt/debugger/graphics.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "graphics.hxx" 5#include "graphics.hxx"
diff --git a/src/citra_qt/debugger/graphics.hxx b/src/citra_qt/debugger/graphics.hxx
index 72656f93c..8119b4c87 100644
--- a/src/citra_qt/debugger/graphics.hxx
+++ b/src/citra_qt/debugger/graphics.hxx
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp
new file mode 100644
index 000000000..9486f06cc
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_breakpoints.cpp
@@ -0,0 +1,263 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QMetaType>
6#include <QPushButton>
7#include <QTreeWidget>
8#include <QVBoxLayout>
9#include <QLabel>
10
11#include "graphics_breakpoints.hxx"
12#include "graphics_breakpoints_p.hxx"
13
14BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_context, QObject* parent)
15 : QAbstractListModel(parent), context_weak(debug_context),
16 at_breakpoint(debug_context->at_breakpoint),
17 active_breakpoint(debug_context->active_breakpoint)
18{
19
20}
21
22int BreakPointModel::columnCount(const QModelIndex& parent) const
23{
24 return 2;
25}
26
27int BreakPointModel::rowCount(const QModelIndex& parent) const
28{
29 return static_cast<int>(Pica::DebugContext::Event::NumEvents);
30}
31
32QVariant BreakPointModel::data(const QModelIndex& index, int role) const
33{
34 const auto event = static_cast<Pica::DebugContext::Event>(index.row());
35
36 switch (role) {
37 case Qt::DisplayRole:
38 {
39 switch (index.column()) {
40 case 0:
41 {
42 static const std::map<Pica::DebugContext::Event, QString> map = {
43 { Pica::DebugContext::Event::CommandLoaded, tr("Pica command loaded") },
44 { Pica::DebugContext::Event::CommandProcessed, tr("Pica command processed") },
45 { Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch") },
46 { Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch") },
47 { Pica::DebugContext::Event::VertexLoaded, tr("Vertex Loaded") }
48 };
49
50 _dbg_assert_(Debug_GPU, map.size() == static_cast<size_t>(Pica::DebugContext::Event::NumEvents));
51
52 return (map.find(event) != map.end()) ? map.at(event) : QString();
53 }
54
55 case 1:
56 return data(index, Role_IsEnabled).toBool() ? tr("Enabled") : tr("Disabled");
57
58 default:
59 break;
60 }
61
62 break;
63 }
64
65 case Qt::BackgroundRole:
66 {
67 if (at_breakpoint && index.row() == static_cast<int>(active_breakpoint)) {
68 return QBrush(QColor(0xE0, 0xE0, 0x10));
69 }
70 break;
71 }
72
73 case Role_IsEnabled:
74 {
75 auto context = context_weak.lock();
76 return context && context->breakpoints[event].enabled;
77 }
78
79 default:
80 break;
81 }
82 return QVariant();
83}
84
85QVariant BreakPointModel::headerData(int section, Qt::Orientation orientation, int role) const
86{
87 switch(role) {
88 case Qt::DisplayRole:
89 {
90 if (section == 0) {
91 return tr("Event");
92 } else if (section == 1) {
93 return tr("Status");
94 }
95
96 break;
97 }
98 }
99
100 return QVariant();
101}
102
103bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, int role)
104{
105 const auto event = static_cast<Pica::DebugContext::Event>(index.row());
106
107 switch (role) {
108 case Role_IsEnabled:
109 {
110 auto context = context_weak.lock();
111 if (!context)
112 return false;
113
114 context->breakpoints[event].enabled = value.toBool();
115 QModelIndex changed_index = createIndex(index.row(), 1);
116 emit dataChanged(changed_index, changed_index);
117 return true;
118 }
119 }
120
121 return false;
122}
123
124
125void BreakPointModel::OnBreakPointHit(Pica::DebugContext::Event event)
126{
127 auto context = context_weak.lock();
128 if (!context)
129 return;
130
131 active_breakpoint = context->active_breakpoint;
132 at_breakpoint = context->at_breakpoint;
133 emit dataChanged(createIndex(static_cast<int>(event), 0),
134 createIndex(static_cast<int>(event), 1));
135}
136
137void BreakPointModel::OnResumed()
138{
139 auto context = context_weak.lock();
140 if (!context)
141 return;
142
143 at_breakpoint = context->at_breakpoint;
144 emit dataChanged(createIndex(static_cast<int>(active_breakpoint), 0),
145 createIndex(static_cast<int>(active_breakpoint), 1));
146 active_breakpoint = context->active_breakpoint;
147}
148
149
150GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::DebugContext> debug_context,
151 QWidget* parent)
152 : QDockWidget(tr("Pica Breakpoints"), parent),
153 Pica::DebugContext::BreakPointObserver(debug_context)
154{
155 setObjectName("PicaBreakPointsWidget");
156
157 status_text = new QLabel(tr("Emulation running"));
158 resume_button = new QPushButton(tr("Resume"));
159 resume_button->setEnabled(false);
160
161 breakpoint_model = new BreakPointModel(debug_context, this);
162 breakpoint_list = new QTreeView;
163 breakpoint_list->setModel(breakpoint_model);
164
165 toggle_breakpoint_button = new QPushButton(tr("Enable"));
166 toggle_breakpoint_button->setEnabled(false);
167
168 qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event");
169
170 connect(resume_button, SIGNAL(clicked()), this, SLOT(OnResumeRequested()));
171
172 connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)),
173 this, SLOT(OnBreakPointHit(Pica::DebugContext::Event,void*)),
174 Qt::BlockingQueuedConnection);
175 connect(this, SIGNAL(Resumed()), this, SLOT(OnResumed()));
176
177 connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)),
178 breakpoint_model, SLOT(OnBreakPointHit(Pica::DebugContext::Event)),
179 Qt::BlockingQueuedConnection);
180 connect(this, SIGNAL(Resumed()), breakpoint_model, SLOT(OnResumed()));
181
182 connect(this, SIGNAL(BreakPointsChanged(const QModelIndex&,const QModelIndex&)),
183 breakpoint_model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)));
184
185 connect(breakpoint_list->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
186 this, SLOT(OnBreakpointSelectionChanged(QModelIndex)));
187
188 connect(toggle_breakpoint_button, SIGNAL(clicked()), this, SLOT(OnToggleBreakpointEnabled()));
189
190 QWidget* main_widget = new QWidget;
191 auto main_layout = new QVBoxLayout;
192 {
193 auto sub_layout = new QHBoxLayout;
194 sub_layout->addWidget(status_text);
195 sub_layout->addWidget(resume_button);
196 main_layout->addLayout(sub_layout);
197 }
198 main_layout->addWidget(breakpoint_list);
199 main_layout->addWidget(toggle_breakpoint_button);
200 main_widget->setLayout(main_layout);
201
202 setWidget(main_widget);
203}
204
205void GraphicsBreakPointsWidget::OnPicaBreakPointHit(Event event, void* data)
206{
207 // Process in GUI thread
208 emit BreakPointHit(event, data);
209}
210
211void GraphicsBreakPointsWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data)
212{
213 status_text->setText(tr("Emulation halted at breakpoint"));
214 resume_button->setEnabled(true);
215}
216
217void GraphicsBreakPointsWidget::OnPicaResume()
218{
219 // Process in GUI thread
220 emit Resumed();
221}
222
223void GraphicsBreakPointsWidget::OnResumed()
224{
225 status_text->setText(tr("Emulation running"));
226 resume_button->setEnabled(false);
227}
228
229void GraphicsBreakPointsWidget::OnResumeRequested()
230{
231 if (auto context = context_weak.lock())
232 context->Resume();
233}
234
235void GraphicsBreakPointsWidget::OnBreakpointSelectionChanged(const QModelIndex& index)
236{
237 if (!index.isValid()) {
238 toggle_breakpoint_button->setEnabled(false);
239 return;
240 }
241
242 toggle_breakpoint_button->setEnabled(true);
243 UpdateToggleBreakpointButton(index);
244}
245
246void GraphicsBreakPointsWidget::OnToggleBreakpointEnabled()
247{
248 QModelIndex index = breakpoint_list->selectionModel()->currentIndex();
249 bool new_state = !(breakpoint_model->data(index, BreakPointModel::Role_IsEnabled).toBool());
250
251 breakpoint_model->setData(index, new_state,
252 BreakPointModel::Role_IsEnabled);
253 UpdateToggleBreakpointButton(index);
254}
255
256void GraphicsBreakPointsWidget::UpdateToggleBreakpointButton(const QModelIndex& index)
257{
258 if (true == breakpoint_model->data(index, BreakPointModel::Role_IsEnabled).toBool()) {
259 toggle_breakpoint_button->setText(tr("Disable"));
260 } else {
261 toggle_breakpoint_button->setText(tr("Enable"));
262 }
263}
diff --git a/src/citra_qt/debugger/graphics_breakpoints.hxx b/src/citra_qt/debugger/graphics_breakpoints.hxx
new file mode 100644
index 000000000..5b9ba324e
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_breakpoints.hxx
@@ -0,0 +1,53 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8
9#include <QAbstractListModel>
10#include <QDockWidget>
11
12#include "video_core/debug_utils/debug_utils.h"
13
14class QLabel;
15class QPushButton;
16class QTreeView;
17
18class BreakPointModel;
19
20class GraphicsBreakPointsWidget : public QDockWidget, Pica::DebugContext::BreakPointObserver {
21 Q_OBJECT
22
23 using Event = Pica::DebugContext::Event;
24
25public:
26 GraphicsBreakPointsWidget(std::shared_ptr<Pica::DebugContext> debug_context,
27 QWidget* parent = nullptr);
28
29 void OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) override;
30 void OnPicaResume() override;
31
32public slots:
33 void OnBreakPointHit(Pica::DebugContext::Event event, void* data);
34 void OnResumeRequested();
35 void OnResumed();
36 void OnBreakpointSelectionChanged(const QModelIndex&);
37 void OnToggleBreakpointEnabled();
38
39signals:
40 void Resumed();
41 void BreakPointHit(Pica::DebugContext::Event event, void* data);
42 void BreakPointsChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
43
44private:
45 void UpdateToggleBreakpointButton(const QModelIndex& index);
46
47 QLabel* status_text;
48 QPushButton* resume_button;
49 QPushButton* toggle_breakpoint_button;
50
51 BreakPointModel* breakpoint_model;
52 QTreeView* breakpoint_list;
53};
diff --git a/src/citra_qt/debugger/graphics_breakpoints_p.hxx b/src/citra_qt/debugger/graphics_breakpoints_p.hxx
new file mode 100644
index 000000000..232bfc863
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_breakpoints_p.hxx
@@ -0,0 +1,38 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8
9#include <QAbstractListModel>
10
11#include "video_core/debug_utils/debug_utils.h"
12
13class BreakPointModel : public QAbstractListModel {
14 Q_OBJECT
15
16public:
17 enum {
18 Role_IsEnabled = Qt::UserRole,
19 };
20
21 BreakPointModel(std::shared_ptr<Pica::DebugContext> context, QObject* parent);
22
23 int columnCount(const QModelIndex& parent = QModelIndex()) const override;
24 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
25 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
26 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
27
28 bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole);
29
30public slots:
31 void OnBreakPointHit(Pica::DebugContext::Event event);
32 void OnResumed();
33
34private:
35 std::weak_ptr<Pica::DebugContext> context_weak;
36 bool at_breakpoint;
37 Pica::DebugContext::Event active_breakpoint;
38};
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp
index 71dd166cd..753cc25da 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.cpp
+++ b/src/citra_qt/debugger/graphics_cmdlists.cpp
@@ -1,31 +1,179 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <QLabel>
5#include <QListView> 6#include <QListView>
7#include <QMainWindow>
6#include <QPushButton> 8#include <QPushButton>
7#include <QVBoxLayout> 9#include <QVBoxLayout>
8#include <QTreeView> 10#include <QTreeView>
11#include <QSpinBox>
12#include <QComboBox>
13
14#include "video_core/pica.h"
15#include "video_core/math.h"
16
17#include "video_core/debug_utils/debug_utils.h"
9 18
10#include "graphics_cmdlists.hxx" 19#include "graphics_cmdlists.hxx"
11 20
12GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent) 21#include "util/spinbox.hxx"
13{ 22
23QImage LoadTexture(u8* src, const Pica::DebugUtils::TextureInfo& info) {
24 QImage decoded_image(info.width, info.height, QImage::Format_ARGB32);
25 for (int y = 0; y < info.height; ++y) {
26 for (int x = 0; x < info.width; ++x) {
27 Math::Vec4<u8> color = Pica::DebugUtils::LookupTexture(src, x, y, info, true);
28 decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a()));
29 }
30 }
31
32 return decoded_image;
33}
34
35class TextureInfoWidget : public QWidget {
36public:
37 TextureInfoWidget(u8* src, const Pica::DebugUtils::TextureInfo& info, QWidget* parent = nullptr) : QWidget(parent) {
38 QLabel* image_widget = new QLabel;
39 QPixmap image_pixmap = QPixmap::fromImage(LoadTexture(src, info));
40 image_pixmap = image_pixmap.scaled(200, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation);
41 image_widget->setPixmap(image_pixmap);
42
43 QVBoxLayout* layout = new QVBoxLayout;
44 layout->addWidget(image_widget);
45 setLayout(layout);
46 }
47};
48
49TextureInfoDockWidget::TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo& info, QWidget* parent)
50 : QDockWidget(tr("Texture 0x%1").arg(info.physical_address, 8, 16, QLatin1Char('0'))),
51 info(info) {
52
53 QWidget* main_widget = new QWidget;
54
55 QLabel* image_widget = new QLabel;
56
57 connect(this, SIGNAL(UpdatePixmap(const QPixmap&)), image_widget, SLOT(setPixmap(const QPixmap&)));
58
59 CSpinBox* phys_address_spinbox = new CSpinBox;
60 phys_address_spinbox->SetBase(16);
61 phys_address_spinbox->SetRange(0, 0xFFFFFFFF);
62 phys_address_spinbox->SetPrefix("0x");
63 phys_address_spinbox->SetValue(info.physical_address);
64 connect(phys_address_spinbox, SIGNAL(ValueChanged(qint64)), this, SLOT(OnAddressChanged(qint64)));
65
66 QComboBox* format_choice = new QComboBox;
67 format_choice->addItem(tr("RGBA8"));
68 format_choice->addItem(tr("RGB8"));
69 format_choice->addItem(tr("RGBA5551"));
70 format_choice->addItem(tr("RGB565"));
71 format_choice->addItem(tr("RGBA4"));
72 format_choice->addItem(tr("IA8"));
73 format_choice->addItem(tr("UNK6"));
74 format_choice->addItem(tr("I8"));
75 format_choice->addItem(tr("A8"));
76 format_choice->addItem(tr("IA4"));
77 format_choice->addItem(tr("UNK10"));
78 format_choice->addItem(tr("A4"));
79 format_choice->setCurrentIndex(static_cast<int>(info.format));
80 connect(format_choice, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFormatChanged(int)));
81
82 QSpinBox* width_spinbox = new QSpinBox;
83 width_spinbox->setMaximum(65535);
84 width_spinbox->setValue(info.width);
85 connect(width_spinbox, SIGNAL(valueChanged(int)), this, SLOT(OnWidthChanged(int)));
86
87 QSpinBox* height_spinbox = new QSpinBox;
88 height_spinbox->setMaximum(65535);
89 height_spinbox->setValue(info.height);
90 connect(height_spinbox, SIGNAL(valueChanged(int)), this, SLOT(OnHeightChanged(int)));
91
92 QSpinBox* stride_spinbox = new QSpinBox;
93 stride_spinbox->setMaximum(65535 * 4);
94 stride_spinbox->setValue(info.stride);
95 connect(stride_spinbox, SIGNAL(valueChanged(int)), this, SLOT(OnStrideChanged(int)));
96
97 QVBoxLayout* main_layout = new QVBoxLayout;
98 main_layout->addWidget(image_widget);
99
100 {
101 QHBoxLayout* sub_layout = new QHBoxLayout;
102 sub_layout->addWidget(new QLabel(tr("Source Address:")));
103 sub_layout->addWidget(phys_address_spinbox);
104 main_layout->addLayout(sub_layout);
105 }
106
107 {
108 QHBoxLayout* sub_layout = new QHBoxLayout;
109 sub_layout->addWidget(new QLabel(tr("Format")));
110 sub_layout->addWidget(format_choice);
111 main_layout->addLayout(sub_layout);
112 }
113
114 {
115 QHBoxLayout* sub_layout = new QHBoxLayout;
116 sub_layout->addWidget(new QLabel(tr("Width:")));
117 sub_layout->addWidget(width_spinbox);
118 sub_layout->addStretch();
119 sub_layout->addWidget(new QLabel(tr("Height:")));
120 sub_layout->addWidget(height_spinbox);
121 sub_layout->addStretch();
122 sub_layout->addWidget(new QLabel(tr("Stride:")));
123 sub_layout->addWidget(stride_spinbox);
124 main_layout->addLayout(sub_layout);
125 }
126
127 main_widget->setLayout(main_layout);
128
129 emit UpdatePixmap(ReloadPixmap());
130
131 setWidget(main_widget);
132}
133
134void TextureInfoDockWidget::OnAddressChanged(qint64 value) {
135 info.physical_address = value;
136 emit UpdatePixmap(ReloadPixmap());
137}
14 138
139void TextureInfoDockWidget::OnFormatChanged(int value) {
140 info.format = static_cast<Pica::Regs::TextureFormat>(value);
141 emit UpdatePixmap(ReloadPixmap());
15} 142}
16 143
17int GPUCommandListModel::rowCount(const QModelIndex& parent) const 144void TextureInfoDockWidget::OnWidthChanged(int value) {
18{ 145 info.width = value;
146 emit UpdatePixmap(ReloadPixmap());
147}
148
149void TextureInfoDockWidget::OnHeightChanged(int value) {
150 info.height = value;
151 emit UpdatePixmap(ReloadPixmap());
152}
153
154void TextureInfoDockWidget::OnStrideChanged(int value) {
155 info.stride = value;
156 emit UpdatePixmap(ReloadPixmap());
157}
158
159QPixmap TextureInfoDockWidget::ReloadPixmap() const {
160 u8* src = Memory::GetPointer(Pica::PAddrToVAddr(info.physical_address));
161 return QPixmap::fromImage(LoadTexture(src, info));
162}
163
164GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(parent) {
165
166}
167
168int GPUCommandListModel::rowCount(const QModelIndex& parent) const {
19 return pica_trace.writes.size(); 169 return pica_trace.writes.size();
20} 170}
21 171
22int GPUCommandListModel::columnCount(const QModelIndex& parent) const 172int GPUCommandListModel::columnCount(const QModelIndex& parent) const {
23{
24 return 2; 173 return 2;
25} 174}
26 175
27QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const 176QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const {
28{
29 if (!index.isValid()) 177 if (!index.isValid())
30 return QVariant(); 178 return QVariant();
31 179
@@ -36,21 +184,39 @@ QVariant GPUCommandListModel::data(const QModelIndex& index, int role) const
36 if (role == Qt::DisplayRole) { 184 if (role == Qt::DisplayRole) {
37 QString content; 185 QString content;
38 if (index.column() == 0) { 186 if (index.column() == 0) {
39 content = QString::fromLatin1(Pica::Regs::GetCommandName(cmd.cmd_id).c_str()); 187 QString content = QString::fromLatin1(Pica::Regs::GetCommandName(cmd.cmd_id).c_str());
40 content.append(" "); 188 content.append(" ");
189 return content;
41 } else if (index.column() == 1) { 190 } else if (index.column() == 1) {
42 content.append(QString("%1 ").arg(cmd.hex, 8, 16, QLatin1Char('0'))); 191 QString content = QString("%1 ").arg(cmd.hex, 8, 16, QLatin1Char('0'));
43 content.append(QString("%1 ").arg(val, 8, 16, QLatin1Char('0'))); 192 content.append(QString("%1 ").arg(val, 8, 16, QLatin1Char('0')));
193 return content;
44 } 194 }
195 } else if (role == CommandIdRole) {
196 return QVariant::fromValue<int>(cmd.cmd_id.Value());
197 }
45 198
46 return QVariant(content); 199 return QVariant();
200}
201
202QVariant GPUCommandListModel::headerData(int section, Qt::Orientation orientation, int role) const {
203 switch(role) {
204 case Qt::DisplayRole:
205 {
206 if (section == 0) {
207 return tr("Command Name");
208 } else if (section == 1) {
209 return tr("Data");
210 }
211
212 break;
213 }
47 } 214 }
48 215
49 return QVariant(); 216 return QVariant();
50} 217}
51 218
52void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& trace) 219void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& trace) {
53{
54 beginResetModel(); 220 beginResetModel();
55 221
56 pica_trace = trace; 222 pica_trace = trace;
@@ -58,38 +224,107 @@ void GPUCommandListModel::OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&
58 endResetModel(); 224 endResetModel();
59} 225}
60 226
227#define COMMAND_IN_RANGE(cmd_id, reg_name) \
228 (cmd_id >= PICA_REG_INDEX(reg_name) && \
229 cmd_id < PICA_REG_INDEX(reg_name) + sizeof(decltype(Pica::registers.reg_name)) / 4)
61 230
62GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pica Command List"), parent) 231void GPUCommandListWidget::OnCommandDoubleClicked(const QModelIndex& index) {
63{ 232 const int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toInt();
233 if (COMMAND_IN_RANGE(command_id, texture0) ||
234 COMMAND_IN_RANGE(command_id, texture1) ||
235 COMMAND_IN_RANGE(command_id, texture2)) {
236
237 unsigned index;
238 if (COMMAND_IN_RANGE(command_id, texture0)) {
239 index = 0;
240 } else if (COMMAND_IN_RANGE(command_id, texture1)) {
241 index = 1;
242 } else {
243 index = 2;
244 }
245 auto config = Pica::registers.GetTextures()[index].config;
246 auto format = Pica::registers.GetTextures()[index].format;
247 auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format);
248
249 // TODO: Instead, emit a signal here to be caught by the main window widget.
250 auto main_window = static_cast<QMainWindow*>(parent());
251 main_window->tabifyDockWidget(this, new TextureInfoDockWidget(info, main_window));
252 }
253}
254
255void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
256 QWidget* new_info_widget;
257
258 const int command_id = list_widget->model()->data(index, GPUCommandListModel::CommandIdRole).toInt();
259 if (COMMAND_IN_RANGE(command_id, texture0) ||
260 COMMAND_IN_RANGE(command_id, texture1) ||
261 COMMAND_IN_RANGE(command_id, texture2)) {
262
263 unsigned index;
264 if (COMMAND_IN_RANGE(command_id, texture0)) {
265 index = 0;
266 } else if (COMMAND_IN_RANGE(command_id, texture1)) {
267 index = 1;
268 } else {
269 index = 2;
270 }
271 auto config = Pica::registers.GetTextures()[index].config;
272 auto format = Pica::registers.GetTextures()[index].format;
273
274 auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config, format);
275 u8* src = Memory::GetPointer(Pica::PAddrToVAddr(config.GetPhysicalAddress()));
276 new_info_widget = new TextureInfoWidget(src, info);
277 } else {
278 new_info_widget = new QWidget;
279 }
280
281 widget()->layout()->removeWidget(command_info_widget);
282 delete command_info_widget;
283 widget()->layout()->addWidget(new_info_widget);
284 command_info_widget = new_info_widget;
285}
286#undef COMMAND_IN_RANGE
287
288GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pica Command List"), parent) {
289 setObjectName("Pica Command List");
64 GPUCommandListModel* model = new GPUCommandListModel(this); 290 GPUCommandListModel* model = new GPUCommandListModel(this);
65 291
66 QWidget* main_widget = new QWidget; 292 QWidget* main_widget = new QWidget;
67 293
68 QTreeView* list_widget = new QTreeView; 294 list_widget = new QTreeView;
69 list_widget->setModel(model); 295 list_widget->setModel(model);
70 list_widget->setFont(QFont("monospace")); 296 list_widget->setFont(QFont("monospace"));
71 list_widget->setRootIsDecorated(false); 297 list_widget->setRootIsDecorated(false);
72 298
73 QPushButton* toggle_tracing = new QPushButton(tr("Start Tracing")); 299 connect(list_widget->selectionModel(), SIGNAL(currentChanged(const QModelIndex&,const QModelIndex&)),
300 this, SLOT(SetCommandInfo(const QModelIndex&)));
301 connect(list_widget, SIGNAL(doubleClicked(const QModelIndex&)),
302 this, SLOT(OnCommandDoubleClicked(const QModelIndex&)));
303
304 toggle_tracing = new QPushButton(tr("Start Tracing"));
74 305
75 connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing())); 306 connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing()));
76 connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)), 307 connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)),
77 model, SLOT(OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&))); 308 model, SLOT(OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&)));
78 309
310 command_info_widget = new QWidget;
311
79 QVBoxLayout* main_layout = new QVBoxLayout; 312 QVBoxLayout* main_layout = new QVBoxLayout;
80 main_layout->addWidget(list_widget); 313 main_layout->addWidget(list_widget);
81 main_layout->addWidget(toggle_tracing); 314 main_layout->addWidget(toggle_tracing);
315 main_layout->addWidget(command_info_widget);
82 main_widget->setLayout(main_layout); 316 main_widget->setLayout(main_layout);
83 317
84 setWidget(main_widget); 318 setWidget(main_widget);
85} 319}
86 320
87void GPUCommandListWidget::OnToggleTracing() 321void GPUCommandListWidget::OnToggleTracing() {
88{
89 if (!Pica::DebugUtils::IsPicaTracing()) { 322 if (!Pica::DebugUtils::IsPicaTracing()) {
90 Pica::DebugUtils::StartPicaTracing(); 323 Pica::DebugUtils::StartPicaTracing();
324 toggle_tracing->setText(tr("Finish Tracing"));
91 } else { 325 } else {
92 pica_trace = Pica::DebugUtils::FinishPicaTracing(); 326 pica_trace = Pica::DebugUtils::FinishPicaTracing();
93 emit TracingFinished(*pica_trace); 327 emit TracingFinished(*pica_trace);
328 toggle_tracing->setText(tr("Start Tracing"));
94 } 329 }
95} 330}
diff --git a/src/citra_qt/debugger/graphics_cmdlists.hxx b/src/citra_qt/debugger/graphics_cmdlists.hxx
index 1523e724f..a465d044c 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.hxx
+++ b/src/citra_qt/debugger/graphics_cmdlists.hxx
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -10,16 +10,24 @@
10#include "video_core/gpu_debugger.h" 10#include "video_core/gpu_debugger.h"
11#include "video_core/debug_utils/debug_utils.h" 11#include "video_core/debug_utils/debug_utils.h"
12 12
13class QPushButton;
14class QTreeView;
15
13class GPUCommandListModel : public QAbstractListModel 16class GPUCommandListModel : public QAbstractListModel
14{ 17{
15 Q_OBJECT 18 Q_OBJECT
16 19
17public: 20public:
21 enum {
22 CommandIdRole = Qt::UserRole,
23 };
24
18 GPUCommandListModel(QObject* parent); 25 GPUCommandListModel(QObject* parent);
19 26
20 int columnCount(const QModelIndex& parent = QModelIndex()) const override; 27 int columnCount(const QModelIndex& parent = QModelIndex()) const override;
21 int rowCount(const QModelIndex& parent = QModelIndex()) const override; 28 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
22 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; 29 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
30 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
23 31
24public slots: 32public slots:
25 void OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& trace); 33 void OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace& trace);
@@ -37,10 +45,39 @@ public:
37 45
38public slots: 46public slots:
39 void OnToggleTracing(); 47 void OnToggleTracing();
48 void OnCommandDoubleClicked(const QModelIndex&);
49
50 void SetCommandInfo(const QModelIndex&);
40 51
41signals: 52signals:
42 void TracingFinished(const Pica::DebugUtils::PicaTrace&); 53 void TracingFinished(const Pica::DebugUtils::PicaTrace&);
43 54
44private: 55private:
45 std::unique_ptr<Pica::DebugUtils::PicaTrace> pica_trace; 56 std::unique_ptr<Pica::DebugUtils::PicaTrace> pica_trace;
57
58 QTreeView* list_widget;
59 QWidget* command_info_widget;
60 QPushButton* toggle_tracing;
61};
62
63class TextureInfoDockWidget : public QDockWidget {
64 Q_OBJECT
65
66public:
67 TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo& info, QWidget* parent = nullptr);
68
69signals:
70 void UpdatePixmap(const QPixmap& pixmap);
71
72private slots:
73 void OnAddressChanged(qint64 value);
74 void OnFormatChanged(int value);
75 void OnWidthChanged(int value);
76 void OnHeightChanged(int value);
77 void OnStrideChanged(int value);
78
79private:
80 QPixmap ReloadPixmap() const;
81
82 Pica::DebugUtils::TextureInfo info;
46}; 83};
diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp
new file mode 100644
index 000000000..dd41c3880
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_framebuffer.cpp
@@ -0,0 +1,283 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <QBoxLayout>
6#include <QComboBox>
7#include <QDebug>
8#include <QLabel>
9#include <QMetaType>
10#include <QPushButton>
11#include <QSpinBox>
12
13#include "video_core/pica.h"
14
15#include "graphics_framebuffer.hxx"
16
17#include "util/spinbox.hxx"
18
19BreakPointObserverDock::BreakPointObserverDock(std::shared_ptr<Pica::DebugContext> debug_context,
20 const QString& title, QWidget* parent)
21 : QDockWidget(title, parent), BreakPointObserver(debug_context)
22{
23 qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event");
24
25 connect(this, SIGNAL(Resumed()), this, SLOT(OnResumed()));
26
27 // NOTE: This signal is emitted from a non-GUI thread, but connect() takes
28 // care of delaying its handling to the GUI thread.
29 connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)),
30 this, SLOT(OnBreakPointHit(Pica::DebugContext::Event,void*)),
31 Qt::BlockingQueuedConnection);
32}
33
34void BreakPointObserverDock::OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data)
35{
36 emit BreakPointHit(event, data);
37}
38
39void BreakPointObserverDock::OnPicaResume()
40{
41 emit Resumed();
42}
43
44
45GraphicsFramebufferWidget::GraphicsFramebufferWidget(std::shared_ptr<Pica::DebugContext> debug_context,
46 QWidget* parent)
47 : BreakPointObserverDock(debug_context, tr("Pica Framebuffer"), parent),
48 framebuffer_source(Source::PicaTarget)
49{
50 setObjectName("PicaFramebuffer");
51
52 framebuffer_source_list = new QComboBox;
53 framebuffer_source_list->addItem(tr("Active Render Target"));
54 framebuffer_source_list->addItem(tr("Custom"));
55 framebuffer_source_list->setCurrentIndex(static_cast<int>(framebuffer_source));
56
57 framebuffer_address_control = new CSpinBox;
58 framebuffer_address_control->SetBase(16);
59 framebuffer_address_control->SetRange(0, 0xFFFFFFFF);
60 framebuffer_address_control->SetPrefix("0x");
61
62 framebuffer_width_control = new QSpinBox;
63 framebuffer_width_control->setMinimum(1);
64 framebuffer_width_control->setMaximum(std::numeric_limits<int>::max()); // TODO: Find actual maximum
65
66 framebuffer_height_control = new QSpinBox;
67 framebuffer_height_control->setMinimum(1);
68 framebuffer_height_control->setMaximum(std::numeric_limits<int>::max()); // TODO: Find actual maximum
69
70 framebuffer_format_control = new QComboBox;
71 framebuffer_format_control->addItem(tr("RGBA8"));
72 framebuffer_format_control->addItem(tr("RGB8"));
73 framebuffer_format_control->addItem(tr("RGBA5551"));
74 framebuffer_format_control->addItem(tr("RGB565"));
75 framebuffer_format_control->addItem(tr("RGBA4"));
76
77 // TODO: This QLabel should shrink the image to the available space rather than just expanding...
78 framebuffer_picture_label = new QLabel;
79
80 auto enlarge_button = new QPushButton(tr("Enlarge"));
81
82 // Connections
83 connect(this, SIGNAL(Update()), this, SLOT(OnUpdate()));
84 connect(framebuffer_source_list, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFramebufferSourceChanged(int)));
85 connect(framebuffer_address_control, SIGNAL(ValueChanged(qint64)), this, SLOT(OnFramebufferAddressChanged(qint64)));
86 connect(framebuffer_width_control, SIGNAL(valueChanged(int)), this, SLOT(OnFramebufferWidthChanged(int)));
87 connect(framebuffer_height_control, SIGNAL(valueChanged(int)), this, SLOT(OnFramebufferHeightChanged(int)));
88 connect(framebuffer_format_control, SIGNAL(currentIndexChanged(int)), this, SLOT(OnFramebufferFormatChanged(int)));
89
90 auto main_widget = new QWidget;
91 auto main_layout = new QVBoxLayout;
92 {
93 auto sub_layout = new QHBoxLayout;
94 sub_layout->addWidget(new QLabel(tr("Source:")));
95 sub_layout->addWidget(framebuffer_source_list);
96 main_layout->addLayout(sub_layout);
97 }
98 {
99 auto sub_layout = new QHBoxLayout;
100 sub_layout->addWidget(new QLabel(tr("Virtual Address:")));
101 sub_layout->addWidget(framebuffer_address_control);
102 main_layout->addLayout(sub_layout);
103 }
104 {
105 auto sub_layout = new QHBoxLayout;
106 sub_layout->addWidget(new QLabel(tr("Width:")));
107 sub_layout->addWidget(framebuffer_width_control);
108 main_layout->addLayout(sub_layout);
109 }
110 {
111 auto sub_layout = new QHBoxLayout;
112 sub_layout->addWidget(new QLabel(tr("Height:")));
113 sub_layout->addWidget(framebuffer_height_control);
114 main_layout->addLayout(sub_layout);
115 }
116 {
117 auto sub_layout = new QHBoxLayout;
118 sub_layout->addWidget(new QLabel(tr("Format:")));
119 sub_layout->addWidget(framebuffer_format_control);
120 main_layout->addLayout(sub_layout);
121 }
122 main_layout->addWidget(framebuffer_picture_label);
123 main_layout->addWidget(enlarge_button);
124 main_widget->setLayout(main_layout);
125 setWidget(main_widget);
126
127 // Load current data - TODO: Make sure this works when emulation is not running
128 if (debug_context && debug_context->at_breakpoint)
129 emit Update();
130 widget()->setEnabled(false); // TODO: Only enable if currently at breakpoint
131}
132
133void GraphicsFramebufferWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data)
134{
135 emit Update();
136 widget()->setEnabled(true);
137}
138
139void GraphicsFramebufferWidget::OnResumed()
140{
141 widget()->setEnabled(false);
142}
143
144void GraphicsFramebufferWidget::OnFramebufferSourceChanged(int new_value)
145{
146 framebuffer_source = static_cast<Source>(new_value);
147 emit Update();
148}
149
150void GraphicsFramebufferWidget::OnFramebufferAddressChanged(qint64 new_value)
151{
152 if (framebuffer_address != new_value) {
153 framebuffer_address = static_cast<unsigned>(new_value);
154
155 framebuffer_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
156 emit Update();
157 }
158}
159
160void GraphicsFramebufferWidget::OnFramebufferWidthChanged(int new_value)
161{
162 if (framebuffer_width != new_value) {
163 framebuffer_width = new_value;
164
165 framebuffer_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
166 emit Update();
167 }
168}
169
170void GraphicsFramebufferWidget::OnFramebufferHeightChanged(int new_value)
171{
172 if (framebuffer_height != new_value) {
173 framebuffer_height = new_value;
174
175 framebuffer_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
176 emit Update();
177 }
178}
179
180void GraphicsFramebufferWidget::OnFramebufferFormatChanged(int new_value)
181{
182 if (framebuffer_format != static_cast<Format>(new_value)) {
183 framebuffer_format = static_cast<Format>(new_value);
184
185 framebuffer_source_list->setCurrentIndex(static_cast<int>(Source::Custom));
186 emit Update();
187 }
188}
189
190void GraphicsFramebufferWidget::OnUpdate()
191{
192 QPixmap pixmap;
193
194 switch (framebuffer_source) {
195 case Source::PicaTarget:
196 {
197 // TODO: Store a reference to the registers in the debug context instead of accessing them directly...
198
199 auto framebuffer = Pica::registers.framebuffer;
200 using Framebuffer = decltype(framebuffer);
201
202 framebuffer_address = framebuffer.GetColorBufferPhysicalAddress();
203 framebuffer_width = framebuffer.GetWidth();
204 framebuffer_height = framebuffer.GetHeight();
205 framebuffer_format = static_cast<Format>(framebuffer.color_format);
206
207 break;
208 }
209
210 case Source::Custom:
211 {
212 // Keep user-specified values
213 break;
214 }
215
216 default:
217 qDebug() << "Unknown framebuffer source " << static_cast<int>(framebuffer_source);
218 break;
219 }
220
221 // TODO: Implement a good way to visualize alpha components!
222 // TODO: Unify this decoding code with the texture decoder
223 switch (framebuffer_format) {
224 case Format::RGBA8:
225 {
226 QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32);
227 u32* color_buffer = (u32*)Memory::GetPointer(Pica::PAddrToVAddr(framebuffer_address));
228 for (unsigned y = 0; y < framebuffer_height; ++y) {
229 for (unsigned x = 0; x < framebuffer_width; ++x) {
230 u32 value = *(color_buffer + x + y * framebuffer_width);
231
232 decoded_image.setPixel(x, y, qRgba((value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF, 255/*value >> 24*/));
233 }
234 }
235 pixmap = QPixmap::fromImage(decoded_image);
236 break;
237 }
238
239 case Format::RGB8:
240 {
241 QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32);
242 u8* color_buffer = Memory::GetPointer(Pica::PAddrToVAddr(framebuffer_address));
243 for (unsigned y = 0; y < framebuffer_height; ++y) {
244 for (unsigned x = 0; x < framebuffer_width; ++x) {
245 u8* pixel_pointer = color_buffer + x * 3 + y * 3 * framebuffer_width;
246
247 decoded_image.setPixel(x, y, qRgba(pixel_pointer[0], pixel_pointer[1], pixel_pointer[2], 255/*value >> 24*/));
248 }
249 }
250 pixmap = QPixmap::fromImage(decoded_image);
251 break;
252 }
253
254 case Format::RGBA5551:
255 {
256 QImage decoded_image(framebuffer_width, framebuffer_height, QImage::Format_ARGB32);
257 u32* color_buffer = (u32*)Memory::GetPointer(Pica::PAddrToVAddr(framebuffer_address));
258 for (unsigned y = 0; y < framebuffer_height; ++y) {
259 for (unsigned x = 0; x < framebuffer_width; ++x) {
260 u16 value = *(u16*)(((u8*)color_buffer) + x * 2 + y * framebuffer_width * 2);
261 u8 r = (value >> 11) & 0x1F;
262 u8 g = (value >> 6) & 0x1F;
263 u8 b = (value >> 1) & 0x1F;
264 u8 a = value & 1;
265
266 decoded_image.setPixel(x, y, qRgba(r, g, b, 255/*a*/));
267 }
268 }
269 pixmap = QPixmap::fromImage(decoded_image);
270 break;
271 }
272
273 default:
274 qDebug() << "Unknown fb color format " << static_cast<int>(framebuffer_format);
275 break;
276 }
277
278 framebuffer_address_control->SetValue(framebuffer_address);
279 framebuffer_width_control->setValue(framebuffer_width);
280 framebuffer_height_control->setValue(framebuffer_height);
281 framebuffer_format_control->setCurrentIndex(static_cast<int>(framebuffer_format));
282 framebuffer_picture_label->setPixmap(pixmap);
283}
diff --git a/src/citra_qt/debugger/graphics_framebuffer.hxx b/src/citra_qt/debugger/graphics_framebuffer.hxx
new file mode 100644
index 000000000..56215761e
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_framebuffer.hxx
@@ -0,0 +1,92 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <QDockWidget>
8
9#include "video_core/debug_utils/debug_utils.h"
10
11class QComboBox;
12class QLabel;
13class QSpinBox;
14
15class CSpinBox;
16
17// Utility class which forwards calls to OnPicaBreakPointHit and OnPicaResume to public slots.
18// This is because the Pica breakpoint callbacks are called from a non-GUI thread, while
19// the widget usually wants to perform reactions in the GUI thread.
20class BreakPointObserverDock : public QDockWidget, Pica::DebugContext::BreakPointObserver {
21 Q_OBJECT
22
23public:
24 BreakPointObserverDock(std::shared_ptr<Pica::DebugContext> debug_context, const QString& title,
25 QWidget* parent = nullptr);
26
27 void OnPicaBreakPointHit(Pica::DebugContext::Event event, void* data) override;
28 void OnPicaResume() override;
29
30private slots:
31 virtual void OnBreakPointHit(Pica::DebugContext::Event event, void* data) = 0;
32 virtual void OnResumed() = 0;
33
34signals:
35 void Resumed();
36 void BreakPointHit(Pica::DebugContext::Event event, void* data);
37};
38
39class GraphicsFramebufferWidget : public BreakPointObserverDock {
40 Q_OBJECT
41
42 using Event = Pica::DebugContext::Event;
43
44 enum class Source {
45 PicaTarget = 0,
46 Custom = 1,
47
48 // TODO: Add GPU framebuffer sources!
49 };
50
51 enum class Format {
52 RGBA8 = 0,
53 RGB8 = 1,
54 RGBA5551 = 2,
55 RGB565 = 3,
56 RGBA4 = 4,
57 };
58
59public:
60 GraphicsFramebufferWidget(std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent = nullptr);
61
62public slots:
63 void OnFramebufferSourceChanged(int new_value);
64 void OnFramebufferAddressChanged(qint64 new_value);
65 void OnFramebufferWidthChanged(int new_value);
66 void OnFramebufferHeightChanged(int new_value);
67 void OnFramebufferFormatChanged(int new_value);
68 void OnUpdate();
69
70private slots:
71 void OnBreakPointHit(Pica::DebugContext::Event event, void* data) override;
72 void OnResumed() override;
73
74signals:
75 void Update();
76
77private:
78
79 QComboBox* framebuffer_source_list;
80 CSpinBox* framebuffer_address_control;
81 QSpinBox* framebuffer_width_control;
82 QSpinBox* framebuffer_height_control;
83 QComboBox* framebuffer_format_control;
84
85 QLabel* framebuffer_picture_label;
86
87 Source framebuffer_source;
88 unsigned framebuffer_address;
89 unsigned framebuffer_width;
90 unsigned framebuffer_height;
91 Format framebuffer_format;
92};
diff --git a/src/citra_qt/hotkeys.cpp b/src/citra_qt/hotkeys.cpp
index bbaa4a8dc..5d0b52e4f 100644
--- a/src/citra_qt/hotkeys.cpp
+++ b/src/citra_qt/hotkeys.cpp
@@ -5,7 +5,7 @@
5 5
6struct Hotkey 6struct Hotkey
7{ 7{
8 Hotkey() : shortcut(NULL), context(Qt::WindowShortcut) {} 8 Hotkey() : shortcut(nullptr), context(Qt::WindowShortcut) {}
9 9
10 QKeySequence keyseq; 10 QKeySequence keyseq;
11 QShortcut* shortcut; 11 QShortcut* shortcut;
@@ -81,7 +81,7 @@ QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widge
81 Hotkey& hk = hotkey_groups[group][action]; 81 Hotkey& hk = hotkey_groups[group][action];
82 82
83 if (!hk.shortcut) 83 if (!hk.shortcut)
84 hk.shortcut = new QShortcut(hk.keyseq, widget, NULL, NULL, hk.context); 84 hk.shortcut = new QShortcut(hk.keyseq, widget, nullptr, nullptr, hk.context);
85 85
86 return hk.shortcut; 86 return hk.shortcut;
87} 87}
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index d5554d917..b12e6a02b 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -1,3 +1,5 @@
1#include <thread>
2
1#include <QtGui> 3#include <QtGui>
2#include <QDesktopWidget> 4#include <QDesktopWidget>
3#include <QFileDialog> 5#include <QFileDialog>
@@ -5,8 +7,13 @@
5#include "main.hxx" 7#include "main.hxx"
6 8
7#include "common/common.h" 9#include "common/common.h"
10#include "common/logging/text_formatter.h"
11#include "common/logging/log.h"
12#include "common/logging/backend.h"
13#include "common/logging/filter.h"
8#include "common/platform.h" 14#include "common/platform.h"
9#include "common/log_manager.h" 15#include "common/scope_exit.h"
16
10#if EMU_PLATFORM == PLATFORM_LINUX 17#if EMU_PLATFORM == PLATFORM_LINUX
11#include <unistd.h> 18#include <unistd.h>
12#endif 19#endif
@@ -20,7 +27,9 @@
20#include "debugger/callstack.hxx" 27#include "debugger/callstack.hxx"
21#include "debugger/ramview.hxx" 28#include "debugger/ramview.hxx"
22#include "debugger/graphics.hxx" 29#include "debugger/graphics.hxx"
30#include "debugger/graphics_breakpoints.hxx"
23#include "debugger/graphics_cmdlists.hxx" 31#include "debugger/graphics_cmdlists.hxx"
32#include "debugger/graphics_framebuffer.hxx"
24 33
25#include "core/settings.h" 34#include "core/settings.h"
26#include "core/system.h" 35#include "core/system.h"
@@ -31,16 +40,12 @@
31 40
32#include "version.h" 41#include "version.h"
33 42
34
35GMainWindow::GMainWindow() 43GMainWindow::GMainWindow()
36{ 44{
37 LogManager::Init(); 45 Pica::g_debug_context = Pica::DebugContext::Construct();
38 46
39 Config config; 47 Config config;
40 48
41 if (!Settings::values.enable_log)
42 LogManager::Shutdown();
43
44 ui.setupUi(this); 49 ui.setupUi(this);
45 statusBar()->hide(); 50 statusBar()->hide();
46 51
@@ -67,12 +72,22 @@ GMainWindow::GMainWindow()
67 addDockWidget(Qt::RightDockWidgetArea, graphicsCommandsWidget); 72 addDockWidget(Qt::RightDockWidgetArea, graphicsCommandsWidget);
68 graphicsCommandsWidget->hide(); 73 graphicsCommandsWidget->hide();
69 74
75 auto graphicsBreakpointsWidget = new GraphicsBreakPointsWidget(Pica::g_debug_context, this);
76 addDockWidget(Qt::RightDockWidgetArea, graphicsBreakpointsWidget);
77 graphicsBreakpointsWidget->hide();
78
79 auto graphicsFramebufferWidget = new GraphicsFramebufferWidget(Pica::g_debug_context, this);
80 addDockWidget(Qt::RightDockWidgetArea, graphicsFramebufferWidget);
81 graphicsFramebufferWidget->hide();
82
70 QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); 83 QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging"));
71 debug_menu->addAction(disasmWidget->toggleViewAction()); 84 debug_menu->addAction(disasmWidget->toggleViewAction());
72 debug_menu->addAction(registersWidget->toggleViewAction()); 85 debug_menu->addAction(registersWidget->toggleViewAction());
73 debug_menu->addAction(callstackWidget->toggleViewAction()); 86 debug_menu->addAction(callstackWidget->toggleViewAction());
74 debug_menu->addAction(graphicsWidget->toggleViewAction()); 87 debug_menu->addAction(graphicsWidget->toggleViewAction());
75 debug_menu->addAction(graphicsCommandsWidget->toggleViewAction()); 88 debug_menu->addAction(graphicsCommandsWidget->toggleViewAction());
89 debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction());
90 debug_menu->addAction(graphicsFramebufferWidget->toggleViewAction());
76 91
77 // Set default UI state 92 // Set default UI state
78 // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half 93 // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half
@@ -131,24 +146,20 @@ GMainWindow::GMainWindow()
131GMainWindow::~GMainWindow() 146GMainWindow::~GMainWindow()
132{ 147{
133 // will get automatically deleted otherwise 148 // will get automatically deleted otherwise
134 if (render_window->parent() == NULL) 149 if (render_window->parent() == nullptr)
135 delete render_window; 150 delete render_window;
151
152 Pica::g_debug_context.reset();
136} 153}
137 154
138void GMainWindow::BootGame(std::string filename) 155void GMainWindow::BootGame(std::string filename)
139{ 156{
140 NOTICE_LOG(MASTER_LOG, "Citra starting...\n"); 157 LOG_INFO(Frontend, "Citra starting...\n");
141 System::Init(render_window); 158 System::Init(render_window);
142 159
143 if (Core::Init()) {
144 ERROR_LOG(MASTER_LOG, "Core initialization failed, exiting...");
145 Core::Stop();
146 exit(1);
147 }
148
149 // Load a game or die... 160 // Load a game or die...
150 if (Loader::ResultStatus::Success != Loader::LoadFile(filename)) { 161 if (Loader::ResultStatus::Success != Loader::LoadFile(filename)) {
151 ERROR_LOG(BOOT, "Failed to load ROM!"); 162 LOG_CRITICAL(Frontend, "Failed to load ROM!");
152 } 163 }
153 164
154 disasmWidget->Init(); 165 disasmWidget->Init();
@@ -164,7 +175,7 @@ void GMainWindow::BootGame(std::string filename)
164 175
165void GMainWindow::OnMenuLoadFile() 176void GMainWindow::OnMenuLoadFile()
166{ 177{
167 QString filename = QFileDialog::getOpenFileName(this, tr("Load file"), QString(), tr("3DS executable (*.elf *.axf *.bin *.cci *.cxi)")); 178 QString filename = QFileDialog::getOpenFileName(this, tr("Load file"), QString(), tr("3DS executable (*.3dsx *.elf *.axf *.bin *.cci *.cxi)"));
168 if (filename.size()) 179 if (filename.size())
169 BootGame(filename.toLatin1().data()); 180 BootGame(filename.toLatin1().data());
170} 181}
@@ -213,18 +224,21 @@ void GMainWindow::OnOpenHotkeysDialog()
213void GMainWindow::ToggleWindowMode() 224void GMainWindow::ToggleWindowMode()
214{ 225{
215 bool enable = ui.action_Popout_Window_Mode->isChecked(); 226 bool enable = ui.action_Popout_Window_Mode->isChecked();
216 if (enable && render_window->parent() != NULL) 227 if (enable && render_window->parent() != nullptr)
217 { 228 {
218 ui.horizontalLayout->removeWidget(render_window); 229 ui.horizontalLayout->removeWidget(render_window);
219 render_window->setParent(NULL); 230 render_window->setParent(nullptr);
220 render_window->setVisible(true); 231 render_window->setVisible(true);
221 render_window->RestoreGeometry(); 232 render_window->RestoreGeometry();
233 render_window->setFocusPolicy(Qt::NoFocus);
222 } 234 }
223 else if (!enable && render_window->parent() == NULL) 235 else if (!enable && render_window->parent() == nullptr)
224 { 236 {
225 render_window->BackupGeometry(); 237 render_window->BackupGeometry();
226 ui.horizontalLayout->addWidget(render_window); 238 ui.horizontalLayout->addWidget(render_window);
227 render_window->setVisible(true); 239 render_window->setVisible(true);
240 render_window->setFocusPolicy(Qt::ClickFocus);
241 render_window->setFocus();
228 } 242 }
229} 243}
230 244
@@ -255,9 +269,21 @@ void GMainWindow::closeEvent(QCloseEvent* event)
255 269
256int __cdecl main(int argc, char* argv[]) 270int __cdecl main(int argc, char* argv[])
257{ 271{
272 std::shared_ptr<Log::Logger> logger = Log::InitGlobalLogger();
273 Log::Filter log_filter(Log::Level::Info);
274 std::thread logging_thread(Log::TextLoggingLoop, logger, &log_filter);
275 SCOPE_EXIT({
276 logger->Close();
277 logging_thread.join();
278 });
279
258 QApplication::setAttribute(Qt::AA_X11InitThreads); 280 QApplication::setAttribute(Qt::AA_X11InitThreads);
259 QApplication app(argc, argv); 281 QApplication app(argc, argv);
282
260 GMainWindow main_window; 283 GMainWindow main_window;
284 // After settings have been loaded by GMainWindow, apply the filter
285 log_filter.ParseFilterString(Settings::values.log_filter);
286
261 main_window.show(); 287 main_window.show();
262 return app.exec(); 288 return app.exec();
263} 289}
diff --git a/src/citra_qt/util/spinbox.cpp b/src/citra_qt/util/spinbox.cpp
new file mode 100644
index 000000000..f9988409f
--- /dev/null
+++ b/src/citra_qt/util/spinbox.cpp
@@ -0,0 +1,303 @@
1// Licensed under GPLv2 or any later version
2// Refer to the license.txt file included.
3
4
5// Copyright 2014 Tony Wasserka
6// All rights reserved.
7//
8// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are met:
10//
11// * Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13// * Redistributions in binary form must reproduce the above copyright
14// notice, this list of conditions and the following disclaimer in the
15// documentation and/or other materials provided with the distribution.
16// * Neither the name of the owner nor the names of its contributors may
17// be used to endorse or promote products derived from this software
18// without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32#include <QLineEdit>
33#include <QRegExpValidator>
34
35#include "common/log.h"
36
37#include "spinbox.hxx"
38
39CSpinBox::CSpinBox(QWidget* parent) : QAbstractSpinBox(parent), base(10), min_value(-100), max_value(100), value(0), num_digits(0)
40{
41 // TODO: Might be nice to not immediately call the slot.
42 // Think of an address that is being replaced by a different one, in which case a lot
43 // invalid intermediate addresses would be read from during editing.
44 connect(lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(OnEditingFinished()));
45
46 UpdateText();
47}
48
49void CSpinBox::SetValue(qint64 val)
50{
51 auto old_value = value;
52 value = std::max(std::min(val, max_value), min_value);
53
54 if (old_value != value) {
55 UpdateText();
56 emit ValueChanged(value);
57 }
58}
59
60void CSpinBox::SetRange(qint64 min, qint64 max)
61{
62 min_value = min;
63 max_value = max;
64
65 SetValue(value);
66 UpdateText();
67}
68
69void CSpinBox::stepBy(int steps)
70{
71 auto new_value = value;
72 // Scale number of steps by the currently selected digit
73 // TODO: Move this code elsewhere and enable it.
74 // TODO: Support for num_digits==0, too
75 // TODO: Support base!=16, too
76 // TODO: Make the cursor not jump back to the end of the line...
77 /*if (base == 16 && num_digits > 0) {
78 int digit = num_digits - (lineEdit()->cursorPosition() - prefix.length()) - 1;
79 digit = std::max(0, std::min(digit, num_digits - 1));
80 steps <<= digit * 4;
81 }*/
82
83 // Increment "new_value" by "steps", and perform annoying overflow checks, too.
84 if (steps < 0 && new_value + steps > new_value) {
85 new_value = std::numeric_limits<qint64>::min();
86 } else if (steps > 0 && new_value + steps < new_value) {
87 new_value = std::numeric_limits<qint64>::max();
88 } else {
89 new_value += steps;
90 }
91
92 SetValue(new_value);
93 UpdateText();
94}
95
96QAbstractSpinBox::StepEnabled CSpinBox::stepEnabled() const
97{
98 StepEnabled ret = StepNone;
99
100 if (value > min_value)
101 ret |= StepDownEnabled;
102
103 if (value < max_value)
104 ret |= StepUpEnabled;
105
106 return ret;
107}
108
109void CSpinBox::SetBase(int base)
110{
111 this->base = base;
112
113 UpdateText();
114}
115
116void CSpinBox::SetNumDigits(int num_digits)
117{
118 this->num_digits = num_digits;
119
120 UpdateText();
121}
122
123void CSpinBox::SetPrefix(const QString& prefix)
124{
125 this->prefix = prefix;
126
127 UpdateText();
128}
129
130void CSpinBox::SetSuffix(const QString& suffix)
131{
132 this->suffix = suffix;
133
134 UpdateText();
135}
136
137static QString StringToInputMask(const QString& input) {
138 QString mask = input;
139
140 // ... replace any special characters by their escaped counterparts ...
141 mask.replace("\\", "\\\\");
142 mask.replace("A", "\\A");
143 mask.replace("a", "\\a");
144 mask.replace("N", "\\N");
145 mask.replace("n", "\\n");
146 mask.replace("X", "\\X");
147 mask.replace("x", "\\x");
148 mask.replace("9", "\\9");
149 mask.replace("0", "\\0");
150 mask.replace("D", "\\D");
151 mask.replace("d", "\\d");
152 mask.replace("#", "\\#");
153 mask.replace("H", "\\H");
154 mask.replace("h", "\\h");
155 mask.replace("B", "\\B");
156 mask.replace("b", "\\b");
157 mask.replace(">", "\\>");
158 mask.replace("<", "\\<");
159 mask.replace("!", "\\!");
160
161 return mask;
162}
163
164void CSpinBox::UpdateText()
165{
166 // If a fixed number of digits is used, we put the line edit in insertion mode by setting an
167 // input mask.
168 QString mask;
169 if (num_digits != 0) {
170 mask += StringToInputMask(prefix);
171
172 // For base 10 and negative range, demand a single sign character
173 if (HasSign())
174 mask += "X"; // identified as "-" or "+" in the validator
175
176 // Uppercase digits greater than 9.
177 mask += ">";
178
179 // The greatest signed 64-bit number has 19 decimal digits.
180 // TODO: Could probably make this more generic with some logarithms.
181 // For reference, unsigned 64-bit can have up to 20 decimal digits.
182 int digits = (num_digits != 0) ? num_digits
183 : (base == 16) ? 16
184 : (base == 10) ? 19
185 : 0xFF; // fallback case...
186
187 // Match num_digits digits
188 // Digits irrelevant to the chosen number base are filtered in the validator
189 mask += QString("H").repeated(std::max(num_digits, 1));
190
191 // Switch off case conversion
192 mask += "!";
193
194 mask += StringToInputMask(suffix);
195 }
196 lineEdit()->setInputMask(mask);
197
198 // Set new text without changing the cursor position. This will cause the cursor to briefly
199 // appear at the end of the line and then to jump back to its original position. That's
200 // a bit ugly, but better than having setText() move the cursor permanently all the time.
201 int cursor_position = lineEdit()->cursorPosition();
202 lineEdit()->setText(TextFromValue());
203 lineEdit()->setCursorPosition(cursor_position);
204}
205
206QString CSpinBox::TextFromValue()
207{
208 return prefix
209 + QString(HasSign() ? ((value < 0) ? "-" : "+") : "")
210 + QString("%1").arg(abs(value), num_digits, base, QLatin1Char('0')).toUpper()
211 + suffix;
212}
213
214qint64 CSpinBox::ValueFromText()
215{
216 unsigned strpos = prefix.length();
217
218 QString num_string = text().mid(strpos, text().length() - strpos - suffix.length());
219 return num_string.toLongLong(nullptr, base);
220}
221
222bool CSpinBox::HasSign() const
223{
224 return base == 10 && min_value < 0;
225}
226
227void CSpinBox::OnEditingFinished()
228{
229 // Only update for valid input
230 QString input = lineEdit()->text();
231 int pos = 0;
232 if (QValidator::Acceptable == validate(input, pos))
233 SetValue(ValueFromText());
234}
235
236QValidator::State CSpinBox::validate(QString& input, int& pos) const
237{
238 if (!prefix.isEmpty() && input.left(prefix.length()) != prefix)
239 return QValidator::Invalid;
240
241 int strpos = prefix.length();
242
243 // Empty "numbers" allowed as intermediate values
244 if (strpos >= input.length() - HasSign() - suffix.length())
245 return QValidator::Intermediate;
246
247 _dbg_assert_(Frontend, base <= 10 || base == 16);
248 QString regexp;
249
250 // Demand sign character for negative ranges
251 if (HasSign())
252 regexp += "[+\\-]";
253
254 // Match digits corresponding to the chosen number base.
255 regexp += QString("[0-%1").arg(std::min(base, 9));
256 if (base == 16) {
257 regexp += "a-fA-F";
258 }
259 regexp += "]";
260
261 // Specify number of digits
262 if (num_digits > 0) {
263 regexp += QString("{%1}").arg(num_digits);
264 } else {
265 regexp += "+";
266 }
267
268 // Match string
269 QRegExp num_regexp(regexp);
270 int num_pos = strpos;
271 QString sub_input = input.mid(strpos, input.length() - strpos - suffix.length());
272
273 if (!num_regexp.exactMatch(sub_input) && num_regexp.matchedLength() == 0)
274 return QValidator::Invalid;
275
276 sub_input = sub_input.left(num_regexp.matchedLength());
277 bool ok;
278 qint64 val = sub_input.toLongLong(&ok, base);
279
280 if (!ok)
281 return QValidator::Invalid;
282
283 // Outside boundaries => don't accept
284 if (val < min_value || val > max_value)
285 return QValidator::Invalid;
286
287 // Make sure we are actually at the end of this string...
288 strpos += num_regexp.matchedLength();
289
290 if (!suffix.isEmpty() && input.mid(strpos) != suffix) {
291 return QValidator::Invalid;
292 } else {
293 strpos += suffix.length();
294 }
295
296 if (strpos != input.length())
297 return QValidator::Invalid;
298
299 // At this point we can say for sure that the input is fine. Let's fix it up a bit though
300 input.replace(num_pos, sub_input.length(), sub_input.toUpper());
301
302 return QValidator::Acceptable;
303}
diff --git a/src/citra_qt/util/spinbox.hxx b/src/citra_qt/util/spinbox.hxx
new file mode 100644
index 000000000..ee7f08ec2
--- /dev/null
+++ b/src/citra_qt/util/spinbox.hxx
@@ -0,0 +1,88 @@
1// Licensed under GPLv2 or any later version
2// Refer to the license.txt file included.
3
4
5// Copyright 2014 Tony Wasserka
6// All rights reserved.
7//
8// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions are met:
10//
11// * Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13// * Redistributions in binary form must reproduce the above copyright
14// notice, this list of conditions and the following disclaimer in the
15// documentation and/or other materials provided with the distribution.
16// * Neither the name of the owner nor the names of its contributors may
17// be used to endorse or promote products derived from this software
18// without specific prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
32
33#pragma once
34
35#include <QAbstractSpinBox>
36#include <QtGlobal>
37
38class QVariant;
39
40/**
41 * A custom spin box widget with enhanced functionality over Qt's QSpinBox
42 */
43class CSpinBox : public QAbstractSpinBox {
44 Q_OBJECT
45
46public:
47 CSpinBox(QWidget* parent = nullptr);
48
49 void stepBy(int steps) override;
50 StepEnabled stepEnabled() const override;
51
52 void SetValue(qint64 val);
53
54 void SetRange(qint64 min, qint64 max);
55
56 void SetBase(int base);
57
58 void SetPrefix(const QString& prefix);
59 void SetSuffix(const QString& suffix);
60
61 void SetNumDigits(int num_digits);
62
63 QValidator::State validate(QString& input, int& pos) const override;
64
65signals:
66 void ValueChanged(qint64 val);
67
68private slots:
69 void OnEditingFinished();
70
71private:
72 void UpdateText();
73
74 bool HasSign() const;
75
76 QString TextFromValue();
77 qint64 ValueFromText();
78
79 qint64 min_value, max_value;
80
81 qint64 value;
82
83 QString prefix, suffix;
84
85 int base;
86
87 int num_digits;
88};
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 9d5a90762..3c3419bbc 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -3,14 +3,15 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" "${CMAKE_CURRENT_SOU
3 3
4set(SRCS 4set(SRCS
5 break_points.cpp 5 break_points.cpp
6 console_listener.cpp
7 emu_window.cpp 6 emu_window.cpp
8 extended_trace.cpp 7 extended_trace.cpp
9 file_search.cpp 8 file_search.cpp
10 file_util.cpp 9 file_util.cpp
11 hash.cpp 10 hash.cpp
12 key_map.cpp 11 key_map.cpp
13 log_manager.cpp 12 logging/filter.cpp
13 logging/text_formatter.cpp
14 logging/backend.cpp
14 math_util.cpp 15 math_util.cpp
15 mem_arena.cpp 16 mem_arena.cpp
16 memory_util.cpp 17 memory_util.cpp
@@ -32,7 +33,7 @@ set(HEADERS
32 common_funcs.h 33 common_funcs.h
33 common_paths.h 34 common_paths.h
34 common_types.h 35 common_types.h
35 console_listener.h 36 concurrent_ring_buffer.h
36 cpu_detect.h 37 cpu_detect.h
37 debug_interface.h 38 debug_interface.h
38 emu_window.h 39 emu_window.h
@@ -44,13 +45,18 @@ set(HEADERS
44 key_map.h 45 key_map.h
45 linear_disk_cache.h 46 linear_disk_cache.h
46 log.h 47 log.h
47 log_manager.h 48 logging/text_formatter.h
49 logging/filter.h
50 logging/log.h
51 logging/backend.h
52 make_unique.h
48 math_util.h 53 math_util.h
49 mem_arena.h 54 mem_arena.h
50 memory_util.h 55 memory_util.h
51 msg_handler.h 56 msg_handler.h
52 platform.h 57 platform.h
53 scm_rev.h 58 scm_rev.h
59 scope_exit.h
54 string_util.h 60 string_util.h
55 swap.h 61 swap.h
56 symbols.h 62 symbols.h
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 9e02210f9..8eab054b8 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -1,4 +1,4 @@
1// Licensed under GPLv2 1// Licensed under GPLv2 or any later version
2// Refer to the license.txt file included. 2// Refer to the license.txt file included.
3 3
4 4
@@ -142,7 +142,7 @@ public:
142 142
143 __forceinline BitField& operator=(T val) 143 __forceinline BitField& operator=(T val)
144 { 144 {
145 storage = (storage & ~GetMask()) | (((StorageType)val << position) & GetMask()); 145 Assign(val);
146 return *this; 146 return *this;
147 } 147 }
148 148
@@ -151,6 +151,10 @@ public:
151 return Value(); 151 return Value();
152 } 152 }
153 153
154 __forceinline void Assign(const T& value) {
155 storage = (storage & ~GetMask()) | (((StorageType)value << position) & GetMask());
156 }
157
154 __forceinline T Value() const 158 __forceinline T Value() const
155 { 159 {
156 if (std::numeric_limits<T>::is_signed) 160 if (std::numeric_limits<T>::is_signed)
@@ -164,6 +168,12 @@ public:
164 } 168 }
165 } 169 }
166 170
171 // TODO: we may want to change this to explicit operator bool() if it's bug-free in VS2015
172 __forceinline bool ToBool() const
173 {
174 return Value() != 0;
175 }
176
167private: 177private:
168 // StorageType is T for non-enum types and the underlying type of T if 178 // StorageType is T for non-enum types and the underlying type of T if
169 // T is an enumeration. Note that T is wrapped within an enable_if in the 179 // T is an enumeration. Note that T is wrapped within an enable_if in the
diff --git a/src/common/break_points.cpp b/src/common/break_points.cpp
index 25528b864..6696935fa 100644
--- a/src/common/break_points.cpp
+++ b/src/common/break_points.cpp
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common.h" 5#include "common/common.h"
@@ -180,7 +180,7 @@ void TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr,
180 { 180 {
181 if (Log) 181 if (Log)
182 { 182 {
183 INFO_LOG(MEMMAP, "CHK %08x (%s) %s%i %0*x at %08x (%s)", 183 LOG_DEBUG(Debug_Breakpoint, "CHK %08x (%s) %s%i %0*x at %08x (%s)",
184 pc, debug_interface->getDescription(pc).c_str(), 184 pc, debug_interface->getDescription(pc).c_str(),
185 write ? "Write" : "Read", size*8, size*2, iValue, addr, 185 write ? "Write" : "Read", size*8, size*2, iValue, addr,
186 debug_interface->getDescription(addr).c_str() 186 debug_interface->getDescription(addr).c_str()
diff --git a/src/common/break_points.h b/src/common/break_points.h
index cf3884fbc..5557cd50e 100644
--- a/src/common/break_points.h
+++ b/src/common/break_points.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h
index 609784076..39a14dc81 100644
--- a/src/common/chunk_file.h
+++ b/src/common/chunk_file.h
@@ -154,7 +154,7 @@ public:
154 Do(foundVersion); 154 Do(foundVersion);
155 155
156 if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) { 156 if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) {
157 WARN_LOG(COMMON, "Savestate failure: wrong version %d found for %s", foundVersion, title); 157 LOG_ERROR(Common, "Savestate failure: wrong version %d found for %s", foundVersion, title);
158 SetError(ERROR_FAILURE); 158 SetError(ERROR_FAILURE);
159 return PointerWrapSection(*this, -1, title); 159 return PointerWrapSection(*this, -1, title);
160 } 160 }
@@ -178,7 +178,14 @@ public:
178 case MODE_READ: if (memcmp(data, *ptr, size) != 0) return false; break; 178 case MODE_READ: if (memcmp(data, *ptr, size) != 0) return false; break;
179 case MODE_WRITE: memcpy(*ptr, data, size); break; 179 case MODE_WRITE: memcpy(*ptr, data, size); break;
180 case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything 180 case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything
181 case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break; 181 case MODE_VERIFY:
182 for (int i = 0; i < size; i++) {
183 _dbg_assert_msg_(Common, ((u8*)data)[i] == (*ptr)[i],
184 "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n",
185 ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i],
186 (*ptr)[i], (*ptr)[i], &(*ptr)[i]);
187 }
188 break;
182 default: break; // throw an error? 189 default: break; // throw an error?
183 } 190 }
184 (*ptr) += size; 191 (*ptr) += size;
@@ -191,7 +198,14 @@ public:
191 case MODE_READ: memcpy(data, *ptr, size); break; 198 case MODE_READ: memcpy(data, *ptr, size); break;
192 case MODE_WRITE: memcpy(*ptr, data, size); break; 199 case MODE_WRITE: memcpy(*ptr, data, size); break;
193 case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything 200 case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything
194 case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break; 201 case MODE_VERIFY:
202 for (int i = 0; i < size; i++) {
203 _dbg_assert_msg_(Common, ((u8*)data)[i] == (*ptr)[i],
204 "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n",
205 ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i],
206 (*ptr)[i], (*ptr)[i], &(*ptr)[i]);
207 }
208 break;
195 default: break; // throw an error? 209 default: break; // throw an error?
196 } 210 }
197 (*ptr) += size; 211 (*ptr) += size;
@@ -204,11 +218,11 @@ public:
204 { 218 {
205 for (auto it = x.begin(), end = x.end(); it != end; ++it) 219 for (auto it = x.begin(), end = x.end(); it != end; ++it)
206 { 220 {
207 if (it->second != NULL) 221 if (it->second != nullptr)
208 delete it->second; 222 delete it->second;
209 } 223 }
210 } 224 }
211 T *dv = NULL; 225 T *dv = nullptr;
212 DoMap(x, dv); 226 DoMap(x, dv);
213 } 227 }
214 228
@@ -264,11 +278,11 @@ public:
264 { 278 {
265 for (auto it = x.begin(), end = x.end(); it != end; ++it) 279 for (auto it = x.begin(), end = x.end(); it != end; ++it)
266 { 280 {
267 if (it->second != NULL) 281 if (it->second != nullptr)
268 delete it->second; 282 delete it->second;
269 } 283 }
270 } 284 }
271 T *dv = NULL; 285 T *dv = nullptr;
272 DoMultimap(x, dv); 286 DoMultimap(x, dv);
273 } 287 }
274 288
@@ -320,7 +334,7 @@ public:
320 template<class T> 334 template<class T>
321 void Do(std::vector<T *> &x) 335 void Do(std::vector<T *> &x)
322 { 336 {
323 T *dv = NULL; 337 T *dv = nullptr;
324 DoVector(x, dv); 338 DoVector(x, dv);
325 } 339 }
326 340
@@ -369,7 +383,7 @@ public:
369 template<class T> 383 template<class T>
370 void Do(std::deque<T *> &x) 384 void Do(std::deque<T *> &x)
371 { 385 {
372 T *dv = NULL; 386 T *dv = nullptr;
373 DoDeque(x, dv); 387 DoDeque(x, dv);
374 } 388 }
375 389
@@ -395,7 +409,7 @@ public:
395 template<class T> 409 template<class T>
396 void Do(std::list<T *> &x) 410 void Do(std::list<T *> &x)
397 { 411 {
398 T *dv = NULL; 412 T *dv = nullptr;
399 Do(x, dv); 413 Do(x, dv);
400 } 414 }
401 415
@@ -433,7 +447,7 @@ public:
433 { 447 {
434 for (auto it = x.begin(), end = x.end(); it != end; ++it) 448 for (auto it = x.begin(), end = x.end(); it != end; ++it)
435 { 449 {
436 if (*it != NULL) 450 if (*it != nullptr)
437 delete *it; 451 delete *it;
438 } 452 }
439 } 453 }
@@ -476,7 +490,7 @@ public:
476 break; 490 break;
477 491
478 default: 492 default:
479 ERROR_LOG(COMMON, "Savestate error: invalid mode %d.", mode); 493 LOG_ERROR(Common, "Savestate error: invalid mode %d.", mode);
480 } 494 }
481 } 495 }
482 496
@@ -490,7 +504,12 @@ public:
490 case MODE_READ: x = (char*)*ptr; break; 504 case MODE_READ: x = (char*)*ptr; break;
491 case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; 505 case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
492 case MODE_MEASURE: break; 506 case MODE_MEASURE: break;
493 case MODE_VERIFY: _dbg_assert_msg_(COMMON, !strcmp(x.c_str(), (char*)*ptr), "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (char*)*ptr, ptr); break; 507 case MODE_VERIFY:
508 _dbg_assert_msg_(Common,
509 !strcmp(x.c_str(), (char*)*ptr),
510 "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n",
511 x.c_str(), (char*)*ptr, ptr);
512 break;
494 } 513 }
495 (*ptr) += stringLen; 514 (*ptr) += stringLen;
496 } 515 }
@@ -504,7 +523,11 @@ public:
504 case MODE_READ: x = (wchar_t*)*ptr; break; 523 case MODE_READ: x = (wchar_t*)*ptr; break;
505 case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break; 524 case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
506 case MODE_MEASURE: break; 525 case MODE_MEASURE: break;
507 case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break; 526 case MODE_VERIFY:
527 _dbg_assert_msg_(Common, x == (wchar_t*)*ptr,
528 "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n",
529 x.c_str(), (wchar_t*)*ptr, ptr);
530 break;
508 } 531 }
509 (*ptr) += stringLen; 532 (*ptr) += stringLen;
510 } 533 }
@@ -518,7 +541,7 @@ public:
518 void DoClass(T *&x) { 541 void DoClass(T *&x) {
519 if (mode == MODE_READ) 542 if (mode == MODE_READ)
520 { 543 {
521 if (x != NULL) 544 if (x != nullptr)
522 delete x; 545 delete x;
523 x = new T(); 546 x = new T();
524 } 547 }
@@ -567,7 +590,7 @@ public:
567 { 590 {
568 if (mode == MODE_READ) 591 if (mode == MODE_READ)
569 { 592 {
570 cur->next = 0; 593 cur->next = nullptr;
571 list_cur = cur; 594 list_cur = cur;
572 if (prev) 595 if (prev)
573 prev->next = cur; 596 prev->next = cur;
@@ -586,13 +609,13 @@ public:
586 if (mode == MODE_READ) 609 if (mode == MODE_READ)
587 { 610 {
588 if (prev) 611 if (prev)
589 prev->next = 0; 612 prev->next = nullptr;
590 if (list_end) 613 if (list_end)
591 *list_end = prev; 614 *list_end = prev;
592 if (list_cur) 615 if (list_cur)
593 { 616 {
594 if (list_start == list_cur) 617 if (list_start == list_cur)
595 list_start = 0; 618 list_start = nullptr;
596 do 619 do
597 { 620 {
598 LinkedListItem<T>* next = list_cur->next; 621 LinkedListItem<T>* next = list_cur->next;
diff --git a/src/common/common.h b/src/common/common.h
index 0d7934622..ba33373ae 100644
--- a/src/common/common.h
+++ b/src/common/common.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index ddf3958cc..c2750a63c 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -1,9 +1,12 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
7#include "common_types.h"
8#include <cstdlib>
9
7#ifdef _WIN32 10#ifdef _WIN32
8#define SLEEP(x) Sleep(x) 11#define SLEEP(x) Sleep(x)
9#else 12#else
@@ -73,6 +76,8 @@ inline u64 _rotr64(u64 x, unsigned int shift){
73} 76}
74 77
75#else // _MSC_VER 78#else // _MSC_VER
79#include <locale.h>
80
76// Function Cross-Compatibility 81// Function Cross-Compatibility
77 #define strcasecmp _stricmp 82 #define strcasecmp _stricmp
78 #define strncasecmp _strnicmp 83 #define strncasecmp _strnicmp
@@ -106,7 +111,7 @@ inline u64 _rotr64(u64 x, unsigned int shift){
106 // Restore the global locale 111 // Restore the global locale
107 _configthreadlocale(_DISABLE_PER_THREAD_LOCALE); 112 _configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
108 } 113 }
109 else if(new_locale != NULL) 114 else if(new_locale != nullptr)
110 { 115 {
111 // Configure the thread to set the locale only for this thread 116 // Configure the thread to set the locale only for this thread
112 _configthreadlocale(_ENABLE_PER_THREAD_LOCALE); 117 _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
diff --git a/src/common/common_paths.h b/src/common/common_paths.h
index ae08d082a..9d62a8368 100644
--- a/src/common/common_paths.h
+++ b/src/common/common_paths.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -29,19 +29,6 @@
29 #endif 29 #endif
30#endif 30#endif
31 31
32// Shared data dirs (Sys and shared User for linux)
33#ifdef _WIN32
34 #define SYSDATA_DIR "sys"
35#else
36 #ifdef DATA_DIR
37 #define SYSDATA_DIR DATA_DIR "sys"
38 #define SHARED_USER_DIR DATA_DIR USERDATA_DIR DIR_SEP
39 #else
40 #define SYSDATA_DIR "sys"
41 #define SHARED_USER_DIR ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP
42 #endif
43#endif
44
45// Dirs in both User and Sys 32// Dirs in both User and Sys
46#define EUR_DIR "EUR" 33#define EUR_DIR "EUR"
47#define USA_DIR "USA" 34#define USA_DIR "USA"
@@ -53,6 +40,9 @@
53#define MAPS_DIR "maps" 40#define MAPS_DIR "maps"
54#define CACHE_DIR "cache" 41#define CACHE_DIR "cache"
55#define SDMC_DIR "sdmc" 42#define SDMC_DIR "sdmc"
43#define SAVEDATA_DIR "savedata"
44#define SYSDATA_DIR "sysdata"
45#define SYSSAVEDATA_DIR "syssavedata"
56#define SHADERCACHE_DIR "shader_cache" 46#define SHADERCACHE_DIR "shader_cache"
57#define STATESAVES_DIR "state_saves" 47#define STATESAVES_DIR "state_saves"
58#define SCREENSHOTS_DIR "screenShots" 48#define SCREENSHOTS_DIR "screenShots"
@@ -70,6 +60,9 @@
70#define DEBUGGER_CONFIG "debugger.ini" 60#define DEBUGGER_CONFIG "debugger.ini"
71#define LOGGER_CONFIG "logger.ini" 61#define LOGGER_CONFIG "logger.ini"
72 62
63// Sys files
64#define SHARED_FONT "shared_font.bin"
65
73// Files in the directory returned by GetUserPath(D_LOGS_IDX) 66// Files in the directory returned by GetUserPath(D_LOGS_IDX)
74#define MAIN_LOG "emu.log" 67#define MAIN_LOG "emu.log"
75 68
diff --git a/src/common/common_types.h b/src/common/common_types.h
index fcc8b9a4e..c74c74f0f 100644
--- a/src/common/common_types.h
+++ b/src/common/common_types.h
@@ -41,8 +41,6 @@ typedef std::int64_t s64; ///< 64-bit signed int
41typedef float f32; ///< 32-bit floating point 41typedef float f32; ///< 32-bit floating point
42typedef double f64; ///< 64-bit floating point 42typedef double f64; ///< 64-bit floating point
43 43
44#include "common/common.h"
45
46/// Union for fast 16-bit type casting 44/// Union for fast 16-bit type casting
47union t16 { 45union t16 {
48 u8 _u8[2]; ///< 8-bit unsigned char(s) 46 u8 _u8[2]; ///< 8-bit unsigned char(s)
diff --git a/src/common/concurrent_ring_buffer.h b/src/common/concurrent_ring_buffer.h
new file mode 100644
index 000000000..311bb01f4
--- /dev/null
+++ b/src/common/concurrent_ring_buffer.h
@@ -0,0 +1,164 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include <condition_variable>
9#include <cstdint>
10#include <mutex>
11#include <thread>
12
13#include "common/common.h" // for NonCopyable
14#include "common/log.h" // for _dbg_assert_
15
16namespace Common {
17
18/**
19 * A MPMC (Multiple-Producer Multiple-Consumer) concurrent ring buffer. This data structure permits
20 * multiple threads to push and pop from a queue of bounded size.
21 */
22template <typename T, size_t ArraySize>
23class ConcurrentRingBuffer : private NonCopyable {
24public:
25 /// Value returned by the popping functions when the queue has been closed.
26 static const size_t QUEUE_CLOSED = -1;
27
28 ConcurrentRingBuffer() {}
29
30 ~ConcurrentRingBuffer() {
31 // If for whatever reason the queue wasn't completely drained, destroy the left over items.
32 for (size_t i = reader_index, end = writer_index; i != end; i = (i + 1) % ArraySize) {
33 Data()[i].~T();
34 }
35 }
36
37 /**
38 * Pushes a value to the queue. If the queue is full, this method will block. Does nothing if
39 * the queue is closed.
40 */
41 void Push(T val) {
42 std::unique_lock<std::mutex> lock(mutex);
43 if (closed) {
44 return;
45 }
46
47 // If the buffer is full, wait
48 writer.wait(lock, [&]{
49 return (writer_index + 1) % ArraySize != reader_index;
50 });
51
52 T* item = &Data()[writer_index];
53 new (item) T(std::move(val));
54
55 writer_index = (writer_index + 1) % ArraySize;
56
57 // Wake up waiting readers
58 lock.unlock();
59 reader.notify_one();
60 }
61
62 /**
63 * Pops up to `dest_len` items from the queue, storing them in `dest`. This function will not
64 * block, and might return 0 values if there are no elements in the queue when it is called.
65 *
66 * @return The number of elements stored in `dest`. If the queue has been closed, returns
67 * `QUEUE_CLOSED`.
68 */
69 size_t Pop(T* dest, size_t dest_len) {
70 std::unique_lock<std::mutex> lock(mutex);
71 if (closed && !CanRead()) {
72 return QUEUE_CLOSED;
73 }
74 return PopInternal(dest, dest_len);
75 }
76
77 /**
78 * Pops up to `dest_len` items from the queue, storing them in `dest`. This function will block
79 * if there are no elements in the queue when it is called.
80 *
81 * @return The number of elements stored in `dest`. If the queue has been closed, returns
82 * `QUEUE_CLOSED`.
83 */
84 size_t BlockingPop(T* dest, size_t dest_len) {
85 std::unique_lock<std::mutex> lock(mutex);
86 if (closed && !CanRead()) {
87 return QUEUE_CLOSED;
88 }
89
90 while (!CanRead()) {
91 reader.wait(lock);
92 if (closed && !CanRead()) {
93 return QUEUE_CLOSED;
94 }
95 }
96 _dbg_assert_(Common, CanRead());
97 return PopInternal(dest, dest_len);
98 }
99
100 /**
101 * Closes the queue. After calling this method, `Push` operations won't have any effect, and
102 * `PopMany` and `PopManyBlock` will start returning `QUEUE_CLOSED`. This is intended to allow
103 * a graceful shutdown of all consumers.
104 */
105 void Close() {
106 std::unique_lock<std::mutex> lock(mutex);
107 closed = true;
108 // We need to wake up any reader that are waiting for an item that will never come.
109 lock.unlock();
110 reader.notify_all();
111 }
112
113 /// Returns true if `Close()` has been called.
114 bool IsClosed() const {
115 return closed;
116 }
117
118private:
119 size_t PopInternal(T* dest, size_t dest_len) {
120 size_t output_count = 0;
121 while (output_count < dest_len && CanRead()) {
122 _dbg_assert_(Common, CanRead());
123
124 T* item = &Data()[reader_index];
125 T out_val = std::move(*item);
126 item->~T();
127
128 size_t prev_index = (reader_index + ArraySize - 1) % ArraySize;
129 reader_index = (reader_index + 1) % ArraySize;
130 if (writer_index == prev_index) {
131 writer.notify_one();
132 }
133 dest[output_count++] = std::move(out_val);
134 }
135 return output_count;
136 }
137
138 bool CanRead() const {
139 return reader_index != writer_index;
140 }
141
142 T* Data() {
143 return static_cast<T*>(static_cast<void*>(&storage));
144 }
145
146 /// Storage for entries
147 typename std::aligned_storage<ArraySize * sizeof(T),
148 std::alignment_of<T>::value>::type storage;
149
150 /// Data is valid in the half-open interval [reader, writer). If they are `QUEUE_CLOSED` then the
151 /// queue has been closed.
152 size_t writer_index = 0, reader_index = 0;
153 // True if the queue has been closed.
154 bool closed = false;
155
156 /// Mutex that protects the entire data structure.
157 std::mutex mutex;
158 /// Signaling wakes up reader which is waiting for storage to be non-empty.
159 std::condition_variable reader;
160 /// Signaling wakes up writer which is waiting for storage to be non-full.
161 std::condition_variable writer;
162};
163
164} // namespace
diff --git a/src/common/console_listener.cpp b/src/common/console_listener.cpp
deleted file mode 100644
index d7f27c358..000000000
--- a/src/common/console_listener.cpp
+++ /dev/null
@@ -1,319 +0,0 @@
1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <algorithm>
6
7#ifdef _WIN32
8#include <windows.h>
9#include <array>
10#endif
11
12#include "common/common.h"
13#include "common/log_manager.h" // Common
14#include "common/console_listener.h" // Common
15
16ConsoleListener::ConsoleListener()
17{
18#ifdef _WIN32
19 hConsole = NULL;
20 bUseColor = true;
21#else
22 bUseColor = isatty(fileno(stdout));
23#endif
24}
25
26ConsoleListener::~ConsoleListener()
27{
28 Close();
29}
30
31// 100, 100, "Dolphin Log Console"
32// Open console window - width and height is the size of console window
33// Name is the window title
34void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title)
35{
36#ifdef _WIN32
37 if (!GetConsoleWindow())
38 {
39 // Open the console window and create the window handle for GetStdHandle()
40 AllocConsole();
41 // Hide
42 if (Hidden) ShowWindow(GetConsoleWindow(), SW_HIDE);
43 // Save the window handle that AllocConsole() created
44 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
45 // Set the console window title
46 SetConsoleTitle(Common::UTF8ToTStr(Title).c_str());
47 // Set letter space
48 LetterSpace(80, 4000);
49 //MoveWindow(GetConsoleWindow(), 200,200, 800,800, true);
50 }
51 else
52 {
53 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
54 }
55#endif
56}
57
58void ConsoleListener::UpdateHandle()
59{
60#ifdef _WIN32
61 hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
62#endif
63}
64
65// Close the console window and close the eventual file handle
66void ConsoleListener::Close()
67{
68#ifdef _WIN32
69 if (hConsole == NULL)
70 return;
71 FreeConsole();
72 hConsole = NULL;
73#else
74 fflush(NULL);
75#endif
76}
77
78bool ConsoleListener::IsOpen()
79{
80#ifdef _WIN32
81 return (hConsole != NULL);
82#else
83 return true;
84#endif
85}
86
87/*
88 LetterSpace: SetConsoleScreenBufferSize and SetConsoleWindowInfo are
89 dependent on each other, that's the reason for the additional checks.
90*/
91void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst)
92{
93#ifdef _WIN32
94 BOOL SB, SW;
95 if (BufferFirst)
96 {
97 // Change screen buffer size
98 COORD Co = {BufferWidth, BufferHeight};
99 SB = SetConsoleScreenBufferSize(hConsole, Co);
100 // Change the screen buffer window size
101 SMALL_RECT coo = {0,0,ScreenWidth, ScreenHeight}; // top, left, right, bottom
102 SW = SetConsoleWindowInfo(hConsole, TRUE, &coo);
103 }
104 else
105 {
106 // Change the screen buffer window size
107 SMALL_RECT coo = {0,0, ScreenWidth, ScreenHeight}; // top, left, right, bottom
108 SW = SetConsoleWindowInfo(hConsole, TRUE, &coo);
109 // Change screen buffer size
110 COORD Co = {BufferWidth, BufferHeight};
111 SB = SetConsoleScreenBufferSize(hConsole, Co);
112 }
113#endif
114}
115void ConsoleListener::LetterSpace(int Width, int Height)
116{
117#ifdef _WIN32
118 // Get console info
119 CONSOLE_SCREEN_BUFFER_INFO ConInfo;
120 GetConsoleScreenBufferInfo(hConsole, &ConInfo);
121
122 //
123 int OldBufferWidth = ConInfo.dwSize.X;
124 int OldBufferHeight = ConInfo.dwSize.Y;
125 int OldScreenWidth = (ConInfo.srWindow.Right - ConInfo.srWindow.Left);
126 int OldScreenHeight = (ConInfo.srWindow.Bottom - ConInfo.srWindow.Top);
127 //
128 int NewBufferWidth = Width;
129 int NewBufferHeight = Height;
130 int NewScreenWidth = NewBufferWidth - 1;
131 int NewScreenHeight = OldScreenHeight;
132
133 // Width
134 BufferWidthHeight(NewBufferWidth, OldBufferHeight, NewScreenWidth, OldScreenHeight, (NewBufferWidth > OldScreenWidth-1));
135 // Height
136 BufferWidthHeight(NewBufferWidth, NewBufferHeight, NewScreenWidth, NewScreenHeight, (NewBufferHeight > OldScreenHeight-1));
137
138 // Resize the window too
139 //MoveWindow(GetConsoleWindow(), 200,200, (Width*8 + 50),(NewScreenHeight*12 + 200), true);
140#endif
141}
142#ifdef _WIN32
143COORD ConsoleListener::GetCoordinates(int BytesRead, int BufferWidth)
144{
145 COORD Ret = {0, 0};
146 // Full rows
147 int Step = (int)floor((float)BytesRead / (float)BufferWidth);
148 Ret.Y += Step;
149 // Partial row
150 Ret.X = BytesRead - (BufferWidth * Step);
151 return Ret;
152}
153#endif
154void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool Resize)
155{
156#ifdef _WIN32
157 // Check size
158 if (Width < 8 || Height < 12) return;
159
160 bool DBef = true;
161 bool DAft = true;
162 std::string SLog = "";
163
164 const HWND hWnd = GetConsoleWindow();
165 const HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
166
167 // Get console info
168 CONSOLE_SCREEN_BUFFER_INFO ConInfo;
169 GetConsoleScreenBufferInfo(hConsole, &ConInfo);
170 DWORD BufferSize = ConInfo.dwSize.X * ConInfo.dwSize.Y;
171
172 // ---------------------------------------------------------------------
173 // Save the current text
174 // ------------------------
175 DWORD cCharsRead = 0;
176 COORD coordScreen = { 0, 0 };
177
178 static const int MAX_BYTES = 1024 * 16;
179
180 std::vector<std::array<TCHAR, MAX_BYTES>> Str;
181 std::vector<std::array<WORD, MAX_BYTES>> Attr;
182
183 // ReadConsoleOutputAttribute seems to have a limit at this level
184 static const int ReadBufferSize = MAX_BYTES - 32;
185
186 DWORD cAttrRead = ReadBufferSize;
187 DWORD BytesRead = 0;
188 while (BytesRead < BufferSize)
189 {
190 Str.resize(Str.size() + 1);
191 if (!ReadConsoleOutputCharacter(hConsole, Str.back().data(), ReadBufferSize, coordScreen, &cCharsRead))
192 SLog += Common::StringFromFormat("WriteConsoleOutputCharacter error");
193
194 Attr.resize(Attr.size() + 1);
195 if (!ReadConsoleOutputAttribute(hConsole, Attr.back().data(), ReadBufferSize, coordScreen, &cAttrRead))
196 SLog += Common::StringFromFormat("WriteConsoleOutputAttribute error");
197
198 // Break on error
199 if (cAttrRead == 0) break;
200 BytesRead += cAttrRead;
201 coordScreen = GetCoordinates(BytesRead, ConInfo.dwSize.X);
202 }
203 // Letter space
204 int LWidth = (int)(floor((float)Width / 8.0f) - 1.0f);
205 int LHeight = (int)(floor((float)Height / 12.0f) - 1.0f);
206 int LBufWidth = LWidth + 1;
207 int LBufHeight = (int)floor((float)BufferSize / (float)LBufWidth);
208 // Change screen buffer size
209 LetterSpace(LBufWidth, LBufHeight);
210
211
212 ClearScreen(true);
213 coordScreen.Y = 0;
214 coordScreen.X = 0;
215 DWORD cCharsWritten = 0;
216
217 int BytesWritten = 0;
218 DWORD cAttrWritten = 0;
219 for (size_t i = 0; i < Attr.size(); i++)
220 {
221 if (!WriteConsoleOutputCharacter(hConsole, Str[i].data(), ReadBufferSize, coordScreen, &cCharsWritten))
222 SLog += Common::StringFromFormat("WriteConsoleOutputCharacter error");
223 if (!WriteConsoleOutputAttribute(hConsole, Attr[i].data(), ReadBufferSize, coordScreen, &cAttrWritten))
224 SLog += Common::StringFromFormat("WriteConsoleOutputAttribute error");
225
226 BytesWritten += cAttrWritten;
227 coordScreen = GetCoordinates(BytesWritten, LBufWidth);
228 }
229
230 const int OldCursor = ConInfo.dwCursorPosition.Y * ConInfo.dwSize.X + ConInfo.dwCursorPosition.X;
231 COORD Coo = GetCoordinates(OldCursor, LBufWidth);
232 SetConsoleCursorPosition(hConsole, Coo);
233
234 if (SLog.length() > 0) Log(LogTypes::LNOTICE, SLog.c_str());
235
236 // Resize the window too
237 if (Resize) MoveWindow(GetConsoleWindow(), Left,Top, (Width + 100),Height, true);
238#endif
239}
240
241void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text)
242{
243#if defined(_WIN32)
244 WORD Color;
245
246 switch (Level)
247 {
248 case OS_LEVEL: // light yellow
249 Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
250 break;
251 case NOTICE_LEVEL: // light green
252 Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
253 break;
254 case ERROR_LEVEL: // light red
255 Color = FOREGROUND_RED | FOREGROUND_INTENSITY;
256 break;
257 case WARNING_LEVEL: // light purple
258 Color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
259 break;
260 case INFO_LEVEL: // cyan
261 Color = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
262 break;
263 case DEBUG_LEVEL: // gray
264 Color = FOREGROUND_INTENSITY;
265 break;
266 default: // off-white
267 Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
268 break;
269 }
270 SetConsoleTextAttribute(hConsole, Color);
271 printf(Text);
272#else
273 char ColorAttr[16] = "";
274 char ResetAttr[16] = "";
275
276 if (bUseColor)
277 {
278 strcpy(ResetAttr, "\033[0m");
279 switch (Level)
280 {
281 case NOTICE_LEVEL: // light green
282 strcpy(ColorAttr, "\033[92m");
283 break;
284 case ERROR_LEVEL: // light red
285 strcpy(ColorAttr, "\033[91m");
286 break;
287 case WARNING_LEVEL: // light yellow
288 strcpy(ColorAttr, "\033[93m");
289 break;
290 default:
291 break;
292 }
293 }
294 fprintf(stderr, "%s%s%s", ColorAttr, Text, ResetAttr);
295#endif
296}
297// Clear console screen
298void ConsoleListener::ClearScreen(bool Cursor)
299{
300#if defined(_WIN32)
301 COORD coordScreen = { 0, 0 };
302 DWORD cCharsWritten;
303 CONSOLE_SCREEN_BUFFER_INFO csbi;
304 DWORD dwConSize;
305
306 HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
307
308 GetConsoleScreenBufferInfo(hConsole, &csbi);
309 dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
310 // Write space to the entire console
311 FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten);
312 GetConsoleScreenBufferInfo(hConsole, &csbi);
313 FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten);
314 // Reset cursor
315 if (Cursor) SetConsoleCursorPosition(hConsole, coordScreen);
316#endif
317}
318
319
diff --git a/src/common/console_listener.h b/src/common/console_listener.h
deleted file mode 100644
index ebd90a105..000000000
--- a/src/common/console_listener.h
+++ /dev/null
@@ -1,38 +0,0 @@
1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/log_manager.h"
8
9#ifdef _WIN32
10#include <windows.h>
11#endif
12
13class ConsoleListener : public LogListener
14{
15public:
16 ConsoleListener();
17 ~ConsoleListener();
18
19 void Open(bool Hidden = false, int Width = 100, int Height = 100, const char * Name = "Console");
20 void UpdateHandle();
21 void Close();
22 bool IsOpen();
23 void LetterSpace(int Width, int Height);
24 void BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst);
25 void PixelSpace(int Left, int Top, int Width, int Height, bool);
26#ifdef _WIN32
27 COORD GetCoordinates(int BytesRead, int BufferWidth);
28#endif
29 void Log(LogTypes::LOG_LEVELS, const char *Text) override;
30 void ClearScreen(bool Cursor = true);
31
32private:
33#ifdef _WIN32
34 HWND GetHwnd(void);
35 HANDLE hConsole;
36#endif
37 bool bUseColor;
38};
diff --git a/src/common/cpu_detect.h b/src/common/cpu_detect.h
index def6afdee..b585f9608 100644
--- a/src/common/cpu_detect.h
+++ b/src/common/cpu_detect.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5 5
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index 7a2c50ac8..4ec7b263a 100644
--- a/src/common/emu_window.cpp
+++ b/src/common/emu_window.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "emu_window.h" 5#include "emu_window.h"
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index 4cb94fed1..1ad4b82a3 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/common/extended_trace.cpp b/src/common/extended_trace.cpp
index bf61ac1d1..cf7c346d4 100644
--- a/src/common/extended_trace.cpp
+++ b/src/common/extended_trace.cpp
@@ -82,7 +82,7 @@ static void InitSymbolPath( PSTR lpszSymbolPath, PCSTR lpszIniPath )
82 } 82 }
83 83
84 // Add user defined path 84 // Add user defined path
85 if ( lpszIniPath != NULL ) 85 if ( lpszIniPath != nullptr )
86 if ( lpszIniPath[0] != '\0' ) 86 if ( lpszIniPath[0] != '\0' )
87 { 87 {
88 strcat( lpszSymbolPath, ";" ); 88 strcat( lpszSymbolPath, ";" );
@@ -138,7 +138,7 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L
138 DWORD dwSymSize = 10000; 138 DWORD dwSymSize = 10000;
139 TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?"); 139 TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?");
140 CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?"; 140 CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?";
141 LPTSTR lpszParamSep = NULL; 141 LPTSTR lpszParamSep = nullptr;
142 LPTSTR lpszParsed = lpszUnDSymbol; 142 LPTSTR lpszParsed = lpszUnDSymbol;
143 PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc( GMEM_FIXED, dwSymSize ); 143 PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc( GMEM_FIXED, dwSymSize );
144 144
@@ -187,13 +187,13 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L
187 187
188 // Let's go through the stack, and modify the function prototype, and insert the actual 188 // Let's go through the stack, and modify the function prototype, and insert the actual
189 // parameter values from the stack 189 // parameter values from the stack
190 if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == NULL && _tcsstr( lpszUnDSymbol, _T("()") ) == NULL) 190 if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == nullptr && _tcsstr( lpszUnDSymbol, _T("()") ) == nullptr)
191 { 191 {
192 ULONG index = 0; 192 ULONG index = 0;
193 for( ; ; index++ ) 193 for( ; ; index++ )
194 { 194 {
195 lpszParamSep = _tcschr( lpszParsed, _T(',') ); 195 lpszParamSep = _tcschr( lpszParsed, _T(',') );
196 if ( lpszParamSep == NULL ) 196 if ( lpszParamSep == nullptr )
197 break; 197 break;
198 198
199 *lpszParamSep = _T('\0'); 199 *lpszParamSep = _T('\0');
@@ -205,7 +205,7 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L
205 } 205 }
206 206
207 lpszParamSep = _tcschr( lpszParsed, _T(')') ); 207 lpszParamSep = _tcschr( lpszParsed, _T(')') );
208 if ( lpszParamSep != NULL ) 208 if ( lpszParamSep != nullptr )
209 { 209 {
210 *lpszParamSep = _T('\0'); 210 *lpszParamSep = _T('\0');
211 211
@@ -248,7 +248,7 @@ static BOOL GetSourceInfoFromAddress( UINT address, LPTSTR lpszSourceInfo )
248 PCSTR2LPTSTR( lineInfo.FileName, lpszFileName ); 248 PCSTR2LPTSTR( lineInfo.FileName, lpszFileName );
249 TCHAR fname[_MAX_FNAME]; 249 TCHAR fname[_MAX_FNAME];
250 TCHAR ext[_MAX_EXT]; 250 TCHAR ext[_MAX_EXT];
251 _tsplitpath(lpszFileName, NULL, NULL, fname, ext); 251 _tsplitpath(lpszFileName, nullptr, nullptr, fname, ext);
252 _stprintf( lpszSourceInfo, _T("%s%s(%d)"), fname, ext, lineInfo.LineNumber ); 252 _stprintf( lpszSourceInfo, _T("%s%s(%d)"), fname, ext, lineInfo.LineNumber );
253 ret = TRUE; 253 ret = TRUE;
254 } 254 }
@@ -332,11 +332,11 @@ void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file )
332 hProcess, 332 hProcess,
333 hThread, 333 hThread,
334 &callStack, 334 &callStack,
335 NULL, 335 nullptr,
336 NULL, 336 nullptr,
337 SymFunctionTableAccess, 337 SymFunctionTableAccess,
338 SymGetModuleBase, 338 SymGetModuleBase,
339 NULL); 339 nullptr);
340 340
341 if ( index == 0 ) 341 if ( index == 0 )
342 continue; 342 continue;
@@ -389,11 +389,11 @@ void StackTrace(HANDLE hThread, const char* lpszMessage, FILE *file, DWORD eip,
389 hProcess, 389 hProcess,
390 hThread, 390 hThread,
391 &callStack, 391 &callStack,
392 NULL, 392 nullptr,
393 NULL, 393 nullptr,
394 SymFunctionTableAccess, 394 SymFunctionTableAccess,
395 SymGetModuleBase, 395 SymGetModuleBase,
396 NULL); 396 nullptr);
397 397
398 if ( index == 0 ) 398 if ( index == 0 )
399 continue; 399 continue;
diff --git a/src/common/fifo_queue.h b/src/common/fifo_queue.h
index 2c18285d4..b426e6596 100644
--- a/src/common/fifo_queue.h
+++ b/src/common/fifo_queue.h
@@ -57,7 +57,7 @@ public:
57 // advance the read pointer 57 // advance the read pointer
58 m_read_ptr = m_read_ptr->next; 58 m_read_ptr = m_read_ptr->next;
59 // set the next element to NULL to stop the recursive deletion 59 // set the next element to NULL to stop the recursive deletion
60 tmpptr->next = NULL; 60 tmpptr->next = nullptr;
61 delete tmpptr; // this also deletes the element 61 delete tmpptr; // this also deletes the element
62 } 62 }
63 63
@@ -86,7 +86,7 @@ private:
86 class ElementPtr 86 class ElementPtr
87 { 87 {
88 public: 88 public:
89 ElementPtr() : current(NULL), next(NULL) {} 89 ElementPtr() : current(nullptr), next(nullptr) {}
90 90
91 ~ElementPtr() 91 ~ElementPtr()
92 { 92 {
diff --git a/src/common/file_search.cpp b/src/common/file_search.cpp
index bfb54ce72..b3a0a84fb 100644
--- a/src/common/file_search.cpp
+++ b/src/common/file_search.cpp
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5 5
diff --git a/src/common/file_search.h b/src/common/file_search.h
index f966a008d..55ca02638 100644
--- a/src/common/file_search.h
+++ b/src/common/file_search.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index b6dec838c..bba830c70 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5 5
@@ -88,7 +88,7 @@ bool IsDirectory(const std::string &filename)
88#endif 88#endif
89 89
90 if (result < 0) { 90 if (result < 0) {
91 WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s", 91 LOG_WARNING(Common_Filesystem, "stat failed on %s: %s",
92 filename.c_str(), GetLastErrorMsg()); 92 filename.c_str(), GetLastErrorMsg());
93 return false; 93 return false;
94 } 94 }
@@ -100,33 +100,33 @@ bool IsDirectory(const std::string &filename)
100// Doesn't supports deleting a directory 100// Doesn't supports deleting a directory
101bool Delete(const std::string &filename) 101bool Delete(const std::string &filename)
102{ 102{
103 INFO_LOG(COMMON, "Delete: file %s", filename.c_str()); 103 LOG_INFO(Common_Filesystem, "file %s", filename.c_str());
104 104
105 // Return true because we care about the file no 105 // Return true because we care about the file no
106 // being there, not the actual delete. 106 // being there, not the actual delete.
107 if (!Exists(filename)) 107 if (!Exists(filename))
108 { 108 {
109 WARN_LOG(COMMON, "Delete: %s does not exist", filename.c_str()); 109 LOG_WARNING(Common_Filesystem, "%s does not exist", filename.c_str());
110 return true; 110 return true;
111 } 111 }
112 112
113 // We can't delete a directory 113 // We can't delete a directory
114 if (IsDirectory(filename)) 114 if (IsDirectory(filename))
115 { 115 {
116 WARN_LOG(COMMON, "Delete failed: %s is a directory", filename.c_str()); 116 LOG_ERROR(Common_Filesystem, "Failed: %s is a directory", filename.c_str());
117 return false; 117 return false;
118 } 118 }
119 119
120#ifdef _WIN32 120#ifdef _WIN32
121 if (!DeleteFile(Common::UTF8ToTStr(filename).c_str())) 121 if (!DeleteFile(Common::UTF8ToTStr(filename).c_str()))
122 { 122 {
123 WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s", 123 LOG_ERROR(Common_Filesystem, "DeleteFile failed on %s: %s",
124 filename.c_str(), GetLastErrorMsg()); 124 filename.c_str(), GetLastErrorMsg());
125 return false; 125 return false;
126 } 126 }
127#else 127#else
128 if (unlink(filename.c_str()) == -1) { 128 if (unlink(filename.c_str()) == -1) {
129 WARN_LOG(COMMON, "Delete: unlink failed on %s: %s", 129 LOG_ERROR(Common_Filesystem, "unlink failed on %s: %s",
130 filename.c_str(), GetLastErrorMsg()); 130 filename.c_str(), GetLastErrorMsg());
131 return false; 131 return false;
132 } 132 }
@@ -138,17 +138,17 @@ bool Delete(const std::string &filename)
138// Returns true if successful, or path already exists. 138// Returns true if successful, or path already exists.
139bool CreateDir(const std::string &path) 139bool CreateDir(const std::string &path)
140{ 140{
141 INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str()); 141 LOG_TRACE(Common_Filesystem, "directory %s", path.c_str());
142#ifdef _WIN32 142#ifdef _WIN32
143 if (::CreateDirectory(Common::UTF8ToTStr(path).c_str(), NULL)) 143 if (::CreateDirectory(Common::UTF8ToTStr(path).c_str(), nullptr))
144 return true; 144 return true;
145 DWORD error = GetLastError(); 145 DWORD error = GetLastError();
146 if (error == ERROR_ALREADY_EXISTS) 146 if (error == ERROR_ALREADY_EXISTS)
147 { 147 {
148 WARN_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: already exists", path.c_str()); 148 LOG_WARNING(Common_Filesystem, "CreateDirectory failed on %s: already exists", path.c_str());
149 return true; 149 return true;
150 } 150 }
151 ERROR_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: %i", path.c_str(), error); 151 LOG_ERROR(Common_Filesystem, "CreateDirectory failed on %s: %i", path.c_str(), error);
152 return false; 152 return false;
153#else 153#else
154 if (mkdir(path.c_str(), 0755) == 0) 154 if (mkdir(path.c_str(), 0755) == 0)
@@ -158,11 +158,11 @@ bool CreateDir(const std::string &path)
158 158
159 if (err == EEXIST) 159 if (err == EEXIST)
160 { 160 {
161 WARN_LOG(COMMON, "CreateDir: mkdir failed on %s: already exists", path.c_str()); 161 LOG_WARNING(Common_Filesystem, "mkdir failed on %s: already exists", path.c_str());
162 return true; 162 return true;
163 } 163 }
164 164
165 ERROR_LOG(COMMON, "CreateDir: mkdir failed on %s: %s", path.c_str(), strerror(err)); 165 LOG_ERROR(Common_Filesystem, "mkdir failed on %s: %s", path.c_str(), strerror(err));
166 return false; 166 return false;
167#endif 167#endif
168} 168}
@@ -171,11 +171,11 @@ bool CreateDir(const std::string &path)
171bool CreateFullPath(const std::string &fullPath) 171bool CreateFullPath(const std::string &fullPath)
172{ 172{
173 int panicCounter = 100; 173 int panicCounter = 100;
174 INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str()); 174 LOG_TRACE(Common_Filesystem, "path %s", fullPath.c_str());
175 175
176 if (FileUtil::Exists(fullPath)) 176 if (FileUtil::Exists(fullPath))
177 { 177 {
178 INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str()); 178 LOG_WARNING(Common_Filesystem, "path exists %s", fullPath.c_str());
179 return true; 179 return true;
180 } 180 }
181 181
@@ -192,7 +192,7 @@ bool CreateFullPath(const std::string &fullPath)
192 // Include the '/' so the first call is CreateDir("/") rather than CreateDir("") 192 // Include the '/' so the first call is CreateDir("/") rather than CreateDir("")
193 std::string const subPath(fullPath.substr(0, position + 1)); 193 std::string const subPath(fullPath.substr(0, position + 1));
194 if (!FileUtil::IsDirectory(subPath) && !FileUtil::CreateDir(subPath)) { 194 if (!FileUtil::IsDirectory(subPath) && !FileUtil::CreateDir(subPath)) {
195 ERROR_LOG(COMMON, "CreateFullPath: directory creation failed"); 195 LOG_ERROR(Common, "CreateFullPath: directory creation failed");
196 return false; 196 return false;
197 } 197 }
198 198
@@ -200,7 +200,7 @@ bool CreateFullPath(const std::string &fullPath)
200 panicCounter--; 200 panicCounter--;
201 if (panicCounter <= 0) 201 if (panicCounter <= 0)
202 { 202 {
203 ERROR_LOG(COMMON, "CreateFullPath: directory structure is too deep"); 203 LOG_ERROR(Common, "CreateFullPath: directory structure is too deep");
204 return false; 204 return false;
205 } 205 }
206 position++; 206 position++;
@@ -211,12 +211,12 @@ bool CreateFullPath(const std::string &fullPath)
211// Deletes a directory filename, returns true on success 211// Deletes a directory filename, returns true on success
212bool DeleteDir(const std::string &filename) 212bool DeleteDir(const std::string &filename)
213{ 213{
214 INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str()); 214 LOG_INFO(Common_Filesystem, "directory %s", filename.c_str());
215 215
216 // check if a directory 216 // check if a directory
217 if (!FileUtil::IsDirectory(filename)) 217 if (!FileUtil::IsDirectory(filename))
218 { 218 {
219 ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str()); 219 LOG_ERROR(Common_Filesystem, "Not a directory %s", filename.c_str());
220 return false; 220 return false;
221 } 221 }
222 222
@@ -227,7 +227,7 @@ bool DeleteDir(const std::string &filename)
227 if (rmdir(filename.c_str()) == 0) 227 if (rmdir(filename.c_str()) == 0)
228 return true; 228 return true;
229#endif 229#endif
230 ERROR_LOG(COMMON, "DeleteDir: %s: %s", filename.c_str(), GetLastErrorMsg()); 230 LOG_ERROR(Common_Filesystem, "failed %s: %s", filename.c_str(), GetLastErrorMsg());
231 231
232 return false; 232 return false;
233} 233}
@@ -235,11 +235,11 @@ bool DeleteDir(const std::string &filename)
235// renames file srcFilename to destFilename, returns true on success 235// renames file srcFilename to destFilename, returns true on success
236bool Rename(const std::string &srcFilename, const std::string &destFilename) 236bool Rename(const std::string &srcFilename, const std::string &destFilename)
237{ 237{
238 INFO_LOG(COMMON, "Rename: %s --> %s", 238 LOG_TRACE(Common_Filesystem, "%s --> %s",
239 srcFilename.c_str(), destFilename.c_str()); 239 srcFilename.c_str(), destFilename.c_str());
240 if (rename(srcFilename.c_str(), destFilename.c_str()) == 0) 240 if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
241 return true; 241 return true;
242 ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s", 242 LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s",
243 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); 243 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
244 return false; 244 return false;
245} 245}
@@ -247,13 +247,13 @@ bool Rename(const std::string &srcFilename, const std::string &destFilename)
247// copies file srcFilename to destFilename, returns true on success 247// copies file srcFilename to destFilename, returns true on success
248bool Copy(const std::string &srcFilename, const std::string &destFilename) 248bool Copy(const std::string &srcFilename, const std::string &destFilename)
249{ 249{
250 INFO_LOG(COMMON, "Copy: %s --> %s", 250 LOG_TRACE(Common_Filesystem, "%s --> %s",
251 srcFilename.c_str(), destFilename.c_str()); 251 srcFilename.c_str(), destFilename.c_str());
252#ifdef _WIN32 252#ifdef _WIN32
253 if (CopyFile(Common::UTF8ToTStr(srcFilename).c_str(), Common::UTF8ToTStr(destFilename).c_str(), FALSE)) 253 if (CopyFile(Common::UTF8ToTStr(srcFilename).c_str(), Common::UTF8ToTStr(destFilename).c_str(), FALSE))
254 return true; 254 return true;
255 255
256 ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s", 256 LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s",
257 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); 257 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
258 return false; 258 return false;
259#else 259#else
@@ -267,7 +267,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
267 FILE *input = fopen(srcFilename.c_str(), "rb"); 267 FILE *input = fopen(srcFilename.c_str(), "rb");
268 if (!input) 268 if (!input)
269 { 269 {
270 ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s", 270 LOG_ERROR(Common_Filesystem, "opening input failed %s --> %s: %s",
271 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); 271 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
272 return false; 272 return false;
273 } 273 }
@@ -277,7 +277,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
277 if (!output) 277 if (!output)
278 { 278 {
279 fclose(input); 279 fclose(input);
280 ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s", 280 LOG_ERROR(Common_Filesystem, "opening output failed %s --> %s: %s",
281 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); 281 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
282 return false; 282 return false;
283 } 283 }
@@ -291,8 +291,8 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
291 { 291 {
292 if (ferror(input) != 0) 292 if (ferror(input) != 0)
293 { 293 {
294 ERROR_LOG(COMMON, 294 LOG_ERROR(Common_Filesystem,
295 "Copy: failed reading from source, %s --> %s: %s", 295 "failed reading from source, %s --> %s: %s",
296 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); 296 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
297 goto bail; 297 goto bail;
298 } 298 }
@@ -302,8 +302,8 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
302 int wnum = fwrite(buffer, sizeof(char), rnum, output); 302 int wnum = fwrite(buffer, sizeof(char), rnum, output);
303 if (wnum != rnum) 303 if (wnum != rnum)
304 { 304 {
305 ERROR_LOG(COMMON, 305 LOG_ERROR(Common_Filesystem,
306 "Copy: failed writing to output, %s --> %s: %s", 306 "failed writing to output, %s --> %s: %s",
307 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg()); 307 srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
308 goto bail; 308 goto bail;
309 } 309 }
@@ -326,13 +326,13 @@ u64 GetSize(const std::string &filename)
326{ 326{
327 if (!Exists(filename)) 327 if (!Exists(filename))
328 { 328 {
329 WARN_LOG(COMMON, "GetSize: failed %s: No such file", filename.c_str()); 329 LOG_ERROR(Common_Filesystem, "failed %s: No such file", filename.c_str());
330 return 0; 330 return 0;
331 } 331 }
332 332
333 if (IsDirectory(filename)) 333 if (IsDirectory(filename))
334 { 334 {
335 WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.c_str()); 335 LOG_ERROR(Common_Filesystem, "failed %s: is a directory", filename.c_str());
336 return 0; 336 return 0;
337 } 337 }
338 338
@@ -343,12 +343,12 @@ u64 GetSize(const std::string &filename)
343 if (stat64(filename.c_str(), &buf) == 0) 343 if (stat64(filename.c_str(), &buf) == 0)
344#endif 344#endif
345 { 345 {
346 DEBUG_LOG(COMMON, "GetSize: %s: %lld", 346 LOG_TRACE(Common_Filesystem, "%s: %lld",
347 filename.c_str(), (long long)buf.st_size); 347 filename.c_str(), (long long)buf.st_size);
348 return buf.st_size; 348 return buf.st_size;
349 } 349 }
350 350
351 ERROR_LOG(COMMON, "GetSize: Stat failed %s: %s", 351 LOG_ERROR(Common_Filesystem, "Stat failed %s: %s",
352 filename.c_str(), GetLastErrorMsg()); 352 filename.c_str(), GetLastErrorMsg());
353 return 0; 353 return 0;
354} 354}
@@ -358,7 +358,7 @@ u64 GetSize(const int fd)
358{ 358{
359 struct stat64 buf; 359 struct stat64 buf;
360 if (fstat64(fd, &buf) != 0) { 360 if (fstat64(fd, &buf) != 0) {
361 ERROR_LOG(COMMON, "GetSize: stat failed %i: %s", 361 LOG_ERROR(Common_Filesystem, "GetSize: stat failed %i: %s",
362 fd, GetLastErrorMsg()); 362 fd, GetLastErrorMsg());
363 return 0; 363 return 0;
364 } 364 }
@@ -371,13 +371,13 @@ u64 GetSize(FILE *f)
371 // can't use off_t here because it can be 32-bit 371 // can't use off_t here because it can be 32-bit
372 u64 pos = ftello(f); 372 u64 pos = ftello(f);
373 if (fseeko(f, 0, SEEK_END) != 0) { 373 if (fseeko(f, 0, SEEK_END) != 0) {
374 ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", 374 LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s",
375 f, GetLastErrorMsg()); 375 f, GetLastErrorMsg());
376 return 0; 376 return 0;
377 } 377 }
378 u64 size = ftello(f); 378 u64 size = ftello(f);
379 if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) { 379 if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) {
380 ERROR_LOG(COMMON, "GetSize: seek failed %p: %s", 380 LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s",
381 f, GetLastErrorMsg()); 381 f, GetLastErrorMsg());
382 return 0; 382 return 0;
383 } 383 }
@@ -387,11 +387,11 @@ u64 GetSize(FILE *f)
387// creates an empty file filename, returns true on success 387// creates an empty file filename, returns true on success
388bool CreateEmptyFile(const std::string &filename) 388bool CreateEmptyFile(const std::string &filename)
389{ 389{
390 INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str()); 390 LOG_TRACE(Common_Filesystem, "%s", filename.c_str());
391 391
392 if (!FileUtil::IOFile(filename, "wb")) 392 if (!FileUtil::IOFile(filename, "wb"))
393 { 393 {
394 ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s", 394 LOG_ERROR(Common_Filesystem, "failed %s: %s",
395 filename.c_str(), GetLastErrorMsg()); 395 filename.c_str(), GetLastErrorMsg());
396 return false; 396 return false;
397 } 397 }
@@ -404,7 +404,7 @@ bool CreateEmptyFile(const std::string &filename)
404// results into parentEntry. Returns the number of files+directories found 404// results into parentEntry. Returns the number of files+directories found
405u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry) 405u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
406{ 406{
407 INFO_LOG(COMMON, "ScanDirectoryTree: directory %s", directory.c_str()); 407 LOG_TRACE(Common_Filesystem, "directory %s", directory.c_str());
408 // How many files + directories we found 408 // How many files + directories we found
409 u32 foundEntries = 0; 409 u32 foundEntries = 0;
410#ifdef _WIN32 410#ifdef _WIN32
@@ -423,7 +423,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
423 FSTEntry entry; 423 FSTEntry entry;
424 const std::string virtualName(Common::TStrToUTF8(ffd.cFileName)); 424 const std::string virtualName(Common::TStrToUTF8(ffd.cFileName));
425#else 425#else
426 struct dirent dirent, *result = NULL; 426 struct dirent dirent, *result = nullptr;
427 427
428 DIR *dirp = opendir(directory.c_str()); 428 DIR *dirp = opendir(directory.c_str());
429 if (!dirp) 429 if (!dirp)
@@ -474,7 +474,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
474// Deletes the given directory and anything under it. Returns true on success. 474// Deletes the given directory and anything under it. Returns true on success.
475bool DeleteDirRecursively(const std::string &directory) 475bool DeleteDirRecursively(const std::string &directory)
476{ 476{
477 INFO_LOG(COMMON, "DeleteDirRecursively: %s", directory.c_str()); 477 LOG_TRACE(Common_Filesystem, "%s", directory.c_str());
478#ifdef _WIN32 478#ifdef _WIN32
479 // Find the first file in the directory. 479 // Find the first file in the directory.
480 WIN32_FIND_DATA ffd; 480 WIN32_FIND_DATA ffd;
@@ -491,7 +491,7 @@ bool DeleteDirRecursively(const std::string &directory)
491 { 491 {
492 const std::string virtualName(Common::TStrToUTF8(ffd.cFileName)); 492 const std::string virtualName(Common::TStrToUTF8(ffd.cFileName));
493#else 493#else
494 struct dirent dirent, *result = NULL; 494 struct dirent dirent, *result = nullptr;
495 DIR *dirp = opendir(directory.c_str()); 495 DIR *dirp = opendir(directory.c_str());
496 if (!dirp) 496 if (!dirp)
497 return false; 497 return false;
@@ -552,7 +552,7 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
552 if (!FileUtil::Exists(source_path)) return; 552 if (!FileUtil::Exists(source_path)) return;
553 if (!FileUtil::Exists(dest_path)) FileUtil::CreateFullPath(dest_path); 553 if (!FileUtil::Exists(dest_path)) FileUtil::CreateFullPath(dest_path);
554 554
555 struct dirent dirent, *result = NULL; 555 struct dirent dirent, *result = nullptr;
556 DIR *dirp = opendir(source_path.c_str()); 556 DIR *dirp = opendir(source_path.c_str());
557 if (!dirp) return; 557 if (!dirp) return;
558 558
@@ -586,11 +586,11 @@ std::string GetCurrentDir()
586{ 586{
587 char *dir; 587 char *dir;
588 // Get the current working directory (getcwd uses malloc) 588 // Get the current working directory (getcwd uses malloc)
589 if (!(dir = __getcwd(NULL, 0))) { 589 if (!(dir = __getcwd(nullptr, 0))) {
590 590
591 ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s", 591 LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: %s",
592 GetLastErrorMsg()); 592 GetLastErrorMsg());
593 return NULL; 593 return nullptr;
594 } 594 }
595 std::string strDir = dir; 595 std::string strDir = dir;
596 free(dir); 596 free(dir);
@@ -626,7 +626,7 @@ std::string& GetExeDirectory()
626 if (DolphinPath.empty()) 626 if (DolphinPath.empty())
627 { 627 {
628 TCHAR Dolphin_exe_Path[2048]; 628 TCHAR Dolphin_exe_Path[2048];
629 GetModuleFileName(NULL, Dolphin_exe_Path, 2048); 629 GetModuleFileName(nullptr, Dolphin_exe_Path, 2048);
630 DolphinPath = Common::TStrToUTF8(Dolphin_exe_Path); 630 DolphinPath = Common::TStrToUTF8(Dolphin_exe_Path);
631 DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\')); 631 DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\'));
632 } 632 }
@@ -647,7 +647,7 @@ std::string GetSysDirectory()
647#endif 647#endif
648 sysDir += DIR_SEP; 648 sysDir += DIR_SEP;
649 649
650 INFO_LOG(COMMON, "GetSysDirectory: Setting to %s:", sysDir.c_str()); 650 LOG_DEBUG(Common_Filesystem, "Setting to %s:", sysDir.c_str());
651 return sysDir; 651 return sysDir;
652} 652}
653 653
@@ -676,6 +676,9 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
676 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; 676 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
677 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; 677 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
678 paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; 678 paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
679 paths[D_SAVEDATA_IDX] = paths[D_USER_IDX] + SAVEDATA_DIR DIR_SEP;
680 paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP;
681 paths[D_SYSSAVEDATA_IDX] = paths[D_USER_IDX] + SYSSAVEDATA_DIR DIR_SEP;
679 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; 682 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
680 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; 683 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
681 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; 684 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
@@ -694,7 +697,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
694 { 697 {
695 if (!FileUtil::IsDirectory(newPath)) 698 if (!FileUtil::IsDirectory(newPath))
696 { 699 {
697 WARN_LOG(COMMON, "Invalid path specified %s", newPath.c_str()); 700 LOG_ERROR(Common_Filesystem, "Invalid path specified %s", newPath.c_str());
698 return paths[DirIDX]; 701 return paths[DirIDX];
699 } 702 }
700 else 703 else
@@ -717,6 +720,8 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
717 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP; 720 paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
718 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP; 721 paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
719 paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP; 722 paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
723 paths[D_SAVEDATA_IDX] = paths[D_USER_IDX] + SAVEDATA_DIR DIR_SEP;
724 paths[D_SYSSAVEDATA_IDX] = paths[D_USER_IDX] + SYSSAVEDATA_DIR DIR_SEP;
720 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP; 725 paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
721 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP; 726 paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
722 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP; 727 paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
@@ -753,19 +758,6 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
753 return paths[DirIDX]; 758 return paths[DirIDX];
754} 759}
755 760
756//std::string GetThemeDir(const std::string& theme_name)
757//{
758// std::string dir = FileUtil::GetUserPath(D_THEMES_IDX) + theme_name + "/";
759//
760//#if !defined(_WIN32)
761// // If theme does not exist in user's dir load from shared directory
762// if (!FileUtil::Exists(dir))
763// dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/";
764//#endif
765//
766// return dir;
767//}
768
769size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename) 761size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename)
770{ 762{
771 return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size()); 763 return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size());
@@ -826,7 +818,7 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
826} 818}
827 819
828IOFile::IOFile() 820IOFile::IOFile()
829 : m_file(NULL), m_good(true) 821 : m_file(nullptr), m_good(true)
830{} 822{}
831 823
832IOFile::IOFile(std::FILE* file) 824IOFile::IOFile(std::FILE* file)
@@ -834,7 +826,7 @@ IOFile::IOFile(std::FILE* file)
834{} 826{}
835 827
836IOFile::IOFile(const std::string& filename, const char openmode[]) 828IOFile::IOFile(const std::string& filename, const char openmode[])
837 : m_file(NULL), m_good(true) 829 : m_file(nullptr), m_good(true)
838{ 830{
839 Open(filename, openmode); 831 Open(filename, openmode);
840} 832}
@@ -845,7 +837,7 @@ IOFile::~IOFile()
845} 837}
846 838
847IOFile::IOFile(IOFile&& other) 839IOFile::IOFile(IOFile&& other)
848 : m_file(NULL), m_good(true) 840 : m_file(nullptr), m_good(true)
849{ 841{
850 Swap(other); 842 Swap(other);
851} 843}
@@ -880,14 +872,14 @@ bool IOFile::Close()
880 if (!IsOpen() || 0 != std::fclose(m_file)) 872 if (!IsOpen() || 0 != std::fclose(m_file))
881 m_good = false; 873 m_good = false;
882 874
883 m_file = NULL; 875 m_file = nullptr;
884 return m_good; 876 return m_good;
885} 877}
886 878
887std::FILE* IOFile::ReleaseHandle() 879std::FILE* IOFile::ReleaseHandle()
888{ 880{
889 std::FILE* const ret = m_file; 881 std::FILE* const ret = m_file;
890 m_file = NULL; 882 m_file = nullptr;
891 return ret; 883 return ret;
892} 884}
893 885
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 72b80be8a..293c30941 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -27,6 +27,9 @@ enum {
27 D_STATESAVES_IDX, 27 D_STATESAVES_IDX,
28 D_SCREENSHOTS_IDX, 28 D_SCREENSHOTS_IDX,
29 D_SDMC_IDX, 29 D_SDMC_IDX,
30 D_SAVEDATA_IDX,
31 D_SYSDATA_IDX,
32 D_SYSSAVEDATA_IDX,
30 D_HIRESTEXTURES_IDX, 33 D_HIRESTEXTURES_IDX,
31 D_DUMP_IDX, 34 D_DUMP_IDX,
32 D_DUMPFRAMES_IDX, 35 D_DUMPFRAMES_IDX,
@@ -202,11 +205,11 @@ public:
202 return WriteArray(reinterpret_cast<const char*>(data), length); 205 return WriteArray(reinterpret_cast<const char*>(data), length);
203 } 206 }
204 207
205 bool IsOpen() { return NULL != m_file; } 208 bool IsOpen() { return nullptr != m_file; }
206 209
207 // m_good is set to false when a read, write or other function fails 210 // m_good is set to false when a read, write or other function fails
208 bool IsGood() { return m_good; } 211 bool IsGood() { return m_good; }
209 operator void*() { return m_good ? m_file : NULL; } 212 operator void*() { return m_good ? m_file : nullptr; }
210 213
211 std::FILE* ReleaseHandle(); 214 std::FILE* ReleaseHandle();
212 215
diff --git a/src/common/hash.cpp b/src/common/hash.cpp
index 2ddcfe6b7..fe2c9e636 100644
--- a/src/common/hash.cpp
+++ b/src/common/hash.cpp
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5 5
diff --git a/src/common/hash.h b/src/common/hash.h
index 29f699d7f..3ac42bc44 100644
--- a/src/common/hash.h
+++ b/src/common/hash.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/common/key_map.cpp b/src/common/key_map.cpp
index 309caab98..d8945bb13 100644
--- a/src/common/key_map.cpp
+++ b/src/common/key_map.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "key_map.h" 5#include "key_map.h"
diff --git a/src/common/key_map.h b/src/common/key_map.h
index bf72362c0..8d949b852 100644
--- a/src/common/key_map.h
+++ b/src/common/key_map.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/common/linear_disk_cache.h b/src/common/linear_disk_cache.h
index f4263f72a..74ce74aba 100644
--- a/src/common/linear_disk_cache.h
+++ b/src/common/linear_disk_cache.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -70,7 +70,7 @@ public:
70 // good header, read some key/value pairs 70 // good header, read some key/value pairs
71 K key; 71 K key;
72 72
73 V *value = NULL; 73 V *value = nullptr;
74 u32 value_size; 74 u32 value_size;
75 u32 entry_number; 75 u32 entry_number;
76 76
diff --git a/src/common/log.h b/src/common/log.h
index 4c96ef0a6..c6a023552 100644
--- a/src/common/log.h
+++ b/src/common/log.h
@@ -1,108 +1,12 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
7#ifndef LOGGING 7#include "common/common_funcs.h"
8#define LOGGING 8#include "common/msg_handler.h"
9#endif 9#include "common/logging/log.h"
10
11enum {
12 OS_LEVEL, // Printed by the emulated operating system
13 NOTICE_LEVEL, // VERY important information that is NOT errors. Like startup and OSReports.
14 ERROR_LEVEL, // Critical errors
15 WARNING_LEVEL, // Something is suspicious.
16 INFO_LEVEL, // General information.
17 DEBUG_LEVEL, // Detailed debugging - might make things slow.
18};
19
20namespace LogTypes
21{
22
23enum LOG_TYPE {
24 ACTIONREPLAY,
25 AUDIO,
26 AUDIO_INTERFACE,
27 BOOT,
28 COMMANDPROCESSOR,
29 COMMON,
30 CONSOLE,
31 CONFIG,
32 DISCIO,
33 FILEMON,
34 DSPHLE,
35 DSPLLE,
36 DSP_MAIL,
37 DSPINTERFACE,
38 DVDINTERFACE,
39 DYNA_REC,
40 EXPANSIONINTERFACE,
41 GDB_STUB,
42 ARM11,
43 GSP,
44 OSHLE,
45 MASTER_LOG,
46 MEMMAP,
47 MEMCARD_MANAGER,
48 OSREPORT,
49 PAD,
50 PROCESSORINTERFACE,
51 PIXELENGINE,
52 SERIALINTERFACE,
53 SP1,
54 STREAMINGINTERFACE,
55 VIDEO,
56 VIDEOINTERFACE,
57 LOADER,
58 FILESYS,
59 WII_IPC_DVD,
60 WII_IPC_ES,
61 WII_IPC_FILEIO,
62 WII_IPC_HID,
63 KERNEL,
64 SVC,
65 NDMA,
66 HLE,
67 RENDER,
68 GPU,
69 HW,
70 TIME,
71 NETPLAY,
72 GUI,
73
74 NUMBER_OF_LOGS // Must be last
75};
76
77// FIXME: should this be removed?
78enum LOG_LEVELS {
79 LOS = OS_LEVEL,
80 LNOTICE = NOTICE_LEVEL,
81 LERROR = ERROR_LEVEL,
82 LWARNING = WARNING_LEVEL,
83 LINFO = INFO_LEVEL,
84 LDEBUG = DEBUG_LEVEL,
85};
86
87#define LOGTYPES_LEVELS LogTypes::LOG_LEVELS
88#define LOGTYPES_TYPE LogTypes::LOG_TYPE
89
90} // namespace
91
92void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int line,
93 const char* function, const char* fmt, ...)
94#ifdef __GNUC__
95 __attribute__((format(printf, 6, 7)))
96#endif
97 ;
98
99#if defined LOGGING || defined _DEBUG || defined DEBUGFAST
100#define MAX_LOGLEVEL LDEBUG
101#else
102#ifndef MAX_LOGLEVEL
103#define MAX_LOGLEVEL LWARNING
104#endif // loglevel
105#endif // logging
106 10
107#ifdef MSVC_VER 11#ifdef MSVC_VER
108#ifndef __func__ 12#ifndef __func__
@@ -110,29 +14,16 @@ void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int
110#endif 14#endif
111#endif 15#endif
112 16
113// Let the compiler optimize this out 17#if _DEBUG
114#define GENERIC_LOG(t, v, ...) { \
115 if (v <= LogTypes::MAX_LOGLEVEL) \
116 GenericLog(v, t, __FILE__, __LINE__, __func__, __VA_ARGS__); \
117 }
118
119#define OS_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LOS, __VA_ARGS__) } while (0)
120#define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (0)
121#define WARN_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) } while (0)
122#define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (0)
123#define INFO_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LINFO, __VA_ARGS__) } while (0)
124#define DEBUG_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LDEBUG, __VA_ARGS__) } while (0)
125
126#if MAX_LOGLEVEL >= DEBUG_LEVEL
127#define _dbg_assert_(_t_, _a_) \ 18#define _dbg_assert_(_t_, _a_) \
128 if (!(_a_)) {\ 19 if (!(_a_)) {\
129 ERROR_LOG(_t_, "Error...\n\n Line: %d\n File: %s\n Time: %s\n\nIgnore and continue?", \ 20 LOG_CRITICAL(_t_, "Error...\n\n Line: %d\n File: %s\n Time: %s\n\nIgnore and continue?", \
130 __LINE__, __FILE__, __TIME__); \ 21 __LINE__, __FILE__, __TIME__); \
131 if (!PanicYesNo("*** Assertion (see log)***\n")) {Crash();} \ 22 if (!PanicYesNo("*** Assertion (see log)***\n")) {Crash();} \
132 } 23 }
133#define _dbg_assert_msg_(_t_, _a_, ...)\ 24#define _dbg_assert_msg_(_t_, _a_, ...)\
134 if (!(_a_)) {\ 25 if (!(_a_)) {\
135 ERROR_LOG(_t_, __VA_ARGS__); \ 26 LOG_CRITICAL(_t_, __VA_ARGS__); \
136 if (!PanicYesNo(__VA_ARGS__)) {Crash();} \ 27 if (!PanicYesNo(__VA_ARGS__)) {Crash();} \
137 } 28 }
138#define _dbg_update_() Host_UpdateLogDisplay(); 29#define _dbg_update_() Host_UpdateLogDisplay();
@@ -144,12 +35,12 @@ void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int
144#define _dbg_assert_(_t_, _a_) {} 35#define _dbg_assert_(_t_, _a_) {}
145#define _dbg_assert_msg_(_t_, _a_, _desc_, ...) {} 36#define _dbg_assert_msg_(_t_, _a_, _desc_, ...) {}
146#endif // dbg_assert 37#endif // dbg_assert
147#endif // MAX_LOGLEVEL DEBUG 38#endif
148 39
149#define _assert_(_a_) _dbg_assert_(MASTER_LOG, _a_) 40#define _assert_(_a_) _dbg_assert_(MASTER_LOG, _a_)
150 41
151#ifndef GEKKO 42#ifndef GEKKO
152#ifdef MSVC_VER 43#ifdef _WIN32
153#define _assert_msg_(_t_, _a_, _fmt_, ...) \ 44#define _assert_msg_(_t_, _a_, _fmt_, ...) \
154 if (!(_a_)) {\ 45 if (!(_a_)) {\
155 if (!PanicYesNo(_fmt_, __VA_ARGS__)) {Crash();} \ 46 if (!PanicYesNo(_fmt_, __VA_ARGS__)) {Crash();} \
@@ -159,7 +50,7 @@ void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int
159 if (!(_a_)) {\ 50 if (!(_a_)) {\
160 if (!PanicYesNo(_fmt_, ##__VA_ARGS__)) {Crash();} \ 51 if (!PanicYesNo(_fmt_, ##__VA_ARGS__)) {Crash();} \
161 } 52 }
162#endif // MSVC_VER 53#endif // _WIN32
163#else // GEKKO 54#else // GEKKO
164#define _assert_msg_(_t_, _a_, _fmt_, ...) 55#define _assert_msg_(_t_, _a_, _fmt_, ...)
165#endif 56#endif \ No newline at end of file
diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp
deleted file mode 100644
index 2ef7d98c0..000000000
--- a/src/common/log_manager.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <algorithm>
6
7#include "common/log_manager.h"
8#include "common/console_listener.h"
9#include "common/timer.h"
10
11void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,
12 const char* function, const char* fmt, ...)
13{
14 va_list args;
15 va_start(args, fmt);
16
17 if (LogManager::GetInstance()) {
18 LogManager::GetInstance()->Log(level, type,
19 file, line, function, fmt, args);
20 }
21 va_end(args);
22}
23
24LogManager *LogManager::m_logManager = NULL;
25
26LogManager::LogManager()
27{
28 // create log files
29 m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log");
30 m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot");
31 m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common");
32 m_Log[LogTypes::CONFIG] = new LogContainer("CONFIG", "Configuration");
33 m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO");
34 m_Log[LogTypes::FILEMON] = new LogContainer("FileMon", "File Monitor");
35 m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad");
36 m_Log[LogTypes::PIXELENGINE] = new LogContainer("PE", "PixelEngine");
37 m_Log[LogTypes::COMMANDPROCESSOR] = new LogContainer("CP", "CommandProc");
38 m_Log[LogTypes::VIDEOINTERFACE] = new LogContainer("VI", "VideoInt");
39 m_Log[LogTypes::SERIALINTERFACE] = new LogContainer("SI", "SerialInt");
40 m_Log[LogTypes::PROCESSORINTERFACE] = new LogContainer("PI", "ProcessorInt");
41 m_Log[LogTypes::MEMMAP] = new LogContainer("MI", "MI & memmap");
42 m_Log[LogTypes::SP1] = new LogContainer("SP1", "Serial Port 1");
43 m_Log[LogTypes::STREAMINGINTERFACE] = new LogContainer("Stream", "StreamingInt");
44 m_Log[LogTypes::DSPINTERFACE] = new LogContainer("DSP", "DSPInterface");
45 m_Log[LogTypes::DVDINTERFACE] = new LogContainer("DVD", "DVDInterface");
46 m_Log[LogTypes::GSP] = new LogContainer("GSP", "GSP");
47 m_Log[LogTypes::EXPANSIONINTERFACE] = new LogContainer("EXI", "ExpansionInt");
48 m_Log[LogTypes::GDB_STUB] = new LogContainer("GDB_STUB", "GDB Stub");
49 m_Log[LogTypes::AUDIO_INTERFACE] = new LogContainer("AI", "AudioInt");
50 m_Log[LogTypes::ARM11] = new LogContainer("ARM11", "ARM11");
51 m_Log[LogTypes::OSHLE] = new LogContainer("HLE", "HLE");
52 m_Log[LogTypes::DSPHLE] = new LogContainer("DSPHLE", "DSP HLE");
53 m_Log[LogTypes::DSPLLE] = new LogContainer("DSPLLE", "DSP LLE");
54 m_Log[LogTypes::DSP_MAIL] = new LogContainer("DSPMails", "DSP Mails");
55 m_Log[LogTypes::VIDEO] = new LogContainer("Video", "Video Backend");
56 m_Log[LogTypes::AUDIO] = new LogContainer("Audio", "Audio Emulator");
57 m_Log[LogTypes::DYNA_REC] = new LogContainer("JIT", "JIT");
58 m_Log[LogTypes::CONSOLE] = new LogContainer("CONSOLE", "Dolphin Console");
59 m_Log[LogTypes::OSREPORT] = new LogContainer("OSREPORT", "OSReport");
60 m_Log[LogTypes::TIME] = new LogContainer("Time", "Core Timing");
61 m_Log[LogTypes::LOADER] = new LogContainer("Loader", "Loader");
62 m_Log[LogTypes::FILESYS] = new LogContainer("FileSys", "File System");
63 m_Log[LogTypes::WII_IPC_HID] = new LogContainer("WII_IPC_HID", "WII IPC HID");
64 m_Log[LogTypes::KERNEL] = new LogContainer("KERNEL", "KERNEL HLE");
65 m_Log[LogTypes::WII_IPC_DVD] = new LogContainer("WII_IPC_DVD", "WII IPC DVD");
66 m_Log[LogTypes::WII_IPC_ES] = new LogContainer("WII_IPC_ES", "WII IPC ES");
67 m_Log[LogTypes::WII_IPC_FILEIO] = new LogContainer("WII_IPC_FILEIO", "WII IPC FILEIO");
68 m_Log[LogTypes::RENDER] = new LogContainer("RENDER", "RENDER");
69 m_Log[LogTypes::GPU] = new LogContainer("GPU", "GPU");
70 m_Log[LogTypes::SVC] = new LogContainer("SVC", "Supervisor Call HLE");
71 m_Log[LogTypes::NDMA] = new LogContainer("NDMA", "NDMA");
72 m_Log[LogTypes::HLE] = new LogContainer("HLE", "High Level Emulation");
73 m_Log[LogTypes::HW] = new LogContainer("HW", "Hardware");
74 m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay");
75 m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager");
76 m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay");
77 m_Log[LogTypes::GUI] = new LogContainer("GUI", "GUI");
78
79 m_fileLog = new FileLogListener(FileUtil::GetUserPath(F_MAINLOG_IDX).c_str());
80 m_consoleLog = new ConsoleListener();
81 m_debuggerLog = new DebuggerLogListener();
82
83 for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
84 {
85 m_Log[i]->SetEnable(true);
86 m_Log[i]->AddListener(m_fileLog);
87 m_Log[i]->AddListener(m_consoleLog);
88#ifdef _MSC_VER
89 if (IsDebuggerPresent())
90 m_Log[i]->AddListener(m_debuggerLog);
91#endif
92 }
93
94 m_consoleLog->Open();
95}
96
97LogManager::~LogManager()
98{
99 for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
100 {
101 m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_fileLog);
102 m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_consoleLog);
103 m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_debuggerLog);
104 }
105
106 for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
107 delete m_Log[i];
108
109 delete m_fileLog;
110 delete m_consoleLog;
111 delete m_debuggerLog;
112}
113
114void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file,
115 int line, const char* function, const char *fmt, va_list args)
116{
117 char temp[MAX_MSGLEN];
118 char msg[MAX_MSGLEN * 2];
119 LogContainer *log = m_Log[type];
120
121 if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners())
122 return;
123
124 Common::CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args);
125
126 static const char level_to_char[7] = "ONEWID";
127 sprintf(msg, "%s %s:%u %c[%s] %s: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line,
128 level_to_char[(int)level], log->GetShortName(), function, temp);
129
130#ifdef ANDROID
131 Host_SysMessage(msg);
132#endif
133 log->Trigger(level, msg);
134}
135
136void LogManager::Init()
137{
138 m_logManager = new LogManager();
139}
140
141void LogManager::Shutdown()
142{
143 delete m_logManager;
144 m_logManager = NULL;
145}
146
147LogContainer::LogContainer(const char* shortName, const char* fullName, bool enable)
148 : m_enable(enable)
149{
150 strncpy(m_fullName, fullName, 128);
151 strncpy(m_shortName, shortName, 32);
152 m_level = LogTypes::MAX_LOGLEVEL;
153}
154
155// LogContainer
156void LogContainer::AddListener(LogListener *listener)
157{
158 std::lock_guard<std::mutex> lk(m_listeners_lock);
159 m_listeners.insert(listener);
160}
161
162void LogContainer::RemoveListener(LogListener *listener)
163{
164 std::lock_guard<std::mutex> lk(m_listeners_lock);
165 m_listeners.erase(listener);
166}
167
168void LogContainer::Trigger(LogTypes::LOG_LEVELS level, const char *msg)
169{
170 std::lock_guard<std::mutex> lk(m_listeners_lock);
171
172 std::set<LogListener*>::const_iterator i;
173 for (i = m_listeners.begin(); i != m_listeners.end(); ++i)
174 {
175 (*i)->Log(level, msg);
176 }
177}
178
179FileLogListener::FileLogListener(const char *filename)
180{
181 OpenFStream(m_logfile, filename, std::ios::app);
182 SetEnable(true);
183}
184
185void FileLogListener::Log(LogTypes::LOG_LEVELS, const char *msg)
186{
187 if (!IsEnabled() || !IsValid())
188 return;
189
190 std::lock_guard<std::mutex> lk(m_log_lock);
191 m_logfile << msg << std::flush;
192}
193
194void DebuggerLogListener::Log(LogTypes::LOG_LEVELS, const char *msg)
195{
196#if _MSC_VER
197 ::OutputDebugStringA(msg);
198#endif
199}
diff --git a/src/common/log_manager.h b/src/common/log_manager.h
deleted file mode 100644
index baefc4ba8..000000000
--- a/src/common/log_manager.h
+++ /dev/null
@@ -1,166 +0,0 @@
1// Copyright 2013 Dolphin Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/log.h"
8#include "common/string_util.h"
9#include "common/file_util.h"
10
11#include <cstring>
12#include <set>
13#include <mutex>
14
15#define MAX_MESSAGES 8000
16#define MAX_MSGLEN 1024
17
18
19// pure virtual interface
20class LogListener
21{
22public:
23 virtual ~LogListener() {}
24
25 virtual void Log(LogTypes::LOG_LEVELS, const char *msg) = 0;
26};
27
28class FileLogListener : public LogListener
29{
30public:
31 FileLogListener(const char *filename);
32
33 void Log(LogTypes::LOG_LEVELS, const char *msg) override;
34
35 bool IsValid() { return !m_logfile.fail(); }
36 bool IsEnabled() const { return m_enable; }
37 void SetEnable(bool enable) { m_enable = enable; }
38
39 const char* GetName() const { return "file"; }
40
41private:
42 std::mutex m_log_lock;
43 std::ofstream m_logfile;
44 bool m_enable;
45};
46
47class DebuggerLogListener : public LogListener
48{
49public:
50 void Log(LogTypes::LOG_LEVELS, const char *msg) override;
51};
52
53class LogContainer
54{
55public:
56 LogContainer(const char* shortName, const char* fullName, bool enable = false);
57
58 const char* GetShortName() const { return m_shortName; }
59 const char* GetFullName() const { return m_fullName; }
60
61 void AddListener(LogListener* listener);
62 void RemoveListener(LogListener* listener);
63
64 void Trigger(LogTypes::LOG_LEVELS, const char *msg);
65
66 bool IsEnabled() const { return m_enable; }
67 void SetEnable(bool enable) { m_enable = enable; }
68
69 LogTypes::LOG_LEVELS GetLevel() const { return m_level; }
70
71 void SetLevel(LogTypes::LOG_LEVELS level) { m_level = level; }
72
73 bool HasListeners() const { return !m_listeners.empty(); }
74
75private:
76 char m_fullName[128];
77 char m_shortName[32];
78 bool m_enable;
79 LogTypes::LOG_LEVELS m_level;
80 std::mutex m_listeners_lock;
81 std::set<LogListener*> m_listeners;
82};
83
84class ConsoleListener;
85
86class LogManager : NonCopyable
87{
88private:
89 LogContainer* m_Log[LogTypes::NUMBER_OF_LOGS];
90 FileLogListener *m_fileLog;
91 ConsoleListener *m_consoleLog;
92 DebuggerLogListener *m_debuggerLog;
93 static LogManager *m_logManager; // Singleton. Ugh.
94
95 LogManager();
96 ~LogManager();
97public:
98
99 static u32 GetMaxLevel() { return LogTypes::MAX_LOGLEVEL; }
100
101 void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,
102 const char* function, const char *fmt, va_list args);
103
104 void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level)
105 {
106 m_Log[type]->SetLevel(level);
107 }
108
109 void SetEnable(LogTypes::LOG_TYPE type, bool enable)
110 {
111 m_Log[type]->SetEnable(enable);
112 }
113
114 bool IsEnabled(LogTypes::LOG_TYPE type) const
115 {
116 return m_Log[type]->IsEnabled();
117 }
118
119 const char* GetShortName(LogTypes::LOG_TYPE type) const
120 {
121 return m_Log[type]->GetShortName();
122 }
123
124 const char* GetFullName(LogTypes::LOG_TYPE type) const
125 {
126 return m_Log[type]->GetFullName();
127 }
128
129 void AddListener(LogTypes::LOG_TYPE type, LogListener *listener)
130 {
131 m_Log[type]->AddListener(listener);
132 }
133
134 void RemoveListener(LogTypes::LOG_TYPE type, LogListener *listener)
135 {
136 m_Log[type]->RemoveListener(listener);
137 }
138
139 FileLogListener *GetFileListener() const
140 {
141 return m_fileLog;
142 }
143
144 ConsoleListener *GetConsoleListener() const
145 {
146 return m_consoleLog;
147 }
148
149 DebuggerLogListener *GetDebuggerListener() const
150 {
151 return m_debuggerLog;
152 }
153
154 static LogManager* GetInstance()
155 {
156 return m_logManager;
157 }
158
159 static void SetInstance(LogManager *logManager)
160 {
161 m_logManager = logManager;
162 }
163
164 static void Init();
165 static void Shutdown();
166};
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
new file mode 100644
index 000000000..816d1bb55
--- /dev/null
+++ b/src/common/logging/backend.cpp
@@ -0,0 +1,151 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6
7#include "common/log.h" // For _dbg_assert_
8
9#include "common/logging/backend.h"
10#include "common/logging/log.h"
11#include "common/logging/text_formatter.h"
12
13namespace Log {
14
15static std::shared_ptr<Logger> global_logger;
16
17/// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this.
18#define ALL_LOG_CLASSES() \
19 CLS(Log) \
20 CLS(Common) \
21 SUB(Common, Filesystem) \
22 SUB(Common, Memory) \
23 CLS(Core) \
24 SUB(Core, ARM11) \
25 CLS(Config) \
26 CLS(Debug) \
27 SUB(Debug, Emulated) \
28 SUB(Debug, GPU) \
29 SUB(Debug, Breakpoint) \
30 CLS(Kernel) \
31 SUB(Kernel, SVC) \
32 CLS(Service) \
33 SUB(Service, SRV) \
34 SUB(Service, FS) \
35 SUB(Service, APT) \
36 SUB(Service, GSP) \
37 SUB(Service, AC) \
38 SUB(Service, PTM) \
39 SUB(Service, CFG) \
40 SUB(Service, DSP) \
41 SUB(Service, HID) \
42 CLS(HW) \
43 SUB(HW, Memory) \
44 SUB(HW, GPU) \
45 CLS(Frontend) \
46 CLS(Render) \
47 SUB(Render, Software) \
48 SUB(Render, OpenGL) \
49 CLS(Loader)
50
51Logger::Logger() {
52 // Register logging classes so that they can be queried at runtime
53 size_t parent_class;
54 all_classes.reserve((size_t)Class::Count);
55
56#define CLS(x) \
57 all_classes.push_back(Class::x); \
58 parent_class = all_classes.size() - 1;
59#define SUB(x, y) \
60 all_classes.push_back(Class::x##_##y); \
61 all_classes[parent_class].num_children += 1;
62
63 ALL_LOG_CLASSES()
64#undef CLS
65#undef SUB
66
67 // Ensures that ALL_LOG_CLASSES isn't missing any entries.
68 _dbg_assert_(Log, all_classes.size() == (size_t)Class::Count);
69}
70
71// GetClassName is a macro defined by Windows.h, grrr...
72const char* Logger::GetLogClassName(Class log_class) {
73 switch (log_class) {
74#define CLS(x) case Class::x: return #x;
75#define SUB(x, y) case Class::x##_##y: return #x "." #y;
76 ALL_LOG_CLASSES()
77#undef CLS
78#undef SUB
79 }
80 return "Unknown";
81}
82
83const char* Logger::GetLevelName(Level log_level) {
84#define LVL(x) case Level::x: return #x
85 switch (log_level) {
86 LVL(Trace);
87 LVL(Debug);
88 LVL(Info);
89 LVL(Warning);
90 LVL(Error);
91 LVL(Critical);
92 }
93 return "Unknown";
94#undef LVL
95}
96
97void Logger::LogMessage(Entry entry) {
98 ring_buffer.Push(std::move(entry));
99}
100
101size_t Logger::GetEntries(Entry* out_buffer, size_t buffer_len) {
102 return ring_buffer.BlockingPop(out_buffer, buffer_len);
103}
104
105std::shared_ptr<Logger> InitGlobalLogger() {
106 global_logger = std::make_shared<Logger>();
107 return global_logger;
108}
109
110Entry CreateEntry(Class log_class, Level log_level,
111 const char* filename, unsigned int line_nr, const char* function,
112 const char* format, va_list args) {
113 using std::chrono::steady_clock;
114 using std::chrono::duration_cast;
115
116 static steady_clock::time_point time_origin = steady_clock::now();
117
118 std::array<char, 4 * 1024> formatting_buffer;
119
120 Entry entry;
121 entry.timestamp = duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin);
122 entry.log_class = log_class;
123 entry.log_level = log_level;
124
125 snprintf(formatting_buffer.data(), formatting_buffer.size(), "%s:%s:%u", filename, function, line_nr);
126 entry.location = std::string(formatting_buffer.data());
127
128 vsnprintf(formatting_buffer.data(), formatting_buffer.size(), format, args);
129 entry.message = std::string(formatting_buffer.data());
130
131 return std::move(entry);
132}
133
134void LogMessage(Class log_class, Level log_level,
135 const char* filename, unsigned int line_nr, const char* function,
136 const char* format, ...) {
137 va_list args;
138 va_start(args, format);
139 Entry entry = CreateEntry(log_class, log_level,
140 filename, line_nr, function, format, args);
141 va_end(args);
142
143 if (global_logger != nullptr && !global_logger->IsClosed()) {
144 global_logger->LogMessage(std::move(entry));
145 } else {
146 // Fall back to directly printing to stderr
147 PrintMessage(entry);
148 }
149}
150
151}
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
new file mode 100644
index 000000000..1c44c929e
--- /dev/null
+++ b/src/common/logging/backend.h
@@ -0,0 +1,134 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstdarg>
8#include <memory>
9#include <vector>
10
11#include "common/concurrent_ring_buffer.h"
12
13#include "common/logging/log.h"
14
15namespace Log {
16
17/**
18 * A log entry. Log entries are store in a structured format to permit more varied output
19 * formatting on different frontends, as well as facilitating filtering and aggregation.
20 */
21struct Entry {
22 std::chrono::microseconds timestamp;
23 Class log_class;
24 Level log_level;
25 std::string location;
26 std::string message;
27
28 Entry() = default;
29
30 // TODO(yuriks) Use defaulted move constructors once MSVC supports them
31#define MOVE(member) member(std::move(o.member))
32 Entry(Entry&& o)
33 : MOVE(timestamp), MOVE(log_class), MOVE(log_level),
34 MOVE(location), MOVE(message)
35 {}
36#undef MOVE
37
38 Entry& operator=(const Entry&& o) {
39#define MOVE(member) member = std::move(o.member)
40 MOVE(timestamp);
41 MOVE(log_class);
42 MOVE(log_level);
43 MOVE(location);
44 MOVE(message);
45#undef MOVE
46 return *this;
47 }
48};
49
50struct ClassInfo {
51 Class log_class;
52
53 /**
54 * Total number of (direct or indirect) sub classes this class has. If any, they follow in
55 * sequence after this class in the class list.
56 */
57 unsigned int num_children = 0;
58
59 ClassInfo(Class log_class) : log_class(log_class) {}
60};
61
62/**
63 * Logging management class. This class has the dual purpose of acting as an exchange point between
64 * the logging clients and the log outputter, as well as containing reflection info about available
65 * log classes.
66 */
67class Logger {
68private:
69 using Buffer = Common::ConcurrentRingBuffer<Entry, 16 * 1024 / sizeof(Entry)>;
70
71public:
72 static const size_t QUEUE_CLOSED = Buffer::QUEUE_CLOSED;
73
74 Logger();
75
76 /**
77 * Returns a list of all vector classes and subclasses. The sequence returned is a pre-order of
78 * classes and subclasses, which together with the `num_children` field in ClassInfo, allows
79 * you to recover the hierarchy.
80 */
81 const std::vector<ClassInfo>& GetClasses() const { return all_classes; }
82
83 /**
84 * Returns the name of the passed log class as a C-string. Subclasses are separated by periods
85 * instead of underscores as in the enumeration.
86 */
87 static const char* GetLogClassName(Class log_class);
88
89 /**
90 * Returns the name of the passed log level as a C-string.
91 */
92 static const char* GetLevelName(Level log_level);
93
94 /**
95 * Appends a messages to the log buffer.
96 * @note This function is thread safe.
97 */
98 void LogMessage(Entry entry);
99
100 /**
101 * Retrieves a batch of messages from the log buffer, blocking until they are available.
102 * @note This function is thread safe.
103 *
104 * @param out_buffer Destination buffer that will receive the log entries.
105 * @param buffer_len The maximum size of `out_buffer`.
106 * @return The number of entries stored. In case the logger is shutting down, `QUEUE_CLOSED` is
107 * returned, no entries are stored and the logger should shutdown.
108 */
109 size_t GetEntries(Entry* out_buffer, size_t buffer_len);
110
111 /**
112 * Initiates a shutdown of the logger. This will indicate to log output clients that they
113 * should shutdown.
114 */
115 void Close() { ring_buffer.Close(); }
116
117 /**
118 * Returns true if Close() has already been called on the Logger.
119 */
120 bool IsClosed() const { return ring_buffer.IsClosed(); }
121
122private:
123 Buffer ring_buffer;
124 std::vector<ClassInfo> all_classes;
125};
126
127/// Creates a log entry by formatting the given source location, and message.
128Entry CreateEntry(Class log_class, Level log_level,
129 const char* filename, unsigned int line_nr, const char* function,
130 const char* format, va_list args);
131/// Initializes the default Logger.
132std::shared_ptr<Logger> InitGlobalLogger();
133
134}
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
new file mode 100644
index 000000000..50f2e13f4
--- /dev/null
+++ b/src/common/logging/filter.cpp
@@ -0,0 +1,132 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6
7#include "common/logging/filter.h"
8#include "common/logging/backend.h"
9#include "common/string_util.h"
10
11namespace Log {
12
13Filter::Filter(Level default_level) {
14 ResetAll(default_level);
15}
16
17void Filter::ResetAll(Level level) {
18 class_levels.fill(level);
19}
20
21void Filter::SetClassLevel(Class log_class, Level level) {
22 class_levels[static_cast<size_t>(log_class)] = level;
23}
24
25void Filter::SetSubclassesLevel(const ClassInfo& log_class, Level level) {
26 const size_t log_class_i = static_cast<size_t>(log_class.log_class);
27
28 const size_t begin = log_class_i + 1;
29 const size_t end = begin + log_class.num_children;
30 for (size_t i = begin; begin < end; ++i) {
31 class_levels[i] = level;
32 }
33}
34
35void Filter::ParseFilterString(const std::string& filter_str) {
36 auto clause_begin = filter_str.cbegin();
37 while (clause_begin != filter_str.cend()) {
38 auto clause_end = std::find(clause_begin, filter_str.cend(), ' ');
39
40 // If clause isn't empty
41 if (clause_end != clause_begin) {
42 ParseFilterRule(clause_begin, clause_end);
43 }
44
45 if (clause_end != filter_str.cend()) {
46 // Skip over the whitespace
47 ++clause_end;
48 }
49 clause_begin = clause_end;
50 }
51}
52
53template <typename It>
54static Level GetLevelByName(const It begin, const It end) {
55 for (u8 i = 0; i < static_cast<u8>(Level::Count); ++i) {
56 const char* level_name = Logger::GetLevelName(static_cast<Level>(i));
57 if (Common::ComparePartialString(begin, end, level_name)) {
58 return static_cast<Level>(i);
59 }
60 }
61 return Level::Count;
62}
63
64template <typename It>
65static Class GetClassByName(const It begin, const It end) {
66 for (ClassType i = 0; i < static_cast<ClassType>(Class::Count); ++i) {
67 const char* level_name = Logger::GetLogClassName(static_cast<Class>(i));
68 if (Common::ComparePartialString(begin, end, level_name)) {
69 return static_cast<Class>(i);
70 }
71 }
72 return Class::Count;
73}
74
75template <typename InputIt, typename T>
76static InputIt find_last(InputIt begin, const InputIt end, const T& value) {
77 auto match = end;
78 while (begin != end) {
79 auto new_match = std::find(begin, end, value);
80 if (new_match != end) {
81 match = new_match;
82 ++new_match;
83 }
84 begin = new_match;
85 }
86 return match;
87}
88
89bool Filter::ParseFilterRule(const std::string::const_iterator begin,
90 const std::string::const_iterator end) {
91 auto level_separator = std::find(begin, end, ':');
92 if (level_separator == end) {
93 LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: %s",
94 std::string(begin, end).c_str());
95 return false;
96 }
97
98 const Level level = GetLevelByName(level_separator + 1, end);
99 if (level == Level::Count) {
100 LOG_ERROR(Log, "Unknown log level in filter: %s", std::string(begin, end).c_str());
101 return false;
102 }
103
104 if (Common::ComparePartialString(begin, level_separator, "*")) {
105 ResetAll(level);
106 return true;
107 }
108
109 auto class_name_end = find_last(begin, level_separator, '.');
110 if (class_name_end != level_separator &&
111 !Common::ComparePartialString(class_name_end + 1, level_separator, "*")) {
112 class_name_end = level_separator;
113 }
114
115 const Class log_class = GetClassByName(begin, class_name_end);
116 if (log_class == Class::Count) {
117 LOG_ERROR(Log, "Unknown log class in filter: %s", std::string(begin, end).c_str());
118 return false;
119 }
120
121 if (class_name_end == level_separator) {
122 SetClassLevel(log_class, level);
123 }
124 SetSubclassesLevel(log_class, level);
125 return true;
126}
127
128bool Filter::CheckMessage(Class log_class, Level level) const {
129 return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]);
130}
131
132}
diff --git a/src/common/logging/filter.h b/src/common/logging/filter.h
new file mode 100644
index 000000000..c3da9989f
--- /dev/null
+++ b/src/common/logging/filter.h
@@ -0,0 +1,63 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6#include <string>
7
8#include "common/logging/log.h"
9
10namespace Log {
11
12struct ClassInfo;
13
14/**
15 * Implements a log message filter which allows different log classes to have different minimum
16 * severity levels. The filter can be changed at runtime and can be parsed from a string to allow
17 * editing via the interface or loading from a configuration file.
18 */
19class Filter {
20public:
21 /// Initializes the filter with all classes having `default_level` as the minimum level.
22 Filter(Level default_level);
23
24 /// Resets the filter so that all classes have `level` as the minimum displayed level.
25 void ResetAll(Level level);
26 /// Sets the minimum level of `log_class` (and not of its subclasses) to `level`.
27 void SetClassLevel(Class log_class, Level level);
28 /**
29 * Sets the minimum level of all of `log_class` subclasses to `level`. The level of `log_class`
30 * itself is not changed.
31 */
32 void SetSubclassesLevel(const ClassInfo& log_class, Level level);
33
34 /**
35 * Parses a filter string and applies it to this filter.
36 *
37 * A filter string consists of a space-separated list of filter rules, each of the format
38 * `<class>:<level>`. `<class>` is a log class name, with subclasses separated using periods.
39 * A rule for a given class also affects all of its subclasses. `*` wildcards are allowed and
40 * can be used to apply a rule to all classes or to all subclasses of a class without affecting
41 * the parent class. `<level>` a severity level name which will be set as the minimum logging
42 * level of the matched classes. Rules are applied left to right, with each rule overriding
43 * previous ones in the sequence.
44 *
45 * A few examples of filter rules:
46 * - `*:Info` -- Resets the level of all classes to Info.
47 * - `Service:Info` -- Sets the level of Service and all subclasses (Service.FS, Service.APT,
48 * etc.) to Info.
49 * - `Service.*:Debug` -- Sets the level of all Service subclasses to Debug, while leaving the
50 * level of Service unchanged.
51 * - `Service.FS:Trace` -- Sets the level of the Service.FS class to Trace.
52 */
53 void ParseFilterString(const std::string& filter_str);
54 bool ParseFilterRule(const std::string::const_iterator start, const std::string::const_iterator end);
55
56 /// Matches class/level combination against the filter, returning true if it passed.
57 bool CheckMessage(Class log_class, Level level) const;
58
59private:
60 std::array<Level, (size_t)Class::Count> class_levels;
61};
62
63}
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
new file mode 100644
index 000000000..d1c391862
--- /dev/null
+++ b/src/common/logging/log.h
@@ -0,0 +1,115 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cassert>
8#include <chrono>
9#include <string>
10
11#include "common/common_types.h"
12
13namespace Log {
14
15/// Specifies the severity or level of detail of the log message.
16enum class Level : u8 {
17 Trace, ///< Extremely detailed and repetitive debugging information that is likely to
18 /// pollute logs.
19 Debug, ///< Less detailed debugging information.
20 Info, ///< Status information from important points during execution.
21 Warning, ///< Minor or potential problems found during execution of a task.
22 Error, ///< Major problems found during execution of a task that prevent it from being
23 /// completed.
24 Critical, ///< Major problems during execution that threathen the stability of the entire
25 /// application.
26
27 Count ///< Total number of logging levels
28};
29
30typedef u8 ClassType;
31
32/**
33 * Specifies the sub-system that generated the log message.
34 *
35 * @note If you add a new entry here, also add a corresponding one to `ALL_LOG_CLASSES` in log.cpp.
36 */
37enum class Class : ClassType {
38 Log, ///< Messages about the log system itself
39 Common, ///< Library routines
40 Common_Filesystem, ///< Filesystem interface library
41 Common_Memory, ///< Memory mapping and management functions
42 Core, ///< LLE emulation core
43 Core_ARM11, ///< ARM11 CPU core
44 Config, ///< Emulator configuration (including commandline)
45 Debug, ///< Debugging tools
46 Debug_Emulated, ///< Debug messages from the emulated programs
47 Debug_GPU, ///< GPU debugging tools
48 Debug_Breakpoint, ///< Logging breakpoints and watchpoints
49 Kernel, ///< The HLE implementation of the CTR kernel
50 Kernel_SVC, ///< Kernel system calls
51 Service, ///< HLE implementation of system services. Each major service
52 /// should have its own subclass.
53 Service_SRV, ///< The SRV (Service Directory) implementation
54 Service_FS, ///< The FS (Filesystem) service implementation
55 Service_APT, ///< The APT (Applets) service
56 Service_GSP, ///< The GSP (GPU control) service
57 Service_AC, ///< The AC (WiFi status) service
58 Service_PTM, ///< The PTM (Power status & misc.) service
59 Service_CFG, ///< The CFG (Configuration) service
60 Service_DSP, ///< The DSP (DSP control) service
61 Service_HID, ///< The HID (User input) service
62 HW, ///< Low-level hardware emulation
63 HW_Memory, ///< Memory-map and address translation
64 HW_GPU, ///< GPU control emulation
65 Frontend, ///< Emulator UI
66 Render, ///< Emulator video output and hardware acceleration
67 Render_Software, ///< Software renderer backend
68 Render_OpenGL, ///< OpenGL backend
69 Loader, ///< ROM loader
70
71 Count ///< Total number of logging classes
72};
73
74/**
75 * Level below which messages are simply discarded without buffering regardless of the display
76 * settings.
77 */
78const Level MINIMUM_LEVEL =
79#ifdef _DEBUG
80 Level::Trace;
81#else
82 Level::Debug;
83#endif
84
85/**
86 * Logs a message to the global logger. This proxy exists to avoid exposing the details of the
87 * Logger class, including the ConcurrentRingBuffer template, to all files that desire to log
88 * messages, reducing unecessary recompilations.
89 */
90void LogMessage(Class log_class, Level log_level,
91 const char* filename, unsigned int line_nr, const char* function,
92#ifdef _MSC_VER
93 _Printf_format_string_
94#endif
95 const char* format, ...)
96#ifdef __GNUC__
97 __attribute__((format(printf, 6, 7)))
98#endif
99 ;
100
101} // namespace Log
102
103#define LOG_GENERIC(log_class, log_level, ...) \
104 do { \
105 if (::Log::Level::log_level >= ::Log::MINIMUM_LEVEL) \
106 ::Log::LogMessage(::Log::Class::log_class, ::Log::Level::log_level, \
107 __FILE__, __LINE__, __func__, __VA_ARGS__); \
108 } while (0)
109
110#define LOG_TRACE( log_class, ...) LOG_GENERIC(log_class, Trace, __VA_ARGS__)
111#define LOG_DEBUG( log_class, ...) LOG_GENERIC(log_class, Debug, __VA_ARGS__)
112#define LOG_INFO( log_class, ...) LOG_GENERIC(log_class, Info, __VA_ARGS__)
113#define LOG_WARNING( log_class, ...) LOG_GENERIC(log_class, Warning, __VA_ARGS__)
114#define LOG_ERROR( log_class, ...) LOG_GENERIC(log_class, Error, __VA_ARGS__)
115#define LOG_CRITICAL(log_class, ...) LOG_GENERIC(log_class, Critical, __VA_ARGS__)
diff --git a/src/common/logging/text_formatter.cpp b/src/common/logging/text_formatter.cpp
new file mode 100644
index 000000000..ef5739d84
--- /dev/null
+++ b/src/common/logging/text_formatter.cpp
@@ -0,0 +1,136 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <array>
6#include <cstdio>
7
8#ifdef _WIN32
9# define WIN32_LEAN_AND_MEAN
10# include <Windows.h>
11#endif
12
13#include "common/logging/backend.h"
14#include "common/logging/filter.h"
15#include "common/logging/log.h"
16#include "common/logging/text_formatter.h"
17
18#include "common/string_util.h"
19
20namespace Log {
21
22// TODO(bunnei): This should be moved to a generic path manipulation library
23const char* TrimSourcePath(const char* path, const char* root) {
24 const char* p = path;
25
26 while (*p != '\0') {
27 const char* next_slash = p;
28 while (*next_slash != '\0' && *next_slash != '/' && *next_slash != '\\') {
29 ++next_slash;
30 }
31
32 bool is_src = Common::ComparePartialString(p, next_slash, root);
33 p = next_slash;
34
35 if (*p != '\0') {
36 ++p;
37 }
38 if (is_src) {
39 path = p;
40 }
41 }
42 return path;
43}
44
45void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len) {
46 unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000);
47 unsigned int time_fractional = static_cast<unsigned int>(entry.timestamp.count() % 1000000);
48
49 const char* class_name = Logger::GetLogClassName(entry.log_class);
50 const char* level_name = Logger::GetLevelName(entry.log_level);
51
52 snprintf(out_text, text_len, "[%4u.%06u] %s <%s> %s: %s",
53 time_seconds, time_fractional, class_name, level_name,
54 TrimSourcePath(entry.location.c_str()), entry.message.c_str());
55}
56
57void PrintMessage(const Entry& entry) {
58 std::array<char, 4 * 1024> format_buffer;
59 FormatLogMessage(entry, format_buffer.data(), format_buffer.size());
60 fputs(format_buffer.data(), stderr);
61 fputc('\n', stderr);
62}
63
64void PrintColoredMessage(const Entry& entry) {
65#ifdef _WIN32
66 static HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE);
67
68 CONSOLE_SCREEN_BUFFER_INFO original_info = {0};
69 GetConsoleScreenBufferInfo(console_handle, &original_info);
70
71 WORD color = 0;
72 switch (entry.log_level) {
73 case Level::Trace: // Grey
74 color = FOREGROUND_INTENSITY; break;
75 case Level::Debug: // Cyan
76 color = FOREGROUND_GREEN | FOREGROUND_BLUE; break;
77 case Level::Info: // Bright gray
78 color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
79 case Level::Warning: // Bright yellow
80 color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; break;
81 case Level::Error: // Bright red
82 color = FOREGROUND_RED | FOREGROUND_INTENSITY; break;
83 case Level::Critical: // Bright magenta
84 color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
85 }
86
87 SetConsoleTextAttribute(console_handle, color);
88#else
89# define ESC "\x1b"
90 const char* color = "";
91 switch (entry.log_level) {
92 case Level::Trace: // Grey
93 color = ESC "[1;30m"; break;
94 case Level::Debug: // Cyan
95 color = ESC "[0;36m"; break;
96 case Level::Info: // Bright gray
97 color = ESC "[0;37m"; break;
98 case Level::Warning: // Bright yellow
99 color = ESC "[1;33m"; break;
100 case Level::Error: // Bright red
101 color = ESC "[1;31m"; break;
102 case Level::Critical: // Bright magenta
103 color = ESC "[1;35m"; break;
104 }
105
106 fputs(color, stderr);
107#endif
108
109 PrintMessage(entry);
110
111#ifdef _WIN32
112 SetConsoleTextAttribute(console_handle, original_info.wAttributes);
113#else
114 fputs(ESC "[0m", stderr);
115# undef ESC
116#endif
117}
118
119void TextLoggingLoop(std::shared_ptr<Logger> logger, const Filter* filter) {
120 std::array<Entry, 256> entry_buffer;
121
122 while (true) {
123 size_t num_entries = logger->GetEntries(entry_buffer.data(), entry_buffer.size());
124 if (num_entries == Logger::QUEUE_CLOSED) {
125 break;
126 }
127 for (size_t i = 0; i < num_entries; ++i) {
128 const Entry& entry = entry_buffer[i];
129 if (filter->CheckMessage(entry.log_class, entry.log_level)) {
130 PrintColoredMessage(entry);
131 }
132 }
133 }
134}
135
136}
diff --git a/src/common/logging/text_formatter.h b/src/common/logging/text_formatter.h
new file mode 100644
index 000000000..2f05794f0
--- /dev/null
+++ b/src/common/logging/text_formatter.h
@@ -0,0 +1,41 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstddef>
8#include <memory>
9
10namespace Log {
11
12class Logger;
13struct Entry;
14class Filter;
15
16/**
17 * Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's
18 * intended to be used to strip a system-specific build directory from the `__FILE__` macro,
19 * leaving only the path relative to the sources root.
20 *
21 * @param path The input file path as a null-terminated string
22 * @param root The name of the root source directory as a null-terminated string. Path up to and
23 * including the last occurence of this name will be stripped
24 * @return A pointer to the same string passed as `path`, but starting at the trimmed portion
25 */
26const char* TrimSourcePath(const char* path, const char* root = "src");
27
28/// Formats a log entry into the provided text buffer.
29void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len);
30/// Formats and prints a log entry to stderr.
31void PrintMessage(const Entry& entry);
32/// Prints the same message as `PrintMessage`, but colored acoording to the severity level.
33void PrintColoredMessage(const Entry& entry);
34
35/**
36 * Logging loop that repeatedly reads messages from the provided logger and prints them to the
37 * console. It is the baseline barebones log outputter.
38 */
39void TextLoggingLoop(std::shared_ptr<Logger> logger, const Filter* filter);
40
41}
diff --git a/src/common/make_unique.h b/src/common/make_unique.h
new file mode 100644
index 000000000..2a7b76412
--- /dev/null
+++ b/src/common/make_unique.h
@@ -0,0 +1,16 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8
9namespace Common {
10
11template <typename T, typename... Args>
12std::unique_ptr<T> make_unique(Args&&... args) {
13 return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
14}
15
16} // namespace
diff --git a/src/common/math_util.cpp b/src/common/math_util.cpp
index 3613e82a6..a83592dd2 100644
--- a/src/common/math_util.cpp
+++ b/src/common/math_util.cpp
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5 5
diff --git a/src/common/math_util.h b/src/common/math_util.h
index b10a25c13..43b0e0dc3 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/common/mem_arena.cpp b/src/common/mem_arena.cpp
index 67dbaf509..9904d2472 100644
--- a/src/common/mem_arena.cpp
+++ b/src/common/mem_arena.cpp
@@ -30,7 +30,7 @@
30#endif 30#endif
31 31
32#ifdef IOS 32#ifdef IOS
33void* globalbase = NULL; 33void* globalbase = nullptr;
34#endif 34#endif
35 35
36#ifdef ANDROID 36#ifdef ANDROID
@@ -71,7 +71,7 @@ int ashmem_create_region(const char *name, size_t size)
71 return fd; 71 return fd;
72 72
73error: 73error:
74 ERROR_LOG(MEMMAP, "NASTY ASHMEM ERROR: ret = %08x", ret); 74 LOG_ERROR(Common_Memory, "NASTY ASHMEM ERROR: ret = %08x", ret);
75 close(fd); 75 close(fd);
76 return ret; 76 return ret;
77} 77}
@@ -121,7 +121,7 @@ void MemArena::GrabLowMemSpace(size_t size)
121{ 121{
122#ifdef _WIN32 122#ifdef _WIN32
123#ifndef _XBOX 123#ifndef _XBOX
124 hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), NULL); 124 hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, (DWORD)(size), nullptr);
125 GetSystemInfo(&sysInfo); 125 GetSystemInfo(&sysInfo);
126#endif 126#endif
127#elif defined(ANDROID) 127#elif defined(ANDROID)
@@ -130,7 +130,7 @@ void MemArena::GrabLowMemSpace(size_t size)
130 // Note that it appears that ashmem is pinned by default, so no need to pin. 130 // Note that it appears that ashmem is pinned by default, so no need to pin.
131 if (fd < 0) 131 if (fd < 0)
132 { 132 {
133 ERROR_LOG(MEMMAP, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno)); 133 LOG_ERROR(Common_Memory, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno));
134 return; 134 return;
135 } 135 }
136#else 136#else
@@ -148,12 +148,12 @@ void MemArena::GrabLowMemSpace(size_t size)
148 } 148 }
149 else if (errno != EEXIST) 149 else if (errno != EEXIST)
150 { 150 {
151 ERROR_LOG(MEMMAP, "shm_open failed: %s", strerror(errno)); 151 LOG_ERROR(Common_Memory, "shm_open failed: %s", strerror(errno));
152 return; 152 return;
153 } 153 }
154 } 154 }
155 if (ftruncate(fd, size) < 0) 155 if (ftruncate(fd, size) < 0)
156 ERROR_LOG(MEMMAP, "Failed to allocate low memory space"); 156 LOG_ERROR(Common_Memory, "Failed to allocate low memory space");
157#endif 157#endif
158} 158}
159 159
@@ -178,7 +178,7 @@ void *MemArena::CreateView(s64 offset, size_t size, void *base)
178#ifdef _XBOX 178#ifdef _XBOX
179 size = roundup(size); 179 size = roundup(size);
180 // use 64kb pages 180 // use 64kb pages
181 void * ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); 181 void * ptr = VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
182 return ptr; 182 return ptr;
183#else 183#else
184 size = roundup(size); 184 size = roundup(size);
@@ -197,7 +197,7 @@ void *MemArena::CreateView(s64 offset, size_t size, void *base)
197 197
198 if (retval == MAP_FAILED) 198 if (retval == MAP_FAILED)
199 { 199 {
200 NOTICE_LOG(MEMMAP, "mmap failed"); 200 LOG_ERROR(Common_Memory, "mmap failed");
201 return nullptr; 201 return nullptr;
202 } 202 }
203 return retval; 203 return retval;
@@ -243,8 +243,8 @@ u8* MemArena::Find4GBBase()
243 return base; 243 return base;
244#else 244#else
245#ifdef IOS 245#ifdef IOS
246 void* base = NULL; 246 void* base = nullptr;
247 if (globalbase == NULL){ 247 if (globalbase == nullptr){
248 base = mmap(0, 0x08000000, PROT_READ | PROT_WRITE, 248 base = mmap(0, 0x08000000, PROT_READ | PROT_WRITE,
249 MAP_ANON | MAP_SHARED, -1, 0); 249 MAP_ANON | MAP_SHARED, -1, 0);
250 if (base == MAP_FAILED) { 250 if (base == MAP_FAILED) {
@@ -357,7 +357,7 @@ bail:
357 if (views[j].out_ptr_low && *views[j].out_ptr_low) 357 if (views[j].out_ptr_low && *views[j].out_ptr_low)
358 { 358 {
359 arena->ReleaseView(*views[j].out_ptr_low, views[j].size); 359 arena->ReleaseView(*views[j].out_ptr_low, views[j].size);
360 *views[j].out_ptr_low = NULL; 360 *views[j].out_ptr_low = nullptr;
361 } 361 }
362 if (*views[j].out_ptr) 362 if (*views[j].out_ptr)
363 { 363 {
@@ -369,7 +369,7 @@ bail:
369 arena->ReleaseView(*views[j].out_ptr, views[j].size); 369 arena->ReleaseView(*views[j].out_ptr, views[j].size);
370 } 370 }
371#endif 371#endif
372 *views[j].out_ptr = NULL; 372 *views[j].out_ptr = nullptr;
373 } 373 }
374 } 374 }
375 return false; 375 return false;
@@ -415,7 +415,7 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena
415#elif defined(_WIN32) 415#elif defined(_WIN32)
416 // Try a whole range of possible bases. Return once we got a valid one. 416 // Try a whole range of possible bases. Return once we got a valid one.
417 u32 max_base_addr = 0x7FFF0000 - 0x10000000; 417 u32 max_base_addr = 0x7FFF0000 - 0x10000000;
418 u8 *base = NULL; 418 u8 *base = nullptr;
419 419
420 for (u32 base_addr = 0x01000000; base_addr < max_base_addr; base_addr += 0x400000) 420 for (u32 base_addr = 0x01000000; base_addr < max_base_addr; base_addr += 0x400000)
421 { 421 {
@@ -423,7 +423,7 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena
423 base = (u8 *)base_addr; 423 base = (u8 *)base_addr;
424 if (Memory_TryBase(base, views, num_views, flags, arena)) 424 if (Memory_TryBase(base, views, num_views, flags, arena))
425 { 425 {
426 INFO_LOG(MEMMAP, "Found valid memory base at %p after %i tries.", base, base_attempts); 426 LOG_DEBUG(Common_Memory, "Found valid memory base at %p after %i tries.", base, base_attempts);
427 base_attempts = 0; 427 base_attempts = 0;
428 break; 428 break;
429 } 429 }
@@ -442,7 +442,7 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena
442 u8 *base = MemArena::Find4GBBase(); 442 u8 *base = MemArena::Find4GBBase();
443 if (!Memory_TryBase(base, views, num_views, flags, arena)) 443 if (!Memory_TryBase(base, views, num_views, flags, arena))
444 { 444 {
445 ERROR_LOG(MEMMAP, "MemoryMap_Setup: Failed finding a memory base."); 445 LOG_ERROR(Common_Memory, "MemoryMap_Setup: Failed finding a memory base.");
446 PanicAlert("MemoryMap_Setup: Failed finding a memory base."); 446 PanicAlert("MemoryMap_Setup: Failed finding a memory base.");
447 return 0; 447 return 0;
448 } 448 }
@@ -463,8 +463,8 @@ void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemAr
463 arena->ReleaseView(*views[i].out_ptr_low, views[i].size); 463 arena->ReleaseView(*views[i].out_ptr_low, views[i].size);
464 if (*views[i].out_ptr && (views[i].out_ptr_low && *views[i].out_ptr != *views[i].out_ptr_low)) 464 if (*views[i].out_ptr && (views[i].out_ptr_low && *views[i].out_ptr != *views[i].out_ptr_low))
465 arena->ReleaseView(*views[i].out_ptr, views[i].size); 465 arena->ReleaseView(*views[i].out_ptr, views[i].size);
466 *views[i].out_ptr = NULL; 466 *views[i].out_ptr = nullptr;
467 if (views[i].out_ptr_low) 467 if (views[i].out_ptr_low)
468 *views[i].out_ptr_low = NULL; 468 *views[i].out_ptr_low = nullptr;
469 } 469 }
470} 470}
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp
index b6f66e4e1..8f982da89 100644
--- a/src/common/memory_util.cpp
+++ b/src/common/memory_util.cpp
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5 5
@@ -93,7 +93,7 @@ void* AllocateMemoryPages(size_t size)
93 // printf("Mapped memory at %p (size %ld)\n", ptr, 93 // printf("Mapped memory at %p (size %ld)\n", ptr,
94 // (unsigned long)size); 94 // (unsigned long)size);
95 95
96 if (ptr == NULL) 96 if (ptr == nullptr)
97 PanicAlert("Failed to allocate raw memory"); 97 PanicAlert("Failed to allocate raw memory");
98 98
99 return ptr; 99 return ptr;
@@ -104,19 +104,19 @@ void* AllocateAlignedMemory(size_t size,size_t alignment)
104#ifdef _WIN32 104#ifdef _WIN32
105 void* ptr = _aligned_malloc(size,alignment); 105 void* ptr = _aligned_malloc(size,alignment);
106#else 106#else
107 void* ptr = NULL; 107 void* ptr = nullptr;
108#ifdef ANDROID 108#ifdef ANDROID
109 ptr = memalign(alignment, size); 109 ptr = memalign(alignment, size);
110#else 110#else
111 if (posix_memalign(&ptr, alignment, size) != 0) 111 if (posix_memalign(&ptr, alignment, size) != 0)
112 ERROR_LOG(MEMMAP, "Failed to allocate aligned memory"); 112 LOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
113#endif 113#endif
114#endif 114#endif
115 115
116 // printf("Mapped memory at %p (size %ld)\n", ptr, 116 // printf("Mapped memory at %p (size %ld)\n", ptr,
117 // (unsigned long)size); 117 // (unsigned long)size);
118 118
119 if (ptr == NULL) 119 if (ptr == nullptr)
120 PanicAlert("Failed to allocate aligned memory"); 120 PanicAlert("Failed to allocate aligned memory");
121 121
122 return ptr; 122 return ptr;
@@ -130,7 +130,7 @@ void FreeMemoryPages(void* ptr, size_t size)
130 130
131 if (!VirtualFree(ptr, 0, MEM_RELEASE)) 131 if (!VirtualFree(ptr, 0, MEM_RELEASE))
132 PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg()); 132 PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg());
133 ptr = NULL; // Is this our responsibility? 133 ptr = nullptr; // Is this our responsibility?
134 134
135#else 135#else
136 munmap(ptr, size); 136 munmap(ptr, size);
@@ -184,7 +184,7 @@ std::string MemUsage()
184 // Print information about the memory usage of the process. 184 // Print information about the memory usage of the process.
185 185
186 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID); 186 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
187 if (NULL == hProcess) return "MemUsage Error"; 187 if (nullptr == hProcess) return "MemUsage Error";
188 188
189 if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) 189 if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
190 Ret = Common::StringFromFormat("%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str()); 190 Ret = Common::StringFromFormat("%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
diff --git a/src/common/memory_util.h b/src/common/memory_util.h
index 922bd44b2..9fdbf1f12 100644
--- a/src/common/memory_util.h
+++ b/src/common/memory_util.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/common/misc.cpp b/src/common/misc.cpp
index cf6df44e8..e33055d10 100644
--- a/src/common/misc.cpp
+++ b/src/common/misc.cpp
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common.h" 5#include "common/common.h"
@@ -23,9 +23,9 @@ const char* GetLastErrorMsg()
23#ifdef _WIN32 23#ifdef _WIN32
24 static __declspec(thread) char err_str[buff_size] = {}; 24 static __declspec(thread) char err_str[buff_size] = {};
25 25
26 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 26 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(),
27 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 27 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
28 err_str, buff_size, NULL); 28 err_str, buff_size, nullptr);
29#else 29#else
30 static __thread char err_str[buff_size] = {}; 30 static __thread char err_str[buff_size] = {};
31 31
diff --git a/src/common/msg_handler.cpp b/src/common/msg_handler.cpp
index b3556aaa8..4a47b518e 100644
--- a/src/common/msg_handler.cpp
+++ b/src/common/msg_handler.cpp
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstdio> 5#include <cstdio>
@@ -75,7 +75,7 @@ bool MsgAlert(bool yes_no, int Style, const char* format, ...)
75 Common::CharArrayFromFormatV(buffer, sizeof(buffer)-1, str_translator(format).c_str(), args); 75 Common::CharArrayFromFormatV(buffer, sizeof(buffer)-1, str_translator(format).c_str(), args);
76 va_end(args); 76 va_end(args);
77 77
78 ERROR_LOG(MASTER_LOG, "%s: %s", caption.c_str(), buffer); 78 LOG_INFO(Common, "%s: %s", caption.c_str(), buffer);
79 79
80 // Don't ignore questions, especially AskYesNo, PanicYesNo could be ignored 80 // Don't ignore questions, especially AskYesNo, PanicYesNo could be ignored
81 if (msg_handler && (AlertEnabled || Style == QUESTION || Style == CRITICAL)) 81 if (msg_handler && (AlertEnabled || Style == QUESTION || Style == CRITICAL))
diff --git a/src/common/msg_handler.h b/src/common/msg_handler.h
index a1db89aa3..b4f380782 100644
--- a/src/common/msg_handler.h
+++ b/src/common/msg_handler.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/common/platform.h b/src/common/platform.h
index 7d123caa0..ce5550520 100644
--- a/src/common/platform.h
+++ b/src/common/platform.h
@@ -80,7 +80,7 @@
80inline struct tm* localtime_r(const time_t *clock, struct tm *result) { 80inline struct tm* localtime_r(const time_t *clock, struct tm *result) {
81 if (localtime_s(result, clock) == 0) 81 if (localtime_s(result, clock) == 0)
82 return result; 82 return result;
83 return NULL; 83 return nullptr;
84} 84}
85#endif 85#endif
86 86
diff --git a/src/common/scm_rev.h b/src/common/scm_rev.h
index d34664614..0ef190afa 100644
--- a/src/common/scm_rev.h
+++ b/src/common/scm_rev.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h
new file mode 100644
index 000000000..263beaf0e
--- /dev/null
+++ b/src/common/scope_exit.h
@@ -0,0 +1,37 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7namespace detail {
8 template <typename Func>
9 struct ScopeExitHelper {
10 explicit ScopeExitHelper(Func&& func) : func(std::move(func)) {}
11 ~ScopeExitHelper() { func(); }
12
13 Func func;
14 };
15
16 template <typename Func>
17 ScopeExitHelper<Func> ScopeExit(Func&& func) { return ScopeExitHelper<Func>(std::move(func)); }
18}
19
20/**
21 * This macro allows you to conveniently specify a block of code that will run on scope exit. Handy
22 * for doing ad-hoc clean-up tasks in a function with multiple returns.
23 *
24 * Example usage:
25 * \code
26 * const int saved_val = g_foo;
27 * g_foo = 55;
28 * SCOPE_EXIT({ g_foo = saved_val; });
29 *
30 * if (Bar()) {
31 * return 0;
32 * } else {
33 * return 20;
34 * }
35 * \endcode
36 */
37#define SCOPE_EXIT(body) auto scope_exit_helper_##__LINE__ = detail::ScopeExit([&]() body)
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 1ca2dfb39..0dd2d2349 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -1,8 +1,8 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <boost/range/algorithm.hpp>
6 6
7#include "common/common.h" 7#include "common/common.h"
8#include "common/string_util.h" 8#include "common/string_util.h"
@@ -18,20 +18,20 @@ namespace Common {
18 18
19/// Make a string lowercase 19/// Make a string lowercase
20std::string ToLower(std::string str) { 20std::string ToLower(std::string str) {
21 std::transform(str.begin(), str.end(), str.begin(), ::tolower); 21 boost::transform(str, str.begin(), ::tolower);
22 return str; 22 return str;
23} 23}
24 24
25/// Make a string uppercase 25/// Make a string uppercase
26std::string ToUpper(std::string str) { 26std::string ToUpper(std::string str) {
27 std::transform(str.begin(), str.end(), str.begin(), ::toupper); 27 boost::transform(str, str.begin(), ::toupper);
28 return str; 28 return str;
29} 29}
30 30
31// faster than sscanf 31// faster than sscanf
32bool AsciiToHex(const char* _szValue, u32& result) 32bool AsciiToHex(const char* _szValue, u32& result)
33{ 33{
34 char *endptr = NULL; 34 char *endptr = nullptr;
35 const u32 value = strtoul(_szValue, &endptr, 16); 35 const u32 value = strtoul(_szValue, &endptr, 16);
36 36
37 if (!endptr || *endptr) 37 if (!endptr || *endptr)
@@ -69,7 +69,7 @@ bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list ar
69 // will be present in the middle of a multibyte sequence. 69 // will be present in the middle of a multibyte sequence.
70 // 70 //
71 // This is why we lookup an ANSI (cp1252) locale here and use _vsnprintf_l. 71 // This is why we lookup an ANSI (cp1252) locale here and use _vsnprintf_l.
72 static locale_t c_locale = NULL; 72 static locale_t c_locale = nullptr;
73 if (!c_locale) 73 if (!c_locale)
74 c_locale = _create_locale(LC_ALL, ".1252"); 74 c_locale = _create_locale(LC_ALL, ".1252");
75 writtenCount = _vsnprintf_l(out, outsize, format, c_locale, args); 75 writtenCount = _vsnprintf_l(out, outsize, format, c_locale, args);
@@ -92,7 +92,7 @@ bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list ar
92std::string StringFromFormat(const char* format, ...) 92std::string StringFromFormat(const char* format, ...)
93{ 93{
94 va_list args; 94 va_list args;
95 char *buf = NULL; 95 char *buf = nullptr;
96#ifdef _WIN32 96#ifdef _WIN32
97 int required = 0; 97 int required = 0;
98 98
@@ -107,7 +107,7 @@ std::string StringFromFormat(const char* format, ...)
107#else 107#else
108 va_start(args, format); 108 va_start(args, format);
109 if (vasprintf(&buf, format, args) < 0) 109 if (vasprintf(&buf, format, args) < 0)
110 ERROR_LOG(COMMON, "Unable to allocate memory for string"); 110 LOG_ERROR(Common, "Unable to allocate memory for string");
111 va_end(args); 111 va_end(args);
112 112
113 std::string temp = buf; 113 std::string temp = buf;
@@ -162,7 +162,7 @@ std::string StripQuotes(const std::string& s)
162 162
163bool TryParse(const std::string &str, u32 *const output) 163bool TryParse(const std::string &str, u32 *const output)
164{ 164{
165 char *endptr = NULL; 165 char *endptr = nullptr;
166 166
167 // Reset errno to a value other than ERANGE 167 // Reset errno to a value other than ERANGE
168 errno = 0; 168 errno = 0;
@@ -475,7 +475,7 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>&
475 iconv_t const conv_desc = iconv_open("UTF-8", fromcode); 475 iconv_t const conv_desc = iconv_open("UTF-8", fromcode);
476 if ((iconv_t)(-1) == conv_desc) 476 if ((iconv_t)(-1) == conv_desc)
477 { 477 {
478 ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno)); 478 LOG_ERROR(Common, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno));
479 iconv_close(conv_desc); 479 iconv_close(conv_desc);
480 return {}; 480 return {};
481 } 481 }
@@ -510,7 +510,7 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>&
510 } 510 }
511 else 511 else
512 { 512 {
513 ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno)); 513 LOG_ERROR(Common, "iconv failure [%s]: %s", fromcode, strerror(errno));
514 break; 514 break;
515 } 515 }
516 } 516 }
@@ -528,10 +528,10 @@ std::u16string UTF8ToUTF16(const std::string& input)
528{ 528{
529 std::u16string result; 529 std::u16string result;
530 530
531 iconv_t const conv_desc = iconv_open("UTF-16", "UTF-8"); 531 iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8");
532 if ((iconv_t)(-1) == conv_desc) 532 if ((iconv_t)(-1) == conv_desc)
533 { 533 {
534 ERROR_LOG(COMMON, "Iconv initialization failure [UTF-8]: %s", strerror(errno)); 534 LOG_ERROR(Common, "Iconv initialization failure [UTF-8]: %s", strerror(errno));
535 iconv_close(conv_desc); 535 iconv_close(conv_desc);
536 return {}; 536 return {};
537 } 537 }
@@ -566,7 +566,7 @@ std::u16string UTF8ToUTF16(const std::string& input)
566 } 566 }
567 else 567 else
568 { 568 {
569 ERROR_LOG(COMMON, "iconv failure [UTF-8]: %s", strerror(errno)); 569 LOG_ERROR(Common, "iconv failure [UTF-8]: %s", strerror(errno));
570 break; 570 break;
571 } 571 }
572 } 572 }
@@ -582,7 +582,7 @@ std::u16string UTF8ToUTF16(const std::string& input)
582 582
583std::string UTF16ToUTF8(const std::u16string& input) 583std::string UTF16ToUTF8(const std::u16string& input)
584{ 584{
585 return CodeToUTF8("UTF-16", input); 585 return CodeToUTF8("UTF-16LE", input);
586} 586}
587 587
588std::string CP1252ToUTF8(const std::string& input) 588std::string CP1252ToUTF8(const std::string& input)
diff --git a/src/common/string_util.h b/src/common/string_util.h
index ae5bbadad..74974263f 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -115,4 +115,19 @@ inline std::string UTF8ToTStr(const std::string& str)
115 115
116#endif 116#endif
117 117
118/**
119 * Compares the string defined by the range [`begin`, `end`) to the null-terminated C-string
120 * `other` for equality.
121 */
122template <typename InIt>
123bool ComparePartialString(InIt begin, InIt end, const char* other) {
124 for (; begin != end && *other != '\0'; ++begin, ++other) {
125 if (*begin != *other) {
126 return false;
127 }
128 }
129 // Only return true if both strings finished at the same point
130 return (begin == end) == (*other == '\0');
131}
132
118} 133}
diff --git a/src/common/symbols.cpp b/src/common/symbols.cpp
index 63ad6218b..9e4dccfb3 100644
--- a/src/common/symbols.cpp
+++ b/src/common/symbols.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/symbols.h" 5#include "common/symbols.h"
diff --git a/src/common/symbols.h b/src/common/symbols.h
index 4560f5240..f76cb6b1e 100644
--- a/src/common/symbols.h
+++ b/src/common/symbols.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 6eeda0828..04e33101b 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/thread.h" 5#include "common/thread.h"
diff --git a/src/common/thread.h b/src/common/thread.h
index be9b5cbe2..eaf1ba00c 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -21,6 +21,7 @@
21//for gettimeofday and struct time(spec|val) 21//for gettimeofday and struct time(spec|val)
22#include <time.h> 22#include <time.h>
23#include <sys/time.h> 23#include <sys/time.h>
24#include <unistd.h>
24#endif 25#endif
25 26
26namespace Common 27namespace Common
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
index 59efbce4c..4e1c0a215 100644
--- a/src/common/thread_queue_list.h
+++ b/src/common/thread_queue_list.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project / PPSSPP Project 1// Copyright 2014 Citra Emulator Project / PPSSPP Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -37,7 +37,7 @@ struct ThreadQueueList {
37 ~ThreadQueueList() { 37 ~ThreadQueueList() {
38 for (int i = 0; i < NUM_QUEUES; ++i) 38 for (int i = 0; i < NUM_QUEUES; ++i)
39 { 39 {
40 if (queues[i].data != NULL) 40 if (queues[i].data != nullptr)
41 free(queues[i].data); 41 free(queues[i].data);
42 } 42 }
43 } 43 }
@@ -46,7 +46,7 @@ struct ThreadQueueList {
46 int contains(const IdType uid) { 46 int contains(const IdType uid) {
47 for (int i = 0; i < NUM_QUEUES; ++i) 47 for (int i = 0; i < NUM_QUEUES; ++i)
48 { 48 {
49 if (queues[i].data == NULL) 49 if (queues[i].data == nullptr)
50 continue; 50 continue;
51 51
52 Queue *cur = &queues[i]; 52 Queue *cur = &queues[i];
@@ -133,7 +133,7 @@ struct ThreadQueueList {
133 inline void clear() { 133 inline void clear() {
134 for (int i = 0; i < NUM_QUEUES; ++i) 134 for (int i = 0; i < NUM_QUEUES; ++i)
135 { 135 {
136 if (queues[i].data != NULL) 136 if (queues[i].data != nullptr)
137 free(queues[i].data); 137 free(queues[i].data);
138 } 138 }
139 memset(queues, 0, sizeof(queues)); 139 memset(queues, 0, sizeof(queues));
@@ -147,7 +147,7 @@ struct ThreadQueueList {
147 147
148 inline void prepare(u32 priority) { 148 inline void prepare(u32 priority) {
149 Queue *cur = &queues[priority]; 149 Queue *cur = &queues[priority];
150 if (cur->next == NULL) 150 if (cur->next == nullptr)
151 link(priority, INITIAL_CAPACITY); 151 link(priority, INITIAL_CAPACITY);
152 } 152 }
153 153
@@ -176,7 +176,7 @@ private:
176 176
177 for (int i = (int) priority - 1; i >= 0; --i) 177 for (int i = (int) priority - 1; i >= 0; --i)
178 { 178 {
179 if (queues[i].next != NULL) 179 if (queues[i].next != nullptr)
180 { 180 {
181 cur->next = queues[i].next; 181 cur->next = queues[i].next;
182 queues[i].next = cur; 182 queues[i].next = cur;
@@ -193,7 +193,7 @@ private:
193 int size = cur->end - cur->first; 193 int size = cur->end - cur->first;
194 if (size >= cur->capacity - 2) { 194 if (size >= cur->capacity - 2) {
195 IdType *new_data = (IdType *)realloc(cur->data, cur->capacity * 2 * sizeof(IdType)); 195 IdType *new_data = (IdType *)realloc(cur->data, cur->capacity * 2 * sizeof(IdType));
196 if (new_data != NULL) { 196 if (new_data != nullptr) {
197 cur->capacity *= 2; 197 cur->capacity *= 2;
198 cur->data = new_data; 198 cur->data = new_data;
199 } 199 }
diff --git a/src/common/thunk.h b/src/common/thunk.h
index 90c8be888..4fb7c98e1 100644
--- a/src/common/thunk.h
+++ b/src/common/thunk.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/common/timer.cpp b/src/common/timer.cpp
index ded4a344e..a6682ea19 100644
--- a/src/common/timer.cpp
+++ b/src/common/timer.cpp
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <time.h> 5#include <time.h>
@@ -25,7 +25,7 @@ u32 Timer::GetTimeMs()
25 return timeGetTime(); 25 return timeGetTime();
26#else 26#else
27 struct timeval t; 27 struct timeval t;
28 (void)gettimeofday(&t, NULL); 28 (void)gettimeofday(&t, nullptr);
29 return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000)); 29 return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000));
30#endif 30#endif
31} 31}
@@ -183,7 +183,7 @@ std::string Timer::GetTimeFormatted()
183 return StringFromFormat("%s:%03i", tmp, tp.millitm); 183 return StringFromFormat("%s:%03i", tmp, tp.millitm);
184#else 184#else
185 struct timeval t; 185 struct timeval t;
186 (void)gettimeofday(&t, NULL); 186 (void)gettimeofday(&t, nullptr);
187 return StringFromFormat("%s:%03d", tmp, (int)(t.tv_usec / 1000)); 187 return StringFromFormat("%s:%03d", tmp, (int)(t.tv_usec / 1000));
188#endif 188#endif
189} 189}
@@ -197,7 +197,7 @@ double Timer::GetDoubleTime()
197 (void)::ftime(&tp); 197 (void)::ftime(&tp);
198#else 198#else
199 struct timeval t; 199 struct timeval t;
200 (void)gettimeofday(&t, NULL); 200 (void)gettimeofday(&t, nullptr);
201#endif 201#endif
202 // Get continuous timestamp 202 // Get continuous timestamp
203 u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970(); 203 u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970();
diff --git a/src/common/timer.h b/src/common/timer.h
index 86418e7a7..4b44c33a0 100644
--- a/src/common/timer.h
+++ b/src/common/timer.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/common/utf8.cpp b/src/common/utf8.cpp
index be4ebc855..66a2f6339 100644
--- a/src/common/utf8.cpp
+++ b/src/common/utf8.cpp
@@ -281,28 +281,28 @@ int u8_read_escape_sequence(const char *str, u32 *dest)
281 do { 281 do {
282 digs[dno++] = str[i++]; 282 digs[dno++] = str[i++];
283 } while (octal_digit(str[i]) && dno < 3); 283 } while (octal_digit(str[i]) && dno < 3);
284 ch = strtol(digs, NULL, 8); 284 ch = strtol(digs, nullptr, 8);
285 } 285 }
286 else if (str[0] == 'x') { 286 else if (str[0] == 'x') {
287 while (hex_digit(str[i]) && dno < 2) { 287 while (hex_digit(str[i]) && dno < 2) {
288 digs[dno++] = str[i++]; 288 digs[dno++] = str[i++];
289 } 289 }
290 if (dno > 0) 290 if (dno > 0)
291 ch = strtol(digs, NULL, 16); 291 ch = strtol(digs, nullptr, 16);
292 } 292 }
293 else if (str[0] == 'u') { 293 else if (str[0] == 'u') {
294 while (hex_digit(str[i]) && dno < 4) { 294 while (hex_digit(str[i]) && dno < 4) {
295 digs[dno++] = str[i++]; 295 digs[dno++] = str[i++];
296 } 296 }
297 if (dno > 0) 297 if (dno > 0)
298 ch = strtol(digs, NULL, 16); 298 ch = strtol(digs, nullptr, 16);
299 } 299 }
300 else if (str[0] == 'U') { 300 else if (str[0] == 'U') {
301 while (hex_digit(str[i]) && dno < 8) { 301 while (hex_digit(str[i]) && dno < 8) {
302 digs[dno++] = str[i++]; 302 digs[dno++] = str[i++];
303 } 303 }
304 if (dno > 0) 304 if (dno > 0)
305 ch = strtol(digs, NULL, 16); 305 ch = strtol(digs, nullptr, 16);
306 } 306 }
307 *dest = ch; 307 *dest = ch;
308 308
@@ -353,7 +353,7 @@ const char *u8_strchr(const char *s, u32 ch, int *charn)
353 lasti = i; 353 lasti = i;
354 (*charn)++; 354 (*charn)++;
355 } 355 }
356 return NULL; 356 return nullptr;
357} 357}
358 358
359const char *u8_memchr(const char *s, u32 ch, size_t sz, int *charn) 359const char *u8_memchr(const char *s, u32 ch, size_t sz, int *charn)
@@ -378,7 +378,7 @@ const char *u8_memchr(const char *s, u32 ch, size_t sz, int *charn)
378 lasti = i; 378 lasti = i;
379 (*charn)++; 379 (*charn)++;
380 } 380 }
381 return NULL; 381 return nullptr;
382} 382}
383 383
384int u8_is_locale_utf8(const char *locale) 384int u8_is_locale_utf8(const char *locale)
@@ -419,35 +419,35 @@ bool UTF8StringHasNonASCII(const char *utf8string) {
419 419
420std::string ConvertWStringToUTF8(const wchar_t *wstr) { 420std::string ConvertWStringToUTF8(const wchar_t *wstr) {
421 int len = (int)wcslen(wstr); 421 int len = (int)wcslen(wstr);
422 int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr, len, 0, 0, NULL, NULL); 422 int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr, len, 0, 0, nullptr, nullptr);
423 std::string s; 423 std::string s;
424 s.resize(size); 424 s.resize(size);
425 if (size > 0) { 425 if (size > 0) {
426 WideCharToMultiByte(CP_UTF8, 0, wstr, len, &s[0], size, NULL, NULL); 426 WideCharToMultiByte(CP_UTF8, 0, wstr, len, &s[0], size, nullptr, nullptr);
427 } 427 }
428 return s; 428 return s;
429} 429}
430 430
431std::string ConvertWStringToUTF8(const std::wstring &wstr) { 431std::string ConvertWStringToUTF8(const std::wstring &wstr) {
432 int len = (int)wstr.size(); 432 int len = (int)wstr.size();
433 int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, 0, 0, NULL, NULL); 433 int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, 0, 0, nullptr, nullptr);
434 std::string s; 434 std::string s;
435 s.resize(size); 435 s.resize(size);
436 if (size > 0) { 436 if (size > 0) {
437 WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, &s[0], size, NULL, NULL); 437 WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, &s[0], size, nullptr, nullptr);
438 } 438 }
439 return s; 439 return s;
440} 440}
441 441
442void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const std::string &source) { 442void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const std::string &source) {
443 int len = (int)source.size(); 443 int len = (int)source.size();
444 int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, NULL, 0); 444 int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, nullptr, 0);
445 MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, dest, std::min((int)destSize, size)); 445 MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, dest, std::min((int)destSize, size));
446} 446}
447 447
448std::wstring ConvertUTF8ToWString(const std::string &source) { 448std::wstring ConvertUTF8ToWString(const std::string &source) {
449 int len = (int)source.size(); 449 int len = (int)source.size();
450 int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, NULL, 0); 450 int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, nullptr, 0);
451 std::wstring str; 451 std::wstring str;
452 str.resize(size); 452 str.resize(size);
453 if (size > 0) { 453 if (size > 0) {
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 48241c3d4..fdd97c184 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -18,35 +18,46 @@ set(SRCS
18 arm/skyeye_common/vfp/vfpinstr.cpp 18 arm/skyeye_common/vfp/vfpinstr.cpp
19 arm/skyeye_common/vfp/vfpsingle.cpp 19 arm/skyeye_common/vfp/vfpsingle.cpp
20 file_sys/archive_romfs.cpp 20 file_sys/archive_romfs.cpp
21 file_sys/archive_savedata.cpp
21 file_sys/archive_sdmc.cpp 22 file_sys/archive_sdmc.cpp
23 file_sys/archive_systemsavedata.cpp
24 file_sys/disk_archive.cpp
22 file_sys/file_romfs.cpp 25 file_sys/file_romfs.cpp
23 file_sys/file_sdmc.cpp
24 file_sys/directory_romfs.cpp 26 file_sys/directory_romfs.cpp
25 file_sys/directory_sdmc.cpp
26 hle/kernel/address_arbiter.cpp 27 hle/kernel/address_arbiter.cpp
27 hle/kernel/archive.cpp
28 hle/kernel/event.cpp 28 hle/kernel/event.cpp
29 hle/kernel/kernel.cpp 29 hle/kernel/kernel.cpp
30 hle/kernel/mutex.cpp 30 hle/kernel/mutex.cpp
31 hle/kernel/semaphore.cpp
31 hle/kernel/shared_memory.cpp 32 hle/kernel/shared_memory.cpp
32 hle/kernel/thread.cpp 33 hle/kernel/thread.cpp
33 hle/service/ac_u.cpp 34 hle/service/ac_u.cpp
35 hle/service/act_u.cpp
36 hle/service/am_app.cpp
34 hle/service/am_net.cpp 37 hle/service/am_net.cpp
38 hle/service/apt_a.cpp
35 hle/service/apt_u.cpp 39 hle/service/apt_u.cpp
36 hle/service/boss_u.cpp 40 hle/service/boss_u.cpp
37 hle/service/cfg_i.cpp 41 hle/service/cecd_u.cpp
38 hle/service/cfg_u.cpp 42 hle/service/cfg/cfg.cpp
43 hle/service/cfg/cfg_i.cpp
44 hle/service/cfg/cfg_u.cpp
39 hle/service/csnd_snd.cpp 45 hle/service/csnd_snd.cpp
40 hle/service/dsp_dsp.cpp 46 hle/service/dsp_dsp.cpp
41 hle/service/err_f.cpp 47 hle/service/err_f.cpp
42 hle/service/fs_user.cpp
43 hle/service/frd_u.cpp 48 hle/service/frd_u.cpp
49 hle/service/fs/archive.cpp
50 hle/service/fs/fs_user.cpp
44 hle/service/gsp_gpu.cpp 51 hle/service/gsp_gpu.cpp
45 hle/service/hid_user.cpp 52 hle/service/hid_user.cpp
53 hle/service/http_c.cpp
46 hle/service/ir_rst.cpp 54 hle/service/ir_rst.cpp
47 hle/service/ir_u.cpp 55 hle/service/ir_u.cpp
56 hle/service/ldr_ro.cpp
48 hle/service/mic_u.cpp 57 hle/service/mic_u.cpp
49 hle/service/ndm_u.cpp 58 hle/service/ndm_u.cpp
59 hle/service/news_u.cpp
60 hle/service/nim_aoc.cpp
50 hle/service/nwm_uds.cpp 61 hle/service/nwm_uds.cpp
51 hle/service/pm_app.cpp 62 hle/service/pm_app.cpp
52 hle/service/ptm_u.cpp 63 hle/service/ptm_u.cpp
@@ -59,10 +70,10 @@ set(SRCS
59 hle/svc.cpp 70 hle/svc.cpp
60 hw/gpu.cpp 71 hw/gpu.cpp
61 hw/hw.cpp 72 hw/hw.cpp
62 hw/ndma.cpp
63 loader/elf.cpp 73 loader/elf.cpp
64 loader/loader.cpp 74 loader/loader.cpp
65 loader/ncch.cpp 75 loader/ncch.cpp
76 loader/3dsx.cpp
66 core.cpp 77 core.cpp
67 core_timing.cpp 78 core_timing.cpp
68 mem_map.cpp 79 mem_map.cpp
@@ -92,39 +103,51 @@ set(HEADERS
92 arm/skyeye_common/vfp/vfp.h 103 arm/skyeye_common/vfp/vfp.h
93 arm/skyeye_common/vfp/vfp_helper.h 104 arm/skyeye_common/vfp/vfp_helper.h
94 arm/arm_interface.h 105 arm/arm_interface.h
95 file_sys/archive.h 106 file_sys/archive_backend.h
96 file_sys/archive_romfs.h 107 file_sys/archive_romfs.h
108 file_sys/archive_savedata.h
97 file_sys/archive_sdmc.h 109 file_sys/archive_sdmc.h
98 file_sys/file.h 110 file_sys/archive_systemsavedata.h
111 file_sys/disk_archive.h
112 file_sys/file_backend.h
99 file_sys/file_romfs.h 113 file_sys/file_romfs.h
100 file_sys/file_sdmc.h 114 file_sys/directory_backend.h
101 file_sys/directory.h
102 file_sys/directory_romfs.h 115 file_sys/directory_romfs.h
103 file_sys/directory_sdmc.h
104 hle/kernel/address_arbiter.h 116 hle/kernel/address_arbiter.h
105 hle/kernel/archive.h
106 hle/kernel/event.h 117 hle/kernel/event.h
107 hle/kernel/kernel.h 118 hle/kernel/kernel.h
108 hle/kernel/mutex.h 119 hle/kernel/mutex.h
120 hle/kernel/semaphore.h
121 hle/kernel/session.h
109 hle/kernel/shared_memory.h 122 hle/kernel/shared_memory.h
110 hle/kernel/thread.h 123 hle/kernel/thread.h
111 hle/service/ac_u.h 124 hle/service/ac_u.h
125 hle/service/act_u.h
126 hle/service/am_app.h
112 hle/service/am_net.h 127 hle/service/am_net.h
128 hle/service/apt_a.h
113 hle/service/apt_u.h 129 hle/service/apt_u.h
114 hle/service/boss_u.h 130 hle/service/boss_u.h
115 hle/service/cfg_i.h 131 hle/service/cecd_u.h
116 hle/service/cfg_u.h 132 hle/service/cfg/cfg.h
133 hle/service/cfg/cfg_i.h
134 hle/service/cfg/cfg_u.h
117 hle/service/csnd_snd.h 135 hle/service/csnd_snd.h
118 hle/service/dsp_dsp.h 136 hle/service/dsp_dsp.h
119 hle/service/err_f.h 137 hle/service/err_f.h
120 hle/service/fs_user.h
121 hle/service/frd_u.h 138 hle/service/frd_u.h
139 hle/service/fs/archive.h
140 hle/service/fs/fs_user.h
122 hle/service/gsp_gpu.h 141 hle/service/gsp_gpu.h
123 hle/service/hid_user.h 142 hle/service/hid_user.h
143 hle/service/http_c.h
124 hle/service/ir_rst.h 144 hle/service/ir_rst.h
125 hle/service/ir_u.h 145 hle/service/ir_u.h
146 hle/service/ldr_ro.h
126 hle/service/mic_u.h 147 hle/service/mic_u.h
127 hle/service/ndm_u.h 148 hle/service/ndm_u.h
149 hle/service/news_u.h
150 hle/service/nim_aoc.h
128 hle/service/nwm_uds.h 151 hle/service/nwm_uds.h
129 hle/service/pm_app.h 152 hle/service/pm_app.h
130 hle/service/ptm_u.h 153 hle/service/ptm_u.h
@@ -139,10 +162,10 @@ set(HEADERS
139 hle/svc.h 162 hle/svc.h
140 hw/gpu.h 163 hw/gpu.h
141 hw/hw.h 164 hw/hw.h
142 hw/ndma.h
143 loader/elf.h 165 loader/elf.h
144 loader/loader.h 166 loader/loader.h
145 loader/ncch.h 167 loader/ncch.h
168 loader/3dsx.h
146 core.h 169 core.h
147 core_timing.h 170 core_timing.h
148 mem_map.h 171 mem_map.h
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 3ae528562..3b7209418 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -78,6 +78,12 @@ public:
78 virtual u64 GetTicks() const = 0; 78 virtual u64 GetTicks() const = 0;
79 79
80 /** 80 /**
81 * Advance the CPU core by the specified number of ticks (e.g. to simulate CPU execution time)
82 * @param ticks Number of ticks to advance the CPU core
83 */
84 virtual void AddTicks(u64 ticks) = 0;
85
86 /**
81 * Saves the current CPU context 87 * Saves the current CPU context
82 * @param ctx Thread context to save 88 * @param ctx Thread context to save
83 */ 89 */
diff --git a/src/core/arm/disassembler/load_symbol_map.cpp b/src/core/arm/disassembler/load_symbol_map.cpp
index 55278474b..13d26d170 100644
--- a/src/core/arm/disassembler/load_symbol_map.cpp
+++ b/src/core/arm/disassembler/load_symbol_map.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <string> 5#include <string>
diff --git a/src/core/arm/disassembler/load_symbol_map.h b/src/core/arm/disassembler/load_symbol_map.h
index 837cca99b..d28c551c3 100644
--- a/src/core/arm/disassembler/load_symbol_map.h
+++ b/src/core/arm/disassembler/load_symbol_map.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp
index 6c8ea211e..a838fd25a 100644
--- a/src/core/arm/dyncom/arm_dyncom.cpp
+++ b/src/core/arm/dyncom/arm_dyncom.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/arm/skyeye_common/armcpu.h" 5#include "core/arm/skyeye_common/armcpu.h"
@@ -47,68 +47,38 @@ ARM_DynCom::ARM_DynCom() : ticks(0) {
47ARM_DynCom::~ARM_DynCom() { 47ARM_DynCom::~ARM_DynCom() {
48} 48}
49 49
50/**
51 * Set the Program Counter to an address
52 * @param addr Address to set PC to
53 */
54void ARM_DynCom::SetPC(u32 pc) { 50void ARM_DynCom::SetPC(u32 pc) {
55 state->pc = state->Reg[15] = pc; 51 state->pc = state->Reg[15] = pc;
56} 52}
57 53
58/*
59 * Get the current Program Counter
60 * @return Returns current PC
61 */
62u32 ARM_DynCom::GetPC() const { 54u32 ARM_DynCom::GetPC() const {
63 return state->Reg[15]; 55 return state->Reg[15];
64} 56}
65 57
66/**
67 * Get an ARM register
68 * @param index Register index (0-15)
69 * @return Returns the value in the register
70 */
71u32 ARM_DynCom::GetReg(int index) const { 58u32 ARM_DynCom::GetReg(int index) const {
72 return state->Reg[index]; 59 return state->Reg[index];
73} 60}
74 61
75/**
76 * Set an ARM register
77 * @param index Register index (0-15)
78 * @param value Value to set register to
79 */
80void ARM_DynCom::SetReg(int index, u32 value) { 62void ARM_DynCom::SetReg(int index, u32 value) {
81 state->Reg[index] = value; 63 state->Reg[index] = value;
82} 64}
83 65
84/**
85 * Get the current CPSR register
86 * @return Returns the value of the CPSR register
87 */
88u32 ARM_DynCom::GetCPSR() const { 66u32 ARM_DynCom::GetCPSR() const {
89 return state->Cpsr; 67 return state->Cpsr;
90} 68}
91 69
92/**
93 * Set the current CPSR register
94 * @param cpsr Value to set CPSR to
95 */
96void ARM_DynCom::SetCPSR(u32 cpsr) { 70void ARM_DynCom::SetCPSR(u32 cpsr) {
97 state->Cpsr = cpsr; 71 state->Cpsr = cpsr;
98} 72}
99 73
100/**
101 * Returns the number of clock ticks since the last reset
102 * @return Returns number of clock ticks
103 */
104u64 ARM_DynCom::GetTicks() const { 74u64 ARM_DynCom::GetTicks() const {
105 return ticks; 75 return ticks;
106} 76}
107 77
108/** 78void ARM_DynCom::AddTicks(u64 ticks) {
109 * Executes the given number of instructions 79 this->ticks += ticks;
110 * @param num_instructions Number of instructions to executes 80}
111 */ 81
112void ARM_DynCom::ExecuteInstructions(int num_instructions) { 82void ARM_DynCom::ExecuteInstructions(int num_instructions) {
113 state->NumInstrsToExecute = num_instructions; 83 state->NumInstrsToExecute = num_instructions;
114 84
@@ -118,11 +88,6 @@ void ARM_DynCom::ExecuteInstructions(int num_instructions) {
118 ticks += InterpreterMainLoop(state.get()); 88 ticks += InterpreterMainLoop(state.get());
119} 89}
120 90
121/**
122 * Saves the current CPU context
123 * @param ctx Thread context to save
124 * @todo Do we need to save Reg[15] and NextInstr?
125 */
126void ARM_DynCom::SaveContext(ThreadContext& ctx) { 91void ARM_DynCom::SaveContext(ThreadContext& ctx) {
127 memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers)); 92 memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers));
128 memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers)); 93 memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers));
@@ -139,11 +104,6 @@ void ARM_DynCom::SaveContext(ThreadContext& ctx) {
139 ctx.mode = state->NextInstr; 104 ctx.mode = state->NextInstr;
140} 105}
141 106
142/**
143 * Loads a CPU context
144 * @param ctx Thread context to load
145 * @param Do we need to load Reg[15] and NextInstr?
146 */
147void ARM_DynCom::LoadContext(const ThreadContext& ctx) { 107void ARM_DynCom::LoadContext(const ThreadContext& ctx) {
148 memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers)); 108 memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers));
149 memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers)); 109 memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers));
@@ -160,7 +120,6 @@ void ARM_DynCom::LoadContext(const ThreadContext& ctx) {
160 state->NextInstr = ctx.mode; 120 state->NextInstr = ctx.mode;
161} 121}
162 122
163/// Prepare core for thread reschedule (if needed to correctly handle state)
164void ARM_DynCom::PrepareReschedule() { 123void ARM_DynCom::PrepareReschedule() {
165 state->NumInstrsToExecute = 0; 124 state->NumInstrsToExecute = 0;
166} 125}
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index 51eea41ed..7284dcd07 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -27,14 +27,14 @@ public:
27 * Get the current Program Counter 27 * Get the current Program Counter
28 * @return Returns current PC 28 * @return Returns current PC
29 */ 29 */
30 u32 GetPC() const; 30 u32 GetPC() const override;
31 31
32 /** 32 /**
33 * Get an ARM register 33 * Get an ARM register
34 * @param index Register index (0-15) 34 * @param index Register index (0-15)
35 * @return Returns the value in the register 35 * @return Returns the value in the register
36 */ 36 */
37 u32 GetReg(int index) const; 37 u32 GetReg(int index) const override;
38 38
39 /** 39 /**
40 * Set an ARM register 40 * Set an ARM register
@@ -47,7 +47,7 @@ public:
47 * Get the current CPSR register 47 * Get the current CPSR register
48 * @return Returns the value of the CPSR register 48 * @return Returns the value of the CPSR register
49 */ 49 */
50 u32 GetCPSR() const; 50 u32 GetCPSR() const override;
51 51
52 /** 52 /**
53 * Set the current CPSR register 53 * Set the current CPSR register
@@ -59,7 +59,13 @@ public:
59 * Returns the number of clock ticks since the last reset 59 * Returns the number of clock ticks since the last reset
60 * @return Returns number of clock ticks 60 * @return Returns number of clock ticks
61 */ 61 */
62 u64 GetTicks() const; 62 u64 GetTicks() const override;
63
64 /**
65 * Advance the CPU core by the specified number of ticks (e.g. to simulate CPU execution time)
66 * @param ticks Number of ticks to advance the CPU core
67 */
68 void AddTicks(u64 ticks) override;
63 69
64 /** 70 /**
65 * Saves the current CPU context 71 * Saves the current CPU context
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.cpp b/src/core/arm/dyncom/arm_dyncom_dec.cpp
index 5d174a08f..333b40f54 100644
--- a/src/core/arm/dyncom/arm_dyncom_dec.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_dec.cpp
@@ -1,402 +1,443 @@
1/* Copyright (C) 1// Copyright 2012 Michael Kang, 2014 Citra Emulator Project
2* 2012 - Michael.Kang blackfin.kang@gmail.com 2// Licensed under GPLv2 or any later version
3* This program is free software; you can redistribute it and/or 3// Refer to the license.txt file included.
4* modify it under the terms of the GNU General Public License
5* as published by the Free Software Foundation; either version 2
6* of the License, or (at your option) any later version.
7*
8* This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program; if not, write to the Free Software
15* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16*
17*/
18/**
19* @file arm_dyncom_dec.cpp
20* @brief Some common utility for arm decoder
21* @author Michael.Kang blackfin.kang@gmail.com
22* @version 7849
23* @date 2012-03-15
24*/
25 4
26#include "core/arm/skyeye_common/arm_regformat.h" 5#include "core/arm/skyeye_common/arm_regformat.h"
27#include "core/arm/skyeye_common/armdefs.h" 6#include "core/arm/skyeye_common/armdefs.h"
28#include "core/arm/dyncom/arm_dyncom_dec.h" 7#include "core/arm/dyncom/arm_dyncom_dec.h"
29 8
30const ISEITEM arm_instruction[] = { 9const ISEITEM arm_instruction[] = {
31 #define VFP_DECODE 10 { "vmla", 4, ARMVFP2, 23, 27, 0x1C, 20, 21, 0x0, 9, 11, 0x5, 4, 4, 0 },
32 #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 11 { "vmls", 7, ARMVFP2, 28, 31, 0xF, 25, 27, 0x1, 23, 23, 1, 11, 11, 0, 8, 9, 0x2, 6, 6, 1, 4, 4, 0 },
33 #undef VFP_DECODE 12 { "vnmla", 4, ARMVFP2, 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 4, 4, 0 },
34 {"srs" , 4 , 6 , 25, 31, 0x0000007c, 22, 22, 0x00000001, 16, 20, 0x0000000d, 8, 11, 0x00000005}, 13 { "vnmla", 5, ARMVFP2, 23, 27, 0x1C, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 },
35 {"rfe" , 4 , 6 , 25, 31, 0x0000007c, 22, 22, 0x00000000, 20, 20, 0x00000001, 8, 11, 0x0000000a}, 14 { "vnmls", 5, ARMVFP2, 23, 27, 0x1C, 20, 21, 0x1, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 },
36 {"bkpt" , 2 , 3 , 20, 31, 0x00000e12, 4, 7, 0x00000007}, 15 { "vnmul", 5, ARMVFP2, 23, 27, 0x1C, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 },
37 {"blx" , 1 , 3 , 25, 31, 0x0000007d}, 16 { "vmul", 5, ARMVFP2, 23, 27, 0x1C, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 },
38 {"cps" , 3 , 6 , 20, 31, 0x00000f10, 16, 16, 0x00000000, 5, 5, 0x00000000}, 17 { "vadd", 5, ARMVFP2, 23, 27, 0x1C, 20, 21, 0x3, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 },
39 {"pld" , 4 , 4 , 26, 31, 0x0000003d, 24, 24, 0x00000001, 20, 22, 0x00000005, 12, 15, 0x0000000f}, 18 { "vsub", 5, ARMVFP2, 23, 27, 0x1C, 20, 21, 0x3, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 },
40 {"setend" , 2 , 6 , 16, 31, 0x0000f101, 4, 7, 0x00000000}, 19 { "vdiv", 5, ARMVFP2, 23, 27, 0x1D, 20, 21, 0x0, 9, 11, 0x5, 6, 6, 0, 4, 4, 0 },
41 {"clrex" , 1 , 6 , 0, 31, 0xf57ff01f}, 20 { "vmov(i)", 4, ARMVFP3, 23, 27, 0x1D, 20, 21, 0x3, 9, 11, 0x5, 4, 7, 0 },
42 {"rev16" , 2 , 6 , 16, 27, 0x000006bf, 4, 11, 0x000000fb}, 21 { "vmov(r)", 5, ARMVFP3, 23, 27, 0x1D, 16, 21, 0x30, 9, 11, 0x5, 6, 7, 1, 4, 4, 0 },
43 {"usad8" , 3 , 6 , 20, 27, 0x00000078, 12, 15, 0x0000000f, 4, 7, 0x00000001}, 22 { "vabs", 5, ARMVFP2, 23, 27, 0x1D, 16, 21, 0x30, 9, 11, 0x5, 6, 7, 3, 4, 4, 0 },
44 {"sxtb" , 2 , 6 , 16, 27, 0x000006af, 4, 7, 0x00000007}, 23 { "vneg", 5, ARMVFP2, 23, 27, 0x1D, 17, 21, 0x18, 9, 11, 0x5, 6, 7, 1, 4, 4, 0 },
45 {"uxtb" , 2 , 6 , 16, 27, 0x000006ef, 4, 7, 0x00000007}, 24 { "vsqrt", 5, ARMVFP2, 23, 27, 0x1D, 16, 21, 0x31, 9, 11, 0x5, 6, 7, 3, 4, 4, 0 },
46 {"sxth" , 2 , 6 , 16, 27, 0x000006bf, 4, 7, 0x00000007}, 25 { "vcmp", 5, ARMVFP2, 23, 27, 0x1D, 16, 21, 0x34, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 },
47 {"sxtb16" , 2 , 6 , 16, 27, 0x0000068f, 4, 7, 0x00000007}, 26 { "vcmp2", 5, ARMVFP2, 23, 27, 0x1D, 16, 21, 0x35, 9, 11, 0x5, 0, 6, 0x40 },
48 {"uxth" , 2 , 6 , 16, 27, 0x000006ff, 4, 7, 0x00000007}, 27 { "vcvt(bds)", 5, ARMVFP2, 23, 27, 0x1D, 16, 21, 0x37, 9, 11, 0x5, 6, 7, 3, 4, 4, 0 },
49 {"uxtb16" , 2 , 6 , 16, 27, 0x000006cf, 4, 7, 0x00000007}, 28 { "vcvt(bff)", 6, ARMVFP3, 23, 27, 0x1D, 19, 21, 0x7, 17, 17, 0x1, 9, 11, 5, 6, 6, 1 },
50 {"cpy" , 2 , 6 , 20, 27, 0x0000001a, 4, 11, 0x00000000}, 29 { "vcvt(bfi)", 5, ARMVFP2, 23, 27, 0x1D, 19, 21, 0x7, 9, 11, 0x5, 6, 6, 1, 4, 4, 0 },
51 {"uxtab" , 2 , 6 , 20, 27, 0x0000006e, 4, 9, 0x00000007}, 30 { "vmovbrs", 3, ARMVFP2, 21, 27, 0x70, 8, 11, 0xA, 0, 6, 0x10 },
52 {"ssub8" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x0000000f}, 31 { "vmsr", 2, ARMVFP2, 20, 27, 0xEE, 0, 11, 0xA10 },
53 {"shsub8" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x0000000f}, 32 { "vmovbrc", 4, ARMVFP2, 23, 27, 0x1C, 20, 20, 0x0, 8, 11, 0xB, 0, 4, 0x10 },
54 {"ssubaddx" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000005}, 33 { "vmrs", 2, ARMVFP2, 20, 27, 0xEF, 0, 11, 0xA10 },
55 {"strex" , 2 , 6 , 20, 27, 0x00000018, 4, 7, 0x00000009}, 34 { "vmovbcr", 4, ARMVFP2, 24, 27, 0xE, 20, 20, 1, 8, 11, 0xB, 0, 4, 0x10 },
56 {"strexb" , 2 , 7 , 20, 27, 0x0000001c, 4, 7, 0x00000009}, 35 { "vmovbrrss", 3, ARMVFP2, 21, 27, 0x62, 8, 11, 0xA, 4, 4, 1 },
57 {"swp" , 2 , 0 , 20, 27, 0x00000010, 4, 7, 0x00000009}, 36 { "vmovbrrd", 3, ARMVFP2, 21, 27, 0x62, 6, 11, 0x2C, 4, 4, 1 },
58 {"swpb" , 2 , 0 , 20, 27, 0x00000014, 4, 7, 0x00000009}, 37 { "vstr", 3, ARMVFP2, 24, 27, 0xD, 20, 21, 0, 9, 11, 5 },
59 {"ssub16" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000007}, 38 { "vpush", 3, ARMVFP2, 23, 27, 0x1A, 16, 21, 0x2D, 9, 11, 5 },
60 {"ssat16" , 2 , 6 , 20, 27, 0x0000006a, 4, 7, 0x00000003}, 39 { "vstm", 3, ARMVFP2, 25, 27, 0x6, 20, 20, 0, 9, 11, 5 },
61 {"shsubaddx" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000005}, 40 { "vpop", 3, ARMVFP2, 23, 27, 0x19, 16, 21, 0x3D, 9, 11, 5 },
62 {"qsubaddx" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000005}, 41 { "vldr", 3, ARMVFP2, 24, 27, 0xD, 20, 21, 1, 9, 11, 5 },
63 {"shaddsubx" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000003}, 42 { "vldm", 3, ARMVFP2, 25, 27, 0x6, 20, 20, 1, 9, 11, 5 },
64 {"shadd8" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000009}, 43
65 {"shadd16" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000001}, 44 { "srs", 4, 6, 25, 31, 0x0000007c, 22, 22, 0x00000001, 16, 20, 0x0000000d, 8, 11, 0x00000005 },
66 {"sel" , 2 , 6 , 20, 27, 0x00000068, 4, 7, 0x0000000b}, 45 { "rfe", 4, 6, 25, 31, 0x0000007c, 22, 22, 0x00000000, 20, 20, 0x00000001, 8, 11, 0x0000000a },
67 {"saddsubx" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000003}, 46 { "bkpt", 2, 3, 20, 31, 0x00000e12, 4, 7, 0x00000007 },
68 {"sadd8" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000009}, 47 { "blx", 1, 3, 25, 31, 0x0000007d },
69 {"sadd16" , 2 , 6 , 20, 27, 0x00000061, 4, 7, 0x00000001}, 48 { "cps", 3, 6, 20, 31, 0x00000f10, 16, 16, 0x00000000, 5, 5, 0x00000000 },
70 {"shsub16" , 2 , 6 , 20, 27, 0x00000063, 4, 7, 0x00000007}, 49 { "pld", 4, 4, 26, 31, 0x0000003d, 24, 24, 0x00000001, 20, 22, 0x00000005, 12, 15, 0x0000000f },
71 {"umaal" , 2 , 6 , 20, 27, 0x00000004, 4, 7, 0x00000009}, 50 { "setend", 2, 6, 16, 31, 0x0000f101, 4, 7, 0x00000000 },
72 {"uxtab16" , 2 , 6 , 20, 27, 0x0000006c, 4, 7, 0x00000007}, 51 { "clrex", 1, 6, 0, 31, 0xf57ff01f },
73 {"usubaddx" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000005}, 52 { "rev16", 2, 6, 16, 27, 0x000006bf, 4, 11, 0x000000fb },
74 {"usub8" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x0000000f}, 53 { "usad8", 3, 6, 20, 27, 0x00000078, 12, 15, 0x0000000f, 4, 7, 0x00000001 },
75 {"usub16" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000007}, 54 { "sxtb", 2, 6, 16, 27, 0x000006af, 4, 7, 0x00000007 },
76 {"usat16" , 2 , 6 , 20, 27, 0x0000006e, 4, 7, 0x00000003}, 55 { "uxtb", 2, 6, 16, 27, 0x000006ef, 4, 7, 0x00000007 },
77 {"usada8" , 2 , 6 , 20, 27, 0x00000078, 4, 7, 0x00000001}, 56 { "sxth", 2, 6, 16, 27, 0x000006bf, 4, 7, 0x00000007 },
78 {"uqsubaddx" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000005}, 57 { "sxtb16", 2, 6, 16, 27, 0x0000068f, 4, 7, 0x00000007 },
79 {"uqsub8" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x0000000f}, 58 { "uxth", 2, 6, 16, 27, 0x000006ff, 4, 7, 0x00000007 },
80 {"uqsub16" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000007}, 59 { "uxtb16", 2, 6, 16, 27, 0x000006cf, 4, 7, 0x00000007 },
81 {"uqaddsubx" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000003}, 60 { "cpy", 2, 6, 20, 27, 0x0000001a, 4, 11, 0x00000000 },
82 {"uqadd8" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000009}, 61 { "uxtab", 2, 6, 20, 27, 0x0000006e, 4, 9, 0x00000007 },
83 {"uqadd16" , 2 , 6 , 20, 27, 0x00000066, 4, 7, 0x00000001}, 62 { "ssub8", 2, 6, 20, 27, 0x00000061, 4, 7, 0x0000000f },
84 {"sxtab" , 2 , 6 , 20, 27, 0x0000006a, 4, 7, 0x00000007}, 63 { "shsub8", 2, 6, 20, 27, 0x00000063, 4, 7, 0x0000000f },
85 {"uhsubaddx" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000005}, 64 { "ssubaddx", 2, 6, 20, 27, 0x00000061, 4, 7, 0x00000005 },
86 {"uhsub8" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x0000000f}, 65 { "strex", 2, 6, 20, 27, 0x00000018, 4, 7, 0x00000009 },
87 {"uhsub16" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000007}, 66 { "strexb", 2, 7, 20, 27, 0x0000001c, 4, 7, 0x00000009 },
88 {"uhaddsubx" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000003}, 67 { "swp", 2, 0, 20, 27, 0x00000010, 4, 7, 0x00000009 },
89 {"uhadd8" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000009}, 68 { "swpb", 2, 0, 20, 27, 0x00000014, 4, 7, 0x00000009 },
90 {"uhadd16" , 2 , 6 , 20, 27, 0x00000067, 4, 7, 0x00000001}, 69 { "ssub16", 2, 6, 20, 27, 0x00000061, 4, 7, 0x00000007 },
91 {"uaddsubx" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000003}, 70 { "ssat16", 2, 6, 20, 27, 0x0000006a, 4, 7, 0x00000003 },
92 {"uadd8" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000009}, 71 { "shsubaddx", 2, 6, 20, 27, 0x00000063, 4, 7, 0x00000005 },
93 {"uadd16" , 2 , 6 , 20, 27, 0x00000065, 4, 7, 0x00000001}, 72 { "qsubaddx", 2, 6, 20, 27, 0x00000062, 4, 7, 0x00000005 },
94 {"sxtah" , 2 , 6 , 20, 27, 0x0000006b, 4, 7, 0x00000007}, 73 { "shaddsubx", 2, 6, 20, 27, 0x00000063, 4, 7, 0x00000003 },
95 {"sxtab16" , 2 , 6 , 20, 27, 0x00000068, 4, 7, 0x00000007}, 74 { "shadd8", 2, 6, 20, 27, 0x00000063, 4, 7, 0x00000009 },
96 {"qadd8" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000009}, 75 { "shadd16", 2, 6, 20, 27, 0x00000063, 4, 7, 0x00000001 },
97 {"bxj" , 2 , 5 , 20, 27, 0x00000012, 4, 7, 0x00000002}, 76 { "sel", 2, 6, 20, 27, 0x00000068, 4, 7, 0x0000000b },
98 {"clz" , 2 , 3 , 20, 27, 0x00000016, 4, 7, 0x00000001}, 77 { "saddsubx", 2, 6, 20, 27, 0x00000061, 4, 7, 0x00000003 },
99 {"uxtah" , 2 , 6 , 20, 27, 0x0000006f, 4, 7, 0x00000007}, 78 { "sadd8", 2, 6, 20, 27, 0x00000061, 4, 7, 0x00000009 },
100 {"bx" , 2 , 2 , 20, 27, 0x00000012, 4, 7, 0x00000001}, 79 { "sadd16", 2, 6, 20, 27, 0x00000061, 4, 7, 0x00000001 },
101 {"rev" , 2 , 6 , 20, 27, 0x0000006b, 4, 7, 0x00000003}, 80 { "shsub16", 2, 6, 20, 27, 0x00000063, 4, 7, 0x00000007 },
102 {"blx" , 2 , 3 , 20, 27, 0x00000012, 4, 7, 0x00000003}, 81 { "umaal", 2, 6, 20, 27, 0x00000004, 4, 7, 0x00000009 },
103 {"revsh" , 2 , 6 , 20, 27, 0x0000006f, 4, 7, 0x0000000b}, 82 { "uxtab16", 2, 6, 20, 27, 0x0000006c, 4, 7, 0x00000007 },
104 {"qadd" , 2 , 4 , 20, 27, 0x00000010, 4, 7, 0x00000005}, 83 { "usubaddx", 2, 6, 20, 27, 0x00000065, 4, 7, 0x00000005 },
105 {"qadd16" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000001}, 84 { "usub8", 2, 6, 20, 27, 0x00000065, 4, 7, 0x0000000f },
106 {"qaddsubx" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000003}, 85 { "usub16", 2, 6, 20, 27, 0x00000065, 4, 7, 0x00000007 },
107 {"ldrex" , 2 , 0 , 20, 27, 0x00000019, 4, 7, 0x00000009}, 86 { "usat16", 2, 6, 20, 27, 0x0000006e, 4, 7, 0x00000003 },
108 {"qdadd" , 2 , 4 , 20, 27, 0x00000014, 4, 7, 0x00000005}, 87 { "usada8", 2, 6, 20, 27, 0x00000078, 4, 7, 0x00000001 },
109 {"qdsub" , 2 , 4 , 20, 27, 0x00000016, 4, 7, 0x00000005}, 88 { "uqsubaddx", 2, 6, 20, 27, 0x00000066, 4, 7, 0x00000005 },
110 {"qsub" , 2 , 4 , 20, 27, 0x00000012, 4, 7, 0x00000005}, 89 { "uqsub8", 2, 6, 20, 27, 0x00000066, 4, 7, 0x0000000f },
111 {"ldrexb" , 2 , 7 , 20, 27, 0x0000001d, 4, 7, 0x00000009}, 90 { "uqsub16", 2, 6, 20, 27, 0x00000066, 4, 7, 0x00000007 },
112 {"qsub8" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x0000000f}, 91 { "uqaddsubx", 2, 6, 20, 27, 0x00000066, 4, 7, 0x00000003 },
113 {"qsub16" , 2 , 6 , 20, 27, 0x00000062, 4, 7, 0x00000007}, 92 { "uqadd8", 2, 6, 20, 27, 0x00000066, 4, 7, 0x00000009 },
114 {"smuad" , 4 , 6 , 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001}, 93 { "uqadd16", 2, 6, 20, 27, 0x00000066, 4, 7, 0x00000001 },
115 {"smmul" , 4 , 6 , 20, 27, 0x00000075, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001}, 94 { "sxtab", 2, 6, 20, 27, 0x0000006a, 4, 7, 0x00000007 },
116 {"smusd" , 4 , 6 , 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000001, 4, 4, 0x00000001}, 95 { "uhsubaddx", 2, 6, 20, 27, 0x00000067, 4, 7, 0x00000005 },
117 {"smlsd" , 3 , 6 , 20, 27, 0x00000070, 6, 7, 0x00000001, 4, 4, 0x00000001}, 96 { "uhsub8", 2, 6, 20, 27, 0x00000067, 4, 7, 0x0000000f },
118 {"smlsld" , 3 , 6 , 20, 27, 0x00000074, 6, 7, 0x00000001, 4, 4, 0x00000001}, 97 { "uhsub16", 2, 6, 20, 27, 0x00000067, 4, 7, 0x00000007 },
119 {"smmla" , 3 , 6 , 20, 27, 0x00000075, 6, 7, 0x00000000, 4, 4, 0x00000001}, 98 { "uhaddsubx", 2, 6, 20, 27, 0x00000067, 4, 7, 0x00000003 },
120 {"smmls" , 3 , 6 , 20, 27, 0x00000075, 6, 7, 0x00000003, 4, 4, 0x00000001}, 99 { "uhadd8", 2, 6, 20, 27, 0x00000067, 4, 7, 0x00000009 },
121 {"smlald" , 3 , 6 , 20, 27, 0x00000074, 6, 7, 0x00000000, 4, 4, 0x00000001}, 100 { "uhadd16", 2, 6, 20, 27, 0x00000067, 4, 7, 0x00000001 },
122 {"smlad" , 3 , 6 , 20, 27, 0x00000070, 6, 7, 0x00000000, 4, 4, 0x00000001}, 101 { "uaddsubx", 2, 6, 20, 27, 0x00000065, 4, 7, 0x00000003 },
123 {"smlaw" , 3 , 4 , 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000000}, 102 { "uadd8", 2, 6, 20, 27, 0x00000065, 4, 7, 0x00000009 },
124 {"smulw" , 3 , 4 , 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000002}, 103 { "uadd16", 2, 6, 20, 27, 0x00000065, 4, 7, 0x00000001 },
125 {"pkhtb" , 2 , 6 , 20, 27, 0x00000068, 4, 6, 0x00000005}, 104 { "sxtah", 2, 6, 20, 27, 0x0000006b, 4, 7, 0x00000007 },
126 {"pkhbt" , 2 , 6 , 20, 27, 0x00000068, 4, 6, 0x00000001}, 105 { "sxtab16", 2, 6, 20, 27, 0x00000068, 4, 7, 0x00000007 },
127 {"smul" , 3 , 4 , 20, 27, 0x00000016, 7, 7, 0x00000001, 4, 4, 0x00000000}, 106 { "qadd8", 2, 6, 20, 27, 0x00000062, 4, 7, 0x00000009 },
128 {"smlalxy" , 3 , 4 , 20, 27, 0x00000014, 7, 7, 0x00000001, 4, 4, 0x00000000}, 107 { "bxj", 2, 5, 20, 27, 0x00000012, 4, 7, 0x00000002 },
129// {"smlal" , 2 , 4 , 21, 27, 0x00000007, 4, 7, 0x00000009}, 108 { "clz", 2, 3, 20, 27, 0x00000016, 4, 7, 0x00000001 },
130 {"smla" , 3 , 4 , 20, 27, 0x00000010, 7, 7, 0x00000001, 4, 4, 0x00000000}, 109 { "uxtah", 2, 6, 20, 27, 0x0000006f, 4, 7, 0x00000007 },
131 {"mcrr" , 1 , 6 , 20, 27, 0x000000c4}, 110 { "bx", 2, 2, 20, 27, 0x00000012, 4, 7, 0x00000001 },
132 {"mrrc" , 1 , 6 , 20, 27, 0x000000c5}, 111 { "rev", 2, 6, 20, 27, 0x0000006b, 4, 7, 0x00000003 },
133 {"cmp" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000015}, 112 { "blx", 2, 3, 20, 27, 0x00000012, 4, 7, 0x00000003 },
134 {"tst" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000011}, 113 { "revsh", 2, 6, 20, 27, 0x0000006f, 4, 7, 0x0000000b },
135 {"teq" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000013}, 114 { "qadd", 2, 4, 20, 27, 0x00000010, 4, 7, 0x00000005 },
136 {"cmn" , 2 , 0 , 26, 27, 0x00000000, 20, 24, 0x00000017}, 115 { "qadd16", 2, 6, 20, 27, 0x00000062, 4, 7, 0x00000001 },
137 {"smull" , 2 , 0 , 21, 27, 0x00000006, 4, 7, 0x00000009}, 116 { "qaddsubx", 2, 6, 20, 27, 0x00000062, 4, 7, 0x00000003 },
138 {"umull" , 2 , 0 , 21, 27, 0x00000004, 4, 7, 0x00000009}, 117 { "ldrex", 2, 0, 20, 27, 0x00000019, 4, 7, 0x00000009 },
139 {"umlal" , 2 , 0 , 21, 27, 0x00000005, 4, 7, 0x00000009}, 118 { "qdadd", 2, 4, 20, 27, 0x00000014, 4, 7, 0x00000005 },
140 {"smlal" , 2 , 0 , 21, 27, 0x00000007, 4, 7, 0x00000009}, 119 { "qdsub", 2, 4, 20, 27, 0x00000016, 4, 7, 0x00000005 },
141 {"mul" , 2 , 0 , 21, 27, 0x00000000, 4, 7, 0x00000009}, 120 { "qsub", 2, 4, 20, 27, 0x00000012, 4, 7, 0x00000005 },
142 {"mla" , 2 , 0 , 21, 27, 0x00000001, 4, 7, 0x00000009}, 121 { "ldrexb", 2, 7, 20, 27, 0x0000001d, 4, 7, 0x00000009 },
143 {"ssat" , 2 , 6 , 21, 27, 0x00000035, 4, 5, 0x00000001}, 122 { "qsub8", 2, 6, 20, 27, 0x00000062, 4, 7, 0x0000000f },
144 {"usat" , 2 , 6 , 21, 27, 0x00000037, 4, 5, 0x00000001}, 123 { "qsub16", 2, 6, 20, 27, 0x00000062, 4, 7, 0x00000007 },
145 {"mrs" , 4 , 0 , 23, 27, 0x00000002, 20, 21, 0x00000000, 16, 19, 0x0000000f, 0, 11, 0x00000000}, 124 { "smuad", 4, 6, 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001 },
146 {"msr" , 3 , 0 , 23, 27, 0x00000002, 20, 21, 0x00000002, 4, 7, 0x00000000}, 125 { "smmul", 4, 6, 20, 27, 0x00000075, 12, 15, 0x0000000f, 6, 7, 0x00000000, 4, 4, 0x00000001 },
147 {"and" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000000}, 126 { "smusd", 4, 6, 20, 27, 0x00000070, 12, 15, 0x0000000f, 6, 7, 0x00000001, 4, 4, 0x00000001 },
148 {"bic" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000e}, 127 { "smlsd", 3, 6, 20, 27, 0x00000070, 6, 7, 0x00000001, 4, 4, 0x00000001 },
149 {"ldm" , 3 , 0 , 25, 27, 0x00000004, 20, 22, 0x00000005, 15, 15, 0x00000000}, 128 { "smlsld", 3, 6, 20, 27, 0x00000074, 6, 7, 0x00000001, 4, 4, 0x00000001 },
150 {"eor" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000001}, 129 { "smmla", 3, 6, 20, 27, 0x00000075, 6, 7, 0x00000000, 4, 4, 0x00000001 },
151 {"add" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000004}, 130 { "smmls", 3, 6, 20, 27, 0x00000075, 6, 7, 0x00000003, 4, 4, 0x00000001 },
152 {"rsb" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000003}, 131 { "smlald", 3, 6, 20, 27, 0x00000074, 6, 7, 0x00000000, 4, 4, 0x00000001 },
153 {"rsc" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000007}, 132 { "smlad", 3, 6, 20, 27, 0x00000070, 6, 7, 0x00000000, 4, 4, 0x00000001 },
154 {"sbc" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000006}, 133 { "smlaw", 3, 4, 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000000 },
155 {"adc" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000005}, 134 { "smulw", 3, 4, 20, 27, 0x00000012, 7, 7, 0x00000001, 4, 5, 0x00000002 },
156 {"sub" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x00000002}, 135 { "pkhtb", 2, 6, 20, 27, 0x00000068, 4, 6, 0x00000005 },
157 {"orr" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000c}, 136 { "pkhbt", 2, 6, 20, 27, 0x00000068, 4, 6, 0x00000001 },
158 {"mvn" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000f}, 137 { "smul", 3, 4, 20, 27, 0x00000016, 7, 7, 0x00000001, 4, 4, 0x00000000 },
159 {"mov" , 2 , 0 , 26, 27, 0x00000000, 21, 24, 0x0000000d}, 138 { "smlalxy", 3, 4, 20, 27, 0x00000014, 7, 7, 0x00000001, 4, 4, 0x00000000 },
160 {"stm" , 2 , 0 , 25, 27, 0x00000004, 20, 22, 0x00000004}, 139 // {"smlal" , 2 , 4 , 21, 27, 0x00000007, 4, 7, 0x00000009},
161 {"ldm" , 4 , 0 , 25, 27, 0x00000004, 22, 22, 0x00000001, 20, 20, 0x00000001, 15, 15, 0x00000001}, 140 { "smla", 3, 4, 20, 27, 0x00000010, 7, 7, 0x00000001, 4, 4, 0x00000000 },
162 {"ldrsh" , 3 , 2 , 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000f}, 141 { "mcrr", 1, 6, 20, 27, 0x000000c4 },
163 {"stm" , 3 , 0 , 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000000}, 142 { "mrrc", 1, 6, 20, 27, 0x000000c5 },
164 {"ldm" , 3 , 0 , 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000001}, 143 { "cmp", 2, 0, 26, 27, 0x00000000, 20, 24, 0x00000015 },
165 {"ldrsb" , 3 , 2 , 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000d}, 144 { "tst", 2, 0, 26, 27, 0x00000000, 20, 24, 0x00000011 },
166 {"strd" , 3 , 4 , 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000f}, 145 { "teq", 2, 0, 26, 27, 0x00000000, 20, 24, 0x00000013 },
167 {"ldrh" , 3 , 0 , 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000b}, 146 { "cmn", 2, 0, 26, 27, 0x00000000, 20, 24, 0x00000017 },
168 {"strh" , 3 , 0 , 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000b}, 147 { "smull", 2, 0, 21, 27, 0x00000006, 4, 7, 0x00000009 },
169 {"ldrd" , 3 , 4 , 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000d}, 148 { "umull", 2, 0, 21, 27, 0x00000004, 4, 7, 0x00000009 },
170 {"strt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000002}, 149 { "umlal", 2, 0, 21, 27, 0x00000005, 4, 7, 0x00000009 },
171 {"strbt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000006}, 150 { "smlal", 2, 0, 21, 27, 0x00000007, 4, 7, 0x00000009 },
172 {"ldrbt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000007}, 151 { "mul", 2, 0, 21, 27, 0x00000000, 4, 7, 0x00000009 },
173 {"ldrt" , 3 , 0 , 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000003}, 152 { "mla", 2, 0, 21, 27, 0x00000001, 4, 7, 0x00000009 },
174 {"mrc" , 3 , 6 , 24, 27, 0x0000000e, 20, 20, 0x00000001, 4, 4, 0x00000001}, 153 { "ssat", 2, 6, 21, 27, 0x00000035, 4, 5, 0x00000001 },
175 {"mcr" , 3 , 0 , 24, 27, 0x0000000e, 20, 20, 0x00000000, 4, 4, 0x00000001}, 154 { "usat", 2, 6, 21, 27, 0x00000037, 4, 5, 0x00000001 },
176 {"msr" , 2 , 0 , 23, 27, 0x00000006, 20, 21, 0x00000002}, 155 { "mrs", 4, 0, 23, 27, 0x00000002, 20, 21, 0x00000000, 16, 19, 0x0000000f, 0, 11, 0x00000000 },
177 {"ldrb" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000001}, 156 { "msr", 3, 0, 23, 27, 0x00000002, 20, 21, 0x00000002, 4, 7, 0x00000000 },
178 {"strb" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000000}, 157 { "and", 2, 0, 26, 27, 0x00000000, 21, 24, 0x00000000 },
179 {"ldr" , 4 , 0 , 28, 31, 0x0000000e, 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001}, 158 { "bic", 2, 0, 26, 27, 0x00000000, 21, 24, 0x0000000e },
180 {"ldrcond" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001}, 159 { "ldm", 3, 0, 25, 27, 0x00000004, 20, 22, 0x00000005, 15, 15, 0x00000000 },
181 {"str" , 3 , 0 , 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000000}, 160 { "eor", 2, 0, 26, 27, 0x00000000, 21, 24, 0x00000001 },
182 {"cdp" , 2 , 0 , 24, 27, 0x0000000e, 4, 4, 0x00000000}, 161 { "add", 2, 0, 26, 27, 0x00000000, 21, 24, 0x00000004 },
183 {"stc" , 2 , 0 , 25, 27, 0x00000006, 20, 20, 0x00000000}, 162 { "rsb", 2, 0, 26, 27, 0x00000000, 21, 24, 0x00000003 },
184 {"ldc" , 2 , 0 , 25, 27, 0x00000006, 20, 20, 0x00000001}, 163 { "rsc", 2, 0, 26, 27, 0x00000000, 21, 24, 0x00000007 },
185 {"swi" , 1 , 0 , 24, 27, 0x0000000f}, 164 { "sbc", 2, 0, 26, 27, 0x00000000, 21, 24, 0x00000006 },
186 {"bbl" , 1 , 0 , 25, 27, 0x00000005}, 165 { "adc", 2, 0, 26, 27, 0x00000000, 21, 24, 0x00000005 },
166 { "sub", 2, 0, 26, 27, 0x00000000, 21, 24, 0x00000002 },
167 { "orr", 2, 0, 26, 27, 0x00000000, 21, 24, 0x0000000c },
168 { "mvn", 2, 0, 26, 27, 0x00000000, 21, 24, 0x0000000f },
169 { "mov", 2, 0, 26, 27, 0x00000000, 21, 24, 0x0000000d },
170 { "stm", 2, 0, 25, 27, 0x00000004, 20, 22, 0x00000004 },
171 { "ldm", 4, 0, 25, 27, 0x00000004, 22, 22, 0x00000001, 20, 20, 0x00000001, 15, 15, 0x00000001 },
172 { "ldrsh", 3, 2, 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000f },
173 { "stm", 3, 0, 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000000 },
174 { "ldm", 3, 0, 25, 27, 0x00000004, 22, 22, 0x00000000, 20, 20, 0x00000001 },
175 { "ldrsb", 3, 2, 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000d },
176 { "strd", 3, 4, 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000f },
177 { "ldrh", 3, 0, 25, 27, 0x00000000, 20, 20, 0x00000001, 4, 7, 0x0000000b },
178 { "strh", 3, 0, 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000b },
179 { "ldrd", 3, 4, 25, 27, 0x00000000, 20, 20, 0x00000000, 4, 7, 0x0000000d },
180 { "strt", 3, 0, 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000002 },
181 { "strbt", 3, 0, 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000006 },
182 { "ldrbt", 3, 0, 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000007 },
183 { "ldrt", 3, 0, 26, 27, 0x00000001, 24, 24, 0x00000000, 20, 22, 0x00000003 },
184 { "mrc", 3, 6, 24, 27, 0x0000000e, 20, 20, 0x00000001, 4, 4, 0x00000001 },
185 { "mcr", 3, 0, 24, 27, 0x0000000e, 20, 20, 0x00000000, 4, 4, 0x00000001 },
186 { "msr", 2, 0, 23, 27, 0x00000006, 20, 21, 0x00000002 },
187 { "ldrb", 3, 0, 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000001 },
188 { "strb", 3, 0, 26, 27, 0x00000001, 22, 22, 0x00000001, 20, 20, 0x00000000 },
189 { "ldr", 4, 0, 28, 31, 0x0000000e, 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001 },
190 { "ldrcond", 3, 0, 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000001 },
191 { "str", 3, 0, 26, 27, 0x00000001, 22, 22, 0x00000000, 20, 20, 0x00000000 },
192 { "cdp", 2, 0, 24, 27, 0x0000000e, 4, 4, 0x00000000 },
193 { "stc", 2, 0, 25, 27, 0x00000006, 20, 20, 0x00000000 },
194 { "ldc", 2, 0, 25, 27, 0x00000006, 20, 20, 0x00000001 },
195 { "swi", 1, 0, 24, 27, 0x0000000f },
196 { "bbl", 1, 0, 25, 27, 0x00000005 },
187}; 197};
188 198
189const ISEITEM arm_exclusion_code[] = { 199const ISEITEM arm_exclusion_code[] = {
190 #define VFP_DECODE_EXCLUSION 200 { "vmla", 0, ARMVFP2, 0 },
191 #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 201 { "vmls", 0, ARMVFP2, 0 },
192 #undef VFP_DECODE_EXCLUSION 202 { "vnmla", 0, ARMVFP2, 0 },
193 {"srs" , 0 , 6 , 0}, 203 { "vnmla", 0, ARMVFP2, 0 },
194 {"rfe" , 0 , 6 , 0}, 204 { "vnmls", 0, ARMVFP2, 0 },
195 {"bkpt" , 0 , 3 , 0}, 205 { "vnmul", 0, ARMVFP2, 0 },
196 {"blx" , 0 , 3 , 0}, 206 { "vmul", 0, ARMVFP2, 0 },
197 {"cps" , 0 , 6 , 0}, 207 { "vadd", 0, ARMVFP2, 0 },
198 {"pld" , 0 , 4 , 0}, 208 { "vsub", 0, ARMVFP2, 0 },
199 {"setend" , 0 , 6 , 0}, 209 { "vdiv", 0, ARMVFP2, 0 },
200 {"clrex" , 0 , 6 , 0}, 210 { "vmov(i)", 0, ARMVFP3, 0 },
201 {"rev16" , 0 , 6 , 0}, 211 { "vmov(r)", 0, ARMVFP3, 0 },
202 {"usad8" , 0 , 6 , 0}, 212 { "vabs", 0, ARMVFP2, 0 },
203 {"sxtb" , 0 , 6 , 0}, 213 { "vneg", 0, ARMVFP2, 0 },
204 {"uxtb" , 0 , 6 , 0}, 214 { "vsqrt", 0, ARMVFP2, 0 },
205 {"sxth" , 0 , 6 , 0}, 215 { "vcmp", 0, ARMVFP2, 0 },
206 {"sxtb16" , 0 , 6 , 0}, 216 { "vcmp2", 0, ARMVFP2, 0 },
207 {"uxth" , 0 , 6 , 0}, 217 { "vcvt(bff)", 0, ARMVFP3, 4, 4, 1 },
208 {"uxtb16" , 0 , 6 , 0}, 218 { "vcvt(bds)", 0, ARMVFP2, 0 },
209 {"cpy" , 0 , 6 , 0}, 219 { "vcvt(bfi)", 0, ARMVFP2, 0 },
210 {"uxtab" , 0 , 6 , 0}, 220 { "vmovbrs", 0, ARMVFP2, 0 },
211 {"ssub8" , 0 , 6 , 0}, 221 { "vmsr", 0, ARMVFP2, 0 },
212 {"shsub8" , 0 , 6 , 0}, 222 { "vmovbrc", 0, ARMVFP2, 0 },
213 {"ssubaddx" , 0 , 6 , 0}, 223 { "vmrs", 0, ARMVFP2, 0 },
214 {"strex" , 0 , 6 , 0}, 224 { "vmovbcr", 0, ARMVFP2, 0 },
215 {"strexb" , 0 , 7 , 0}, 225 { "vmovbrrss", 0, ARMVFP2, 0 },
216 {"swp" , 0 , 0 , 0}, 226 { "vmovbrrd", 0, ARMVFP2, 0 },
217 {"swpb" , 0 , 0 , 0}, 227 { "vstr", 0, ARMVFP2, 0 },
218 {"ssub16" , 0 , 6 , 0}, 228 { "vpush", 0, ARMVFP2, 0 },
219 {"ssat16" , 0 , 6 , 0}, 229 { "vstm", 0, ARMVFP2, 0 },
220 {"shsubaddx" , 0 , 6 , 0}, 230 { "vpop", 0, ARMVFP2, 0 },
221 {"qsubaddx" , 0 , 6 , 0}, 231 { "vldr", 0, ARMVFP2, 0 },
222 {"shaddsubx" , 0 , 6 , 0}, 232 { "vldm", 0, ARMVFP2, 0 },
223 {"shadd8" , 0 , 6 , 0}, 233
224 {"shadd16" , 0 , 6 , 0}, 234 { "srs", 0, 6, 0 },
225 {"sel" , 0 , 6 , 0}, 235 { "rfe", 0, 6, 0 },
226 {"saddsubx" , 0 , 6 , 0}, 236 { "bkpt", 0, 3, 0 },
227 {"sadd8" , 0 , 6 , 0}, 237 { "blx", 0, 3, 0 },
228 {"sadd16" , 0 , 6 , 0}, 238 { "cps", 0, 6, 0 },
229 {"shsub16" , 0 , 6 , 0}, 239 { "pld", 0, 4, 0 },
230 {"umaal" , 0 , 6 , 0}, 240 { "setend", 0, 6, 0 },
231 {"uxtab16" , 0 , 6 , 0}, 241 { "clrex", 0, 6, 0 },
232 {"usubaddx" , 0 , 6 , 0}, 242 { "rev16", 0, 6, 0 },
233 {"usub8" , 0 , 6 , 0}, 243 { "usad8", 0, 6, 0 },
234 {"usub16" , 0 , 6 , 0}, 244 { "sxtb", 0, 6, 0 },
235 {"usat16" , 0 , 6 , 0}, 245 { "uxtb", 0, 6, 0 },
236 {"usada8" , 0 , 6 , 0}, 246 { "sxth", 0, 6, 0 },
237 {"uqsubaddx" , 0 , 6 , 0}, 247 { "sxtb16", 0, 6, 0 },
238 {"uqsub8" , 0 , 6 , 0}, 248 { "uxth", 0, 6, 0 },
239 {"uqsub16" , 0 , 6 , 0}, 249 { "uxtb16", 0, 6, 0 },
240 {"uqaddsubx" , 0 , 6 , 0}, 250 { "cpy", 0, 6, 0 },
241 {"uqadd8" , 0 , 6 , 0}, 251 { "uxtab", 0, 6, 0 },
242 {"uqadd16" , 0 , 6 , 0}, 252 { "ssub8", 0, 6, 0 },
243 {"sxtab" , 0 , 6 , 0}, 253 { "shsub8", 0, 6, 0 },
244 {"uhsubaddx" , 0 , 6 , 0}, 254 { "ssubaddx", 0, 6, 0 },
245 {"uhsub8" , 0 , 6 , 0}, 255 { "strex", 0, 6, 0 },
246 {"uhsub16" , 0 , 6 , 0}, 256 { "strexb", 0, 7, 0 },
247 {"uhaddsubx" , 0 , 6 , 0}, 257 { "swp", 0, 0, 0 },
248 {"uhadd8" , 0 , 6 , 0}, 258 { "swpb", 0, 0, 0 },
249 {"uhadd16" , 0 , 6 , 0}, 259 { "ssub16", 0, 6, 0 },
250 {"uaddsubx" , 0 , 6 , 0}, 260 { "ssat16", 0, 6, 0 },
251 {"uadd8" , 0 , 6 , 0}, 261 { "shsubaddx", 0, 6, 0 },
252 {"uadd16" , 0 , 6 , 0}, 262 { "qsubaddx", 0, 6, 0 },
253 {"sxtah" , 0 , 6 , 0}, 263 { "shaddsubx", 0, 6, 0 },
254 {"sxtab16" , 0 , 6 , 0}, 264 { "shadd8", 0, 6, 0 },
255 {"qadd8" , 0 , 6 , 0}, 265 { "shadd16", 0, 6, 0 },
256 {"bxj" , 0 , 5 , 0}, 266 { "sel", 0, 6, 0 },
257 {"clz" , 0 , 3 , 0}, 267 { "saddsubx", 0, 6, 0 },
258 {"uxtah" , 0 , 6 , 0}, 268 { "sadd8", 0, 6, 0 },
259 {"bx" , 0 , 2 , 0}, 269 { "sadd16", 0, 6, 0 },
260 {"rev" , 0 , 6 , 0}, 270 { "shsub16", 0, 6, 0 },
261 {"blx" , 0 , 3 , 0}, 271 { "umaal", 0, 6, 0 },
262 {"revsh" , 0 , 6 , 0}, 272 { "uxtab16", 0, 6, 0 },
263 {"qadd" , 0 , 4 , 0}, 273 { "usubaddx", 0, 6, 0 },
264 {"qadd16" , 0 , 6 , 0}, 274 { "usub8", 0, 6, 0 },
265 {"qaddsubx" , 0 , 6 , 0}, 275 { "usub16", 0, 6, 0 },
266 {"ldrex" , 0 , 0 , 0}, 276 { "usat16", 0, 6, 0 },
267 {"qdadd" , 0 , 4 , 0}, 277 { "usada8", 0, 6, 0 },
268 {"qdsub" , 0 , 4 , 0}, 278 { "uqsubaddx", 0, 6, 0 },
269 {"qsub" , 0 , 4 , 0}, 279 { "uqsub8", 0, 6, 0 },
270 {"ldrexb" , 0 , 7 , 0}, 280 { "uqsub16", 0, 6, 0 },
271 {"qsub8" , 0 , 6 , 0}, 281 { "uqaddsubx", 0, 6, 0 },
272 {"qsub16" , 0 , 6 , 0}, 282 { "uqadd8", 0, 6, 0 },
273 {"smuad" , 0 , 6 , 0}, 283 { "uqadd16", 0, 6, 0 },
274 {"smmul" , 0 , 6 , 0}, 284 { "sxtab", 0, 6, 0 },
275 {"smusd" , 0 , 6 , 0}, 285 { "uhsubaddx", 0, 6, 0 },
276 {"smlsd" , 0 , 6 , 0}, 286 { "uhsub8", 0, 6, 0 },
277 {"smlsld" , 0 , 6 , 0}, 287 { "uhsub16", 0, 6, 0 },
278 {"smmla" , 0 , 6 , 0}, 288 { "uhaddsubx", 0, 6, 0 },
279 {"smmls" , 0 , 6 , 0}, 289 { "uhadd8", 0, 6, 0 },
280 {"smlald" , 0 , 6 , 0}, 290 { "uhadd16", 0, 6, 0 },
281 {"smlad" , 0 , 6 , 0}, 291 { "uaddsubx", 0, 6, 0 },
282 {"smlaw" , 0 , 4 , 0}, 292 { "uadd8", 0, 6, 0 },
283 {"smulw" , 0 , 4 , 0}, 293 { "uadd16", 0, 6, 0 },
284 {"pkhtb" , 0 , 6 , 0}, 294 { "sxtah", 0, 6, 0 },
285 {"pkhbt" , 0 , 6 , 0}, 295 { "sxtab16", 0, 6, 0 },
286 {"smul" , 0 , 4 , 0}, 296 { "qadd8", 0, 6, 0 },
287 {"smlal" , 0 , 4 , 0}, 297 { "bxj", 0, 5, 0 },
288 {"smla" , 0 , 4 , 0}, 298 { "clz", 0, 3, 0 },
289 {"mcrr" , 0 , 6 , 0}, 299 { "uxtah", 0, 6, 0 },
290 {"mrrc" , 0 , 6 , 0}, 300 { "bx", 0, 2, 0 },
291 {"cmp" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, 301 { "rev", 0, 6, 0 },
292 {"tst" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, 302 { "blx", 0, 3, 0 },
293 {"teq" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, 303 { "revsh", 0, 6, 0 },
294 {"cmn" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, 304 { "qadd", 0, 4, 0 },
295 {"smull" , 0 , 0 , 0}, 305 { "qadd16", 0, 6, 0 },
296 {"umull" , 0 , 0 , 0}, 306 { "qaddsubx", 0, 6, 0 },
297 {"umlal" , 0 , 0 , 0}, 307 { "ldrex", 0, 0, 0 },
298 {"smlal" , 0 , 0 , 0}, 308 { "qdadd", 0, 4, 0 },
299 {"mul" , 0 , 0 , 0}, 309 { "qdsub", 0, 4, 0 },
300 {"mla" , 0 , 0 , 0}, 310 { "qsub", 0, 4, 0 },
301 {"ssat" , 0 , 6 , 0}, 311 { "ldrexb", 0, 7, 0 },
302 {"usat" , 0 , 6 , 0}, 312 { "qsub8", 0, 6, 0 },
303 {"mrs" , 0 , 0 , 0}, 313 { "qsub16", 0, 6, 0 },
304 {"msr" , 0 , 0 , 0}, 314 { "smuad", 0, 6, 0 },
305 {"and" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, 315 { "smmul", 0, 6, 0 },
306 {"bic" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, 316 { "smusd", 0, 6, 0 },
307 {"ldm" , 0 , 0 , 0}, 317 { "smlsd", 0, 6, 0 },
308 {"eor" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, 318 { "smlsld", 0, 6, 0 },
309 {"add" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, 319 { "smmla", 0, 6, 0 },
310 {"rsb" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, 320 { "smmls", 0, 6, 0 },
311 {"rsc" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, 321 { "smlald", 0, 6, 0 },
312 {"sbc" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, 322 { "smlad", 0, 6, 0 },
313 {"adc" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, 323 { "smlaw", 0, 4, 0 },
314 {"sub" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, 324 { "smulw", 0, 4, 0 },
315 {"orr" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, 325 { "pkhtb", 0, 6, 0 },
316 {"mvn" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, 326 { "pkhbt", 0, 6, 0 },
317 {"mov" , 3 , 0 , 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000}, 327 { "smul", 0, 4, 0 },
318 {"stm" , 0 , 0 , 0}, 328 { "smlal", 0, 4, 0 },
319 {"ldm" , 0 , 0 , 0}, 329 { "smla", 0, 4, 0 },
320 {"ldrsh" , 0 , 2 , 0}, 330 { "mcrr", 0, 6, 0 },
321 {"stm" , 0 , 0 , 0}, 331 { "mrrc", 0, 6, 0 },
322 {"ldm" , 0 , 0 , 0}, 332 { "cmp", 3, 0, 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 },
323 {"ldrsb" , 0 , 2 , 0}, 333 { "tst", 3, 0, 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 },
324 {"strd" , 0 , 4 , 0}, 334 { "teq", 3, 0, 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 },
325 {"ldrh" , 0 , 0 , 0}, 335 { "cmn", 3, 0, 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 },
326 {"strh" , 0 , 0 , 0}, 336 { "smull", 0, 0, 0 },
327 {"ldrd" , 0 , 4 , 0}, 337 { "umull", 0, 0, 0 },
328 {"strt" , 0 , 0 , 0}, 338 { "umlal", 0, 0, 0 },
329 {"strbt" , 0 , 0 , 0}, 339 { "smlal", 0, 0, 0 },
330 {"ldrbt" , 0 , 0 , 0}, 340 { "mul", 0, 0, 0 },
331 {"ldrt" , 0 , 0 , 0}, 341 { "mla", 0, 0, 0 },
332 {"mrc" , 0 , 6 , 0}, 342 { "ssat", 0, 6, 0 },
333 {"mcr" , 0 , 0 , 0}, 343 { "usat", 0, 6, 0 },
334 {"msr" , 0 , 0 , 0}, 344 { "mrs", 0, 0, 0 },
335 {"ldrb" , 0 , 0 , 0}, 345 { "msr", 0, 0, 0 },
336 {"strb" , 0 , 0 , 0}, 346 { "and", 3, 0, 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 },
337 {"ldr" , 0 , 0 , 0}, 347 { "bic", 3, 0, 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 },
338 {"ldrcond" , 1 , 0 , 28, 31, 0x0000000e}, 348 { "ldm", 0, 0, 0 },
339 {"str" , 0 , 0 , 0}, 349 { "eor", 3, 0, 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 },
340 {"cdp" , 0 , 0 , 0}, 350 { "add", 3, 0, 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 },
341 {"stc" , 0 , 0 , 0}, 351 { "rsb", 3, 0, 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 },
342 {"ldc" , 0 , 0 , 0}, 352 { "rsc", 3, 0, 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 },
343 {"swi" , 0 , 0 , 0}, 353 { "sbc", 3, 0, 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 },
344 {"bbl" , 0 , 0 , 0}, 354 { "adc", 3, 0, 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 },
345 {"bl_1_thumb", 0, INVALID, 0},/* should be table[-4] */ 355 { "sub", 3, 0, 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 },
346 {"bl_2_thumb", 0, INVALID, 0}, /* should be located at the end of the table[-3] */ 356 { "orr", 3, 0, 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 },
347 {"blx_1_thumb", 0, INVALID, 0}, /* should be located at table[-2] */ 357 { "mvn", 3, 0, 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 },
348 {"invalid", 0, INVALID, 0} 358 { "mov", 3, 0, 4, 4, 0x00000001, 7, 7, 0x00000001, 25, 25, 0x00000000 },
359 { "stm", 0, 0, 0 },
360 { "ldm", 0, 0, 0 },
361 { "ldrsh", 0, 2, 0 },
362 { "stm", 0, 0, 0 },
363 { "ldm", 0, 0, 0 },
364 { "ldrsb", 0, 2, 0 },
365 { "strd", 0, 4, 0 },
366 { "ldrh", 0, 0, 0 },
367 { "strh", 0, 0, 0 },
368 { "ldrd", 0, 4, 0 },
369 { "strt", 0, 0, 0 },
370 { "strbt", 0, 0, 0 },
371 { "ldrbt", 0, 0, 0 },
372 { "ldrt", 0, 0, 0 },
373 { "mrc", 0, 6, 0 },
374 { "mcr", 0, 0, 0 },
375 { "msr", 0, 0, 0 },
376 { "ldrb", 0, 0, 0 },
377 { "strb", 0, 0, 0 },
378 { "ldr", 0, 0, 0 },
379 { "ldrcond", 1, 0, 28, 31, 0x0000000e },
380 { "str", 0, 0, 0 },
381 { "cdp", 0, 0, 0 },
382 { "stc", 0, 0, 0 },
383 { "ldc", 0, 0, 0 },
384 { "swi", 0, 0, 0 },
385 { "bbl", 0, 0, 0 },
386 { "bl_1_thumb", 0, INVALID, 0 }, // Should be table[-4]
387 { "bl_2_thumb", 0, INVALID, 0 }, // Should be located at the end of the table[-3]
388 { "blx_1_thumb", 0, INVALID, 0 }, // Should be located at table[-2]
389 { "invalid", 0, INVALID, 0 }
349}; 390};
350 391
351int decode_arm_instr(uint32_t instr, int32_t *idx) 392int decode_arm_instr(uint32_t instr, int32_t *idx) {
352{ 393 int n = 0;
353 int n = 0; 394 int base = 0;
354 int base = 0; 395 int ret = DECODE_FAILURE;
355 int ret = DECODE_FAILURE; 396 int i = 0;
356 int i = 0; 397 int instr_slots = sizeof(arm_instruction) / sizeof(ISEITEM);
357 int instr_slots = sizeof(arm_instruction)/sizeof(ISEITEM); 398 for (i = 0; i < instr_slots; i++) {
358 for (i = 0; i < instr_slots; i++) 399 n = arm_instruction[i].attribute_value;
359 { 400 base = 0;
360// ret = DECODE_SUCCESS;
361 n = arm_instruction[i].attribute_value;
362 base = 0;
363 while (n) {
364 if (arm_instruction[i].content[base + 1] == 31 && arm_instruction[i].content[base] == 0) {
365 /* clrex */
366 if (instr != arm_instruction[i].content[base + 2]) {
367 break;
368 }
369 } else if (BITS(arm_instruction[i].content[base], arm_instruction[i].content[base + 1]) != arm_instruction[i].content[base + 2]) {
370 break;
371 }
372 base += 3;
373 n --;
374 }
375 //All conditions is satisfied.
376 if (n == 0)
377 ret = DECODE_SUCCESS;
378 401
379 if (ret == DECODE_SUCCESS) { 402 while (n) {
380 n = arm_exclusion_code[i].attribute_value; 403 if (arm_instruction[i].content[base + 1] == 31 && arm_instruction[i].content[base] == 0) {
381 if (n != 0) { 404 // clrex
382 base = 0; 405 if (instr != arm_instruction[i].content[base + 2]) {
383 while (n) { 406 break;
384 if (BITS(arm_exclusion_code[i].content[base], arm_exclusion_code[i].content[base + 1]) != arm_exclusion_code[i].content[base + 2]) { 407 }
385 break; } 408 } else if (BITS(arm_instruction[i].content[base], arm_instruction[i].content[base + 1]) != arm_instruction[i].content[base + 2]) {
386 base += 3; 409 break;
387 n --; 410 }
388 } 411 base += 3;
389 //All conditions is satisfied. 412 n--;
390 if (n == 0) 413 }
391 ret = DECODE_FAILURE;
392 }
393 }
394 414
395 if (ret == DECODE_SUCCESS) { 415 // All conditions is satisfied.
396 *idx = i; 416 if (n == 0)
397 return ret; 417 ret = DECODE_SUCCESS;
398 }
399 }
400 return ret;
401}
402 418
419 if (ret == DECODE_SUCCESS) {
420 n = arm_exclusion_code[i].attribute_value;
421 if (n != 0) {
422 base = 0;
423 while (n) {
424 if (BITS(arm_exclusion_code[i].content[base], arm_exclusion_code[i].content[base + 1]) != arm_exclusion_code[i].content[base + 2]) {
425 break;
426 }
427 base += 3;
428 n--;
429 }
430
431 // All conditions is satisfied.
432 if (n == 0)
433 ret = DECODE_FAILURE;
434 }
435 }
436
437 if (ret == DECODE_SUCCESS) {
438 *idx = i;
439 return ret;
440 }
441 }
442 return ret;
443}
diff --git a/src/core/arm/dyncom/arm_dyncom_dec.h b/src/core/arm/dyncom/arm_dyncom_dec.h
index 19d94f369..70eb96e93 100644
--- a/src/core/arm/dyncom/arm_dyncom_dec.h
+++ b/src/core/arm/dyncom/arm_dyncom_dec.h
@@ -56,8 +56,6 @@
56#define RN ((instr >> 16) & 0xF) 56#define RN ((instr >> 16) & 0xF)
57/*xxxx xxxx xxxx xxxx xxxx xxxx xxxx 1111 */ 57/*xxxx xxxx xxxx xxxx xxxx xxxx xxxx 1111 */
58#define RM (instr & 0xF) 58#define RM (instr & 0xF)
59#define BIT(n) ((instr >> (n)) & 1)
60#define BITS(a,b) ((instr >> (a)) & ((1 << (1+(b)-(a)))-1))
61 59
62/* CP15 registers */ 60/* CP15 registers */
63#define OPCODE_1 BITS(21, 23) 61#define OPCODE_1 BITS(21, 23)
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index 37925e8a8..53da7ca9c 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -1,32 +1,11 @@
1/* Copyright (C) 1// Copyright 2012 Michael Kang, 2014 Citra Emulator Project
2* 2012 - Michael.Kang blackfin.kang@gmail.com 2// Licensed under GPLv2 or any later version
3* This program is free software; you can redistribute it and/or 3// Refer to the license.txt file included.
4* modify it under the terms of the GNU General Public License
5* as published by the Free Software Foundation; either version 2
6* of the License, or (at your option) any later version.
7*
8* This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program; if not, write to the Free Software
15* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16*
17*/
18/**
19* @file arm_dyncom_interpreter.cpp
20* @brief The fast interpreter for arm
21* @author Michael.Kang blackfin.kang@gmail.com
22* @version 7849
23* @date 2012-03-15
24*/
25 4
26#define CITRA_IGNORE_EXIT(x) 5#define CITRA_IGNORE_EXIT(x)
27 6
28#include <algorithm> 7#include <algorithm>
29#include <map> 8#include <unordered_map>
30#include <stdio.h> 9#include <stdio.h>
31#include <assert.h> 10#include <assert.h>
32#include <cstdio> 11#include <cstdio>
@@ -47,10 +26,6 @@ using namespace std;
47#include "arm_dyncom_thumb.h" 26#include "arm_dyncom_thumb.h"
48#include "arm_dyncom_run.h" 27#include "arm_dyncom_run.h"
49#include "core/arm/skyeye_common/vfp/vfp.h" 28#include "core/arm/skyeye_common/vfp/vfp.h"
50/* shenoubang 2012-6-14 */
51#ifdef __WIN32__
52#include "bank_defs.h"
53#endif
54 29
55#include "core/mem_map.h" 30#include "core/mem_map.h"
56#include "core/hle/hle.h" 31#include "core/hle/hle.h"
@@ -66,327 +41,243 @@ enum {
66 THUMB = (1 << 7) 41 THUMB = (1 << 7)
67}; 42};
68 43
69#define USER_MODE_OPT 1 44#define USER_MODE_OPT 1
70#define HYBRID_MODE 0 // Enable for JIT mode 45#define HYBRID_MODE 0 // Enable for JIT mode
71 46
72#define THRESHOLD 1000 47#define THRESHOLD 1000
73#define DURATION 500 48#define DURATION 500
74//#define PRINT_PROFILE_INFO
75 49
76#define CHECK_RS if(RS == 15) rs += 8 50#define CHECK_RS if(RS == 15) rs += 8
77#define CHECK_RM if(RM == 15) rm += 8 51#define CHECK_RM if(RM == 15) rm += 8
78 52
79//#define BITS(s, a, b) (((s) >> (a)) & ((1 << (1 + (b) - (a))) - 1))
80#undef BITS 53#undef BITS
81#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1)) 54#define BITS(s, a, b) ((s << ((sizeof(s) * 8 - 1) - b)) >> (sizeof(s) * 8 - b + a - 1))
82#define BIT(s, n) ((s >> (n)) & 1) 55#define BIT(s, n) ((s >> (n)) & 1)
83#define RM BITS(sht_oper, 0, 3) 56#define RM BITS(sht_oper, 0, 3)
84#define RS BITS(sht_oper, 8, 11) 57#define RS BITS(sht_oper, 8, 11)
85 58
86#define glue(x, y) x ## y 59#define glue(x, y) x ## y
87#define DPO(s) glue(DataProcessingOperands, s) 60#define DPO(s) glue(DataProcessingOperands, s)
88#define ROTATE_RIGHT(n, i, l) ((n << (l - i)) | (n >> i)) 61#define ROTATE_RIGHT(n, i, l) ((n << (l - i)) | (n >> i))
89#define ROTATE_LEFT(n, i, l) ((n >> (l - i)) | (n << i)) 62#define ROTATE_LEFT(n, i, l) ((n >> (l - i)) | (n << i))
90#define ROTATE_RIGHT_32(n, i) ROTATE_RIGHT(n, i, 32) 63#define ROTATE_RIGHT_32(n, i) ROTATE_RIGHT(n, i, 32)
91#define ROTATE_LEFT_32(n, i) ROTATE_LEFT(n, i, 32) 64#define ROTATE_LEFT_32(n, i) ROTATE_LEFT(n, i, 32)
92 65
93//#define rotr(x,n) ((((x)>>(n))&((1<<(sizeof(x) * 8)-1))|(x<<(sizeof(x)*8-n))))
94//#define rotl(x,n) ((((x)<<(n))&(-(1<<(n))))|(((x)>>(sizeof(x)*8-n))&((1<<(n))-1)))
95#define rotr(x,n) ( (x >> n) | ((x & ((1 << (n + 1)) - 1)) << (32 - n)) ) 66#define rotr(x,n) ( (x >> n) | ((x & ((1 << (n + 1)) - 1)) << (32 - n)) )
96 67
97extern void switch_mode(arm_core_t *core, uint32_t mode); 68extern void switch_mode(arm_core_t *core, uint32_t mode);
98//extern bool InAPrivilegedMode(arm_core_t *core);
99 69
100typedef arm_core_t arm_processor; 70typedef arm_core_t arm_processor;
101typedef unsigned int (*shtop_fp_t)(arm_processor *cpu, unsigned int sht_oper); 71typedef unsigned int (*shtop_fp_t)(arm_processor *cpu, unsigned int sht_oper);
102 72
103/* exclusive memory access */ 73// Exclusive memory access
104static int exclusive_detect(ARMul_State* state, ARMword addr){ 74static int exclusive_detect(ARMul_State* state, ARMword addr){
105 int i; 75 if(state->exclusive_tag == addr)
106 #if 0 76 return 0;
107 for(i = 0; i < 128; i++){ 77 else
108 if(state->exclusive_tag_array[i] == addr) 78 return -1;
109 return 0;
110 }
111 #endif
112 if(state->exclusive_tag == addr)
113 return 0;
114 else
115 return -1;
116} 79}
117 80
118static void add_exclusive_addr(ARMul_State* state, ARMword addr){ 81static void add_exclusive_addr(ARMul_State* state, ARMword addr){
119 int i; 82 state->exclusive_tag = addr;
120 #if 0 83 return;
121 for(i = 0; i < 128; i++){
122 if(state->exclusive_tag_array[i] == 0xffffffff){
123 state->exclusive_tag_array[i] = addr;
124 //DEBUG_LOG(ARM11, "In %s, add addr 0x%x\n", __func__, addr);
125 return;
126 }
127 }
128 DEBUG_LOG(ARM11, "In %s ,can not monitor the addr, out of array\n", __FUNCTION__);
129 #endif
130 state->exclusive_tag = addr;
131 return;
132} 84}
133 85
134static void remove_exclusive(ARMul_State* state, ARMword addr){ 86static void remove_exclusive(ARMul_State* state, ARMword addr){
135 #if 0 87 state->exclusive_tag = 0xFFFFFFFF;
136 int i; 88}
137 for(i = 0; i < 128; i++){ 89
138 if(state->exclusive_tag_array[i] == addr){ 90
139 state->exclusive_tag_array[i] = 0xffffffff; 91unsigned int DPO(Immediate)(arm_processor *cpu, unsigned int sht_oper) {
140 //DEBUG_LOG(ARM11, "In %s, remove addr 0x%x\n", __func__, addr); 92 unsigned int immed_8 = BITS(sht_oper, 0, 7);
141 return; 93 unsigned int rotate_imm = BITS(sht_oper, 8, 11);
142 } 94 unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2);
143 } 95 if (rotate_imm == 0)
144 #endif 96 cpu->shifter_carry_out = cpu->CFlag;
145 state->exclusive_tag = 0xFFFFFFFF; 97 else
146} 98 cpu->shifter_carry_out = BIT(shifter_operand, 31);
147 99 return shifter_operand;
148 100}
149unsigned int DPO(Immediate)(arm_processor *cpu, unsigned int sht_oper) 101
150{ 102unsigned int DPO(Register)(arm_processor *cpu, unsigned int sht_oper) {
151// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); 103 unsigned int rm = CHECK_READ_REG15(cpu, RM);
152 unsigned int immed_8 = BITS(sht_oper, 0, 7); 104 unsigned int shifter_operand = rm;
153 unsigned int rotate_imm = BITS(sht_oper, 8, 11); 105 cpu->shifter_carry_out = cpu->CFlag;
154// DEBUG_LOG(ARM11, "immed_8 is %x\n", immed_8); 106 return shifter_operand;
155// DEBUG_LOG(ARM11, "rotate_imm is %x\n", rotate_imm); 107}
156 unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2);//ROTATE_RIGHT_32(immed_8, rotate_imm * 2); 108
157// DEBUG_LOG(ARM11, "shifter_operand : %x\n", shifter_operand); 109unsigned int DPO(LogicalShiftLeftByImmediate)(arm_processor *cpu, unsigned int sht_oper) {
158 /* set c flag */ 110 int shift_imm = BITS(sht_oper, 7, 11);
159 if (rotate_imm == 0) 111 unsigned int rm = CHECK_READ_REG15(cpu, RM);
160 cpu->shifter_carry_out = cpu->CFlag; 112 unsigned int shifter_operand;
161 else 113 if (shift_imm == 0) {
162 cpu->shifter_carry_out = BIT(shifter_operand, 31); 114 shifter_operand = rm;
163 return shifter_operand; 115 cpu->shifter_carry_out = cpu->CFlag;
164} 116 } else {
165 117 shifter_operand = rm << shift_imm;
166unsigned int DPO(Register)(arm_processor *cpu, unsigned int sht_oper) 118 cpu->shifter_carry_out = BIT(rm, 32 - shift_imm);
167{ 119 }
168// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); 120 return shifter_operand;
169 unsigned int rm = CHECK_READ_REG15(cpu, RM); 121}
170 //if (RM == 15) rm += 8; 122
171 unsigned int shifter_operand = rm; 123unsigned int DPO(LogicalShiftLeftByRegister)(arm_processor *cpu, unsigned int sht_oper) {
172 cpu->shifter_carry_out = cpu->CFlag; 124 int shifter_operand;
173 return shifter_operand; 125 unsigned int rm = CHECK_READ_REG15(cpu, RM);
126 unsigned int rs = CHECK_READ_REG15(cpu, RS);
127 if (BITS(rs, 0, 7) == 0) {
128 shifter_operand = rm;
129 cpu->shifter_carry_out = cpu->CFlag;
130 } else if (BITS(rs, 0, 7) < 32) {
131 shifter_operand = rm << BITS(rs, 0, 7);
132 cpu->shifter_carry_out = BIT(rm, 32 - BITS(rs, 0, 7));
133 } else if (BITS(rs, 0, 7) == 32) {
134 shifter_operand = 0;
135 cpu->shifter_carry_out = BIT(rm, 0);
136 } else {
137 shifter_operand = 0;
138 cpu->shifter_carry_out = 0;
139 }
140 return shifter_operand;
141}
142
143unsigned int DPO(LogicalShiftRightByImmediate)(arm_processor *cpu, unsigned int sht_oper) {
144 unsigned int rm = CHECK_READ_REG15(cpu, RM);
145 unsigned int shifter_operand;
146 int shift_imm = BITS(sht_oper, 7, 11);
147 if (shift_imm == 0) {
148 shifter_operand = 0;
149 cpu->shifter_carry_out = BIT(rm, 31);
150 } else {
151 shifter_operand = rm >> shift_imm;
152 cpu->shifter_carry_out = BIT(rm, shift_imm - 1);
153 }
154 return shifter_operand;
155}
156
157unsigned int DPO(LogicalShiftRightByRegister)(arm_processor *cpu, unsigned int sht_oper) {
158 unsigned int rs = CHECK_READ_REG15(cpu, RS);
159 unsigned int rm = CHECK_READ_REG15(cpu, RM);
160 unsigned int shifter_operand;
161 if (BITS(rs, 0, 7) == 0) {
162 shifter_operand = rm;
163 cpu->shifter_carry_out = cpu->CFlag;
164 } else if (BITS(rs, 0, 7) < 32) {
165 shifter_operand = rm >> BITS(rs, 0, 7);
166 cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 7) - 1);
167 } else if (BITS(rs, 0, 7) == 32) {
168 shifter_operand = 0;
169 cpu->shifter_carry_out = BIT(rm, 31);
170 } else {
171 shifter_operand = 0;
172 cpu->shifter_carry_out = 0;
173 }
174 return shifter_operand;
175}
176
177unsigned int DPO(ArithmeticShiftRightByImmediate)(arm_processor *cpu, unsigned int sht_oper) {
178 unsigned int rm = CHECK_READ_REG15(cpu, RM);
179 unsigned int shifter_operand;
180 int shift_imm = BITS(sht_oper, 7, 11);
181 if (shift_imm == 0) {
182 if (BIT(rm, 31)) {
183 shifter_operand = 0;
184 cpu->shifter_carry_out = BIT(rm, 31);
185 } else {
186 shifter_operand = 0xFFFFFFFF;
187 cpu->shifter_carry_out = BIT(rm, 31);
188 }
189 } else {
190 shifter_operand = static_cast<int>(rm) >> shift_imm;
191 cpu->shifter_carry_out = BIT(rm, shift_imm - 1);
192 }
193 return shifter_operand;
194}
195
196unsigned int DPO(ArithmeticShiftRightByRegister)(arm_processor *cpu, unsigned int sht_oper) {
197 unsigned int rs = CHECK_READ_REG15(cpu, RS);
198 unsigned int rm = CHECK_READ_REG15(cpu, RM);
199 unsigned int shifter_operand;
200 if (BITS(rs, 0, 7) == 0) {
201 shifter_operand = rm;
202 cpu->shifter_carry_out = cpu->CFlag;
203 } else if (BITS(rs, 0, 7) < 32) {
204 shifter_operand = static_cast<int>(rm) >> BITS(rs, 0, 7);
205 cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 7) - 1);
206 } else {
207 if (BIT(rm, 31) == 0)
208 shifter_operand = 0;
209 else
210 shifter_operand = 0xffffffff;
211 cpu->shifter_carry_out = BIT(rm, 31);
212 }
213 return shifter_operand;
214}
215
216unsigned int DPO(RotateRightByImmediate)(arm_processor *cpu, unsigned int sht_oper) {
217 unsigned int shifter_operand;
218 unsigned int rm = CHECK_READ_REG15(cpu, RM);
219 int shift_imm = BITS(sht_oper, 7, 11);
220 if (shift_imm == 0) {
221 shifter_operand = (cpu->CFlag << 31) | (rm >> 1);
222 cpu->shifter_carry_out = BIT(rm, 0);
223 } else {
224 shifter_operand = ROTATE_RIGHT_32(rm, shift_imm);
225 cpu->shifter_carry_out = BIT(rm, shift_imm - 1);
226 }
227 return shifter_operand;
228}
229
230unsigned int DPO(RotateRightByRegister)(arm_processor *cpu, unsigned int sht_oper) {
231 unsigned int rm = CHECK_READ_REG15(cpu, RM);
232 unsigned int rs = CHECK_READ_REG15(cpu, RS);
233 unsigned int shifter_operand;
234 if (BITS(rs, 0, 7) == 0) {
235 shifter_operand = rm;
236 cpu->shifter_carry_out = cpu->CFlag;
237 } else if (BITS(rs, 0, 4) == 0) {
238 shifter_operand = rm;
239 cpu->shifter_carry_out = BIT(rm, 31);
240 } else {
241 shifter_operand = ROTATE_RIGHT_32(rm, BITS(rs, 0, 4));
242 cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 4) - 1);
243 }
244 return shifter_operand;
174} 245}
175 246
176unsigned int DPO(LogicalShiftLeftByImmediate)(arm_processor *cpu, unsigned int sht_oper)
177{
178// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
179 int shift_imm = BITS(sht_oper, 7, 11);
180 unsigned int rm = CHECK_READ_REG15(cpu, RM);
181 //if (RM == 15) rm += 8;
182 unsigned int shifter_operand;
183 if (shift_imm == 0) {
184 shifter_operand = rm;
185 cpu->shifter_carry_out = cpu->CFlag;
186 } else {
187 shifter_operand = rm << shift_imm;
188 cpu->shifter_carry_out = BIT(rm, 32 - shift_imm);
189 }
190 return shifter_operand;
191}
192
193unsigned int DPO(LogicalShiftLeftByRegister)(arm_processor *cpu, unsigned int sht_oper)
194{
195// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
196 int shifter_operand;
197 unsigned int rm = CHECK_READ_REG15(cpu, RM);
198 unsigned int rs = CHECK_READ_REG15(cpu, RS);
199 //if (RM == 15) rm += 8;
200 //if (RS == 15) rs += 8;
201 if (BITS(rs, 0, 7) == 0) {
202 shifter_operand = rm;
203 cpu->shifter_carry_out = cpu->CFlag;
204 } else if (BITS(rs, 0, 7) < 32) {
205 shifter_operand = rm << BITS(rs, 0, 7);
206 cpu->shifter_carry_out = BIT(rm, 32 - BITS(rs, 0, 7));
207 } else if (BITS(rs, 0, 7) == 32) {
208 shifter_operand = 0;
209 cpu->shifter_carry_out = BIT(rm, 0);
210 } else {
211 shifter_operand = 0;
212 cpu->shifter_carry_out = 0;
213 }
214 return shifter_operand;
215}
216
217unsigned int DPO(LogicalShiftRightByImmediate)(arm_processor *cpu, unsigned int sht_oper)
218{
219// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
220 //unsigned int rm = cpu->Reg[RM];
221 unsigned int rm = CHECK_READ_REG15(cpu, RM);
222 //if (RM == 15) rm += 8;
223 unsigned int shifter_operand;
224 int shift_imm = BITS(sht_oper, 7, 11);
225 if (shift_imm == 0) {
226 shifter_operand = 0;
227 cpu->shifter_carry_out = BIT(rm, 31);
228 } else {
229 shifter_operand = rm >> shift_imm;
230 cpu->shifter_carry_out = BIT(rm, shift_imm - 1);
231 }
232 return shifter_operand;
233}
234
235unsigned int DPO(LogicalShiftRightByRegister)(arm_processor *cpu, unsigned int sht_oper)
236{
237// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
238 unsigned int rs = CHECK_READ_REG15(cpu, RS);
239 unsigned int rm = CHECK_READ_REG15(cpu, RM);
240 //if (RS == 15) rs += 8;
241 //if (RM == 15) rm += 8;
242 unsigned int shifter_operand;
243 if (BITS(rs, 0, 7) == 0) {
244 shifter_operand = rm;
245 cpu->shifter_carry_out = cpu->CFlag;
246 } else if (BITS(rs, 0, 7) < 32) {
247 shifter_operand = rm >> BITS(rs, 0, 7);
248 cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 7) - 1);
249 } else if (BITS(rs, 0, 7) == 32) {
250 shifter_operand = 0;
251 cpu->shifter_carry_out = BIT(rm, 31);
252 } else {
253 shifter_operand = 0;
254 cpu->shifter_carry_out = 0;
255 }
256 return shifter_operand;
257}
258
259unsigned int DPO(ArithmeticShiftRightByImmediate)(arm_processor *cpu, unsigned int sht_oper)
260{
261// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
262 //unsigned int rm = cpu->Reg[RM];
263 unsigned int rm = CHECK_READ_REG15(cpu, RM);
264 //if (RM == 15) rm += 8;
265 unsigned int shifter_operand;
266 int shift_imm = BITS(sht_oper, 7, 11);
267 if (shift_imm == 0) {
268 if (BIT(rm, 31)) {
269 shifter_operand = 0;
270 cpu->shifter_carry_out = BIT(rm, 31);
271 } else {
272 shifter_operand = 0xFFFFFFFF;
273 cpu->shifter_carry_out = BIT(rm, 31);
274 }
275 } else {
276 shifter_operand = static_cast<int>(rm) >> shift_imm;
277 cpu->shifter_carry_out = BIT(rm, shift_imm - 1);
278 }
279 return shifter_operand;
280}
281
282unsigned int DPO(ArithmeticShiftRightByRegister)(arm_processor *cpu, unsigned int sht_oper)
283{
284// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
285 //unsigned int rs = cpu->Reg[RS];
286 unsigned int rs = CHECK_READ_REG15(cpu, RS);
287 //unsigned int rm = cpu->Reg[RM];
288 unsigned int rm = CHECK_READ_REG15(cpu, RM);
289 //if (RS == 15) rs += 8;
290 //if (RM == 15) rm += 8;
291 unsigned int shifter_operand;
292 if (BITS(rs, 0, 7) == 0) {
293 shifter_operand = rm;
294 cpu->shifter_carry_out = cpu->CFlag;
295 } else if (BITS(rs, 0, 7) < 32) {
296 shifter_operand = static_cast<int>(rm) >> BITS(rs, 0, 7);
297 cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 7) - 1);
298 } else {
299 if (BIT(rm, 31) == 0) {
300 shifter_operand = 0;
301 } else
302 shifter_operand = 0xffffffff;
303 cpu->shifter_carry_out = BIT(rm, 31);
304 }
305 return shifter_operand;
306}
307
308unsigned int DPO(RotateRightByImmediate)(arm_processor *cpu, unsigned int sht_oper)
309{
310// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
311 unsigned int shifter_operand;
312 //unsigned int rm = cpu->Reg[RM];
313 unsigned int rm = CHECK_READ_REG15(cpu, RM);
314 //if (RM == 15) rm += 8;
315 int shift_imm = BITS(sht_oper, 7, 11);
316 if (shift_imm == 0) {
317 shifter_operand = (cpu->CFlag << 31) |
318 (rm >> 1);
319 cpu->shifter_carry_out = BIT(rm, 0);
320 } else {
321 shifter_operand = ROTATE_RIGHT_32(rm, shift_imm);
322 cpu->shifter_carry_out = BIT(rm, shift_imm - 1);
323 }
324 return shifter_operand;
325}
326
327unsigned int DPO(RotateRightByRegister)(arm_processor *cpu, unsigned int sht_oper)
328{
329// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
330 unsigned int rm = CHECK_READ_REG15(cpu, RM);
331 //if (RM == 15) rm += 8;
332 unsigned int rs = CHECK_READ_REG15(cpu, RS);
333 //if (RS == 15) rs += 8;
334 unsigned int shifter_operand;
335 if (BITS(rs, 0, 7) == 0) {
336 shifter_operand = rm;
337 cpu->shifter_carry_out = cpu->CFlag;
338 } else if (BITS(rs, 0, 4) == 0) {
339 shifter_operand = rm;
340 cpu->shifter_carry_out = BIT(rm, 31);
341 } else {
342 shifter_operand = ROTATE_RIGHT_32(rm, BITS(rs, 0, 4));
343 cpu->shifter_carry_out = BIT(rm, BITS(rs, 0, 4) - 1);
344 }
345 #if 0
346 if (cpu->icounter >= 20371544) {
347 DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__);
348 DEBUG_LOG(ARM11, "RM:%d\nRS:%d\n", RM, RS);
349 DEBUG_LOG(ARM11, "rm:0x%08x\nrs:0x%08x\n", cpu->Reg[RM], cpu->Reg[RS]);
350 }
351 #endif
352 return shifter_operand;
353}
354
355//typedef unsigned int (*get_addr_fp_t)(arm_processor *cpu);
356typedef struct _MiscImmeData { 247typedef struct _MiscImmeData {
357 unsigned int U; 248 unsigned int U;
358 unsigned int Rn; 249 unsigned int Rn;
359 unsigned int offset_8; 250 unsigned int offset_8;
360} MiscLSData; 251} MiscLSData;
361 252
362typedef struct _MiscRegData { 253typedef struct _MiscRegData {
363 unsigned int U; 254 unsigned int U;
364 unsigned int Rn; 255 unsigned int Rn;
365 unsigned int Rm; 256 unsigned int Rm;
366} MiscRegData; 257} MiscRegData;
367 258
368typedef struct _MiscImmePreIdx { 259typedef struct _MiscImmePreIdx {
369 unsigned int offset_8; 260 unsigned int offset_8;
370 unsigned int U; 261 unsigned int U;
371 unsigned int Rn; 262 unsigned int Rn;
372} MiscImmePreIdx; 263} MiscImmePreIdx;
373 264
374typedef struct _MiscRegPreIdx { 265typedef struct _MiscRegPreIdx {
375 unsigned int U; 266 unsigned int U;
376 unsigned int Rn; 267 unsigned int Rn;
377 unsigned int Rm; 268 unsigned int Rm;
378} MiscRegPreIdx; 269} MiscRegPreIdx;
379 270
380typedef struct _MiscImmePstIdx { 271typedef struct _MiscImmePstIdx {
381 unsigned int offset_8; 272 unsigned int offset_8;
382 unsigned int U; 273 unsigned int U;
383 unsigned int Rn; 274 unsigned int Rn;
384} MIscImmePstIdx; 275} MIscImmePstIdx;
385 276
386typedef struct _MiscRegPstIdx { 277typedef struct _MiscRegPstIdx {
387 unsigned int Rn; 278 unsigned int Rn;
388 unsigned int Rm; 279 unsigned int Rm;
389 unsigned int U; 280 unsigned int U;
390} MiscRegPstIdx; 281} MiscRegPstIdx;
391 282
392typedef struct _LSWordorUnsignedByte { 283typedef struct _LSWordorUnsignedByte {
@@ -394,40 +285,38 @@ typedef struct _LSWordorUnsignedByte {
394 285
395#if USER_MODE_OPT 286#if USER_MODE_OPT
396static inline fault_t interpreter_read_memory(addr_t virt_addr, addr_t phys_addr, uint32_t &value, uint32_t size){ 287static inline fault_t interpreter_read_memory(addr_t virt_addr, addr_t phys_addr, uint32_t &value, uint32_t size){
397 switch(size) { 288 switch(size) {
398 case 8: 289 case 8:
399 value = Memory::Read8(virt_addr); 290 value = Memory::Read8(virt_addr);
400 break; 291 break;
401 case 16: 292 case 16:
402 value = Memory::Read16(virt_addr); 293 value = Memory::Read16(virt_addr);
403 break; 294 break;
404 case 32: 295 case 32:
405 value = Memory::Read32(virt_addr); 296 value = Memory::Read32(virt_addr);
406 break; 297 break;
407 } 298 }
408 return NO_FAULT; 299 return NO_FAULT;
409} 300}
410 301
411//static inline void interpreter_write_memory(void *mem_ptr, uint32_t offset, uint32_t value, int size) 302static inline fault_t interpreter_write_memory(addr_t virt_addr, addr_t phys_addr, uint32_t value, uint32_t size) {
412static inline fault_t interpreter_write_memory(addr_t virt_addr, addr_t phys_addr, uint32_t value, uint32_t size) 303 switch(size) {
413{ 304 case 8:
414 switch(size) {
415 case 8:
416 Memory::Write8(virt_addr, value & 0xff); 305 Memory::Write8(virt_addr, value & 0xff);
417 break; 306 break;
418 case 16: 307 case 16:
419 Memory::Write16(virt_addr, value & 0xffff); 308 Memory::Write16(virt_addr, value & 0xffff);
420 break; 309 break;
421 case 32: 310 case 32:
422 Memory::Write32(virt_addr, value); 311 Memory::Write32(virt_addr, value);
423 break; 312 break;
424 } 313 }
425 return NO_FAULT; 314 return NO_FAULT;
426} 315}
427 316
428static inline fault_t check_address_validity(arm_core_t *core, addr_t virt_addr, addr_t *phys_addr, uint32_t rw){ 317static inline fault_t check_address_validity(arm_core_t *core, addr_t virt_addr, addr_t *phys_addr, uint32_t rw) {
429 *phys_addr = virt_addr; 318 *phys_addr = virt_addr;
430 return NO_FAULT; 319 return NO_FAULT;
431} 320}
432 321
433#else 322#else
@@ -440,738 +329,679 @@ fault_t check_address_validity(arm_core_t *core, addr_t virt_addr, addr_t *phys_
440typedef fault_t (*get_addr_fp_t)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw); 329typedef fault_t (*get_addr_fp_t)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw);
441 330
442typedef struct _ldst_inst { 331typedef struct _ldst_inst {
443 unsigned int inst; 332 unsigned int inst;
444 get_addr_fp_t get_addr; 333 get_addr_fp_t get_addr;
445} ldst_inst; 334} ldst_inst;
446#define DEBUG_MSG DEBUG_LOG(ARM11, "in %s %d\n", __FUNCTION__, __LINE__); \ 335#define DEBUG_MSG LOG_DEBUG(Core_ARM11, "inst is %x", inst); CITRA_IGNORE_EXIT(0)
447 DEBUG_LOG(ARM11, "inst is %x\n", inst); \
448 CITRA_IGNORE_EXIT(0)
449 336
450int CondPassed(arm_processor *cpu, unsigned int cond); 337int CondPassed(arm_processor *cpu, unsigned int cond);
451#define LnSWoUB(s) glue(LnSWoUB, s) 338#define LnSWoUB(s) glue(LnSWoUB, s)
452#define MLnS(s) glue(MLnS, s) 339#define MLnS(s) glue(MLnS, s)
453#define LdnStM(s) glue(LdnStM, s) 340#define LdnStM(s) glue(LdnStM, s)
454 341
455#define W_BIT BIT(inst, 21) 342#define W_BIT BIT(inst, 21)
456#define U_BIT BIT(inst, 23) 343#define U_BIT BIT(inst, 23)
457#define I_BIT BIT(inst, 25) 344#define I_BIT BIT(inst, 25)
458#define P_BIT BIT(inst, 24) 345#define P_BIT BIT(inst, 24)
459#define OFFSET_12 BITS(inst, 0, 11) 346#define OFFSET_12 BITS(inst, 0, 11)
460fault_t LnSWoUB(ImmediateOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) 347fault_t LnSWoUB(ImmediateOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
461{ 348 unsigned int Rn = BITS(inst, 16, 19);
462 unsigned int Rn = BITS(inst, 16, 19); 349 unsigned int addr;
463 unsigned int addr; 350 fault_t fault;
464 fault_t fault; 351 if (U_BIT) {
465 if (U_BIT) { 352 addr = CHECK_READ_REG15_WA(cpu, Rn) + OFFSET_12;
466 addr = CHECK_READ_REG15_WA(cpu, Rn) + OFFSET_12; 353 } else {
467 } else { 354 addr = CHECK_READ_REG15_WA(cpu, Rn) - OFFSET_12;
468 addr = CHECK_READ_REG15_WA(cpu, Rn) - OFFSET_12; 355 }
469 } 356 virt_addr = addr;
470 //if (Rn == 15) rn += 8; 357 fault = check_address_validity(cpu, addr, &phys_addr, rw);
471 virt_addr = addr; 358 return fault;
472 fault = check_address_validity(cpu, addr, &phys_addr, rw); 359}
473 return fault; 360
474// return addr; 361fault_t LnSWoUB(RegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
475} 362 fault_t fault;
476 363 unsigned int Rn = BITS(inst, 16, 19);
477fault_t LnSWoUB(RegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) 364 unsigned int Rm = BITS(inst, 0, 3);
478{ 365 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
479 fault_t fault; 366 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
480 unsigned int Rn = BITS(inst, 16, 19); 367 unsigned int addr;
481 unsigned int Rm = BITS(inst, 0, 3); 368 if (U_BIT) {
482 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); 369 addr = rn + rm;
483 //if (Rn == 15) rn += 8; 370 } else {
484 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); 371 addr = rn - rm;
485 //if (Rm == 15) rm += 8; 372 }
486 unsigned int addr; 373 virt_addr = addr;
487 if (U_BIT) { 374 fault = check_address_validity(cpu, addr, &phys_addr, rw);
488 addr = rn + rm; 375 return fault;
489 } else { 376}
490 addr = rn - rm; 377
491 } 378fault_t LnSWoUB(ImmediatePostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
492 virt_addr = addr; 379 fault_t fault;
493 fault = check_address_validity(cpu, addr, &phys_addr, rw); 380 unsigned int Rn = BITS(inst, 16, 19);
494 return fault; 381 unsigned int addr = CHECK_READ_REG15_WA(cpu, Rn);
495} 382
496 383 virt_addr = addr;
497fault_t LnSWoUB(ImmediatePostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) 384 fault = check_address_validity(cpu, addr, &phys_addr, rw);
498{ 385 if (fault) return fault;
499 fault_t fault; 386
500 unsigned int Rn = BITS(inst, 16, 19); 387 if (U_BIT) {
501 unsigned int addr = CHECK_READ_REG15_WA(cpu, Rn); 388 cpu->Reg[Rn] += OFFSET_12;
502 //if (Rn == 15) addr += 8; 389 } else {
390 cpu->Reg[Rn] -= OFFSET_12;
391 }
392 return fault;
393}
503 394
504 virt_addr = addr; 395fault_t LnSWoUB(ImmediatePreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
505 fault = check_address_validity(cpu, addr, &phys_addr, rw); 396 fault_t fault;
506 if (fault) return fault; 397 unsigned int Rn = BITS(inst, 16, 19);
398 unsigned int addr;
399 if (U_BIT) {
400 addr = CHECK_READ_REG15_WA(cpu, Rn) + OFFSET_12;
401 } else {
402 addr = CHECK_READ_REG15_WA(cpu, Rn) - OFFSET_12;
403 }
404
405 virt_addr = addr;
406 fault = check_address_validity(cpu, addr, &phys_addr, rw);
407 if (fault) return fault;
507 408
508 if (U_BIT) { 409 if (CondPassed(cpu, BITS(inst, 28, 31))) {
509 cpu->Reg[Rn] += OFFSET_12; 410 cpu->Reg[Rn] = addr;
510 } else { 411 }
511 cpu->Reg[Rn] -= OFFSET_12; 412 return fault;
512 } 413}
513 return fault; 414
415fault_t MLnS(RegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
416 fault_t fault;
417 unsigned int addr;
418 unsigned int Rn = BITS(inst, 16, 19);
419 unsigned int Rm = BITS(inst, 0, 3);
420 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
421 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
422
423 if (U_BIT) {
424 addr = rn + rm;
425 } else
426 addr = rn - rm;
427 if(BIT(inst, 20)){ // L BIT
428 }
429 if(BIT(inst, 6)){ // Sign Bit
430 }
431 if(BIT(inst, 5)){ // Half Bit
432 }
433
434 virt_addr = addr;
435 fault = check_address_validity(cpu, addr, &phys_addr, rw);
436 if (fault) return fault;
437
438 if (CondPassed(cpu, BITS(inst, 28, 31))) {
439 cpu->Reg[Rn] = addr;
440 }
441 return fault;
442}
443
444fault_t LnSWoUB(RegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
445 fault_t fault;
446 unsigned int Rn = BITS(inst, 16, 19);
447 unsigned int Rm = BITS(inst, 0, 3);
448 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
449 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
450 unsigned int addr;
451 if (U_BIT) {
452 addr = rn + rm;
453 } else {
454 addr = rn - rm;
455 }
456 virt_addr = addr;
457 fault = check_address_validity(cpu, addr, &phys_addr, rw);
458 if(fault)
459 return fault;
460 if (CondPassed(cpu, BITS(inst, 28, 31))) {
461 cpu->Reg[Rn] = addr;
462 }
463 return fault;
464}
465fault_t LnSWoUB(ScaledRegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
466 fault_t fault;
467 unsigned int shift = BITS(inst, 5, 6);
468 unsigned int shift_imm = BITS(inst, 7, 11);
469 unsigned int Rn = BITS(inst, 16, 19);
470 unsigned int Rm = BITS(inst, 0, 3);
471 unsigned int index;
472 unsigned int addr;
473
474 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
475 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
476
477 switch (shift) {
478 case 0:
479 index = rm << shift_imm;
480 break;
481 case 1:
482 if (shift_imm == 0) {
483 index = 0;
484 } else {
485 index = rm >> shift_imm;
486 }
487 break;
488 case 2:
489 DEBUG_MSG;
490 break;
491 case 3:
492 DEBUG_MSG;
493 break;
494 }
495 if (U_BIT) {
496 addr = rn + index;
497 } else
498 addr = rn - index;
499 virt_addr = addr;
500 fault = check_address_validity(cpu, addr, &phys_addr, rw);
501 if(fault)
502 return fault;
503 if (CondPassed(cpu, BITS(inst, 28, 31))) {
504 cpu->Reg[Rn] = addr;
505 }
506
507 return fault;
508}
509
510fault_t LnSWoUB(ScaledRegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
511 fault_t fault;
512 unsigned int shift = BITS(inst, 5, 6);
513 unsigned int shift_imm = BITS(inst, 7, 11);
514 unsigned int Rn = BITS(inst, 16, 19);
515 unsigned int Rm = BITS(inst, 0, 3);
516 unsigned int index;
517 unsigned int addr;
518
519 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
520 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
521 addr = rn;
522 switch (shift) {
523 case 0:
524 index = rm << shift_imm;
525 break;
526 case 1:
527 if (shift_imm == 0) {
528 index = 0;
529 } else {
530 index = rm >> shift_imm;
531 }
532 break;
533 case 2:
534 DEBUG_MSG;
535 break;
536 case 3:
537 DEBUG_MSG;
538 break;
539 }
540 virt_addr = addr;
541 fault = check_address_validity(cpu, addr, &phys_addr, rw);
542 if(fault)
543 return fault;
544 if (CondPassed(cpu, BITS(inst, 28, 31))) {
545 if (U_BIT)
546 cpu->Reg[Rn] += index;
547 else
548 cpu->Reg[Rn] -= index;
549 }
550
551 return fault;
514} 552}
515 553
516fault_t LnSWoUB(ImmediatePreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) 554fault_t LnSWoUB(RegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
517{ 555 fault_t fault;
518 fault_t fault; 556 unsigned int Rn = BITS(inst, 16, 19);
519 unsigned int Rn = BITS(inst, 16, 19); 557 unsigned int Rm = BITS(inst, 0, 3);
520 unsigned int addr; 558 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
521 if (U_BIT) { 559 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
522 addr = CHECK_READ_REG15_WA(cpu, Rn) + OFFSET_12; 560
523 } else { 561 unsigned int addr = rn;
524 addr = CHECK_READ_REG15_WA(cpu, Rn) - OFFSET_12; 562 virt_addr = addr;
525 } 563 fault = check_address_validity(cpu, addr, &phys_addr, rw);
526 #if 0 564 if (fault) return fault;
527 if (Rn == 15) { 565
528 addr += 8; 566 if (CondPassed(cpu, BITS(inst, 28, 31))) {
529 } 567 if (U_BIT) {
530 #endif 568 cpu->Reg[Rn] += rm;
531 569 } else {
532 virt_addr = addr; 570 cpu->Reg[Rn] -= rm;
533 fault = check_address_validity(cpu, addr, &phys_addr, rw); 571 }
534 if (fault) return fault; 572 }
535 573 return fault;
536 if (CondPassed(cpu, BITS(inst, 28, 31))) { 574}
537 cpu->Reg[Rn] = addr; 575
538 } 576fault_t MLnS(ImmediateOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
539 return fault; 577 fault_t fault;
540} 578 unsigned int immedL = BITS(inst, 0, 3);
541 579 unsigned int immedH = BITS(inst, 8, 11);
542fault_t MLnS(RegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) 580
543{ 581 unsigned int Rn = BITS(inst, 16, 19);
544 fault_t fault; 582 unsigned int addr;
545 unsigned int addr; 583
546 unsigned int Rn = BITS(inst, 16, 19); 584 unsigned int offset_8 = (immedH << 4) | immedL;
547 unsigned int Rm = BITS(inst, 0, 3); 585 if (U_BIT) {
548 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); 586 addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8;
549 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); 587 } else
550 //if (Rn == 15) rn += 8; 588 addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8;
551 //if (Rm == 15) rm += 8; 589
552 if (U_BIT) { 590 virt_addr = addr;
553 addr = rn + rm; 591 fault = check_address_validity(cpu, addr, &phys_addr, rw);
554 } else 592 return fault;
555 addr = rn - rm; 593}
556 if(BIT(inst, 20)){ /* L BIT */ 594
557 } 595fault_t MLnS(RegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
558 if(BIT(inst, 6)){ /* Sign Bit */ 596 fault_t fault;
559 } 597 unsigned int addr;
560 if(BIT(inst, 5)){ /* Half Bit */ 598 unsigned int Rn = BITS(inst, 16, 19);
561 } 599 unsigned int Rm = BITS(inst, 0, 3);
562 600 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
563 virt_addr = addr; 601 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
564 fault = check_address_validity(cpu, addr, &phys_addr, rw); 602 if (U_BIT) {
565 if (fault) return fault; 603 addr = rn + rm;
566 604 } else
567 if (CondPassed(cpu, BITS(inst, 28, 31))) { 605 addr = rn - rm;
568 cpu->Reg[Rn] = addr; 606 if(BIT(inst, 20)){ // L BIT
569 } 607 }
570 return fault; 608 if(BIT(inst, 6)){ // Sign Bit
571} 609 }
572 610 if(BIT(inst, 5)){ // Half Bit
573fault_t LnSWoUB(RegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) 611 }
574{ 612 virt_addr = addr;
575 fault_t fault; 613 fault = check_address_validity(cpu, addr, &phys_addr, rw);
576 unsigned int Rn = BITS(inst, 16, 19); 614 return fault;
577 unsigned int Rm = BITS(inst, 0, 3); 615}
578 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); 616
579 //if (Rn == 15) rn += 8; 617fault_t MLnS(ImmediatePreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
580 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); 618 fault_t fault;
581 //if (Rm == 15) rm += 8; 619 unsigned int Rn = BITS(inst, 16, 19);
582 unsigned int addr; 620 unsigned int immedH = BITS(inst, 8, 11);
583 if (U_BIT) { 621 unsigned int immedL = BITS(inst, 0, 3);
584 addr = rn + rm; 622 unsigned int addr;
585 } else { 623 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
586 addr = rn - rm; 624 unsigned int offset_8 = (immedH << 4) | immedL;
587 } 625
588 virt_addr = addr; 626 if (U_BIT) {
589 fault = check_address_validity(cpu, addr, &phys_addr, rw); 627 addr = rn + offset_8;
590 if(fault) 628 } else
591 return fault; 629 addr = rn - offset_8;
592 if (CondPassed(cpu, BITS(inst, 28, 31))) { 630
593 cpu->Reg[Rn] = addr; 631 virt_addr = addr;
594 } 632 fault = check_address_validity(cpu, addr, &phys_addr, rw);
595 return fault; 633 if (fault) return fault;
596} 634
597fault_t LnSWoUB(ScaledRegisterPreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) 635 if (CondPassed(cpu, BITS(inst, 28, 31))) {
598{ 636 cpu->Reg[Rn] = addr;
599 fault_t fault; 637 }
600 unsigned int shift = BITS(inst, 5, 6); 638 return fault;
601 unsigned int shift_imm = BITS(inst, 7, 11); 639}
602 unsigned int Rn = BITS(inst, 16, 19); 640
603 unsigned int Rm = BITS(inst, 0, 3); 641fault_t MLnS(ImmediatePostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
604 unsigned int index; 642 fault_t fault;
605 unsigned int addr; 643 unsigned int Rn = BITS(inst, 16, 19);
606 644 unsigned int immedH = BITS(inst, 8, 11);
607 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); 645 unsigned int immedL = BITS(inst, 0, 3);
608 //if (Rm == 15) rm += 8; 646 unsigned int addr;
609 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); 647 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
610 //if (Rn == 15) rn += 8; 648 addr = rn;
611 switch (shift) { 649
612 case 0: 650 virt_addr = addr;
613 //DEBUG_MSG; 651 fault = check_address_validity(cpu, addr, &phys_addr, rw);
614 index = rm << shift_imm; 652 if (fault) return fault;
615 break; 653
616 case 1: 654 if (CondPassed(cpu, BITS(inst, 28, 31))) {
617// DEBUG_MSG; 655 unsigned int offset_8 = (immedH << 4) | immedL;
618 if (shift_imm == 0) { 656 if (U_BIT) {
619 index = 0; 657 rn += offset_8;
620 } else { 658 } else {
621 index = rm >> shift_imm; 659 rn -= offset_8;
622 } 660 }
623 break; 661 cpu->Reg[Rn] = rn;
624 case 2: 662 }
625 DEBUG_MSG; 663
626 break; 664 return fault;
627 case 3: 665}
628 DEBUG_MSG; 666fault_t MLnS(RegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
629 break; 667 fault_t fault;
630 } 668 unsigned int Rn = BITS(inst, 16, 19);
631 if (U_BIT) { 669 unsigned int Rm = BITS(inst, 0, 3);
632 addr = rn + index; 670 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
633 } else 671 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
634 addr = rn - index; 672 unsigned int addr = rn;
635 virt_addr = addr; 673
636 fault = check_address_validity(cpu, addr, &phys_addr, rw); 674 virt_addr = addr;
637 if(fault) 675 fault = check_address_validity(cpu, addr, &phys_addr, rw);
638 return fault; 676 if (fault) return fault;
639 if (CondPassed(cpu, BITS(inst, 28, 31))) { 677
640 cpu->Reg[Rn] = addr; 678 if (CondPassed(cpu, BITS(inst, 28, 31))) {
641 } 679 if (U_BIT) {
642 680 cpu->Reg[Rn] += rm;
643 return fault; 681 } else {
644} 682 cpu->Reg[Rn] -= rm;
645 683 }
646fault_t LnSWoUB(ScaledRegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) 684 }
647{ 685 return fault;
648 fault_t fault; 686}
649 unsigned int shift = BITS(inst, 5, 6); 687
650 unsigned int shift_imm = BITS(inst, 7, 11); 688fault_t LdnStM(DecrementBefore)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
651 unsigned int Rn = BITS(inst, 16, 19); 689 fault_t fault;
652 unsigned int Rm = BITS(inst, 0, 3); 690 unsigned int Rn = BITS(inst, 16, 19);
653 unsigned int index; 691 unsigned int i = BITS(inst, 0, 15);
654 unsigned int addr; 692 int count = 0;
655 693 while(i) {
656 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); 694 if(i & 1) count ++;
657 //if (Rm == 15) rm += 8; 695 i = i >> 1;
658 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); 696 }
659 //if (Rn == 15) rn += 8; 697 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
660 addr = rn; 698 unsigned int start_addr = rn - count * 4;
661 switch (shift) { 699 unsigned int end_addr = rn - 4;
662 case 0: 700
663 //DEBUG_MSG; 701 fault = check_address_validity(cpu, end_addr, &phys_addr, rw);
664 index = rm << shift_imm; 702 virt_addr = end_addr;
665 break; 703 if (fault) return fault;
666 case 1: 704
667// DEBUG_MSG; 705 fault = check_address_validity(cpu, start_addr, &phys_addr, rw);
668 if (shift_imm == 0) { 706 virt_addr = start_addr;
669 index = 0; 707 if (fault) return fault;
670 } else { 708
671 index = rm >> shift_imm; 709 if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
672 } 710 cpu->Reg[Rn] -= count * 4;
673 break; 711 }
674 case 2: 712
675 DEBUG_MSG; 713 return fault;
676 break; 714}
677 case 3: 715
678 DEBUG_MSG; 716fault_t LdnStM(IncrementBefore)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
679 break; 717 fault_t fault;
680 } 718 unsigned int Rn = BITS(inst, 16, 19);
681 virt_addr = addr; 719 unsigned int i = BITS(inst, 0, 15);
682 fault = check_address_validity(cpu, addr, &phys_addr, rw); 720 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
683 if(fault) 721 int count = 0;
684 return fault; 722 while(i) {
685 if (CondPassed(cpu, BITS(inst, 28, 31))) { 723 if(i & 1) count ++;
686 if (U_BIT) 724 i = i >> 1;
687 cpu->Reg[Rn] += index; 725 }
688 else 726
689 cpu->Reg[Rn] -= index; 727 unsigned int start_addr = rn + 4;
690 } 728 unsigned int end_addr = rn + count * 4;
691 729
692 return fault; 730 fault = check_address_validity(cpu, end_addr, &phys_addr, rw);
693} 731 virt_addr = end_addr;
694 732 if (fault) return fault;
695fault_t LnSWoUB(RegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) 733
696{ 734 fault = check_address_validity(cpu, start_addr, &phys_addr, rw);
697 fault_t fault; 735 virt_addr = start_addr;
698 unsigned int Rn = BITS(inst, 16, 19); 736 if (fault) return fault;
699 unsigned int Rm = BITS(inst, 0, 3); 737
700 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); 738 if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
701 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); 739 cpu->Reg[Rn] += count * 4;
702 740 }
703 unsigned int addr = rn; 741 return fault;
704 virt_addr = addr; 742}
705 fault = check_address_validity(cpu, addr, &phys_addr, rw); 743
706 if (fault) return fault; 744fault_t LdnStM(IncrementAfter)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
707 745 fault_t fault;
708 if (CondPassed(cpu, BITS(inst, 28, 31))) { 746 unsigned int Rn = BITS(inst, 16, 19);
709 if (U_BIT) { 747 unsigned int i = BITS(inst, 0, 15);
710 cpu->Reg[Rn] += rm; 748 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
711 } else { 749 int count = 0;
712 cpu->Reg[Rn] -= rm; 750 while(i) {
713 } 751 if(i & 1) count ++;
714 } 752 i = i >> 1;
715 return fault; 753 }
716} 754 unsigned int start_addr = rn;
717 755 unsigned int end_addr = rn + count * 4 - 4;
718fault_t MLnS(ImmediateOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) 756
719{ 757 fault = check_address_validity(cpu, end_addr, &phys_addr, rw);
720 fault_t fault; 758 virt_addr = end_addr;
721 unsigned int immedL = BITS(inst, 0, 3); 759 if (fault) return fault;
722 unsigned int immedH = BITS(inst, 8, 11); 760
723 761 fault = check_address_validity(cpu, start_addr, &phys_addr, rw);
724 unsigned int Rn = BITS(inst, 16, 19); 762 virt_addr = start_addr;
725 unsigned int addr; 763 if (fault) return fault;
726 764
727 unsigned int offset_8 = (immedH << 4) | immedL; 765 if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
728 if (U_BIT) { 766 cpu->Reg[Rn] += count * 4;
729 addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8; 767 }
730 } else 768 return fault;
731 addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8; 769}
732 #if 0 770
733 if (Rn == 15) { 771fault_t LdnStM(DecrementAfter)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
734 addr += 8; 772 fault_t fault;
735 } 773 unsigned int Rn = BITS(inst, 16, 19);
736 #endif 774 unsigned int i = BITS(inst, 0, 15);
737 virt_addr = addr; 775 int count = 0;
738 fault = check_address_validity(cpu, addr, &phys_addr, rw); 776 while(i) {
739 return fault; 777 if(i & 1) count ++;
740} 778 i = i >> 1;
741 779 }
742fault_t MLnS(RegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) 780 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
743{ 781 unsigned int start_addr = rn - count * 4 + 4;
744 fault_t fault; 782 unsigned int end_addr = rn;
745 unsigned int addr; 783
746 unsigned int Rn = BITS(inst, 16, 19); 784 fault = check_address_validity(cpu, end_addr, &phys_addr, rw);
747 unsigned int Rm = BITS(inst, 0, 3); 785 virt_addr = end_addr;
748 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); 786 if (fault) return fault;
749 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm); 787
750 //if (Rn == 15) rn += 8; 788 fault = check_address_validity(cpu, start_addr, &phys_addr, rw);
751 //if (Rm == 15) rm += 8; 789 if (fault) return fault;
752 if (U_BIT) { 790 virt_addr = start_addr;
753 addr = rn + rm; 791
754 } else 792 if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
755 addr = rn - rm; 793 cpu->Reg[Rn] -= count * 4;
756 if(BIT(inst, 20)){ /* L BIT */ 794 }
757 } 795 return fault;
758 if(BIT(inst, 6)){ /* Sign Bit */ 796}
759 } 797
760 if(BIT(inst, 5)){ /* Half Bit */ 798fault_t LnSWoUB(ScaledRegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) {
761 } 799 fault_t fault;
762 virt_addr = addr; 800 unsigned int shift = BITS(inst, 5, 6);
763 fault = check_address_validity(cpu, addr, &phys_addr, rw); 801 unsigned int shift_imm = BITS(inst, 7, 11);
764 return fault; 802 unsigned int Rn = BITS(inst, 16, 19);
765} 803 unsigned int Rm = BITS(inst, 0, 3);
766 804 unsigned int index;
767fault_t MLnS(ImmediatePreIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) 805 unsigned int addr;
768{ 806
769 fault_t fault; 807 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
770 unsigned int Rn = BITS(inst, 16, 19); 808 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
771 unsigned int immedH = BITS(inst, 8, 11); 809 switch (shift) {
772 unsigned int immedL = BITS(inst, 0, 3); 810 case 0:
773 unsigned int addr; 811 index = rm << shift_imm;
774 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); 812 break;
775 //if (Rn == 15) rn += 8; 813 case 1:
776 814 if (shift_imm == 0) {
777// DEBUG_LOG(ARM11, "in %s\n", __FUNCTION__); 815 index = 0;
778 unsigned int offset_8 = (immedH << 4) | immedL; 816 } else {
779 if (U_BIT) { 817 index = rm >> shift_imm;
780 addr = rn + offset_8; 818 }
781 } else 819 break;
782 addr = rn - offset_8; 820 case 2:
783 821 if (shift_imm == 0){ // ASR #32
784 virt_addr = addr; 822 if (rm >> 31)
785 fault = check_address_validity(cpu, addr, &phys_addr, rw); 823 index = 0xFFFFFFFF;
786 if (fault) return fault; 824 else
787 825 index = 0;
788 if (CondPassed(cpu, BITS(inst, 28, 31))) { 826 }
789 cpu->Reg[Rn] = addr; 827 else {
790 } 828 index = static_cast<int>(rm) >> shift_imm;
791 return fault; 829 }
792} 830 break;
793 831 case 3:
794fault_t MLnS(ImmediatePostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw) 832 DEBUG_MSG;
795{ 833 break;
796 fault_t fault; 834 }
797 unsigned int Rn = BITS(inst, 16, 19); 835 if (U_BIT) {
798 unsigned int immedH = BITS(inst, 8, 11); 836 addr = rn + index;
799 unsigned int immedL = BITS(inst, 0, 3); 837 } else
800 unsigned int addr; 838 addr = rn - index;
801 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn); 839
802 addr = rn; 840 virt_addr = addr;
803 841 fault = check_address_validity(cpu, addr, &phys_addr, rw);
804 virt_addr = addr; 842
805 fault = check_address_validity(cpu, addr, &phys_addr, rw); 843 return fault;
806 if (fault) return fault; 844}
807 845
808 if (CondPassed(cpu, BITS(inst, 28, 31))) { 846#define ISNEG(n) (n < 0)
809 unsigned int offset_8 = (immedH << 4) | immedL; 847#define ISPOS(n) (n >= 0)
810 if (U_BIT) {
811 rn += offset_8;
812 } else {
813 rn -= offset_8;
814 }
815 cpu->Reg[Rn] = rn;
816 }
817
818 return fault;
819}
820fault_t MLnS(RegisterPostIndexed)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
821{
822 fault_t fault;
823 unsigned int Rn = BITS(inst, 16, 19);
824 unsigned int Rm = BITS(inst, 0, 3);
825 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
826 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
827
828 unsigned int addr = rn;
829 virt_addr = addr;
830 fault = check_address_validity(cpu, addr, &phys_addr, rw);
831 if (fault) return fault;
832
833 if (CondPassed(cpu, BITS(inst, 28, 31))) {
834 if (U_BIT) {
835 cpu->Reg[Rn] += rm;
836 } else {
837 cpu->Reg[Rn] -= rm;
838 }
839 }
840 return fault;
841}
842
843fault_t LdnStM(DecrementBefore)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
844{
845 fault_t fault;
846 unsigned int Rn = BITS(inst, 16, 19);
847 unsigned int i = BITS(inst, 0, 15);
848 int count = 0;
849 while(i) {
850 if(i & 1) count ++;
851 i = i >> 1;
852 }
853 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
854 //if (Rn == 15) rn += 8;
855 unsigned int start_addr = rn - count * 4;
856 unsigned int end_addr = rn - 4;
857
858 fault = check_address_validity(cpu, end_addr, &phys_addr, rw);
859 virt_addr = end_addr;
860 if (fault) return fault;
861
862 fault = check_address_validity(cpu, start_addr, &phys_addr, rw);
863 virt_addr = start_addr;
864 if (fault) return fault;
865
866 if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
867 cpu->Reg[Rn] -= count * 4;
868 }
869
870 return fault;
871}
872
873fault_t LdnStM(IncrementBefore)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
874{
875 fault_t fault;
876 unsigned int Rn = BITS(inst, 16, 19);
877 unsigned int i = BITS(inst, 0, 15);
878 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
879 //if (Rn == 15) rn += 8;
880 int count = 0;
881 while(i) {
882 if(i & 1) count ++;
883 i = i >> 1;
884 }
885
886 unsigned int start_addr = rn + 4;
887 unsigned int end_addr = rn + count * 4;
888
889 fault = check_address_validity(cpu, end_addr, &phys_addr, rw);
890 virt_addr = end_addr;
891 if (fault) return fault;
892
893 fault = check_address_validity(cpu, start_addr, &phys_addr, rw);
894 virt_addr = start_addr;
895 if (fault) return fault;
896
897 if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
898 cpu->Reg[Rn] += count * 4;
899 }
900 return fault;
901}
902
903fault_t LdnStM(IncrementAfter)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
904{
905 fault_t fault;
906 unsigned int Rn = BITS(inst, 16, 19);
907 unsigned int i = BITS(inst, 0, 15);
908 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
909 int count = 0;
910 while(i) {
911 if(i & 1) count ++;
912 i = i >> 1;
913 }
914 //if (Rn == 15) rn += 8;
915 unsigned int start_addr = rn;
916 unsigned int end_addr = rn + count * 4 - 4;
917
918 fault = check_address_validity(cpu, end_addr, &phys_addr, rw);
919 virt_addr = end_addr;
920 if (fault) return fault;
921
922 fault = check_address_validity(cpu, start_addr, &phys_addr, rw);
923 virt_addr = start_addr;
924 if (fault) return fault;
925
926 if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
927 cpu->Reg[Rn] += count * 4;
928 }
929 return fault;
930}
931
932fault_t LdnStM(DecrementAfter)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
933{
934 fault_t fault;
935 unsigned int Rn = BITS(inst, 16, 19);
936 unsigned int i = BITS(inst, 0, 15);
937 int count = 0;
938 while(i) {
939 if(i & 1) count ++;
940 i = i >> 1;
941 }
942 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
943 //if (Rn == 15) rn += 8;
944 unsigned int start_addr = rn - count * 4 + 4;
945 unsigned int end_addr = rn;
946
947 fault = check_address_validity(cpu, end_addr, &phys_addr, rw);
948 virt_addr = end_addr;
949 if (fault) return fault;
950
951 fault = check_address_validity(cpu, start_addr, &phys_addr, rw);
952 if (fault) return fault;
953 virt_addr = start_addr;
954
955 if (CondPassed(cpu, BITS(inst, 28, 31)) && BIT(inst, 21)) {
956 cpu->Reg[Rn] -= count * 4;
957 }
958 return fault;
959}
960
961fault_t LnSWoUB(ScaledRegisterOffset)(arm_processor *cpu, unsigned int inst, unsigned int &virt_addr, unsigned int &phys_addr, unsigned int rw)
962{
963 fault_t fault;
964 unsigned int shift = BITS(inst, 5, 6);
965 unsigned int shift_imm = BITS(inst, 7, 11);
966 unsigned int Rn = BITS(inst, 16, 19);
967 unsigned int Rm = BITS(inst, 0, 3);
968 unsigned int index;
969 unsigned int addr;
970
971 unsigned int rm = CHECK_READ_REG15_WA(cpu, Rm);
972 //if (Rm == 15) rm += 8;
973 unsigned int rn = CHECK_READ_REG15_WA(cpu, Rn);
974 //if (Rn == 15) rn += 8;
975 switch (shift) {
976 case 0:
977 //DEBUG_MSG;
978 index = rm << shift_imm;
979 break;
980 case 1:
981// DEBUG_MSG;
982 if (shift_imm == 0) {
983 index = 0;
984 } else {
985 index = rm >> shift_imm;
986 }
987 break;
988 case 2:
989 if (shift_imm == 0){ /* ASR #32 */
990 if (rm >> 31)
991 index = 0xFFFFFFFF;
992 else
993 index = 0;
994 }
995 else {
996 index = static_cast<int>(rm) >> shift_imm;
997 }
998 break;
999 case 3:
1000 DEBUG_MSG;
1001 break;
1002 }
1003 if (U_BIT) {
1004 addr = rn + index;
1005 } else
1006 addr = rn - index;
1007 virt_addr = addr;
1008 fault = check_address_validity(cpu, addr, &phys_addr, rw);
1009 return fault;
1010}
1011
1012#define ISNEG(n) (n < 0)
1013#define ISPOS(n) (n >= 0)
1014
1015//enum {
1016// COND = (1 << 0),
1017// NON_BRANCH = (1 << 1),
1018// DIRECT_BRANCH = (1 << 2),
1019// INDIRECT_BRANCH = (1 << 3),
1020// CALL = (1 << 4),
1021// RET = (1 << 5),
1022// END_OF_PAGE = (1 << 6),
1023// THUMB = (1 << 7)
1024//};
1025 848
1026typedef struct _arm_inst { 849typedef struct _arm_inst {
1027 unsigned int idx; 850 unsigned int idx;
1028 unsigned int cond; 851 unsigned int cond;
1029 int br; 852 int br;
1030 int load_r15; 853 int load_r15;
1031 char component[0]; 854 char component[0];
1032} arm_inst; 855} arm_inst;
1033 856
857typedef struct generic_arm_inst {
858 u32 Ra;
859 u32 Rm;
860 u32 Rn;
861 u32 Rd;
862 u8 op1;
863 u8 op2;
864} generic_arm_inst;
865
1034typedef struct _adc_inst { 866typedef struct _adc_inst {
1035 unsigned int I; 867 unsigned int I;
1036 unsigned int S; 868 unsigned int S;
1037 unsigned int Rn; 869 unsigned int Rn;
1038 unsigned int Rd; 870 unsigned int Rd;
1039 unsigned int shifter_operand; 871 unsigned int shifter_operand;
1040 shtop_fp_t shtop_func; 872 shtop_fp_t shtop_func;
1041} adc_inst; 873} adc_inst;
1042 874
1043typedef struct _add_inst { 875typedef struct _add_inst {
1044 unsigned int I; 876 unsigned int I;
1045 unsigned int S; 877 unsigned int S;
1046 unsigned int Rn; 878 unsigned int Rn;
1047 unsigned int Rd; 879 unsigned int Rd;
1048 unsigned int shifter_operand; 880 unsigned int shifter_operand;
1049 shtop_fp_t shtop_func; 881 shtop_fp_t shtop_func;
1050} add_inst; 882} add_inst;
1051 883
1052typedef struct _orr_inst { 884typedef struct _orr_inst {
1053 unsigned int I; 885 unsigned int I;
1054 unsigned int S; 886 unsigned int S;
1055 unsigned int Rn; 887 unsigned int Rn;
1056 unsigned int Rd; 888 unsigned int Rd;
1057 unsigned int shifter_operand; 889 unsigned int shifter_operand;
1058 shtop_fp_t shtop_func; 890 shtop_fp_t shtop_func;
1059} orr_inst; 891} orr_inst;
1060 892
1061typedef struct _and_inst { 893typedef struct _and_inst {
1062 unsigned int I; 894 unsigned int I;
1063 unsigned int S; 895 unsigned int S;
1064 unsigned int Rn; 896 unsigned int Rn;
1065 unsigned int Rd; 897 unsigned int Rd;
1066 unsigned int shifter_operand; 898 unsigned int shifter_operand;
1067 shtop_fp_t shtop_func; 899 shtop_fp_t shtop_func;
1068} and_inst; 900} and_inst;
1069 901
1070typedef struct _eor_inst { 902typedef struct _eor_inst {
1071 unsigned int I; 903 unsigned int I;
1072 unsigned int S; 904 unsigned int S;
1073 unsigned int Rn; 905 unsigned int Rn;
1074 unsigned int Rd; 906 unsigned int Rd;
1075 unsigned int shifter_operand; 907 unsigned int shifter_operand;
1076 shtop_fp_t shtop_func; 908 shtop_fp_t shtop_func;
1077} eor_inst; 909} eor_inst;
1078 910
1079typedef struct _bbl_inst { 911typedef struct _bbl_inst {
1080 unsigned int L; 912 unsigned int L;
1081 int signed_immed_24; 913 int signed_immed_24;
1082 unsigned int next_addr; 914 unsigned int next_addr;
1083 unsigned int jmp_addr; 915 unsigned int jmp_addr;
1084} bbl_inst; 916} bbl_inst;
1085 917
1086typedef struct _bx_inst { 918typedef struct _bx_inst {
1087 unsigned int Rm; 919 unsigned int Rm;
1088} bx_inst; 920} bx_inst;
1089 921
1090typedef struct _blx_inst { 922typedef struct _blx_inst {
1091 union { 923 union {
1092 int32_t signed_immed_24; 924 int32_t signed_immed_24;
1093 uint32_t Rm; 925 uint32_t Rm;
1094 } val; 926 } val;
1095 unsigned int inst; 927 unsigned int inst;
1096} blx_inst; 928} blx_inst;
1097 929
1098typedef struct _clz_inst { 930typedef struct _clz_inst {
1099 unsigned int Rm; 931 unsigned int Rm;
1100 unsigned int Rd; 932 unsigned int Rd;
1101} clz_inst; 933} clz_inst;
1102 934
1103typedef struct _cps_inst { 935typedef struct _cps_inst {
1104 unsigned int imod0; 936 unsigned int imod0;
1105 unsigned int imod1; 937 unsigned int imod1;
1106 unsigned int mmod; 938 unsigned int mmod;
1107 unsigned int A, I, F; 939 unsigned int A, I, F;
1108 unsigned int mode; 940 unsigned int mode;
1109} cps_inst; 941} cps_inst;
1110 942
1111typedef struct _clrex_inst { 943typedef struct _clrex_inst {
1112} clrex_inst; 944} clrex_inst;
1113 945
1114typedef struct _cpy_inst { 946typedef struct _cpy_inst {
1115 unsigned int Rm; 947 unsigned int Rm;
1116 unsigned int Rd; 948 unsigned int Rd;
1117} cpy_inst; 949} cpy_inst;
1118 950
1119typedef struct _bic_inst { 951typedef struct _bic_inst {
1120 unsigned int I; 952 unsigned int I;
1121 unsigned int S; 953 unsigned int S;
1122 unsigned int Rn; 954 unsigned int Rn;
1123 unsigned int Rd; 955 unsigned int Rd;
1124 unsigned int shifter_operand; 956 unsigned int shifter_operand;
1125 shtop_fp_t shtop_func; 957 shtop_fp_t shtop_func;
1126} bic_inst; 958} bic_inst;
1127 959
1128typedef struct _sub_inst { 960typedef struct _sub_inst {
1129 unsigned int I; 961 unsigned int I;
1130 unsigned int S; 962 unsigned int S;
1131 unsigned int Rn; 963 unsigned int Rn;
1132 unsigned int Rd; 964 unsigned int Rd;
1133 unsigned int shifter_operand; 965 unsigned int shifter_operand;
1134 shtop_fp_t shtop_func; 966 shtop_fp_t shtop_func;
1135} sub_inst; 967} sub_inst;
1136 968
1137typedef struct _tst_inst { 969typedef struct _tst_inst {
1138 unsigned int I; 970 unsigned int I;
1139 unsigned int S; 971 unsigned int S;
1140 unsigned int Rn; 972 unsigned int Rn;
1141 unsigned int Rd; 973 unsigned int Rd;
1142 unsigned int shifter_operand; 974 unsigned int shifter_operand;
1143 shtop_fp_t shtop_func; 975 shtop_fp_t shtop_func;
1144} tst_inst; 976} tst_inst;
1145 977
1146typedef struct _cmn_inst { 978typedef struct _cmn_inst {
1147 unsigned int I; 979 unsigned int I;
1148 //unsigned int S; 980 unsigned int Rn;
1149 unsigned int Rn; 981 unsigned int shifter_operand;
1150 //unsigned int Rd; 982 shtop_fp_t shtop_func;
1151 unsigned int shifter_operand;
1152 shtop_fp_t shtop_func;
1153} cmn_inst; 983} cmn_inst;
1154 984
1155typedef struct _teq_inst { 985typedef struct _teq_inst {
1156 unsigned int I; 986 unsigned int I;
1157 unsigned int Rn; 987 unsigned int Rn;
1158 unsigned int shifter_operand; 988 unsigned int shifter_operand;
1159 shtop_fp_t shtop_func; 989 shtop_fp_t shtop_func;
1160} teq_inst; 990} teq_inst;
1161 991
1162typedef struct _stm_inst { 992typedef struct _stm_inst {
1163 unsigned int inst; 993 unsigned int inst;
1164} stm_inst; 994} stm_inst;
1165 995
1166struct bkpt_inst { 996struct bkpt_inst {
1167}; 997};
1168 998
1169struct blx1_inst { 999struct blx1_inst {
1170 unsigned int addr; 1000 unsigned int addr;
1171}; 1001};
1172 1002
1173struct blx2_inst { 1003struct blx2_inst {
1174 unsigned int Rm; 1004 unsigned int Rm;
1175}; 1005};
1176 1006
1177typedef struct _stc_inst { 1007typedef struct _stc_inst {
@@ -1181,1965 +1011,2188 @@ typedef struct _ldc_inst {
1181} ldc_inst; 1011} ldc_inst;
1182 1012
1183typedef struct _swi_inst { 1013typedef struct _swi_inst {
1184 unsigned int num; 1014 unsigned int num;
1185} swi_inst; 1015} swi_inst;
1186 1016
1187typedef struct _cmp_inst { 1017typedef struct _cmp_inst {
1188 unsigned int I; 1018 unsigned int I;
1189 unsigned int Rn; 1019 unsigned int Rn;
1190 unsigned int shifter_operand; 1020 unsigned int shifter_operand;
1191 shtop_fp_t shtop_func; 1021 shtop_fp_t shtop_func;
1192} cmp_inst; 1022} cmp_inst;
1193 1023
1194typedef struct _mov_inst { 1024typedef struct _mov_inst {
1195 unsigned int I; 1025 unsigned int I;
1196 unsigned int S; 1026 unsigned int S;
1197 unsigned int Rd; 1027 unsigned int Rd;
1198 unsigned int shifter_operand; 1028 unsigned int shifter_operand;
1199 shtop_fp_t shtop_func; 1029 shtop_fp_t shtop_func;
1200} mov_inst; 1030} mov_inst;
1201 1031
1202typedef struct _mvn_inst { 1032typedef struct _mvn_inst {
1203 unsigned int I; 1033 unsigned int I;
1204 unsigned int S; 1034 unsigned int S;
1205 unsigned int Rd; 1035 unsigned int Rd;
1206 unsigned int shifter_operand; 1036 unsigned int shifter_operand;
1207 shtop_fp_t shtop_func; 1037 shtop_fp_t shtop_func;
1208} mvn_inst; 1038} mvn_inst;
1209 1039
1210typedef struct _rev_inst { 1040typedef struct _rev_inst {
1211 unsigned int Rd; 1041 unsigned int Rd;
1212 unsigned int Rm; 1042 unsigned int Rm;
1213} rev_inst; 1043} rev_inst;
1214 1044
1215typedef struct _rsb_inst { 1045typedef struct _rsb_inst {
1216 unsigned int I; 1046 unsigned int I;
1217 unsigned int S; 1047 unsigned int S;
1218 unsigned int Rn; 1048 unsigned int Rn;
1219 unsigned int Rd; 1049 unsigned int Rd;
1220 unsigned int shifter_operand; 1050 unsigned int shifter_operand;
1221 shtop_fp_t shtop_func; 1051 shtop_fp_t shtop_func;
1222} rsb_inst; 1052} rsb_inst;
1223 1053
1224typedef struct _rsc_inst { 1054typedef struct _rsc_inst {
1225 unsigned int I; 1055 unsigned int I;
1226 unsigned int S; 1056 unsigned int S;
1227 unsigned int Rn; 1057 unsigned int Rn;
1228 unsigned int Rd; 1058 unsigned int Rd;
1229 unsigned int shifter_operand; 1059 unsigned int shifter_operand;
1230 shtop_fp_t shtop_func; 1060 shtop_fp_t shtop_func;
1231} rsc_inst; 1061} rsc_inst;
1232 1062
1233typedef struct _sbc_inst { 1063typedef struct _sbc_inst {
1234 unsigned int I; 1064 unsigned int I;
1235 unsigned int S; 1065 unsigned int S;
1236 unsigned int Rn; 1066 unsigned int Rn;
1237 unsigned int Rd; 1067 unsigned int Rd;
1238 unsigned int shifter_operand; 1068 unsigned int shifter_operand;
1239 shtop_fp_t shtop_func; 1069 shtop_fp_t shtop_func;
1240} sbc_inst; 1070} sbc_inst;
1241 1071
1242typedef struct _mul_inst { 1072typedef struct _mul_inst {
1243 unsigned int S; 1073 unsigned int S;
1244 unsigned int Rd; 1074 unsigned int Rd;
1245 unsigned int Rs; 1075 unsigned int Rs;
1246 unsigned int Rm; 1076 unsigned int Rm;
1247} mul_inst; 1077} mul_inst;
1248 1078
1249typedef struct _smul_inst { 1079typedef struct _smul_inst {
1250 unsigned int Rd; 1080 unsigned int Rd;
1251 unsigned int Rs; 1081 unsigned int Rs;
1252 unsigned int Rm; 1082 unsigned int Rm;
1253 unsigned int x; 1083 unsigned int x;
1254 unsigned int y; 1084 unsigned int y;
1255} smul_inst; 1085} smul_inst;
1256 1086
1257typedef struct _umull_inst { 1087typedef struct _umull_inst {
1258 unsigned int S; 1088 unsigned int S;
1259 unsigned int RdHi; 1089 unsigned int RdHi;
1260 unsigned int RdLo; 1090 unsigned int RdLo;
1261 unsigned int Rs; 1091 unsigned int Rs;
1262 unsigned int Rm; 1092 unsigned int Rm;
1263} umull_inst; 1093} umull_inst;
1264typedef struct _smlad_inst { 1094typedef struct _smlad_inst {
1265 unsigned int m; 1095 unsigned int m;
1266 unsigned int Rm; 1096 unsigned int Rm;
1267 unsigned int Rd; 1097 unsigned int Rd;
1268 unsigned int Ra; 1098 unsigned int Ra;
1269 unsigned int Rn; 1099 unsigned int Rn;
1270} smlad_inst; 1100} smlad_inst;
1271 1101
1272typedef struct _smla_inst { 1102typedef struct _smla_inst {
1273 unsigned int x; 1103 unsigned int x;
1274 unsigned int y; 1104 unsigned int y;
1275 unsigned int Rm; 1105 unsigned int Rm;
1276 unsigned int Rd; 1106 unsigned int Rd;
1277 unsigned int Rs; 1107 unsigned int Rs;
1278 unsigned int Rn; 1108 unsigned int Rn;
1279} smla_inst; 1109} smla_inst;
1280 1110
1111typedef struct ssat_inst {
1112 unsigned int Rn;
1113 unsigned int Rd;
1114 unsigned int imm5;
1115 unsigned int sat_imm;
1116 unsigned int shift_type;
1117} ssat_inst;
1118
1119typedef struct umaal_inst {
1120 unsigned int Rn;
1121 unsigned int Rm;
1122 unsigned int RdHi;
1123 unsigned int RdLo;
1124} umaal_inst;
1125
1281typedef struct _umlal_inst { 1126typedef struct _umlal_inst {
1282 unsigned int S; 1127 unsigned int S;
1283 unsigned int Rm; 1128 unsigned int Rm;
1284 unsigned int Rs; 1129 unsigned int Rs;
1285 unsigned int RdHi; 1130 unsigned int RdHi;
1286 unsigned int RdLo; 1131 unsigned int RdLo;
1287} umlal_inst; 1132} umlal_inst;
1288 1133
1289typedef struct _smlal_inst { 1134typedef struct _smlal_inst {
1290 unsigned int S; 1135 unsigned int S;
1291 unsigned int Rm; 1136 unsigned int Rm;
1292 unsigned int Rs; 1137 unsigned int Rs;
1293 unsigned int RdHi; 1138 unsigned int RdHi;
1294 unsigned int RdLo; 1139 unsigned int RdLo;
1295} smlal_inst; 1140} smlal_inst;
1296 1141
1297typedef struct _mla_inst { 1142typedef struct _mla_inst {
1298 unsigned int S; 1143 unsigned int S;
1299 unsigned int Rn; 1144 unsigned int Rn;
1300 unsigned int Rd; 1145 unsigned int Rd;
1301 unsigned int Rs; 1146 unsigned int Rs;
1302 unsigned int Rm; 1147 unsigned int Rm;
1303} mla_inst; 1148} mla_inst;
1304 1149
1305typedef struct _mrc_inst { 1150typedef struct _mrc_inst {
1306 unsigned int opcode_1; 1151 unsigned int opcode_1;
1307 unsigned int opcode_2; 1152 unsigned int opcode_2;
1308 unsigned int cp_num; 1153 unsigned int cp_num;
1309 unsigned int crn; 1154 unsigned int crn;
1310 unsigned int crm; 1155 unsigned int crm;
1311 unsigned int Rd; 1156 unsigned int Rd;
1312 unsigned int inst; 1157 unsigned int inst;
1313} mrc_inst; 1158} mrc_inst;
1314 1159
1315typedef struct _mcr_inst { 1160typedef struct _mcr_inst {
1316 unsigned int opcode_1; 1161 unsigned int opcode_1;
1317 unsigned int opcode_2; 1162 unsigned int opcode_2;
1318 unsigned int cp_num; 1163 unsigned int cp_num;
1319 unsigned int crn; 1164 unsigned int crn;
1320 unsigned int crm; 1165 unsigned int crm;
1321 unsigned int Rd; 1166 unsigned int Rd;
1322 unsigned int inst; 1167 unsigned int inst;
1323} mcr_inst; 1168} mcr_inst;
1324 1169
1325typedef struct _mrs_inst { 1170typedef struct _mrs_inst {
1326 unsigned int R; 1171 unsigned int R;
1327 unsigned int Rd; 1172 unsigned int Rd;
1328} mrs_inst; 1173} mrs_inst;
1329 1174
1330typedef struct _msr_inst { 1175typedef struct _msr_inst {
1331 unsigned int field_mask; 1176 unsigned int field_mask;
1332 unsigned int R; 1177 unsigned int R;
1333 unsigned int inst; 1178 unsigned int inst;
1334} msr_inst; 1179} msr_inst;
1335 1180
1336typedef struct _pld_inst { 1181typedef struct _pld_inst {
1337} pld_inst; 1182} pld_inst;
1338 1183
1339typedef struct _sxtb_inst { 1184typedef struct _sxtb_inst {
1340 unsigned int Rd; 1185 unsigned int Rd;
1341 unsigned int Rm; 1186 unsigned int Rm;
1342 unsigned int rotate; 1187 unsigned int rotate;
1343} sxtb_inst; 1188} sxtb_inst;
1344 1189
1345typedef struct _sxtab_inst { 1190typedef struct _sxtab_inst {
1346 unsigned int Rd; 1191 unsigned int Rd;
1347 unsigned int Rn; 1192 unsigned int Rn;
1348 unsigned int Rm; 1193 unsigned int Rm;
1349 unsigned rotate; 1194 unsigned rotate;
1350} sxtab_inst; 1195} sxtab_inst;
1351 1196
1352typedef struct _sxtah_inst { 1197typedef struct _sxtah_inst {
1353 unsigned int Rd; 1198 unsigned int Rd;
1354 unsigned int Rn; 1199 unsigned int Rn;
1355 unsigned int Rm; 1200 unsigned int Rm;
1356 unsigned int rotate; 1201 unsigned int rotate;
1357} sxtah_inst; 1202} sxtah_inst;
1358 1203
1359typedef struct _sxth_inst { 1204typedef struct _sxth_inst {
1360 unsigned int Rd; 1205 unsigned int Rd;
1361 unsigned int Rm; 1206 unsigned int Rm;
1362 unsigned int rotate; 1207 unsigned int rotate;
1363} sxth_inst; 1208} sxth_inst;
1364 1209
1365typedef struct _uxtab_inst { 1210typedef struct _uxtab_inst {
1366 unsigned int Rn; 1211 unsigned int Rn;
1367 unsigned int Rd; 1212 unsigned int Rd;
1368 unsigned int rotate; 1213 unsigned int rotate;
1369 unsigned int Rm; 1214 unsigned int Rm;
1370} uxtab_inst; 1215} uxtab_inst;
1371 1216
1372typedef struct _uxtah_inst { 1217typedef struct _uxtah_inst {
1373 unsigned int Rn; 1218 unsigned int Rn;
1374 unsigned int Rd; 1219 unsigned int Rd;
1375 unsigned int rotate; 1220 unsigned int rotate;
1376 unsigned int Rm; 1221 unsigned int Rm;
1377} uxtah_inst; 1222} uxtah_inst;
1378 1223
1379typedef struct _uxth_inst { 1224typedef struct _uxth_inst {
1380 unsigned int Rd; 1225 unsigned int Rd;
1381 unsigned int Rm; 1226 unsigned int Rm;
1382 unsigned int rotate; 1227 unsigned int rotate;
1383} uxth_inst; 1228} uxth_inst;
1384 1229
1385typedef struct _cdp_inst { 1230typedef struct _cdp_inst {
1386 unsigned int opcode_1; 1231 unsigned int opcode_1;
1387 unsigned int CRn; 1232 unsigned int CRn;
1388 unsigned int CRd; 1233 unsigned int CRd;
1389 unsigned int cp_num; 1234 unsigned int cp_num;
1390 unsigned int opcode_2; 1235 unsigned int opcode_2;
1391 unsigned int CRm; 1236 unsigned int CRm;
1392 uint32 inst; 1237 uint32 inst;
1393}cdp_inst; 1238}cdp_inst;
1394 1239
1395typedef struct _uxtb_inst { 1240typedef struct _uxtb_inst {
1396 unsigned int Rd; 1241 unsigned int Rd;
1397 unsigned int Rm; 1242 unsigned int Rm;
1398 unsigned int rotate; 1243 unsigned int rotate;
1399} uxtb_inst; 1244} uxtb_inst;
1400 1245
1401typedef struct _swp_inst { 1246typedef struct _swp_inst {
1402 unsigned int Rn; 1247 unsigned int Rn;
1403 unsigned int Rd; 1248 unsigned int Rd;
1404 unsigned int Rm; 1249 unsigned int Rm;
1405} swp_inst; 1250} swp_inst;
1406 1251
1407typedef struct _b_2_thumb { 1252typedef struct _b_2_thumb {
1408 unsigned int imm; 1253 unsigned int imm;
1409}b_2_thumb; 1254}b_2_thumb;
1410typedef struct _b_cond_thumb { 1255typedef struct _b_cond_thumb {
1411 unsigned int imm; 1256 unsigned int imm;
1412 unsigned int cond; 1257 unsigned int cond;
1413}b_cond_thumb; 1258}b_cond_thumb;
1414 1259
1415typedef struct _bl_1_thumb { 1260typedef struct _bl_1_thumb {
1416 unsigned int imm; 1261 unsigned int imm;
1417}bl_1_thumb; 1262}bl_1_thumb;
1418typedef struct _bl_2_thumb { 1263typedef struct _bl_2_thumb {
1419 unsigned int imm; 1264 unsigned int imm;
1420}bl_2_thumb; 1265}bl_2_thumb;
1421typedef struct _blx_1_thumb { 1266typedef struct _blx_1_thumb {
1422 unsigned int imm; 1267 unsigned int imm;
1423 unsigned int instr; 1268 unsigned int instr;
1424}blx_1_thumb; 1269}blx_1_thumb;
1425 1270
1271typedef struct _pkh_inst {
1272 u32 Rm;
1273 u32 Rn;
1274 u32 Rd;
1275 u8 imm;
1276} pkh_inst;
1277
1426typedef arm_inst * ARM_INST_PTR; 1278typedef arm_inst * ARM_INST_PTR;
1427 1279
1428#define CACHE_BUFFER_SIZE (64 * 1024 * 2000) 1280#define CACHE_BUFFER_SIZE (64 * 1024 * 2000)
1429char inst_buf[CACHE_BUFFER_SIZE]; 1281char inst_buf[CACHE_BUFFER_SIZE];
1430int top = 0; 1282int top = 0;
1431inline void *AllocBuffer(unsigned int size) 1283inline void *AllocBuffer(unsigned int size) {
1432{ 1284 int start = top;
1433 int start = top; 1285 top += size;
1434 top += size; 1286 if (top > CACHE_BUFFER_SIZE) {
1435 if (top > CACHE_BUFFER_SIZE) { 1287 LOG_ERROR(Core_ARM11, "inst_buf is full");
1436 DEBUG_LOG(ARM11, "inst_buf is full\n"); 1288 CITRA_IGNORE_EXIT(-1);
1437 CITRA_IGNORE_EXIT(-1); 1289 }
1438 } 1290 return (void *)&inst_buf[start];
1439 return (void *)&inst_buf[start]; 1291}
1440} 1292
1441 1293int CondPassed(arm_processor *cpu, unsigned int cond) {
1442int CondPassed(arm_processor *cpu, unsigned int cond) 1294 #define NFLAG cpu->NFlag
1443{ 1295 #define ZFLAG cpu->ZFlag
1444 #define NFLAG cpu->NFlag 1296 #define CFLAG cpu->CFlag
1445 #define ZFLAG cpu->ZFlag 1297 #define VFLAG cpu->VFlag
1446 #define CFLAG cpu->CFlag 1298
1447 #define VFLAG cpu->VFlag 1299 int temp;
1448 int temp; 1300
1449 switch (cond) { 1301 switch (cond) {
1450 case 0x0: 1302 case 0x0:
1451 temp = ZFLAG; 1303 temp = ZFLAG;
1452 break; 1304 break;
1453 case 0x1: /* NE */ 1305 case 0x1: // NE
1454 temp = !ZFLAG; 1306 temp = !ZFLAG;
1455 break; 1307 break;
1456 case 0x6: /* VS */ 1308 case 0x6: // VS
1457 temp = VFLAG; 1309 temp = VFLAG;
1458 break; 1310 break;
1459 case 0x7: /* VC */ 1311 case 0x7: // VC
1460 temp = !VFLAG; 1312 temp = !VFLAG;
1461 break; 1313 break;
1462 case 0x4: /* MI */ 1314 case 0x4: // MI
1463 temp = NFLAG; 1315 temp = NFLAG;
1464 break; 1316 break;
1465 case 0x5: /* PL */ 1317 case 0x5: // PL
1466 temp = !NFLAG; 1318 temp = !NFLAG;
1467 break; 1319 break;
1468 case 0x2: /* CS */ 1320 case 0x2: // CS
1469 temp = CFLAG; 1321 temp = CFLAG;
1470 break; 1322 break;
1471 case 0x3: /* CC */ 1323 case 0x3: // CC
1472 temp = !CFLAG; 1324 temp = !CFLAG;
1473 break; 1325 break;
1474 case 0x8: /* HI */ 1326 case 0x8: // HI
1475 temp = (CFLAG && !ZFLAG); 1327 temp = (CFLAG && !ZFLAG);
1476 break; 1328 break;
1477 case 0x9: /* LS */ 1329 case 0x9: // LS
1478 temp = (!CFLAG || ZFLAG); 1330 temp = (!CFLAG || ZFLAG);
1479 break; 1331 break;
1480 case 0xa: /* GE */ 1332 case 0xa: // GE
1481 temp = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG)); 1333 temp = ((!NFLAG && !VFLAG) || (NFLAG && VFLAG));
1482 break; 1334 break;
1483 case 0xb: /* LT */ 1335 case 0xb: // LT
1484 temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)); 1336 temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG));
1485 break; 1337 break;
1486 case 0xc: /* GT */ 1338 case 0xc: // GT
1487 temp = ((!NFLAG && !VFLAG && !ZFLAG) 1339 temp = ((!NFLAG && !VFLAG && !ZFLAG) || (NFLAG && VFLAG && !ZFLAG));
1488 || (NFLAG && VFLAG && !ZFLAG)); 1340 break;
1489 break; 1341 case 0xd: // LE
1490 case 0xd: /* LE */ 1342 temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) || ZFLAG;
1491 temp = ((NFLAG && !VFLAG) || (!NFLAG && VFLAG)) 1343 break;
1492 || ZFLAG; 1344 case 0xe: // AL
1493 break; 1345 temp = 1;
1494 case 0xe: /* AL */ 1346 break;
1495 temp = 1; 1347 case 0xf:
1496 break; 1348 temp = 1;
1497 case 0xf: 1349 break;
1498// DEBUG_LOG(ARM11, "inst is %x\n"); 1350 }
1499// DEBUG_LOG(ARM11, "icounter is %lld\n", cpu->icounter); 1351 return temp;
1500// CITRA_IGNORE_EXIT(-1);
1501 temp = 1;
1502 break;
1503 }
1504 return temp;
1505} 1352}
1506 1353
1507enum DECODE_STATUS { 1354enum DECODE_STATUS {
1508 DECODE_SUCCESS, 1355 DECODE_SUCCESS,
1509 DECODE_FAILURE 1356 DECODE_FAILURE
1510}; 1357};
1511 1358
1512int decode_arm_instr(uint32_t instr, int32_t *idx); 1359int decode_arm_instr(uint32_t instr, int32_t *idx);
1513 1360
1514shtop_fp_t get_shtop(unsigned int inst) 1361shtop_fp_t get_shtop(unsigned int inst) {
1515{ 1362 if (BIT(inst, 25)) {
1516 if (BIT(inst, 25)) { 1363 return DPO(Immediate);
1517 return DPO(Immediate); 1364 } else if (BITS(inst, 4, 11) == 0) {
1518 } else if (BITS(inst, 4, 11) == 0) { 1365 return DPO(Register);
1519 return DPO(Register); 1366 } else if (BITS(inst, 4, 6) == 0) {
1520 } else if (BITS(inst, 4, 6) == 0) { 1367 return DPO(LogicalShiftLeftByImmediate);
1521 return DPO(LogicalShiftLeftByImmediate); 1368 } else if (BITS(inst, 4, 7) == 1) {
1522 } else if (BITS(inst, 4, 7) == 1) { 1369 return DPO(LogicalShiftLeftByRegister);
1523 return DPO(LogicalShiftLeftByRegister); 1370 } else if (BITS(inst, 4, 6) == 2) {
1524 } else if (BITS(inst, 4, 6) == 2) { 1371 return DPO(LogicalShiftRightByImmediate);
1525 return DPO(LogicalShiftRightByImmediate); 1372 } else if (BITS(inst, 4, 7) == 3) {
1526 } else if (BITS(inst, 4, 7) == 3) { 1373 return DPO(LogicalShiftRightByRegister);
1527 return DPO(LogicalShiftRightByRegister); 1374 } else if (BITS(inst, 4, 6) == 4) {
1528 } else if (BITS(inst, 4, 6) == 4) { 1375 return DPO(ArithmeticShiftRightByImmediate);
1529 return DPO(ArithmeticShiftRightByImmediate); 1376 } else if (BITS(inst, 4, 7) == 5) {
1530 } else if (BITS(inst, 4, 7) == 5) { 1377 return DPO(ArithmeticShiftRightByRegister);
1531 return DPO(ArithmeticShiftRightByRegister); 1378 } else if (BITS(inst, 4, 6) == 6) {
1532 } else if (BITS(inst, 4, 6) == 6) { 1379 return DPO(RotateRightByImmediate);
1533 return DPO(RotateRightByImmediate); 1380 } else if (BITS(inst, 4, 7) == 7) {
1534 } else if (BITS(inst, 4, 7) == 7) { 1381 return DPO(RotateRightByRegister);
1535 return DPO(RotateRightByRegister); 1382 }
1536 } 1383 return nullptr;
1537 return NULL; 1384}
1538} 1385
1539 1386get_addr_fp_t get_calc_addr_op(unsigned int inst) {
1540get_addr_fp_t get_calc_addr_op(unsigned int inst) 1387 if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 0) {
1541{ 1388 return LnSWoUB(ImmediateOffset);
1542 /* 1 */ 1389 } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) {
1543 if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 0) { 1390 return LnSWoUB(RegisterOffset);
1544// DEBUG_LOG(ARM11, "line is %d", __LINE__); 1391 } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BIT(inst, 4) == 0) {
1545 return LnSWoUB(ImmediateOffset); 1392 return LnSWoUB(ScaledRegisterOffset);
1546 } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) { 1393 } else if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 1) {
1547// DEBUG_MSG; 1394 return LnSWoUB(ImmediatePreIndexed);
1548// DEBUG_LOG(ARM11, "line is %d", __LINE__); 1395 } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 1 && BITS(inst, 4, 11) == 0) {
1549 return LnSWoUB(RegisterOffset); 1396 return LnSWoUB(RegisterPreIndexed);
1550 } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 0 && BIT(inst, 4) == 0) { 1397 } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 1 && BIT(inst, 4) == 0) {
1551// DEBUG_MSG; 1398 return LnSWoUB(ScaledRegisterPreIndexed);
1552// DEBUG_LOG(ARM11, "line is %d", __LINE__); 1399 } else if (BITS(inst, 24, 27) == 4 && BIT(inst, 21) == 0) {
1553 return LnSWoUB(ScaledRegisterOffset); 1400 return LnSWoUB(ImmediatePostIndexed);
1554 } else if (BITS(inst, 24, 27) == 5 && BIT(inst, 21) == 1) { 1401 } else if (BITS(inst, 24, 27) == 6 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) {
1555// DEBUG_LOG(ARM11, "line is %d", __LINE__); 1402 return LnSWoUB(RegisterPostIndexed);
1556 return LnSWoUB(ImmediatePreIndexed); 1403 } else if (BITS(inst, 24, 27) == 6 && BIT(inst, 21) == 0 && BIT(inst, 4) == 0) {
1557 } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 1 && BITS(inst, 4, 11) == 0) { 1404 return LnSWoUB(ScaledRegisterPostIndexed);
1558 return LnSWoUB(RegisterPreIndexed); 1405 } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 2 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
1559 } else if (BITS(inst, 24, 27) == 7 && BIT(inst, 21) == 1 && BIT(inst, 4) == 0) { 1406 return MLnS(ImmediateOffset);
1560 return LnSWoUB(ScaledRegisterPreIndexed); 1407 } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 0 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
1561 } else if (BITS(inst, 24, 27) == 4 && BIT(inst, 21) == 0) { 1408 return MLnS(RegisterOffset);
1562 return LnSWoUB(ImmediatePostIndexed); 1409 } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 3 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
1563 } else if (BITS(inst, 24, 27) == 6 && BIT(inst, 21) == 0 && BITS(inst, 4, 11) == 0) { 1410 return MLnS(ImmediatePreIndexed);
1564// DEBUG_MSG; 1411 } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 1 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
1565 return LnSWoUB(RegisterPostIndexed); 1412 return MLnS(RegisterPreIndexed);
1566 } else if (BITS(inst, 24, 27) == 6 && BIT(inst, 21) == 0 && BIT(inst, 4) == 0) { 1413 } else if (BITS(inst, 24, 27) == 0 && BITS(inst, 21, 22) == 2 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
1567 return LnSWoUB(ScaledRegisterPostIndexed); 1414 return MLnS(ImmediatePostIndexed);
1568// DEBUG_MSG; 1415 } else if (BITS(inst, 24, 27) == 0 && BITS(inst, 21, 22) == 0 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
1569 } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 2 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) { 1416 return MLnS(RegisterPostIndexed);
1570 /* 2 */ 1417 } else if (BITS(inst, 23, 27) == 0x11) {
1571// DEBUG_LOG(ARM11, "line is %d", __LINE__); 1418 return LdnStM(IncrementAfter);
1572 return MLnS(ImmediateOffset); 1419 } else if (BITS(inst, 23, 27) == 0x13) {
1573// DEBUG_MSG; 1420 return LdnStM(IncrementBefore);
1574 } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 0 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) { 1421 } else if (BITS(inst, 23, 27) == 0x10) {
1575// DEBUG_LOG(ARM11, "line is %d\n", __LINE__); 1422 return LdnStM(DecrementAfter);
1576 return MLnS(RegisterOffset); 1423 } else if (BITS(inst, 23, 27) == 0x12) {
1577// DEBUG_MSG; 1424 return LdnStM(DecrementBefore);
1578 } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 3 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) { 1425 }
1579// DEBUG_LOG(ARM11, "line is %d\n", __LINE__); 1426 return nullptr;
1580 return MLnS(ImmediatePreIndexed);
1581// DEBUG_MSG;
1582 } else if (BITS(inst, 24, 27) == 1 && BITS(inst, 21, 22) == 1 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
1583 return MLnS(RegisterPreIndexed);
1584 } else if (BITS(inst, 24, 27) == 0 && BITS(inst, 21, 22) == 2 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
1585// DEBUG_MSG;
1586 return MLnS(ImmediatePostIndexed);
1587 } else if (BITS(inst, 24, 27) == 0 && BITS(inst, 21, 22) == 0 && BIT(inst, 7) == 1 && BIT(inst, 4) == 1) {
1588 //DEBUG_MSG;
1589 return MLnS(RegisterPostIndexed);
1590 } else if (BITS(inst, 23, 27) == 0x11) {
1591 /* 3 */
1592// DEBUG_MSG;
1593// DEBUG_LOG(ARM11, "line is %d", __LINE__);
1594 return LdnStM(IncrementAfter);
1595 } else if (BITS(inst, 23, 27) == 0x13) {
1596// DEBUG_LOG(ARM11, "line is %d", __LINE__);
1597 return LdnStM(IncrementBefore);
1598// DEBUG_MSG;
1599 } else if (BITS(inst, 23, 27) == 0x10) {
1600// DEBUG_MSG;
1601// DEBUG_LOG(ARM11, "line is %d", __LINE__);
1602 return LdnStM(DecrementAfter);
1603 } else if (BITS(inst, 23, 27) == 0x12) {
1604// DEBUG_MSG;
1605// DEBUG_LOG(ARM11, "line is %d", __LINE__);
1606 return LdnStM(DecrementBefore);
1607 }
1608 #if 0
1609 DEBUG_LOG(ARM11, "In %s Unknown addressing mode\n", __FUNCTION__);
1610 DEBUG_LOG(ARM11, "inst:%x\n", inst);
1611 CITRA_IGNORE_EXIT(-1);
1612 #endif
1613 return NULL;
1614} 1427}
1615 1428
1616#define INTERPRETER_TRANSLATE(s) glue(InterpreterTranslate_, s) 1429#define INTERPRETER_TRANSLATE(s) glue(InterpreterTranslate_, s)
1617 1430
1618#define CHECK_RN (inst_cream->Rn == 15) 1431#define CHECK_RN (inst_cream->Rn == 15)
1619#define CHECK_RM (inst_cream->Rm == 15) 1432#define CHECK_RM (inst_cream->Rm == 15)
1620#define CHECK_RS (inst_cream->Rs == 15) 1433#define CHECK_RS (inst_cream->Rs == 15)
1621 1434
1435#define UNIMPLEMENTED_INSTRUCTION(mnemonic) \
1436 LOG_ERROR(Core_ARM11, "unimplemented instruction: %s", mnemonic); \
1437 CITRA_IGNORE_EXIT(-1); \
1438 return nullptr;
1622 1439
1623ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index) 1440ARM_INST_PTR INTERPRETER_TRANSLATE(adc)(unsigned int inst, int index)
1624{ 1441{
1625 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(adc_inst)); 1442 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(adc_inst));
1626 adc_inst *inst_cream = (adc_inst *)inst_base->component; 1443 adc_inst *inst_cream = (adc_inst *)inst_base->component;
1627 1444
1628 inst_base->cond = BITS(inst, 28, 31); 1445 inst_base->cond = BITS(inst, 28, 31);
1629 inst_base->idx = index; 1446 inst_base->idx = index;
1630 inst_base->br = NON_BRANCH; 1447 inst_base->br = NON_BRANCH;
1631 inst_base->load_r15 = 0; 1448 inst_base->load_r15 = 0;
1632 1449
1633 inst_cream->I = BIT(inst, 25); 1450 inst_cream->I = BIT(inst, 25);
1634 inst_cream->S = BIT(inst, 20); 1451 inst_cream->S = BIT(inst, 20);
1635 inst_cream->Rn = BITS(inst, 16, 19); 1452 inst_cream->Rn = BITS(inst, 16, 19);
1636 inst_cream->Rd = BITS(inst, 12, 15); 1453 inst_cream->Rd = BITS(inst, 12, 15);
1637 if (CHECK_RN) 1454 if (CHECK_RN)
1638 inst_base->load_r15 = 1; 1455 inst_base->load_r15 = 1;
1639 inst_cream->shifter_operand = BITS(inst, 0, 11); 1456 inst_cream->shifter_operand = BITS(inst, 0, 11);
1640 inst_cream->shtop_func = get_shtop(inst); 1457 inst_cream->shtop_func = get_shtop(inst);
1641 if (inst_cream->Rd == 15) { 1458 if (inst_cream->Rd == 15) {
1642 inst_base->br = INDIRECT_BRANCH; 1459 inst_base->br = INDIRECT_BRANCH;
1643 } 1460 }
1644 return inst_base; 1461 return inst_base;
1645} 1462}
1646ARM_INST_PTR INTERPRETER_TRANSLATE(add)(unsigned int inst, int index) 1463ARM_INST_PTR INTERPRETER_TRANSLATE(add)(unsigned int inst, int index)
1647{ 1464{
1648 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(add_inst)); 1465 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(add_inst));
1649 add_inst *inst_cream = (add_inst *)inst_base->component; 1466 add_inst *inst_cream = (add_inst *)inst_base->component;
1650 1467
1651 inst_base->cond = BITS(inst, 28, 31); 1468 inst_base->cond = BITS(inst, 28, 31);
1652 inst_base->idx = index; 1469 inst_base->idx = index;
1653 inst_base->br = NON_BRANCH; 1470 inst_base->br = NON_BRANCH;
1654 inst_base->load_r15 = 0; 1471 inst_base->load_r15 = 0;
1655 1472
1656 inst_cream->I = BIT(inst, 25); 1473 inst_cream->I = BIT(inst, 25);
1657 inst_cream->S = BIT(inst, 20); 1474 inst_cream->S = BIT(inst, 20);
1658 inst_cream->Rn = BITS(inst, 16, 19); 1475 inst_cream->Rn = BITS(inst, 16, 19);
1659 inst_cream->Rd = BITS(inst, 12, 15); 1476 inst_cream->Rd = BITS(inst, 12, 15);
1660 if (CHECK_RN) 1477 if (CHECK_RN)
1661 inst_base->load_r15 = 1; 1478 inst_base->load_r15 = 1;
1662 inst_cream->shifter_operand = BITS(inst, 0, 11); 1479 inst_cream->shifter_operand = BITS(inst, 0, 11);
1663 inst_cream->shtop_func = get_shtop(inst); 1480 inst_cream->shtop_func = get_shtop(inst);
1664 if (inst_cream->Rd == 15) { 1481 if (inst_cream->Rd == 15) {
1665 inst_base->br = INDIRECT_BRANCH; 1482 inst_base->br = INDIRECT_BRANCH;
1666 } 1483 }
1667 return inst_base; 1484 return inst_base;
1668} 1485}
1669ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index) 1486ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index)
1670{ 1487{
1671 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(and_inst)); 1488 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(and_inst));
1672 and_inst *inst_cream = (and_inst *)inst_base->component; 1489 and_inst *inst_cream = (and_inst *)inst_base->component;
1673 1490
1674 inst_base->cond = BITS(inst, 28, 31); 1491 inst_base->cond = BITS(inst, 28, 31);
1675 inst_base->idx = index; 1492 inst_base->idx = index;
1676 inst_base->br = NON_BRANCH; 1493 inst_base->br = NON_BRANCH;
1677 inst_base->load_r15 = 0; 1494 inst_base->load_r15 = 0;
1678 1495
1679 inst_cream->I = BIT(inst, 25); 1496 inst_cream->I = BIT(inst, 25);
1680 inst_cream->S = BIT(inst, 20); 1497 inst_cream->S = BIT(inst, 20);
1681 inst_cream->Rn = BITS(inst, 16, 19); 1498 inst_cream->Rn = BITS(inst, 16, 19);
1682 inst_cream->Rd = BITS(inst, 12, 15); 1499 inst_cream->Rd = BITS(inst, 12, 15);
1683 if (CHECK_RN) 1500 if (CHECK_RN)
1684 inst_base->load_r15 = 1; 1501 inst_base->load_r15 = 1;
1685 inst_cream->shifter_operand = BITS(inst, 0, 11); 1502 inst_cream->shifter_operand = BITS(inst, 0, 11);
1686 inst_cream->shtop_func = get_shtop(inst); 1503 inst_cream->shtop_func = get_shtop(inst);
1687 if (inst_cream->Rd == 15) 1504 if (inst_cream->Rd == 15)
1688 inst_base->br = INDIRECT_BRANCH; 1505 inst_base->br = INDIRECT_BRANCH;
1689 return inst_base; 1506 return inst_base;
1690} 1507}
1691ARM_INST_PTR INTERPRETER_TRANSLATE(bbl)(unsigned int inst, int index) 1508ARM_INST_PTR INTERPRETER_TRANSLATE(bbl)(unsigned int inst, int index)
1692{ 1509{
1693 #define POSBRANCH ((inst & 0x7fffff) << 2) 1510 #define POSBRANCH ((inst & 0x7fffff) << 2)
1694 #define NEGBRANCH ((0xff000000 |(inst & 0xffffff)) << 2) 1511 #define NEGBRANCH ((0xff000000 |(inst & 0xffffff)) << 2)
1695 1512
1696 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bbl_inst)); 1513 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bbl_inst));
1697 bbl_inst *inst_cream = (bbl_inst *)inst_base->component; 1514 bbl_inst *inst_cream = (bbl_inst *)inst_base->component;
1698 1515
1699 inst_base->cond = BITS(inst, 28, 31); 1516 inst_base->cond = BITS(inst, 28, 31);
1700 inst_base->idx = index; 1517 inst_base->idx = index;
1701 inst_base->br = DIRECT_BRANCH; 1518 inst_base->br = DIRECT_BRANCH;
1702 1519
1703 if (BIT(inst, 24)) 1520 if (BIT(inst, 24))
1704 inst_base->br = CALL; 1521 inst_base->br = CALL;
1705 if (BITS(inst, 28, 31) <= 0xe) 1522 if (BITS(inst, 28, 31) <= 0xe)
1706 inst_base->br |= COND; 1523 inst_base->br |= COND;
1707 1524
1708 inst_cream->L = BIT(inst, 24); 1525 inst_cream->L = BIT(inst, 24);
1709 inst_cream->signed_immed_24 = BIT(inst, 23) ? NEGBRANCH : POSBRANCH; 1526 inst_cream->signed_immed_24 = BIT(inst, 23) ? NEGBRANCH : POSBRANCH;
1710 1527
1711 return inst_base; 1528 return inst_base;
1712} 1529}
1713ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index) 1530ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index)
1714{ 1531{
1715 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bic_inst)); 1532 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bic_inst));
1716 bic_inst *inst_cream = (bic_inst *)inst_base->component; 1533 bic_inst *inst_cream = (bic_inst *)inst_base->component;
1717 1534
1718 inst_base->cond = BITS(inst, 28, 31); 1535 inst_base->cond = BITS(inst, 28, 31);
1719 inst_base->idx = index; 1536 inst_base->idx = index;
1720 inst_base->br = NON_BRANCH; 1537 inst_base->br = NON_BRANCH;
1721 inst_base->load_r15 = 0; 1538 inst_base->load_r15 = 0;
1722 1539
1723 inst_cream->I = BIT(inst, 25); 1540 inst_cream->I = BIT(inst, 25);
1724 inst_cream->S = BIT(inst, 20); 1541 inst_cream->S = BIT(inst, 20);
1725 inst_cream->Rn = BITS(inst, 16, 19); 1542 inst_cream->Rn = BITS(inst, 16, 19);
1726 inst_cream->Rd = BITS(inst, 12, 15); 1543 inst_cream->Rd = BITS(inst, 12, 15);
1727 if (CHECK_RN) 1544 if (CHECK_RN)
1728 inst_base->load_r15 = 1; 1545 inst_base->load_r15 = 1;
1729 inst_cream->shifter_operand = BITS(inst, 0, 11); 1546 inst_cream->shifter_operand = BITS(inst, 0, 11);
1730 inst_cream->shtop_func = get_shtop(inst); 1547 inst_cream->shtop_func = get_shtop(inst);
1731 1548
1732 if (inst_cream->Rd == 15) 1549 if (inst_cream->Rd == 15)
1733 inst_base->br = INDIRECT_BRANCH; 1550 inst_base->br = INDIRECT_BRANCH;
1734 return inst_base; 1551 return inst_base;
1735} 1552}
1736ARM_INST_PTR INTERPRETER_TRANSLATE(bkpt)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 1553ARM_INST_PTR INTERPRETER_TRANSLATE(bkpt)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("BKPT"); }
1737ARM_INST_PTR INTERPRETER_TRANSLATE(blx)(unsigned int inst, int index) 1554ARM_INST_PTR INTERPRETER_TRANSLATE(blx)(unsigned int inst, int index)
1738{ 1555{
1739 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_inst)); 1556 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_inst));
1740 blx_inst *inst_cream = (blx_inst *)inst_base->component; 1557 blx_inst *inst_cream = (blx_inst *)inst_base->component;
1741 1558
1742 inst_base->cond = BITS(inst, 28, 31); 1559 inst_base->cond = BITS(inst, 28, 31);
1743 inst_base->idx = index; 1560 inst_base->idx = index;
1744 inst_base->br = INDIRECT_BRANCH; 1561 inst_base->br = INDIRECT_BRANCH;
1745 1562
1746 inst_cream->inst = inst; 1563 inst_cream->inst = inst;
1747 if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) { 1564 if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) {
1748 inst_cream->val.Rm = BITS(inst, 0, 3); 1565 inst_cream->val.Rm = BITS(inst, 0, 3);
1749 } else { 1566 } else {
1750 inst_cream->val.signed_immed_24 = BITS(inst, 0, 23); 1567 inst_cream->val.signed_immed_24 = BITS(inst, 0, 23);
1751 //DEBUG_LOG(ARM11, " blx inst is %x\n", inst); 1568 }
1752 //CITRA_IGNORE_EXIT(-1);
1753// DEBUG_MSG;
1754 }
1755 1569
1756 return inst_base; 1570 return inst_base;
1757} 1571}
1758ARM_INST_PTR INTERPRETER_TRANSLATE(bx)(unsigned int inst, int index) 1572ARM_INST_PTR INTERPRETER_TRANSLATE(bx)(unsigned int inst, int index)
1759{ 1573{
1760 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bx_inst)); 1574 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bx_inst));
1761 bx_inst *inst_cream = (bx_inst *)inst_base->component; 1575 bx_inst *inst_cream = (bx_inst *)inst_base->component;
1762 1576
1763 inst_base->cond = BITS(inst, 28, 31); 1577 inst_base->cond = BITS(inst, 28, 31);
1764 inst_base->idx = index; 1578 inst_base->idx = index;
1765 inst_base->br = INDIRECT_BRANCH; 1579 inst_base->br = INDIRECT_BRANCH;
1766 1580
1767 inst_cream->Rm = BITS(inst, 0, 3); 1581 inst_cream->Rm = BITS(inst, 0, 3);
1768 1582
1769 return inst_base; 1583 return inst_base;
1770} 1584}
1771ARM_INST_PTR INTERPRETER_TRANSLATE(bxj)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 1585ARM_INST_PTR INTERPRETER_TRANSLATE(bxj)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("BXJ"); }
1772ARM_INST_PTR INTERPRETER_TRANSLATE(cdp)(unsigned int inst, int index){ 1586ARM_INST_PTR INTERPRETER_TRANSLATE(cdp)(unsigned int inst, int index){
1773 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cdp_inst)); 1587 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cdp_inst));
1774 cdp_inst *inst_cream = (cdp_inst *)inst_base->component; 1588 cdp_inst *inst_cream = (cdp_inst *)inst_base->component;
1775 inst_base->cond = BITS(inst, 28, 31); 1589 inst_base->cond = BITS(inst, 28, 31);
1776 inst_base->idx = index; 1590 inst_base->idx = index;
1777 inst_base->br = NON_BRANCH; 1591 inst_base->br = NON_BRANCH;
1778 inst_base->load_r15 = 0; 1592 inst_base->load_r15 = 0;
1779 1593
1780 inst_cream->CRm = BITS(inst, 0, 3); 1594 inst_cream->CRm = BITS(inst, 0, 3);
1781 inst_cream->CRd = BITS(inst, 12, 15); 1595 inst_cream->CRd = BITS(inst, 12, 15);
1782 inst_cream->CRn = BITS(inst, 16, 19); 1596 inst_cream->CRn = BITS(inst, 16, 19);
1783 inst_cream->cp_num = BITS(inst, 8, 11); 1597 inst_cream->cp_num = BITS(inst, 8, 11);
1784 inst_cream->opcode_2 = BITS(inst, 5, 7); 1598 inst_cream->opcode_2 = BITS(inst, 5, 7);
1785 inst_cream->opcode_1 = BITS(inst, 20, 23); 1599 inst_cream->opcode_1 = BITS(inst, 20, 23);
1786 inst_cream->inst = inst; 1600 inst_cream->inst = inst;
1787 1601
1788 DEBUG_LOG(ARM11, "in func %s inst %x index %x\n", __FUNCTION__, inst, index); 1602 LOG_TRACE(Core_ARM11, "inst %x index %x", inst, index);
1789 return inst_base; 1603 return inst_base;
1790} 1604}
1791ARM_INST_PTR INTERPRETER_TRANSLATE(clrex)(unsigned int inst, int index) 1605ARM_INST_PTR INTERPRETER_TRANSLATE(clrex)(unsigned int inst, int index)
1792{ 1606{
1793 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clrex_inst)); 1607 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clrex_inst));
1794 inst_base->cond = BITS(inst, 28, 31); 1608 inst_base->cond = BITS(inst, 28, 31);
1795 inst_base->idx = index; 1609 inst_base->idx = index;
1796 inst_base->br = NON_BRANCH; 1610 inst_base->br = NON_BRANCH;
1797 1611
1798 return inst_base; 1612 return inst_base;
1799} 1613}
1800ARM_INST_PTR INTERPRETER_TRANSLATE(clz)(unsigned int inst, int index) 1614ARM_INST_PTR INTERPRETER_TRANSLATE(clz)(unsigned int inst, int index)
1801{ 1615{
1802 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clz_inst)); 1616 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(clz_inst));
1803 clz_inst *inst_cream = (clz_inst *)inst_base->component; 1617 clz_inst *inst_cream = (clz_inst *)inst_base->component;
1804 1618
1805 inst_base->cond = BITS(inst, 28, 31); 1619 inst_base->cond = BITS(inst, 28, 31);
1806 inst_base->idx = index; 1620 inst_base->idx = index;
1807 inst_base->br = NON_BRANCH; 1621 inst_base->br = NON_BRANCH;
1808 inst_base->load_r15 = 0; 1622 inst_base->load_r15 = 0;
1809 1623
1810 inst_cream->Rm = BITS(inst, 0, 3); 1624 inst_cream->Rm = BITS(inst, 0, 3);
1811 inst_cream->Rd = BITS(inst, 12, 15); 1625 inst_cream->Rd = BITS(inst, 12, 15);
1812 if (CHECK_RM) 1626 if (CHECK_RM)
1813 inst_base->load_r15 = 1; 1627 inst_base->load_r15 = 1;
1814 1628
1815 return inst_base; 1629 return inst_base;
1816} 1630}
1817ARM_INST_PTR INTERPRETER_TRANSLATE(cmn)(unsigned int inst, int index) 1631ARM_INST_PTR INTERPRETER_TRANSLATE(cmn)(unsigned int inst, int index)
1818{ 1632{
1819 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmn_inst)); 1633 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmn_inst));
1820 cmn_inst *inst_cream = (cmn_inst *)inst_base->component; 1634 cmn_inst *inst_cream = (cmn_inst *)inst_base->component;
1821 1635
1822 inst_base->cond = BITS(inst, 28, 31); 1636 inst_base->cond = BITS(inst, 28, 31);
1823 inst_base->idx = index; 1637 inst_base->idx = index;
1824 inst_base->br = NON_BRANCH; 1638 inst_base->br = NON_BRANCH;
1825 inst_base->load_r15 = 0; 1639 inst_base->load_r15 = 0;
1826 1640
1827 inst_cream->I = BIT(inst, 25); 1641 inst_cream->I = BIT(inst, 25);
1828 //inst_cream->S = BIT(inst, 20); 1642 //inst_cream->S = BIT(inst, 20);
1829 inst_cream->Rn = BITS(inst, 16, 19); 1643 inst_cream->Rn = BITS(inst, 16, 19);
1830 //inst_cream->Rd = BITS(inst, 12, 15); 1644 //inst_cream->Rd = BITS(inst, 12, 15);
1831 if (CHECK_RN) 1645 if (CHECK_RN)
1832 inst_base->load_r15 = 1; 1646 inst_base->load_r15 = 1;
1833 inst_cream->shifter_operand = BITS(inst, 0, 11); 1647 inst_cream->shifter_operand = BITS(inst, 0, 11);
1834 inst_cream->shtop_func = get_shtop(inst); 1648 inst_cream->shtop_func = get_shtop(inst);
1835 return inst_base; 1649 return inst_base;
1836} 1650}
1837ARM_INST_PTR INTERPRETER_TRANSLATE(cmp)(unsigned int inst, int index) 1651ARM_INST_PTR INTERPRETER_TRANSLATE(cmp)(unsigned int inst, int index)
1838{ 1652{
1839 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmp_inst)); 1653 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cmp_inst));
1840 cmp_inst *inst_cream = (cmp_inst *)inst_base->component; 1654 cmp_inst *inst_cream = (cmp_inst *)inst_base->component;
1841 1655
1842 inst_base->cond = BITS(inst, 28, 31); 1656 inst_base->cond = BITS(inst, 28, 31);
1843 inst_base->idx = index; 1657 inst_base->idx = index;
1844 inst_base->br = NON_BRANCH; 1658 inst_base->br = NON_BRANCH;
1845 inst_base->load_r15 = 0; 1659 inst_base->load_r15 = 0;
1846 1660
1847 inst_cream->I = BIT(inst, 25); 1661 inst_cream->I = BIT(inst, 25);
1848 inst_cream->Rn = BITS(inst, 16, 19); 1662 inst_cream->Rn = BITS(inst, 16, 19);
1849 if (CHECK_RN) 1663 if (CHECK_RN)
1850 inst_base->load_r15 = 1; 1664 inst_base->load_r15 = 1;
1851 inst_cream->shifter_operand = BITS(inst, 0, 11); 1665 inst_cream->shifter_operand = BITS(inst, 0, 11);
1852 inst_cream->shtop_func = get_shtop(inst); 1666 inst_cream->shtop_func = get_shtop(inst);
1853 return inst_base; 1667 return inst_base;
1854} 1668}
1855ARM_INST_PTR INTERPRETER_TRANSLATE(cps)(unsigned int inst, int index) 1669ARM_INST_PTR INTERPRETER_TRANSLATE(cps)(unsigned int inst, int index)
1856{ 1670{
1857 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cps_inst)); 1671 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(cps_inst));
1858 cps_inst *inst_cream = (cps_inst *)inst_base->component; 1672 cps_inst *inst_cream = (cps_inst *)inst_base->component;
1859 1673
1860 inst_base->cond = BITS(inst, 28, 31); 1674 inst_base->cond = BITS(inst, 28, 31);
1861 inst_base->idx = index; 1675 inst_base->idx = index;
1862 inst_base->br = NON_BRANCH; 1676 inst_base->br = NON_BRANCH;
1863 1677
1864 inst_cream->imod0 = BIT(inst, 18); 1678 inst_cream->imod0 = BIT(inst, 18);
1865 inst_cream->imod1 = BIT(inst, 19); 1679 inst_cream->imod1 = BIT(inst, 19);
1866 inst_cream->mmod = BIT(inst, 17); 1680 inst_cream->mmod = BIT(inst, 17);
1867 inst_cream->A = BIT(inst, 8); 1681 inst_cream->A = BIT(inst, 8);
1868 inst_cream->I = BIT(inst, 7); 1682 inst_cream->I = BIT(inst, 7);
1869 inst_cream->F = BIT(inst, 6); 1683 inst_cream->F = BIT(inst, 6);
1870 inst_cream->mode = BITS(inst, 0, 4); 1684 inst_cream->mode = BITS(inst, 0, 4);
1871 1685
1872 return inst_base; 1686 return inst_base;
1873} 1687}
1874ARM_INST_PTR INTERPRETER_TRANSLATE(cpy)(unsigned int inst, int index) 1688ARM_INST_PTR INTERPRETER_TRANSLATE(cpy)(unsigned int inst, int index)
1875{ 1689{
1876 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst)); 1690 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst));
1877 mov_inst *inst_cream = (mov_inst *)inst_base->component; 1691 mov_inst *inst_cream = (mov_inst *)inst_base->component;
1878 1692
1879 inst_base->cond = BITS(inst, 28, 31); 1693 inst_base->cond = BITS(inst, 28, 31);
1880 inst_base->idx = index; 1694 inst_base->idx = index;
1881 inst_base->br = NON_BRANCH; 1695 inst_base->br = NON_BRANCH;
1882 1696
1883 inst_cream->I = BIT(inst, 25); 1697 inst_cream->I = BIT(inst, 25);
1884 inst_cream->S = BIT(inst, 20); 1698 inst_cream->S = BIT(inst, 20);
1885 inst_cream->Rd = BITS(inst, 12, 15); 1699 inst_cream->Rd = BITS(inst, 12, 15);
1886 inst_cream->shifter_operand = BITS(inst, 0, 11); 1700 inst_cream->shifter_operand = BITS(inst, 0, 11);
1887 inst_cream->shtop_func = get_shtop(inst); 1701 inst_cream->shtop_func = get_shtop(inst);
1888 1702
1889 if (inst_cream->Rd == 15) { 1703 if (inst_cream->Rd == 15) {
1890 inst_base->br = INDIRECT_BRANCH; 1704 inst_base->br = INDIRECT_BRANCH;
1891 } 1705 }
1892 return inst_base; 1706 return inst_base;
1893} 1707}
1894ARM_INST_PTR INTERPRETER_TRANSLATE(eor)(unsigned int inst, int index) 1708ARM_INST_PTR INTERPRETER_TRANSLATE(eor)(unsigned int inst, int index)
1895{ 1709{
1896 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(eor_inst)); 1710 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(eor_inst));
1897 eor_inst *inst_cream = (eor_inst *)inst_base->component; 1711 eor_inst *inst_cream = (eor_inst *)inst_base->component;
1898 1712
1899 inst_base->cond = BITS(inst, 28, 31); 1713 inst_base->cond = BITS(inst, 28, 31);
1900 inst_base->idx = index; 1714 inst_base->idx = index;
1901 inst_base->br = NON_BRANCH; 1715 inst_base->br = NON_BRANCH;
1902 inst_base->load_r15 = 0; 1716 inst_base->load_r15 = 0;
1903 1717
1904 inst_cream->I = BIT(inst, 25); 1718 inst_cream->I = BIT(inst, 25);
1905 inst_cream->S = BIT(inst, 20); 1719 inst_cream->S = BIT(inst, 20);
1906 inst_cream->Rn = BITS(inst, 16, 19); 1720 inst_cream->Rn = BITS(inst, 16, 19);
1907 inst_cream->Rd = BITS(inst, 12, 15); 1721 inst_cream->Rd = BITS(inst, 12, 15);
1908 if (CHECK_RN) 1722 if (CHECK_RN)
1909 inst_base->load_r15 = 1; 1723 inst_base->load_r15 = 1;
1910 inst_cream->shifter_operand = BITS(inst, 0, 11); 1724 inst_cream->shifter_operand = BITS(inst, 0, 11);
1911 inst_cream->shtop_func = get_shtop(inst); 1725 inst_cream->shtop_func = get_shtop(inst);
1912 if (inst_cream->Rd == 15) { 1726 if (inst_cream->Rd == 15) {
1913 inst_base->br = INDIRECT_BRANCH; 1727 inst_base->br = INDIRECT_BRANCH;
1914 } 1728 }
1915 return inst_base; 1729 return inst_base;
1916} 1730}
1917ARM_INST_PTR INTERPRETER_TRANSLATE(ldc)(unsigned int inst, int index) 1731ARM_INST_PTR INTERPRETER_TRANSLATE(ldc)(unsigned int inst, int index)
1918{ 1732{
1919 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldc_inst)); 1733 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldc_inst));
1920 inst_base->cond = BITS(inst, 28, 31); 1734 inst_base->cond = BITS(inst, 28, 31);
1921 inst_base->idx = index; 1735 inst_base->idx = index;
1922 inst_base->br = NON_BRANCH; 1736 inst_base->br = NON_BRANCH;
1923 1737
1924 return inst_base; 1738 return inst_base;
1925} 1739}
1926ARM_INST_PTR INTERPRETER_TRANSLATE(ldm)(unsigned int inst, int index) 1740ARM_INST_PTR INTERPRETER_TRANSLATE(ldm)(unsigned int inst, int index)
1927{ 1741{
1928 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 1742 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
1929 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 1743 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
1930 1744
1931 inst_base->cond = BITS(inst, 28, 31); 1745 inst_base->cond = BITS(inst, 28, 31);
1932 inst_base->idx = index; 1746 inst_base->idx = index;
1933 inst_base->br = NON_BRANCH; 1747 inst_base->br = NON_BRANCH;
1934 1748
1935 inst_cream->inst = inst; 1749 inst_cream->inst = inst;
1936 inst_cream->get_addr = get_calc_addr_op(inst); 1750 inst_cream->get_addr = get_calc_addr_op(inst);
1937 1751
1938 if (BIT(inst, 15)) { 1752 if (BIT(inst, 15)) {
1939 inst_base->br = INDIRECT_BRANCH; 1753 inst_base->br = INDIRECT_BRANCH;
1940 } 1754 }
1941 return inst_base; 1755 return inst_base;
1942} 1756}
1943ARM_INST_PTR INTERPRETER_TRANSLATE(sxth)(unsigned int inst, int index) 1757ARM_INST_PTR INTERPRETER_TRANSLATE(sxth)(unsigned int inst, int index)
1944{ 1758{
1945 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst)); 1759 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst));
1946 sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component; 1760 sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component;
1947 1761
1948 inst_base->cond = BITS(inst, 28, 31); 1762 inst_base->cond = BITS(inst, 28, 31);
1949 inst_base->idx = index; 1763 inst_base->idx = index;
1950 inst_base->br = NON_BRANCH; 1764 inst_base->br = NON_BRANCH;
1951 inst_base->load_r15 = 0; 1765 inst_base->load_r15 = 0;
1952 1766
1953 inst_cream->Rd = BITS(inst, 12, 15); 1767 inst_cream->Rd = BITS(inst, 12, 15);
1954 inst_cream->Rm = BITS(inst, 0, 3); 1768 inst_cream->Rm = BITS(inst, 0, 3);
1955 inst_cream->rotate = BITS(inst, 10, 11); 1769 inst_cream->rotate = BITS(inst, 10, 11);
1956 if (CHECK_RM) 1770 if (CHECK_RM)
1957 inst_base->load_r15 = 1; 1771 inst_base->load_r15 = 1;
1958 1772
1959 return inst_base; 1773 return inst_base;
1960} 1774}
1961ARM_INST_PTR INTERPRETER_TRANSLATE(ldr)(unsigned int inst, int index) 1775ARM_INST_PTR INTERPRETER_TRANSLATE(ldr)(unsigned int inst, int index)
1962{ 1776{
1963 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 1777 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
1964 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 1778 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
1965 1779
1966 inst_base->cond = BITS(inst, 28, 31); 1780 inst_base->cond = BITS(inst, 28, 31);
1967 inst_base->idx = index; 1781 inst_base->idx = index;
1968 inst_base->br = NON_BRANCH; 1782 inst_base->br = NON_BRANCH;
1969 inst_base->load_r15 = 0; 1783 inst_base->load_r15 = 0;
1970 1784
1971 inst_cream->inst = inst; 1785 inst_cream->inst = inst;
1972 inst_cream->get_addr = get_calc_addr_op(inst); 1786 inst_cream->get_addr = get_calc_addr_op(inst);
1973 1787
1974 if (BITS(inst, 12, 15) == 15) { 1788 if (BITS(inst, 12, 15) == 15) {
1975 inst_base->br = INDIRECT_BRANCH; 1789 inst_base->br = INDIRECT_BRANCH;
1976 } 1790 }
1977 return inst_base; 1791 return inst_base;
1978} 1792}
1979 1793
1980ARM_INST_PTR INTERPRETER_TRANSLATE(ldrcond)(unsigned int inst, int index) 1794ARM_INST_PTR INTERPRETER_TRANSLATE(ldrcond)(unsigned int inst, int index)
1981{ 1795{
1982 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 1796 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
1983 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 1797 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
1984 1798
1985 inst_base->cond = BITS(inst, 28, 31); 1799 inst_base->cond = BITS(inst, 28, 31);
1986 inst_base->idx = index; 1800 inst_base->idx = index;
1987 inst_base->br = NON_BRANCH; 1801 inst_base->br = NON_BRANCH;
1988 inst_base->load_r15 = 0; 1802 inst_base->load_r15 = 0;
1989 1803
1990 inst_cream->inst = inst; 1804 inst_cream->inst = inst;
1991 inst_cream->get_addr = get_calc_addr_op(inst); 1805 inst_cream->get_addr = get_calc_addr_op(inst);
1992 1806
1993 if (BITS(inst, 12, 15) == 15) { 1807 if (BITS(inst, 12, 15) == 15) {
1994 inst_base->br = INDIRECT_BRANCH; 1808 inst_base->br = INDIRECT_BRANCH;
1995 } 1809 }
1996 return inst_base; 1810 return inst_base;
1997} 1811}
1998 1812
1999ARM_INST_PTR INTERPRETER_TRANSLATE(uxth)(unsigned int inst, int index) 1813ARM_INST_PTR INTERPRETER_TRANSLATE(uxth)(unsigned int inst, int index)
2000{ 1814{
2001 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst)); 1815 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst));
2002 uxth_inst *inst_cream = (uxth_inst *)inst_base->component; 1816 uxth_inst *inst_cream = (uxth_inst *)inst_base->component;
2003 1817
2004 inst_base->cond = BITS(inst, 28, 31); 1818 inst_base->cond = BITS(inst, 28, 31);
2005 inst_base->idx = index; 1819 inst_base->idx = index;
2006 inst_base->br = NON_BRANCH; 1820 inst_base->br = NON_BRANCH;
2007 inst_base->load_r15 = 0; 1821 inst_base->load_r15 = 0;
2008 1822
2009 inst_cream->Rd = BITS(inst, 12, 15); 1823 inst_cream->Rd = BITS(inst, 12, 15);
2010 inst_cream->rotate = BITS(inst, 10, 11); 1824 inst_cream->rotate = BITS(inst, 10, 11);
2011 inst_cream->Rm = BITS(inst, 0, 3); 1825 inst_cream->Rm = BITS(inst, 0, 3);
2012 if (CHECK_RM) 1826 if (CHECK_RM)
2013 inst_base->load_r15 = 1; 1827 inst_base->load_r15 = 1;
2014 1828
2015 return inst_base; 1829 return inst_base;
2016} 1830}
2017ARM_INST_PTR INTERPRETER_TRANSLATE(uxtah)(unsigned int inst, int index) 1831ARM_INST_PTR INTERPRETER_TRANSLATE(uxtah)(unsigned int inst, int index)
2018{ 1832{
2019 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtah_inst)); 1833 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtah_inst));
2020 uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component; 1834 uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component;
2021 1835
2022 inst_base->cond = BITS(inst, 28, 31); 1836 inst_base->cond = BITS(inst, 28, 31);
2023 inst_base->idx = index; 1837 inst_base->idx = index;
2024 inst_base->br = NON_BRANCH; 1838 inst_base->br = NON_BRANCH;
2025 inst_base->load_r15 = 0; 1839 inst_base->load_r15 = 0;
2026 1840
2027 inst_cream->Rn = BITS(inst, 16, 19); 1841 inst_cream->Rn = BITS(inst, 16, 19);
2028 inst_cream->Rd = BITS(inst, 12, 15); 1842 inst_cream->Rd = BITS(inst, 12, 15);
2029 inst_cream->rotate = BITS(inst, 10, 11); 1843 inst_cream->rotate = BITS(inst, 10, 11);
2030 inst_cream->Rm = BITS(inst, 0, 3); 1844 inst_cream->Rm = BITS(inst, 0, 3);
2031 if (CHECK_RM || CHECK_RN) 1845 if (CHECK_RM || CHECK_RN)
2032 inst_base->load_r15 = 1; 1846 inst_base->load_r15 = 1;
2033 1847
2034 return inst_base; 1848 return inst_base;
2035} 1849}
2036ARM_INST_PTR INTERPRETER_TRANSLATE(ldrb)(unsigned int inst, int index) 1850ARM_INST_PTR INTERPRETER_TRANSLATE(ldrb)(unsigned int inst, int index)
2037{ 1851{
2038 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 1852 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2039 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 1853 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2040 1854
2041 inst_base->cond = BITS(inst, 28, 31); 1855 inst_base->cond = BITS(inst, 28, 31);
2042 inst_base->idx = index; 1856 inst_base->idx = index;
2043 inst_base->br = NON_BRANCH; 1857 inst_base->br = NON_BRANCH;
2044 1858
2045 inst_cream->inst = inst; 1859 inst_cream->inst = inst;
2046 inst_cream->get_addr = get_calc_addr_op(inst); 1860 inst_cream->get_addr = get_calc_addr_op(inst);
2047 1861
2048 if (BITS(inst, 12, 15) == 15) { 1862 if (BITS(inst, 12, 15) == 15) {
2049 inst_base->br = INDIRECT_BRANCH; 1863 inst_base->br = INDIRECT_BRANCH;
2050 } 1864 }
2051 return inst_base; 1865 return inst_base;
2052} 1866}
2053ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index) 1867ARM_INST_PTR INTERPRETER_TRANSLATE(ldrbt)(unsigned int inst, int index)
2054{ 1868{
2055 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 1869 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2056 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 1870 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2057 1871
2058 inst_base->cond = BITS(inst, 28, 31); 1872 inst_base->cond = BITS(inst, 28, 31);
2059 inst_base->idx = index; 1873 inst_base->idx = index;
2060 inst_base->br = NON_BRANCH; 1874 inst_base->br = NON_BRANCH;
2061 1875
2062 inst_cream->inst = inst; 1876 inst_cream->inst = inst;
2063 if (I_BIT == 0) { 1877 if (I_BIT == 0) {
2064 inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); 1878 inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed);
2065 } else { 1879 } else {
2066 DEBUG_MSG; 1880 DEBUG_MSG;
2067 } 1881 }
2068 #if 0 1882 #if 0
2069 inst_cream->get_addr = get_calc_addr_op(inst); 1883 inst_cream->get_addr = get_calc_addr_op(inst);
2070 if(inst == 0x54f13001) { 1884 if(inst == 0x54f13001) {
2071 DEBUG_LOG(ARM11, "get_calc_addr_op:%llx\n", inst_cream->get_addr); 1885 DEBUG_LOG(ARM11, "get_calc_addr_op:%llx\n", inst_cream->get_addr);
2072 } 1886 }
2073 #endif 1887 #endif
2074 1888
2075 if (BITS(inst, 12, 15) == 15) { 1889 if (BITS(inst, 12, 15) == 15) {
2076 inst_base->br = INDIRECT_BRANCH; 1890 inst_base->br = INDIRECT_BRANCH;
2077 } 1891 }
2078 return inst_base; 1892 return inst_base;
2079} 1893}
2080ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index) 1894ARM_INST_PTR INTERPRETER_TRANSLATE(ldrd)(unsigned int inst, int index)
2081{ 1895{
2082 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 1896 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2083 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 1897 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2084 1898
2085 inst_base->cond = BITS(inst, 28, 31); 1899 inst_base->cond = BITS(inst, 28, 31);
2086 inst_base->idx = index; 1900 inst_base->idx = index;
2087 inst_base->br = NON_BRANCH; 1901 inst_base->br = NON_BRANCH;
2088 1902
2089 inst_cream->inst = inst; 1903 inst_cream->inst = inst;
2090 inst_cream->get_addr = get_calc_addr_op(inst); 1904 inst_cream->get_addr = get_calc_addr_op(inst);
2091 1905
2092 return inst_base; 1906 return inst_base;
2093} 1907}
2094 1908
2095ARM_INST_PTR INTERPRETER_TRANSLATE(ldrex)(unsigned int inst, int index) 1909ARM_INST_PTR INTERPRETER_TRANSLATE(ldrex)(unsigned int inst, int index)
2096{ 1910{
2097 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 1911 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2098 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 1912 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2099 1913
2100 inst_base->cond = BITS(inst, 28, 31); 1914 inst_base->cond = BITS(inst, 28, 31);
2101 inst_base->idx = index; 1915 inst_base->idx = index;
2102 inst_base->br = NON_BRANCH; 1916 inst_base->br = NON_BRANCH;
2103 1917
2104 inst_cream->inst = inst; 1918 inst_cream->inst = inst;
2105 //inst_cream->get_addr = get_calc_addr_op(inst); 1919 //inst_cream->get_addr = get_calc_addr_op(inst);
2106 1920
2107 if (BITS(inst, 12, 15) == 15) { 1921 if (BITS(inst, 12, 15) == 15) {
2108 inst_base->br = INDIRECT_BRANCH; 1922 inst_base->br = INDIRECT_BRANCH;
2109 } 1923 }
2110 return inst_base; 1924 return inst_base;
2111} 1925}
2112ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexb)(unsigned int inst, int index) 1926ARM_INST_PTR INTERPRETER_TRANSLATE(ldrexb)(unsigned int inst, int index)
2113{ 1927{
2114 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 1928 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2115 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 1929 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2116 1930
2117 inst_base->cond = BITS(inst, 28, 31); 1931 inst_base->cond = BITS(inst, 28, 31);
2118 inst_base->idx = index; 1932 inst_base->idx = index;
2119 inst_base->br = NON_BRANCH; 1933 inst_base->br = NON_BRANCH;
2120 1934
2121 inst_cream->inst = inst; 1935 inst_cream->inst = inst;
2122 inst_cream->get_addr = get_calc_addr_op(inst); 1936 inst_cream->get_addr = get_calc_addr_op(inst);
2123 1937
2124 if (BITS(inst, 12, 15) == 15) { 1938 if (BITS(inst, 12, 15) == 15) {
2125 inst_base->br = INDIRECT_BRANCH; 1939 inst_base->br = INDIRECT_BRANCH;
2126 } 1940 }
2127 return inst_base; 1941 return inst_base;
2128} 1942}
2129ARM_INST_PTR INTERPRETER_TRANSLATE(ldrh)(unsigned int inst, int index) 1943ARM_INST_PTR INTERPRETER_TRANSLATE(ldrh)(unsigned int inst, int index)
2130{ 1944{
2131 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 1945 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2132 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 1946 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2133 1947
2134 inst_base->cond = BITS(inst, 28, 31); 1948 inst_base->cond = BITS(inst, 28, 31);
2135 inst_base->idx = index; 1949 inst_base->idx = index;
2136 inst_base->br = NON_BRANCH; 1950 inst_base->br = NON_BRANCH;
2137 1951
2138 inst_cream->inst = inst; 1952 inst_cream->inst = inst;
2139 inst_cream->get_addr = get_calc_addr_op(inst); 1953 inst_cream->get_addr = get_calc_addr_op(inst);
2140 1954
2141 if (BITS(inst, 12, 15) == 15) { 1955 if (BITS(inst, 12, 15) == 15) {
2142 inst_base->br = INDIRECT_BRANCH; 1956 inst_base->br = INDIRECT_BRANCH;
2143 } 1957 }
2144 return inst_base; 1958 return inst_base;
2145} 1959}
2146ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index) 1960ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsb)(unsigned int inst, int index)
2147{ 1961{
2148 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 1962 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2149 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 1963 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2150 1964
2151 inst_base->cond = BITS(inst, 28, 31); 1965 inst_base->cond = BITS(inst, 28, 31);
2152 inst_base->idx = index; 1966 inst_base->idx = index;
2153 inst_base->br = NON_BRANCH; 1967 inst_base->br = NON_BRANCH;
2154 1968
2155 inst_cream->inst = inst; 1969 inst_cream->inst = inst;
2156 inst_cream->get_addr = get_calc_addr_op(inst); 1970 inst_cream->get_addr = get_calc_addr_op(inst);
2157 1971
2158 if (BITS(inst, 12, 15) == 15) { 1972 if (BITS(inst, 12, 15) == 15) {
2159 inst_base->br = INDIRECT_BRANCH; 1973 inst_base->br = INDIRECT_BRANCH;
2160 } 1974 }
2161 return inst_base; 1975 return inst_base;
2162} 1976}
2163ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index) 1977ARM_INST_PTR INTERPRETER_TRANSLATE(ldrsh)(unsigned int inst, int index)
2164{ 1978{
2165 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 1979 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2166 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 1980 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2167 1981
2168 inst_base->cond = BITS(inst, 28, 31); 1982 inst_base->cond = BITS(inst, 28, 31);
2169 inst_base->idx = index; 1983 inst_base->idx = index;
2170 inst_base->br = NON_BRANCH; 1984 inst_base->br = NON_BRANCH;
2171 1985
2172 inst_cream->inst = inst; 1986 inst_cream->inst = inst;
2173 inst_cream->get_addr = get_calc_addr_op(inst); 1987 inst_cream->get_addr = get_calc_addr_op(inst);
2174 1988
2175 if (BITS(inst, 12, 15) == 15) { 1989 if (BITS(inst, 12, 15) == 15) {
2176 inst_base->br = INDIRECT_BRANCH; 1990 inst_base->br = INDIRECT_BRANCH;
2177 } 1991 }
2178 return inst_base; 1992 return inst_base;
2179} 1993}
2180ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index) 1994ARM_INST_PTR INTERPRETER_TRANSLATE(ldrt)(unsigned int inst, int index)
2181{ 1995{
2182 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 1996 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2183 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 1997 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2184 1998
2185 inst_base->cond = BITS(inst, 28, 31); 1999 inst_base->cond = BITS(inst, 28, 31);
2186 inst_base->idx = index; 2000 inst_base->idx = index;
2187 inst_base->br = NON_BRANCH; 2001 inst_base->br = NON_BRANCH;
2188 2002
2189 inst_cream->inst = inst; 2003 inst_cream->inst = inst;
2190 if (I_BIT == 0) { 2004 if (I_BIT == 0) {
2191 inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); 2005 inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed);
2192 } else { 2006 } else {
2193 DEBUG_MSG; 2007 DEBUG_MSG;
2194 } 2008 }
2195 2009
2196 if (BITS(inst, 12, 15) == 15) { 2010 if (BITS(inst, 12, 15) == 15) {
2197 inst_base->br = INDIRECT_BRANCH; 2011 inst_base->br = INDIRECT_BRANCH;
2198 } 2012 }
2199 return inst_base; 2013 return inst_base;
2200} 2014}
2201ARM_INST_PTR INTERPRETER_TRANSLATE(mcr)(unsigned int inst, int index) 2015ARM_INST_PTR INTERPRETER_TRANSLATE(mcr)(unsigned int inst, int index)
2202{ 2016{
2203 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mcr_inst)); 2017 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mcr_inst));
2204 mcr_inst *inst_cream = (mcr_inst *)inst_base->component; 2018 mcr_inst *inst_cream = (mcr_inst *)inst_base->component;
2205 inst_base->cond = BITS(inst, 28, 31); 2019 inst_base->cond = BITS(inst, 28, 31);
2206 inst_base->idx = index; 2020 inst_base->idx = index;
2207 inst_base->br = NON_BRANCH; 2021 inst_base->br = NON_BRANCH;
2208 2022
2209 inst_cream->crn = BITS(inst, 16, 19); 2023 inst_cream->crn = BITS(inst, 16, 19);
2210 inst_cream->crm = BITS(inst, 0, 3); 2024 inst_cream->crm = BITS(inst, 0, 3);
2211 inst_cream->opcode_1 = BITS(inst, 21, 23); 2025 inst_cream->opcode_1 = BITS(inst, 21, 23);
2212 inst_cream->opcode_2 = BITS(inst, 5, 7); 2026 inst_cream->opcode_2 = BITS(inst, 5, 7);
2213 inst_cream->Rd = BITS(inst, 12, 15); 2027 inst_cream->Rd = BITS(inst, 12, 15);
2214 inst_cream->cp_num = BITS(inst, 8, 11); 2028 inst_cream->cp_num = BITS(inst, 8, 11);
2215 inst_cream->inst = inst; 2029 inst_cream->inst = inst;
2216 return inst_base; 2030 return inst_base;
2217} 2031}
2218ARM_INST_PTR INTERPRETER_TRANSLATE(mcrr)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2032ARM_INST_PTR INTERPRETER_TRANSLATE(mcrr)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("MCRR"); }
2219ARM_INST_PTR INTERPRETER_TRANSLATE(mla)(unsigned int inst, int index) 2033ARM_INST_PTR INTERPRETER_TRANSLATE(mla)(unsigned int inst, int index)
2220{ 2034{
2221 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mla_inst)); 2035 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mla_inst));
2222 mla_inst *inst_cream = (mla_inst *)inst_base->component; 2036 mla_inst *inst_cream = (mla_inst *)inst_base->component;
2223 2037
2224 inst_base->cond = BITS(inst, 28, 31); 2038 inst_base->cond = BITS(inst, 28, 31);
2225 inst_base->idx = index; 2039 inst_base->idx = index;
2226 inst_base->br = NON_BRANCH; 2040 inst_base->br = NON_BRANCH;
2227 inst_base->load_r15 = 0; 2041 inst_base->load_r15 = 0;
2228 2042
2229 inst_cream->S = BIT(inst, 20); 2043 inst_cream->S = BIT(inst, 20);
2230 inst_cream->Rn = BITS(inst, 12, 15); 2044 inst_cream->Rn = BITS(inst, 12, 15);
2231 inst_cream->Rd = BITS(inst, 16, 19); 2045 inst_cream->Rd = BITS(inst, 16, 19);
2232 inst_cream->Rs = BITS(inst, 8, 11); 2046 inst_cream->Rs = BITS(inst, 8, 11);
2233 inst_cream->Rm = BITS(inst, 0, 3); 2047 inst_cream->Rm = BITS(inst, 0, 3);
2234 2048
2235 if (CHECK_RM || CHECK_RN || CHECK_RS) 2049 if (CHECK_RM || CHECK_RN || CHECK_RS)
2236 inst_base->load_r15 = 1; 2050 inst_base->load_r15 = 1;
2237 2051
2238 return inst_base; 2052 return inst_base;
2239} 2053}
2240ARM_INST_PTR INTERPRETER_TRANSLATE(mov)(unsigned int inst, int index) 2054ARM_INST_PTR INTERPRETER_TRANSLATE(mov)(unsigned int inst, int index)
2241{ 2055{
2242 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst)); 2056 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mov_inst));
2243 mov_inst *inst_cream = (mov_inst *)inst_base->component; 2057 mov_inst *inst_cream = (mov_inst *)inst_base->component;
2244 2058
2245 inst_base->cond = BITS(inst, 28, 31); 2059 inst_base->cond = BITS(inst, 28, 31);
2246 inst_base->idx = index; 2060 inst_base->idx = index;
2247 inst_base->br = NON_BRANCH; 2061 inst_base->br = NON_BRANCH;
2248 2062
2249 inst_cream->I = BIT(inst, 25); 2063 inst_cream->I = BIT(inst, 25);
2250 inst_cream->S = BIT(inst, 20); 2064 inst_cream->S = BIT(inst, 20);
2251 inst_cream->Rd = BITS(inst, 12, 15); 2065 inst_cream->Rd = BITS(inst, 12, 15);
2252 inst_cream->shifter_operand = BITS(inst, 0, 11); 2066 inst_cream->shifter_operand = BITS(inst, 0, 11);
2253 inst_cream->shtop_func = get_shtop(inst); 2067 inst_cream->shtop_func = get_shtop(inst);
2254 2068
2255 if (inst_cream->Rd == 15) { 2069 if (inst_cream->Rd == 15) {
2256 inst_base->br = INDIRECT_BRANCH; 2070 inst_base->br = INDIRECT_BRANCH;
2257 } 2071 }
2258 return inst_base; 2072 return inst_base;
2259} 2073}
2260ARM_INST_PTR INTERPRETER_TRANSLATE(mrc)(unsigned int inst, int index) 2074ARM_INST_PTR INTERPRETER_TRANSLATE(mrc)(unsigned int inst, int index)
2261{ 2075{
2262 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrc_inst)); 2076 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrc_inst));
2263 mrc_inst *inst_cream = (mrc_inst *)inst_base->component; 2077 mrc_inst *inst_cream = (mrc_inst *)inst_base->component;
2264 inst_base->cond = BITS(inst, 28, 31); 2078 inst_base->cond = BITS(inst, 28, 31);
2265 inst_base->idx = index; 2079 inst_base->idx = index;
2266 inst_base->br = NON_BRANCH; 2080 inst_base->br = NON_BRANCH;
2267 2081
2268 inst_cream->crn = BITS(inst, 16, 19); 2082 inst_cream->crn = BITS(inst, 16, 19);
2269 inst_cream->crm = BITS(inst, 0, 3); 2083 inst_cream->crm = BITS(inst, 0, 3);
2270 inst_cream->opcode_1 = BITS(inst, 21, 23); 2084 inst_cream->opcode_1 = BITS(inst, 21, 23);
2271 inst_cream->opcode_2 = BITS(inst, 5, 7); 2085 inst_cream->opcode_2 = BITS(inst, 5, 7);
2272 inst_cream->Rd = BITS(inst, 12, 15); 2086 inst_cream->Rd = BITS(inst, 12, 15);
2273 inst_cream->cp_num = BITS(inst, 8, 11); 2087 inst_cream->cp_num = BITS(inst, 8, 11);
2274 inst_cream->inst = inst; 2088 inst_cream->inst = inst;
2275 return inst_base; 2089 return inst_base;
2276} 2090}
2277ARM_INST_PTR INTERPRETER_TRANSLATE(mrrc)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2091ARM_INST_PTR INTERPRETER_TRANSLATE(mrrc)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("MRRC"); }
2278ARM_INST_PTR INTERPRETER_TRANSLATE(mrs)(unsigned int inst, int index) 2092ARM_INST_PTR INTERPRETER_TRANSLATE(mrs)(unsigned int inst, int index)
2279{ 2093{
2280 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrs_inst)); 2094 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mrs_inst));
2281 mrs_inst *inst_cream = (mrs_inst *)inst_base->component; 2095 mrs_inst *inst_cream = (mrs_inst *)inst_base->component;
2282 2096
2283 inst_base->cond = BITS(inst, 28, 31); 2097 inst_base->cond = BITS(inst, 28, 31);
2284 inst_base->idx = index; 2098 inst_base->idx = index;
2285 inst_base->br = NON_BRANCH; 2099 inst_base->br = NON_BRANCH;
2286 2100
2287 inst_cream->Rd = BITS(inst, 12, 15); 2101 inst_cream->Rd = BITS(inst, 12, 15);
2288 inst_cream->R = BIT(inst, 22); 2102 inst_cream->R = BIT(inst, 22);
2289 2103
2290 return inst_base; 2104 return inst_base;
2291} 2105}
2292ARM_INST_PTR INTERPRETER_TRANSLATE(msr)(unsigned int inst, int index) 2106ARM_INST_PTR INTERPRETER_TRANSLATE(msr)(unsigned int inst, int index)
2293{ 2107{
2294 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(msr_inst)); 2108 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(msr_inst));
2295 msr_inst *inst_cream = (msr_inst *)inst_base->component; 2109 msr_inst *inst_cream = (msr_inst *)inst_base->component;
2296 2110
2297 inst_base->cond = BITS(inst, 28, 31); 2111 inst_base->cond = BITS(inst, 28, 31);
2298 inst_base->idx = index; 2112 inst_base->idx = index;
2299 inst_base->br = NON_BRANCH; 2113 inst_base->br = NON_BRANCH;
2300 2114
2301 inst_cream->field_mask = BITS(inst, 16, 19); 2115 inst_cream->field_mask = BITS(inst, 16, 19);
2302 inst_cream->R = BIT(inst, 22); 2116 inst_cream->R = BIT(inst, 22);
2303 inst_cream->inst = inst; 2117 inst_cream->inst = inst;
2304 2118
2305 return inst_base; 2119 return inst_base;
2306} 2120}
2307ARM_INST_PTR INTERPRETER_TRANSLATE(mul)(unsigned int inst, int index) 2121ARM_INST_PTR INTERPRETER_TRANSLATE(mul)(unsigned int inst, int index)
2308{ 2122{
2309 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mul_inst)); 2123 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mul_inst));
2310 mul_inst *inst_cream = (mul_inst *)inst_base->component; 2124 mul_inst *inst_cream = (mul_inst *)inst_base->component;
2311 2125
2312 inst_base->cond = BITS(inst, 28, 31); 2126 inst_base->cond = BITS(inst, 28, 31);
2313 inst_base->idx = index; 2127 inst_base->idx = index;
2314 inst_base->br = NON_BRANCH; 2128 inst_base->br = NON_BRANCH;
2315 inst_base->load_r15 = 0; 2129 inst_base->load_r15 = 0;
2316 2130
2317 inst_cream->S = BIT(inst, 20); 2131 inst_cream->S = BIT(inst, 20);
2318 inst_cream->Rm = BITS(inst, 0, 3); 2132 inst_cream->Rm = BITS(inst, 0, 3);
2319 inst_cream->Rs = BITS(inst, 8, 11); 2133 inst_cream->Rs = BITS(inst, 8, 11);
2320 inst_cream->Rd = BITS(inst, 16, 19); 2134 inst_cream->Rd = BITS(inst, 16, 19);
2321 2135
2322 if (CHECK_RM || CHECK_RS) 2136 if (CHECK_RM || CHECK_RS)
2323 inst_base->load_r15 = 1; 2137 inst_base->load_r15 = 1;
2324 return inst_base; 2138 return inst_base;
2325} 2139}
2326ARM_INST_PTR INTERPRETER_TRANSLATE(mvn)(unsigned int inst, int index) 2140ARM_INST_PTR INTERPRETER_TRANSLATE(mvn)(unsigned int inst, int index)
2327{ 2141{
2328 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mvn_inst)); 2142 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(mvn_inst));
2329 mvn_inst *inst_cream = (mvn_inst *)inst_base->component; 2143 mvn_inst *inst_cream = (mvn_inst *)inst_base->component;
2330 2144
2331 inst_base->cond = BITS(inst, 28, 31); 2145 inst_base->cond = BITS(inst, 28, 31);
2332 inst_base->idx = index; 2146 inst_base->idx = index;
2333 inst_base->br = NON_BRANCH; 2147 inst_base->br = NON_BRANCH;
2334 2148
2335 inst_cream->I = BIT(inst, 25); 2149 inst_cream->I = BIT(inst, 25);
2336 inst_cream->S = BIT(inst, 20); 2150 inst_cream->S = BIT(inst, 20);
2337 inst_cream->Rd = BITS(inst, 12, 15); 2151 inst_cream->Rd = BITS(inst, 12, 15);
2338 inst_cream->shifter_operand = BITS(inst, 0, 11); 2152 inst_cream->shifter_operand = BITS(inst, 0, 11);
2339 inst_cream->shtop_func = get_shtop(inst); 2153 inst_cream->shtop_func = get_shtop(inst);
2340 2154
2341 if (inst_cream->Rd == 15) { 2155 if (inst_cream->Rd == 15) {
2342 inst_base->br = INDIRECT_BRANCH; 2156 inst_base->br = INDIRECT_BRANCH;
2343 } 2157 }
2344 return inst_base; 2158 return inst_base;
2345 2159
2346} 2160}
2347ARM_INST_PTR INTERPRETER_TRANSLATE(orr)(unsigned int inst, int index) 2161ARM_INST_PTR INTERPRETER_TRANSLATE(orr)(unsigned int inst, int index)
2348{ 2162{
2349 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(orr_inst)); 2163 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(orr_inst));
2350 orr_inst *inst_cream = (orr_inst *)inst_base->component; 2164 orr_inst *inst_cream = (orr_inst *)inst_base->component;
2351 2165
2352 inst_base->cond = BITS(inst, 28, 31); 2166 inst_base->cond = BITS(inst, 28, 31);
2353 inst_base->idx = index; 2167 inst_base->idx = index;
2354 inst_base->br = NON_BRANCH; 2168 inst_base->br = NON_BRANCH;
2355 inst_base->load_r15 = 0; 2169 inst_base->load_r15 = 0;
2356 2170
2357 inst_cream->I = BIT(inst, 25); 2171 inst_cream->I = BIT(inst, 25);
2358 inst_cream->S = BIT(inst, 20); 2172 inst_cream->S = BIT(inst, 20);
2359 inst_cream->Rd = BITS(inst, 12, 15); 2173 inst_cream->Rd = BITS(inst, 12, 15);
2360 inst_cream->Rn = BITS(inst, 16, 19); 2174 inst_cream->Rn = BITS(inst, 16, 19);
2361 inst_cream->shifter_operand = BITS(inst, 0, 11); 2175 inst_cream->shifter_operand = BITS(inst, 0, 11);
2362 inst_cream->shtop_func = get_shtop(inst); 2176 inst_cream->shtop_func = get_shtop(inst);
2363 2177
2364 if (CHECK_RN) 2178 if (CHECK_RN)
2365 inst_base->load_r15 = 1; 2179 inst_base->load_r15 = 1;
2366 if (inst_cream->Rd == 15) { 2180 if (inst_cream->Rd == 15) {
2367 inst_base->br = INDIRECT_BRANCH; 2181 inst_base->br = INDIRECT_BRANCH;
2368 } 2182 }
2369 return inst_base; 2183 return inst_base;
2370} 2184}
2371ARM_INST_PTR INTERPRETER_TRANSLATE(pkhbt)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2185
2372ARM_INST_PTR INTERPRETER_TRANSLATE(pkhtb)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2186ARM_INST_PTR INTERPRETER_TRANSLATE(pkhbt)(unsigned int inst, int index)
2187{
2188 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pkh_inst));
2189 pkh_inst *inst_cream = (pkh_inst *)inst_base->component;
2190
2191 inst_base->cond = BITS(inst, 28, 31);
2192 inst_base->idx = index;
2193 inst_base->br = NON_BRANCH;
2194 inst_base->load_r15 = 0;
2195
2196 inst_cream->Rd = BITS(inst, 12, 15);
2197 inst_cream->Rn = BITS(inst, 16, 19);
2198 inst_cream->Rm = BITS(inst, 0, 3);
2199 inst_cream->imm = BITS(inst, 7, 11);
2200
2201 return inst_base;
2202}
2203
2204ARM_INST_PTR INTERPRETER_TRANSLATE(pkhtb)(unsigned int inst, int index)
2205{
2206 return INTERPRETER_TRANSLATE(pkhbt)(inst, index);
2207}
2208
2373ARM_INST_PTR INTERPRETER_TRANSLATE(pld)(unsigned int inst, int index) 2209ARM_INST_PTR INTERPRETER_TRANSLATE(pld)(unsigned int inst, int index)
2374{ 2210{
2375 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pld_inst)); 2211 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(pld_inst));
2376 2212
2377 inst_base->cond = BITS(inst, 28, 31); 2213 inst_base->cond = BITS(inst, 28, 31);
2378 inst_base->idx = index; 2214 inst_base->idx = index;
2379 inst_base->br = NON_BRANCH; 2215 inst_base->br = NON_BRANCH;
2380 inst_base->load_r15 = 0; 2216 inst_base->load_r15 = 0;
2381 2217
2382 return inst_base; 2218 return inst_base;
2383} 2219}
2384ARM_INST_PTR INTERPRETER_TRANSLATE(qadd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2220ARM_INST_PTR INTERPRETER_TRANSLATE(qadd)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("QADD"); }
2385ARM_INST_PTR INTERPRETER_TRANSLATE(qadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2221ARM_INST_PTR INTERPRETER_TRANSLATE(qadd8)(unsigned int inst, int index)
2386ARM_INST_PTR INTERPRETER_TRANSLATE(qadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2222{
2387ARM_INST_PTR INTERPRETER_TRANSLATE(qaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2223 arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
2388ARM_INST_PTR INTERPRETER_TRANSLATE(qdadd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2224 generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
2389ARM_INST_PTR INTERPRETER_TRANSLATE(qdsub)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2225
2390ARM_INST_PTR INTERPRETER_TRANSLATE(qsub)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2226 inst_base->cond = BITS(inst, 28, 31);
2391ARM_INST_PTR INTERPRETER_TRANSLATE(qsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2227 inst_base->idx = index;
2392ARM_INST_PTR INTERPRETER_TRANSLATE(qsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2228 inst_base->br = NON_BRANCH;
2393ARM_INST_PTR INTERPRETER_TRANSLATE(qsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2229 inst_base->load_r15 = 0;
2230
2231 inst_cream->Rm = BITS(inst, 0, 3);
2232 inst_cream->Rn = BITS(inst, 16, 19);
2233 inst_cream->Rd = BITS(inst, 12, 15);
2234 inst_cream->op1 = BITS(inst, 20, 21);
2235 inst_cream->op2 = BITS(inst, 5, 7);
2236
2237 return inst_base;
2238}
2239ARM_INST_PTR INTERPRETER_TRANSLATE(qadd16)(unsigned int inst, int index)
2240{
2241 return INTERPRETER_TRANSLATE(qadd8)(inst, index);
2242}
2243ARM_INST_PTR INTERPRETER_TRANSLATE(qaddsubx)(unsigned int inst, int index)
2244{
2245 return INTERPRETER_TRANSLATE(qadd8)(inst, index);
2246}
2247ARM_INST_PTR INTERPRETER_TRANSLATE(qdadd)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("QDADD"); }
2248ARM_INST_PTR INTERPRETER_TRANSLATE(qdsub)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("QDSUB"); }
2249ARM_INST_PTR INTERPRETER_TRANSLATE(qsub)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("QSUB"); }
2250ARM_INST_PTR INTERPRETER_TRANSLATE(qsub8)(unsigned int inst, int index)
2251{
2252 return INTERPRETER_TRANSLATE(qadd8)(inst, index);
2253}
2254ARM_INST_PTR INTERPRETER_TRANSLATE(qsub16)(unsigned int inst, int index)
2255{
2256 return INTERPRETER_TRANSLATE(qadd8)(inst, index);
2257}
2258ARM_INST_PTR INTERPRETER_TRANSLATE(qsubaddx)(unsigned int inst, int index)
2259{
2260 return INTERPRETER_TRANSLATE(qadd8)(inst, index);
2261}
2394ARM_INST_PTR INTERPRETER_TRANSLATE(rev)(unsigned int inst, int index) 2262ARM_INST_PTR INTERPRETER_TRANSLATE(rev)(unsigned int inst, int index)
2395{ 2263{
2396 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst)); 2264 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst));
2397 rev_inst *inst_cream = (rev_inst *)inst_base->component; 2265 rev_inst *inst_cream = (rev_inst *)inst_base->component;
2398 2266
2399 inst_base->cond = BITS(inst, 28, 31); 2267 inst_base->cond = BITS(inst, 28, 31);
2400 inst_base->idx = index; 2268 inst_base->idx = index;
2401 inst_base->br = NON_BRANCH; 2269 inst_base->br = NON_BRANCH;
2402 inst_base->load_r15 = 0; 2270 inst_base->load_r15 = 0;
2403 2271
2404 inst_cream->Rm = BITS(inst, 0, 3); 2272 inst_cream->Rm = BITS(inst, 0, 3);
2405 inst_cream->Rd = BITS(inst, 12, 15); 2273 inst_cream->Rd = BITS(inst, 12, 15);
2406 2274
2407 return inst_base; 2275 return inst_base;
2408} 2276}
2409ARM_INST_PTR INTERPRETER_TRANSLATE(rev16)(unsigned int inst, int index){ 2277ARM_INST_PTR INTERPRETER_TRANSLATE(rev16)(unsigned int inst, int index){
2410 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst)); 2278 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rev_inst));
2411 rev_inst *inst_cream = (rev_inst *)inst_base->component; 2279 rev_inst *inst_cream = (rev_inst *)inst_base->component;
2412 2280
2413 inst_base->cond = BITS(inst, 28, 31); 2281 inst_base->cond = BITS(inst, 28, 31);
2414 inst_base->idx = index; 2282 inst_base->idx = index;
2415 inst_base->br = NON_BRANCH; 2283 inst_base->br = NON_BRANCH;
2416 inst_base->load_r15 = 0; 2284 inst_base->load_r15 = 0;
2417 2285
2418 inst_cream->Rm = BITS(inst, 0, 3); 2286 inst_cream->Rm = BITS(inst, 0, 3);
2419 inst_cream->Rd = BITS(inst, 12, 15); 2287 inst_cream->Rd = BITS(inst, 12, 15);
2420 2288
2421 return inst_base; 2289 return inst_base;
2422} 2290}
2423ARM_INST_PTR INTERPRETER_TRANSLATE(revsh)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2291ARM_INST_PTR INTERPRETER_TRANSLATE(revsh)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("REVSH"); }
2424ARM_INST_PTR INTERPRETER_TRANSLATE(rfe)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2292ARM_INST_PTR INTERPRETER_TRANSLATE(rfe)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("RFE"); }
2425ARM_INST_PTR INTERPRETER_TRANSLATE(rsb)(unsigned int inst, int index) 2293ARM_INST_PTR INTERPRETER_TRANSLATE(rsb)(unsigned int inst, int index)
2426{ 2294{
2427 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsb_inst)); 2295 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsb_inst));
2428 rsb_inst *inst_cream = (rsb_inst *)inst_base->component; 2296 rsb_inst *inst_cream = (rsb_inst *)inst_base->component;
2429 2297
2430 inst_base->cond = BITS(inst, 28, 31); 2298 inst_base->cond = BITS(inst, 28, 31);
2431 inst_base->idx = index; 2299 inst_base->idx = index;
2432 inst_base->br = NON_BRANCH; 2300 inst_base->br = NON_BRANCH;
2433 inst_base->load_r15 = 0; 2301 inst_base->load_r15 = 0;
2434 2302
2435 inst_cream->I = BIT(inst, 25); 2303 inst_cream->I = BIT(inst, 25);
2436 inst_cream->S = BIT(inst, 20); 2304 inst_cream->S = BIT(inst, 20);
2437 inst_cream->Rn = BITS(inst, 16, 19); 2305 inst_cream->Rn = BITS(inst, 16, 19);
2438 inst_cream->Rd = BITS(inst, 12, 15); 2306 inst_cream->Rd = BITS(inst, 12, 15);
2439 inst_cream->shifter_operand = BITS(inst, 0, 11); 2307 inst_cream->shifter_operand = BITS(inst, 0, 11);
2440 inst_cream->shtop_func = get_shtop(inst); 2308 inst_cream->shtop_func = get_shtop(inst);
2441 if (CHECK_RN) 2309 if (CHECK_RN)
2442 inst_base->load_r15 = 1; 2310 inst_base->load_r15 = 1;
2443 2311
2444 if (inst_cream->Rd == 15) { 2312 if (inst_cream->Rd == 15) {
2445 inst_base->br = INDIRECT_BRANCH; 2313 inst_base->br = INDIRECT_BRANCH;
2446 } 2314 }
2447 return inst_base; 2315 return inst_base;
2448} 2316}
2449ARM_INST_PTR INTERPRETER_TRANSLATE(rsc)(unsigned int inst, int index) 2317ARM_INST_PTR INTERPRETER_TRANSLATE(rsc)(unsigned int inst, int index)
2450{ 2318{
2451 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsc_inst)); 2319 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(rsc_inst));
2452 rsc_inst *inst_cream = (rsc_inst *)inst_base->component; 2320 rsc_inst *inst_cream = (rsc_inst *)inst_base->component;
2453 2321
2454 inst_base->cond = BITS(inst, 28, 31); 2322 inst_base->cond = BITS(inst, 28, 31);
2455 inst_base->idx = index; 2323 inst_base->idx = index;
2456 inst_base->br = NON_BRANCH; 2324 inst_base->br = NON_BRANCH;
2457 inst_base->load_r15 = 0; 2325 inst_base->load_r15 = 0;
2458 2326
2459 inst_cream->I = BIT(inst, 25); 2327 inst_cream->I = BIT(inst, 25);
2460 inst_cream->S = BIT(inst, 20); 2328 inst_cream->S = BIT(inst, 20);
2461 inst_cream->Rn = BITS(inst, 16, 19); 2329 inst_cream->Rn = BITS(inst, 16, 19);
2462 inst_cream->Rd = BITS(inst, 12, 15); 2330 inst_cream->Rd = BITS(inst, 12, 15);
2463 inst_cream->shifter_operand = BITS(inst, 0, 11); 2331 inst_cream->shifter_operand = BITS(inst, 0, 11);
2464 inst_cream->shtop_func = get_shtop(inst); 2332 inst_cream->shtop_func = get_shtop(inst);
2465 if (CHECK_RN) 2333 if (CHECK_RN)
2466 inst_base->load_r15 = 1; 2334 inst_base->load_r15 = 1;
2467 2335
2468 if (inst_cream->Rd == 15) { 2336 if (inst_cream->Rd == 15) {
2469 inst_base->br = INDIRECT_BRANCH; 2337 inst_base->br = INDIRECT_BRANCH;
2470 } 2338 }
2471 return inst_base; 2339 return inst_base;
2472} 2340}
2473ARM_INST_PTR INTERPRETER_TRANSLATE(sadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2341ARM_INST_PTR INTERPRETER_TRANSLATE(sadd8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SADD8"); }
2474ARM_INST_PTR INTERPRETER_TRANSLATE(sadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2342ARM_INST_PTR INTERPRETER_TRANSLATE(sadd16)(unsigned int inst, int index)
2475ARM_INST_PTR INTERPRETER_TRANSLATE(saddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2343{
2344 arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
2345 generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
2346
2347 inst_base->cond = BITS(inst, 28, 31);
2348 inst_base->idx = index;
2349 inst_base->br = NON_BRANCH;
2350 inst_base->load_r15 = 0;
2351
2352 inst_cream->Rm = BITS(inst, 0, 3);
2353 inst_cream->Rn = BITS(inst, 16, 19);
2354 inst_cream->Rd = BITS(inst, 12, 15);
2355 inst_cream->op1 = BITS(inst, 20, 21);
2356 inst_cream->op2 = BITS(inst, 5, 7);
2357
2358 return inst_base;
2359}
2360ARM_INST_PTR INTERPRETER_TRANSLATE(saddsubx)(unsigned int inst, int index)
2361{
2362 return INTERPRETER_TRANSLATE(sadd16)(inst, index);
2363}
2476ARM_INST_PTR INTERPRETER_TRANSLATE(sbc)(unsigned int inst, int index) 2364ARM_INST_PTR INTERPRETER_TRANSLATE(sbc)(unsigned int inst, int index)
2477{ 2365{
2478 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sbc_inst)); 2366 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sbc_inst));
2479 sbc_inst *inst_cream = (sbc_inst *)inst_base->component; 2367 sbc_inst *inst_cream = (sbc_inst *)inst_base->component;
2480 2368
2481 inst_base->cond = BITS(inst, 28, 31); 2369 inst_base->cond = BITS(inst, 28, 31);
2482 inst_base->idx = index; 2370 inst_base->idx = index;
2483 inst_base->br = NON_BRANCH; 2371 inst_base->br = NON_BRANCH;
2484 inst_base->load_r15 = 0; 2372 inst_base->load_r15 = 0;
2485 2373
2486 inst_cream->I = BIT(inst, 25); 2374 inst_cream->I = BIT(inst, 25);
2487 inst_cream->S = BIT(inst, 20); 2375 inst_cream->S = BIT(inst, 20);
2488 inst_cream->Rn = BITS(inst, 16, 19); 2376 inst_cream->Rn = BITS(inst, 16, 19);
2489 inst_cream->Rd = BITS(inst, 12, 15); 2377 inst_cream->Rd = BITS(inst, 12, 15);
2490 inst_cream->shifter_operand = BITS(inst, 0, 11); 2378 inst_cream->shifter_operand = BITS(inst, 0, 11);
2491 inst_cream->shtop_func = get_shtop(inst); 2379 inst_cream->shtop_func = get_shtop(inst);
2492 if (CHECK_RN) 2380 if (CHECK_RN)
2493 inst_base->load_r15 = 1; 2381 inst_base->load_r15 = 1;
2494 2382
2495 if (inst_cream->Rd == 15) { 2383 if (inst_cream->Rd == 15) {
2496 inst_base->br = INDIRECT_BRANCH; 2384 inst_base->br = INDIRECT_BRANCH;
2497 } 2385 }
2498 return inst_base; 2386 return inst_base;
2499} 2387}
2500ARM_INST_PTR INTERPRETER_TRANSLATE(sel)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2388ARM_INST_PTR INTERPRETER_TRANSLATE(sel)(unsigned int inst, int index)
2501ARM_INST_PTR INTERPRETER_TRANSLATE(setend)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2389{
2502ARM_INST_PTR INTERPRETER_TRANSLATE(shadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2390 arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
2503ARM_INST_PTR INTERPRETER_TRANSLATE(shadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2391 generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
2504ARM_INST_PTR INTERPRETER_TRANSLATE(shaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2392
2505ARM_INST_PTR INTERPRETER_TRANSLATE(shsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2393 inst_base->cond = BITS(inst, 28, 31);
2506ARM_INST_PTR INTERPRETER_TRANSLATE(shsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2394 inst_base->idx = index;
2507ARM_INST_PTR INTERPRETER_TRANSLATE(shsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2395 inst_base->br = NON_BRANCH;
2396 inst_base->load_r15 = 0;
2397
2398 inst_cream->Rm = BITS(inst, 0, 3);
2399 inst_cream->Rn = BITS(inst, 16, 19);
2400 inst_cream->Rd = BITS(inst, 12, 15);
2401 inst_cream->op1 = BITS(inst, 20, 22);
2402 inst_cream->op2 = BITS(inst, 5, 7);
2403
2404 return inst_base;
2405}
2406ARM_INST_PTR INTERPRETER_TRANSLATE(setend)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SETEND"); }
2407ARM_INST_PTR INTERPRETER_TRANSLATE(shadd16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SHADD16"); }
2408ARM_INST_PTR INTERPRETER_TRANSLATE(shadd8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SHADD8"); }
2409ARM_INST_PTR INTERPRETER_TRANSLATE(shaddsubx)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SHADDSUBX"); }
2410ARM_INST_PTR INTERPRETER_TRANSLATE(shsub16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SHSUB16"); }
2411ARM_INST_PTR INTERPRETER_TRANSLATE(shsub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SHSUB8"); }
2412ARM_INST_PTR INTERPRETER_TRANSLATE(shsubaddx)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SHSUBADDX"); }
2508ARM_INST_PTR INTERPRETER_TRANSLATE(smla)(unsigned int inst, int index) 2413ARM_INST_PTR INTERPRETER_TRANSLATE(smla)(unsigned int inst, int index)
2509{ 2414{
2510 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smla_inst)); 2415 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smla_inst));
2511 smla_inst *inst_cream = (smla_inst *)inst_base->component; 2416 smla_inst *inst_cream = (smla_inst *)inst_base->component;
2512 2417
2513 inst_base->cond = BITS(inst, 28, 31); 2418 inst_base->cond = BITS(inst, 28, 31);
2514 inst_base->idx = index; 2419 inst_base->idx = index;
2515 inst_base->br = NON_BRANCH; 2420 inst_base->br = NON_BRANCH;
2516 inst_base->load_r15 = 0; 2421 inst_base->load_r15 = 0;
2517 2422
2518 inst_cream->x = BIT(inst, 5); 2423 inst_cream->x = BIT(inst, 5);
2519 inst_cream->y = BIT(inst, 6); 2424 inst_cream->y = BIT(inst, 6);
2520 inst_cream->Rm = BITS(inst, 0, 3); 2425 inst_cream->Rm = BITS(inst, 0, 3);
2521 inst_cream->Rs = BITS(inst, 8, 11); 2426 inst_cream->Rs = BITS(inst, 8, 11);
2522 inst_cream->Rd = BITS(inst, 16, 19); 2427 inst_cream->Rd = BITS(inst, 16, 19);
2523 inst_cream->Rn = BITS(inst, 12, 15); 2428 inst_cream->Rn = BITS(inst, 12, 15);
2524 2429
2525 return inst_base; 2430 return inst_base;
2526} 2431}
2527ARM_INST_PTR INTERPRETER_TRANSLATE(smlad)(unsigned int inst, int index){ 2432ARM_INST_PTR INTERPRETER_TRANSLATE(smlad)(unsigned int inst, int index){
2528 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); 2433 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst));
2529 smlad_inst *inst_cream = (smlad_inst *)inst_base->component; 2434 smlad_inst *inst_cream = (smlad_inst *)inst_base->component;
2530 2435
2531 inst_base->cond = BITS(inst, 28, 31); 2436 inst_base->cond = BITS(inst, 28, 31);
2532 inst_base->idx = index; 2437 inst_base->idx = index;
2533 inst_base->br = NON_BRANCH; 2438 inst_base->br = NON_BRANCH;
2534 inst_base->load_r15 = 0; 2439 inst_base->load_r15 = 0;
2535 2440
2536 inst_cream->m = BIT(inst, 4); 2441 inst_cream->m = BIT(inst, 4);
2537 inst_cream->Rn = BITS(inst, 0, 3); 2442 inst_cream->Rn = BITS(inst, 0, 3);
2538 inst_cream->Rm = BITS(inst, 8, 11); 2443 inst_cream->Rm = BITS(inst, 8, 11);
2539 inst_cream->Rd = BITS(inst, 16, 19); 2444 inst_cream->Rd = BITS(inst, 16, 19);
2540 inst_cream->Ra = BITS(inst, 12, 15); 2445 inst_cream->Ra = BITS(inst, 12, 15);
2541 2446
2542 if (CHECK_RM ) 2447 if (CHECK_RM )
2543 inst_base->load_r15 = 1; 2448 inst_base->load_r15 = 1;
2544 return inst_base; 2449 return inst_base;
2545} 2450}
2546ARM_INST_PTR INTERPRETER_TRANSLATE(smlal)(unsigned int inst, int index) 2451ARM_INST_PTR INTERPRETER_TRANSLATE(smlal)(unsigned int inst, int index)
2547{ 2452{
2548 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst)); 2453 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst));
2549 umlal_inst *inst_cream = (umlal_inst *)inst_base->component; 2454 umlal_inst *inst_cream = (umlal_inst *)inst_base->component;
2550 2455
2551 inst_base->cond = BITS(inst, 28, 31); 2456 inst_base->cond = BITS(inst, 28, 31);
2552 inst_base->idx = index; 2457 inst_base->idx = index;
2553 inst_base->br = NON_BRANCH; 2458 inst_base->br = NON_BRANCH;
2554 inst_base->load_r15 = 0; 2459 inst_base->load_r15 = 0;
2555 2460
2556 inst_cream->S = BIT(inst, 20); 2461 inst_cream->S = BIT(inst, 20);
2557 inst_cream->Rm = BITS(inst, 0, 3); 2462 inst_cream->Rm = BITS(inst, 0, 3);
2558 inst_cream->Rs = BITS(inst, 8, 11); 2463 inst_cream->Rs = BITS(inst, 8, 11);
2559 inst_cream->RdHi = BITS(inst, 16, 19); 2464 inst_cream->RdHi = BITS(inst, 16, 19);
2560 inst_cream->RdLo = BITS(inst, 12, 15); 2465 inst_cream->RdLo = BITS(inst, 12, 15);
2561 2466
2562 if (CHECK_RM || CHECK_RS) 2467 if (CHECK_RM || CHECK_RS)
2563 inst_base->load_r15 = 1; 2468 inst_base->load_r15 = 1;
2564 return inst_base; 2469 return inst_base;
2565} 2470}
2566ARM_INST_PTR INTERPRETER_TRANSLATE(smlalxy)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2471ARM_INST_PTR INTERPRETER_TRANSLATE(smlalxy)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SMLALXY"); }
2567ARM_INST_PTR INTERPRETER_TRANSLATE(smlald)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2472ARM_INST_PTR INTERPRETER_TRANSLATE(smlald)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SMLALD"); }
2568ARM_INST_PTR INTERPRETER_TRANSLATE(smlaw)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2473ARM_INST_PTR INTERPRETER_TRANSLATE(smlaw)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SMLAW"); }
2569ARM_INST_PTR INTERPRETER_TRANSLATE(smlsd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2474ARM_INST_PTR INTERPRETER_TRANSLATE(smlsd)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SMLSD"); }
2570ARM_INST_PTR INTERPRETER_TRANSLATE(smlsld)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2475ARM_INST_PTR INTERPRETER_TRANSLATE(smlsld)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SMLSLD"); }
2571ARM_INST_PTR INTERPRETER_TRANSLATE(smmla)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2476ARM_INST_PTR INTERPRETER_TRANSLATE(smmla)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SMMLA"); }
2572ARM_INST_PTR INTERPRETER_TRANSLATE(smmls)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2477ARM_INST_PTR INTERPRETER_TRANSLATE(smmls)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SMMLS"); }
2573ARM_INST_PTR INTERPRETER_TRANSLATE(smmul)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2478ARM_INST_PTR INTERPRETER_TRANSLATE(smmul)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SMMUL"); }
2574ARM_INST_PTR INTERPRETER_TRANSLATE(smuad)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2479ARM_INST_PTR INTERPRETER_TRANSLATE(smuad)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SMUAD"); }
2575ARM_INST_PTR INTERPRETER_TRANSLATE(smul)(unsigned int inst, int index) 2480ARM_INST_PTR INTERPRETER_TRANSLATE(smul)(unsigned int inst, int index)
2576{ 2481{
2577 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smul_inst)); 2482 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smul_inst));
2578 smul_inst *inst_cream = (smul_inst *)inst_base->component; 2483 smul_inst *inst_cream = (smul_inst *)inst_base->component;
2579 2484
2580 inst_base->cond = BITS(inst, 28, 31); 2485 inst_base->cond = BITS(inst, 28, 31);
2581 inst_base->idx = index; 2486 inst_base->idx = index;
2582 inst_base->br = NON_BRANCH; 2487 inst_base->br = NON_BRANCH;
2583 inst_base->load_r15 = 0; 2488 inst_base->load_r15 = 0;
2584 2489
2585 inst_cream->Rd = BITS(inst, 16, 19); 2490 inst_cream->Rd = BITS(inst, 16, 19);
2586 inst_cream->Rs = BITS(inst, 8, 11); 2491 inst_cream->Rs = BITS(inst, 8, 11);
2587 inst_cream->Rm = BITS(inst, 0, 3); 2492 inst_cream->Rm = BITS(inst, 0, 3);
2588 2493
2589 inst_cream->x = BIT(inst, 5); 2494 inst_cream->x = BIT(inst, 5);
2590 inst_cream->y = BIT(inst, 6); 2495 inst_cream->y = BIT(inst, 6);
2591 2496
2592 if (CHECK_RM || CHECK_RS) 2497 if (CHECK_RM || CHECK_RS)
2593 inst_base->load_r15 = 1; 2498 inst_base->load_r15 = 1;
2594 return inst_base; 2499 return inst_base;
2595 2500
2596} 2501}
2597ARM_INST_PTR INTERPRETER_TRANSLATE(smull)(unsigned int inst, int index) 2502ARM_INST_PTR INTERPRETER_TRANSLATE(smull)(unsigned int inst, int index)
2598{ 2503{
2599 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst)); 2504 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst));
2600 umull_inst *inst_cream = (umull_inst *)inst_base->component; 2505 umull_inst *inst_cream = (umull_inst *)inst_base->component;
2601 2506
2602 inst_base->cond = BITS(inst, 28, 31); 2507 inst_base->cond = BITS(inst, 28, 31);
2603 inst_base->idx = index; 2508 inst_base->idx = index;
2604 inst_base->br = NON_BRANCH; 2509 inst_base->br = NON_BRANCH;
2605 inst_base->load_r15 = 0; 2510 inst_base->load_r15 = 0;
2606 2511
2607 inst_cream->S = BIT(inst, 20); 2512 inst_cream->S = BIT(inst, 20);
2608 inst_cream->Rm = BITS(inst, 0, 3); 2513 inst_cream->Rm = BITS(inst, 0, 3);
2609 inst_cream->Rs = BITS(inst, 8, 11); 2514 inst_cream->Rs = BITS(inst, 8, 11);
2610 inst_cream->RdHi = BITS(inst, 16, 19); 2515 inst_cream->RdHi = BITS(inst, 16, 19);
2611 inst_cream->RdLo = BITS(inst, 12, 15); 2516 inst_cream->RdLo = BITS(inst, 12, 15);
2612 2517
2613 if (CHECK_RM || CHECK_RS) 2518 if (CHECK_RM || CHECK_RS)
2614 inst_base->load_r15 = 1; 2519 inst_base->load_r15 = 1;
2615 return inst_base; 2520 return inst_base;
2616} 2521}
2617 2522
2618ARM_INST_PTR INTERPRETER_TRANSLATE(smulw)(unsigned int inst, int index) 2523ARM_INST_PTR INTERPRETER_TRANSLATE(smulw)(unsigned int inst, int index)
2619{ 2524{
2620 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst)); 2525 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(smlad_inst));
2621 smlad_inst *inst_cream = (smlad_inst *)inst_base->component; 2526 smlad_inst *inst_cream = (smlad_inst *)inst_base->component;
2622 2527
2623 inst_base->cond = BITS(inst, 28, 31); 2528 inst_base->cond = BITS(inst, 28, 31);
2624 inst_base->idx = index; 2529 inst_base->idx = index;
2625 inst_base->br = NON_BRANCH; 2530 inst_base->br = NON_BRANCH;
2626 inst_base->load_r15 = 0; 2531 inst_base->load_r15 = 0;
2627 2532
2628 inst_cream->m = BIT(inst, 6); 2533 inst_cream->m = BIT(inst, 6);
2629 inst_cream->Rm = BITS(inst, 8, 11); 2534 inst_cream->Rm = BITS(inst, 8, 11);
2630 inst_cream->Rn = BITS(inst, 0, 3); 2535 inst_cream->Rn = BITS(inst, 0, 3);
2631 inst_cream->Rd = BITS(inst, 16, 19); 2536 inst_cream->Rd = BITS(inst, 16, 19);
2632 2537
2633 if (CHECK_RM || CHECK_RN) 2538 if (CHECK_RM || CHECK_RN)
2634 inst_base->load_r15 = 1; 2539 inst_base->load_r15 = 1;
2635 return inst_base; 2540 return inst_base;
2636} 2541}
2637ARM_INST_PTR INTERPRETER_TRANSLATE(smusd)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2542ARM_INST_PTR INTERPRETER_TRANSLATE(smusd)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SMUSD"); }
2638ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2543ARM_INST_PTR INTERPRETER_TRANSLATE(srs)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SRS"); }
2639ARM_INST_PTR INTERPRETER_TRANSLATE(ssat)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2544ARM_INST_PTR INTERPRETER_TRANSLATE(ssat)(unsigned int inst, int index)
2640ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2545{
2641ARM_INST_PTR INTERPRETER_TRANSLATE(ssub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2546 arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(ssat_inst));
2642ARM_INST_PTR INTERPRETER_TRANSLATE(ssub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2547 ssat_inst* const inst_cream = (ssat_inst*)inst_base->component;
2643ARM_INST_PTR INTERPRETER_TRANSLATE(ssubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2548
2549 inst_base->cond = BITS(inst, 28, 31);
2550 inst_base->idx = index;
2551 inst_base->br = NON_BRANCH;
2552 inst_base->load_r15 = 0;
2553
2554 inst_cream->Rn = BITS(inst, 0, 3);
2555 inst_cream->Rd = BITS(inst, 12, 15);
2556 inst_cream->imm5 = BITS(inst, 7, 11);
2557 inst_cream->sat_imm = BITS(inst, 16, 20);
2558 inst_cream->shift_type = BIT(inst, 6);
2559
2560 return inst_base;
2561}
2562ARM_INST_PTR INTERPRETER_TRANSLATE(ssat16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SSAT16"); }
2563ARM_INST_PTR INTERPRETER_TRANSLATE(ssub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SSUB8"); }
2564ARM_INST_PTR INTERPRETER_TRANSLATE(ssub16)(unsigned int inst, int index)
2565{
2566 return INTERPRETER_TRANSLATE(sadd16)(inst, index);
2567}
2568ARM_INST_PTR INTERPRETER_TRANSLATE(ssubaddx)(unsigned int inst, int index)
2569{
2570 return INTERPRETER_TRANSLATE(sadd16)(inst, index);
2571}
2644ARM_INST_PTR INTERPRETER_TRANSLATE(stc)(unsigned int inst, int index) 2572ARM_INST_PTR INTERPRETER_TRANSLATE(stc)(unsigned int inst, int index)
2645{ 2573{
2646 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(stc_inst)); 2574 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(stc_inst));
2647 inst_base->cond = BITS(inst, 28, 31); 2575 inst_base->cond = BITS(inst, 28, 31);
2648 inst_base->idx = index; 2576 inst_base->idx = index;
2649 inst_base->br = NON_BRANCH; 2577 inst_base->br = NON_BRANCH;
2650 2578
2651 return inst_base; 2579 return inst_base;
2652} 2580}
2653ARM_INST_PTR INTERPRETER_TRANSLATE(stm)(unsigned int inst, int index) 2581ARM_INST_PTR INTERPRETER_TRANSLATE(stm)(unsigned int inst, int index)
2654{ 2582{
2655 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 2583 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2656 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 2584 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2657 2585
2658 inst_base->cond = BITS(inst, 28, 31); 2586 inst_base->cond = BITS(inst, 28, 31);
2659 inst_base->idx = index; 2587 inst_base->idx = index;
2660 inst_base->br = NON_BRANCH; 2588 inst_base->br = NON_BRANCH;
2661 2589
2662 inst_cream->inst = inst; 2590 inst_cream->inst = inst;
2663 inst_cream->get_addr = get_calc_addr_op(inst); 2591 inst_cream->get_addr = get_calc_addr_op(inst);
2664 return inst_base; 2592 return inst_base;
2665} 2593}
2666ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb)(unsigned int inst, int index) 2594ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb)(unsigned int inst, int index)
2667{ 2595{
2668 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst)); 2596 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtb_inst));
2669 sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component; 2597 sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component;
2670 2598
2671 inst_base->cond = BITS(inst, 28, 31); 2599 inst_base->cond = BITS(inst, 28, 31);
2672 inst_base->idx = index; 2600 inst_base->idx = index;
2673 inst_base->br = NON_BRANCH; 2601 inst_base->br = NON_BRANCH;
2674 inst_base->load_r15 = 0; 2602 inst_base->load_r15 = 0;
2675 2603
2676 inst_cream->Rd = BITS(inst, 12, 15); 2604 inst_cream->Rd = BITS(inst, 12, 15);
2677 inst_cream->Rm = BITS(inst, 0, 3); 2605 inst_cream->Rm = BITS(inst, 0, 3);
2678 inst_cream->rotate = BITS(inst, 10, 11); 2606 inst_cream->rotate = BITS(inst, 10, 11);
2679 2607
2680 if (CHECK_RM) 2608 if (CHECK_RM)
2681 inst_base->load_r15 = 1; 2609 inst_base->load_r15 = 1;
2682 return inst_base; 2610 return inst_base;
2683} 2611}
2684ARM_INST_PTR INTERPRETER_TRANSLATE(str)(unsigned int inst, int index) 2612ARM_INST_PTR INTERPRETER_TRANSLATE(str)(unsigned int inst, int index)
2685{ 2613{
2686 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 2614 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2687 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 2615 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2688 2616
2689 inst_base->cond = BITS(inst, 28, 31); 2617 inst_base->cond = BITS(inst, 28, 31);
2690 inst_base->idx = index; 2618 inst_base->idx = index;
2691 inst_base->br = NON_BRANCH; 2619 inst_base->br = NON_BRANCH;
2692 2620
2693 inst_cream->inst = inst; 2621 inst_cream->inst = inst;
2694 inst_cream->get_addr = get_calc_addr_op(inst); 2622 inst_cream->get_addr = get_calc_addr_op(inst);
2695 2623
2696 if (BITS(inst, 12, 15) == 15) { 2624 if (BITS(inst, 12, 15) == 15) {
2697 inst_base->br = INDIRECT_BRANCH; 2625 inst_base->br = INDIRECT_BRANCH;
2698 } 2626 }
2699 return inst_base; 2627 return inst_base;
2700} 2628}
2701ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb)(unsigned int inst, int index) 2629ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb)(unsigned int inst, int index)
2702{ 2630{
2703 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst)); 2631 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxth_inst));
2704 uxth_inst *inst_cream = (uxth_inst *)inst_base->component; 2632 uxth_inst *inst_cream = (uxth_inst *)inst_base->component;
2705 2633
2706 inst_base->cond = BITS(inst, 28, 31); 2634 inst_base->cond = BITS(inst, 28, 31);
2707 inst_base->idx = index; 2635 inst_base->idx = index;
2708 inst_base->br = NON_BRANCH; 2636 inst_base->br = NON_BRANCH;
2709 inst_base->load_r15 = 0; 2637 inst_base->load_r15 = 0;
2710 2638
2711 inst_cream->Rd = BITS(inst, 12, 15); 2639 inst_cream->Rd = BITS(inst, 12, 15);
2712 inst_cream->rotate = BITS(inst, 10, 11); 2640 inst_cream->rotate = BITS(inst, 10, 11);
2713 inst_cream->Rm = BITS(inst, 0, 3); 2641 inst_cream->Rm = BITS(inst, 0, 3);
2714 2642
2715 if (CHECK_RM) 2643 if (CHECK_RM)
2716 inst_base->load_r15 = 1; 2644 inst_base->load_r15 = 1;
2717 return inst_base; 2645 return inst_base;
2718} 2646}
2719ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab)(unsigned int inst, int index) 2647ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab)(unsigned int inst, int index)
2720{ 2648{
2721 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst)); 2649 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst));
2722 uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component; 2650 uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component;
2723 2651
2724 inst_base->cond = BITS(inst, 28, 31); 2652 inst_base->cond = BITS(inst, 28, 31);
2725 inst_base->idx = index; 2653 inst_base->idx = index;
2726 inst_base->br = NON_BRANCH; 2654 inst_base->br = NON_BRANCH;
2727 inst_base->load_r15 = 0; 2655 inst_base->load_r15 = 0;
2728 2656
2729 inst_cream->Rd = BITS(inst, 12, 15); 2657 inst_cream->Rd = BITS(inst, 12, 15);
2730 inst_cream->rotate = BITS(inst, 10, 11); 2658 inst_cream->rotate = BITS(inst, 10, 11);
2731 inst_cream->Rm = BITS(inst, 0, 3); 2659 inst_cream->Rm = BITS(inst, 0, 3);
2732 inst_cream->Rn = BITS(inst, 16, 19); 2660 inst_cream->Rn = BITS(inst, 16, 19);
2733 2661
2734 return inst_base; 2662 return inst_base;
2735} 2663}
2736ARM_INST_PTR INTERPRETER_TRANSLATE(strb)(unsigned int inst, int index) 2664ARM_INST_PTR INTERPRETER_TRANSLATE(strb)(unsigned int inst, int index)
2737{ 2665{
2738 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 2666 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2739 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 2667 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2740 2668
2741 inst_base->cond = BITS(inst, 28, 31); 2669 inst_base->cond = BITS(inst, 28, 31);
2742 inst_base->idx = index; 2670 inst_base->idx = index;
2743 inst_base->br = NON_BRANCH; 2671 inst_base->br = NON_BRANCH;
2744 2672
2745 inst_cream->inst = inst; 2673 inst_cream->inst = inst;
2746 inst_cream->get_addr = get_calc_addr_op(inst); 2674 inst_cream->get_addr = get_calc_addr_op(inst);
2747 2675
2748 if (BITS(inst, 12, 15) == 15) { 2676 if (BITS(inst, 12, 15) == 15) {
2749 inst_base->br = INDIRECT_BRANCH; 2677 inst_base->br = INDIRECT_BRANCH;
2750 } 2678 }
2751 return inst_base; 2679 return inst_base;
2752} 2680}
2753ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index) 2681ARM_INST_PTR INTERPRETER_TRANSLATE(strbt)(unsigned int inst, int index)
2754{ 2682{
2755 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 2683 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2756 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 2684 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2757 2685
2758 inst_base->cond = BITS(inst, 28, 31); 2686 inst_base->cond = BITS(inst, 28, 31);
2759 inst_base->idx = index; 2687 inst_base->idx = index;
2760 inst_base->br = NON_BRANCH; 2688 inst_base->br = NON_BRANCH;
2761 2689
2762 inst_cream->inst = inst; 2690 inst_cream->inst = inst;
2763// inst_cream->get_addr = get_calc_addr_op(inst); 2691// inst_cream->get_addr = get_calc_addr_op(inst);
2764 if (I_BIT == 0) { 2692 if (I_BIT == 0) {
2765 inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); 2693 inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed);
2766 } else { 2694 } else {
2767 DEBUG_MSG; 2695 DEBUG_MSG;
2768 } 2696 }
2769 2697
2770 if (BITS(inst, 12, 15) == 15) { 2698 if (BITS(inst, 12, 15) == 15) {
2771 inst_base->br = INDIRECT_BRANCH; 2699 inst_base->br = INDIRECT_BRANCH;
2772 } 2700 }
2773 return inst_base; 2701 return inst_base;
2774} 2702}
2775ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){ 2703ARM_INST_PTR INTERPRETER_TRANSLATE(strd)(unsigned int inst, int index){
2776 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 2704 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2777 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 2705 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2778 2706
2779 inst_base->cond = BITS(inst, 28, 31); 2707 inst_base->cond = BITS(inst, 28, 31);
2780 inst_base->idx = index; 2708 inst_base->idx = index;
2781 inst_base->br = NON_BRANCH; 2709 inst_base->br = NON_BRANCH;
2782 2710
2783 inst_cream->inst = inst; 2711 inst_cream->inst = inst;
2784 inst_cream->get_addr = get_calc_addr_op(inst); 2712 inst_cream->get_addr = get_calc_addr_op(inst);
2785 2713
2786 if (BITS(inst, 12, 15) == 15) { 2714 if (BITS(inst, 12, 15) == 15) {
2787 inst_base->br = INDIRECT_BRANCH; 2715 inst_base->br = INDIRECT_BRANCH;
2788 } 2716 }
2789 return inst_base; 2717 return inst_base;
2790} 2718}
2791ARM_INST_PTR INTERPRETER_TRANSLATE(strex)(unsigned int inst, int index) 2719ARM_INST_PTR INTERPRETER_TRANSLATE(strex)(unsigned int inst, int index)
2792{ 2720{
2793 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 2721 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2794 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 2722 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2795 2723
2796 inst_base->cond = BITS(inst, 28, 31); 2724 inst_base->cond = BITS(inst, 28, 31);
2797 inst_base->idx = index; 2725 inst_base->idx = index;
2798 inst_base->br = NON_BRANCH; 2726 inst_base->br = NON_BRANCH;
2799 2727
2800 inst_cream->inst = inst; 2728 inst_cream->inst = inst;
2801 inst_cream->get_addr = get_calc_addr_op(inst); 2729 inst_cream->get_addr = get_calc_addr_op(inst);
2802 2730
2803 if (BITS(inst, 12, 15) == 15) { 2731 if (BITS(inst, 12, 15) == 15) {
2804 inst_base->br = INDIRECT_BRANCH; 2732 inst_base->br = INDIRECT_BRANCH;
2805 } 2733 }
2806 return inst_base; 2734 return inst_base;
2807} 2735}
2808ARM_INST_PTR INTERPRETER_TRANSLATE(strexb)(unsigned int inst, int index) 2736ARM_INST_PTR INTERPRETER_TRANSLATE(strexb)(unsigned int inst, int index)
2809{ 2737{
2810 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 2738 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2811 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 2739 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2812 2740
2813 inst_base->cond = BITS(inst, 28, 31); 2741 inst_base->cond = BITS(inst, 28, 31);
2814 inst_base->idx = index; 2742 inst_base->idx = index;
2815 inst_base->br = NON_BRANCH; 2743 inst_base->br = NON_BRANCH;
2816 2744
2817 inst_cream->inst = inst; 2745 inst_cream->inst = inst;
2818 inst_cream->get_addr = get_calc_addr_op(inst); 2746 inst_cream->get_addr = get_calc_addr_op(inst);
2819 2747
2820 if (BITS(inst, 12, 15) == 15) { 2748 if (BITS(inst, 12, 15) == 15) {
2821 inst_base->br = INDIRECT_BRANCH; 2749 inst_base->br = INDIRECT_BRANCH;
2822 } 2750 }
2823 return inst_base; 2751 return inst_base;
2824} 2752}
2825ARM_INST_PTR INTERPRETER_TRANSLATE(strh)(unsigned int inst, int index) 2753ARM_INST_PTR INTERPRETER_TRANSLATE(strh)(unsigned int inst, int index)
2826{ 2754{
2827 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 2755 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2828 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 2756 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2829 2757
2830 inst_base->cond = BITS(inst, 28, 31); 2758 inst_base->cond = BITS(inst, 28, 31);
2831 inst_base->idx = index; 2759 inst_base->idx = index;
2832 inst_base->br = NON_BRANCH; 2760 inst_base->br = NON_BRANCH;
2833 2761
2834 inst_cream->inst = inst; 2762 inst_cream->inst = inst;
2835 inst_cream->get_addr = get_calc_addr_op(inst); 2763 inst_cream->get_addr = get_calc_addr_op(inst);
2836 2764
2837 if (BITS(inst, 12, 15) == 15) { 2765 if (BITS(inst, 12, 15) == 15) {
2838 inst_base->br = INDIRECT_BRANCH; 2766 inst_base->br = INDIRECT_BRANCH;
2839 } 2767 }
2840 return inst_base; 2768 return inst_base;
2841} 2769}
2842ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index) 2770ARM_INST_PTR INTERPRETER_TRANSLATE(strt)(unsigned int inst, int index)
2843{ 2771{
2844 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst)); 2772 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(ldst_inst));
2845 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 2773 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
2846 2774
2847 inst_base->cond = BITS(inst, 28, 31); 2775 inst_base->cond = BITS(inst, 28, 31);
2848 inst_base->idx = index; 2776 inst_base->idx = index;
2849 inst_base->br = NON_BRANCH; 2777 inst_base->br = NON_BRANCH;
2850 2778
2851 inst_cream->inst = inst; 2779 inst_cream->inst = inst;
2852 if (I_BIT == 0) { 2780 if (I_BIT == 0) {
2853 inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed); 2781 inst_cream->get_addr = LnSWoUB(ImmediatePostIndexed);
2854 } else { 2782 } else {
2855 DEBUG_MSG; 2783 DEBUG_MSG;
2856 } 2784 }
2857 2785
2858 if (BITS(inst, 12, 15) == 15) { 2786 if (BITS(inst, 12, 15) == 15) {
2859 inst_base->br = INDIRECT_BRANCH; 2787 inst_base->br = INDIRECT_BRANCH;
2860 } 2788 }
2861 return inst_base; 2789 return inst_base;
2862} 2790}
2863ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index) 2791ARM_INST_PTR INTERPRETER_TRANSLATE(sub)(unsigned int inst, int index)
2864{ 2792{
2865 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sub_inst)); 2793 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sub_inst));
2866 sub_inst *inst_cream = (sub_inst *)inst_base->component; 2794 sub_inst *inst_cream = (sub_inst *)inst_base->component;
2867 2795
2868 inst_base->cond = BITS(inst, 28, 31); 2796 inst_base->cond = BITS(inst, 28, 31);
2869 inst_base->idx = index; 2797 inst_base->idx = index;
2870 inst_base->br = NON_BRANCH; 2798 inst_base->br = NON_BRANCH;
2871 inst_base->load_r15 = 0; 2799 inst_base->load_r15 = 0;
2872 2800
2873 inst_cream->I = BIT(inst, 25); 2801 inst_cream->I = BIT(inst, 25);
2874 inst_cream->S = BIT(inst, 20); 2802 inst_cream->S = BIT(inst, 20);
2875 inst_cream->Rn = BITS(inst, 16, 19); 2803 inst_cream->Rn = BITS(inst, 16, 19);
2876 inst_cream->Rd = BITS(inst, 12, 15); 2804 inst_cream->Rd = BITS(inst, 12, 15);
2877 inst_cream->shifter_operand = BITS(inst, 0, 11); 2805 inst_cream->shifter_operand = BITS(inst, 0, 11);
2878 inst_cream->shtop_func = get_shtop(inst); 2806 inst_cream->shtop_func = get_shtop(inst);
2879 if (inst_cream->Rd == 15) { 2807 if (inst_cream->Rd == 15) {
2880 inst_base->br = INDIRECT_BRANCH; 2808 inst_base->br = INDIRECT_BRANCH;
2881 } 2809 }
2882 if (CHECK_RN) 2810 if (CHECK_RN)
2883 inst_base->load_r15 = 1; 2811 inst_base->load_r15 = 1;
2884 2812
2885 return inst_base; 2813 return inst_base;
2886} 2814}
2887ARM_INST_PTR INTERPRETER_TRANSLATE(swi)(unsigned int inst, int index) 2815ARM_INST_PTR INTERPRETER_TRANSLATE(swi)(unsigned int inst, int index)
2888{ 2816{
2889 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swi_inst)); 2817 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swi_inst));
2890 swi_inst *inst_cream = (swi_inst *)inst_base->component; 2818 swi_inst *inst_cream = (swi_inst *)inst_base->component;
2891 2819
2892 inst_base->cond = BITS(inst, 28, 31); 2820 inst_base->cond = BITS(inst, 28, 31);
2893 inst_base->idx = index; 2821 inst_base->idx = index;
2894 inst_base->br = NON_BRANCH; 2822 inst_base->br = NON_BRANCH;
2895 2823
2896 inst_cream->num = BITS(inst, 0, 23); 2824 inst_cream->num = BITS(inst, 0, 23);
2897 return inst_base; 2825 return inst_base;
2898} 2826}
2899ARM_INST_PTR INTERPRETER_TRANSLATE(swp)(unsigned int inst, int index) 2827ARM_INST_PTR INTERPRETER_TRANSLATE(swp)(unsigned int inst, int index)
2900{ 2828{
2901 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst)); 2829 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst));
2902 swp_inst *inst_cream = (swp_inst *)inst_base->component; 2830 swp_inst *inst_cream = (swp_inst *)inst_base->component;
2903 2831
2904 inst_base->cond = BITS(inst, 28, 31); 2832 inst_base->cond = BITS(inst, 28, 31);
2905 inst_base->idx = index; 2833 inst_base->idx = index;
2906 inst_base->br = NON_BRANCH; 2834 inst_base->br = NON_BRANCH;
2907 2835
2908 inst_cream->Rn = BITS(inst, 16, 19); 2836 inst_cream->Rn = BITS(inst, 16, 19);
2909 inst_cream->Rd = BITS(inst, 12, 15); 2837 inst_cream->Rd = BITS(inst, 12, 15);
2910 inst_cream->Rm = BITS(inst, 0, 3); 2838 inst_cream->Rm = BITS(inst, 0, 3);
2911 2839
2912 if (inst_cream->Rd == 15) { 2840 if (inst_cream->Rd == 15) {
2913 inst_base->br = INDIRECT_BRANCH; 2841 inst_base->br = INDIRECT_BRANCH;
2914 } 2842 }
2915 return inst_base; 2843 return inst_base;
2916} 2844}
2917ARM_INST_PTR INTERPRETER_TRANSLATE(swpb)(unsigned int inst, int index){ 2845ARM_INST_PTR INTERPRETER_TRANSLATE(swpb)(unsigned int inst, int index){
2918 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst)); 2846 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(swp_inst));
2919 swp_inst *inst_cream = (swp_inst *)inst_base->component; 2847 swp_inst *inst_cream = (swp_inst *)inst_base->component;
2920 2848
2921 inst_base->cond = BITS(inst, 28, 31); 2849 inst_base->cond = BITS(inst, 28, 31);
2922 inst_base->idx = index; 2850 inst_base->idx = index;
2923 inst_base->br = NON_BRANCH; 2851 inst_base->br = NON_BRANCH;
2924 2852
2925 inst_cream->Rn = BITS(inst, 16, 19); 2853 inst_cream->Rn = BITS(inst, 16, 19);
2926 inst_cream->Rd = BITS(inst, 12, 15); 2854 inst_cream->Rd = BITS(inst, 12, 15);
2927 inst_cream->Rm = BITS(inst, 0, 3); 2855 inst_cream->Rm = BITS(inst, 0, 3);
2928 2856
2929 if (inst_cream->Rd == 15) { 2857 if (inst_cream->Rd == 15) {
2930 inst_base->br = INDIRECT_BRANCH; 2858 inst_base->br = INDIRECT_BRANCH;
2931 } 2859 }
2932 return inst_base; 2860 return inst_base;
2933} 2861}
2934ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab)(unsigned int inst, int index){ 2862ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab)(unsigned int inst, int index){
2935 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtab_inst)); 2863 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtab_inst));
2936 sxtab_inst *inst_cream = (sxtab_inst *)inst_base->component; 2864 sxtab_inst *inst_cream = (sxtab_inst *)inst_base->component;
2937 2865
2938 inst_base->cond = BITS(inst, 28, 31); 2866 inst_base->cond = BITS(inst, 28, 31);
2939 inst_base->idx = index; 2867 inst_base->idx = index;
2940 inst_base->br = NON_BRANCH; 2868 inst_base->br = NON_BRANCH;
2941 inst_base->load_r15 = 0; 2869 inst_base->load_r15 = 0;
2942 2870
2943 inst_cream->Rd = BITS(inst, 12, 15); 2871 inst_cream->Rd = BITS(inst, 12, 15);
2944 inst_cream->rotate = BITS(inst, 10, 11); 2872 inst_cream->rotate = BITS(inst, 10, 11);
2945 inst_cream->Rm = BITS(inst, 0, 3); 2873 inst_cream->Rm = BITS(inst, 0, 3);
2946 inst_cream->Rn = BITS(inst, 16, 19); 2874 inst_cream->Rn = BITS(inst, 16, 19);
2947 2875
2948 return inst_base; 2876 return inst_base;
2949} 2877}
2950ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2878ARM_INST_PTR INTERPRETER_TRANSLATE(sxtab16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SXTAB16"); }
2951ARM_INST_PTR INTERPRETER_TRANSLATE(sxtah)(unsigned int inst, int index){ 2879ARM_INST_PTR INTERPRETER_TRANSLATE(sxtah)(unsigned int inst, int index){
2952 DEBUG_LOG(ARM11, "in func %s, SXTAH untested\n", __func__); 2880 LOG_WARNING(Core_ARM11, "SXTAH untested");
2953 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtah_inst)); 2881 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(sxtah_inst));
2954 sxtah_inst *inst_cream = (sxtah_inst *)inst_base->component; 2882 sxtah_inst *inst_cream = (sxtah_inst *)inst_base->component;
2955 2883
2956 inst_base->cond = BITS(inst, 28, 31); 2884 inst_base->cond = BITS(inst, 28, 31);
2957 inst_base->idx = index; 2885 inst_base->idx = index;
2958 inst_base->br = NON_BRANCH; 2886 inst_base->br = NON_BRANCH;
2959 inst_base->load_r15 = 0; 2887 inst_base->load_r15 = 0;
2960 2888
2961 inst_cream->Rd = BITS(inst, 12, 15); 2889 inst_cream->Rd = BITS(inst, 12, 15);
2962 inst_cream->rotate = BITS(inst, 10, 11); 2890 inst_cream->rotate = BITS(inst, 10, 11);
2963 inst_cream->Rm = BITS(inst, 0, 3); 2891 inst_cream->Rm = BITS(inst, 0, 3);
2964 inst_cream->Rn = BITS(inst, 16, 19); 2892 inst_cream->Rn = BITS(inst, 16, 19);
2965 2893
2966 return inst_base; 2894 return inst_base;
2967} 2895}
2968ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2896ARM_INST_PTR INTERPRETER_TRANSLATE(sxtb16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("SXTB16"); }
2969ARM_INST_PTR INTERPRETER_TRANSLATE(teq)(unsigned int inst, int index) 2897ARM_INST_PTR INTERPRETER_TRANSLATE(teq)(unsigned int inst, int index)
2970{ 2898{
2971 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(teq_inst)); 2899 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(teq_inst));
2972 teq_inst *inst_cream = (teq_inst *)inst_base->component; 2900 teq_inst *inst_cream = (teq_inst *)inst_base->component;
2973 2901
2974 inst_base->cond = BITS(inst, 28, 31); 2902 inst_base->cond = BITS(inst, 28, 31);
2975 inst_base->idx = index; 2903 inst_base->idx = index;
2976 inst_base->br = NON_BRANCH; 2904 inst_base->br = NON_BRANCH;
2977 inst_base->load_r15 = 0; 2905 inst_base->load_r15 = 0;
2978 2906
2979 inst_cream->I = BIT(inst, 25); 2907 inst_cream->I = BIT(inst, 25);
2980 inst_cream->Rn = BITS(inst, 16, 19); 2908 inst_cream->Rn = BITS(inst, 16, 19);
2981 inst_cream->shifter_operand = BITS(inst, 0, 11); 2909 inst_cream->shifter_operand = BITS(inst, 0, 11);
2982 inst_cream->shtop_func = get_shtop(inst); 2910 inst_cream->shtop_func = get_shtop(inst);
2983 2911
2984 if (CHECK_RN) 2912 if (CHECK_RN)
2985 inst_base->load_r15 = 1; 2913 inst_base->load_r15 = 1;
2986 return inst_base; 2914 return inst_base;
2987} 2915}
2988ARM_INST_PTR INTERPRETER_TRANSLATE(tst)(unsigned int inst, int index) 2916ARM_INST_PTR INTERPRETER_TRANSLATE(tst)(unsigned int inst, int index)
2989{ 2917{
2990 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(tst_inst)); 2918 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(tst_inst));
2991 tst_inst *inst_cream = (tst_inst *)inst_base->component; 2919 tst_inst *inst_cream = (tst_inst *)inst_base->component;
2992 2920
2993 inst_base->cond = BITS(inst, 28, 31); 2921 inst_base->cond = BITS(inst, 28, 31);
2994 inst_base->idx = index; 2922 inst_base->idx = index;
2995 inst_base->br = NON_BRANCH; 2923 inst_base->br = NON_BRANCH;
2996 inst_base->load_r15 = 0; 2924 inst_base->load_r15 = 0;
2997 2925
2998 inst_cream->I = BIT(inst, 25); 2926 inst_cream->I = BIT(inst, 25);
2999 inst_cream->S = BIT(inst, 20); 2927 inst_cream->S = BIT(inst, 20);
3000 inst_cream->Rn = BITS(inst, 16, 19); 2928 inst_cream->Rn = BITS(inst, 16, 19);
3001 inst_cream->Rd = BITS(inst, 12, 15); 2929 inst_cream->Rd = BITS(inst, 12, 15);
3002 inst_cream->shifter_operand = BITS(inst, 0, 11); 2930 inst_cream->shifter_operand = BITS(inst, 0, 11);
3003 inst_cream->shtop_func = get_shtop(inst); 2931 inst_cream->shtop_func = get_shtop(inst);
3004 if (inst_cream->Rd == 15) { 2932 if (inst_cream->Rd == 15) {
3005 inst_base->br = INDIRECT_BRANCH; 2933 inst_base->br = INDIRECT_BRANCH;
3006 } 2934 }
3007 2935
3008 if (CHECK_RN) 2936 if (CHECK_RN)
3009 inst_base->load_r15 = 1; 2937 inst_base->load_r15 = 1;
3010 return inst_base; 2938 return inst_base;
3011} 2939}
3012ARM_INST_PTR INTERPRETER_TRANSLATE(uadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2940ARM_INST_PTR INTERPRETER_TRANSLATE(uadd8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UADD8"); }
3013ARM_INST_PTR INTERPRETER_TRANSLATE(uadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2941ARM_INST_PTR INTERPRETER_TRANSLATE(uadd16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UADD16"); }
3014ARM_INST_PTR INTERPRETER_TRANSLATE(uaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2942ARM_INST_PTR INTERPRETER_TRANSLATE(uaddsubx)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("UADDSUBX"); }
3015ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2943ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd8)(unsigned int inst, int index)
3016ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2944{
3017ARM_INST_PTR INTERPRETER_TRANSLATE(uhaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2945 arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
3018ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2946 generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
3019ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2947
3020ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2948 inst_base->cond = BITS(inst, 28, 31);
3021ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 2949 inst_base->idx = index;
2950 inst_base->br = NON_BRANCH;
2951 inst_base->load_r15 = 0;
2952
2953 inst_cream->op1 = BITS(inst, 20, 21);
2954 inst_cream->op2 = BITS(inst, 5, 7);
2955 inst_cream->Rm = BITS(inst, 0, 3);
2956 inst_cream->Rn = BITS(inst, 16, 19);
2957 inst_cream->Rd = BITS(inst, 12, 15);
2958
2959 return inst_base;
2960}
2961ARM_INST_PTR INTERPRETER_TRANSLATE(uhadd16)(unsigned int inst, int index)
2962{
2963 return INTERPRETER_TRANSLATE(uhadd8)(inst, index);
2964}
2965ARM_INST_PTR INTERPRETER_TRANSLATE(uhaddsubx)(unsigned int inst, int index)
2966{
2967 return INTERPRETER_TRANSLATE(uhadd8)(inst, index);
2968}
2969ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub8)(unsigned int inst, int index)
2970{
2971 return INTERPRETER_TRANSLATE(uhadd8)(inst, index);
2972}
2973ARM_INST_PTR INTERPRETER_TRANSLATE(uhsub16)(unsigned int inst, int index)
2974{
2975 return INTERPRETER_TRANSLATE(uhadd8)(inst, index);
2976}
2977ARM_INST_PTR INTERPRETER_TRANSLATE(uhsubaddx)(unsigned int inst, int index)
2978{
2979 return INTERPRETER_TRANSLATE(uhadd8)(inst, index);
2980}
2981ARM_INST_PTR INTERPRETER_TRANSLATE(umaal)(unsigned int inst, int index)
2982{
2983 arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(umaal_inst));
2984 umaal_inst* const inst_cream = (umaal_inst*)inst_base->component;
2985
2986 inst_base->cond = BITS(inst, 28, 31);
2987 inst_base->idx = index;
2988 inst_base->br = NON_BRANCH;
2989 inst_base->load_r15 = 0;
2990
2991 inst_cream->Rm = BITS(inst, 8, 11);
2992 inst_cream->Rn = BITS(inst, 0, 3);
2993 inst_cream->RdLo = BITS(inst, 12, 15);
2994 inst_cream->RdHi = BITS(inst, 16, 19);
2995
2996 if (CHECK_RM || CHECK_RN)
2997 inst_base->load_r15 = 1;
2998
2999 return inst_base;
3000}
3022ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index) 3001ARM_INST_PTR INTERPRETER_TRANSLATE(umlal)(unsigned int inst, int index)
3023{ 3002{
3024 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst)); 3003 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umlal_inst));
3025 umlal_inst *inst_cream = (umlal_inst *)inst_base->component; 3004 umlal_inst *inst_cream = (umlal_inst *)inst_base->component;
3005
3006 inst_base->cond = BITS(inst, 28, 31);
3007 inst_base->idx = index;
3008 inst_base->br = NON_BRANCH;
3009 inst_base->load_r15 = 0;
3026 3010
3027 inst_base->cond = BITS(inst, 28, 31); 3011 inst_cream->S = BIT(inst, 20);
3028 inst_base->idx = index; 3012 inst_cream->Rm = BITS(inst, 0, 3);
3029 inst_base->br = NON_BRANCH; 3013 inst_cream->Rs = BITS(inst, 8, 11);
3030 inst_base->load_r15 = 0; 3014 inst_cream->RdHi = BITS(inst, 16, 19);
3015 inst_cream->RdLo = BITS(inst, 12, 15);
3031 3016
3032 inst_cream->S = BIT(inst, 20); 3017 if (CHECK_RM || CHECK_RS)
3033 inst_cream->Rm = BITS(inst, 0, 3); 3018 inst_base->load_r15 = 1;
3034 inst_cream->Rs = BITS(inst, 8, 11);
3035 inst_cream->RdHi = BITS(inst, 16, 19);
3036 inst_cream->RdLo = BITS(inst, 12, 15);
3037 3019
3038 if (CHECK_RM || CHECK_RS) 3020 return inst_base;
3039 inst_base->load_r15 = 1;
3040 return inst_base;
3041} 3021}
3042ARM_INST_PTR INTERPRETER_TRANSLATE(umull)(unsigned int inst, int index) 3022ARM_INST_PTR INTERPRETER_TRANSLATE(umull)(unsigned int inst, int index)
3043{ 3023{
3044 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst)); 3024 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(umull_inst));
3045 umull_inst *inst_cream = (umull_inst *)inst_base->component; 3025 umull_inst *inst_cream = (umull_inst *)inst_base->component;
3046 3026
3047 inst_base->cond = BITS(inst, 28, 31); 3027 inst_base->cond = BITS(inst, 28, 31);
3048 inst_base->idx = index; 3028 inst_base->idx = index;
3049 inst_base->br = NON_BRANCH; 3029 inst_base->br = NON_BRANCH;
3050 inst_base->load_r15 = 0; 3030 inst_base->load_r15 = 0;
3051 3031
3052 inst_cream->S = BIT(inst, 20); 3032 inst_cream->S = BIT(inst, 20);
3053 inst_cream->Rm = BITS(inst, 0, 3); 3033 inst_cream->Rm = BITS(inst, 0, 3);
3054 inst_cream->Rs = BITS(inst, 8, 11); 3034 inst_cream->Rs = BITS(inst, 8, 11);
3055 inst_cream->RdHi = BITS(inst, 16, 19); 3035 inst_cream->RdHi = BITS(inst, 16, 19);
3056 inst_cream->RdLo = BITS(inst, 12, 15); 3036 inst_cream->RdLo = BITS(inst, 12, 15);
3057 3037
3058 if (CHECK_RM || CHECK_RS) 3038 if (CHECK_RM || CHECK_RS)
3059 inst_base->load_r15 = 1; 3039 inst_base->load_r15 = 1;
3060 return inst_base; 3040 return inst_base;
3061} 3041}
3062 3042
3063ARM_INST_PTR INTERPRETER_TRANSLATE(b_2_thumb)(unsigned int tinst, int index) 3043ARM_INST_PTR INTERPRETER_TRANSLATE(b_2_thumb)(unsigned int tinst, int index)
3064{ 3044{
3065 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_2_thumb)); 3045 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_2_thumb));
3066 b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component; 3046 b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component;
3067 3047
3068 inst_cream->imm =((tinst & 0x3FF) << 1) | ((tinst & (1 << 10)) ? 0xFFFFF800 : 0); 3048 inst_cream->imm = ((tinst & 0x3FF) << 1) | ((tinst & (1 << 10)) ? 0xFFFFF800 : 0);
3069 //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm); 3049
3070 inst_base->idx = index; 3050 inst_base->idx = index;
3071 inst_base->br = DIRECT_BRANCH; 3051 inst_base->br = DIRECT_BRANCH;
3072 return inst_base; 3052
3053 return inst_base;
3073} 3054}
3074 3055
3075ARM_INST_PTR INTERPRETER_TRANSLATE(b_cond_thumb)(unsigned int tinst, int index) 3056ARM_INST_PTR INTERPRETER_TRANSLATE(b_cond_thumb)(unsigned int tinst, int index)
3076{ 3057{
3077 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_cond_thumb)); 3058 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(b_cond_thumb));
3078 b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component; 3059 b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component;
3079 3060
3080 inst_cream->imm = (((tinst & 0x7F) << 1) | ((tinst & (1 << 7)) ? 0xFFFFFF00 : 0)); 3061 inst_cream->imm = (((tinst & 0x7F) << 1) | ((tinst & (1 << 7)) ? 0xFFFFFF00 : 0));
3081 inst_cream->cond = ((tinst >> 8) & 0xf); 3062 inst_cream->cond = ((tinst >> 8) & 0xf);
3082 //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x, cond=0x%x\n", __FUNCTION__, tinst, inst_cream->imm, inst_cream->cond); 3063 inst_base->idx = index;
3083 inst_base->idx = index; 3064 inst_base->br = DIRECT_BRANCH;
3084 inst_base->br = DIRECT_BRANCH; 3065
3085 return inst_base; 3066 return inst_base;
3086} 3067}
3087 3068
3088ARM_INST_PTR INTERPRETER_TRANSLATE(bl_1_thumb)(unsigned int tinst, int index) 3069ARM_INST_PTR INTERPRETER_TRANSLATE(bl_1_thumb)(unsigned int tinst, int index)
3089{ 3070{
3090 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_1_thumb)); 3071 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_1_thumb));
3091 bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component; 3072 bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component;
3092 3073
3093 inst_cream->imm = (((tinst & 0x07FF) << 12) | ((tinst & (1 << 10)) ? 0xFF800000 : 0)); 3074 inst_cream->imm = (((tinst & 0x07FF) << 12) | ((tinst & (1 << 10)) ? 0xFF800000 : 0));
3094 //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm);
3095 3075
3096 inst_base->idx = index; 3076 inst_base->idx = index;
3097 inst_base->br = NON_BRANCH; 3077 inst_base->br = NON_BRANCH;
3098 return inst_base; 3078 return inst_base;
3099} 3079}
3100ARM_INST_PTR INTERPRETER_TRANSLATE(bl_2_thumb)(unsigned int tinst, int index) 3080ARM_INST_PTR INTERPRETER_TRANSLATE(bl_2_thumb)(unsigned int tinst, int index)
3101{ 3081{
3102 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_2_thumb)); 3082 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(bl_2_thumb));
3103 bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component; 3083 bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component;
3084
3085 inst_cream->imm = (tinst & 0x07FF) << 1;
3104 3086
3105 inst_cream->imm = (tinst & 0x07FF) << 1; 3087 inst_base->idx = index;
3106 //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm); 3088 inst_base->br = DIRECT_BRANCH;
3107 inst_base->idx = index; 3089 return inst_base;
3108 inst_base->br = DIRECT_BRANCH;
3109 return inst_base;
3110} 3090}
3111ARM_INST_PTR INTERPRETER_TRANSLATE(blx_1_thumb)(unsigned int tinst, int index) 3091ARM_INST_PTR INTERPRETER_TRANSLATE(blx_1_thumb)(unsigned int tinst, int index)
3112{ 3092{
3113 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_1_thumb)); 3093 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(blx_1_thumb));
3114 blx_1_thumb *inst_cream = (blx_1_thumb *)inst_base->component; 3094 blx_1_thumb *inst_cream = (blx_1_thumb *)inst_base->component;
3115 3095
3116 inst_cream->imm = (tinst & 0x07FF) << 1; 3096 inst_cream->imm = (tinst & 0x07FF) << 1;
3117 //DEBUG_LOG(ARM11, "In %s, tinst=0x%x, imm=0x%x\n", __FUNCTION__, tinst, inst_cream->imm); 3097 inst_cream->instr = tinst;
3118 inst_cream->instr = tinst; 3098
3119 inst_base->idx = index; 3099 inst_base->idx = index;
3120 inst_base->br = DIRECT_BRANCH; 3100 inst_base->br = DIRECT_BRANCH;
3121 return inst_base; 3101 return inst_base;
3122} 3102}
3123 3103
3124ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 3104ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd8)(unsigned int inst, int index)
3125ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 3105{
3126ARM_INST_PTR INTERPRETER_TRANSLATE(uqaddsubx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 3106 arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
3127ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 3107 generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
3128ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 3108
3129ARM_INST_PTR INTERPRETER_TRANSLATE(uqsubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 3109 inst_base->cond = BITS(inst, 28, 31);
3130ARM_INST_PTR INTERPRETER_TRANSLATE(usad8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 3110 inst_base->idx = index;
3131ARM_INST_PTR INTERPRETER_TRANSLATE(usada8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 3111 inst_base->br = NON_BRANCH;
3132ARM_INST_PTR INTERPRETER_TRANSLATE(usat)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 3112 inst_base->load_r15 = 0;
3133ARM_INST_PTR INTERPRETER_TRANSLATE(usat16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 3113
3134ARM_INST_PTR INTERPRETER_TRANSLATE(usub16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 3114 inst_cream->Rm = BITS(inst, 0, 3);
3135ARM_INST_PTR INTERPRETER_TRANSLATE(usub8)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 3115 inst_cream->Rn = BITS(inst, 16, 19);
3136ARM_INST_PTR INTERPRETER_TRANSLATE(usubaddx)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 3116 inst_cream->Rd = BITS(inst, 12, 15);
3137ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 3117 inst_cream->op1 = BITS(inst, 20, 21);
3138ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb16)(unsigned int inst, int index){DEBUG_LOG(ARM11, "in func %s\n", __FUNCTION__);CITRA_IGNORE_EXIT(-1); return nullptr;} 3118 inst_cream->op2 = BITS(inst, 5, 7);
3119
3120 return inst_base;
3121}
3122ARM_INST_PTR INTERPRETER_TRANSLATE(uqadd16)(unsigned int inst, int index)
3123{
3124 return INTERPRETER_TRANSLATE(uqadd8)(inst, index);
3125}
3126ARM_INST_PTR INTERPRETER_TRANSLATE(uqaddsubx)(unsigned int inst, int index)
3127{
3128 return INTERPRETER_TRANSLATE(uqadd8)(inst, index);
3129}
3130ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub8)(unsigned int inst, int index)
3131{
3132 return INTERPRETER_TRANSLATE(uqadd8)(inst, index);
3133}
3134ARM_INST_PTR INTERPRETER_TRANSLATE(uqsub16)(unsigned int inst, int index)
3135{
3136 return INTERPRETER_TRANSLATE(uqadd8)(inst, index);
3137}
3138ARM_INST_PTR INTERPRETER_TRANSLATE(uqsubaddx)(unsigned int inst, int index)
3139{
3140 return INTERPRETER_TRANSLATE(uqadd8)(inst, index);
3141}
3142ARM_INST_PTR INTERPRETER_TRANSLATE(usada8)(unsigned int inst, int index)
3143{
3144 arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(generic_arm_inst));
3145 generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
3139 3146
3147 inst_base->cond = BITS(inst, 28, 31);
3148 inst_base->idx = index;
3149 inst_base->br = NON_BRANCH;
3150 inst_base->load_r15 = 0;
3140 3151
3152 inst_cream->op1 = BITS(inst, 20, 24);
3153 inst_cream->op2 = BITS(inst, 5, 7);
3154 inst_cream->Rm = BITS(inst, 8, 11);
3155 inst_cream->Rn = BITS(inst, 0, 3);
3156 inst_cream->Ra = BITS(inst, 12, 15);
3141 3157
3142/* Floating point VFPv3 structures and instructions */ 3158 return inst_base;
3159}
3160ARM_INST_PTR INTERPRETER_TRANSLATE(usad8)(unsigned int inst, int index)
3161{
3162 return INTERPRETER_TRANSLATE(usada8)(inst, index);
3163}
3164ARM_INST_PTR INTERPRETER_TRANSLATE(usat)(unsigned int inst, int index)
3165{
3166 return INTERPRETER_TRANSLATE(ssat)(inst, index);
3167}
3168ARM_INST_PTR INTERPRETER_TRANSLATE(usat16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USAT16"); }
3169ARM_INST_PTR INTERPRETER_TRANSLATE(usub16)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USUB16"); }
3170ARM_INST_PTR INTERPRETER_TRANSLATE(usub8)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USUB8"); }
3171ARM_INST_PTR INTERPRETER_TRANSLATE(usubaddx)(unsigned int inst, int index) { UNIMPLEMENTED_INSTRUCTION("USUBADDX"); }
3172
3173ARM_INST_PTR INTERPRETER_TRANSLATE(uxtab16)(unsigned int inst, int index)
3174{
3175 arm_inst* const inst_base = (arm_inst*)AllocBuffer(sizeof(arm_inst) + sizeof(uxtab_inst));
3176 uxtab_inst* const inst_cream = (uxtab_inst*)inst_base->component;
3177
3178 inst_base->cond = BITS(inst, 28, 31);
3179 inst_base->idx = index;
3180 inst_base->br = NON_BRANCH;
3181 inst_base->load_r15 = 0;
3182
3183 inst_cream->Rm = BITS(inst, 0, 3);
3184 inst_cream->Rn = BITS(inst, 16, 19);
3185 inst_cream->Rd = BITS(inst, 12, 15);
3186 inst_cream->rotate = BITS(inst, 10, 11);
3187
3188 return inst_base;
3189}
3190ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb16)(unsigned int inst, int index)
3191{
3192 return INTERPRETER_TRANSLATE(uxtab16)(inst, index);
3193}
3194
3195// Floating point VFPv3 structures and instructions
3143 3196
3144#define VFP_INTERPRETER_STRUCT 3197#define VFP_INTERPRETER_STRUCT
3145#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 3198#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
@@ -3149,324 +3202,288 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(uxtb16)(unsigned int inst, int index){DEBUG_L
3149#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 3202#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
3150#undef VFP_INTERPRETER_TRANS 3203#undef VFP_INTERPRETER_TRANS
3151 3204
3152
3153
3154typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int); 3205typedef ARM_INST_PTR (*transop_fp_t)(unsigned int, int);
3155 3206
3156const transop_fp_t arm_instruction_trans[] = { 3207const transop_fp_t arm_instruction_trans[] = {
3157 #define VFP_INTERPRETER_TABLE 3208 INTERPRETER_TRANSLATE(vmla),
3158 #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 3209 INTERPRETER_TRANSLATE(vmls),
3159 #undef VFP_INTERPRETER_TABLE 3210 INTERPRETER_TRANSLATE(vnmla),
3160 INTERPRETER_TRANSLATE(srs), 3211 INTERPRETER_TRANSLATE(vnmla),
3161 INTERPRETER_TRANSLATE(rfe), 3212 INTERPRETER_TRANSLATE(vnmls),
3162 INTERPRETER_TRANSLATE(bkpt), 3213 INTERPRETER_TRANSLATE(vnmul),
3163 INTERPRETER_TRANSLATE(blx), 3214 INTERPRETER_TRANSLATE(vmul),
3164 INTERPRETER_TRANSLATE(cps), 3215 INTERPRETER_TRANSLATE(vadd),
3165 INTERPRETER_TRANSLATE(pld), 3216 INTERPRETER_TRANSLATE(vsub),
3166 INTERPRETER_TRANSLATE(setend), 3217 INTERPRETER_TRANSLATE(vdiv),
3167 INTERPRETER_TRANSLATE(clrex), 3218 INTERPRETER_TRANSLATE(vmovi),
3168 INTERPRETER_TRANSLATE(rev16), 3219 INTERPRETER_TRANSLATE(vmovr),
3169 INTERPRETER_TRANSLATE(usad8), 3220 INTERPRETER_TRANSLATE(vabs),
3170 INTERPRETER_TRANSLATE(sxtb), 3221 INTERPRETER_TRANSLATE(vneg),
3171 INTERPRETER_TRANSLATE(uxtb), 3222 INTERPRETER_TRANSLATE(vsqrt),
3172 INTERPRETER_TRANSLATE(sxth), 3223 INTERPRETER_TRANSLATE(vcmp),
3173 INTERPRETER_TRANSLATE(sxtb16), 3224 INTERPRETER_TRANSLATE(vcmp2),
3174 INTERPRETER_TRANSLATE(uxth), 3225 INTERPRETER_TRANSLATE(vcvtbds),
3175 INTERPRETER_TRANSLATE(uxtb16), 3226 INTERPRETER_TRANSLATE(vcvtbff),
3176 INTERPRETER_TRANSLATE(cpy), 3227 INTERPRETER_TRANSLATE(vcvtbfi),
3177 INTERPRETER_TRANSLATE(uxtab), 3228 INTERPRETER_TRANSLATE(vmovbrs),
3178 INTERPRETER_TRANSLATE(ssub8), 3229 INTERPRETER_TRANSLATE(vmsr),
3179 INTERPRETER_TRANSLATE(shsub8), 3230 INTERPRETER_TRANSLATE(vmovbrc),
3180 INTERPRETER_TRANSLATE(ssubaddx), 3231 INTERPRETER_TRANSLATE(vmrs),
3181 INTERPRETER_TRANSLATE(strex), 3232 INTERPRETER_TRANSLATE(vmovbcr),
3182 INTERPRETER_TRANSLATE(strexb), 3233 INTERPRETER_TRANSLATE(vmovbrrss),
3183 INTERPRETER_TRANSLATE(swp), 3234 INTERPRETER_TRANSLATE(vmovbrrd),
3184 INTERPRETER_TRANSLATE(swpb), 3235 INTERPRETER_TRANSLATE(vstr),
3185 INTERPRETER_TRANSLATE(ssub16), 3236 INTERPRETER_TRANSLATE(vpush),
3186 INTERPRETER_TRANSLATE(ssat16), 3237 INTERPRETER_TRANSLATE(vstm),
3187 INTERPRETER_TRANSLATE(shsubaddx), 3238 INTERPRETER_TRANSLATE(vpop),
3188 INTERPRETER_TRANSLATE(qsubaddx), 3239 INTERPRETER_TRANSLATE(vldr),
3189 INTERPRETER_TRANSLATE(shaddsubx), 3240 INTERPRETER_TRANSLATE(vldm),
3190 INTERPRETER_TRANSLATE(shadd8), 3241
3191 INTERPRETER_TRANSLATE(shadd16), 3242 INTERPRETER_TRANSLATE(srs),
3192 INTERPRETER_TRANSLATE(sel), 3243 INTERPRETER_TRANSLATE(rfe),
3193 INTERPRETER_TRANSLATE(saddsubx), 3244 INTERPRETER_TRANSLATE(bkpt),
3194 INTERPRETER_TRANSLATE(sadd8), 3245 INTERPRETER_TRANSLATE(blx),
3195 INTERPRETER_TRANSLATE(sadd16), 3246 INTERPRETER_TRANSLATE(cps),
3196 INTERPRETER_TRANSLATE(shsub16), 3247 INTERPRETER_TRANSLATE(pld),
3197 INTERPRETER_TRANSLATE(umaal), 3248 INTERPRETER_TRANSLATE(setend),
3198 INTERPRETER_TRANSLATE(uxtab16), 3249 INTERPRETER_TRANSLATE(clrex),
3199 INTERPRETER_TRANSLATE(usubaddx), 3250 INTERPRETER_TRANSLATE(rev16),
3200 INTERPRETER_TRANSLATE(usub8), 3251 INTERPRETER_TRANSLATE(usad8),
3201 INTERPRETER_TRANSLATE(usub16), 3252 INTERPRETER_TRANSLATE(sxtb),
3202 INTERPRETER_TRANSLATE(usat16), 3253 INTERPRETER_TRANSLATE(uxtb),
3203 INTERPRETER_TRANSLATE(usada8), 3254 INTERPRETER_TRANSLATE(sxth),
3204 INTERPRETER_TRANSLATE(uqsubaddx), 3255 INTERPRETER_TRANSLATE(sxtb16),
3205 INTERPRETER_TRANSLATE(uqsub8), 3256 INTERPRETER_TRANSLATE(uxth),
3206 INTERPRETER_TRANSLATE(uqsub16), 3257 INTERPRETER_TRANSLATE(uxtb16),
3207 INTERPRETER_TRANSLATE(uqaddsubx), 3258 INTERPRETER_TRANSLATE(cpy),
3208 INTERPRETER_TRANSLATE(uqadd8), 3259 INTERPRETER_TRANSLATE(uxtab),
3209 INTERPRETER_TRANSLATE(uqadd16), 3260 INTERPRETER_TRANSLATE(ssub8),
3210 INTERPRETER_TRANSLATE(sxtab), 3261 INTERPRETER_TRANSLATE(shsub8),
3211 INTERPRETER_TRANSLATE(uhsubaddx), 3262 INTERPRETER_TRANSLATE(ssubaddx),
3212 INTERPRETER_TRANSLATE(uhsub8), 3263 INTERPRETER_TRANSLATE(strex),
3213 INTERPRETER_TRANSLATE(uhsub16), 3264 INTERPRETER_TRANSLATE(strexb),
3214 INTERPRETER_TRANSLATE(uhaddsubx), 3265 INTERPRETER_TRANSLATE(swp),
3215 INTERPRETER_TRANSLATE(uhadd8), 3266 INTERPRETER_TRANSLATE(swpb),
3216 INTERPRETER_TRANSLATE(uhadd16), 3267 INTERPRETER_TRANSLATE(ssub16),
3217 INTERPRETER_TRANSLATE(uaddsubx), 3268 INTERPRETER_TRANSLATE(ssat16),
3218 INTERPRETER_TRANSLATE(uadd8), 3269 INTERPRETER_TRANSLATE(shsubaddx),
3219 INTERPRETER_TRANSLATE(uadd16), 3270 INTERPRETER_TRANSLATE(qsubaddx),
3220 INTERPRETER_TRANSLATE(sxtah), 3271 INTERPRETER_TRANSLATE(shaddsubx),
3221 INTERPRETER_TRANSLATE(sxtab16), 3272 INTERPRETER_TRANSLATE(shadd8),
3222 INTERPRETER_TRANSLATE(qadd8), 3273 INTERPRETER_TRANSLATE(shadd16),
3223 INTERPRETER_TRANSLATE(bxj), 3274 INTERPRETER_TRANSLATE(sel),
3224 INTERPRETER_TRANSLATE(clz), 3275 INTERPRETER_TRANSLATE(saddsubx),
3225 INTERPRETER_TRANSLATE(uxtah), 3276 INTERPRETER_TRANSLATE(sadd8),
3226 INTERPRETER_TRANSLATE(bx), 3277 INTERPRETER_TRANSLATE(sadd16),
3227 INTERPRETER_TRANSLATE(rev), 3278 INTERPRETER_TRANSLATE(shsub16),
3228 INTERPRETER_TRANSLATE(blx), 3279 INTERPRETER_TRANSLATE(umaal),
3229 INTERPRETER_TRANSLATE(revsh), 3280 INTERPRETER_TRANSLATE(uxtab16),
3230 INTERPRETER_TRANSLATE(qadd), 3281 INTERPRETER_TRANSLATE(usubaddx),
3231 INTERPRETER_TRANSLATE(qadd16), 3282 INTERPRETER_TRANSLATE(usub8),
3232 INTERPRETER_TRANSLATE(qaddsubx), 3283 INTERPRETER_TRANSLATE(usub16),
3233 INTERPRETER_TRANSLATE(ldrex), 3284 INTERPRETER_TRANSLATE(usat16),
3234 INTERPRETER_TRANSLATE(qdadd), 3285 INTERPRETER_TRANSLATE(usada8),
3235 INTERPRETER_TRANSLATE(qdsub), 3286 INTERPRETER_TRANSLATE(uqsubaddx),
3236 INTERPRETER_TRANSLATE(qsub), 3287 INTERPRETER_TRANSLATE(uqsub8),
3237 INTERPRETER_TRANSLATE(ldrexb), 3288 INTERPRETER_TRANSLATE(uqsub16),
3238 INTERPRETER_TRANSLATE(qsub8), 3289 INTERPRETER_TRANSLATE(uqaddsubx),
3239 INTERPRETER_TRANSLATE(qsub16), 3290 INTERPRETER_TRANSLATE(uqadd8),
3240 INTERPRETER_TRANSLATE(smuad), 3291 INTERPRETER_TRANSLATE(uqadd16),
3241 INTERPRETER_TRANSLATE(smmul), 3292 INTERPRETER_TRANSLATE(sxtab),
3242 INTERPRETER_TRANSLATE(smusd), 3293 INTERPRETER_TRANSLATE(uhsubaddx),
3243 INTERPRETER_TRANSLATE(smlsd), 3294 INTERPRETER_TRANSLATE(uhsub8),
3244 INTERPRETER_TRANSLATE(smlsld), 3295 INTERPRETER_TRANSLATE(uhsub16),
3245 INTERPRETER_TRANSLATE(smmla), 3296 INTERPRETER_TRANSLATE(uhaddsubx),
3246 INTERPRETER_TRANSLATE(smmls), 3297 INTERPRETER_TRANSLATE(uhadd8),
3247 INTERPRETER_TRANSLATE(smlald), 3298 INTERPRETER_TRANSLATE(uhadd16),
3248 INTERPRETER_TRANSLATE(smlad), 3299 INTERPRETER_TRANSLATE(uaddsubx),
3249 INTERPRETER_TRANSLATE(smlaw), 3300 INTERPRETER_TRANSLATE(uadd8),
3250 INTERPRETER_TRANSLATE(smulw), 3301 INTERPRETER_TRANSLATE(uadd16),
3251 INTERPRETER_TRANSLATE(pkhtb), 3302 INTERPRETER_TRANSLATE(sxtah),
3252 INTERPRETER_TRANSLATE(pkhbt), 3303 INTERPRETER_TRANSLATE(sxtab16),
3253 INTERPRETER_TRANSLATE(smul), 3304 INTERPRETER_TRANSLATE(qadd8),
3254 INTERPRETER_TRANSLATE(smlalxy), 3305 INTERPRETER_TRANSLATE(bxj),
3255 INTERPRETER_TRANSLATE(smla), 3306 INTERPRETER_TRANSLATE(clz),
3256 INTERPRETER_TRANSLATE(mcrr), 3307 INTERPRETER_TRANSLATE(uxtah),
3257 INTERPRETER_TRANSLATE(mrrc), 3308 INTERPRETER_TRANSLATE(bx),
3258 INTERPRETER_TRANSLATE(cmp), 3309 INTERPRETER_TRANSLATE(rev),
3259 INTERPRETER_TRANSLATE(tst), 3310 INTERPRETER_TRANSLATE(blx),
3260 INTERPRETER_TRANSLATE(teq), 3311 INTERPRETER_TRANSLATE(revsh),
3261 INTERPRETER_TRANSLATE(cmn), 3312 INTERPRETER_TRANSLATE(qadd),
3262 INTERPRETER_TRANSLATE(smull), 3313 INTERPRETER_TRANSLATE(qadd16),
3263 INTERPRETER_TRANSLATE(umull), 3314 INTERPRETER_TRANSLATE(qaddsubx),
3264 INTERPRETER_TRANSLATE(umlal), 3315 INTERPRETER_TRANSLATE(ldrex),
3265 INTERPRETER_TRANSLATE(smlal), 3316 INTERPRETER_TRANSLATE(qdadd),
3266 INTERPRETER_TRANSLATE(mul), 3317 INTERPRETER_TRANSLATE(qdsub),
3267 INTERPRETER_TRANSLATE(mla), 3318 INTERPRETER_TRANSLATE(qsub),
3268 INTERPRETER_TRANSLATE(ssat), 3319 INTERPRETER_TRANSLATE(ldrexb),
3269 INTERPRETER_TRANSLATE(usat), 3320 INTERPRETER_TRANSLATE(qsub8),
3270 INTERPRETER_TRANSLATE(mrs), 3321 INTERPRETER_TRANSLATE(qsub16),
3271 INTERPRETER_TRANSLATE(msr), 3322 INTERPRETER_TRANSLATE(smuad),
3272 INTERPRETER_TRANSLATE(and), 3323 INTERPRETER_TRANSLATE(smmul),
3273 INTERPRETER_TRANSLATE(bic), 3324 INTERPRETER_TRANSLATE(smusd),
3274 INTERPRETER_TRANSLATE(ldm), 3325 INTERPRETER_TRANSLATE(smlsd),
3275 INTERPRETER_TRANSLATE(eor), 3326 INTERPRETER_TRANSLATE(smlsld),
3276 INTERPRETER_TRANSLATE(add), 3327 INTERPRETER_TRANSLATE(smmla),
3277 INTERPRETER_TRANSLATE(rsb), 3328 INTERPRETER_TRANSLATE(smmls),
3278 INTERPRETER_TRANSLATE(rsc), 3329 INTERPRETER_TRANSLATE(smlald),
3279 INTERPRETER_TRANSLATE(sbc), 3330 INTERPRETER_TRANSLATE(smlad),
3280 INTERPRETER_TRANSLATE(adc), 3331 INTERPRETER_TRANSLATE(smlaw),
3281 INTERPRETER_TRANSLATE(sub), 3332 INTERPRETER_TRANSLATE(smulw),
3282 INTERPRETER_TRANSLATE(orr), 3333 INTERPRETER_TRANSLATE(pkhtb),
3283 INTERPRETER_TRANSLATE(mvn), 3334 INTERPRETER_TRANSLATE(pkhbt),
3284 INTERPRETER_TRANSLATE(mov), 3335 INTERPRETER_TRANSLATE(smul),
3285 INTERPRETER_TRANSLATE(stm), 3336 INTERPRETER_TRANSLATE(smlalxy),
3286 INTERPRETER_TRANSLATE(ldm), 3337 INTERPRETER_TRANSLATE(smla),
3287 INTERPRETER_TRANSLATE(ldrsh), 3338 INTERPRETER_TRANSLATE(mcrr),
3288 INTERPRETER_TRANSLATE(stm), 3339 INTERPRETER_TRANSLATE(mrrc),
3289 INTERPRETER_TRANSLATE(ldm), 3340 INTERPRETER_TRANSLATE(cmp),
3290 INTERPRETER_TRANSLATE(ldrsb), 3341 INTERPRETER_TRANSLATE(tst),
3291 INTERPRETER_TRANSLATE(strd), 3342 INTERPRETER_TRANSLATE(teq),
3292 INTERPRETER_TRANSLATE(ldrh), 3343 INTERPRETER_TRANSLATE(cmn),
3293 INTERPRETER_TRANSLATE(strh), 3344 INTERPRETER_TRANSLATE(smull),
3294 INTERPRETER_TRANSLATE(ldrd), 3345 INTERPRETER_TRANSLATE(umull),
3295 INTERPRETER_TRANSLATE(strt), 3346 INTERPRETER_TRANSLATE(umlal),
3296 INTERPRETER_TRANSLATE(strbt), 3347 INTERPRETER_TRANSLATE(smlal),
3297 INTERPRETER_TRANSLATE(ldrbt), 3348 INTERPRETER_TRANSLATE(mul),
3298 INTERPRETER_TRANSLATE(ldrt), 3349 INTERPRETER_TRANSLATE(mla),
3299 INTERPRETER_TRANSLATE(mrc), 3350 INTERPRETER_TRANSLATE(ssat),
3300 INTERPRETER_TRANSLATE(mcr), 3351 INTERPRETER_TRANSLATE(usat),
3301 INTERPRETER_TRANSLATE(msr), 3352 INTERPRETER_TRANSLATE(mrs),
3302 INTERPRETER_TRANSLATE(ldrb), 3353 INTERPRETER_TRANSLATE(msr),
3303 INTERPRETER_TRANSLATE(strb), 3354 INTERPRETER_TRANSLATE(and),
3304 INTERPRETER_TRANSLATE(ldr), 3355 INTERPRETER_TRANSLATE(bic),
3305 INTERPRETER_TRANSLATE(ldrcond), 3356 INTERPRETER_TRANSLATE(ldm),
3306 INTERPRETER_TRANSLATE(str), 3357 INTERPRETER_TRANSLATE(eor),
3307 INTERPRETER_TRANSLATE(cdp), 3358 INTERPRETER_TRANSLATE(add),
3308 INTERPRETER_TRANSLATE(stc), 3359 INTERPRETER_TRANSLATE(rsb),
3309 INTERPRETER_TRANSLATE(ldc), 3360 INTERPRETER_TRANSLATE(rsc),
3310 INTERPRETER_TRANSLATE(swi), 3361 INTERPRETER_TRANSLATE(sbc),
3311 INTERPRETER_TRANSLATE(bbl), 3362 INTERPRETER_TRANSLATE(adc),
3312 /* All the thumb instructions should be placed the end of table */ 3363 INTERPRETER_TRANSLATE(sub),
3313 INTERPRETER_TRANSLATE(b_2_thumb), 3364 INTERPRETER_TRANSLATE(orr),
3314 INTERPRETER_TRANSLATE(b_cond_thumb), 3365 INTERPRETER_TRANSLATE(mvn),
3315 INTERPRETER_TRANSLATE(bl_1_thumb), 3366 INTERPRETER_TRANSLATE(mov),
3316 INTERPRETER_TRANSLATE(bl_2_thumb), 3367 INTERPRETER_TRANSLATE(stm),
3317 INTERPRETER_TRANSLATE(blx_1_thumb) 3368 INTERPRETER_TRANSLATE(ldm),
3369 INTERPRETER_TRANSLATE(ldrsh),
3370 INTERPRETER_TRANSLATE(stm),
3371 INTERPRETER_TRANSLATE(ldm),
3372 INTERPRETER_TRANSLATE(ldrsb),
3373 INTERPRETER_TRANSLATE(strd),
3374 INTERPRETER_TRANSLATE(ldrh),
3375 INTERPRETER_TRANSLATE(strh),
3376 INTERPRETER_TRANSLATE(ldrd),
3377 INTERPRETER_TRANSLATE(strt),
3378 INTERPRETER_TRANSLATE(strbt),
3379 INTERPRETER_TRANSLATE(ldrbt),
3380 INTERPRETER_TRANSLATE(ldrt),
3381 INTERPRETER_TRANSLATE(mrc),
3382 INTERPRETER_TRANSLATE(mcr),
3383 INTERPRETER_TRANSLATE(msr),
3384 INTERPRETER_TRANSLATE(ldrb),
3385 INTERPRETER_TRANSLATE(strb),
3386 INTERPRETER_TRANSLATE(ldr),
3387 INTERPRETER_TRANSLATE(ldrcond),
3388 INTERPRETER_TRANSLATE(str),
3389 INTERPRETER_TRANSLATE(cdp),
3390 INTERPRETER_TRANSLATE(stc),
3391 INTERPRETER_TRANSLATE(ldc),
3392 INTERPRETER_TRANSLATE(swi),
3393 INTERPRETER_TRANSLATE(bbl),
3394 // All the thumb instructions should be placed the end of table
3395 INTERPRETER_TRANSLATE(b_2_thumb),
3396 INTERPRETER_TRANSLATE(b_cond_thumb),
3397 INTERPRETER_TRANSLATE(bl_1_thumb),
3398 INTERPRETER_TRANSLATE(bl_2_thumb),
3399 INTERPRETER_TRANSLATE(blx_1_thumb)
3318}; 3400};
3319 3401
3320typedef map<unsigned int, int> bb_map; 3402typedef std::unordered_map<u32, int> bb_map;
3321bb_map CreamCache[65536]; 3403bb_map CreamCache;
3322bb_map ProfileCache[65536];
3323
3324//#define USE_DUMMY_CACHE
3325 3404
3326#ifdef USE_DUMMY_CACHE 3405void insert_bb(unsigned int addr, int start) {
3327unsigned int DummyCache[0x100000]; 3406 CreamCache[addr] = start;
3328#endif
3329
3330#define HASH(x) ((x + (x << 3) + (x >> 6)) % 65536)
3331void insert_bb(unsigned int addr, int start)
3332{
3333#ifdef USE_DUMMY_CACHE
3334 DummyCache[addr] = start;
3335#else
3336// CreamCache[addr] = start;
3337 CreamCache[HASH(addr)][addr] = start;
3338#endif
3339} 3407}
3340 3408
3341#define TRANS_THRESHOLD 65000 3409#define TRANS_THRESHOLD 65000
3342int find_bb(unsigned int addr, int &start) 3410int find_bb(unsigned int addr, int &start) {
3343{ 3411 int ret = -1;
3344 int ret = -1; 3412 bb_map::const_iterator it = CreamCache.find(addr);
3345#ifdef USE_DUMMY_CACHE 3413 if (it != CreamCache.end()) {
3346 start = DummyCache[addr]; 3414 start = static_cast<int>(it->second);
3347 if (start) { 3415 ret = 0;
3348 ret = 0; 3416 } else {
3349 } else 3417 ret = -1;
3350 ret = -1; 3418 }
3351#else 3419 return ret;
3352 bb_map::const_iterator it = CreamCache[HASH(addr)].find(addr);
3353 if (it != CreamCache[HASH(addr)].end()) {
3354 start = static_cast<int>(it->second);
3355 ret = 0;
3356#if HYBRID_MODE
3357#if PROFILE
3358#else
3359 /* increase the bb counter */
3360 if(get_bb_prof(cpu, addr, 1) == TRANS_THRESHOLD){
3361 push_to_compiled(cpu, addr);
3362 }
3363#endif
3364#endif
3365 } else {
3366 ret = -1;
3367 }
3368#endif
3369 return ret;
3370} 3420}
3371 3421
3372
3373enum { 3422enum {
3374 FETCH_SUCCESS, 3423 FETCH_SUCCESS,
3375 FETCH_FAILURE 3424 FETCH_FAILURE
3376}; 3425};
3426
3377static tdstate decode_thumb_instr(arm_processor *cpu, uint32_t inst, addr_t addr, uint32_t *arm_inst, uint32_t* inst_size, ARM_INST_PTR* ptr_inst_base){ 3427static tdstate decode_thumb_instr(arm_processor *cpu, uint32_t inst, addr_t addr, uint32_t *arm_inst, uint32_t* inst_size, ARM_INST_PTR* ptr_inst_base){
3378 /* Check if in Thumb mode. */ 3428 // Check if in Thumb mode
3379 tdstate ret; 3429 tdstate ret = thumb_translate (addr, inst, arm_inst, inst_size);
3380 ret = thumb_translate (addr, inst, arm_inst, inst_size); 3430 if(ret == t_branch){
3381 if(ret == t_branch){ 3431 // TODO: FIXME, endian should be judged
3382 /* FIXME, endian should be judged */ 3432 uint32 tinstr;
3383 uint32 tinstr; 3433 if((addr & 0x3) != 0)
3384 if((addr & 0x3) != 0) 3434 tinstr = inst >> 16;
3385 tinstr = inst >> 16; 3435 else
3386 else 3436 tinstr = inst & 0xFFFF;
3387 tinstr = inst & 0xFFFF; 3437
3388 3438 int inst_index;
3389 //tinstr = inst & 0xFFFF; 3439 int table_length = sizeof(arm_instruction_trans) / sizeof(transop_fp_t);
3390 int inst_index; 3440
3391 /* table_length */ 3441 switch((tinstr & 0xF800) >> 11){
3392 int table_length = sizeof(arm_instruction_trans) / sizeof(transop_fp_t); 3442 case 26:
3393 3443 case 27:
3394 switch((tinstr & 0xF800) >> 11){ 3444 if (((tinstr & 0x0F00) != 0x0E00) && ((tinstr & 0x0F00) != 0x0F00)){
3395 /* we will translate the thumb instruction directly here */ 3445 uint32 cond = (tinstr & 0x0F00) >> 8;
3396 /* we will translate the thumb instruction directly here */ 3446 inst_index = table_length - 4;
3397 case 26: 3447 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
3398 case 27: 3448 } else {
3399 if (((tinstr & 0x0F00) != 0x0E00) && ((tinstr & 0x0F00) != 0x0F00)){ 3449 LOG_ERROR(Core_ARM11, "thumb decoder error");
3400 uint32 cond = (tinstr & 0x0F00) >> 8; 3450 }
3401 inst_index = table_length - 4; 3451 break;
3402 //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, blx 1 thumb index=%d\n", __FUNCTION__, tinstr, inst_index); 3452 case 28:
3403 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); 3453 // Branch 2, unconditional branch
3404 } 3454 inst_index = table_length - 5;
3405 else{ 3455 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
3406 /* something wrong */ 3456 break;
3407 DEBUG_LOG(ARM11, "In %s, thumb decoder error\n", __FUNCTION__); 3457
3408 } 3458 case 8:
3409 break; 3459 case 29:
3410 case 28: 3460 // For BLX 1 thumb instruction
3411 /* Branch 2, unconditional branch */ 3461 inst_index = table_length - 1;
3412 inst_index = table_length - 5; 3462 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
3413 //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, blx 1 thumb index=%d\n", __FUNCTION__, tinstr, inst_index); 3463 break;
3414 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); 3464 case 30:
3415 break; 3465 // For BL 1 thumb instruction
3416 3466 inst_index = table_length - 3;
3417 case 8: 3467 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
3418 case 29: 3468 break;
3419 /* For BLX 1 thumb instruction*/ 3469 case 31:
3420 inst_index = table_length - 1; 3470 // For BL 2 thumb instruction
3421 //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, blx 1 thumb index=%d, pc=0x%x\n", __FUNCTION__, tinstr, inst_index, cpu->translate_pc); 3471 inst_index = table_length - 2;
3422 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); 3472 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
3423 break; 3473 break;
3424 case 30: 3474 default:
3425 /* For BL 1 thumb instruction*/ 3475 ret = t_undefined;
3426 inst_index = table_length - 3; 3476 break;
3427 //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, bl 1 thumb index=%d, pc=0x%x\n", __FUNCTION__, tinstr, inst_index, cpu->translate_pc); 3477 }
3428 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index); 3478 }
3429 break; 3479 return ret;
3430 case 31:
3431 /* For BL 2 thumb instruction*/
3432 inst_index = table_length - 2;
3433 //DEBUG_LOG(ARM11, "In %s, tinstr=0x%x, bl 2 thumb index=%d, px=0x%x\n", __FUNCTION__, tinstr, inst_index, cpu->translate_pc);
3434 *ptr_inst_base = arm_instruction_trans[inst_index](tinstr, inst_index);
3435 break;
3436 default:
3437 ret = t_undefined;
3438 break;
3439 }
3440 }
3441 return ret;
3442}
3443
3444#if 0
3445int FetchInst(cpu_t *core, unsigned int &inst)
3446{
3447 //arm_processor *cpu = (arm_processor *)get_cast_conf_obj(core->cpu_data, "arm_core_t");
3448 arm_processor *cpu = (arm_processor *)(core->cpu_data->obj);
3449// fault_t fault = interpreter_read_memory(cpu->translate_pc, inst, 32);
3450 fault_t fault = interpreter_fetch(core, cpu->translate_pc, inst, 32);
3451 if (!core->is_user_mode) {
3452 if (fault) {
3453 cpu->abortSig = true;
3454 cpu->Aborted = ARMul_PrefetchAbortV;
3455 cpu->AbortAddr = cpu->translate_pc;
3456 cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff;
3457 cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->translate_pc;
3458 return FETCH_FAILURE;
3459 }
3460 }
3461 return FETCH_SUCCESS;
3462} 3480}
3463#endif
3464 3481
3465unsigned int *InstLength; 3482unsigned int *InstLength;
3466 3483
3467enum { 3484enum {
3468 KEEP_GOING, 3485 KEEP_GOING,
3469 FETCH_EXCEPTION 3486 FETCH_EXCEPTION
3470}; 3487};
3471 3488
3472typedef struct instruction_set_encoding_item ISEITEM; 3489typedef struct instruction_set_encoding_item ISEITEM;
@@ -3475,289 +3492,148 @@ extern const ISEITEM arm_instruction[];
3475 3492
3476vector<uint64_t> code_page_set; 3493vector<uint64_t> code_page_set;
3477 3494
3478void flush_bb(uint32_t addr) 3495void flush_bb(uint32_t addr) {
3479{ 3496 bb_map::iterator it;
3480 bb_map::iterator it; 3497 uint32_t start;
3481 uint32_t start; 3498
3482 3499 addr &= 0xfffff000;
3483 addr &= 0xfffff000; 3500 for (it = CreamCache.begin(); it != CreamCache.end(); ) {
3484 for (int i = 0; i < 65536; i ++) { 3501 start = static_cast<uint32_t>(it->first);
3485 for (it = CreamCache[i].begin(); it != CreamCache[i].end(); ) { 3502 start &= 0xfffff000;
3486 start = static_cast<uint32_t>(it->first); 3503 if (start == addr) {
3487 //start = (start >> 12) << 12; 3504 CreamCache.erase(it++);
3488 start &= 0xfffff000; 3505 } else
3489 if (start == addr) { 3506 ++it;
3490 //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first)); 3507 }
3491 CreamCache[i].erase(it ++); 3508}
3492 } else
3493 ++it;
3494 }
3495 }
3496
3497 for (int i = 0; i < 65536; i ++) {
3498 for (it = ProfileCache[i].begin(); it != ProfileCache[i].end(); ) {
3499 start = static_cast<uint32_t>(it->first);
3500 //start = (start >> 12) << 12;
3501 start &= 0xfffff000;
3502 if (start == addr) {
3503 //DEBUG_LOG(ARM11, "[ERASE][0x%08x]\n", static_cast<int>(it->first));
3504 ProfileCache[i].erase(it ++);
3505 } else
3506 ++it;
3507 }
3508 }
3509
3510 //DEBUG_LOG(ARM11, "flush bb @ %x\n", addr);
3511}
3512
3513//static uint32_t get_bank_addr(void *addr)
3514//{
3515// uint64_t address = (uint64_t)addr;
3516// uint64_t bank0 = get_dma_addr(BANK0_START);
3517// if ((address >= bank0) && (address < (bank0 + BANK0_SIZE))) {
3518// //DEBUG_LOG(ARM11, "1.addr is %llx\n", addr);
3519// return ((uint64_t)addr - bank0) + BANK0_START;
3520// }
3521// return 0;
3522//}
3523
3524/* shenoubang add win32 2012-6-12 */
3525//#ifndef __WIN32__
3526//static void flush_code_cache(int signal_number, siginfo_t *si, void *unused)
3527//{
3528// DEBUG_LOG(ARM11, "in %s, addr=0x%llx\n", __FUNCTION__, si->si_addr);
3529// uint64_t addr = (uint64_t)si->si_addr;
3530// addr = (addr >> 12) << 12;
3531// skyeye_backtrace();
3532// #if 0
3533// if (addr == 0) {
3534// return;
3535// }
3536// const vector<uint64_t>::iterator it = find(code_page_set.begin(),
3537// code_page_set.end(),
3538// (uint64_t)addr);
3539// if (it != code_page_set.end()) {
3540// code_page_set.erase(it);
3541// }
3542// mprotect((void *)addr, 4096, PROT_READ | PROT_WRITE);
3543// //DEBUG_LOG(ARM11, "[flush][ADDR:0x%08llx]\n", addr);
3544// uint32_t phys_addr = get_bank_addr((void *)addr);
3545//// DEBUG_LOG(ARM11, "[PHYSICAL][ADDR:0x%08llx]\n", phys_addr);
3546// flush_bb(phys_addr);
3547// flush_bb(phys_addr + 4096);
3548//#if HYBRID_MODE
3549// /* flush the translated BB of dyncom */
3550// clear_translated_cache(phys_addr);
3551//#endif
3552// #endif
3553//}
3554//#endif /* shenoubang */
3555
3556//void protect_code_page(uint32_t addr)
3557//{
3558// void *mem_ptr = (void *)get_dma_addr(addr);
3559// mem_ptr = (void *)((long long int)mem_ptr & 0xfffffffffffff000LL);
3560//
3561// const vector<uint64_t>::iterator it = find(code_page_set.begin(),
3562// code_page_set.end(),
3563// (uint64_t)mem_ptr);
3564// if (it != code_page_set.end()) {
3565// return;
3566// }
3567// //DEBUG_LOG(ARM11, "[mprotect][ADDR:0x%08llx]\n", mem_ptr);
3568// /* shenoubang add win32 2012-6-12 */
3569//#ifndef __WIN32__
3570// struct sigaction sa;
3571//
3572// memset(&sa, 0, sizeof(sa));
3573// sa.sa_flags = SA_RESTART | SA_SIGINFO;
3574// sa.sa_sigaction = &flush_code_cache;
3575// sigaction(SIGSEGV, &sa, NULL);
3576//
3577// //mprotect(mem_ptr, 4096, PROT_READ);
3578//
3579// code_page_set.push_back((uint64_t)mem_ptr);
3580//#endif /* shenoubang */
3581//}
3582
3583
3584
3585int InterpreterTranslate(arm_processor *cpu, int &bb_start, addr_t addr)
3586{
3587 /* Decode instruction, get index */
3588 /* Allocate memory and init InsCream */
3589 /* Go on next, until terminal instruction */
3590 /* Save start addr of basicblock in CreamCache */
3591 //arm_processor *cpu = (arm_processor *)get_cast_conf_obj(core->cpu_data, "arm_core_t");
3592 //arm_processor *cpu = (arm_processor *)(core->cpu_data->obj);
3593 ARM_INST_PTR inst_base = NULL;
3594 unsigned int inst, inst_size = 4;
3595 int idx;
3596 int ret = NON_BRANCH;
3597 int thumb = 0;
3598 /* instruction size of basic block */
3599 int size = 0;
3600 /* (R15 - 8) ? */
3601 //cpu->translate_pc = cpu->Reg[15];
3602 bb_start = top;
3603
3604 if (cpu->TFlag)
3605 thumb = THUMB;
3606
3607 addr_t phys_addr;
3608 addr_t pc_start;
3609 fault_t fault = NO_FAULT;
3610 //fault = check_address_validity(cpu, addr, &phys_addr, 1, INSN_TLB);
3611 fault = check_address_validity(cpu, addr, &phys_addr, 1);
3612 if(fault != NO_FAULT){
3613 cpu->abortSig = true;
3614 cpu->Aborted = ARMul_PrefetchAbortV;
3615 cpu->AbortAddr = addr;
3616 cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff;
3617 cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = addr;
3618 return FETCH_EXCEPTION;
3619 }
3620 pc_start = phys_addr;
3621 //phys_addr = get_dma_addr(phys_addr);
3622 while(ret == NON_BRANCH) {
3623 /* shenoubang add win32 2012-6-14 */
3624#ifdef __WIN32__
3625 mem_bank_t* bank;
3626 if (bank = bank_ptr(addr)) {
3627 bank->bank_read(32, phys_addr, &inst);
3628 }
3629 else {
3630 DEBUG_LOG(ARM11, "SKYEYE: Read physical addr 0x%x error!!\n", phys_addr);
3631 return FETCH_FAILURE;
3632 }
3633#else
3634 inst = Memory::Read32(phys_addr & 0xFFFFFFFC);//*(uint32_t *)(phys_addr & 0xFFFFFFFC);
3635#endif
3636 //or_tag(core, phys_addr, TAG_FAST_INTERP);
3637
3638 /*if (ret == FETCH_FAILURE) {
3639 return FETCH_EXCEPTION;
3640 }*/
3641
3642 size ++;
3643 /* If we are in thumb instruction, we will translate one thumb to one corresponding arm instruction */
3644 if (cpu->TFlag){
3645 //if(cpu->Cpsr & (1 << THUMB_BIT)){
3646 uint32_t arm_inst;
3647 tdstate state;
3648 state = decode_thumb_instr(cpu, inst, phys_addr, &arm_inst, &inst_size, &inst_base);
3649 //or_tag(core, phys_addr, TAG_THUMB);
3650 //DEBUG_LOG(ARM11, "In thumb state, arm_inst=0x%x, inst_size=0x%x, pc=0x%x\n", arm_inst, inst_size, cpu->translate_pc);
3651 /* we have translated the branch instruction of thumb in thumb decoder */
3652 if(state == t_branch){
3653 goto translated;
3654 }
3655 inst = arm_inst;
3656 }
3657
3658 ret = decode_arm_instr(inst, &idx);
3659 if (ret == DECODE_FAILURE) {
3660 DEBUG_LOG(ARM11, "[info] : Decode failure.\tPC : [0x%x]\tInstruction : [%x]\n", phys_addr, inst);
3661 DEBUG_LOG(ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x\n", cpu->Cpsr, cpu->TFlag, cpu->Reg[15]);
3662 CITRA_IGNORE_EXIT(-1);
3663 }
3664// DEBUG_LOG(ARM11, "PC : [0x%x] INST : %s\n", cpu->translate_pc, arm_instruction[idx].name);
3665 inst_base = arm_instruction_trans[idx](inst, idx);
3666// DEBUG_LOG(ARM11, "translated @ %x INST : %x\n", cpu->translate_pc, inst);
3667// DEBUG_LOG(ARM11, "inst size is %d\n", InstLength[idx]);
3668translated:
3669 phys_addr += inst_size;
3670 3509
3671 if ((phys_addr & 0xfff) == 0) { 3510int InterpreterTranslate(arm_processor *cpu, int &bb_start, addr_t addr) {
3672 inst_base->br = END_OF_PAGE; 3511 // Decode instruction, get index
3673 } 3512 // Allocate memory and init InsCream
3674 ret = inst_base->br; 3513 // Go on next, until terminal instruction
3675 }; 3514 // Save start addr of basicblock in CreamCache
3515 ARM_INST_PTR inst_base = nullptr;
3516 unsigned int inst, inst_size = 4;
3517 int idx;
3518 int ret = NON_BRANCH;
3519 int thumb = 0;
3520 int size = 0; // instruction size of basic block
3521 bb_start = top;
3522
3523 if (cpu->TFlag)
3524 thumb = THUMB;
3525
3526 addr_t phys_addr;
3527 addr_t pc_start;
3528 fault_t fault = NO_FAULT;
3529 fault = check_address_validity(cpu, addr, &phys_addr, 1);
3530 if(fault != NO_FAULT){
3531 cpu->abortSig = true;
3532 cpu->Aborted = ARMul_PrefetchAbortV;
3533 cpu->AbortAddr = addr;
3534 cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff;
3535 cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = addr;
3536 return FETCH_EXCEPTION;
3537 }
3676 3538
3677 //DEBUG_LOG(ARM11, "In %s,insert_bb pc=0x%x, TFlag=0x%x\n", __FUNCTION__, pc_start, cpu->TFlag); 3539 pc_start = phys_addr;
3678 insert_bb(pc_start, bb_start);
3679 return KEEP_GOING;
3680}
3681 3540
3682#define LOG_IN_CLR skyeye_printf_in_color 3541 while(ret == NON_BRANCH) {
3542 inst = Memory::Read32(phys_addr & 0xFFFFFFFC);//*(uint32_t *)(phys_addr & 0xFFFFFFFC);
3683 3543
3684int cmp(const void *x, const void *y) 3544 size ++;
3685{ 3545 // If we are in thumb instruction, we will translate one thumb to one corresponding arm instruction
3686 return *(unsigned long long int*)x - *(unsigned long long int *)y; 3546 if (cpu->TFlag) {
3547 uint32_t arm_inst;
3548 tdstate state;
3549 state = decode_thumb_instr(cpu, inst, phys_addr, &arm_inst, &inst_size, &inst_base);
3550 // We have translated the branch instruction of thumb in thumb decoder
3551 if(state == t_branch){
3552 goto translated;
3553 }
3554 inst = arm_inst;
3555 }
3556
3557 ret = decode_arm_instr(inst, &idx);
3558 if (ret == DECODE_FAILURE) {
3559 LOG_ERROR(Core_ARM11, "Decode failure.\tPC : [0x%x]\tInstruction : [%x]", phys_addr, inst);
3560 LOG_ERROR(Core_ARM11, "cpsr=0x%x, cpu->TFlag=%d, r15=0x%x", cpu->Cpsr, cpu->TFlag, cpu->Reg[15]);
3561 CITRA_IGNORE_EXIT(-1);
3562 }
3563 inst_base = arm_instruction_trans[idx](inst, idx);
3564translated:
3565 phys_addr += inst_size;
3566
3567 if ((phys_addr & 0xfff) == 0) {
3568 inst_base->br = END_OF_PAGE;
3569 }
3570 ret = inst_base->br;
3571 };
3572 insert_bb(pc_start, bb_start);
3573 return KEEP_GOING;
3574}
3575
3576#define LOG_IN_CLR skyeye_printf_in_color
3577
3578int cmp(const void *x, const void *y) {
3579 return *(unsigned long long int*)x - *(unsigned long long int *)y;
3580}
3581
3582void InterpreterInitInstLength(unsigned long long int *ptr, size_t size) {
3583 int array_size = size / sizeof(void *);
3584 unsigned long long int *InstLabel = new unsigned long long int[array_size];
3585 memcpy(InstLabel, ptr, size);
3586 qsort(InstLabel, array_size, sizeof(void *), cmp);
3587 InstLength = new unsigned int[array_size - 4];
3588 for (int i = 0; i < array_size - 4; i ++) {
3589 for (int j = 0; j < array_size; j ++) {
3590 if (ptr[i] == InstLabel[j]) {
3591 InstLength[i] = InstLabel[j + 1] - InstLabel[j];
3592 break;
3593 }
3594 }
3595 }
3596 for (int i = 0; i < array_size - 4; i ++)
3597 LOG_DEBUG(Core_ARM11, "[%d]:%d", i, InstLength[i]);
3687} 3598}
3688 3599
3689void InterpreterInitInstLength(unsigned long long int *ptr, size_t size) 3600int clz(unsigned int x) {
3690{ 3601 int n;
3691 int array_size = size / sizeof(void *); 3602 if (x == 0) return (32);
3692 unsigned long long int *InstLabel = new unsigned long long int[array_size]; 3603 n = 1;
3693 memcpy(InstLabel, ptr, size); 3604 if ((x >> 16) == 0) { n = n + 16; x = x << 16;}
3694 qsort(InstLabel, array_size, sizeof(void *), cmp); 3605 if ((x >> 24) == 0) { n = n + 8; x = x << 8;}
3695 InstLength = new unsigned int[array_size - 4]; 3606 if ((x >> 28) == 0) { n = n + 4; x = x << 4;}
3696 for (int i = 0; i < array_size - 4; i ++) { 3607 if ((x >> 30) == 0) { n = n + 2; x = x << 2;}
3697 for (int j = 0; j < array_size; j ++) { 3608 n = n - (x >> 31);
3698 if (ptr[i] == InstLabel[j]) { 3609 return n;
3699 InstLength[i] = InstLabel[j + 1] - InstLabel[j];
3700 break;
3701 }
3702 }
3703 }
3704 for (int i = 0; i < array_size - 4; i ++)
3705 DEBUG_LOG(ARM11, "[%d]:%d\n", i, InstLength[i]);
3706}
3707
3708int clz(unsigned int x)
3709{
3710 int n;
3711 if (x == 0) return (32);
3712 n = 1;
3713 if ((x >> 16) == 0) { n = n + 16; x = x << 16;}
3714 if ((x >> 24) == 0) { n = n + 8; x = x << 8;}
3715 if ((x >> 28) == 0) { n = n + 4; x = x << 4;}
3716 if ((x >> 30) == 0) { n = n + 2; x = x << 2;}
3717 n = n - (x >> 31);
3718 return n;
3719} 3610}
3720 3611
3721unsigned arm_dyncom_SWI (ARMul_State * state, ARMword number); 3612unsigned arm_dyncom_SWI (ARMul_State * state, ARMword number);
3722 3613
3723static bool InAPrivilegedMode(arm_core_t *core) 3614static bool InAPrivilegedMode(arm_core_t *core) {
3724{ 3615 return (core->Mode != USER32MODE);
3725 return (core->Mode != USER32MODE);
3726} 3616}
3727 3617
3728/* r15 = r15 + 8 */ 3618unsigned InterpreterMainLoop(ARMul_State* state) {
3729unsigned InterpreterMainLoop(ARMul_State* state) 3619 #define CRn inst_cream->crn
3730{ 3620 #define OPCODE_2 inst_cream->opcode_2
3731 #define CRn inst_cream->crn 3621 #define CRm inst_cream->crm
3732 #define OPCODE_2 inst_cream->opcode_2 3622 #define CP15_REG(n) cpu->CP15[CP15(n)]
3733 #define CRm inst_cream->crm 3623 #define RD cpu->Reg[inst_cream->Rd]
3734 #define CP15_REG(n) cpu->CP15[CP15(n)] 3624 #define RN cpu->Reg[inst_cream->Rn]
3735 #define RD cpu->Reg[inst_cream->Rd] 3625 #define RM cpu->Reg[inst_cream->Rm]
3736 #define RN cpu->Reg[inst_cream->Rn] 3626 #define RS cpu->Reg[inst_cream->Rs]
3737 #define RM cpu->Reg[inst_cream->Rm] 3627 #define RDHI cpu->Reg[inst_cream->RdHi]
3738 #define RS cpu->Reg[inst_cream->Rs] 3628 #define RDLO cpu->Reg[inst_cream->RdLo]
3739 #define RDHI cpu->Reg[inst_cream->RdHi] 3629 #define LINK_RTN_ADDR (cpu->Reg[14] = cpu->Reg[15] + 4)
3740 #define RDLO cpu->Reg[inst_cream->RdLo] 3630 #define SET_PC (cpu->Reg[15] = cpu->Reg[15] + 8 + inst_cream->signed_immed_24)
3741 #define LINK_RTN_ADDR (cpu->Reg[14] = cpu->Reg[15] + 4) 3631 #define SHIFTER_OPERAND inst_cream->shtop_func(cpu, inst_cream->shifter_operand)
3742 #define SET_PC (cpu->Reg[15] = cpu->Reg[15] + 8 + inst_cream->signed_immed_24) 3632
3743 #define SHIFTER_OPERAND inst_cream->shtop_func(cpu, inst_cream->shifter_operand) 3633 #define FETCH_INST if (inst_base->br != NON_BRANCH) goto DISPATCH; \
3744 3634 inst_base = (arm_inst *)&inst_buf[ptr]
3745 #if ENABLE_ICOUNTER 3635
3746 #define INC_ICOUNTER cpu->icounter++; \ 3636 #define INC_PC(l) ptr += sizeof(arm_inst) + l
3747 if(cpu->Reg[15] > 0xc0000000) \
3748 cpu->kernel_icounter++;
3749 //if (debug_function(core)) \
3750 if (core->check_int_flag) \
3751 goto END
3752 //DEBUG_LOG(ARM11, "icounter is %llx line is %d pc is %x\n", cpu->icounter, __LINE__, cpu->Reg[15])
3753 #else
3754 #define INC_ICOUNTER ;
3755 #endif
3756
3757 #define FETCH_INST if (inst_base->br != NON_BRANCH) \
3758 goto DISPATCH; \
3759 inst_base = (arm_inst *)&inst_buf[ptr]
3760#define INC_PC(l) ptr += sizeof(arm_inst) + l
3761 3637
3762// GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a 3638// GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback to a
3763// clunky switch statement. 3639// clunky switch statement.
@@ -3898,7 +3774,7 @@ unsigned InterpreterMainLoop(ARMul_State* state)
3898 case 124: goto PKHTB_INST; \ 3774 case 124: goto PKHTB_INST; \
3899 case 125: goto PKHBT_INST; \ 3775 case 125: goto PKHBT_INST; \
3900 case 126: goto SMUL_INST; \ 3776 case 126: goto SMUL_INST; \
3901 case 127: goto SMLAL_INST; \ 3777 case 127: goto SMLALXY_INST; \
3902 case 128: goto SMLA_INST; \ 3778 case 128: goto SMLA_INST; \
3903 case 129: goto MCRR_INST; \ 3779 case 129: goto MCRR_INST; \
3904 case 130: goto MRRC_INST; \ 3780 case 130: goto MRRC_INST; \
@@ -3967,2606 +3843,2586 @@ unsigned InterpreterMainLoop(ARMul_State* state)
3967 } 3843 }
3968#endif 3844#endif
3969 3845
3970 #define UPDATE_NFLAG(dst) (cpu->NFlag = BIT(dst, 31) ? 1 : 0) 3846 #define UPDATE_NFLAG(dst) (cpu->NFlag = BIT(dst, 31) ? 1 : 0)
3971 #define UPDATE_ZFLAG(dst) (cpu->ZFlag = dst ? 0 : 1) 3847 #define UPDATE_ZFLAG(dst) (cpu->ZFlag = dst ? 0 : 1)
3972// #define UPDATE_CFLAG(dst, lop, rop) (cpu->CFlag = ((ISNEG(lop) && ISPOS(rop)) || \ 3848
3973 (ISNEG(lop) && ISPOS(dst)) || \ 3849 #define UPDATE_CFLAG(dst, lop, rop) (cpu->CFlag = ((dst < lop) || (dst < rop)))
3974 (ISPOS(rop) && ISPOS(dst)))) 3850 #define UPDATE_CFLAG_CARRY_FROM_ADD(lop, rop, flag) (cpu->CFlag = (((uint64_t) lop + (uint64_t) rop + (uint64_t) flag) > 0xffffffff) )
3975 #define UPDATE_CFLAG(dst, lop, rop) (cpu->CFlag = ((dst < lop) || (dst < rop))) 3851 #define UPDATE_CFLAG_NOT_BORROW_FROM_FLAG(lop, rop, flag) (cpu->CFlag = ((uint64_t) lop >= ((uint64_t) rop + (uint64_t) flag)))
3976 #define UPDATE_CFLAG_CARRY_FROM_ADD(lop, rop, flag) (cpu->CFlag = (((uint64_t) lop + (uint64_t) rop + (uint64_t) flag) > 0xffffffff) ) 3852 #define UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop) (cpu->CFlag = (lop >= rop))
3977 #define UPDATE_CFLAG_NOT_BORROW_FROM_FLAG(lop, rop, flag) (cpu->CFlag = ((uint64_t) lop >= ((uint64_t) rop + (uint64_t) flag))) 3853 #define UPDATE_CFLAG_WITH_NOT(dst, lop, rop) (cpu->CFlag = !(dst < lop))
3978 #define UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop) (cpu->CFlag = (lop >= rop)) 3854 #define UPDATE_CFLAG_WITH_SC (cpu->CFlag = cpu->shifter_carry_out)
3979 #define UPDATE_CFLAG_WITH_NOT(dst, lop, rop) (cpu->CFlag = !(dst < lop)) 3855
3980 #define UPDATE_CFLAG_WITH_SC cpu->CFlag = cpu->shifter_carry_out 3856 #define UPDATE_VFLAG(dst, lop, rop) (cpu->VFlag = (((lop < 0) && (rop < 0) && (dst >= 0)) || \
3981// #define UPDATE_CFLAG_WITH_NOT(dst, lop, rop) cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || \ 3857 ((lop >= 0) && (rop) >= 0 && (dst < 0))))
3982 (ISNEG(lop) && ISPOS(dst)) || \ 3858 #define UPDATE_VFLAG_WITH_NOT(dst, lop, rop) (cpu->VFlag = !(((lop < 0) && (rop < 0) && (dst >= 0)) || \
3983 (ISPOS(rop) && ISPOS(dst))) 3859 ((lop >= 0) && (rop) >= 0 && (dst < 0))))
3984 #define UPDATE_VFLAG(dst, lop, rop) (cpu->VFlag = (((lop < 0) && (rop < 0) && (dst >= 0)) || \ 3860 #define UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop) (cpu->VFlag = (((lop ^ rop) & (lop ^ dst)) >> 31))
3985 ((lop >= 0) && (rop) >= 0 && (dst < 0)))) 3861
3986 #define UPDATE_VFLAG_WITH_NOT(dst, lop, rop) (cpu->VFlag = !(((lop < 0) && (rop < 0) && (dst >= 0)) || \ 3862 #define SAVE_NZCVT cpu->Cpsr = (cpu->Cpsr & 0x0fffffdf) | \
3987 ((lop >= 0) && (rop) >= 0 && (dst < 0)))) 3863 (cpu->NFlag << 31) | \
3988 #define UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop) (cpu->VFlag = (((lop ^ rop) & (lop ^ dst)) >> 31)) 3864 (cpu->ZFlag << 30) | \
3989 3865 (cpu->CFlag << 29) | \
3990 #define SAVE_NZCVT cpu->Cpsr = (cpu->Cpsr & 0x0fffffdf) | \ 3866 (cpu->VFlag << 28) | \
3991 (cpu->NFlag << 31) | \ 3867 (cpu->TFlag << 5)
3992 (cpu->ZFlag << 30) | \ 3868 #define LOAD_NZCVT cpu->NFlag = (cpu->Cpsr >> 31); \
3993 (cpu->CFlag << 29) | \ 3869 cpu->ZFlag = (cpu->Cpsr >> 30) & 1; \
3994 (cpu->VFlag << 28) | \ 3870 cpu->CFlag = (cpu->Cpsr >> 29) & 1; \
3995 (cpu->TFlag << 5) 3871 cpu->VFlag = (cpu->Cpsr >> 28) & 1; \
3996 #define LOAD_NZCVT cpu->NFlag = (cpu->Cpsr >> 31); \ 3872 cpu->TFlag = (cpu->Cpsr >> 5) & 1;
3997 cpu->ZFlag = (cpu->Cpsr >> 30) & 1; \ 3873
3998 cpu->CFlag = (cpu->Cpsr >> 29) & 1; \ 3874 #define CurrentModeHasSPSR (cpu->Mode != SYSTEM32MODE) && (cpu->Mode != USER32MODE)
3999 cpu->VFlag = (cpu->Cpsr >> 28) & 1; \ 3875 #define PC (cpu->Reg[15])
4000 cpu->TFlag = (cpu->Cpsr >> 5) & 1; 3876 #define CHECK_EXT_INT if (!cpu->NirqSig && !(cpu->Cpsr & 0x80)) goto END;
4001 3877
4002 #define CurrentModeHasSPSR (cpu->Mode != SYSTEM32MODE) && (cpu->Mode != USER32MODE) 3878 arm_processor *cpu = state;
4003 #define PC (cpu->Reg[15])
4004 #define CHECK_EXT_INT if (!cpu->NirqSig) { \
4005 if (!(cpu->Cpsr & 0x80)) { \
4006 goto END; \
4007 } \
4008 }
4009
4010
4011
4012 //arm_processor *cpu = (arm_processor *)get_cast_conf_obj(core->cpu_data, "arm_core_t");
4013 arm_processor *cpu = state; //(arm_processor *)(core->cpu_data->obj);
4014 3879
4015 // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback 3880 // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback
4016 // to a clunky switch statement. 3881 // to a clunky switch statement.
4017#if defined __GNUC__ || defined __clang__ 3882#if defined __GNUC__ || defined __clang__
4018 void *InstLabel[] = { 3883 void *InstLabel[] = {
4019 #define VFP_INTERPRETER_LABEL 3884 &&VMLA_INST, &&VMLS_INST, &&VNMLA_INST, &&VNMLA_INST, &&VNMLS_INST, &&VNMUL_INST, &&VMUL_INST, &&VADD_INST, &&VSUB_INST,
4020 #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 3885 &&VDIV_INST, &&VMOVI_INST, &&VMOVR_INST, &&VABS_INST, &&VNEG_INST, &&VSQRT_INST, &&VCMP_INST, &&VCMP2_INST, &&VCVTBDS_INST,
4021 #undef VFP_INTERPRETER_LABEL 3886 &&VCVTBFF_INST, &&VCVTBFI_INST, &&VMOVBRS_INST, &&VMSR_INST, &&VMOVBRC_INST, &&VMRS_INST, &&VMOVBCR_INST, &&VMOVBRRSS_INST,
4022 &&SRS_INST,&&RFE_INST,&&BKPT_INST,&&BLX_INST,&&CPS_INST,&&PLD_INST,&&SETEND_INST,&&CLREX_INST,&&REV16_INST,&&USAD8_INST,&&SXTB_INST, 3887 &&VMOVBRRD_INST, &&VSTR_INST, &&VPUSH_INST, &&VSTM_INST, &&VPOP_INST, &&VLDR_INST, &&VLDM_INST,
4023 &&UXTB_INST,&&SXTH_INST,&&SXTB16_INST,&&UXTH_INST,&&UXTB16_INST,&&CPY_INST,&&UXTAB_INST,&&SSUB8_INST,&&SHSUB8_INST,&&SSUBADDX_INST, 3888
4024 &&STREX_INST,&&STREXB_INST,&&SWP_INST,&&SWPB_INST,&&SSUB16_INST,&&SSAT16_INST,&&SHSUBADDX_INST,&&QSUBADDX_INST,&&SHADDSUBX_INST, 3889 &&SRS_INST,&&RFE_INST,&&BKPT_INST,&&BLX_INST,&&CPS_INST,&&PLD_INST,&&SETEND_INST,&&CLREX_INST,&&REV16_INST,&&USAD8_INST,&&SXTB_INST,
4025 &&SHADD8_INST,&&SHADD16_INST,&&SEL_INST,&&SADDSUBX_INST,&&SADD8_INST,&&SADD16_INST,&&SHSUB16_INST,&&UMAAL_INST,&&UXTAB16_INST, 3890 &&UXTB_INST,&&SXTH_INST,&&SXTB16_INST,&&UXTH_INST,&&UXTB16_INST,&&CPY_INST,&&UXTAB_INST,&&SSUB8_INST,&&SHSUB8_INST,&&SSUBADDX_INST,
4026 &&USUBADDX_INST,&&USUB8_INST,&&USUB16_INST,&&USAT16_INST,&&USADA8_INST,&&UQSUBADDX_INST,&&UQSUB8_INST,&&UQSUB16_INST, 3891 &&STREX_INST,&&STREXB_INST,&&SWP_INST,&&SWPB_INST,&&SSUB16_INST,&&SSAT16_INST,&&SHSUBADDX_INST,&&QSUBADDX_INST,&&SHADDSUBX_INST,
4027 &&UQADDSUBX_INST,&&UQADD8_INST,&&UQADD16_INST,&&SXTAB_INST,&&UHSUBADDX_INST,&&UHSUB8_INST,&&UHSUB16_INST,&&UHADDSUBX_INST,&&UHADD8_INST, 3892 &&SHADD8_INST,&&SHADD16_INST,&&SEL_INST,&&SADDSUBX_INST,&&SADD8_INST,&&SADD16_INST,&&SHSUB16_INST,&&UMAAL_INST,&&UXTAB16_INST,
4028 &&UHADD16_INST,&&UADDSUBX_INST,&&UADD8_INST,&&UADD16_INST,&&SXTAH_INST,&&SXTAB16_INST,&&QADD8_INST,&&BXJ_INST,&&CLZ_INST,&&UXTAH_INST, 3893 &&USUBADDX_INST,&&USUB8_INST,&&USUB16_INST,&&USAT16_INST,&&USADA8_INST,&&UQSUBADDX_INST,&&UQSUB8_INST,&&UQSUB16_INST,
4029 &&BX_INST,&&REV_INST,&&BLX_INST,&&REVSH_INST,&&QADD_INST,&&QADD16_INST,&&QADDSUBX_INST,&&LDREX_INST,&&QDADD_INST,&&QDSUB_INST, 3894 &&UQADDSUBX_INST,&&UQADD8_INST,&&UQADD16_INST,&&SXTAB_INST,&&UHSUBADDX_INST,&&UHSUB8_INST,&&UHSUB16_INST,&&UHADDSUBX_INST,&&UHADD8_INST,
4030 &&QSUB_INST,&&LDREXB_INST,&&QSUB8_INST,&&QSUB16_INST,&&SMUAD_INST,&&SMMUL_INST,&&SMUSD_INST,&&SMLSD_INST,&&SMLSLD_INST,&&SMMLA_INST, 3895 &&UHADD16_INST,&&UADDSUBX_INST,&&UADD8_INST,&&UADD16_INST,&&SXTAH_INST,&&SXTAB16_INST,&&QADD8_INST,&&BXJ_INST,&&CLZ_INST,&&UXTAH_INST,
4031 &&SMMLS_INST,&&SMLALD_INST,&&SMLAD_INST,&&SMLAW_INST,&&SMULW_INST,&&PKHTB_INST,&&PKHBT_INST,&&SMUL_INST,&&SMLAL_INST,&&SMLA_INST, 3896 &&BX_INST,&&REV_INST,&&BLX_INST,&&REVSH_INST,&&QADD_INST,&&QADD16_INST,&&QADDSUBX_INST,&&LDREX_INST,&&QDADD_INST,&&QDSUB_INST,
4032 &&MCRR_INST,&&MRRC_INST,&&CMP_INST,&&TST_INST,&&TEQ_INST,&&CMN_INST,&&SMULL_INST,&&UMULL_INST,&&UMLAL_INST,&&SMLAL_INST,&&MUL_INST, 3897 &&QSUB_INST,&&LDREXB_INST,&&QSUB8_INST,&&QSUB16_INST,&&SMUAD_INST,&&SMMUL_INST,&&SMUSD_INST,&&SMLSD_INST,&&SMLSLD_INST,&&SMMLA_INST,
4033 &&MLA_INST,&&SSAT_INST,&&USAT_INST,&&MRS_INST,&&MSR_INST,&&AND_INST,&&BIC_INST,&&LDM_INST,&&EOR_INST,&&ADD_INST,&&RSB_INST,&&RSC_INST, 3898 &&SMMLS_INST,&&SMLALD_INST,&&SMLAD_INST,&&SMLAW_INST,&&SMULW_INST,&&PKHTB_INST,&&PKHBT_INST,&&SMUL_INST,&&SMLALXY_INST,&&SMLA_INST,
4034 &&SBC_INST,&&ADC_INST,&&SUB_INST,&&ORR_INST,&&MVN_INST,&&MOV_INST,&&STM_INST,&&LDM_INST,&&LDRSH_INST,&&STM_INST,&&LDM_INST,&&LDRSB_INST, 3899 &&MCRR_INST,&&MRRC_INST,&&CMP_INST,&&TST_INST,&&TEQ_INST,&&CMN_INST,&&SMULL_INST,&&UMULL_INST,&&UMLAL_INST,&&SMLAL_INST,&&MUL_INST,
4035 &&STRD_INST,&&LDRH_INST,&&STRH_INST,&&LDRD_INST,&&STRT_INST,&&STRBT_INST,&&LDRBT_INST,&&LDRT_INST,&&MRC_INST,&&MCR_INST,&&MSR_INST, 3900 &&MLA_INST,&&SSAT_INST,&&USAT_INST,&&MRS_INST,&&MSR_INST,&&AND_INST,&&BIC_INST,&&LDM_INST,&&EOR_INST,&&ADD_INST,&&RSB_INST,&&RSC_INST,
4036 &&LDRB_INST,&&STRB_INST,&&LDR_INST,&&LDRCOND_INST, &&STR_INST,&&CDP_INST,&&STC_INST,&&LDC_INST,&&SWI_INST,&&BBL_INST,&&B_2_THUMB, &&B_COND_THUMB, 3901 &&SBC_INST,&&ADC_INST,&&SUB_INST,&&ORR_INST,&&MVN_INST,&&MOV_INST,&&STM_INST,&&LDM_INST,&&LDRSH_INST,&&STM_INST,&&LDM_INST,&&LDRSB_INST,
4037 &&BL_1_THUMB, &&BL_2_THUMB, &&BLX_1_THUMB, &&DISPATCH,&&INIT_INST_LENGTH,&&END 3902 &&STRD_INST,&&LDRH_INST,&&STRH_INST,&&LDRD_INST,&&STRT_INST,&&STRBT_INST,&&LDRBT_INST,&&LDRT_INST,&&MRC_INST,&&MCR_INST,&&MSR_INST,
4038 }; 3903 &&LDRB_INST,&&STRB_INST,&&LDR_INST,&&LDRCOND_INST, &&STR_INST,&&CDP_INST,&&STC_INST,&&LDC_INST,&&SWI_INST,&&BBL_INST,&&B_2_THUMB, &&B_COND_THUMB,
4039#endif 3904 &&BL_1_THUMB, &&BL_2_THUMB, &&BLX_1_THUMB, &&DISPATCH,&&INIT_INST_LENGTH,&&END
4040 arm_inst * inst_base; 3905 };
4041 unsigned int lop, rop, dst;
4042 unsigned int addr;
4043 unsigned int phys_addr;
4044 unsigned int last_pc = 0;
4045 unsigned int num_instrs = 0;
4046 fault_t fault;
4047 static unsigned int last_physical_base = 0, last_logical_base = 0;
4048 int ptr;
4049 bool single_step = (cpu->NumInstrsToExecute == 1);
4050
4051 LOAD_NZCVT;
4052 DISPATCH:
4053 {
4054 if (!cpu->NirqSig) {
4055 if (!(cpu->Cpsr & 0x80)) {
4056 goto END;
4057 }
4058 }
4059
4060 if (cpu->TFlag) {
4061 cpu->Reg[15] &= 0xfffffffe;
4062 } else
4063 cpu->Reg[15] &= 0xfffffffc;
4064#if PROFILE
4065 /* check next instruction address is valid. */
4066 last_pc = cpu->Reg[15];
4067#endif 3906#endif
4068#if USER_MODE_OPT 3907 arm_inst * inst_base;
4069 phys_addr = cpu->Reg[15]; 3908 unsigned int lop, rop, dst;
4070#else 3909 unsigned int addr;
4071 { 3910 unsigned int phys_addr;
4072 if (last_logical_base == (cpu->Reg[15] & 0xfffff000)) 3911 unsigned int last_pc = 0;
4073 phys_addr = last_physical_base + (cpu->Reg[15] & 0xfff); 3912 unsigned int num_instrs = 0;
4074 else { 3913 fault_t fault;
4075 /* check next instruction address is valid. */ 3914 static unsigned int last_physical_base = 0, last_logical_base = 0;
4076 fault = check_address_validity(cpu, cpu->Reg[15], &phys_addr, 1, INSN_TLB); 3915 int ptr;
4077 if (fault) { 3916 bool single_step = (cpu->NumInstrsToExecute == 1);
4078 cpu->abortSig = true; 3917
4079 cpu->Aborted = ARMul_PrefetchAbortV; 3918 LOAD_NZCVT;
4080 cpu->AbortAddr = cpu->Reg[15]; 3919 DISPATCH:
4081 cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff; 3920 {
4082 cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->Reg[15]; 3921 if (!cpu->NirqSig) {
4083 goto END; 3922 if (!(cpu->Cpsr & 0x80)) {
4084 } 3923 goto END;
4085 last_logical_base = cpu->Reg[15] & 0xfffff000; 3924 }
4086 last_physical_base = phys_addr & 0xfffff000; 3925 }
4087 } 3926
4088 } 3927 if (cpu->TFlag)
4089#if HYBRID_MODE 3928 cpu->Reg[15] &= 0xfffffffe;
4090 /* check if the native code of dyncom is available */ 3929 else
4091 //fast_map hash_map = core->dyncom_engine->fmap; 3930 cpu->Reg[15] &= 0xfffffffc;
4092 //void * pfunc = NULL; 3931
4093 //PFUNC(phys_addr); 3932 phys_addr = cpu->Reg[15];
4094 //if(pfunc){ 3933
4095 if(is_translated_entry(core, phys_addr)){ 3934 if (find_bb(phys_addr, ptr) == -1)
4096 int rc = JIT_RETURN_NOERR;
4097 //DEBUG_LOG(ARM11, "enter jit icounter is %lld, pc=0x%x\n", core->icounter, cpu->Reg[15]);
4098 SAVE_NZCVT;
4099// resume_timing();
4100 rc = cpu_run(core);
4101 LOAD_NZCVT;
4102 //DEBUG_LOG(ARM11, "out of jit ret is %d icounter is %lld, pc=0x%x\n", rc, core->icounter, cpu->Reg[15]);
4103 if((rc == JIT_RETURN_FUNCNOTFOUND) || (rc == JIT_RETURN_FUNC_BLANK)){
4104 /* keep the tflag same with the bit in CPSR */
4105 //cpu->TFlag = cpu->Cpsr & (1 << THUMB_BIT);
4106 //cpu->TFlag = cpu->Cpsr & (1 << 5);
4107 //switch_mode(cpu, cpu->Cpsr & 0x1f);
4108 //DEBUG_LOG(ARM11, "FUNCTION not found , pc=0x%x\n", cpu->Reg[15]);
4109 fault = check_address_validity(cpu, cpu->Reg[15], &phys_addr, 1, INSN_TLB);
4110 if (fault) {
4111 cpu->abortSig = true;
4112 cpu->Aborted = ARMul_PrefetchAbortV;
4113 cpu->AbortAddr = cpu->Reg[15];
4114 cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff;
4115 cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->Reg[15];
4116 goto END;
4117 }
4118 last_logical_base = cpu->Reg[15] & 0xfffff000;
4119 last_physical_base = phys_addr & 0xfffff000;
4120 core->current_page_phys = last_physical_base;
4121 core->current_page_effec = last_logical_base;
4122 //push_to_compiled(core, phys_addr);
4123 }
4124 else{
4125 if((cpu->CP15[CP15(CP15_TLB_FAULT_STATUS)] & 0xf0)){
4126 //DEBUG_LOG(ARM11, "\n\n###############In %s, fsr=0x%x, fault_addr=0x%x, pc=0x%x\n\n", __FUNCTION__, cpu->CP15[CP15(CP15_FAULT_STATUS)], cpu->CP15[CP15(CP15_FAULT_ADDRESS)], cpu->Reg[15]);
4127 //core->Reg[15] -= get_instr_size(cpu_dyncom);
4128 fill_tlb(cpu);
4129 goto END;
4130 }
4131 if (cpu->syscallSig) {
4132 goto END;
4133 }
4134 if (cpu->abortSig) {
4135 cpu->CP15[CP15_TLB_FAULT_STATUS - CP15_BASE] &= 0xFFFFFFF0;
4136 goto END;
4137 }
4138 if (!cpu->NirqSig) {
4139 if (!(cpu->Cpsr & 0x80)) {
4140 goto END;
4141 }
4142 }
4143
4144 /* if regular trap */
4145 cpu->Reg[15] += GET_INST_SIZE(cpu);
4146 /*uint32_t mode = cpu->Cpsr & 0x1f;
4147 if ((mode != cpu->Mode) && (!is_user_mode(core))) {
4148 switch_mode(cpu, mode);
4149 return 1;
4150 }*/
4151
4152 goto END;
4153 }
4154 //phys_addr = cpu->Reg[15];
4155 }
4156 else{
4157 if (last_logical_base == (cpu->Reg[15] & 0xfffff000))
4158 phys_addr = last_physical_base + (cpu->Reg[15] & 0xfff);
4159 else {
4160 /* check next instruction address is valid. */
4161 fault = check_address_validity(cpu, cpu->Reg[15], &phys_addr, 1, INSN_TLB);
4162 if (fault) {
4163 cpu->abortSig = true;
4164 cpu->Aborted = ARMul_PrefetchAbortV;
4165 cpu->AbortAddr = cpu->Reg[15];
4166 cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)] = fault & 0xff;
4167 cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = cpu->Reg[15];
4168 goto END;
4169 }
4170 last_logical_base = cpu->Reg[15] & 0xfffff000;
4171 last_physical_base = phys_addr & 0xfffff000;
4172 }
4173 }
4174#endif /* #if HYBRID_MODE */
4175#endif /* #if USER_MODE_OPT */
4176 if (true){//if(is_fast_interp_code(core, phys_addr)){
4177 if (find_bb(phys_addr, ptr) == -1)
4178 if (InterpreterTranslate(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION)
4179 goto END;
4180 }
4181 else{
4182 if (InterpreterTranslate(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION) 3935 if (InterpreterTranslate(cpu, ptr, cpu->Reg[15]) == FETCH_EXCEPTION)
4183 goto END; 3936 goto END;
4184 } 3937
4185#if PROFILE 3938 inst_base = (arm_inst *)&inst_buf[ptr];
4186 resume_timing(); 3939 GOTO_NEXT_INST;
4187#endif 3940 }
4188 inst_base = (arm_inst *)&inst_buf[ptr]; 3941 ADC_INST:
4189 GOTO_NEXT_INST; 3942 {
4190 } 3943 adc_inst *inst_cream = (adc_inst *)inst_base->component;
4191 ADC_INST: 3944 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4192 { 3945 lop = RN;
4193 INC_ICOUNTER; 3946 unsigned int sht_op = SHIFTER_OPERAND;
4194 adc_inst *inst_cream = (adc_inst *)inst_base->component; 3947 rop = SHIFTER_OPERAND + cpu->CFlag;
4195 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 3948 RD = dst = lop + rop;
4196 lop = RN; 3949 if (inst_cream->S && (inst_cream->Rd == 15)) {
4197 unsigned int sht_op = SHIFTER_OPERAND; 3950 if (CurrentModeHasSPSR) {
4198 rop = SHIFTER_OPERAND + cpu->CFlag; 3951 cpu->Cpsr = cpu->Spsr_copy;
4199 RD = dst = lop + rop; 3952 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
4200 if (inst_cream->S && (inst_cream->Rd == 15)) { 3953 LOAD_NZCVT;
4201 /* cpsr = spsr */ 3954 }
4202 if (CurrentModeHasSPSR) { 3955 } else if (inst_cream->S) {
4203 cpu->Cpsr = cpu->Spsr_copy; 3956 UPDATE_NFLAG(dst);
4204 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 3957 UPDATE_ZFLAG(dst);
4205 LOAD_NZCVT; 3958 UPDATE_CFLAG_CARRY_FROM_ADD(lop, sht_op, cpu->CFlag);
4206 } 3959 UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
4207 } else if (inst_cream->S) { 3960 }
4208 UPDATE_NFLAG(dst); 3961 if (inst_cream->Rd == 15) {
4209 UPDATE_ZFLAG(dst); 3962 INC_PC(sizeof(adc_inst));
4210 UPDATE_CFLAG_CARRY_FROM_ADD(lop, sht_op, cpu->CFlag); 3963 goto DISPATCH;
4211 UPDATE_VFLAG((int)dst, (int)lop, (int)rop); 3964 }
4212 } 3965 }
4213 if (inst_cream->Rd == 15) { 3966 cpu->Reg[15] += GET_INST_SIZE(cpu);
4214 INC_PC(sizeof(adc_inst)); 3967 INC_PC(sizeof(adc_inst));
4215 goto DISPATCH; 3968 FETCH_INST;
4216 } 3969 GOTO_NEXT_INST;
4217 } 3970 }
4218 cpu->Reg[15] += GET_INST_SIZE(cpu); 3971 ADD_INST:
4219 INC_PC(sizeof(adc_inst)); 3972 {
4220 FETCH_INST; 3973 add_inst *inst_cream = (add_inst *)inst_base->component;
4221 GOTO_NEXT_INST; 3974 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4222 } 3975 lop = RN;
4223 ADD_INST: 3976 if (inst_cream->Rn == 15) {
4224 { 3977 lop += 2 * GET_INST_SIZE(cpu);
4225 INC_ICOUNTER; 3978 }
4226 add_inst *inst_cream = (add_inst *)inst_base->component; 3979 rop = SHIFTER_OPERAND;
4227 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 3980 RD = dst = lop + rop;
4228 lop = RN; 3981 if (inst_cream->S && (inst_cream->Rd == 15)) {
4229 if (inst_cream->Rn == 15) { 3982 if (CurrentModeHasSPSR) {
4230 lop += 2 * GET_INST_SIZE(cpu); 3983 cpu->Cpsr = cpu->Spsr_copy;
4231 } 3984 switch_mode(cpu, cpu->Cpsr & 0x1f);
4232 rop = SHIFTER_OPERAND; 3985 LOAD_NZCVT;
4233 RD = dst = lop + rop; 3986 }
4234 if (inst_cream->S && (inst_cream->Rd == 15)) { 3987 } else if (inst_cream->S) {
4235 /* cpsr = spsr*/ 3988 UPDATE_NFLAG(dst);
4236 if (CurrentModeHasSPSR) { 3989 UPDATE_ZFLAG(dst);
4237 cpu->Cpsr = cpu->Spsr_copy; 3990 UPDATE_CFLAG(dst, lop, rop);
4238 switch_mode(cpu, cpu->Cpsr & 0x1f); 3991 UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
4239 LOAD_NZCVT; 3992 }
4240 } 3993 if (inst_cream->Rd == 15) {
4241 } else if (inst_cream->S) { 3994 INC_PC(sizeof(add_inst));
4242 UPDATE_NFLAG(dst); 3995 goto DISPATCH;
4243 UPDATE_ZFLAG(dst); 3996 }
4244 UPDATE_CFLAG(dst, lop, rop); 3997 }
4245 UPDATE_VFLAG((int)dst, (int)lop, (int)rop); 3998 cpu->Reg[15] += GET_INST_SIZE(cpu);
4246 } 3999 INC_PC(sizeof(add_inst));
4247 if (inst_cream->Rd == 15) { 4000 FETCH_INST;
4248 INC_PC(sizeof(add_inst)); 4001 GOTO_NEXT_INST;
4249 goto DISPATCH; 4002 }
4250 } 4003 AND_INST:
4251 } 4004 {
4252 cpu->Reg[15] += GET_INST_SIZE(cpu); 4005 and_inst *inst_cream = (and_inst *)inst_base->component;
4253 INC_PC(sizeof(add_inst)); 4006 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4254 FETCH_INST; 4007 lop = RN;
4255 GOTO_NEXT_INST; 4008 rop = SHIFTER_OPERAND;
4256 } 4009 RD = dst = lop & rop;
4257 AND_INST: 4010 if (inst_cream->S && (inst_cream->Rd == 15)) {
4258 { 4011 if (CurrentModeHasSPSR) {
4259 INC_ICOUNTER; 4012 cpu->Cpsr = cpu->Spsr_copy;
4260 and_inst *inst_cream = (and_inst *)inst_base->component; 4013 switch_mode(cpu, cpu->Cpsr & 0x1f);
4261 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4014 LOAD_NZCVT;
4262 lop = RN; 4015 }
4263 rop = SHIFTER_OPERAND; 4016 } else if (inst_cream->S) {
4264 RD = dst = lop & rop; 4017 UPDATE_NFLAG(dst);
4265 if (inst_cream->S && (inst_cream->Rd == 15)) { 4018 UPDATE_ZFLAG(dst);
4266 /* cpsr = spsr*/ 4019 UPDATE_CFLAG_WITH_SC;
4267 if (CurrentModeHasSPSR) { 4020 }
4268 cpu->Cpsr = cpu->Spsr_copy; 4021 if (inst_cream->Rd == 15) {
4269 switch_mode(cpu, cpu->Cpsr & 0x1f); 4022 INC_PC(sizeof(and_inst));
4270 LOAD_NZCVT; 4023 goto DISPATCH;
4271 } 4024 }
4272 } else if (inst_cream->S) { 4025 }
4273 UPDATE_NFLAG(dst); 4026 cpu->Reg[15] += GET_INST_SIZE(cpu);
4274 UPDATE_ZFLAG(dst); 4027 INC_PC(sizeof(and_inst));
4275 UPDATE_CFLAG_WITH_SC; 4028 FETCH_INST;
4276 //UPDATE_VFLAG((int)dst, (int)lop, (int)rop); 4029 GOTO_NEXT_INST;
4277 } 4030 }
4278 if (inst_cream->Rd == 15) { 4031 BBL_INST:
4279 INC_PC(sizeof(and_inst)); 4032 {
4280 goto DISPATCH; 4033 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4281 } 4034 bbl_inst *inst_cream = (bbl_inst *)inst_base->component;
4282 } 4035 if (inst_cream->L) {
4283 cpu->Reg[15] += GET_INST_SIZE(cpu); 4036 LINK_RTN_ADDR;
4284 INC_PC(sizeof(and_inst)); 4037 }
4285 FETCH_INST; 4038 SET_PC;
4286 GOTO_NEXT_INST; 4039 INC_PC(sizeof(bbl_inst));
4287 } 4040 goto DISPATCH;
4288 BBL_INST: 4041 }
4289 { 4042 cpu->Reg[15] += GET_INST_SIZE(cpu);
4290 INC_ICOUNTER; 4043 INC_PC(sizeof(bbl_inst));
4291 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4044 goto DISPATCH;
4292 bbl_inst *inst_cream = (bbl_inst *)inst_base->component; 4045 }
4293 if (inst_cream->L) { 4046 BIC_INST:
4294 LINK_RTN_ADDR; 4047 {
4295 } 4048 bic_inst *inst_cream = (bic_inst *)inst_base->component;
4296 SET_PC; 4049 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4297 INC_PC(sizeof(bbl_inst)); 4050 lop = RN;
4298 goto DISPATCH; 4051 if (inst_cream->Rn == 15) {
4299 } 4052 lop += 2 * GET_INST_SIZE(cpu);
4300 cpu->Reg[15] += GET_INST_SIZE(cpu); 4053 }
4301 INC_PC(sizeof(bbl_inst)); 4054 rop = SHIFTER_OPERAND;
4302 goto DISPATCH; 4055 RD = dst = lop & (~rop);
4303 } 4056 if ((inst_cream->S) && (inst_cream->Rd == 15)) {
4304 BIC_INST: 4057 if (CurrentModeHasSPSR) {
4305 { 4058 cpu->Cpsr = cpu->Spsr_copy;
4306 INC_ICOUNTER; 4059 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
4307 bic_inst *inst_cream = (bic_inst *)inst_base->component; 4060 LOAD_NZCVT;
4308 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4061 }
4309 lop = RN; 4062 } else if (inst_cream->S) {
4310 if (inst_cream->Rn == 15) { 4063 UPDATE_NFLAG(dst);
4311 lop += 2 * GET_INST_SIZE(cpu); 4064 UPDATE_ZFLAG(dst);
4312 } 4065 UPDATE_CFLAG_WITH_SC;
4313 rop = SHIFTER_OPERAND; 4066 }
4314// RD = dst = lop & (rop ^ 0xffffffff); 4067 if (inst_cream->Rd == 15) {
4315 RD = dst = lop & (~rop); 4068 INC_PC(sizeof(bic_inst));
4316 if ((inst_cream->S) && (inst_cream->Rd == 15)) { 4069 goto DISPATCH;
4317 /* cpsr = spsr */ 4070 }
4318 if (CurrentModeHasSPSR) { 4071 }
4319 cpu->Cpsr = cpu->Spsr_copy; 4072 cpu->Reg[15] += GET_INST_SIZE(cpu);
4320 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 4073 INC_PC(sizeof(bic_inst));
4321 LOAD_NZCVT; 4074 FETCH_INST;
4322 } 4075 GOTO_NEXT_INST;
4323 } else if (inst_cream->S) { 4076 }
4324 UPDATE_NFLAG(dst); 4077 BKPT_INST:
4325 UPDATE_ZFLAG(dst); 4078 BLX_INST:
4326 UPDATE_CFLAG_WITH_SC; 4079 {
4327 } 4080 blx_inst *inst_cream = (blx_inst *)inst_base->component;
4328 if (inst_cream->Rd == 15) { 4081 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4329 INC_PC(sizeof(bic_inst)); 4082 unsigned int inst = inst_cream->inst;
4330 goto DISPATCH; 4083 if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) {
4331 } 4084 cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu));
4332 } 4085 if(cpu->TFlag)
4333 cpu->Reg[15] += GET_INST_SIZE(cpu); 4086 cpu->Reg[14] |= 0x1;
4334 INC_PC(sizeof(bic_inst)); 4087 cpu->Reg[15] = cpu->Reg[inst_cream->val.Rm] & 0xfffffffe;
4335 FETCH_INST; 4088 cpu->TFlag = cpu->Reg[inst_cream->val.Rm] & 0x1;
4336 GOTO_NEXT_INST; 4089 } else {
4337 } 4090 cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu));
4338 BKPT_INST: 4091 cpu->TFlag = 0x1;
4339 BLX_INST: 4092 int signed_int = inst_cream->val.signed_immed_24;
4340 { 4093 signed_int = (signed_int) & 0x800000 ? (0x3F000000 | signed_int) : signed_int;
4341 INC_ICOUNTER; 4094 signed_int = signed_int << 2;
4342 blx_inst *inst_cream = (blx_inst *)inst_base->component; 4095 cpu->Reg[15] = cpu->Reg[15] + 8 + signed_int + (BIT(inst, 24) << 1);
4343 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4096 }
4344 unsigned int inst = inst_cream->inst; 4097 INC_PC(sizeof(blx_inst));
4345 if (BITS(inst, 20, 27) == 0x12 && BITS(inst, 4, 7) == 0x3) { 4098 goto DISPATCH;
4346 //LINK_RTN_ADDR; 4099 }
4347 cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu)); 4100 cpu->Reg[15] += GET_INST_SIZE(cpu);
4348 if(cpu->TFlag) 4101 INC_PC(sizeof(blx_inst));
4349 cpu->Reg[14] |= 0x1; 4102 goto DISPATCH;
4350 cpu->Reg[15] = cpu->Reg[inst_cream->val.Rm] & 0xfffffffe; 4103 }
4351 cpu->TFlag = cpu->Reg[inst_cream->val.Rm] & 0x1; 4104 BX_INST:
4352 //cpu->Reg[15] = cpu->Reg[BITS(inst, 0, 3)] & 0xfffffffe; 4105 {
4353 //cpu->TFlag = cpu->Reg[BITS(inst, 0, 3)] & 0x1; 4106 bx_inst *inst_cream = (bx_inst *)inst_base->component;
4354 } else { 4107 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4355 cpu->Reg[14] = (cpu->Reg[15] + GET_INST_SIZE(cpu)); 4108 if (inst_cream->Rm == 15)
4356 cpu->TFlag = 0x1; 4109 LOG_WARNING(Core_ARM11, "BX at pc %x: use of Rm = R15 is discouraged", cpu->Reg[15]);
4357 int signed_int = inst_cream->val.signed_immed_24; 4110 cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1;
4358 signed_int = (signed_int) & 0x800000 ? (0x3F000000 | signed_int) : signed_int; 4111 cpu->Reg[15] = cpu->Reg[inst_cream->Rm] & 0xfffffffe;
4359 signed_int = signed_int << 2; 4112 INC_PC(sizeof(bx_inst));
4360 // cpu->Reg[15] = cpu->Reg[15] + 2 * GET_INST_SIZE(cpu) 4113 goto DISPATCH;
4361 cpu->Reg[15] = cpu->Reg[15] + 8 4114 }
4362 + signed_int + (BIT(inst, 24) << 1); 4115 cpu->Reg[15] += GET_INST_SIZE(cpu);
4363 //DEBUG_MSG; 4116 INC_PC(sizeof(bx_inst));
4364 } 4117 goto DISPATCH;
4365 INC_PC(sizeof(blx_inst)); 4118 }
4366 goto DISPATCH; 4119 BXJ_INST:
4367 } 4120 CDP_INST:
4368 cpu->Reg[15] += GET_INST_SIZE(cpu); 4121 {
4369// INC_PC(sizeof(bx_inst)); 4122 cdp_inst *inst_cream = (cdp_inst *)inst_base->component;
4370 INC_PC(sizeof(blx_inst)); 4123 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4371 goto DISPATCH; 4124 // Undefined instruction here
4372 } 4125 cpu->NumInstrsToExecute = 0;
4373 BX_INST: 4126 return num_instrs;
4374 { 4127 }
4375 INC_ICOUNTER; 4128 cpu->Reg[15] += GET_INST_SIZE(cpu);
4376 bx_inst *inst_cream = (bx_inst *)inst_base->component; 4129 INC_PC(sizeof(cdp_inst));
4377 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4130 FETCH_INST;
4378 if (inst_cream->Rm == 15) 4131 GOTO_NEXT_INST;
4379 DEBUG_LOG(ARM11, "In %s, BX at pc %x: use of Rm = R15 is discouraged\n", __FUNCTION__, cpu->Reg[15]); 4132 }
4380 cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1; 4133
4381 cpu->Reg[15] = cpu->Reg[inst_cream->Rm] & 0xfffffffe; 4134 CLREX_INST:
4382// cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1; 4135 {
4383 INC_PC(sizeof(bx_inst)); 4136 remove_exclusive(cpu, 0);
4384 goto DISPATCH; 4137 cpu->exclusive_state = 0;
4385 } 4138
4386 cpu->Reg[15] += GET_INST_SIZE(cpu); 4139 cpu->Reg[15] += GET_INST_SIZE(cpu);
4387// INC_PC(sizeof(bx_inst)); 4140 INC_PC(sizeof(clrex_inst));
4388 INC_PC(sizeof(bx_inst)); 4141 FETCH_INST;
4389 goto DISPATCH; 4142 GOTO_NEXT_INST;
4390 } 4143 }
4391 BXJ_INST: 4144 CLZ_INST:
4392 CDP_INST: 4145 {
4393 { 4146 clz_inst *inst_cream = (clz_inst *)inst_base->component;
4394 INC_ICOUNTER; 4147 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4395 cdp_inst *inst_cream = (cdp_inst *)inst_base->component; 4148 RD = clz(RM);
4396 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4149 }
4397 /* FIXME, check if cp access allowed */ 4150 cpu->Reg[15] += GET_INST_SIZE(cpu);
4398 #define CP_ACCESS_ALLOW 0 4151 INC_PC(sizeof(clz_inst));
4399 if(CP_ACCESS_ALLOW){ 4152 FETCH_INST;
4400 /* undefined instruction here */ 4153 GOTO_NEXT_INST;
4401 cpu->NumInstrsToExecute = 0; 4154 }
4402 return num_instrs; 4155 CMN_INST:
4403 } 4156 {
4404 ERROR_LOG(ARM11, "CDP insn inst=0x%x, pc=0x%x\n", inst_cream->inst, cpu->Reg[15]); 4157 cmn_inst *inst_cream = (cmn_inst *)inst_base->component;
4405 unsigned cpab = (cpu->CDP[inst_cream->cp_num]) (cpu, ARMul_FIRST, inst_cream->inst); 4158 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4406 if(cpab != ARMul_DONE){ 4159 lop = RN;
4407 ERROR_LOG(ARM11, "CDP insn wrong, inst=0x%x, cp_num=0x%x\n", inst_cream->inst, inst_cream->cp_num); 4160 rop = SHIFTER_OPERAND;
4408 //CITRA_IGNORE_EXIT(-1); 4161 dst = lop + rop;
4409 } 4162 UPDATE_NFLAG(dst);
4410 } 4163 UPDATE_ZFLAG(dst);
4411 cpu->Reg[15] += GET_INST_SIZE(cpu); 4164 UPDATE_CFLAG(dst, lop, rop);
4412 INC_PC(sizeof(cdp_inst)); 4165 UPDATE_VFLAG((int)dst, (int)lop, (int)rop);
4413 FETCH_INST; 4166 }
4414 GOTO_NEXT_INST; 4167 cpu->Reg[15] += GET_INST_SIZE(cpu);
4415 } 4168 INC_PC(sizeof(cmn_inst));
4416 4169 FETCH_INST;
4417 CLREX_INST: 4170 GOTO_NEXT_INST;
4418 { 4171 }
4419 INC_ICOUNTER; 4172 CMP_INST:
4420 remove_exclusive(cpu, 0); 4173 {
4421 cpu->exclusive_state = 0; 4174 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4422 4175 cmp_inst *inst_cream = (cmp_inst *)inst_base->component;
4423 cpu->Reg[15] += GET_INST_SIZE(cpu); 4176 lop = RN;
4424 INC_PC(sizeof(clrex_inst)); 4177 if (inst_cream->Rn == 15) {
4425 FETCH_INST; 4178 lop += 2 * GET_INST_SIZE(cpu);
4426 GOTO_NEXT_INST; 4179 }
4427 } 4180 rop = SHIFTER_OPERAND;
4428 CLZ_INST: 4181 dst = lop - rop;
4429 { 4182
4430 INC_ICOUNTER; 4183 UPDATE_NFLAG(dst);
4431 clz_inst *inst_cream = (clz_inst *)inst_base->component; 4184 UPDATE_ZFLAG(dst);
4432 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4185 UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop);
4433 RD = clz(RM); 4186 UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop);
4434 } 4187 }
4435 cpu->Reg[15] += GET_INST_SIZE(cpu); 4188 cpu->Reg[15] += GET_INST_SIZE(cpu);
4436 INC_PC(sizeof(clz_inst)); 4189 INC_PC(sizeof(cmp_inst));
4437 FETCH_INST; 4190 FETCH_INST;
4438 GOTO_NEXT_INST; 4191 GOTO_NEXT_INST;
4439 } 4192 }
4440 CMN_INST: 4193 CPS_INST:
4441 { 4194 {
4442 INC_ICOUNTER; 4195 cps_inst *inst_cream = (cps_inst *)inst_base->component;
4443 cmn_inst *inst_cream = (cmn_inst *)inst_base->component; 4196 uint32_t aif_val = 0;
4444 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4197 uint32_t aif_mask = 0;
4445// DEBUG_LOG(ARM11, "RN is %x\n", RN); 4198 if (InAPrivilegedMode(cpu)) {
4446 lop = RN; 4199 if (inst_cream->imod1) {
4447 rop = SHIFTER_OPERAND; 4200 if (inst_cream->A) {
4448 dst = lop + rop; 4201 aif_val |= (inst_cream->imod0 << 8);
4449 UPDATE_NFLAG(dst); 4202 aif_mask |= 1 << 8;
4450 UPDATE_ZFLAG(dst); 4203 }
4451 UPDATE_CFLAG(dst, lop, rop); 4204 if (inst_cream->I) {
4452 UPDATE_VFLAG((int)dst, (int)lop, (int)rop); 4205 aif_val |= (inst_cream->imod0 << 7);
4453 } 4206 aif_mask |= 1 << 7;
4454 cpu->Reg[15] += GET_INST_SIZE(cpu); 4207 }
4455 INC_PC(sizeof(cmn_inst)); 4208 if (inst_cream->F) {
4456 FETCH_INST; 4209 aif_val |= (inst_cream->imod0 << 6);
4457 GOTO_NEXT_INST; 4210 aif_mask |= 1 << 6;
4458 } 4211 }
4459 CMP_INST: 4212 aif_mask = ~aif_mask;
4460 { 4213 cpu->Cpsr = (cpu->Cpsr & aif_mask) | aif_val;
4461// DEBUG_LOG(ARM11, "cmp inst\n"); 4214 }
4462// DEBUG_LOG(ARM11, "pc: %x\n", cpu->Reg[15]); 4215 if (inst_cream->mmod) {
4463 INC_ICOUNTER; 4216 cpu->Cpsr = (cpu->Cpsr & 0xffffffe0) | inst_cream->mode;
4464 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4217 switch_mode(cpu, inst_cream->mode);
4465// DEBUG_LOG(ARM11, "r0 is %x\n", cpu->Reg[0]); 4218 }
4466 cmp_inst *inst_cream = (cmp_inst *)inst_base->component; 4219 }
4467 lop = RN; 4220 cpu->Reg[15] += GET_INST_SIZE(cpu);
4468 if (inst_cream->Rn == 15) { 4221 INC_PC(sizeof(cps_inst));
4469 lop += 2 * GET_INST_SIZE(cpu); 4222 FETCH_INST;
4470 } 4223 GOTO_NEXT_INST;
4471 rop = SHIFTER_OPERAND; 4224 }
4472 dst = lop - rop; 4225 CPY_INST:
4473 4226 {
4474 UPDATE_NFLAG(dst); 4227 mov_inst *inst_cream = (mov_inst *)inst_base->component;
4475 UPDATE_ZFLAG(dst); 4228 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4476// UPDATE_CFLAG(dst, lop, rop); 4229 RD = SHIFTER_OPERAND;
4477 UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop); 4230 if ((inst_cream->Rd == 15)) {
4478// UPDATE_VFLAG((int)dst, (int)lop, (int)rop); 4231 INC_PC(sizeof(mov_inst));
4479 UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop); 4232 goto DISPATCH;
4480// UPDATE_VFLAG_WITH_NOT(dst, lop, rop); 4233 }
4481 } 4234 }
4482 cpu->Reg[15] += GET_INST_SIZE(cpu); 4235 cpu->Reg[15] += GET_INST_SIZE(cpu);
4483 INC_PC(sizeof(cmp_inst)); 4236 INC_PC(sizeof(mov_inst));
4484 FETCH_INST; 4237 FETCH_INST;
4485 GOTO_NEXT_INST; 4238 GOTO_NEXT_INST;
4486 } 4239 }
4487 CPS_INST: 4240 EOR_INST:
4488 { 4241 {
4489 INC_ICOUNTER; 4242 eor_inst *inst_cream = (eor_inst *)inst_base->component;
4490 cps_inst *inst_cream = (cps_inst *)inst_base->component; 4243 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4491 uint32_t aif_val = 0; 4244 lop = RN;
4492 uint32_t aif_mask = 0; 4245 if (inst_cream->Rn == 15) {
4493 if (InAPrivilegedMode(cpu)) { 4246 lop += 2 * GET_INST_SIZE(cpu);
4494 /* isInAPrivilegedMode */ 4247 }
4495 if (inst_cream->imod1) { 4248 rop = SHIFTER_OPERAND;
4496 if (inst_cream->A) { 4249 RD = dst = lop ^ rop;
4497 aif_val |= (inst_cream->imod0 << 8); 4250 if (inst_cream->S && (inst_cream->Rd == 15)) {
4498 aif_mask |= 1 << 8; 4251 if (CurrentModeHasSPSR) {
4499 } 4252 cpu->Cpsr = cpu->Spsr_copy;
4500 if (inst_cream->I) { 4253 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
4501 aif_val |= (inst_cream->imod0 << 7); 4254 LOAD_NZCVT;
4502 aif_mask |= 1 << 7; 4255 }
4503 } 4256 } else if (inst_cream->S) {
4504 if (inst_cream->F) { 4257 UPDATE_NFLAG(dst);
4505 aif_val |= (inst_cream->imod0 << 6); 4258 UPDATE_ZFLAG(dst);
4506 aif_mask |= 1 << 6; 4259 UPDATE_CFLAG_WITH_SC;
4507 } 4260 }
4508 aif_mask = ~aif_mask; 4261 if (inst_cream->Rd == 15) {
4509 cpu->Cpsr = (cpu->Cpsr & aif_mask) | aif_val; 4262 INC_PC(sizeof(eor_inst));
4510 } 4263 goto DISPATCH;
4511 if (inst_cream->mmod) { 4264 }
4512 cpu->Cpsr = (cpu->Cpsr & 0xffffffe0) | inst_cream->mode; 4265 }
4513 switch_mode(cpu, inst_cream->mode); 4266 cpu->Reg[15] += GET_INST_SIZE(cpu);
4514 } 4267 INC_PC(sizeof(eor_inst));
4515 } 4268 FETCH_INST;
4516 cpu->Reg[15] += GET_INST_SIZE(cpu); 4269 GOTO_NEXT_INST;
4517 INC_PC(sizeof(cps_inst)); 4270 }
4518 FETCH_INST; 4271 LDC_INST:
4519 GOTO_NEXT_INST; 4272 {
4520 } 4273 // Instruction not implemented
4521 CPY_INST: 4274 //LOG_CRITICAL(Core_ARM11, "unimplemented instruction");
4522 { 4275 cpu->Reg[15] += GET_INST_SIZE(cpu);
4523 INC_ICOUNTER; 4276 INC_PC(sizeof(ldc_inst));
4524 mov_inst *inst_cream = (mov_inst *)inst_base->component; 4277 FETCH_INST;
4525// cpy_inst *inst_cream = (cpy_inst *)inst_base->component; 4278 GOTO_NEXT_INST;
4526 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4279 }
4527 RD = SHIFTER_OPERAND; 4280 LDM_INST:
4528// RD = RM; 4281 {
4529 if ((inst_cream->Rd == 15)) { 4282 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4530 INC_PC(sizeof(mov_inst)); 4283 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4531 goto DISPATCH; 4284 int i;
4532 } 4285 unsigned int ret;
4533 } 4286 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4534// DEBUG_LOG(ARM11, "cpy inst %x\n", cpu->Reg[15]); 4287 if (fault) {
4535 cpu->Reg[15] += GET_INST_SIZE(cpu); 4288 goto MMU_EXCEPTION;
4536 INC_PC(sizeof(mov_inst)); 4289 }
4537 FETCH_INST; 4290 unsigned int inst = inst_cream->inst;
4538 GOTO_NEXT_INST; 4291 if (BIT(inst, 22) && !BIT(inst, 15)) {
4539 } 4292 for (i = 0; i < 13; i++) {
4540 EOR_INST: 4293 if(BIT(inst, i)){
4541 { 4294 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4542 INC_ICOUNTER; 4295 cpu->Reg[i] = ret;
4543 eor_inst *inst_cream = (eor_inst *)inst_base->component; 4296 addr += 4;
4544 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4297 if ((addr & 0xfff) == 0) {
4545 lop = RN; 4298 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4546 if (inst_cream->Rn == 15) { 4299 } else {
4547 lop += 2 * GET_INST_SIZE(cpu); 4300 phys_addr += 4;
4548 } 4301 }
4549 rop = SHIFTER_OPERAND; 4302 }
4550 RD = dst = lop ^ rop; 4303 }
4551 if (inst_cream->S && (inst_cream->Rd == 15)) { 4304 if (BIT(inst, 13)) {
4552 /* cpsr = spsr*/ 4305 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4553 if (CurrentModeHasSPSR) { 4306
4554 cpu->Cpsr = cpu->Spsr_copy; 4307 if (cpu->Mode == USER32MODE)
4555 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 4308 cpu->Reg[13] = ret;
4556 LOAD_NZCVT; 4309 else
4557 } 4310 cpu->Reg_usr[0] = ret;
4558 } else if (inst_cream->S) { 4311 addr += 4;
4559 UPDATE_NFLAG(dst); 4312 if ((addr & 0xfff) == 0) {
4560 UPDATE_ZFLAG(dst); 4313 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4561 UPDATE_CFLAG_WITH_SC; 4314 } else {
4562// UPDATE_CFLAG(dst, lop, rop); 4315 phys_addr += 4;
4563// UPDATE_VFLAG((int)dst, (int)lop, (int)rop); 4316 }
4564 } 4317 }
4565 if (inst_cream->Rd == 15) { 4318 if (BIT(inst, 14)) {
4566 INC_PC(sizeof(eor_inst)); 4319 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4567 goto DISPATCH; 4320
4568 } 4321 if (cpu->Mode == USER32MODE)
4569 } 4322 cpu->Reg[14] = ret;
4570 cpu->Reg[15] += GET_INST_SIZE(cpu); 4323 else
4571 INC_PC(sizeof(eor_inst)); 4324 cpu->Reg_usr[1] = ret;
4572 FETCH_INST; 4325 }
4573 GOTO_NEXT_INST; 4326 } else if (!BIT(inst, 22)) {
4574 } 4327 for( i = 0; i < 16; i ++ ){
4575 LDC_INST: 4328 if(BIT(inst, i)){
4576 { 4329 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4577 INC_ICOUNTER; 4330 if (fault) goto MMU_EXCEPTION;
4578 /* NOT IMPL */ 4331
4579 cpu->Reg[15] += GET_INST_SIZE(cpu); 4332 // For armv5t, should enter thumb when bits[0] is non-zero.
4580 INC_PC(sizeof(ldc_inst)); 4333 if(i == 15){
4581 FETCH_INST; 4334 cpu->TFlag = ret & 0x1;
4582 GOTO_NEXT_INST; 4335 ret &= 0xFFFFFFFE;
4583 }
4584 LDM_INST:
4585 {
4586 INC_ICOUNTER;
4587 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4588 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4589 int i;
4590 unsigned int ret;
4591 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4592 if (fault) {
4593 goto MMU_EXCEPTION;
4594 }
4595 unsigned int inst = inst_cream->inst;
4596 if (BIT(inst, 22) && !BIT(inst, 15)) {
4597// DEBUG_MSG;
4598 #if 1
4599 /* LDM (2) user */
4600 for (i = 0; i < 13; i++) {
4601 if(BIT(inst, i)){
4602 #if 0
4603 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4604 if (fault) {
4605 goto MMU_EXCEPTION;
4606 }
4607 #endif
4608 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4609 //if (fault) goto MMU_EXCEPTION;
4610 cpu->Reg[i] = ret;
4611 addr += 4;
4612 if ((addr & 0xfff) == 0) {
4613 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4614 } else {
4615 phys_addr += 4;
4616 }
4617 }
4618 }
4619 if (BIT(inst, 13)) {
4620 #if 0
4621 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4622 if (fault) {
4623 goto MMU_EXCEPTION;
4624 }
4625 #endif
4626 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4627 //if (fault) goto MMU_EXCEPTION;
4628 if (cpu->Mode == USER32MODE)
4629 cpu->Reg[13] = ret;
4630 else
4631 cpu->Reg_usr[0] = ret;
4632 addr += 4;
4633 if ((addr & 0xfff) == 0) {
4634 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4635 } else {
4636 phys_addr += 4;
4637 }
4638 }
4639 if (BIT(inst, 14)) {
4640 #if 0
4641 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4642 if (fault) {
4643 goto MMU_EXCEPTION;
4644 }
4645 #endif
4646 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4647 //if (fault) goto MMU_EXCEPTION;
4648 if (cpu->Mode == USER32MODE)
4649 cpu->Reg[14] = ret;
4650 else
4651 cpu->Reg_usr[1] = ret;
4652 }
4653 #endif
4654 } else if (!BIT(inst, 22)) {
4655 for( i = 0; i < 16; i ++ ){
4656 if(BIT(inst, i)){
4657 //bus_read(32, addr, &ret);
4658 #if 0
4659 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4660 if (fault) {
4661 goto MMU_EXCEPTION;
4662 }
4663 #endif
4664 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4665 if (fault) goto MMU_EXCEPTION;
4666 /* For armv5t, should enter thumb when bits[0] is non-zero. */
4667 if(i == 15){
4668 cpu->TFlag = ret & 0x1;
4669 ret &= 0xFFFFFFFE;
4670 //DEBUG_LOG(ARM11, "In %s, TFlag ret=0x%x\n", __FUNCTION__, ret);
4671 }
4672
4673 cpu->Reg[i] = ret;
4674 addr += 4;
4675 if ((addr & 0xfff) == 0) {
4676 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4677 } else {
4678 phys_addr += 4;
4679 }
4680 }
4681 }
4682 } else if (BIT(inst, 22) && BIT(inst, 15)) {
4683 for( i = 0; i < 15; i ++ ){
4684 if(BIT(inst, i)){
4685 #if 0
4686 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4687 if (fault) {
4688 goto MMU_EXCEPTION;
4689 }
4690 #endif
4691 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4692 //if (fault) goto MMU_EXCEPTION;
4693 cpu->Reg[i] = ret;
4694 addr += 4;
4695 if ((addr & 0xfff) == 0) {
4696 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4697 } else {
4698 phys_addr += 4;
4699 }
4700 }
4701 }
4702
4703 if (CurrentModeHasSPSR) {
4704 cpu->Cpsr = cpu->Spsr_copy;
4705 switch_mode(cpu, cpu->Cpsr & 0x1f);
4706 LOAD_NZCVT;
4707 }
4708 #if 0
4709 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4710 if (fault) {
4711 goto MMU_EXCEPTION;
4712 }
4713 #endif
4714 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4715 if (fault) {
4716 goto MMU_EXCEPTION;
4717 }
4718 cpu->Reg[15] = ret;
4719 #if 0
4720 addr += 4;
4721 phys_addr += 4;
4722 #endif
4723 }
4724 if (BIT(inst, 15)) {
4725 INC_PC(sizeof(ldst_inst));
4726 goto DISPATCH;
4727 }
4728 }
4729 cpu->Reg[15] += GET_INST_SIZE(cpu);
4730 INC_PC(sizeof(ldst_inst));
4731 FETCH_INST;
4732 GOTO_NEXT_INST;
4733 }
4734 SXTH_INST:
4735 {
4736 INC_ICOUNTER;
4737 sxth_inst *inst_cream = (sxth_inst *)inst_base->component;
4738 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4739 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate);
4740 if (BIT(operand2, 15)) {
4741 operand2 |= 0xffff0000;
4742 } else {
4743 operand2 &= 0xffff;
4744 }
4745 RD = operand2;
4746 }
4747 cpu->Reg[15] += GET_INST_SIZE(cpu);
4748 INC_PC(sizeof(sxth_inst));
4749 FETCH_INST;
4750 GOTO_NEXT_INST;
4751 }
4752 LDR_INST:
4753 {
4754 INC_ICOUNTER;
4755 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4756 //if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4757 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4758 if (fault) goto MMU_EXCEPTION;
4759 unsigned int value;
4760 //bus_read(32, addr, &value);
4761 fault = interpreter_read_memory(addr, phys_addr, value, 32);
4762 if (BIT(CP15_REG(CP15_CONTROL), 22) == 1)
4763 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4764 else {
4765 value = ROTATE_RIGHT_32(value,(8*(addr&0x3)));
4766 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4767 }
4768 if (BITS(inst_cream->inst, 12, 15) == 15) {
4769 /* For armv5t, should enter thumb when bits[0] is non-zero. */
4770 cpu->TFlag = value & 0x1;
4771 cpu->Reg[15] &= 0xFFFFFFFE;
4772 INC_PC(sizeof(ldst_inst));
4773 goto DISPATCH;
4774 }
4775 //}
4776 cpu->Reg[15] += GET_INST_SIZE(cpu);
4777 INC_PC(sizeof(ldst_inst));
4778 FETCH_INST;
4779 GOTO_NEXT_INST;
4780 }
4781 LDRCOND_INST:
4782 {
4783 INC_ICOUNTER;
4784 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4785 if (CondPassed(cpu, inst_base->cond)) {
4786 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4787 if (fault) goto MMU_EXCEPTION;
4788 unsigned int value;
4789 //bus_read(32, addr, &value);
4790 fault = interpreter_read_memory(addr, phys_addr, value, 32);
4791 if (BIT(CP15_REG(CP15_CONTROL), 22) == 1)
4792 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4793 else {
4794 value = ROTATE_RIGHT_32(value,(8*(addr&0x3)));
4795 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4796 } 4336 }
4797 4337
4798 if (BITS(inst_cream->inst, 12, 15) == 15) { 4338 cpu->Reg[i] = ret;
4799 /* For armv5t, should enter thumb when bits[0] is non-zero. */ 4339 addr += 4;
4800 cpu->TFlag = value & 0x1; 4340 if ((addr & 0xfff) == 0) {
4801 cpu->Reg[15] &= 0xFFFFFFFE; 4341 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4802 INC_PC(sizeof(ldst_inst)); 4342 } else {
4803 goto DISPATCH; 4343 phys_addr += 4;
4804 } 4344 }
4805 } 4345 }
4806 cpu->Reg[15] += GET_INST_SIZE(cpu); 4346 }
4807 INC_PC(sizeof(ldst_inst)); 4347 } else if (BIT(inst, 22) && BIT(inst, 15)) {
4808 FETCH_INST; 4348 for( i = 0; i < 15; i ++ ){
4809 GOTO_NEXT_INST; 4349 if(BIT(inst, i)){
4810 } 4350 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4811 UXTH_INST: 4351 cpu->Reg[i] = ret;
4812 { 4352 addr += 4;
4813 INC_ICOUNTER; 4353 if ((addr & 0xfff) == 0) {
4814 uxth_inst *inst_cream = (uxth_inst *)inst_base->component; 4354 fault = check_address_validity(cpu, addr, &phys_addr, 1);
4815 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4355 } else {
4816 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) 4356 phys_addr += 4;
4817 & 0xffff; 4357 }
4818 RD = operand2; 4358 }
4819 } 4359 }
4820 cpu->Reg[15] += GET_INST_SIZE(cpu); 4360
4821 INC_PC(sizeof(uxth_inst)); 4361 if (CurrentModeHasSPSR) {
4822 FETCH_INST; 4362 cpu->Cpsr = cpu->Spsr_copy;
4823 GOTO_NEXT_INST; 4363 switch_mode(cpu, cpu->Cpsr & 0x1f);
4824 } 4364 LOAD_NZCVT;
4825 UXTAH_INST: 4365 }
4826 { 4366
4827 INC_ICOUNTER; 4367 fault = interpreter_read_memory(addr, phys_addr, ret, 32);
4828 uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component; 4368 if (fault) {
4829 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4369 goto MMU_EXCEPTION;
4830 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) 4370 }
4831 & 0xffff; 4371 cpu->Reg[15] = ret;
4832 RD = RN + operand2; 4372 }
4833 if (inst_cream->Rn == 15 || inst_cream->Rm == 15) { 4373 if (BIT(inst, 15)) {
4834 DEBUG_LOG(ARM11, "in line %d\n", __LINE__); 4374 INC_PC(sizeof(ldst_inst));
4835 CITRA_IGNORE_EXIT(-1); 4375 goto DISPATCH;
4836 } 4376 }
4837 } 4377 }
4838 cpu->Reg[15] += GET_INST_SIZE(cpu); 4378 cpu->Reg[15] += GET_INST_SIZE(cpu);
4839 INC_PC(sizeof(uxtah_inst)); 4379 INC_PC(sizeof(ldst_inst));
4840 FETCH_INST; 4380 FETCH_INST;
4841 GOTO_NEXT_INST; 4381 GOTO_NEXT_INST;
4842 } 4382 }
4843 LDRB_INST: 4383 SXTH_INST:
4844 { 4384 {
4845 INC_ICOUNTER; 4385 sxth_inst *inst_cream = (sxth_inst *)inst_base->component;
4846 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 4386 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4847 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4387 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate);
4848 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); 4388 if (BIT(operand2, 15)) {
4849 if (fault) goto MMU_EXCEPTION; 4389 operand2 |= 0xffff0000;
4850 unsigned int value; 4390 } else {
4851 fault = interpreter_read_memory(addr, phys_addr, value, 8); 4391 operand2 &= 0xffff;
4852 if (fault) goto MMU_EXCEPTION; 4392 }
4853 //bus_read(8, addr, &value); 4393 RD = operand2;
4854 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; 4394 }
4855 if (BITS(inst_cream->inst, 12, 15) == 15) { 4395 cpu->Reg[15] += GET_INST_SIZE(cpu);
4856 INC_PC(sizeof(ldst_inst)); 4396 INC_PC(sizeof(sxth_inst));
4857 goto DISPATCH; 4397 FETCH_INST;
4858 } 4398 GOTO_NEXT_INST;
4859 } 4399 }
4860 cpu->Reg[15] += GET_INST_SIZE(cpu); 4400 LDR_INST:
4861 INC_PC(sizeof(ldst_inst)); 4401 {
4862 FETCH_INST; 4402 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4863 GOTO_NEXT_INST; 4403 //if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4864 } 4404 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4865 LDRBT_INST: 4405 if (fault) goto MMU_EXCEPTION;
4866 { 4406 unsigned int value;
4867 INC_ICOUNTER; 4407 fault = interpreter_read_memory(addr, phys_addr, value, 32);
4868 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 4408 if (BIT(CP15_REG(CP15_CONTROL), 22) == 1)
4869 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4409 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4870 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); 4410 else {
4871 if (fault) goto MMU_EXCEPTION; 4411 value = ROTATE_RIGHT_32(value,(8*(addr&0x3)));
4872 unsigned int value; 4412 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4873 fault = interpreter_read_memory(addr, phys_addr, value, 8); 4413 }
4874 if (fault) goto MMU_EXCEPTION; 4414 if (BITS(inst_cream->inst, 12, 15) == 15) {
4875 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; 4415 // For armv5t, should enter thumb when bits[0] is non-zero.
4876 if (BITS(inst_cream->inst, 12, 15) == 15) { 4416 cpu->TFlag = value & 0x1;
4877 INC_PC(sizeof(ldst_inst)); 4417 cpu->Reg[15] &= 0xFFFFFFFE;
4878 goto DISPATCH; 4418 INC_PC(sizeof(ldst_inst));
4879 } 4419 goto DISPATCH;
4880 } 4420 }
4881 cpu->Reg[15] += GET_INST_SIZE(cpu); 4421 //}
4882 INC_PC(sizeof(ldst_inst)); 4422 cpu->Reg[15] += GET_INST_SIZE(cpu);
4883 FETCH_INST; 4423 INC_PC(sizeof(ldst_inst));
4884 GOTO_NEXT_INST; 4424 FETCH_INST;
4885 } 4425 GOTO_NEXT_INST;
4886 LDRD_INST: 4426 }
4887 { 4427 LDRCOND_INST:
4888 INC_ICOUNTER; 4428 {
4889 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 4429 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4890 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4430 if (CondPassed(cpu, inst_base->cond)) {
4891 /* Should check if RD is even-numbered, Rd != 14, addr[0:1] == 0, (CP15_reg1_U == 1 || addr[2] == 0) */ 4431 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4892 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); 4432 if (fault) goto MMU_EXCEPTION;
4893 if (fault) goto MMU_EXCEPTION; 4433 unsigned int value;
4894 uint32_t rear_phys_addr; 4434 fault = interpreter_read_memory(addr, phys_addr, value, 32);
4895 fault = check_address_validity(cpu, addr + 4, &rear_phys_addr, 1); 4435 if (BIT(CP15_REG(CP15_CONTROL), 22) == 1)
4896 if(fault){ 4436 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4897 ERROR_LOG(ARM11, "mmu fault , should rollback the above get_addr\n"); 4437 else {
4898 CITRA_IGNORE_EXIT(-1); 4438 value = ROTATE_RIGHT_32(value,(8*(addr&0x3)));
4899 goto MMU_EXCEPTION; 4439 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4900 } 4440 }
4901 unsigned int value; 4441
4902 fault = interpreter_read_memory(addr, phys_addr, value, 32); 4442 if (BITS(inst_cream->inst, 12, 15) == 15) {
4903 if (fault) goto MMU_EXCEPTION; 4443 // For armv5t, should enter thumb when bits[0] is non-zero.
4904 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; 4444 cpu->TFlag = value & 0x1;
4905 fault = interpreter_read_memory(addr + 4, rear_phys_addr, value, 32); 4445 cpu->Reg[15] &= 0xFFFFFFFE;
4906 if (fault) goto MMU_EXCEPTION; 4446 INC_PC(sizeof(ldst_inst));
4907 cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1] = value; 4447 goto DISPATCH;
4908 /* No dispatch since this operation should not modify R15 */ 4448 }
4909 } 4449 }
4910 cpu->Reg[15] += 4; 4450 cpu->Reg[15] += GET_INST_SIZE(cpu);
4911 INC_PC(sizeof(ldst_inst)); 4451 INC_PC(sizeof(ldst_inst));
4912 FETCH_INST; 4452 FETCH_INST;
4913 GOTO_NEXT_INST; 4453 GOTO_NEXT_INST;
4914 } 4454 }
4915 4455 UXTH_INST:
4916 LDREX_INST: 4456 {
4917 { 4457 uxth_inst *inst_cream = (uxth_inst *)inst_base->component;
4918 INC_ICOUNTER; 4458 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4919 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 4459 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate)
4920 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4460 & 0xffff;
4921 addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)]; 4461 RD = operand2;
4922 fault = check_address_validity(cpu, addr, &phys_addr, 1); 4462 }
4923 if (fault) goto MMU_EXCEPTION; 4463 cpu->Reg[15] += GET_INST_SIZE(cpu);
4924 unsigned int value; 4464 INC_PC(sizeof(uxth_inst));
4925 fault = interpreter_read_memory(addr, phys_addr, value, 32); 4465 FETCH_INST;
4926 if (fault) goto MMU_EXCEPTION; 4466 GOTO_NEXT_INST;
4927 4467 }
4928 add_exclusive_addr(cpu, phys_addr); 4468 UXTAH_INST:
4929 cpu->exclusive_state = 1; 4469 {
4930 4470 uxtah_inst *inst_cream = (uxtah_inst *)inst_base->component;
4931 //bus_read(32, addr, &value); 4471 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4932 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; 4472 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate)
4933 if (BITS(inst_cream->inst, 12, 15) == 15) { 4473 & 0xffff;
4934 INC_PC(sizeof(ldst_inst)); 4474 RD = RN + operand2;
4935 goto DISPATCH; 4475 if (inst_cream->Rn == 15 || inst_cream->Rm == 15) {
4936 } 4476 LOG_ERROR(Core_ARM11, "invalid operands for UXTAH");
4937 } 4477 CITRA_IGNORE_EXIT(-1);
4938 cpu->Reg[15] += GET_INST_SIZE(cpu); 4478 }
4939 INC_PC(sizeof(ldst_inst)); 4479 }
4940 FETCH_INST; 4480 cpu->Reg[15] += GET_INST_SIZE(cpu);
4941 GOTO_NEXT_INST; 4481 INC_PC(sizeof(uxtah_inst));
4942 } 4482 FETCH_INST;
4943 LDREXB_INST: 4483 GOTO_NEXT_INST;
4944 { 4484 }
4945 INC_ICOUNTER; 4485 LDRB_INST:
4946 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 4486 {
4947 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4487 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4948 addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)]; 4488 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4949 fault = check_address_validity(cpu, addr, &phys_addr, 1); 4489 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4950 if (fault) goto MMU_EXCEPTION; 4490 if (fault) goto MMU_EXCEPTION;
4951 unsigned int value; 4491 unsigned int value;
4952 fault = interpreter_read_memory(addr, phys_addr, value, 8); 4492 fault = interpreter_read_memory(addr, phys_addr, value, 8);
4953 if (fault) goto MMU_EXCEPTION; 4493 if (fault) goto MMU_EXCEPTION;
4954 4494 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4955 add_exclusive_addr(cpu, phys_addr); 4495 if (BITS(inst_cream->inst, 12, 15) == 15) {
4956 cpu->exclusive_state = 1; 4496 INC_PC(sizeof(ldst_inst));
4957 4497 goto DISPATCH;
4958 //bus_read(8, addr, &value); 4498 }
4959 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; 4499 }
4960 if (BITS(inst_cream->inst, 12, 15) == 15) { 4500 cpu->Reg[15] += GET_INST_SIZE(cpu);
4961 INC_PC(sizeof(ldst_inst)); 4501 INC_PC(sizeof(ldst_inst));
4962 goto DISPATCH; 4502 FETCH_INST;
4963 } 4503 GOTO_NEXT_INST;
4964 } 4504 }
4965 cpu->Reg[15] += GET_INST_SIZE(cpu); 4505 LDRBT_INST:
4966 INC_PC(sizeof(ldst_inst)); 4506 {
4967 FETCH_INST; 4507 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4968 GOTO_NEXT_INST; 4508 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4969 } 4509 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4970 LDRH_INST: 4510 if (fault) goto MMU_EXCEPTION;
4971 { 4511 unsigned int value;
4972 INC_ICOUNTER; 4512 fault = interpreter_read_memory(addr, phys_addr, value, 8);
4973 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 4513 if (fault) goto MMU_EXCEPTION;
4974 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4514 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
4975 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); 4515 if (BITS(inst_cream->inst, 12, 15) == 15) {
4976 if (fault) goto MMU_EXCEPTION; 4516 INC_PC(sizeof(ldst_inst));
4977 unsigned int value = 0; 4517 goto DISPATCH;
4978 fault = interpreter_read_memory(addr, phys_addr, value, 16); 4518 }
4979// fault = interpreter_read_memory(addr, value, 32); 4519 }
4980 if (fault) goto MMU_EXCEPTION; 4520 cpu->Reg[15] += GET_INST_SIZE(cpu);
4981 //if (value == 0xffff && cpu->icounter > 190000000 && cpu->icounter < 210000000) { 4521 INC_PC(sizeof(ldst_inst));
4982 // value = 0xffffffff; 4522 FETCH_INST;
4983 //} 4523 GOTO_NEXT_INST;
4984 //bus_read(16, addr, &value); 4524 }
4985// cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value & 0xffff; 4525 LDRD_INST:
4986 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; 4526 {
4987 if (BITS(inst_cream->inst, 12, 15) == 15) { 4527 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
4988 INC_PC(sizeof(ldst_inst)); 4528 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4989 goto DISPATCH; 4529 // Should check if RD is even-numbered, Rd != 14, addr[0:1] == 0, (CP15_reg1_U == 1 || addr[2] == 0)
4990 } 4530 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
4991 } 4531 if (fault) goto MMU_EXCEPTION;
4992 cpu->Reg[15] += GET_INST_SIZE(cpu); 4532 uint32_t rear_phys_addr;
4993 INC_PC(sizeof(ldst_inst)); 4533 fault = check_address_validity(cpu, addr + 4, &rear_phys_addr, 1);
4994 FETCH_INST; 4534 if(fault){
4995 GOTO_NEXT_INST; 4535 LOG_ERROR(Core_ARM11, "MMU fault , should rollback the above get_addr\n");
4996 } 4536 CITRA_IGNORE_EXIT(-1);
4997 LDRSB_INST: 4537 goto MMU_EXCEPTION;
4998 { 4538 }
4999 INC_ICOUNTER; 4539 unsigned int value;
5000 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 4540 fault = interpreter_read_memory(addr, phys_addr, value, 32);
5001 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4541 if (fault) goto MMU_EXCEPTION;
5002 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); 4542 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
5003 if (fault) goto MMU_EXCEPTION; 4543 fault = interpreter_read_memory(addr + 4, rear_phys_addr, value, 32);
5004 unsigned int value; 4544 if (fault) goto MMU_EXCEPTION;
5005// DEBUG_LOG(ARM11, "ldrsb addr is %x\n", addr); 4545 cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1] = value;
5006 fault = interpreter_read_memory(addr, phys_addr, value, 8); 4546
5007 if (fault) goto MMU_EXCEPTION; 4547 // No dispatch since this operation should not modify R15
5008 //bus_read(8, addr, &value); 4548 }
5009 if (BIT(value, 7)) { 4549 cpu->Reg[15] += 4;
5010 value |= 0xffffff00; 4550 INC_PC(sizeof(ldst_inst));
5011 } 4551 FETCH_INST;
5012 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; 4552 GOTO_NEXT_INST;
5013 if (BITS(inst_cream->inst, 12, 15) == 15) { 4553 }
5014 INC_PC(sizeof(ldst_inst)); 4554
5015 goto DISPATCH; 4555 LDREX_INST:
5016 } 4556 {
5017 } 4557 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
5018 cpu->Reg[15] += GET_INST_SIZE(cpu); 4558 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5019 INC_PC(sizeof(ldst_inst)); 4559 addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)];
5020 FETCH_INST; 4560 fault = check_address_validity(cpu, addr, &phys_addr, 1);
5021 GOTO_NEXT_INST; 4561 if (fault) goto MMU_EXCEPTION;
5022 } 4562 unsigned int value;
5023 LDRSH_INST: 4563 fault = interpreter_read_memory(addr, phys_addr, value, 32);
5024 { 4564 if (fault) goto MMU_EXCEPTION;
5025 INC_ICOUNTER; 4565
5026 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 4566 add_exclusive_addr(cpu, phys_addr);
5027 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4567 cpu->exclusive_state = 1;
5028 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); 4568
5029 if (fault) goto MMU_EXCEPTION; 4569 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
5030 unsigned int value; 4570 if (BITS(inst_cream->inst, 12, 15) == 15) {
5031 fault = interpreter_read_memory(addr, phys_addr, value, 16); 4571 INC_PC(sizeof(ldst_inst));
5032 if (fault) goto MMU_EXCEPTION; 4572 goto DISPATCH;
5033 //bus_read(16, addr, &value); 4573 }
5034 if (BIT(value, 15)) { 4574 }
5035 value |= 0xffff0000; 4575 cpu->Reg[15] += GET_INST_SIZE(cpu);
5036 } 4576 INC_PC(sizeof(ldst_inst));
5037 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; 4577 FETCH_INST;
5038 if (BITS(inst_cream->inst, 12, 15) == 15) { 4578 GOTO_NEXT_INST;
5039 INC_PC(sizeof(ldst_inst)); 4579 }
5040 goto DISPATCH; 4580 LDREXB_INST:
5041 } 4581 {
5042 } 4582 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
5043 cpu->Reg[15] += GET_INST_SIZE(cpu); 4583 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5044 INC_PC(sizeof(ldst_inst)); 4584 addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)];
5045 FETCH_INST; 4585 fault = check_address_validity(cpu, addr, &phys_addr, 1);
5046 GOTO_NEXT_INST; 4586 if (fault) goto MMU_EXCEPTION;
5047 } 4587 unsigned int value;
5048 LDRT_INST: 4588 fault = interpreter_read_memory(addr, phys_addr, value, 8);
5049 { 4589 if (fault) goto MMU_EXCEPTION;
5050 INC_ICOUNTER; 4590
5051 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 4591 add_exclusive_addr(cpu, phys_addr);
5052 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4592 cpu->exclusive_state = 1;
5053 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1); 4593
5054 if (fault) goto MMU_EXCEPTION; 4594 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
5055 unsigned int value; 4595 if (BITS(inst_cream->inst, 12, 15) == 15) {
5056 fault = interpreter_read_memory(addr, phys_addr, value, 32); 4596 INC_PC(sizeof(ldst_inst));
5057 if (fault) goto MMU_EXCEPTION; 4597 goto DISPATCH;
5058 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; 4598 }
5059 4599 }
5060 if (BIT(CP15_REG(CP15_CONTROL), 22) == 1) 4600 cpu->Reg[15] += GET_INST_SIZE(cpu);
5061 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value; 4601 INC_PC(sizeof(ldst_inst));
5062 else 4602 FETCH_INST;
5063 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = ROTATE_RIGHT_32(value,(8*(addr&0x3))) ; 4603 GOTO_NEXT_INST;
5064 4604 }
5065 if (BITS(inst_cream->inst, 12, 15) == 15) { 4605 LDRH_INST:
5066 INC_PC(sizeof(ldst_inst)); 4606 {
5067 goto DISPATCH; 4607 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
5068 } 4608 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5069 } 4609 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
5070 cpu->Reg[15] += GET_INST_SIZE(cpu); 4610 if (fault) goto MMU_EXCEPTION;
5071 INC_PC(sizeof(ldst_inst)); 4611 unsigned int value = 0;
5072 FETCH_INST; 4612 fault = interpreter_read_memory(addr, phys_addr, value, 16);
5073 GOTO_NEXT_INST; 4613 if (fault) goto MMU_EXCEPTION;
5074 } 4614 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
5075 MCR_INST: 4615 if (BITS(inst_cream->inst, 12, 15) == 15) {
5076 { 4616 INC_PC(sizeof(ldst_inst));
5077 INC_ICOUNTER; 4617 goto DISPATCH;
5078 /* NOT IMPL */ 4618 }
5079 mcr_inst *inst_cream = (mcr_inst *)inst_base->component; 4619 }
5080 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4620 cpu->Reg[15] += GET_INST_SIZE(cpu);
5081 unsigned int inst = inst_cream->inst; 4621 INC_PC(sizeof(ldst_inst));
5082 if (inst_cream->Rd == 15) { 4622 FETCH_INST;
5083 DEBUG_MSG; 4623 GOTO_NEXT_INST;
5084 } else { 4624 }
5085 if (inst_cream->cp_num == 15) { 4625 LDRSB_INST:
5086 if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) { 4626 {
5087 //LET(RD, CONST(0x0007b000)); 4627 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
5088 //LET(RD, CONST(0x410FB760)); 4628 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5089 //LET(CP15_MAIN_ID, R(RD)); 4629 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
5090 CP15_REG(CP15_MAIN_ID) = RD; 4630 if (fault) goto MMU_EXCEPTION;
5091 } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) { 4631 unsigned int value;
5092 //LET(RD, R(CP15_CONTROL)); 4632 fault = interpreter_read_memory(addr, phys_addr, value, 8);
5093 CP15_REG(CP15_AUXILIARY_CONTROL) = RD; 4633 if (fault) goto MMU_EXCEPTION;
5094 } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) { 4634 if (BIT(value, 7)) {
5095 //LET(RD, R(CP15_CONTROL)); 4635 value |= 0xffffff00;
5096 CP15_REG(CP15_COPROCESSOR_ACCESS_CONTROL) = RD; 4636 }
5097 } else if(CRn == 1 && CRm == 0 && OPCODE_2 == 0) { 4637 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
5098 //LET(CP15_CONTROL, R(RD)); 4638 if (BITS(inst_cream->inst, 12, 15) == 15) {
5099 CP15_REG(CP15_CONTROL) = RD; 4639 INC_PC(sizeof(ldst_inst));
5100 } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) { 4640 goto DISPATCH;
5101 //LET(CP15_DOMAIN_ACCESS_CONTROL, R(RD)); 4641 }
5102 CP15_REG(CP15_DOMAIN_ACCESS_CONTROL) = RD; 4642 }
5103 } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) { 4643 cpu->Reg[15] += GET_INST_SIZE(cpu);
5104 //LET(CP15_TRANSLATION_BASE_TABLE_0, R(RD)); 4644 INC_PC(sizeof(ldst_inst));
5105 CP15_REG(CP15_TRANSLATION_BASE_TABLE_0) = RD; 4645 FETCH_INST;
5106 } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 1) { 4646 GOTO_NEXT_INST;
5107 //LET(CP15_TRANSLATION_BASE_TABLE_1, R(RD)); 4647 }
5108 CP15_REG(CP15_TRANSLATION_BASE_TABLE_1) = RD; 4648 LDRSH_INST:
5109 } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 2) { 4649 {
5110 //LET(CP15_TRANSLATION_BASE_CONTROL, R(RD)); 4650 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
5111 CP15_REG(CP15_TRANSLATION_BASE_CONTROL) = RD; 4651 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5112 } else if(CRn == MMU_CACHE_OPS){ 4652 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
5113 //SKYEYE_WARNING("cache operation have not implemented.\n"); 4653 if (fault) goto MMU_EXCEPTION;
5114 } else if(CRn == MMU_TLB_OPS){ 4654 unsigned int value;
5115 switch (CRm) { 4655 fault = interpreter_read_memory(addr, phys_addr, value, 16);
5116 case 5: /* ITLB */ 4656 if (fault) goto MMU_EXCEPTION;
5117 switch(OPCODE_2){ 4657 if (BIT(value, 15)) {
5118 case 0: /* invalidate all */ 4658 value |= 0xffff0000;
5119 //invalidate_all_tlb(state); 4659 }
5120 DEBUG_LOG(ARM11, "{TLB} [INSN] invalidate all\n"); 4660 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
5121 //remove_tlb(INSN_TLB); 4661 if (BITS(inst_cream->inst, 12, 15) == 15) {
5122 //erase_all(core, INSN_TLB); 4662 INC_PC(sizeof(ldst_inst));
5123 break; 4663 goto DISPATCH;
5124 case 1: /* invalidate by MVA */ 4664 }
5125 //invalidate_by_mva(state, value); 4665 }
5126 //DEBUG_LOG(ARM11, "{TLB} [INSN] invalidate by mva\n"); 4666 cpu->Reg[15] += GET_INST_SIZE(cpu);
5127 //remove_tlb_by_mva(RD, INSN_TLB); 4667 INC_PC(sizeof(ldst_inst));
5128 //erase_by_mva(core, RD, INSN_TLB); 4668 FETCH_INST;
5129 break; 4669 GOTO_NEXT_INST;
5130 case 2: /* invalidate by asid */ 4670 }
5131 //invalidate_by_asid(state, value); 4671 LDRT_INST:
5132 //DEBUG_LOG(ARM11, "{TLB} [INSN] invalidate by asid\n"); 4672 {
5133 //erase_by_asid(core, RD, INSN_TLB); 4673 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
5134 break; 4674 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5135 default: 4675 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 1);
5136 break; 4676 if (fault) goto MMU_EXCEPTION;
5137 } 4677 unsigned int value;
5138 4678 fault = interpreter_read_memory(addr, phys_addr, value, 32);
5139 break; 4679 if (fault) goto MMU_EXCEPTION;
5140 case 6: /* DTLB */ 4680 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
5141 switch(OPCODE_2){ 4681
5142 case 0: /* invalidate all */ 4682 if (BIT(CP15_REG(CP15_CONTROL), 22) == 1)
5143 //invalidate_all_tlb(state); 4683 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = value;
5144 //remove_tlb(DATA_TLB); 4684 else
5145 //erase_all(core, DATA_TLB); 4685 cpu->Reg[BITS(inst_cream->inst, 12, 15)] = ROTATE_RIGHT_32(value,(8*(addr&0x3))) ;
5146 DEBUG_LOG(ARM11, "{TLB} [DATA] invalidate all\n"); 4686
5147 break; 4687 if (BITS(inst_cream->inst, 12, 15) == 15) {
5148 case 1: /* invalidate by MVA */ 4688 INC_PC(sizeof(ldst_inst));
5149 //invalidate_by_mva(state, value); 4689 goto DISPATCH;
5150 //remove_tlb_by_mva(RD, DATA_TLB); 4690 }
5151 //erase_by_mva(core, RD, DATA_TLB); 4691 }
5152 //DEBUG_LOG(ARM11, "{TLB} [DATA] invalidate by mva\n"); 4692 cpu->Reg[15] += GET_INST_SIZE(cpu);
5153 break; 4693 INC_PC(sizeof(ldst_inst));
5154 case 2: /* invalidate by asid */ 4694 FETCH_INST;
5155 //invalidate_by_asid(state, value); 4695 GOTO_NEXT_INST;
5156 //remove_tlb_by_asid(RD, DATA_TLB); 4696 }
5157 //erase_by_asid(core, RD, DATA_TLB); 4697 MCR_INST:
5158 //DEBUG_LOG(ARM11, "{TLB} [DATA] invalidate by asid\n"); 4698 {
5159 break; 4699 mcr_inst *inst_cream = (mcr_inst *)inst_base->component;
5160 default: 4700 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5161 break; 4701 unsigned int inst = inst_cream->inst;
5162 } 4702 if (inst_cream->Rd == 15) {
5163 break; 4703 DEBUG_MSG;
5164 case 7: /* UNIFILED TLB */ 4704 } else {
5165 switch(OPCODE_2){ 4705 if (inst_cream->cp_num == 15) {
5166 case 0: /* invalidate all */ 4706 if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) {
5167 //invalidate_all_tlb(state); 4707 CP15_REG(CP15_MAIN_ID) = RD;
5168 //erase_all(core, INSN_TLB); 4708 } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) {
5169 //erase_all(core, DATA_TLB); 4709 CP15_REG(CP15_AUXILIARY_CONTROL) = RD;
5170 //remove_tlb(DATA_TLB); 4710 } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) {
5171 //remove_tlb(INSN_TLB); 4711 CP15_REG(CP15_COPROCESSOR_ACCESS_CONTROL) = RD;
5172 //DEBUG_LOG(ARM11, "{TLB} [UNIFILED] invalidate all\n"); 4712 } else if(CRn == 1 && CRm == 0 && OPCODE_2 == 0) {
5173 break; 4713 CP15_REG(CP15_CONTROL) = RD;
5174 case 1: /* invalidate by MVA */ 4714 } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) {
5175 //invalidate_by_mva(state, value); 4715 CP15_REG(CP15_DOMAIN_ACCESS_CONTROL) = RD;
5176 //erase_by_mva(core, RD, DATA_TLB); 4716 } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) {
5177 //erase_by_mva(core, RD, INSN_TLB); 4717 CP15_REG(CP15_TRANSLATION_BASE_TABLE_0) = RD;
5178 DEBUG_LOG(ARM11, "{TLB} [UNIFILED] invalidate by mva\n"); 4718 } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 1) {
5179 break; 4719 CP15_REG(CP15_TRANSLATION_BASE_TABLE_1) = RD;
5180 case 2: /* invalidate by asid */ 4720 } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 2) {
5181 //invalidate_by_asid(state, value); 4721 CP15_REG(CP15_TRANSLATION_BASE_CONTROL) = RD;
5182 //erase_by_asid(core, RD, DATA_TLB); 4722 } else if(CRn == MMU_CACHE_OPS){
5183 //erase_by_asid(core, RD, INSN_TLB); 4723 //LOG_WARNING(Core_ARM11, "cache operations have not implemented.");
5184 DEBUG_LOG(ARM11, "{TLB} [UNIFILED] invalidate by asid\n"); 4724 } else if(CRn == MMU_TLB_OPS){
5185 break; 4725 switch (CRm) {
5186 default: 4726 case 5: // ITLB
5187 break; 4727 switch(OPCODE_2) {
5188 } 4728 case 0: // Invalidate all
5189 break; 4729 LOG_DEBUG(Core_ARM11, "{TLB} [INSN] invalidate all");
5190 default: 4730 break;
5191 break; 4731 case 1: // Invalidate by MVA
5192 } 4732 LOG_DEBUG(Core_ARM11, "{TLB} [INSN] invalidate by mva");
5193 } else if(CRn == MMU_PID){ 4733 break;
5194 if(OPCODE_2 == 0) 4734 case 2: // Invalidate by asid
5195 CP15_REG(CP15_PID) = RD; 4735 LOG_DEBUG(Core_ARM11, "{TLB} [INSN] invalidate by asid");
5196 else if(OPCODE_2 == 1) 4736 break;
5197 CP15_REG(CP15_CONTEXT_ID) = RD; 4737 default:
5198 else if(OPCODE_2 == 3){ 4738 break;
5199 CP15_REG(CP15_THREAD_URO) = RD; 4739 }
5200 } 4740
5201 else{ 4741 break;
5202 printf ("mmu_mcr wrote UNKNOWN - reg %d\n", CRn); 4742 case 6: // DTLB
5203 } 4743 switch(OPCODE_2){
5204 4744 case 0: // Invalidate all
5205 } else { 4745 LOG_DEBUG(Core_ARM11, "{TLB} [DATA] invalidate all");
5206 DEBUG_LOG(ARM11, "mcr is not implementated. CRn is %d, CRm is %d, OPCODE_2 is %d\n", CRn, CRm, OPCODE_2); 4746 break;
5207 } 4747 case 1: // Invalidate by MVA
5208 } 4748 LOG_DEBUG(Core_ARM11, "{TLB} [DATA] invalidate by mva");
5209 } 4749 break;
5210 } 4750 case 2: // Invalidate by asid
5211 cpu->Reg[15] += GET_INST_SIZE(cpu); 4751 LOG_DEBUG(Core_ARM11, "{TLB} [DATA] invalidate by asid");
5212 INC_PC(sizeof(mcr_inst)); 4752 break;
5213 FETCH_INST; 4753 default:
5214 GOTO_NEXT_INST; 4754 break;
5215 } 4755 }
5216 MCRR_INST: 4756 break;
5217 MLA_INST: 4757 case 7: // UNIFILED TLB
5218 { 4758 switch(OPCODE_2){
5219 INC_ICOUNTER; 4759 case 0: // invalidate all
5220 mla_inst *inst_cream = (mla_inst *)inst_base->component; 4760 LOG_DEBUG(Core_ARM11, "{TLB} [UNIFILED] invalidate all");
5221 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4761 break;
5222 uint64_t rm = RM; 4762 case 1: // Invalidate by MVA
5223 uint64_t rs = RS; 4763 LOG_DEBUG(Core_ARM11, "{TLB} [UNIFILED] invalidate by mva");
5224 uint64_t rn = RN; 4764 break;
5225 if (inst_cream->Rm == 15 || inst_cream->Rs == 15 || inst_cream->Rn == 15) { 4765 case 2: // Invalidate by asid
5226 DEBUG_LOG(ARM11, "in __line__\n", __LINE__); 4766 LOG_DEBUG(Core_ARM11, "{TLB} [UNIFILED] invalidate by asid");
5227 CITRA_IGNORE_EXIT(-1); 4767 break;
5228 } 4768 default:
5229// RD = dst = RM * RS + RN; 4769 break;
5230 RD = dst = static_cast<uint32_t>((rm * rs + rn) & 0xffffffff); 4770 }
5231 if (inst_cream->S) { 4771 break;
5232 UPDATE_NFLAG(dst); 4772 default:
5233 UPDATE_ZFLAG(dst); 4773 break;
5234 } 4774 }
5235 if (inst_cream->Rd == 15) { 4775 } else if(CRn == MMU_PID) {
5236 INC_PC(sizeof(mla_inst)); 4776 if(OPCODE_2 == 0)
5237 goto DISPATCH; 4777 CP15_REG(CP15_PID) = RD;
5238 } 4778 else if(OPCODE_2 == 1)
5239 } 4779 CP15_REG(CP15_CONTEXT_ID) = RD;
5240 cpu->Reg[15] += GET_INST_SIZE(cpu); 4780 else if(OPCODE_2 == 3) {
5241 INC_PC(sizeof(mla_inst)); 4781 CP15_REG(CP15_THREAD_URO) = RD;
5242 FETCH_INST; 4782 } else {
5243 GOTO_NEXT_INST; 4783 LOG_ERROR(Core_ARM11, "mmu_mcr wrote UNKNOWN - reg %d", CRn);
5244 } 4784 }
5245 MOV_INST: 4785 } else {
5246 { 4786 LOG_ERROR(Core_ARM11, "mcr CRn=%d, CRm=%d OP2=%d is not implemented", CRn, CRm, OPCODE_2);
5247// DEBUG_LOG(ARM11, "mov inst\n"); 4787 }
5248// DEBUG_LOG(ARM11, "pc: %x\n", cpu->Reg[15]); 4788 }
5249// debug_function(cpu); 4789 }
5250// cpu->icount ++; 4790 }
5251 INC_ICOUNTER; 4791 cpu->Reg[15] += GET_INST_SIZE(cpu);
5252 mov_inst *inst_cream = (mov_inst *)inst_base->component; 4792 INC_PC(sizeof(mcr_inst));
5253 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4793 FETCH_INST;
5254 RD = dst = SHIFTER_OPERAND; 4794 GOTO_NEXT_INST;
5255 if (inst_cream->S && (inst_cream->Rd == 15)) { 4795 }
5256 /* cpsr = spsr */ 4796 MCRR_INST:
5257 if (CurrentModeHasSPSR) { 4797 MLA_INST:
5258 cpu->Cpsr = cpu->Spsr_copy; 4798 {
5259 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 4799 mla_inst *inst_cream = (mla_inst *)inst_base->component;
5260 LOAD_NZCVT; 4800 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5261 } 4801 uint64_t rm = RM;
5262 } else if (inst_cream->S) { 4802 uint64_t rs = RS;
5263 UPDATE_NFLAG(dst); 4803 uint64_t rn = RN;
5264 UPDATE_ZFLAG(dst); 4804 if (inst_cream->Rm == 15 || inst_cream->Rs == 15 || inst_cream->Rn == 15) {
5265 UPDATE_CFLAG_WITH_SC; 4805 LOG_ERROR(Core_ARM11, "invalid operands for MLA");
5266 } 4806 CITRA_IGNORE_EXIT(-1);
5267 if (inst_cream->Rd == 15) { 4807 }
5268 INC_PC(sizeof(mov_inst)); 4808 RD = dst = static_cast<uint32_t>((rm * rs + rn) & 0xffffffff);
5269 goto DISPATCH; 4809 if (inst_cream->S) {
5270 } 4810 UPDATE_NFLAG(dst);
5271// return; 4811 UPDATE_ZFLAG(dst);
5272 } 4812 }
5273 cpu->Reg[15] += GET_INST_SIZE(cpu); 4813 if (inst_cream->Rd == 15) {
5274 INC_PC(sizeof(mov_inst)); 4814 INC_PC(sizeof(mla_inst));
5275 FETCH_INST; 4815 goto DISPATCH;
5276 GOTO_NEXT_INST; 4816 }
5277 } 4817 }
5278 MRC_INST: 4818 cpu->Reg[15] += GET_INST_SIZE(cpu);
5279 { 4819 INC_PC(sizeof(mla_inst));
5280 INC_ICOUNTER; 4820 FETCH_INST;
5281 /* NOT IMPL */ 4821 GOTO_NEXT_INST;
5282 mrc_inst *inst_cream = (mrc_inst *)inst_base->component; 4822 }
5283 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4823 MOV_INST:
5284 unsigned int inst = inst_cream->inst; 4824 {
5285 if (inst_cream->Rd == 15) { 4825 mov_inst *inst_cream = (mov_inst *)inst_base->component;
5286 DEBUG_MSG; 4826 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5287 } 4827 RD = dst = SHIFTER_OPERAND;
5288 if (inst_cream->inst == 0xeef04a10) { 4828 if (inst_cream->S && (inst_cream->Rd == 15)) {
5289 /* undefined instruction fmrx */ 4829 if (CurrentModeHasSPSR) {
5290 RD = 0x20000000; 4830 cpu->Cpsr = cpu->Spsr_copy;
5291 CITRA_IGNORE_EXIT(-1); 4831 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
5292 goto END; 4832 LOAD_NZCVT;
5293 } else { 4833 }
5294 if (inst_cream->cp_num == 15) { 4834 } else if (inst_cream->S) {
5295 if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) { 4835 UPDATE_NFLAG(dst);
5296 //LET(RD, CONST(0x0007b000)); 4836 UPDATE_ZFLAG(dst);
5297 //LET(RD, CONST(0x410FB760)); 4837 UPDATE_CFLAG_WITH_SC;
5298 //LET(RD, R(CP15_MAIN_ID)); 4838 }
5299 RD = cpu->CP15[CP15(CP15_MAIN_ID)]; 4839 if (inst_cream->Rd == 15) {
5300 } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 0) { 4840 INC_PC(sizeof(mov_inst));
5301 //LET(RD, R(CP15_CONTROL)); 4841 goto DISPATCH;
5302 RD = cpu->CP15[CP15(CP15_CONTROL)]; 4842 }
5303 } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) { 4843 }
5304 //LET(RD, R(CP15_CONTROL)); 4844 cpu->Reg[15] += GET_INST_SIZE(cpu);
5305 RD = cpu->CP15[CP15(CP15_AUXILIARY_CONTROL)]; 4845 INC_PC(sizeof(mov_inst));
5306 } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) { 4846 FETCH_INST;
5307 //LET(RD, R(CP15_CONTROL)); 4847 GOTO_NEXT_INST;
5308 RD = cpu->CP15[CP15(CP15_COPROCESSOR_ACCESS_CONTROL)]; 4848 }
5309 } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) { 4849 MRC_INST:
5310 //LET(RD, R(CP15_DOMAIN_ACCESS_CONTROL)); 4850 {
5311 RD = cpu->CP15[CP15(CP15_DOMAIN_ACCESS_CONTROL)]; 4851 mrc_inst *inst_cream = (mrc_inst *)inst_base->component;
5312 } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) { 4852 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5313 //LET(RD, R(CP15_TRANSLATION_BASE_TABLE_0)); 4853 unsigned int inst = inst_cream->inst;
5314 RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_0)]; 4854 if (inst_cream->Rd == 15) {
5315 } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 0) { 4855 DEBUG_MSG;
5316 //LET(RD, R(CP15_FAULT_STATUS)); 4856 }
5317 RD = cpu->CP15[CP15(CP15_FAULT_STATUS)]; 4857 if (inst_cream->inst == 0xeef04a10) {
5318 } else if (CRn == 6 && CRm == 0 && OPCODE_2 == 0) { 4858 // Undefined instruction fmrx
5319 //LET(RD, R(CP15_FAULT_ADDRESS)); 4859 RD = 0x20000000;
5320 RD = cpu->CP15[CP15(CP15_FAULT_ADDRESS)]; 4860 CITRA_IGNORE_EXIT(-1);
5321 } else if (CRn == 0 && CRm == 0 && OPCODE_2 == 1) { 4861 goto END;
5322 //LET(RD, R(CP15_CACHE_TYPE)); 4862 } else {
5323 RD = cpu->CP15[CP15(CP15_CACHE_TYPE)]; 4863 if (inst_cream->cp_num == 15) {
5324 } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 1) { 4864 if(CRn == 0 && OPCODE_2 == 0 && CRm == 0) {
5325 //LET(RD, R(CP15_INSTR_FAULT_STATUS)); 4865 RD = cpu->CP15[CP15(CP15_MAIN_ID)];
5326 RD = cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)]; 4866 } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 0) {
5327 } else if (CRn == 13) { 4867 RD = cpu->CP15[CP15(CP15_CONTROL)];
5328 if(OPCODE_2 == 0) 4868 } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 1) {
5329 RD = CP15_REG(CP15_PID); 4869 RD = cpu->CP15[CP15(CP15_AUXILIARY_CONTROL)];
5330 else if(OPCODE_2 == 1) 4870 } else if (CRn == 1 && CRm == 0 && OPCODE_2 == 2) {
5331 RD = CP15_REG(CP15_CONTEXT_ID); 4871 RD = cpu->CP15[CP15(CP15_COPROCESSOR_ACCESS_CONTROL)];
5332 else if(OPCODE_2 == 3){ 4872 } else if (CRn == 3 && CRm == 0 && OPCODE_2 == 0) {
5333 RD = Memory::KERNEL_MEMORY_VADDR; 4873 RD = cpu->CP15[CP15(CP15_DOMAIN_ACCESS_CONTROL)];
5334 } 4874 } else if (CRn == 2 && CRm == 0 && OPCODE_2 == 0) {
5335 else{ 4875 RD = cpu->CP15[CP15(CP15_TRANSLATION_BASE_TABLE_0)];
5336 printf ("mmu_mrr wrote UNKNOWN - reg %d\n", CRn); 4876 } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 0) {
5337 } 4877 RD = cpu->CP15[CP15(CP15_FAULT_STATUS)];
5338 } 4878 } else if (CRn == 6 && CRm == 0 && OPCODE_2 == 0) {
5339 else { 4879 RD = cpu->CP15[CP15(CP15_FAULT_ADDRESS)];
5340 DEBUG_LOG(ARM11, "mrc is not implementated. CRn is %d, CRm is %d, OPCODE_2 is %d\n", CRn, CRm, OPCODE_2); 4880 } else if (CRn == 0 && CRm == 0 && OPCODE_2 == 1) {
5341 } 4881 RD = cpu->CP15[CP15(CP15_CACHE_TYPE)];
5342 } 4882 } else if (CRn == 5 && CRm == 0 && OPCODE_2 == 1) {
5343 //DEBUG_LOG(ARM11, "mrc is not implementated. CRn is %d, CRm is %d, OPCODE_2 is %d\n", CRn, CRm, OPCODE_2); 4883 RD = cpu->CP15[CP15(CP15_INSTR_FAULT_STATUS)];
5344 } 4884 } else if (CRn == 13) {
5345 } 4885 if(OPCODE_2 == 0)
5346 cpu->Reg[15] += GET_INST_SIZE(cpu); 4886 RD = CP15_REG(CP15_PID);
5347 INC_PC(sizeof(mrc_inst)); 4887 else if(OPCODE_2 == 1)
5348 FETCH_INST; 4888 RD = CP15_REG(CP15_CONTEXT_ID);
5349 GOTO_NEXT_INST; 4889 else if(OPCODE_2 == 3) {
5350 } 4890 RD = Memory::KERNEL_MEMORY_VADDR;
5351 MRRC_INST: 4891 } else {
5352 MRS_INST: 4892 LOG_ERROR(Core_ARM11, "mmu_mrr wrote UNKNOWN - reg %d", CRn);
5353 { 4893 }
5354 INC_ICOUNTER; 4894 } else {
5355 mrs_inst *inst_cream = (mrs_inst *)inst_base->component; 4895 LOG_ERROR(Core_ARM11, "mrc CRn=%d, CRm=%d, OP2=%d is not implemented", CRn, CRm, OPCODE_2);
5356 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4896 }
5357 if (inst_cream->R) { 4897 }
5358 RD = cpu->Spsr_copy; 4898 }
5359 } else { 4899 }
5360 SAVE_NZCVT; 4900 cpu->Reg[15] += GET_INST_SIZE(cpu);
5361 RD = cpu->Cpsr; 4901 INC_PC(sizeof(mrc_inst));
5362 } 4902 FETCH_INST;
5363 } 4903 GOTO_NEXT_INST;
5364 cpu->Reg[15] += GET_INST_SIZE(cpu); 4904 }
5365 INC_PC(sizeof(mrs_inst)); 4905 MRRC_INST:
5366 FETCH_INST; 4906 MRS_INST:
5367 GOTO_NEXT_INST; 4907 {
5368 } 4908 mrs_inst *inst_cream = (mrs_inst *)inst_base->component;
5369 MSR_INST: 4909 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5370 { 4910 if (inst_cream->R) {
5371 INC_ICOUNTER; 4911 RD = cpu->Spsr_copy;
5372 msr_inst *inst_cream = (msr_inst *)inst_base->component; 4912 } else {
5373 const uint32_t UnallocMask = 0x06f0fc00, UserMask = 0xf80f0200, PrivMask = 0x000001df, StateMask = 0x01000020; 4913 SAVE_NZCVT;
5374 unsigned int inst = inst_cream->inst; 4914 RD = cpu->Cpsr;
5375 unsigned int operand; 4915 }
5376 4916 }
5377 if (BIT(inst, 25)) { 4917 cpu->Reg[15] += GET_INST_SIZE(cpu);
5378 int rot_imm = BITS(inst, 8, 11) * 2; 4918 INC_PC(sizeof(mrs_inst));
5379 //operand = ROTL(CONST(BITS(0, 7)), CONST(32 - rot_imm)); 4919 FETCH_INST;
5380 operand = ROTATE_RIGHT_32(BITS(inst, 0, 7), rot_imm); 4920 GOTO_NEXT_INST;
5381 } else { 4921 }
5382 //operand = R(RM); 4922 MSR_INST:
5383 operand = cpu->Reg[BITS(inst, 0, 3)]; 4923 {
5384 } 4924 msr_inst *inst_cream = (msr_inst *)inst_base->component;
5385 uint32_t byte_mask = (BIT(inst, 16) ? 0xff : 0) | (BIT(inst, 17) ? 0xff00 : 0) 4925 const uint32_t UnallocMask = 0x06f0fc00, UserMask = 0xf80f0200, PrivMask = 0x000001df, StateMask = 0x01000020;
5386 | (BIT(inst, 18) ? 0xff0000 : 0) | (BIT(inst, 19) ? 0xff000000 : 0); 4926 unsigned int inst = inst_cream->inst;
5387 uint32_t mask; 4927 unsigned int operand;
5388 if (!inst_cream->R) { 4928
5389 if (InAPrivilegedMode(cpu)) { 4929 if (BIT(inst, 25)) {
5390 if ((operand & StateMask) != 0) { 4930 int rot_imm = BITS(inst, 8, 11) * 2;
5391 /* UNPREDICTABLE */ 4931 operand = ROTATE_RIGHT_32(BITS(inst, 0, 7), rot_imm);
5392 DEBUG_MSG; 4932 } else {
5393 } else 4933 operand = cpu->Reg[BITS(inst, 0, 3)];
5394 mask = byte_mask & (UserMask | PrivMask); 4934 }
5395 } else { 4935 uint32_t byte_mask = (BIT(inst, 16) ? 0xff : 0) | (BIT(inst, 17) ? 0xff00 : 0)
5396 mask = byte_mask & UserMask; 4936 | (BIT(inst, 18) ? 0xff0000 : 0) | (BIT(inst, 19) ? 0xff000000 : 0);
5397 } 4937 uint32_t mask;
5398 //LET(CPSR_REG, OR(AND(R(CPSR_REG), COM(CONST(mask))), AND(operand, CONST(mask)))); 4938 if (!inst_cream->R) {
5399 SAVE_NZCVT; 4939 if (InAPrivilegedMode(cpu)) {
5400 4940 if ((operand & StateMask) != 0) {
5401 cpu->Cpsr = (cpu->Cpsr & ~mask) | (operand & mask); 4941 /// UNPREDICTABLE
5402 switch_mode(cpu, cpu->Cpsr & 0x1f); 4942 DEBUG_MSG;
5403 LOAD_NZCVT; 4943 } else
5404 } else { 4944 mask = byte_mask & (UserMask | PrivMask);
5405 if (CurrentModeHasSPSR) { 4945 } else {
5406 mask = byte_mask & (UserMask | PrivMask | StateMask); 4946 mask = byte_mask & UserMask;
5407 //LET(SPSR_REG, OR(AND(R(SPSR_REG), COM(CONST(mask))), AND(operand, CONST(mask)))); 4947 }
5408 cpu->Spsr_copy = (cpu->Spsr_copy & ~mask) | (operand & mask); 4948 SAVE_NZCVT;
5409 } 4949
5410 } 4950 cpu->Cpsr = (cpu->Cpsr & ~mask) | (operand & mask);
5411 cpu->Reg[15] += GET_INST_SIZE(cpu); 4951 switch_mode(cpu, cpu->Cpsr & 0x1f);
5412 INC_PC(sizeof(msr_inst)); 4952 LOAD_NZCVT;
5413 FETCH_INST; 4953 } else {
5414 GOTO_NEXT_INST; 4954 if (CurrentModeHasSPSR) {
5415 } 4955 mask = byte_mask & (UserMask | PrivMask | StateMask);
5416 MUL_INST: 4956 cpu->Spsr_copy = (cpu->Spsr_copy & ~mask) | (operand & mask);
5417 { 4957 }
5418 INC_ICOUNTER; 4958 }
5419 mul_inst *inst_cream = (mul_inst *)inst_base->component; 4959 cpu->Reg[15] += GET_INST_SIZE(cpu);
5420 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4960 INC_PC(sizeof(msr_inst));
5421// RD = dst = SHIFTER_OPERAND; 4961 FETCH_INST;
5422 uint64_t rm = RM; 4962 GOTO_NEXT_INST;
5423 uint64_t rs = RS; 4963 }
5424 RD = dst = static_cast<uint32_t>((rm * rs) & 0xffffffff); 4964 MUL_INST:
5425 if (inst_cream->S) { 4965 {
5426 UPDATE_NFLAG(dst); 4966 mul_inst *inst_cream = (mul_inst *)inst_base->component;
5427 UPDATE_ZFLAG(dst); 4967 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5428 } 4968 uint64_t rm = RM;
5429 if (inst_cream->Rd == 15) { 4969 uint64_t rs = RS;
5430 INC_PC(sizeof(mul_inst)); 4970 RD = dst = static_cast<uint32_t>((rm * rs) & 0xffffffff);
5431 goto DISPATCH; 4971 if (inst_cream->S) {
5432 } 4972 UPDATE_NFLAG(dst);
5433 } 4973 UPDATE_ZFLAG(dst);
5434 cpu->Reg[15] += GET_INST_SIZE(cpu); 4974 }
5435 INC_PC(sizeof(mul_inst)); 4975 if (inst_cream->Rd == 15) {
5436 FETCH_INST; 4976 INC_PC(sizeof(mul_inst));
5437 GOTO_NEXT_INST; 4977 goto DISPATCH;
5438 } 4978 }
5439 MVN_INST: 4979 }
5440 { 4980 cpu->Reg[15] += GET_INST_SIZE(cpu);
5441 INC_ICOUNTER; 4981 INC_PC(sizeof(mul_inst));
5442 mvn_inst *inst_cream = (mvn_inst *)inst_base->component; 4982 FETCH_INST;
5443 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 4983 GOTO_NEXT_INST;
5444// RD = dst = (SHIFTER_OPERAND ^ 0xffffffff); 4984 }
5445 RD = dst = ~SHIFTER_OPERAND; 4985 MVN_INST:
5446 if (inst_cream->S && (inst_cream->Rd == 15)) { 4986 {
5447 /* cpsr = spsr */ 4987 mvn_inst *inst_cream = (mvn_inst *)inst_base->component;
5448 if (CurrentModeHasSPSR) { 4988 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5449 cpu->Cpsr = cpu->Spsr_copy; 4989 RD = dst = ~SHIFTER_OPERAND;
5450 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 4990 if (inst_cream->S && (inst_cream->Rd == 15)) {
5451 LOAD_NZCVT; 4991 if (CurrentModeHasSPSR) {
5452 } 4992 cpu->Cpsr = cpu->Spsr_copy;
5453 } else if (inst_cream->S) { 4993 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
5454 UPDATE_NFLAG(dst); 4994 LOAD_NZCVT;
5455 UPDATE_ZFLAG(dst); 4995 }
5456 UPDATE_CFLAG_WITH_SC; 4996 } else if (inst_cream->S) {
5457 } 4997 UPDATE_NFLAG(dst);
5458 if (inst_cream->Rd == 15) { 4998 UPDATE_ZFLAG(dst);
5459 INC_PC(sizeof(mvn_inst)); 4999 UPDATE_CFLAG_WITH_SC;
5460 goto DISPATCH; 5000 }
5461 } 5001 if (inst_cream->Rd == 15) {
5462 } 5002 INC_PC(sizeof(mvn_inst));
5463 cpu->Reg[15] += GET_INST_SIZE(cpu); 5003 goto DISPATCH;
5464 INC_PC(sizeof(mvn_inst)); 5004 }
5465 FETCH_INST; 5005 }
5466 GOTO_NEXT_INST; 5006 cpu->Reg[15] += GET_INST_SIZE(cpu);
5467 } 5007 INC_PC(sizeof(mvn_inst));
5468 ORR_INST: 5008 FETCH_INST;
5469 { 5009 GOTO_NEXT_INST;
5470 INC_ICOUNTER; 5010 }
5471 orr_inst *inst_cream = (orr_inst *)inst_base->component; 5011 ORR_INST:
5472 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5012 {
5473 lop = RN; 5013 orr_inst *inst_cream = (orr_inst *)inst_base->component;
5474 rop = SHIFTER_OPERAND; 5014 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5475// DEBUG_LOG(ARM11, "lop is %x, rop is %x, r2 is %x, r3 is %x\n", lop, rop, cpu->Reg[2], cpu->Reg[3]); 5015 lop = RN;
5476 RD = dst = lop | rop; 5016 rop = SHIFTER_OPERAND;
5477 if (inst_cream->S && (inst_cream->Rd == 15)) { 5017 RD = dst = lop | rop;
5478 /* cpsr = spsr*/ 5018 if (inst_cream->S && (inst_cream->Rd == 15)) {
5479 if (CurrentModeHasSPSR) { 5019 if (CurrentModeHasSPSR) {
5480 cpu->Cpsr = cpu->Spsr_copy; 5020 cpu->Cpsr = cpu->Spsr_copy;
5481 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 5021 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
5482 LOAD_NZCVT; 5022 LOAD_NZCVT;
5483 } 5023 }
5484 } else if (inst_cream->S) { 5024 } else if (inst_cream->S) {
5485 UPDATE_NFLAG(dst); 5025 UPDATE_NFLAG(dst);
5486 UPDATE_ZFLAG(dst); 5026 UPDATE_ZFLAG(dst);
5487 UPDATE_CFLAG_WITH_SC; 5027 UPDATE_CFLAG_WITH_SC;
5488// UPDATE_CFLAG(dst, lop, rop); 5028 }
5489 } 5029 if (inst_cream->Rd == 15) {
5490 if (inst_cream->Rd == 15) { 5030 INC_PC(sizeof(orr_inst));
5491 INC_PC(sizeof(orr_inst)); 5031 goto DISPATCH;
5492 goto DISPATCH; 5032 }
5493 } 5033 }
5494 } 5034 cpu->Reg[15] += GET_INST_SIZE(cpu);
5495 cpu->Reg[15] += GET_INST_SIZE(cpu); 5035 INC_PC(sizeof(orr_inst));
5496 INC_PC(sizeof(orr_inst)); 5036 FETCH_INST;
5497 FETCH_INST; 5037 GOTO_NEXT_INST;
5498 GOTO_NEXT_INST; 5038 }
5499 } 5039
5500 PKHBT_INST: 5040 PKHBT_INST:
5501 PKHTB_INST: 5041 {
5502 PLD_INST: 5042 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
5503 { 5043 pkh_inst *inst_cream = (pkh_inst *)inst_base->component;
5504 INC_ICOUNTER; 5044 RD = (RN & 0xFFFF) | ((RM << inst_cream->imm) & 0xFFFF0000);
5505 /* NOT IMPL */ 5045 }
5506 cpu->Reg[15] += GET_INST_SIZE(cpu); 5046 cpu->Reg[15] += GET_INST_SIZE(cpu);
5507 INC_PC(sizeof(stc_inst)); 5047 INC_PC(sizeof(pkh_inst));
5508 FETCH_INST; 5048 FETCH_INST;
5509 GOTO_NEXT_INST; 5049 GOTO_NEXT_INST;
5510 } 5050 }
5511 QADD_INST: 5051
5512 QADD16_INST: 5052 PKHTB_INST:
5513 QADD8_INST: 5053 {
5514 QADDSUBX_INST: 5054 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
5515 QDADD_INST: 5055 pkh_inst *inst_cream = (pkh_inst *)inst_base->component;
5516 QDSUB_INST: 5056 int shift_imm = inst_cream->imm ? inst_cream->imm : 31;
5517 QSUB_INST: 5057 RD = ((static_cast<s32>(RM) >> shift_imm) & 0xFFFF) | (RN & 0xFFFF0000);
5518 QSUB16_INST: 5058 }
5519 QSUB8_INST: 5059 cpu->Reg[15] += GET_INST_SIZE(cpu);
5520 QSUBADDX_INST: 5060 INC_PC(sizeof(pkh_inst));
5521 REV_INST: 5061 FETCH_INST;
5522 { 5062 GOTO_NEXT_INST;
5523 INC_ICOUNTER; 5063 }
5524 rev_inst *inst_cream = (rev_inst *)inst_base->component; 5064
5525 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5065 PLD_INST:
5526 RD = ((RM & 0xff) << 24) | 5066 {
5527 (((RM >> 8) & 0xff) << 16) | 5067 // Instruction not implemented
5528 (((RM >> 16) & 0xff) << 8) | 5068 //LOG_CRITICAL(Core_ARM11, "unimplemented instruction");
5529 ((RM >> 24) & 0xff); 5069 cpu->Reg[15] += GET_INST_SIZE(cpu);
5530 if (inst_cream->Rm == 15) { 5070 INC_PC(sizeof(stc_inst));
5531 DEBUG_LOG(ARM11, "in line %d\n", __LINE__); 5071 FETCH_INST;
5532 CITRA_IGNORE_EXIT(-1); 5072 GOTO_NEXT_INST;
5533 } 5073 }
5534 } 5074
5535 cpu->Reg[15] += GET_INST_SIZE(cpu); 5075 QADD_INST:
5536 INC_PC(sizeof(rev_inst)); 5076 QADD8_INST:
5537 FETCH_INST; 5077 QADD16_INST:
5538 GOTO_NEXT_INST; 5078 QADDSUBX_INST:
5539 } 5079 QSUB8_INST:
5540 REV16_INST: 5080 QSUB16_INST:
5541 { 5081 QSUBADDX_INST:
5542 INC_ICOUNTER; 5082 {
5543 rev_inst *inst_cream = (rev_inst *)inst_base->component; 5083 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
5544 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5084 generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
5545 RD = (BITS(RM, 0, 7) << 8) | 5085 const u16 rm_lo = (RM & 0xFFFF);
5546 BITS(RM, 8, 15) | 5086 const u16 rm_hi = ((RM >> 16) & 0xFFFF);
5547 (BITS(RM, 16, 23) << 24) | 5087 const u16 rn_lo = (RN & 0xFFFF);
5548 (BITS(RM, 24, 31) << 16); 5088 const u16 rn_hi = ((RN >> 16) & 0xFFFF);
5549 } 5089 const u8 op2 = inst_cream->op2;
5550 cpu->Reg[15] += GET_INST_SIZE(cpu); 5090
5551 INC_PC(sizeof(rev_inst)); 5091 u16 lo_result = 0;
5552 FETCH_INST; 5092 u16 hi_result = 0;
5553 GOTO_NEXT_INST; 5093
5554 } 5094 // QADD16
5555 REVSH_INST: 5095 if (op2 == 0x00) {
5556 RFE_INST: 5096 lo_result = ARMul_SignedSaturatedAdd16(rn_lo, rm_lo);
5557 RSB_INST: 5097 hi_result = ARMul_SignedSaturatedAdd16(rn_hi, rm_hi);
5558 { 5098 }
5559 INC_ICOUNTER; 5099 // QASX
5560 rsb_inst *inst_cream = (rsb_inst *)inst_base->component; 5100 else if (op2 == 0x01) {
5561 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5101 lo_result = ARMul_SignedSaturatedSub16(rn_lo, rm_hi);
5562 rop = RN; 5102 hi_result = ARMul_SignedSaturatedAdd16(rn_hi, rm_lo);
5563 lop = SHIFTER_OPERAND; 5103 }
5564 if (inst_cream->Rn == 15) { 5104 // QSAX
5565 rop += 2 * GET_INST_SIZE(cpu);; 5105 else if (op2 == 0x02) {
5566 } 5106 lo_result = ARMul_SignedSaturatedAdd16(rn_lo, rm_hi);
5567 RD = dst = lop - rop; 5107 hi_result = ARMul_SignedSaturatedSub16(rn_hi, rm_lo);
5568 if (inst_cream->S && (inst_cream->Rd == 15)) { 5108 }
5569 /* cpsr = spsr */ 5109 // QSUB16
5570 if (CurrentModeHasSPSR) { 5110 else if (op2 == 0x03) {
5571 cpu->Cpsr = cpu->Spsr_copy; 5111 lo_result = ARMul_SignedSaturatedSub16(rn_lo, rm_lo);
5572 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 5112 hi_result = ARMul_SignedSaturatedSub16(rn_hi, rm_hi);
5573 LOAD_NZCVT; 5113 }
5574 } 5114 // QADD8
5575 } else if (inst_cream->S) { 5115 else if (op2 == 0x04) {
5576 UPDATE_NFLAG(dst); 5116 lo_result = ARMul_SignedSaturatedAdd8(rn_lo & 0xFF, rm_lo & 0xFF) |
5577 UPDATE_ZFLAG(dst); 5117 ARMul_SignedSaturatedAdd8(rn_lo >> 8, rm_lo >> 8) << 8;
5578 UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop); 5118 hi_result = ARMul_SignedSaturatedAdd8(rn_hi & 0xFF, rm_hi & 0xFF) |
5579// UPDATE_VFLAG((int)dst, (int)lop, (int)rop); 5119 ARMul_SignedSaturatedAdd8(rn_hi >> 8, rm_hi >> 8) << 8;
5580 UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop); 5120 }
5581 } 5121 // QSUB8
5582 if (inst_cream->Rd == 15) { 5122 else if (op2 == 0x07) {
5583 INC_PC(sizeof(rsb_inst)); 5123 lo_result = ARMul_SignedSaturatedSub8(rn_lo & 0xFF, rm_lo & 0xFF) |
5584 goto DISPATCH; 5124 ARMul_SignedSaturatedSub8(rn_lo >> 8, rm_lo >> 8) << 8;
5585 } 5125 hi_result = ARMul_SignedSaturatedSub8(rn_hi & 0xFF, rm_hi & 0xFF) |
5586 } 5126 ARMul_SignedSaturatedSub8(rn_hi >> 8, rm_hi >> 8) << 8;
5587 cpu->Reg[15] += GET_INST_SIZE(cpu); 5127 }
5588 INC_PC(sizeof(rsb_inst)); 5128
5589 FETCH_INST; 5129 RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);
5590 GOTO_NEXT_INST; 5130 }
5591 } 5131
5592 RSC_INST: 5132 cpu->Reg[15] += GET_INST_SIZE(cpu);
5593 { 5133 INC_PC(sizeof(generic_arm_inst));
5594 INC_ICOUNTER; 5134 FETCH_INST;
5595 rsc_inst *inst_cream = (rsc_inst *)inst_base->component; 5135 GOTO_NEXT_INST;
5596 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5136 }
5597 //lop = RN + !cpu->CFlag; 5137
5598 //rop = SHIFTER_OPERAND; 5138 QDADD_INST:
5599 //RD = dst = rop - lop; 5139 QDSUB_INST:
5600 lop = RN; 5140 QSUB_INST:
5601 rop = SHIFTER_OPERAND; 5141 REV_INST:
5602 RD = dst = rop - lop - !cpu->CFlag; 5142 {
5603 if (inst_cream->S && (inst_cream->Rd == 15)) { 5143 rev_inst *inst_cream = (rev_inst *)inst_base->component;
5604 /* cpsr = spsr */ 5144 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5605 if (CurrentModeHasSPSR) { 5145 RD = ((RM & 0xff) << 24) |
5606 cpu->Cpsr = cpu->Spsr_copy; 5146 (((RM >> 8) & 0xff) << 16) |
5607 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 5147 (((RM >> 16) & 0xff) << 8) |
5608 LOAD_NZCVT; 5148 ((RM >> 24) & 0xff);
5609 } 5149 if (inst_cream->Rm == 15) {
5610 } else if (inst_cream->S) { 5150 LOG_ERROR(Core_ARM11, "invalid operand for REV");
5611 UPDATE_NFLAG(dst); 5151 CITRA_IGNORE_EXIT(-1);
5612 UPDATE_ZFLAG(dst); 5152 }
5613// UPDATE_CFLAG(dst, lop, rop); 5153 }
5614// UPDATE_CFLAG_NOT_BORROW_FROM(rop, lop); 5154 cpu->Reg[15] += GET_INST_SIZE(cpu);
5615 UPDATE_CFLAG_NOT_BORROW_FROM_FLAG(rop, lop, !cpu->CFlag); 5155 INC_PC(sizeof(rev_inst));
5616// cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || (ISNEG(lop) && ISPOS(dst)) || (ISPOS(rop) && ISPOS(dst))); 5156 FETCH_INST;
5617 UPDATE_VFLAG_OVERFLOW_FROM((int)dst, (int)rop, (int)lop); 5157 GOTO_NEXT_INST;
5618 } 5158 }
5619 if (inst_cream->Rd == 15) { 5159 REV16_INST:
5620 INC_PC(sizeof(rsc_inst)); 5160 {
5621 goto DISPATCH; 5161 rev_inst *inst_cream = (rev_inst *)inst_base->component;
5622 } 5162 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5623 } 5163 RD = (BITS(RM, 0, 7) << 8) |
5624 cpu->Reg[15] += GET_INST_SIZE(cpu); 5164 BITS(RM, 8, 15) |
5625 INC_PC(sizeof(rsc_inst)); 5165 (BITS(RM, 16, 23) << 24) |
5626 FETCH_INST; 5166 (BITS(RM, 24, 31) << 16);
5627 GOTO_NEXT_INST; 5167 }
5628 } 5168 cpu->Reg[15] += GET_INST_SIZE(cpu);
5629 SADD16_INST: 5169 INC_PC(sizeof(rev_inst));
5630 SADD8_INST: 5170 FETCH_INST;
5631 SADDSUBX_INST: 5171 GOTO_NEXT_INST;
5632 SBC_INST: 5172 }
5633 { 5173 REVSH_INST:
5634 INC_ICOUNTER; 5174 RFE_INST:
5635 sbc_inst *inst_cream = (sbc_inst *)inst_base->component; 5175 RSB_INST:
5636 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5176 {
5637 lop = SHIFTER_OPERAND + !cpu->CFlag; 5177 rsb_inst *inst_cream = (rsb_inst *)inst_base->component;
5638 rop = RN; 5178 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5639 RD = dst = rop - lop; 5179 rop = RN;
5640 if (inst_cream->S && (inst_cream->Rd == 15)) { 5180 lop = SHIFTER_OPERAND;
5641 /* cpsr = spsr */ 5181 if (inst_cream->Rn == 15) {
5642 if (CurrentModeHasSPSR) { 5182 rop += 2 * GET_INST_SIZE(cpu);;
5643 cpu->Cpsr = cpu->Spsr_copy; 5183 }
5644 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 5184 RD = dst = lop - rop;
5645 LOAD_NZCVT; 5185 if (inst_cream->S && (inst_cream->Rd == 15)) {
5646 } 5186 if (CurrentModeHasSPSR) {
5647 } else if (inst_cream->S) { 5187 cpu->Cpsr = cpu->Spsr_copy;
5648 UPDATE_NFLAG(dst); 5188 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
5649 UPDATE_ZFLAG(dst); 5189 LOAD_NZCVT;
5650// UPDATE_CFLAG(dst, lop, rop); 5190 }
5651 //UPDATE_CFLAG_NOT_BORROW_FROM(rop, lop); 5191 } else if (inst_cream->S) {
5652 //rop = rop - !cpu->CFlag; 5192 UPDATE_NFLAG(dst);
5653 if(rop >= !cpu->CFlag) 5193 UPDATE_ZFLAG(dst);
5654 UPDATE_CFLAG_NOT_BORROW_FROM(rop - !cpu->CFlag, SHIFTER_OPERAND); 5194 UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop);
5655 else 5195 UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop);
5656 UPDATE_CFLAG_NOT_BORROW_FROM(rop, !cpu->CFlag); 5196 }
5657// cpu->CFlag = !((ISNEG(lop) && ISPOS(rop)) || (ISNEG(lop) && ISPOS(dst)) || (ISPOS(rop) && ISPOS(dst))); 5197 if (inst_cream->Rd == 15) {
5658 UPDATE_VFLAG_OVERFLOW_FROM(dst, rop, lop); 5198 INC_PC(sizeof(rsb_inst));
5659 } 5199 goto DISPATCH;
5660 if (inst_cream->Rd == 15) { 5200 }
5661 INC_PC(sizeof(sbc_inst)); 5201 }
5662 goto DISPATCH; 5202 cpu->Reg[15] += GET_INST_SIZE(cpu);
5663 } 5203 INC_PC(sizeof(rsb_inst));
5664 } 5204 FETCH_INST;
5665 cpu->Reg[15] += GET_INST_SIZE(cpu); 5205 GOTO_NEXT_INST;
5666 INC_PC(sizeof(sbc_inst)); 5206 }
5667 FETCH_INST; 5207 RSC_INST:
5668 GOTO_NEXT_INST; 5208 {
5669 } 5209 rsc_inst *inst_cream = (rsc_inst *)inst_base->component;
5670 SEL_INST: 5210 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5671 SETEND_INST: 5211 lop = RN;
5672 SHADD16_INST: 5212 rop = SHIFTER_OPERAND;
5673 SHADD8_INST: 5213 RD = dst = rop - lop - !cpu->CFlag;
5674 SHADDSUBX_INST: 5214 if (inst_cream->S && (inst_cream->Rd == 15)) {
5675 SHSUB16_INST: 5215 if (CurrentModeHasSPSR) {
5676 SHSUB8_INST: 5216 cpu->Cpsr = cpu->Spsr_copy;
5677 SHSUBADDX_INST: 5217 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
5678 SMLA_INST: 5218 LOAD_NZCVT;
5679 { 5219 }
5680 INC_ICOUNTER; 5220 } else if (inst_cream->S) {
5681 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5221 UPDATE_NFLAG(dst);
5682 smla_inst *inst_cream = (smla_inst *)inst_base->component; 5222 UPDATE_ZFLAG(dst);
5683 int32_t operand1, operand2; 5223 UPDATE_CFLAG_NOT_BORROW_FROM_FLAG(rop, lop, !cpu->CFlag);
5684 if (inst_cream->x == 0) 5224 UPDATE_VFLAG_OVERFLOW_FROM((int)dst, (int)rop, (int)lop);
5685 operand1 = (BIT(RM, 15)) ? (BITS(RM, 0, 15) | 0xffff0000) : BITS(RM, 0, 15); 5225 }
5686 else 5226 if (inst_cream->Rd == 15) {
5687 operand1 = (BIT(RM, 31)) ? (BITS(RM, 16, 31) | 0xffff0000) : BITS(RM, 16, 31); 5227 INC_PC(sizeof(rsc_inst));
5688 5228 goto DISPATCH;
5689 if (inst_cream->y == 0) 5229 }
5690 operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15); 5230 }
5691 else 5231 cpu->Reg[15] += GET_INST_SIZE(cpu);
5692 operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31); 5232 INC_PC(sizeof(rsc_inst));
5693 RD = operand1 * operand2 + RN; 5233 FETCH_INST;
5694 //FIXME: UPDATE Q FLAGS 5234 GOTO_NEXT_INST;
5695 } 5235 }
5696 cpu->Reg[15] += GET_INST_SIZE(cpu); 5236
5697 INC_PC(sizeof(smla_inst)); 5237 SADD8_INST:
5698 FETCH_INST; 5238 SADD16_INST:
5699 GOTO_NEXT_INST; 5239 SADDSUBX_INST:
5700 } 5240 SSUBADDX_INST:
5701 SMLAD_INST: 5241 SSUB16_INST:
5702 { 5242 {
5703 INC_ICOUNTER; 5243 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
5704 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5244 generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
5705 smlad_inst *inst_cream = (smlad_inst *)inst_base->component; 5245
5706 long long int rm = cpu->Reg[inst_cream->Rm]; 5246 const s16 rn_lo = (RN & 0xFFFF);
5707 long long int rn = cpu->Reg[inst_cream->Rn]; 5247 const s16 rn_hi = ((RN >> 16) & 0xFFFF);
5708 long long int ra = cpu->Reg[inst_cream->Ra]; 5248 const s16 rm_lo = (RM & 0xFFFF);
5709 /* see SMUAD */ 5249 const s16 rm_hi = ((RM >> 16) & 0xFFFF);
5710 if(inst_cream->Ra == 15) 5250
5711 CITRA_IGNORE_EXIT(-1); 5251 s32 lo_result = 0;
5712 int operand2 = (inst_cream->m)? ROTATE_RIGHT_32(rm, 16):rm; 5252 s32 hi_result = 0;
5713 5253
5714 int half_rn, half_operand2; 5254 // SADD16
5715 half_rn = rn & 0xFFFF; 5255 if (inst_cream->op2 == 0x00) {
5716 half_rn = (half_rn & 0x8000)? (0xFFFF0000|half_rn) : half_rn; 5256 lo_result = (rn_lo + rm_lo);
5717 5257 hi_result = (rn_hi + rm_hi);
5718 half_operand2 = operand2 & 0xFFFF; 5258 }
5719 half_operand2 = (half_operand2 & 0x8000)? (0xFFFF0000|half_operand2) : half_operand2; 5259 // SASX
5720 5260 else if (inst_cream->op2 == 0x01) {
5721 long long int product1 = half_rn * half_operand2; 5261 lo_result = (rn_lo - rm_hi);
5722 5262 hi_result = (rn_hi + rm_lo);
5723 half_rn = (rn & 0xFFFF0000) >> 16; 5263 }
5724 half_rn = (half_rn & 0x8000)? (0xFFFF0000|half_rn) : half_rn; 5264 // SSAX
5725 5265 else if (inst_cream->op2 == 0x02) {
5726 half_operand2 = (operand2 & 0xFFFF0000) >> 16; 5266 lo_result = (rn_lo + rm_hi);
5727 half_operand2 = (half_operand2 & 0x8000)? (0xFFFF0000|half_operand2) : half_operand2; 5267 hi_result = (rn_hi - rm_lo);
5728 5268 }
5729 long long int product2 = half_rn * half_operand2; 5269 // SSUB16
5730 5270 else if (inst_cream->op2 == 0x03) {
5731 long long int signed_ra = (ra & 0x80000000)? (0xFFFFFFFF00000000LL) | ra : ra; 5271 lo_result = (rn_lo - rm_lo);
5732 long long int result = product1 + product2 + signed_ra; 5272 hi_result = (rn_hi - rm_hi);
5733 cpu->Reg[inst_cream->Rd] = result & 0xFFFFFFFF; 5273 }
5734 /* FIXME , should check Signed overflow */ 5274
5735 } 5275 RD = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);
5736 cpu->Reg[15] += GET_INST_SIZE(cpu); 5276
5737 INC_PC(sizeof(umlal_inst)); 5277 if (lo_result >= 0) {
5738 FETCH_INST; 5278 cpu->Cpsr |= (1 << 16);
5739 GOTO_NEXT_INST; 5279 cpu->Cpsr |= (1 << 17);
5740 } 5280 } else {
5741 5281 cpu->Cpsr &= ~(1 << 16);
5742 SMLAL_INST: 5282 cpu->Cpsr &= ~(1 << 17);
5743 { 5283 }
5744 INC_ICOUNTER; 5284
5745 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5285 if (hi_result >= 0) {
5746 umlal_inst *inst_cream = (umlal_inst *)inst_base->component; 5286 cpu->Cpsr |= (1 << 18);
5747 long long int rm = RM; 5287 cpu->Cpsr |= (1 << 19);
5748 long long int rs = RS; 5288 } else {
5749 if (BIT(rm, 31)) { 5289 cpu->Cpsr &= ~(1 << 18);
5750 rm |= 0xffffffff00000000LL; 5290 cpu->Cpsr &= ~(1 << 19);
5751 } 5291 }
5752 if (BIT(rs, 31)) { 5292 }
5753 rs |= 0xffffffff00000000LL; 5293
5754 } 5294 cpu->Reg[15] += GET_INST_SIZE(cpu);
5755 long long int rst = rm * rs; 5295 INC_PC(sizeof(generic_arm_inst));
5756 long long int rdhi32 = RDHI; 5296 FETCH_INST;
5757 long long int hilo = (rdhi32 << 32) + RDLO; 5297 GOTO_NEXT_INST;
5758 rst += hilo; 5298 }
5759 RDLO = BITS(rst, 0, 31); 5299
5760 RDHI = BITS(rst, 32, 63); 5300 SBC_INST:
5761 if (inst_cream->S) { 5301 {
5762 cpu->NFlag = BIT(RDHI, 31); 5302 sbc_inst *inst_cream = (sbc_inst *)inst_base->component;
5763 cpu->ZFlag = (RDHI == 0 && RDLO == 0); 5303 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5764 } 5304 lop = SHIFTER_OPERAND + !cpu->CFlag;
5765 } 5305 rop = RN;
5766 cpu->Reg[15] += GET_INST_SIZE(cpu); 5306 RD = dst = rop - lop;
5767 INC_PC(sizeof(umlal_inst)); 5307 if (inst_cream->S && (inst_cream->Rd == 15)) {
5768 FETCH_INST; 5308 if (CurrentModeHasSPSR) {
5769 GOTO_NEXT_INST; 5309 cpu->Cpsr = cpu->Spsr_copy;
5770 } 5310 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
5771 SMLALXY_INST: 5311 LOAD_NZCVT;
5772 SMLALD_INST: 5312 }
5773 SMLAW_INST: 5313 } else if (inst_cream->S) {
5774 SMLSD_INST: 5314 UPDATE_NFLAG(dst);
5775 SMLSLD_INST: 5315 UPDATE_ZFLAG(dst);
5776 SMMLA_INST: 5316
5777 SMMLS_INST: 5317 if(rop >= !cpu->CFlag)
5778 SMMUL_INST: 5318 UPDATE_CFLAG_NOT_BORROW_FROM(rop - !cpu->CFlag, SHIFTER_OPERAND);
5779 SMUAD_INST: 5319 else
5780 SMUL_INST: 5320 UPDATE_CFLAG_NOT_BORROW_FROM(rop, !cpu->CFlag);
5781 { 5321
5782 INC_ICOUNTER; 5322 UPDATE_VFLAG_OVERFLOW_FROM(dst, rop, lop);
5783 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5323 }
5784 smul_inst *inst_cream = (smul_inst *)inst_base->component; 5324 if (inst_cream->Rd == 15) {
5785 uint32_t operand1, operand2; 5325 INC_PC(sizeof(sbc_inst));
5786 if (inst_cream->x == 0) 5326 goto DISPATCH;
5787 operand1 = (BIT(RM, 15)) ? (BITS(RM, 0, 15) | 0xffff0000) : BITS(RM, 0, 15); 5327 }
5788 else 5328 }
5789 operand1 = (BIT(RM, 31)) ? (BITS(RM, 16, 31) | 0xffff0000) : BITS(RM, 16, 31); 5329 cpu->Reg[15] += GET_INST_SIZE(cpu);
5790 5330 INC_PC(sizeof(sbc_inst));
5791 if (inst_cream->y == 0) 5331 FETCH_INST;
5792 operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15); 5332 GOTO_NEXT_INST;
5793 else 5333 }
5794 operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31); 5334
5795 RD = operand1 * operand2; 5335 SEL_INST:
5796 } 5336 {
5797 cpu->Reg[15] += GET_INST_SIZE(cpu); 5337 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
5798 INC_PC(sizeof(smul_inst)); 5338 generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
5799 FETCH_INST; 5339
5800 GOTO_NEXT_INST; 5340 const u32 to = RM;
5801 } 5341 const u32 from = RN;
5802 SMULL_INST: 5342 const u32 cpsr = cpu->Cpsr;
5803 { 5343
5804 INC_ICOUNTER; 5344 u32 result;
5805 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5345 if (cpsr & (1 << 16))
5806 umull_inst *inst_cream = (umull_inst *)inst_base->component; 5346 result = from & 0xff;
5807// DEBUG_LOG(ARM11, "rm : [%llx] rs : [%llx] rst [%llx]\n", RM, RS, rst); 5347 else
5808 int64_t rm = RM; 5348 result = to & 0xff;
5809 int64_t rs = RS; 5349
5810 if (BIT(rm, 31)) { 5350 if (cpsr & (1 << 17))
5811 rm |= 0xffffffff00000000LL; 5351 result |= from & 0x0000ff00;
5812 } 5352 else
5813 if (BIT(rs, 31)) { 5353 result |= to & 0x0000ff00;
5814 rs |= 0xffffffff00000000LL; 5354
5815 } 5355 if (cpsr & (1 << 18))
5816 int64_t rst = rm * rs; 5356 result |= from & 0x00ff0000;
5817 RDHI = BITS(rst, 32, 63); 5357 else
5818 RDLO = BITS(rst, 0, 31); 5358 result |= to & 0x00ff0000;
5819 5359
5820 5360 if (cpsr & (1 << 19))
5821 if (inst_cream->S) { 5361 result |= from & 0xff000000;
5822 cpu->NFlag = BIT(RDHI, 31); 5362 else
5823 cpu->ZFlag = (RDHI == 0 && RDLO == 0); 5363 result |= to & 0xff000000;
5824 } 5364
5825 } 5365 RD = result;
5826 cpu->Reg[15] += GET_INST_SIZE(cpu); 5366 }
5827 INC_PC(sizeof(umull_inst)); 5367
5828 FETCH_INST; 5368 cpu->Reg[15] += GET_INST_SIZE(cpu);
5829 GOTO_NEXT_INST; 5369 INC_PC(sizeof(generic_arm_inst));
5830 } 5370 FETCH_INST;
5831 SMULW_INST: 5371 GOTO_NEXT_INST;
5832 INC_ICOUNTER; 5372 }
5833 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5373
5834 smlad_inst *inst_cream = (smlad_inst *)inst_base->component; 5374 SETEND_INST:
5835// DEBUG_LOG(ARM11, "rm : [%llx] rs : [%llx] rst [%llx]\n", RM, RS, rst); 5375 SHADD16_INST:
5836 int64_t rm = RM; 5376 SHADD8_INST:
5837 int64_t rn = RN; 5377 SHADDSUBX_INST:
5838 if (inst_cream->m) 5378 SHSUB16_INST:
5839 rm = BITS(rm,16 , 31); 5379 SHSUB8_INST:
5840 else 5380 SHSUBADDX_INST:
5841 rm = BITS(rm,0 , 15); 5381 SMLA_INST:
5842 int64_t rst = rm * rn; 5382 {
5843 RD = BITS(rst, 16, 47); 5383 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5844 } 5384 smla_inst *inst_cream = (smla_inst *)inst_base->component;
5845 cpu->Reg[15] += GET_INST_SIZE(cpu); 5385 int32_t operand1, operand2;
5846 INC_PC(sizeof(smlad_inst)); 5386 if (inst_cream->x == 0)
5847 FETCH_INST; 5387 operand1 = (BIT(RM, 15)) ? (BITS(RM, 0, 15) | 0xffff0000) : BITS(RM, 0, 15);
5848 GOTO_NEXT_INST; 5388 else
5849 5389 operand1 = (BIT(RM, 31)) ? (BITS(RM, 16, 31) | 0xffff0000) : BITS(RM, 16, 31);
5850 SMUSD_INST: 5390
5851 SRS_INST: 5391 if (inst_cream->y == 0)
5852 SSAT_INST: 5392 operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15);
5853 SSAT16_INST: 5393 else
5854 SSUB16_INST: 5394 operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31);
5855 SSUB8_INST: 5395 RD = operand1 * operand2 + RN;
5856 SSUBADDX_INST: 5396
5857 STC_INST: 5397 // TODO: FIXME: UPDATE Q FLAGS
5858 { 5398 }
5859 INC_ICOUNTER; 5399 cpu->Reg[15] += GET_INST_SIZE(cpu);
5860 /* NOT IMPL */ 5400 INC_PC(sizeof(smla_inst));
5861 cpu->Reg[15] += GET_INST_SIZE(cpu); 5401 FETCH_INST;
5862 INC_PC(sizeof(stc_inst)); 5402 GOTO_NEXT_INST;
5863 FETCH_INST; 5403 }
5864 GOTO_NEXT_INST; 5404 SMLAD_INST:
5865 } 5405 {
5866 STM_INST: 5406 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5867 { 5407 smlad_inst *inst_cream = (smlad_inst *)inst_base->component;
5868 INC_ICOUNTER; 5408 long long int rm = cpu->Reg[inst_cream->Rm];
5869 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 5409 long long int rn = cpu->Reg[inst_cream->Rn];
5870 unsigned int inst = inst_cream->inst; 5410 long long int ra = cpu->Reg[inst_cream->Ra];
5871 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5411
5872 int i; 5412 // See SMUAD
5873 unsigned int Rn = BITS(inst, 16, 19); 5413 if(inst_cream->Ra == 15)
5874 unsigned int old_RN = cpu->Reg[Rn]; 5414 CITRA_IGNORE_EXIT(-1);
5875 5415 int operand2 = (inst_cream->m)? ROTATE_RIGHT_32(rm, 16):rm;
5876 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); 5416 int half_rn, half_operand2;
5877 if (fault) goto MMU_EXCEPTION; 5417
5878 if (BIT(inst_cream->inst, 22) == 1) { 5418 half_rn = rn & 0xFFFF;
5879// DEBUG_MSG; 5419 half_rn = (half_rn & 0x8000)? (0xFFFF0000|half_rn) : half_rn;
5880 #if 1 5420
5881 for (i = 0; i < 13; i++) { 5421 half_operand2 = operand2 & 0xFFFF;
5882 if(BIT(inst_cream->inst, i)){ 5422 half_operand2 = (half_operand2 & 0x8000)? (0xFFFF0000|half_operand2) : half_operand2;
5883 fault = check_address_validity(cpu, addr, &phys_addr, 0); 5423
5884 if (fault) { 5424 long long int product1 = half_rn * half_operand2;
5885 goto MMU_EXCEPTION; 5425
5886 } 5426 half_rn = (rn & 0xFFFF0000) >> 16;
5887 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32); 5427 half_rn = (half_rn & 0x8000)? (0xFFFF0000|half_rn) : half_rn;
5888 if (fault) goto MMU_EXCEPTION; 5428
5889 addr += 4; 5429 half_operand2 = (operand2 & 0xFFFF0000) >> 16;
5890 phys_addr += 4; 5430 half_operand2 = (half_operand2 & 0x8000)? (0xFFFF0000|half_operand2) : half_operand2;
5891 } 5431
5892 } 5432 long long int product2 = half_rn * half_operand2;
5893 if (BIT(inst_cream->inst, 13)) { 5433
5894 if (cpu->Mode == USER32MODE) { 5434 long long int signed_ra = (ra & 0x80000000)? (0xFFFFFFFF00000000LL) | ra : ra;
5895 fault = check_address_validity(cpu, addr, &phys_addr, 0); 5435 long long int result = product1 + product2 + signed_ra;
5896 if (fault) { 5436 cpu->Reg[inst_cream->Rd] = result & 0xFFFFFFFF;
5897 goto MMU_EXCEPTION; 5437
5898 } 5438 // TODO: FIXME should check Signed overflow
5899 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32); 5439 }
5900 if (fault) goto MMU_EXCEPTION; 5440 cpu->Reg[15] += GET_INST_SIZE(cpu);
5901 addr += 4; 5441 INC_PC(sizeof(umlal_inst));
5902 phys_addr += 4; 5442 FETCH_INST;
5903 } else { 5443 GOTO_NEXT_INST;
5904 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg_usr[0], 32); 5444 }
5905 if (fault) goto MMU_EXCEPTION; 5445
5906 addr += 4; 5446 SMLAL_INST:
5907 phys_addr += 4; 5447 {
5908 } 5448 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5909 } 5449 umlal_inst *inst_cream = (umlal_inst *)inst_base->component;
5910 if (BIT(inst_cream->inst, 14)) { 5450 long long int rm = RM;
5911 if (cpu->Mode == USER32MODE) { 5451 long long int rs = RS;
5912 fault = check_address_validity(cpu, addr, &phys_addr, 0); 5452 if (BIT(rm, 31)) {
5913 if (fault) { 5453 rm |= 0xffffffff00000000LL;
5914 goto MMU_EXCEPTION; 5454 }
5915 } 5455 if (BIT(rs, 31)) {
5916 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32); 5456 rs |= 0xffffffff00000000LL;
5917 if (fault) goto MMU_EXCEPTION; 5457 }
5918 addr += 4; 5458 long long int rst = rm * rs;
5919 phys_addr += 4; 5459 long long int rdhi32 = RDHI;
5920 } else { 5460 long long int hilo = (rdhi32 << 32) + RDLO;
5921 fault = check_address_validity(cpu, addr, &phys_addr, 0); 5461 rst += hilo;
5922 if (fault) { 5462 RDLO = BITS(rst, 0, 31);
5923 goto MMU_EXCEPTION; 5463 RDHI = BITS(rst, 32, 63);
5924 } 5464 if (inst_cream->S) {
5925 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg_usr[1], 32); 5465 cpu->NFlag = BIT(RDHI, 31);
5926 if (fault) goto MMU_EXCEPTION; 5466 cpu->ZFlag = (RDHI == 0 && RDLO == 0);
5927 addr += 4; 5467 }
5928 phys_addr += 4; 5468 }
5929 } 5469 cpu->Reg[15] += GET_INST_SIZE(cpu);
5930 } 5470 INC_PC(sizeof(umlal_inst));
5931 if (BIT(inst_cream->inst, 15)) { 5471 FETCH_INST;
5932 fault = check_address_validity(cpu, addr, &phys_addr, 0); 5472 GOTO_NEXT_INST;
5933 if (fault) { 5473 }
5934 goto MMU_EXCEPTION; 5474 SMLALXY_INST:
5935 } 5475 SMLALD_INST:
5936 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i] + 8, 32); 5476 SMLAW_INST:
5937 if (fault) goto MMU_EXCEPTION; 5477 SMLSD_INST:
5938 } 5478 SMLSLD_INST:
5939 #endif 5479 SMMLA_INST:
5940 } else { 5480 SMMLS_INST:
5941 for( i = 0; i < 15; i ++ ){ 5481 SMMUL_INST:
5942 if(BIT(inst_cream->inst, i)){ 5482 SMUAD_INST:
5943 //arch_write_memory(cpu, bb, Addr, R(i), 32); 5483 SMUL_INST:
5944 //bus_write(32, addr, cpu->Reg[i]); 5484 {
5945 fault = check_address_validity(cpu, addr, &phys_addr, 0); 5485 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5946 if (fault) { 5486 smul_inst *inst_cream = (smul_inst *)inst_base->component;
5947 goto MMU_EXCEPTION; 5487 uint32_t operand1, operand2;
5948 } 5488 if (inst_cream->x == 0)
5949 if(i == Rn) 5489 operand1 = (BIT(RM, 15)) ? (BITS(RM, 0, 15) | 0xffff0000) : BITS(RM, 0, 15);
5950 fault = interpreter_write_memory(addr, phys_addr, old_RN, 32); 5490 else
5951 else 5491 operand1 = (BIT(RM, 31)) ? (BITS(RM, 16, 31) | 0xffff0000) : BITS(RM, 16, 31);
5952 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32); 5492
5953 if (fault) goto MMU_EXCEPTION; 5493 if (inst_cream->y == 0)
5954 addr += 4; 5494 operand2 = (BIT(RS, 15)) ? (BITS(RS, 0, 15) | 0xffff0000) : BITS(RS, 0, 15);
5955 phys_addr += 4; 5495 else
5956 //Addr = ADD(Addr, CONST(4)); 5496 operand2 = (BIT(RS, 31)) ? (BITS(RS, 16, 31) | 0xffff0000) : BITS(RS, 16, 31);
5957 } 5497 RD = operand1 * operand2;
5958 } 5498 }
5959 5499 cpu->Reg[15] += GET_INST_SIZE(cpu);
5960 /* check pc reg*/ 5500 INC_PC(sizeof(smul_inst));
5961 if(BIT(inst_cream->inst, i)){ 5501 FETCH_INST;
5962 //arch_write_memory(cpu, bb, Addr, STOREM_CHECK_PC, 32); 5502 GOTO_NEXT_INST;
5963 //bus_write(32, addr, cpu->Reg[i] + 8); 5503 }
5964 fault = check_address_validity(cpu, addr, &phys_addr, 0); 5504 SMULL_INST:
5965 if (fault) { 5505 {
5966 goto MMU_EXCEPTION; 5506 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5967 } 5507 umull_inst *inst_cream = (umull_inst *)inst_base->component;
5968 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i] + 8, 32); 5508 int64_t rm = RM;
5969 if (fault) goto MMU_EXCEPTION; 5509 int64_t rs = RS;
5970 } 5510 if (BIT(rm, 31)) {
5971 } 5511 rm |= 0xffffffff00000000LL;
5972 } 5512 }
5973 cpu->Reg[15] += GET_INST_SIZE(cpu); 5513 if (BIT(rs, 31)) {
5974 INC_PC(sizeof(ldst_inst)); 5514 rs |= 0xffffffff00000000LL;
5975 FETCH_INST; 5515 }
5976 GOTO_NEXT_INST; 5516 int64_t rst = rm * rs;
5977 } 5517 RDHI = BITS(rst, 32, 63);
5978 SXTB_INST: 5518 RDLO = BITS(rst, 0, 31);
5979 { 5519
5980 INC_ICOUNTER; 5520 if (inst_cream->S) {
5981 sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component; 5521 cpu->NFlag = BIT(RDHI, 31);
5982 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5522 cpu->ZFlag = (RDHI == 0 && RDLO == 0);
5983 if (inst_cream->Rm == 15) { 5523 }
5984 DEBUG_LOG(ARM11, "line is %d\n", __LINE__); 5524 }
5985 CITRA_IGNORE_EXIT(-1); 5525 cpu->Reg[15] += GET_INST_SIZE(cpu);
5986 } 5526 INC_PC(sizeof(umull_inst));
5987 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate); 5527 FETCH_INST;
5988 if (BIT(operand2, 7)) { 5528 GOTO_NEXT_INST;
5989 operand2 |= 0xffffff00; 5529 }
5990 } else 5530
5991 operand2 &= 0xff; 5531 SMULW_INST:
5992 RD = operand2; 5532 {
5993 } 5533 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5994 cpu->Reg[15] += GET_INST_SIZE(cpu); 5534 smlad_inst *inst_cream = (smlad_inst *)inst_base->component;
5995 INC_PC(sizeof(sxtb_inst)); 5535 int64_t rm = RM;
5996 FETCH_INST; 5536 int64_t rn = RN;
5997 GOTO_NEXT_INST; 5537 if (inst_cream->m)
5998 } 5538 rm = BITS(rm, 16, 31);
5999 STR_INST: 5539 else
6000 { 5540 rm = BITS(rm, 0, 15);
6001 INC_ICOUNTER; 5541 int64_t rst = rm * rn;
6002 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 5542 RD = BITS(rst, 16, 47);
6003 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5543 }
6004 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); 5544 cpu->Reg[15] += GET_INST_SIZE(cpu);
6005 if (fault) goto MMU_EXCEPTION; 5545 INC_PC(sizeof(smlad_inst));
6006 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; 5546 FETCH_INST;
6007 //bus_write(32, addr, value); 5547 GOTO_NEXT_INST;
6008 fault = interpreter_write_memory(addr, phys_addr, value, 32); 5548 }
6009 if (fault) goto MMU_EXCEPTION; 5549
6010 } 5550 SMUSD_INST:
6011 cpu->Reg[15] += GET_INST_SIZE(cpu); 5551 SRS_INST:
6012 INC_PC(sizeof(ldst_inst)); 5552 SSAT_INST:
6013 FETCH_INST; 5553 {
6014 GOTO_NEXT_INST; 5554 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
6015 } 5555 ssat_inst* const inst_cream = (ssat_inst*)inst_base->component;
6016 UXTB_INST: 5556
6017 { 5557 u8 shift_type = inst_cream->shift_type;
6018 INC_ICOUNTER; 5558 u8 shift_amount = inst_cream->imm5;
6019 uxtb_inst *inst_cream = (uxtb_inst *)inst_base->component; 5559 u32 rn_val = RN;
6020 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5560
6021 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) 5561 // 32-bit ASR is encoded as an amount of 0.
6022 & 0xff; 5562 if (shift_type == 1 && shift_amount == 0)
6023 RD = operand2; 5563 shift_amount = 31;
6024 } 5564
6025 cpu->Reg[15] += GET_INST_SIZE(cpu); 5565 if (shift_type == 0)
6026 INC_PC(sizeof(uxtb_inst)); 5566 rn_val <<= shift_amount;
6027 FETCH_INST; 5567 else if (shift_type == 1)
6028 GOTO_NEXT_INST; 5568 rn_val = ((s32)rn_val >> shift_amount);
6029 } 5569
6030 UXTAB_INST: 5570 bool saturated = false;
6031 { 5571 rn_val = ARMul_SignedSatQ(rn_val, inst_cream->sat_imm, &saturated);
6032 INC_ICOUNTER; 5572
6033 uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component; 5573 if (saturated)
6034 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5574 cpu->Cpsr |= (1 << 27);
6035 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) 5575
6036 & 0xff; 5576 RD = rn_val;
6037 RD = RN + operand2; 5577 }
6038 } 5578
6039 cpu->Reg[15] += GET_INST_SIZE(cpu); 5579 cpu->Reg[15] += GET_INST_SIZE(cpu);
6040 INC_PC(sizeof(uxtab_inst)); 5580 INC_PC(sizeof(ssat_inst));
6041 FETCH_INST; 5581 FETCH_INST;
6042 GOTO_NEXT_INST; 5582 GOTO_NEXT_INST;
6043 } 5583 }
6044 STRB_INST: 5584
6045 { 5585 SSAT16_INST:
6046 INC_ICOUNTER; 5586 SSUB8_INST:
6047 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 5587 STC_INST:
6048 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5588 {
6049 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); 5589 // Instruction not implemented
6050 if (fault) goto MMU_EXCEPTION; 5590 //LOG_CRITICAL(Core_ARM11, "unimplemented instruction");
6051 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; 5591 cpu->Reg[15] += GET_INST_SIZE(cpu);
6052 //bus_write(8, addr, value); 5592 INC_PC(sizeof(stc_inst));
6053 fault = interpreter_write_memory(addr, phys_addr, value, 8); 5593 FETCH_INST;
6054 if (fault) goto MMU_EXCEPTION; 5594 GOTO_NEXT_INST;
6055 } 5595 }
6056 cpu->Reg[15] += GET_INST_SIZE(cpu); 5596 STM_INST:
6057 INC_PC(sizeof(ldst_inst)); 5597 {
6058 FETCH_INST; 5598 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
6059 GOTO_NEXT_INST; 5599 unsigned int inst = inst_cream->inst;
6060 } 5600 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6061 STRBT_INST: 5601 int i;
6062 { 5602 unsigned int Rn = BITS(inst, 16, 19);
6063 INC_ICOUNTER; 5603 unsigned int old_RN = cpu->Reg[Rn];
6064 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 5604
6065 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5605 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
6066 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); 5606 if (fault) goto MMU_EXCEPTION;
6067 if (fault) goto MMU_EXCEPTION; 5607 if (BIT(inst_cream->inst, 22) == 1) {
6068 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff; 5608 for (i = 0; i < 13; i++) {
6069 //bus_write(8, addr, value); 5609 if(BIT(inst_cream->inst, i)){
6070 fault = interpreter_write_memory(addr, phys_addr, value, 8); 5610 fault = check_address_validity(cpu, addr, &phys_addr, 0);
6071 if (fault) goto MMU_EXCEPTION; 5611 if (fault) goto MMU_EXCEPTION;
6072 } 5612 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32);
6073 cpu->Reg[15] += GET_INST_SIZE(cpu); 5613 if (fault) goto MMU_EXCEPTION;
6074 //if (BITS(inst_cream->inst, 12, 15) == 15) 5614 addr += 4;
6075 // goto DISPATCH; 5615 phys_addr += 4;
6076 INC_PC(sizeof(ldst_inst)); 5616 }
6077 FETCH_INST; 5617 }
6078 GOTO_NEXT_INST; 5618 if (BIT(inst_cream->inst, 13)) {
6079 } 5619 if (cpu->Mode == USER32MODE) {
6080 STRD_INST: 5620 fault = check_address_validity(cpu, addr, &phys_addr, 0);
6081 { 5621 if (fault) goto MMU_EXCEPTION;
6082 INC_ICOUNTER; 5622 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32);
6083 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 5623 if (fault) goto MMU_EXCEPTION;
6084 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5624 addr += 4;
6085 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); 5625 phys_addr += 4;
6086 if (fault) goto MMU_EXCEPTION; 5626 } else {
6087 uint32_t rear_phys_addr; 5627 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg_usr[0], 32);
6088 fault = check_address_validity(cpu, addr + 4, &rear_phys_addr, 0); 5628 if (fault) goto MMU_EXCEPTION;
5629 addr += 4;
5630 phys_addr += 4;
5631 }
5632 }
5633 if (BIT(inst_cream->inst, 14)) {
5634 if (cpu->Mode == USER32MODE) {
5635 fault = check_address_validity(cpu, addr, &phys_addr, 0);
5636 if (fault) goto MMU_EXCEPTION;
5637 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32);
5638 if (fault) goto MMU_EXCEPTION;
5639 addr += 4;
5640 phys_addr += 4;
5641 } else {
5642 fault = check_address_validity(cpu, addr, &phys_addr, 0);
5643 if (fault) goto MMU_EXCEPTION;
5644 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg_usr[1], 32);
5645 if (fault) goto MMU_EXCEPTION;
5646 addr += 4;
5647 phys_addr += 4;
5648 }
5649 }
5650 if (BIT(inst_cream->inst, 15)) {
5651 fault = check_address_validity(cpu, addr, &phys_addr, 0);
5652 if (fault) goto MMU_EXCEPTION;
5653 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i] + 8, 32);
5654 if (fault) goto MMU_EXCEPTION;
5655 }
5656 } else {
5657 for( i = 0; i < 15; i ++ ) {
5658 if(BIT(inst_cream->inst, i)) {
5659 fault = check_address_validity(cpu, addr, &phys_addr, 0);
5660 if (fault) goto MMU_EXCEPTION;
5661 if(i == Rn)
5662 fault = interpreter_write_memory(addr, phys_addr, old_RN, 32);
5663 else
5664 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i], 32);
5665 if (fault) goto MMU_EXCEPTION;
5666 addr += 4;
5667 phys_addr += 4;
5668 }
5669 }
5670
5671 // Check PC reg
5672 if(BIT(inst_cream->inst, i)) {
5673 fault = check_address_validity(cpu, addr, &phys_addr, 0);
5674 if (fault) goto MMU_EXCEPTION;
5675 fault = interpreter_write_memory(addr, phys_addr, cpu->Reg[i] + 8, 32);
5676 if (fault) goto MMU_EXCEPTION;
5677 }
5678 }
5679 }
5680 cpu->Reg[15] += GET_INST_SIZE(cpu);
5681 INC_PC(sizeof(ldst_inst));
5682 FETCH_INST;
5683 GOTO_NEXT_INST;
5684 }
5685 SXTB_INST:
5686 {
5687 sxtb_inst *inst_cream = (sxtb_inst *)inst_base->component;
5688 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5689 if (inst_cream->Rm == 15) {
5690 LOG_ERROR(Core_ARM11, "invalid operand for SXTB");
5691 CITRA_IGNORE_EXIT(-1);
5692 }
5693 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate);
5694 if (BIT(operand2, 7)) {
5695 operand2 |= 0xffffff00;
5696 } else
5697 operand2 &= 0xff;
5698 RD = operand2;
5699 }
5700 cpu->Reg[15] += GET_INST_SIZE(cpu);
5701 INC_PC(sizeof(sxtb_inst));
5702 FETCH_INST;
5703 GOTO_NEXT_INST;
5704 }
5705 STR_INST:
5706 {
5707 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
5708 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5709 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
5710 if (fault) goto MMU_EXCEPTION;
5711 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)];
5712 fault = interpreter_write_memory(addr, phys_addr, value, 32);
5713 if (fault) goto MMU_EXCEPTION;
5714 }
5715 cpu->Reg[15] += GET_INST_SIZE(cpu);
5716 INC_PC(sizeof(ldst_inst));
5717 FETCH_INST;
5718 GOTO_NEXT_INST;
5719 }
5720 UXTB_INST:
5721 {
5722 uxtb_inst *inst_cream = (uxtb_inst *)inst_base->component;
5723 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5724 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate)
5725 & 0xff;
5726 RD = operand2;
5727 }
5728 cpu->Reg[15] += GET_INST_SIZE(cpu);
5729 INC_PC(sizeof(uxtb_inst));
5730 FETCH_INST;
5731 GOTO_NEXT_INST;
5732 }
5733 UXTAB_INST:
5734 {
5735 uxtab_inst *inst_cream = (uxtab_inst *)inst_base->component;
5736 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5737 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate)
5738 & 0xff;
5739 RD = RN + operand2;
5740 }
5741 cpu->Reg[15] += GET_INST_SIZE(cpu);
5742 INC_PC(sizeof(uxtab_inst));
5743 FETCH_INST;
5744 GOTO_NEXT_INST;
5745 }
5746 STRB_INST:
5747 {
5748 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
5749 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5750 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
5751 if (fault) goto MMU_EXCEPTION;
5752 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff;
5753 fault = interpreter_write_memory(addr, phys_addr, value, 8);
5754 if (fault) goto MMU_EXCEPTION;
5755 }
5756 cpu->Reg[15] += GET_INST_SIZE(cpu);
5757 INC_PC(sizeof(ldst_inst));
5758 FETCH_INST;
5759 GOTO_NEXT_INST;
5760 }
5761 STRBT_INST:
5762 {
5763 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
5764 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5765 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
5766 if (fault) goto MMU_EXCEPTION;
5767 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xff;
5768 fault = interpreter_write_memory(addr, phys_addr, value, 8);
5769 if (fault) goto MMU_EXCEPTION;
5770 }
5771 cpu->Reg[15] += GET_INST_SIZE(cpu);
5772 INC_PC(sizeof(ldst_inst));
5773 FETCH_INST;
5774 GOTO_NEXT_INST;
5775 }
5776 STRD_INST:
5777 {
5778 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
5779 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
5780 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
5781 if (fault) goto MMU_EXCEPTION;
5782 uint32_t rear_phys_addr;
5783 fault = check_address_validity(cpu, addr + 4, &rear_phys_addr, 0);
6089 if (fault){ 5784 if (fault){
6090 ERROR_LOG(ARM11, "mmu fault , should rollback the above get_addr\n"); 5785 LOG_ERROR(Core_ARM11, "MMU fault , should rollback the above get_addr");
6091 CITRA_IGNORE_EXIT(-1); 5786 CITRA_IGNORE_EXIT(-1);
6092 goto MMU_EXCEPTION; 5787 goto MMU_EXCEPTION;
6093 } 5788 }
6094 5789
6095 //fault = inst_cream->get_addr(cpu, inst_cream->inst, addr + 4, phys_addr + 4, 0); 5790 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)];
6096 //if (fault) goto MMU_EXCEPTION; 5791 fault = interpreter_write_memory(addr, phys_addr, value, 32);
6097 5792 if (fault) goto MMU_EXCEPTION;
6098 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; 5793 value = cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1];
6099 //bus_write(32, addr, value); 5794 fault = interpreter_write_memory(addr + 4, rear_phys_addr, value, 32);
6100 fault = interpreter_write_memory(addr, phys_addr, value, 32); 5795 if (fault) goto MMU_EXCEPTION;
6101 if (fault) goto MMU_EXCEPTION; 5796 }
6102 value = cpu->Reg[BITS(inst_cream->inst, 12, 15) + 1]; 5797 cpu->Reg[15] += GET_INST_SIZE(cpu);
6103 //bus_write(32, addr, value); 5798 INC_PC(sizeof(ldst_inst));
6104 fault = interpreter_write_memory(addr + 4, rear_phys_addr, value, 32); 5799 FETCH_INST;
6105 if (fault) goto MMU_EXCEPTION; 5800 GOTO_NEXT_INST;
6106 } 5801 }
6107 cpu->Reg[15] += GET_INST_SIZE(cpu); 5802 STREX_INST:
6108 INC_PC(sizeof(ldst_inst)); 5803 {
6109 FETCH_INST; 5804 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
6110 GOTO_NEXT_INST; 5805 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6111 } 5806 addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)];
6112 STREX_INST: 5807 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 0, 3)];
6113 { 5808 fault = check_address_validity(cpu, addr, &phys_addr, 0);
6114 INC_ICOUNTER; 5809 if (fault) goto MMU_EXCEPTION;
6115 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 5810
6116 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5811 int dest_reg = BITS(inst_cream->inst, 12, 15);
6117 addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)]; 5812 if((exclusive_detect(cpu, phys_addr) == 0) && (cpu->exclusive_state == 1)){
6118 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 0, 3)]; 5813 remove_exclusive(cpu, phys_addr);
6119 fault = check_address_validity(cpu, addr, &phys_addr, 0); 5814 cpu->Reg[dest_reg] = 0;
6120 if (fault) goto MMU_EXCEPTION; 5815 cpu->exclusive_state = 0;
6121 5816
6122 int dest_reg = BITS(inst_cream->inst, 12, 15); 5817 fault = interpreter_write_memory(addr, phys_addr, value, 32);
6123 if((exclusive_detect(cpu, phys_addr) == 0) && (cpu->exclusive_state == 1)){ 5818 if (fault) goto MMU_EXCEPTION;
6124 remove_exclusive(cpu, phys_addr); 5819 } else {
6125 cpu->Reg[dest_reg] = 0; 5820 // Failed to write due to mutex access
6126 cpu->exclusive_state = 0; 5821 cpu->Reg[dest_reg] = 1;
6127 5822 }
6128 // bus_write(32, addr, value); 5823 }
6129 fault = interpreter_write_memory(addr, phys_addr, value, 32); 5824 cpu->Reg[15] += GET_INST_SIZE(cpu);
6130 if (fault) goto MMU_EXCEPTION; 5825 INC_PC(sizeof(ldst_inst));
6131 } 5826 FETCH_INST;
6132 else{ 5827 GOTO_NEXT_INST;
6133 /* Failed to write due to mutex access */ 5828 }
6134 cpu->Reg[dest_reg] = 1; 5829 STREXB_INST:
6135 } 5830 {
6136 } 5831 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
6137 cpu->Reg[15] += GET_INST_SIZE(cpu); 5832 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6138 INC_PC(sizeof(ldst_inst)); 5833 addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)];
6139 FETCH_INST; 5834 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 0, 3)] & 0xff;
6140 GOTO_NEXT_INST; 5835 fault = check_address_validity(cpu, addr, &phys_addr, 0);
6141 } 5836 if (fault) goto MMU_EXCEPTION;
6142 STREXB_INST: 5837 int dest_reg = BITS(inst_cream->inst, 12, 15);
6143 { 5838 if((exclusive_detect(cpu, phys_addr) == 0) && (cpu->exclusive_state == 1)){
6144 INC_ICOUNTER; 5839 remove_exclusive(cpu, phys_addr);
6145 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 5840 cpu->Reg[dest_reg] = 0;
6146 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5841 cpu->exclusive_state = 0;
6147 addr = cpu->Reg[BITS(inst_cream->inst, 16, 19)]; 5842 fault = interpreter_write_memory(addr, phys_addr, value, 8);
6148 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 0, 3)] & 0xff; 5843 if (fault) goto MMU_EXCEPTION;
6149 fault = check_address_validity(cpu, addr, &phys_addr, 0); 5844 } else {
6150 if (fault) goto MMU_EXCEPTION; 5845 cpu->Reg[dest_reg] = 1;
6151 //bus_write(8, addr, value); 5846 }
6152 int dest_reg = BITS(inst_cream->inst, 12, 15); 5847 }
6153 if((exclusive_detect(cpu, phys_addr) == 0) && (cpu->exclusive_state == 1)){ 5848 cpu->Reg[15] += GET_INST_SIZE(cpu);
6154 remove_exclusive(cpu, phys_addr); 5849 INC_PC(sizeof(ldst_inst));
6155 cpu->Reg[dest_reg] = 0; 5850 FETCH_INST;
6156 cpu->exclusive_state = 0; 5851 GOTO_NEXT_INST;
6157 fault = interpreter_write_memory(addr, phys_addr, value, 8); 5852 }
6158 if (fault) goto MMU_EXCEPTION; 5853 STRH_INST:
6159 5854 {
6160 } 5855 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
6161 else{ 5856 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6162 cpu->Reg[dest_reg] = 1; 5857 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
6163 } 5858 if (fault) goto MMU_EXCEPTION;
6164 } 5859 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xffff;
6165 cpu->Reg[15] += GET_INST_SIZE(cpu); 5860 fault = interpreter_write_memory(addr, phys_addr, value, 16);
6166 INC_PC(sizeof(ldst_inst)); 5861 if (fault) goto MMU_EXCEPTION;
6167 FETCH_INST; 5862 }
6168 GOTO_NEXT_INST; 5863 cpu->Reg[15] += GET_INST_SIZE(cpu);
6169 } 5864 INC_PC(sizeof(ldst_inst));
6170 STRH_INST: 5865 FETCH_INST;
6171 { 5866 GOTO_NEXT_INST;
6172 INC_ICOUNTER; 5867 }
6173 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 5868 STRT_INST:
6174 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5869 {
6175 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); 5870 ldst_inst *inst_cream = (ldst_inst *)inst_base->component;
6176 if (fault) goto MMU_EXCEPTION; 5871 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6177 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)] & 0xffff; 5872 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0);
6178 //bus_write(16, addr, value); 5873 if (fault) goto MMU_EXCEPTION;
6179 fault = interpreter_write_memory(addr, phys_addr, value, 16); 5874 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)];
6180 if (fault) goto MMU_EXCEPTION; 5875 fault = interpreter_write_memory(addr, phys_addr, value, 32);
6181 } 5876 if (fault) goto MMU_EXCEPTION;
6182 cpu->Reg[15] += GET_INST_SIZE(cpu); 5877 }
6183 //if (BITS(inst_cream->inst, 12, 15) == 15) 5878 cpu->Reg[15] += GET_INST_SIZE(cpu);
6184 // goto DISPATCH; 5879 INC_PC(sizeof(ldst_inst));
6185 INC_PC(sizeof(ldst_inst)); 5880 FETCH_INST;
6186 FETCH_INST; 5881 GOTO_NEXT_INST;
6187 GOTO_NEXT_INST; 5882 }
6188 } 5883 SUB_INST:
6189 STRT_INST: 5884 {
6190 { 5885 sub_inst *inst_cream = (sub_inst *)inst_base->component;
6191 INC_ICOUNTER; 5886 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6192 ldst_inst *inst_cream = (ldst_inst *)inst_base->component; 5887 lop = RN;
6193 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5888 if (inst_cream->Rn == 15) {
6194 fault = inst_cream->get_addr(cpu, inst_cream->inst, addr, phys_addr, 0); 5889 lop += 8;
6195 if (fault) goto MMU_EXCEPTION; 5890 }
6196 unsigned int value = cpu->Reg[BITS(inst_cream->inst, 12, 15)]; 5891 rop = SHIFTER_OPERAND;
6197 //bus_write(16, addr, value); 5892 RD = dst = lop - rop;
6198 fault = interpreter_write_memory(addr, phys_addr, value, 32); 5893 if (inst_cream->S && (inst_cream->Rd == 15)) {
6199 if (fault) goto MMU_EXCEPTION; 5894 if (CurrentModeHasSPSR) {
6200 } 5895 cpu->Cpsr = cpu->Spsr_copy;
6201 cpu->Reg[15] += GET_INST_SIZE(cpu); 5896 switch_mode(cpu, cpu->Spsr_copy & 0x1f);
6202 INC_PC(sizeof(ldst_inst)); 5897 LOAD_NZCVT;
6203 FETCH_INST; 5898 }
6204 GOTO_NEXT_INST; 5899 } else if (inst_cream->S) {
6205 } 5900 UPDATE_NFLAG(dst);
6206 SUB_INST: 5901 UPDATE_ZFLAG(dst);
6207 { 5902 UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop);
6208 INC_ICOUNTER; 5903 UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop);
6209 sub_inst *inst_cream = (sub_inst *)inst_base->component; 5904 }
6210 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5905 if (inst_cream->Rd == 15) {
6211 lop = RN; 5906 INC_PC(sizeof(sub_inst));
6212 if (inst_cream->Rn == 15) { 5907 goto DISPATCH;
6213 lop += 8; 5908 }
6214 } 5909 }
6215 rop = SHIFTER_OPERAND; 5910 cpu->Reg[15] += GET_INST_SIZE(cpu);
6216 RD = dst = lop - rop; 5911 INC_PC(sizeof(sub_inst));
6217 if (inst_cream->S && (inst_cream->Rd == 15)) { 5912 FETCH_INST;
6218 /* cpsr = spsr */ 5913 GOTO_NEXT_INST;
6219 if (CurrentModeHasSPSR) { 5914 }
6220 cpu->Cpsr = cpu->Spsr_copy; 5915 SWI_INST:
6221 switch_mode(cpu, cpu->Spsr_copy & 0x1f); 5916 {
6222 LOAD_NZCVT; 5917 swi_inst *inst_cream = (swi_inst *)inst_base->component;
6223 } 5918
6224 } else if (inst_cream->S) { 5919 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond))
6225 UPDATE_NFLAG(dst); 5920 HLE::CallSVC(Memory::Read32(cpu->Reg[15]));
6226 UPDATE_ZFLAG(dst); 5921
6227// UPDATE_CFLAG(dst, lop, rop); 5922 cpu->Reg[15] += GET_INST_SIZE(cpu);
6228 UPDATE_CFLAG_NOT_BORROW_FROM(lop, rop); 5923 INC_PC(sizeof(swi_inst));
6229 // UPDATE_VFLAG((int)dst, (int)lop, (int)rop); 5924 FETCH_INST;
6230 UPDATE_VFLAG_OVERFLOW_FROM(dst, lop, rop); 5925 GOTO_NEXT_INST;
6231 } 5926 }
6232 if (inst_cream->Rd == 15) { 5927 SWP_INST:
6233 INC_PC(sizeof(sub_inst)); 5928 {
6234 goto DISPATCH; 5929 swp_inst *inst_cream = (swp_inst *)inst_base->component;
6235 } 5930 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6236 } 5931 addr = RN;
6237 cpu->Reg[15] += GET_INST_SIZE(cpu); 5932 fault = check_address_validity(cpu, addr, &phys_addr, 1);
6238 INC_PC(sizeof(sub_inst)); 5933 if (fault) goto MMU_EXCEPTION;
6239 FETCH_INST; 5934 unsigned int value;
6240 GOTO_NEXT_INST; 5935 fault = interpreter_read_memory(addr, phys_addr, value, 32);
6241 } 5936 if (fault) goto MMU_EXCEPTION;
6242 SWI_INST: 5937 fault = interpreter_write_memory(addr, phys_addr, RM, 32);
6243 { 5938 if (fault) goto MMU_EXCEPTION;
6244 INC_ICOUNTER; 5939
6245 swi_inst *inst_cream = (swi_inst *)inst_base->component; 5940 assert((phys_addr & 0x3) == 0);
6246 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5941 RD = value;
6247 if (true){ //if (core->is_user_mode) { --> Citra only emulates user mode 5942 }
6248 //arm_dyncom_SWI(cpu, inst_cream->num); 5943 cpu->Reg[15] += GET_INST_SIZE(cpu);
6249 HLE::CallSVC(Memory::Read32(cpu->Reg[15])); 5944 INC_PC(sizeof(swp_inst));
6250 } else { 5945 FETCH_INST;
6251 cpu->syscallSig = 1; 5946 GOTO_NEXT_INST;
6252 goto END; 5947 }
6253 } 5948 SWPB_INST:
6254 } 5949 {
6255 cpu->Reg[15] += GET_INST_SIZE(cpu); 5950 swp_inst *inst_cream = (swp_inst *)inst_base->component;
6256 INC_PC(sizeof(swi_inst)); 5951 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6257 FETCH_INST; 5952 addr = RN;
6258 GOTO_NEXT_INST; 5953 fault = check_address_validity(cpu, addr, &phys_addr, 1);
6259 } 5954 if (fault) goto MMU_EXCEPTION;
6260 SWP_INST: 5955 unsigned int value;
6261 { 5956 fault = interpreter_read_memory(addr, phys_addr, value, 8);
6262 INC_ICOUNTER; 5957 if (fault) goto MMU_EXCEPTION;
6263 swp_inst *inst_cream = (swp_inst *)inst_base->component; 5958 fault = interpreter_write_memory(addr, phys_addr, (RM & 0xFF), 8);
6264 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5959 if (fault) goto MMU_EXCEPTION;
6265 addr = RN; 5960 }
6266 fault = check_address_validity(cpu, addr, &phys_addr, 1); 5961 cpu->Reg[15] += GET_INST_SIZE(cpu);
6267 if (fault) goto MMU_EXCEPTION; 5962 INC_PC(sizeof(swp_inst));
6268 unsigned int value; 5963 FETCH_INST;
6269 fault = interpreter_read_memory(addr, phys_addr, value, 32); 5964 GOTO_NEXT_INST;
6270 if (fault) goto MMU_EXCEPTION; 5965 }
6271 fault = interpreter_write_memory(addr, phys_addr, RM, 32); 5966 SXTAB_INST:
6272 if (fault) goto MMU_EXCEPTION; 5967 {
6273 5968 sxtab_inst *inst_cream = (sxtab_inst *)inst_base->component;
6274 /* ROR(data, 8*UInt(address<1:0>)); */ 5969 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6275 assert((phys_addr & 0x3) == 0); 5970 // R15 should be check
6276 RD = value; 5971 if(inst_cream->Rn == 15 || inst_cream->Rm == 15 || inst_cream->Rd ==15){
6277 } 5972 CITRA_IGNORE_EXIT(-1);
6278 cpu->Reg[15] += GET_INST_SIZE(cpu); 5973 }
6279 INC_PC(sizeof(swp_inst)); 5974 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xff;
6280 FETCH_INST; 5975
6281 GOTO_NEXT_INST; 5976 // Sign extend for byte
6282 } 5977 operand2 = (0x80 & operand2)? (0xFFFFFF00 | operand2):operand2;
6283 SWPB_INST: 5978 RD = RN + operand2;
6284 { 5979 }
6285 INC_ICOUNTER; 5980 cpu->Reg[15] += GET_INST_SIZE(cpu);
6286 swp_inst *inst_cream = (swp_inst *)inst_base->component; 5981 INC_PC(sizeof(uxtab_inst));
6287 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 5982 FETCH_INST;
6288 addr = RN; 5983 GOTO_NEXT_INST;
6289 fault = check_address_validity(cpu, addr, &phys_addr, 1); 5984 }
6290 if (fault) goto MMU_EXCEPTION; 5985 SXTAB16_INST:
6291 unsigned int value; 5986 SXTAH_INST:
6292 fault = interpreter_read_memory(addr, phys_addr, value, 8); 5987 {
6293 if (fault) goto MMU_EXCEPTION; 5988 sxtah_inst *inst_cream = (sxtah_inst *)inst_base->component;
6294 fault = interpreter_write_memory(addr, phys_addr, (RM & 0xFF), 8); 5989 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6295 if (fault) goto MMU_EXCEPTION; 5990 // R15 should be check
6296 5991 if(inst_cream->Rn == 15 || inst_cream->Rm == 15 || inst_cream->Rd ==15) {
6297 /* FIXME */ 5992 CITRA_IGNORE_EXIT(-1);
6298 #if 0 5993 }
6299 if Shared(address) then 5994 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff;
6300 /* ARMv6 */ 5995 // Sign extend for half
6301 physical_address = TLB(address) 5996 operand2 = (0x8000 & operand2) ? (0xFFFF0000 | operand2) : operand2;
6302 ClearExclusiveByAddress(physical_address,processor_id,1) 5997 RD = RN + operand2;
6303 /* See Summary of operation on page A2-49 */ 5998 }
6304 #endif 5999 cpu->Reg[15] += GET_INST_SIZE(cpu);
6305 } 6000 INC_PC(sizeof(sxtah_inst));
6306 cpu->Reg[15] += GET_INST_SIZE(cpu); 6001 FETCH_INST;
6307 INC_PC(sizeof(swp_inst)); 6002 GOTO_NEXT_INST;
6308 FETCH_INST; 6003 }
6309 GOTO_NEXT_INST; 6004 SXTB16_INST:
6310 } 6005 TEQ_INST:
6311 SXTAB_INST: 6006 {
6312 { 6007 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6313 INC_ICOUNTER; 6008 teq_inst *inst_cream = (teq_inst *)inst_base->component;
6314 sxtab_inst *inst_cream = (sxtab_inst *)inst_base->component; 6009 lop = RN;
6315 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 6010
6316 /* R15 should be check */ 6011 if (inst_cream->Rn == 15)
6317 if(inst_cream->Rn == 15 || inst_cream->Rm == 15 || inst_cream->Rd ==15){ 6012 lop += GET_INST_SIZE(cpu) * 2;
6318 CITRA_IGNORE_EXIT(-1); 6013
6319 } 6014 rop = SHIFTER_OPERAND;
6320 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) 6015 dst = lop ^ rop;
6321 & 0xff; 6016
6322 /* sign extend for byte */ 6017 UPDATE_NFLAG(dst);
6323 operand2 = (0x80 & operand2)? (0xFFFFFF00 | operand2):operand2; 6018 UPDATE_ZFLAG(dst);
6324 RD = RN + operand2; 6019 UPDATE_CFLAG_WITH_SC;
6325 } 6020 }
6326 cpu->Reg[15] += GET_INST_SIZE(cpu); 6021 cpu->Reg[15] += GET_INST_SIZE(cpu);
6327 INC_PC(sizeof(uxtab_inst)); 6022 INC_PC(sizeof(teq_inst));
6328 FETCH_INST; 6023 FETCH_INST;
6329 GOTO_NEXT_INST; 6024 GOTO_NEXT_INST;
6330 } 6025 }
6331 SXTAB16_INST: 6026 TST_INST:
6332 SXTAH_INST: 6027 {
6333 { 6028 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6334 INC_ICOUNTER; 6029 tst_inst *inst_cream = (tst_inst *)inst_base->component;
6335 sxtah_inst *inst_cream = (sxtah_inst *)inst_base->component; 6030 lop = RN;
6336 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 6031
6337 /* R15 should be check */ 6032 if (inst_cream->Rn == 15)
6338 if(inst_cream->Rn == 15 || inst_cream->Rm == 15 || inst_cream->Rd ==15){ 6033 lop += GET_INST_SIZE(cpu) * 2;
6339 CITRA_IGNORE_EXIT(-1); 6034
6340 } 6035 rop = SHIFTER_OPERAND;
6341 unsigned int operand2 = ROTATE_RIGHT_32(RM, 8 * inst_cream->rotate) & 0xffff; 6036 dst = lop & rop;
6342 /* sign extend for half */ 6037
6343 operand2 = (0x8000 & operand2)? (0xFFFF0000 | operand2):operand2; 6038 UPDATE_NFLAG(dst);
6344 RD = RN + operand2; 6039 UPDATE_ZFLAG(dst);
6345 } 6040 UPDATE_CFLAG_WITH_SC;
6346 cpu->Reg[15] += GET_INST_SIZE(cpu); 6041 }
6347 INC_PC(sizeof(sxtah_inst)); 6042 cpu->Reg[15] += GET_INST_SIZE(cpu);
6348 FETCH_INST; 6043 INC_PC(sizeof(tst_inst));
6349 GOTO_NEXT_INST; 6044 FETCH_INST;
6350 } 6045 GOTO_NEXT_INST;
6351 SXTB16_INST: 6046 }
6352 TEQ_INST: 6047 UADD8_INST:
6353 { 6048 UADD16_INST:
6354 INC_ICOUNTER; 6049 UADDSUBX_INST:
6355 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 6050
6356 teq_inst *inst_cream = (teq_inst *)inst_base->component; 6051 UHADD8_INST:
6357 lop = RN; 6052 UHADD16_INST:
6358 if (inst_cream->Rn == 15) 6053 UHADDSUBX_INST:
6359 lop += GET_INST_SIZE(cpu) * 2; 6054 UHSUBADDX_INST:
6360 6055 UHSUB8_INST:
6361 rop = SHIFTER_OPERAND; 6056 UHSUB16_INST:
6362 dst = lop ^ rop; 6057 {
6363 6058 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
6364 UPDATE_NFLAG(dst); 6059 generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
6365 UPDATE_ZFLAG(dst); 6060 const u32 rm_val = RM;
6366 UPDATE_CFLAG_WITH_SC; 6061 const u32 rn_val = RN;
6367 } 6062 const u8 op2 = inst_cream->op2;
6368 cpu->Reg[15] += GET_INST_SIZE(cpu); 6063
6369 INC_PC(sizeof(teq_inst)); 6064 if (op2 == 0x00 || op2 == 0x01 || op2 == 0x02 || op2 == 0x03)
6370 FETCH_INST; 6065 {
6371 GOTO_NEXT_INST; 6066 u32 lo_val = 0;
6372 } 6067 u32 hi_val = 0;
6373 TST_INST: 6068
6374 { 6069 // UHADD16
6375 INC_ICOUNTER; 6070 if (op2 == 0x00) {
6376 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 6071 lo_val = (rn_val & 0xFFFF) + (rm_val & 0xFFFF);
6377 tst_inst *inst_cream = (tst_inst *)inst_base->component; 6072 hi_val = ((rn_val >> 16) & 0xFFFF) + ((rm_val >> 16) & 0xFFFF);
6378 lop = RN; 6073 }
6379 if (inst_cream->Rn == 15) 6074 // UHASX
6380 lop += GET_INST_SIZE(cpu) * 2; 6075 else if (op2 == 0x01) {
6381 rop = SHIFTER_OPERAND; 6076 lo_val = (rn_val & 0xFFFF) - ((rm_val >> 16) & 0xFFFF);
6382 dst = lop & rop; 6077 hi_val = ((rn_val >> 16) & 0xFFFF) + (rm_val & 0xFFFF);
6383 6078 }
6384 UPDATE_NFLAG(dst); 6079 // UHSAX
6385 UPDATE_ZFLAG(dst); 6080 else if (op2 == 0x02) {
6386 UPDATE_CFLAG_WITH_SC; 6081 lo_val = (rn_val & 0xFFFF) + ((rm_val >> 16) & 0xFFFF);
6387 } 6082 hi_val = ((rn_val >> 16) & 0xFFFF) - (rm_val & 0xFFFF);
6388 cpu->Reg[15] += GET_INST_SIZE(cpu); 6083 }
6389 INC_PC(sizeof(tst_inst)); 6084 // UHSUB16
6390 FETCH_INST; 6085 else if (op2 == 0x03) {
6391 GOTO_NEXT_INST; 6086 lo_val = (rn_val & 0xFFFF) - (rm_val & 0xFFFF);
6392 } 6087 hi_val = ((rn_val >> 16) & 0xFFFF) - ((rm_val >> 16) & 0xFFFF);
6393 UADD16_INST: 6088 }
6394 UADD8_INST: 6089
6395 UADDSUBX_INST: 6090 lo_val >>= 1;
6396 UHADD16_INST: 6091 hi_val >>= 1;
6397 UHADD8_INST: 6092
6398 UHADDSUBX_INST: 6093 RD = (lo_val & 0xFFFF) | ((hi_val & 0xFFFF) << 16);
6399 UHSUB16_INST: 6094 }
6400 UHSUB8_INST: 6095 else if (op2 == 0x04 || op2 == 0x07) {
6401 UHSUBADDX_INST: 6096 u32 sum1;
6402 UMAAL_INST: 6097 u32 sum2;
6403 UMLAL_INST: 6098 u32 sum3;
6404 { 6099 u32 sum4;
6405 INC_ICOUNTER; 6100
6406 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 6101 // UHADD8
6407 umlal_inst *inst_cream = (umlal_inst *)inst_base->component; 6102 if (op2 == 0x04) {
6408 unsigned long long int rm = RM; 6103 sum1 = (rn_val & 0xFF) + (rm_val & 0xFF);
6409 unsigned long long int rs = RS; 6104 sum2 = ((rn_val >> 8) & 0xFF) + ((rm_val >> 8) & 0xFF);
6410 unsigned long long int rst = rm * rs; 6105 sum3 = ((rn_val >> 16) & 0xFF) + ((rm_val >> 16) & 0xFF);
6411 unsigned long long int add = ((unsigned long long) RDHI)<<32; 6106 sum4 = ((rn_val >> 24) & 0xFF) + ((rm_val >> 24) & 0xFF);
6412 add += RDLO; 6107 }
6413 //DEBUG_LOG(ARM11, "rm[%llx] * rs[%llx] = rst[%llx] | add[%llx]\n", RM, RS, rst, add); 6108 // UHSUB8
6414 rst += add; 6109 else {
6415 RDLO = BITS(rst, 0, 31); 6110 sum1 = (rn_val & 0xFF) - (rm_val & 0xFF);
6416 RDHI = BITS(rst, 32, 63); 6111 sum2 = ((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF);
6417 6112 sum3 = ((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF);
6418 if (inst_cream->S) 6113 sum4 = ((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF);
6419 { 6114 }
6420 cpu->NFlag = BIT(RDHI, 31); 6115
6421 cpu->ZFlag = (RDHI == 0 && RDLO == 0); 6116 sum1 >>= 1;
6422 } 6117 sum2 >>= 1;
6423 } 6118 sum3 >>= 1;
6424 cpu->Reg[15] += GET_INST_SIZE(cpu); 6119 sum4 >>= 1;
6425 INC_PC(sizeof(umlal_inst)); 6120
6426 FETCH_INST; 6121 RD = (sum1 & 0xFF) | ((sum2 & 0xFF) << 8) | ((sum3 & 0xFF) << 16) | ((sum4 & 0xFF) << 24);
6427 GOTO_NEXT_INST; 6122 }
6428 } 6123 }
6429 UMULL_INST: 6124
6430 { 6125 cpu->Reg[15] += GET_INST_SIZE(cpu);
6431 INC_ICOUNTER; 6126 INC_PC(sizeof(generic_arm_inst));
6432 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 6127 FETCH_INST;
6433 umull_inst *inst_cream = (umull_inst *)inst_base->component; 6128 GOTO_NEXT_INST;
6434 unsigned long long int rm = RM; 6129 }
6435 unsigned long long int rs = RS; 6130
6436 unsigned long long int rst = rm * rs; 6131 UMAAL_INST:
6437// DEBUG_LOG(ARM11, "rm : [%llx] rs : [%llx] rst [%llx]\n", RM, RS, rst); 6132 {
6438 RDHI = BITS(rst, 32, 63); 6133 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
6439 RDLO = BITS(rst, 0, 31); 6134 umaal_inst* const inst_cream = (umaal_inst*)inst_base->component;
6440 6135 const u32 rm = RM;
6441 if (inst_cream->S) { 6136 const u32 rn = RN;
6442 cpu->NFlag = BIT(RDHI, 31); 6137 const u32 rd_lo = RDLO;
6443 cpu->ZFlag = (RDHI == 0 && RDLO == 0); 6138 const u32 rd_hi = RDHI;
6444 } 6139 const u64 result = (rm * rn) + rd_lo + rd_hi;
6445 } 6140
6446 cpu->Reg[15] += GET_INST_SIZE(cpu); 6141 RDLO = (result & 0xFFFFFFFF);
6447 INC_PC(sizeof(umull_inst)); 6142 RDHI = ((result >> 32) & 0xFFFFFFFF);
6448 FETCH_INST; 6143 }
6449 GOTO_NEXT_INST; 6144 cpu->Reg[15] += GET_INST_SIZE(cpu);
6450 } 6145 INC_PC(sizeof(umaal_inst));
6451 B_2_THUMB: 6146 FETCH_INST;
6452 { 6147 GOTO_NEXT_INST;
6453 INC_ICOUNTER; 6148 }
6454 b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component; 6149 UMLAL_INST:
6455 cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm; 6150 {
6456 //DEBUG_LOG(ARM11, " BL_1_THUMB: imm=0x%x, r14=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]); 6151 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6457 INC_PC(sizeof(b_2_thumb)); 6152 umlal_inst *inst_cream = (umlal_inst *)inst_base->component;
6458 goto DISPATCH; 6153 unsigned long long int rm = RM;
6459 } 6154 unsigned long long int rs = RS;
6460 B_COND_THUMB: 6155 unsigned long long int rst = rm * rs;
6461 { 6156 unsigned long long int add = ((unsigned long long) RDHI)<<32;
6462 INC_ICOUNTER; 6157 add += RDLO;
6463 b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component; 6158 rst += add;
6464 if(CondPassed(cpu, inst_cream->cond)) 6159 RDLO = BITS(rst, 0, 31);
6465 cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm; 6160 RDHI = BITS(rst, 32, 63);
6466 else 6161
6467 cpu->Reg[15] += 2; 6162 if (inst_cream->S) {
6468 //DEBUG_LOG(ARM11, " B_COND_THUMB: imm=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[15]); 6163 cpu->NFlag = BIT(RDHI, 31);
6469 INC_PC(sizeof(b_cond_thumb)); 6164 cpu->ZFlag = (RDHI == 0 && RDLO == 0);
6470 goto DISPATCH; 6165 }
6471 } 6166 }
6472 BL_1_THUMB: 6167 cpu->Reg[15] += GET_INST_SIZE(cpu);
6473 { 6168 INC_PC(sizeof(umlal_inst));
6474 INC_ICOUNTER; 6169 FETCH_INST;
6475 bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component; 6170 GOTO_NEXT_INST;
6476 cpu->Reg[14] = cpu->Reg[15] + 4 + inst_cream->imm; 6171 }
6477 //cpu->Reg[15] += 2; 6172 UMULL_INST:
6478 //DEBUG_LOG(ARM11, " BL_1_THUMB: imm=0x%x, r14=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]); 6173 {
6479 6174 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
6480 cpu->Reg[15] += GET_INST_SIZE(cpu); 6175 umull_inst *inst_cream = (umull_inst *)inst_base->component;
6481 INC_PC(sizeof(bl_1_thumb)); 6176 unsigned long long int rm = RM;
6482 FETCH_INST; 6177 unsigned long long int rs = RS;
6483 GOTO_NEXT_INST; 6178 unsigned long long int rst = rm * rs;
6484 6179 RDHI = BITS(rst, 32, 63);
6485 } 6180 RDLO = BITS(rst, 0, 31);
6486 BL_2_THUMB: 6181
6487 { 6182 if (inst_cream->S) {
6488 INC_ICOUNTER; 6183 cpu->NFlag = BIT(RDHI, 31);
6489 bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component; 6184 cpu->ZFlag = (RDHI == 0 && RDLO == 0);
6490 int tmp = ((cpu->Reg[15] + 2) | 1); 6185 }
6491 cpu->Reg[15] = 6186 }
6492 (cpu->Reg[14] + inst_cream->imm); 6187 cpu->Reg[15] += GET_INST_SIZE(cpu);
6493 cpu->Reg[14] = tmp; 6188 INC_PC(sizeof(umull_inst));
6494 //DEBUG_LOG(ARM11, " BL_2_THUMB: imm=0x%x, r14=0x%x, r15=0x%x\n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]); 6189 FETCH_INST;
6495 INC_PC(sizeof(bl_2_thumb)); 6190 GOTO_NEXT_INST;
6496 goto DISPATCH; 6191 }
6497 } 6192 B_2_THUMB:
6498 BLX_1_THUMB: 6193 {
6499 { 6194 b_2_thumb *inst_cream = (b_2_thumb *)inst_base->component;
6500 /* BLX 1 for armv5t and above */ 6195 cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm;
6501 INC_ICOUNTER; 6196 INC_PC(sizeof(b_2_thumb));
6502 uint32 tmp = cpu->Reg[15]; 6197 goto DISPATCH;
6503 blx_1_thumb *inst_cream = (blx_1_thumb *)inst_base->component; 6198 }
6504 cpu->Reg[15] = (cpu->Reg[14] + inst_cream->imm) & 0xFFFFFFFC; 6199 B_COND_THUMB:
6505 //DEBUG_LOG(ARM11, "In BLX_1_THUMB, BLX(1),imm=0x%x,r14=0x%x, instr=0x%x\n", inst_cream->imm, cpu->Reg[14], inst_cream->instr); 6200 {
6506 cpu->Reg[14] = ((tmp + 2) | 1); 6201 b_cond_thumb *inst_cream = (b_cond_thumb *)inst_base->component;
6507 //(state->Reg[14] + ((tinstr & 0x07FF) << 1)) & 0xFFFFFFFC; 6202
6508 /* switch to arm state from thumb state */ 6203 if(CondPassed(cpu, inst_cream->cond))
6509 cpu->TFlag = 0; 6204 cpu->Reg[15] = cpu->Reg[15] + 4 + inst_cream->imm;
6510 //DEBUG_LOG(ARM11, "In BLX_1_THUMB, BLX(1),imm=0x%x,r14=0x%x, r15=0x%x, \n", inst_cream->imm, cpu->Reg[14], cpu->Reg[15]); 6205 else
6511 INC_PC(sizeof(blx_1_thumb)); 6206 cpu->Reg[15] += 2;
6512 goto DISPATCH; 6207
6513 } 6208 INC_PC(sizeof(b_cond_thumb));
6514 6209 goto DISPATCH;
6515 UQADD16_INST: 6210 }
6516 UQADD8_INST: 6211 BL_1_THUMB:
6517 UQADDSUBX_INST: 6212 {
6518 UQSUB16_INST: 6213 bl_1_thumb *inst_cream = (bl_1_thumb *)inst_base->component;
6519 UQSUB8_INST: 6214 cpu->Reg[14] = cpu->Reg[15] + 4 + inst_cream->imm;
6520 UQSUBADDX_INST: 6215 cpu->Reg[15] += GET_INST_SIZE(cpu);
6521 USAD8_INST: 6216 INC_PC(sizeof(bl_1_thumb));
6522 USADA8_INST: 6217 FETCH_INST;
6523 USAT_INST: 6218 GOTO_NEXT_INST;
6524 USAT16_INST: 6219 }
6525 USUB16_INST: 6220 BL_2_THUMB:
6526 USUB8_INST: 6221 {
6527 USUBADDX_INST: 6222 bl_2_thumb *inst_cream = (bl_2_thumb *)inst_base->component;
6528 UXTAB16_INST: 6223 int tmp = ((cpu->Reg[15] + 2) | 1);
6529 UXTB16_INST: 6224 cpu->Reg[15] = (cpu->Reg[14] + inst_cream->imm);
6530 #define VFP_INTERPRETER_IMPL 6225 cpu->Reg[14] = tmp;
6531 #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 6226 INC_PC(sizeof(bl_2_thumb));
6532 #undef VFP_INTERPRETER_IMPL 6227 goto DISPATCH;
6533 MMU_EXCEPTION: 6228 }
6534 { 6229 BLX_1_THUMB:
6535 SAVE_NZCVT; 6230 {
6536 cpu->abortSig = true; 6231 // BLX 1 for armv5t and above
6537 cpu->Aborted = ARMul_DataAbortV; 6232 uint32 tmp = cpu->Reg[15];
6538 cpu->AbortAddr = addr; 6233 blx_1_thumb *inst_cream = (blx_1_thumb *)inst_base->component;
6539 cpu->CP15[CP15(CP15_FAULT_STATUS)] = fault & 0xff; 6234 cpu->Reg[15] = (cpu->Reg[14] + inst_cream->imm) & 0xFFFFFFFC;
6540 cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = addr; 6235 cpu->Reg[14] = ((tmp + 2) | 1);
6541 cpu->NumInstrsToExecute = 0; 6236 cpu->TFlag = 0;
6542 return num_instrs; 6237 INC_PC(sizeof(blx_1_thumb));
6543 } 6238 goto DISPATCH;
6544 END: 6239 }
6545 { 6240
6546 SAVE_NZCVT; 6241 UQADD8_INST:
6547 cpu->NumInstrsToExecute = 0; 6242 UQADD16_INST:
6548 return num_instrs; 6243 UQADDSUBX_INST:
6549 } 6244 UQSUB8_INST:
6550 INIT_INST_LENGTH: 6245 UQSUB16_INST:
6551 { 6246 UQSUBADDX_INST:
6552#if 0 6247 {
6553 DEBUG_LOG(ARM11, "InstLabel:%d\n", sizeof(InstLabel)); 6248 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
6554 for (int i = 0; i < (sizeof(InstLabel) / sizeof(void *)); i ++) 6249 generic_arm_inst* const inst_cream = (generic_arm_inst*)inst_base->component;
6555 DEBUG_LOG(ARM11, "[%llx]\n", InstLabel[i]); 6250
6556 DEBUG_LOG(ARM11, "InstLabel:%d\n", sizeof(InstLabel)); 6251 const u8 op2 = inst_cream->op2;
6557#endif 6252 const u32 rm_val = RM;
6253 const u32 rn_val = RN;
6254
6255 u16 lo_val = 0;
6256 u16 hi_val = 0;
6257
6258 // UQADD16
6259 if (op2 == 0x00) {
6260 lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, rm_val & 0xFFFF);
6261 hi_val = ARMul_UnsignedSaturatedAdd16((rn_val >> 16) & 0xFFFF, (rm_val >> 16) & 0xFFFF);
6262 }
6263 // UQASX
6264 else if (op2 == 0x01) {
6265 lo_val = ARMul_UnsignedSaturatedSub16(rn_val & 0xFFFF, (rm_val >> 16) & 0xFFFF);
6266 hi_val = ARMul_UnsignedSaturatedAdd16((rn_val >> 16) & 0xFFFF, rm_val & 0xFFFF);
6267 }
6268 // UQSAX
6269 else if (op2 == 0x02) {
6270 lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, (rm_val >> 16) & 0xFFFF);
6271 hi_val = ARMul_UnsignedSaturatedSub16((rn_val >> 16) & 0xFFFF, rm_val & 0xFFFF);
6272 }
6273 // UQSUB16
6274 else if (op2 == 0x03) {
6275 lo_val = ARMul_UnsignedSaturatedSub16(rn_val & 0xFFFF, rm_val & 0xFFFF);
6276 hi_val = ARMul_UnsignedSaturatedSub16((rn_val >> 16) & 0xFFFF, (rm_val >> 16) & 0xFFFF);
6277 }
6278 // UQADD8
6279 else if (op2 == 0x04) {
6280 lo_val = ARMul_UnsignedSaturatedAdd8(rn_val, rm_val) |
6281 ARMul_UnsignedSaturatedAdd8(rn_val >> 8, rm_val >> 8) << 8;
6282 hi_val = ARMul_UnsignedSaturatedAdd8(rn_val >> 16, rm_val >> 16) |
6283 ARMul_UnsignedSaturatedAdd8(rn_val >> 24, rm_val >> 24) << 8;
6284 }
6285 // UQSUB8
6286 else {
6287 lo_val = ARMul_UnsignedSaturatedSub8(rn_val, rm_val) |
6288 ARMul_UnsignedSaturatedSub8(rn_val >> 8, rm_val >> 8) << 8;
6289 hi_val = ARMul_UnsignedSaturatedSub8(rn_val >> 16, rm_val >> 16) |
6290 ARMul_UnsignedSaturatedSub8(rn_val >> 24, rm_val >> 24) << 8;
6291 }
6292
6293 RD = ((lo_val & 0xFFFF) | hi_val << 16);
6294 }
6295
6296 cpu->Reg[15] += GET_INST_SIZE(cpu);
6297 INC_PC(sizeof(generic_arm_inst));
6298 FETCH_INST;
6299 GOTO_NEXT_INST;
6300 }
6301
6302 USAD8_INST:
6303 USADA8_INST:
6304 {
6305 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
6306 generic_arm_inst* inst_cream = (generic_arm_inst*)inst_base->component;
6307
6308 const u8 ra_idx = inst_cream->Ra;
6309 const u32 rm_val = RM;
6310 const u32 rn_val = RN;
6311
6312 const u8 diff1 = ARMul_UnsignedAbsoluteDifference(rn_val & 0xFF, rm_val & 0xFF);
6313 const u8 diff2 = ARMul_UnsignedAbsoluteDifference((rn_val >> 8) & 0xFF, (rm_val >> 8) & 0xFF);
6314 const u8 diff3 = ARMul_UnsignedAbsoluteDifference((rn_val >> 16) & 0xFF, (rm_val >> 16) & 0xFF);
6315 const u8 diff4 = ARMul_UnsignedAbsoluteDifference((rn_val >> 24) & 0xFF, (rm_val >> 24) & 0xFF);
6316
6317 u32 finalDif = (diff1 + diff2 + diff3 + diff4);
6318
6319 // Op is USADA8 if true.
6320 if (ra_idx != 15)
6321 finalDif += cpu->Reg[ra_idx];
6322
6323 RD = finalDif;
6324 }
6325
6326 cpu->Reg[15] += GET_INST_SIZE(cpu);
6327 INC_PC(sizeof(generic_arm_inst));
6328 FETCH_INST;
6329 GOTO_NEXT_INST;
6330 }
6331
6332 USAT_INST:
6333 {
6334 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
6335 ssat_inst* const inst_cream = (ssat_inst*)inst_base->component;
6336
6337 u8 shift_type = inst_cream->shift_type;
6338 u8 shift_amount = inst_cream->imm5;
6339 u32 rn_val = RN;
6340
6341 // 32-bit ASR is encoded as an amount of 0.
6342 if (shift_type == 1 && shift_amount == 0)
6343 shift_amount = 31;
6344
6345 if (shift_type == 0)
6346 rn_val <<= shift_amount;
6347 else if (shift_type == 1)
6348 rn_val = ((s32)rn_val >> shift_amount);
6349
6350 bool saturated = false;
6351 rn_val = ARMul_UnsignedSatQ(rn_val, inst_cream->sat_imm, &saturated);
6352
6353 if (saturated)
6354 cpu->Cpsr |= (1 << 27);
6355
6356 RD = rn_val;
6357 }
6358
6359 cpu->Reg[15] += GET_INST_SIZE(cpu);
6360 INC_PC(sizeof(ssat_inst));
6361 FETCH_INST;
6362 GOTO_NEXT_INST;
6363 }
6364
6365 USAT16_INST:
6366 USUB16_INST:
6367 USUB8_INST:
6368 USUBADDX_INST:
6369 UXTAB16_INST:
6370 UXTB16_INST:
6371 {
6372 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
6373 uxtab_inst* const inst_cream = (uxtab_inst*)inst_base->component;
6374
6375 const u8 rn_idx = inst_cream->Rn;
6376 const u32 rm_val = RM;
6377 const u32 rotation = inst_cream->rotate * 8;
6378 const u32 rotated_rm = ((rm_val << (32 - rotation)) | (rm_val >> rotation));
6379
6380 // UXTB16, otherwise UXTAB16
6381 if (rn_idx == 15) {
6382 RD = rotated_rm & 0x00FF00FF;
6383 } else {
6384 const u32 rn_val = RN;
6385 const u8 lo_rotated = (rotated_rm & 0xFF);
6386 const u16 lo_result = (rn_val & 0xFFFF) + (u16)lo_rotated;
6387 const u8 hi_rotated = (rotated_rm >> 16) & 0xFF;
6388 const u16 hi_result = (rn_val >> 16) + (u16)hi_rotated;
6389
6390 RD = ((hi_result << 16) | (lo_result & 0xFFFF));
6391 }
6392 }
6393
6394 cpu->Reg[15] += GET_INST_SIZE(cpu);
6395 INC_PC(sizeof(uxtab_inst));
6396 FETCH_INST;
6397 GOTO_NEXT_INST;
6398 }
6399
6400 #define VFP_INTERPRETER_IMPL
6401 #include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
6402 #undef VFP_INTERPRETER_IMPL
6403 MMU_EXCEPTION:
6404 {
6405 SAVE_NZCVT;
6406 cpu->abortSig = true;
6407 cpu->Aborted = ARMul_DataAbortV;
6408 cpu->AbortAddr = addr;
6409 cpu->CP15[CP15(CP15_FAULT_STATUS)] = fault & 0xff;
6410 cpu->CP15[CP15(CP15_FAULT_ADDRESS)] = addr;
6411 cpu->NumInstrsToExecute = 0;
6412 return num_instrs;
6413 }
6414 END:
6415 {
6416 SAVE_NZCVT;
6417 cpu->NumInstrsToExecute = 0;
6418 return num_instrs;
6419 }
6420 INIT_INST_LENGTH:
6421 {
6558#if defined __GNUC__ || defined __clang__ 6422#if defined __GNUC__ || defined __clang__
6559 InterpreterInitInstLength((unsigned long long int *)InstLabel, sizeof(InstLabel)); 6423 InterpreterInitInstLength((unsigned long long int *)InstLabel, sizeof(InstLabel));
6560#endif 6424#endif
6561#if 0 6425 cpu->NumInstrsToExecute = 0;
6562 for (int i = 0; i < (sizeof(InstLabel) / sizeof(void *)); i ++) 6426 return num_instrs;
6563 DEBUG_LOG(ARM11, "[%llx]\n", InstLabel[i]); 6427 }
6564 DEBUG_LOG(ARM11, "%llx\n", InstEndLabel[1]);
6565 DEBUG_LOG(ARM11, "%llx\n", InstLabel[1]);
6566 DEBUG_LOG(ARM11, "%lld\n", (char *)InstEndLabel[1] - (char *)InstLabel[1]);
6567#endif
6568 cpu->NumInstrsToExecute = 0;
6569 return num_instrs;
6570 }
6571} 6428}
6572
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.h b/src/core/arm/dyncom/arm_dyncom_interpreter.h
index 3a2462f55..4791ea25f 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.h
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/core/arm/dyncom/arm_dyncom_run.cpp b/src/core/arm/dyncom/arm_dyncom_run.cpp
index a2026cbf3..d457d0ac5 100644
--- a/src/core/arm/dyncom/arm_dyncom_run.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_run.cpp
@@ -1,42 +1,15 @@
1/* Copyright (C) 1// Copyright 2012 Michael Kang, 2014 Citra Emulator Project
2* 2011 - Michael.Kang blackfin.kang@gmail.com 2// Licensed under GPLv2 or any later version
3* This program is free software; you can redistribute it and/or 3// Refer to the license.txt file included.
4* modify it under the terms of the GNU General Public License
5* as published by the Free Software Foundation; either version 2
6* of the License, or (at your option) any later version.
7*
8* This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program; if not, write to the Free Software
15* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16*
17*/
18/**
19* @file arm_dyncom_run.cpp
20* @brief The dyncom run implementation for arm
21* @author Michael.Kang blackfin.kang@gmail.com
22* @version 78.77
23* @date 2011-11-20
24*/
25 4
26#include <assert.h> 5#include <assert.h>
27 6
28#include "core/arm/skyeye_common/armdefs.h" 7#include "core/arm/skyeye_common/armdefs.h"
29 8
30void switch_mode(arm_core_t *core, uint32_t mode) 9void switch_mode(arm_core_t *core, uint32_t mode) {
31{ 10 if (core->Mode == mode)
32 uint32_t tmp1, tmp2;
33 if (core->Mode == mode) {
34 //Mode not changed.
35 //printf("mode not changed\n");
36 return; 11 return;
37 } 12
38 //printf("%d --->>> %d\n", core->Mode, mode);
39 //printf("In %s, Cpsr=0x%x, R15=0x%x, last_pc=0x%x, cpsr=0x%x, spsr_copy=0x%x, icounter=%lld\n", __FUNCTION__, core->Cpsr, core->Reg[15], core->last_pc, core->Cpsr, core->Spsr_copy, core->icounter);
40 if (mode != USERBANK) { 13 if (mode != USERBANK) {
41 switch (core->Mode) { 14 switch (core->Mode) {
42 case USER32MODE: 15 case USER32MODE:
@@ -110,11 +83,8 @@ void switch_mode(arm_core_t *core, uint32_t mode)
110 83
111 } 84 }
112 core->Mode = mode; 85 core->Mode = mode;
113 //printf("In %si end, Cpsr=0x%x, R15=0x%x, last_pc=0x%x, cpsr=0x%x, spsr_copy=0x%x, icounter=%lld\n", __FUNCTION__, core->Cpsr, core->Reg[15], core->last_pc, core->Cpsr, core->Spsr_copy, core->icounter); 86 } else {
114 //printf("\n--------------------------------------\n"); 87 LOG_CRITICAL(Core_ARM11, "user mode");
115 }
116 else {
117 printf("user mode\n");
118 exit(-2); 88 exit(-2);
119 } 89 }
120} 90}
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
index e10f2f9ee..de70ca8ae 100644
--- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
@@ -1,35 +1,13 @@
1/* Copyright (C) 1// Copyright 2012 Michael Kang, 2014 Citra Emulator Project
2* 2011 - Michael.Kang blackfin.kang@gmail.com 2// Licensed under GPLv2 or any later version
3* This program is free software; you can redistribute it and/or 3// Refer to the license.txt file included.
4* modify it under the terms of the GNU General Public License 4
5* as published by the Free Software Foundation; either version 2 5// We can provide simple Thumb simulation by decoding the Thumb instruction into its corresponding
6* of the License, or (at your option) any later version. 6// ARM instruction, and using the existing ARM simulator.
7*
8* This program is distributed in the hope that it will be useful,
9* but WITHOUT ANY WARRANTY; without even the implied warranty of
10* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11* GNU General Public License for more details.
12*
13* You should have received a copy of the GNU General Public License
14* along with this program; if not, write to the Free Software
15* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16*
17*/
18/**
19* @file arm_dyncom_thumb.c
20* @brief The thumb dynamic interpreter
21* @author Michael.Kang blackfin.kang@gmail.com
22* @version 78.77
23* @date 2011-11-07
24*/
25
26/* We can provide simple Thumb simulation by decoding the Thumb
27instruction into its corresponding ARM instruction, and using the
28existing ARM simulator. */
29 7
30#include "core/arm/skyeye_common/skyeye_defs.h" 8#include "core/arm/skyeye_common/skyeye_defs.h"
31 9
32#ifndef MODET /* required for the Thumb instruction support */ 10#ifndef MODET // Required for the Thumb instruction support
33#if 1 11#if 1
34#error "MODET needs to be defined for the Thumb world to work" 12#error "MODET needs to be defined for the Thumb world to work"
35#else 13#else
@@ -40,482 +18,359 @@ existing ARM simulator. */
40#include "core/arm/skyeye_common/armos.h" 18#include "core/arm/skyeye_common/armos.h"
41#include "core/arm/dyncom/arm_dyncom_thumb.h" 19#include "core/arm/dyncom/arm_dyncom_thumb.h"
42 20
43/* Decode a 16bit Thumb instruction. The instruction is in the low 21// Decode a 16bit Thumb instruction. The instruction is in the low 16-bits of the tinstr field,
44 16-bits of the tinstr field, with the following Thumb instruction 22// with the following Thumb instruction held in the high 16-bits. Passing in two Thumb instructions
45 held in the high 16-bits. Passing in two Thumb instructions allows 23// allows easier simulation of the special dual BL instruction.
46 easier simulation of the special dual BL instruction. */
47 24
48tdstate thumb_translate (addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t* inst_size) 25tdstate thumb_translate (addr_t addr, uint32_t instr, uint32_t* ainstr, uint32_t* inst_size) {
49{
50 tdstate valid = t_uninitialized; 26 tdstate valid = t_uninitialized;
51 ARMword next_instr; 27 ARMword tinstr;
52 ARMword tinstr; 28 tinstr = instr;
53 tinstr = instr; 29
54 /* The endian should be judge here */ 30 // The endian should be judge here
55 #if 0 31 if((addr & 0x3) != 0)
56 if (state->bigendSig) { 32 tinstr = instr >> 16;
57 next_instr = tinstr & 0xFFFF; 33 else
58 tinstr >>= 16; 34 tinstr &= 0xFFFF;
59 } 35
60 else { 36 *ainstr = 0xDEADC0DE; // Debugging to catch non updates
61 next_instr = tinstr >> 16; 37
62 tinstr &= 0xFFFF; 38 switch ((tinstr & 0xF800) >> 11) {
63 } 39 case 0: // LSL
64 #endif 40 case 1: // LSR
65 if((addr & 0x3) != 0) 41 case 2: // ASR
66 tinstr = instr >> 16; 42 *ainstr = 0xE1B00000 // base opcode
67 else 43 | ((tinstr & 0x1800) >> (11 - 5)) // shift type
68 tinstr &= 0xFFFF; 44 |((tinstr & 0x07C0) << (7 - 6)) // imm5
69 45 |((tinstr & 0x0038) >> 3) // Rs
70 //printf("In %s, instr=0x%x, tinstr=0x%x, r15=0x%x\n", __FUNCTION__, instr, tinstr, cpu->translate_pc); 46 |((tinstr & 0x0007) << 12); // Rd
71#if 1 /* debugging to catch non updates */ 47 break;
72 *ainstr = 0xDEADC0DE; 48
73#endif 49 case 3: // ADD/SUB
50 {
51 ARMword subset[4] = {
52 0xE0900000, // ADDS Rd,Rs,Rn
53 0xE0500000, // SUBS Rd,Rs,Rn
54 0xE2900000, // ADDS Rd,Rs,#imm3
55 0xE2500000 // SUBS Rd,Rs,#imm3
56 };
57 // It is quicker indexing into a table, than performing switch or conditionals:
58 *ainstr = subset[(tinstr & 0x0600) >> 9] // base opcode
59 |((tinstr & 0x01C0) >> 6) // Rn or imm3
60 |((tinstr & 0x0038) << (16 - 3)) // Rs
61 |((tinstr & 0x0007) << (12 - 0)); // Rd
62 }
63 break;
64
65 case 4: // MOV
66 case 5: // CMP
67 case 6: // ADD
68 case 7: // SUB
69 {
70 ARMword subset[4] = {
71 0xE3B00000, // MOVS Rd,#imm8
72 0xE3500000, // CMP Rd,#imm8
73 0xE2900000, // ADDS Rd,Rd,#imm8
74 0xE2500000, // SUBS Rd,Rd,#imm8
75 };
76
77 *ainstr = subset[(tinstr & 0x1800) >> 11] // base opcode
78 |((tinstr & 0x00FF) >> 0) // imm8
79 |((tinstr & 0x0700) << (16 - 8)) // Rn
80 |((tinstr & 0x0700) << (12 - 8)); // Rd
81 }
82 break;
83
84 case 8: // Arithmetic and high register transfers
85
86 // TODO: Since the subsets for both Format 4 and Format 5 instructions are made up of
87 // different ARM encodings, we could save the following conditional, and just have one
88 // large subset
89
90 if ((tinstr & (1 << 10)) == 0) {
91 enum otype {
92 t_norm,
93 t_shift,
94 t_neg,
95 t_mul
96 };
97
98 struct {
99 ARMword opcode;
100 otype type;
101 } subset[16] = {
102 { 0xE0100000, t_norm }, // ANDS Rd,Rd,Rs
103 { 0xE0300000, t_norm }, // EORS Rd,Rd,Rs
104 { 0xE1B00010, t_shift }, // MOVS Rd,Rd,LSL Rs
105 { 0xE1B00030, t_shift }, // MOVS Rd,Rd,LSR Rs
106 { 0xE1B00050, t_shift }, // MOVS Rd,Rd,ASR Rs
107 { 0xE0B00000, t_norm }, // ADCS Rd,Rd,Rs
108 { 0xE0D00000, t_norm }, // SBCS Rd,Rd,Rs
109 { 0xE1B00070, t_shift }, // MOVS Rd,Rd,ROR Rs
110 { 0xE1100000, t_norm }, // TST Rd,Rs
111 { 0xE2700000, t_neg }, // RSBS Rd,Rs,#0
112 { 0xE1500000, t_norm }, // CMP Rd,Rs
113 { 0xE1700000, t_norm }, // CMN Rd,Rs
114 { 0xE1900000, t_norm }, // ORRS Rd,Rd,Rs
115 { 0xE0100090, t_mul }, // MULS Rd,Rd,Rs
116 { 0xE1D00000, t_norm }, // BICS Rd,Rd,Rs
117 { 0xE1F00000, t_norm } // MVNS Rd,Rs
118 };
119
120 *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; // base
121
122 switch (subset[(tinstr & 0x03C0) >> 6].type) {
123 case t_norm:
124 *ainstr |= ((tinstr & 0x0007) << 16) // Rn
125 |((tinstr & 0x0007) << 12) // Rd
126 |((tinstr & 0x0038) >> 3); // Rs
127 break;
128 case t_shift:
129 *ainstr |= ((tinstr & 0x0007) << 12) // Rd
130 |((tinstr & 0x0007) >> 0) // Rm
131 |((tinstr & 0x0038) << (8 - 3)); // Rs
132 break;
133 case t_neg:
134 *ainstr |= ((tinstr & 0x0007) << 12) // Rd
135 |((tinstr & 0x0038) << (16 - 3)); // Rn
136 break;
137 case t_mul:
138 *ainstr |= ((tinstr & 0x0007) << 16) // Rd
139 |((tinstr & 0x0007) << 8) // Rs
140 |((tinstr & 0x0038) >> 3); // Rm
141 break;
142 }
143 } else {
144 ARMword Rd = ((tinstr & 0x0007) >> 0);
145 ARMword Rs = ((tinstr & 0x0038) >> 3);
146
147 if (tinstr & (1 << 7))
148 Rd += 8;
149 if (tinstr & (1 << 6))
150 Rs += 8;
151
152 switch ((tinstr & 0x03C0) >> 6) {
153 case 0x1: // ADD Rd,Rd,Hs
154 case 0x2: // ADD Hd,Hd,Rs
155 case 0x3: // ADD Hd,Hd,Hs
156 *ainstr = 0xE0800000 // base
157 | (Rd << 16) // Rn
158 |(Rd << 12) // Rd
159 |(Rs << 0); // Rm
160 break;
161 case 0x5: // CMP Rd,Hs
162 case 0x6: // CMP Hd,Rs
163 case 0x7: // CMP Hd,Hs
164 *ainstr = 0xE1500000 // base
165 | (Rd << 16) // Rn
166 |(Rd << 12) // Rd
167 |(Rs << 0); // Rm
168 break;
169 case 0x9: // MOV Rd,Hs
170 case 0xA: // MOV Hd,Rs
171 case 0xB: // MOV Hd,Hs
172 *ainstr = 0xE1A00000 // base
173 | (Rd << 16) // Rn
174 |(Rd << 12) // Rd
175 |(Rs << 0); // Rm
176 break;
177 case 0xC: // BX Rs
178 case 0xD: // BX Hs
179 *ainstr = 0xE12FFF10 // base
180 | ((tinstr & 0x0078) >> 3); // Rd
181 break;
182 case 0x0: // UNDEFINED
183 case 0x4: // UNDEFINED
184 case 0x8: // UNDEFINED
185 valid = t_undefined;
186 break;
187 case 0xE: // BLX
188 case 0xF: // BLX
189 *ainstr = 0xE1200030 // base
190 | (Rs << 0); // Rm
191 break;
192 }
193 }
194 break;
195
196 case 9: // LDR Rd,[PC,#imm8]
197 *ainstr = 0xE59F0000 // base
198 | ((tinstr & 0x0700) << (12 - 8)) // Rd
199 |((tinstr & 0x00FF) << (2 - 0)); // off8
200 break;
201
202 case 10:
203 case 11:
204 // TODO: Format 7 and Format 8 perform the same ARM encoding, so the following could be
205 // merged into a single subset, saving on the following boolean:
206
207 if ((tinstr & (1 << 9)) == 0) {
208 ARMword subset[4] = {
209 0xE7800000, // STR Rd,[Rb,Ro]
210 0xE7C00000, // STRB Rd,[Rb,Ro]
211 0xE7900000, // LDR Rd,[Rb,Ro]
212 0xE7D00000 // LDRB Rd,[Rb,Ro]
213 };
214
215 *ainstr = subset[(tinstr & 0x0C00) >> 10] // base
216 |((tinstr & 0x0007) << (12 - 0)) // Rd
217 |((tinstr & 0x0038) << (16 - 3)) // Rb
218 |((tinstr & 0x01C0) >> 6); // Ro
219
220 } else {
221 ARMword subset[4] = {
222 0xE18000B0, // STRH Rd,[Rb,Ro]
223 0xE19000D0, // LDRSB Rd,[Rb,Ro]
224 0xE19000B0, // LDRH Rd,[Rb,Ro]
225 0xE19000F0 // LDRSH Rd,[Rb,Ro]
226 };
227 *ainstr = subset[(tinstr & 0x0C00) >> 10] // base
228 |((tinstr & 0x0007) << (12 - 0)) // Rd
229 |((tinstr & 0x0038) << (16 - 3)) // Rb
230 |((tinstr & 0x01C0) >> 6); // Ro
231 }
232 break;
233
234 case 12: // STR Rd,[Rb,#imm5]
235 case 13: // LDR Rd,[Rb,#imm5]
236 case 14: // STRB Rd,[Rb,#imm5]
237 case 15: // LDRB Rd,[Rb,#imm5]
238 {
239 ARMword subset[4] = {
240 0xE5800000, // STR Rd,[Rb,#imm5]
241 0xE5900000, // LDR Rd,[Rb,#imm5]
242 0xE5C00000, // STRB Rd,[Rb,#imm5]
243 0xE5D00000 // LDRB Rd,[Rb,#imm5]
244 };
245 // The offset range defends on whether we are transferring a byte or word value:
246 *ainstr = subset[(tinstr & 0x1800) >> 11] // base
247 |((tinstr & 0x0007) << (12 - 0)) // Rd
248 |((tinstr & 0x0038) << (16 - 3)) // Rb
249 |((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); // off5
250 }
251 break;
252
253 case 16: // STRH Rd,[Rb,#imm5]
254 case 17: // LDRH Rd,[Rb,#imm5]
255 *ainstr = ((tinstr & (1 << 11)) // base
256 ? 0xE1D000B0 // LDRH
257 : 0xE1C000B0) // STRH
258 |((tinstr & 0x0007) << (12 - 0)) // Rd
259 |((tinstr & 0x0038) << (16 - 3)) // Rb
260 |((tinstr & 0x01C0) >> (6 - 1)) // off5, low nibble
261 |((tinstr & 0x0600) >> (9 - 8)); // off5, high nibble
262 break;
263
264 case 18: // STR Rd,[SP,#imm8]
265 case 19: // LDR Rd,[SP,#imm8]
266 *ainstr = ((tinstr & (1 << 11)) // base
267 ? 0xE59D0000 // LDR
268 : 0xE58D0000) // STR
269 |((tinstr & 0x0700) << (12 - 8)) // Rd
270 |((tinstr & 0x00FF) << 2); // off8
271 break;
272
273 case 20: // ADD Rd,PC,#imm8
274 case 21: // ADD Rd,SP,#imm8
275
276 if ((tinstr & (1 << 11)) == 0) {
277
278 // NOTE: The PC value used here should by word aligned. We encode shift-left-by-2 in the
279 // rotate immediate field, so no shift of off8 is needed.
280
281 *ainstr = 0xE28F0F00 // base
282 | ((tinstr & 0x0700) << (12 - 8)) // Rd
283 |(tinstr & 0x00FF); // off8
284 } else {
285 // We encode shift-left-by-2 in the rotate immediate field, so no shift of off8 is needed.
286 *ainstr = 0xE28D0F00 // base
287 | ((tinstr & 0x0700) << (12 - 8)) // Rd
288 |(tinstr & 0x00FF); // off8
289 }
290 break;
291
292 case 22:
293 case 23:
294 if ((tinstr & 0x0F00) == 0x0000) {
295 // NOTE: The instruction contains a shift left of 2 equivalent (implemented as ROR #30):
296 *ainstr = ((tinstr & (1 << 7)) // base
297 ? 0xE24DDF00 // SUB
298 : 0xE28DDF00) // ADD
299 |(tinstr & 0x007F); // off7
300 } else if ((tinstr & 0x0F00) == 0x0e00)
301 *ainstr = 0xEF000000 | SWI_Breakpoint;
302 else {
303 ARMword subset[4] = {
304 0xE92D0000, // STMDB sp!,{rlist}
305 0xE92D4000, // STMDB sp!,{rlist,lr}
306 0xE8BD0000, // LDMIA sp!,{rlist}
307 0xE8BD8000 // LDMIA sp!,{rlist,pc}
308 };
309 *ainstr = subset[((tinstr & (1 << 11)) >> 10) | ((tinstr & (1 << 8)) >> 8)] // base
310 |(tinstr & 0x00FF); // mask8
311 }
312 break;
313
314 case 24: // STMIA
315 case 25: // LDMIA
316 *ainstr = ((tinstr & (1 << 11)) // base
317 ? 0xE8B00000 // LDMIA
318 : 0xE8A00000) // STMIA
319 |((tinstr & 0x0700) << (16 - 8)) // Rb
320 |(tinstr & 0x00FF); // mask8
321 break;
322
323 case 26: // Bcc
324 case 27: // Bcc/SWI
325 if ((tinstr & 0x0F00) == 0x0F00) {
326 // Format 17 : SWI
327 *ainstr = 0xEF000000;
328 // Breakpoint must be handled specially.
329 if ((tinstr & 0x00FF) == 0x18)
330 *ainstr |= ((tinstr & 0x00FF) << 16);
331 // New breakpoint value. See gdb/arm-tdep.c
332 else if ((tinstr & 0x00FF) == 0xFE)
333 *ainstr |= SWI_Breakpoint;
334 else
335 *ainstr |= (tinstr & 0x00FF);
336 } else if ((tinstr & 0x0F00) != 0x0E00)
337 valid = t_branch;
338 else // UNDEFINED : cc=1110(AL) uses different format
339 valid = t_undefined;
340
341 break;
342
343 case 28: // B
344 valid = t_branch;
345 break;
346
347 case 29:
348 if(tinstr & 0x1)
349 valid = t_undefined;
350 else
351 valid = t_branch;
352 break;
353
354 case 30: // BL instruction 1
355
356 // There is no single ARM instruction equivalent for this Thumb instruction. To keep the
357 // simulation simple (from the user perspective) we check if the following instruction is
358 // the second half of this BL, and if it is we simulate it immediately
359
360 valid = t_branch;
361 break;
362
363 case 31: // BL instruction 2
364
365 // There is no single ARM instruction equivalent for this instruction. Also, it should only
366 // ever be matched with the fmt19 "BL instruction 1" instruction. However, we do allow the
367 // simulation of it on its own, with undefined results if r14 is not suitably initialised.
368
369 valid = t_branch;
370 break;
371 }
372
373 *inst_size = 2;
74 374
75 switch ((tinstr & 0xF800) >> 11) { 375 return valid;
76 case 0: /* LSL */
77 case 1: /* LSR */
78 case 2: /* ASR */
79 /* Format 1 */
80 *ainstr = 0xE1B00000 /* base opcode */
81 | ((tinstr & 0x1800) >> (11 - 5)) /* shift type */
82 |((tinstr & 0x07C0) << (7 - 6)) /* imm5 */
83 |((tinstr & 0x0038) >> 3) /* Rs */
84 |((tinstr & 0x0007) << 12); /* Rd */
85 break;
86 case 3: /* ADD/SUB */
87 /* Format 2 */
88 {
89 ARMword subset[4] = {
90 0xE0900000, /* ADDS Rd,Rs,Rn */
91 0xE0500000, /* SUBS Rd,Rs,Rn */
92 0xE2900000, /* ADDS Rd,Rs,#imm3 */
93 0xE2500000 /* SUBS Rd,Rs,#imm3 */
94 };
95 /* It is quicker indexing into a table, than performing switch
96 or conditionals: */
97 *ainstr = subset[(tinstr & 0x0600) >> 9] /* base opcode */
98 |((tinstr & 0x01C0) >> 6) /* Rn or imm3 */
99 |((tinstr & 0x0038) << (16 - 3)) /* Rs */
100 |((tinstr & 0x0007) << (12 - 0)); /* Rd */
101 }
102 break;
103 case 4: /* MOV */
104 case 5: /* CMP */
105 case 6: /* ADD */
106 case 7: /* SUB */
107 /* Format 3 */
108 {
109 ARMword subset[4] = {
110 0xE3B00000, /* MOVS Rd,#imm8 */
111 0xE3500000, /* CMP Rd,#imm8 */
112 0xE2900000, /* ADDS Rd,Rd,#imm8 */
113 0xE2500000, /* SUBS Rd,Rd,#imm8 */
114 };
115 *ainstr = subset[(tinstr & 0x1800) >> 11] /* base opcode */
116 |((tinstr & 0x00FF) >> 0) /* imm8 */
117 |((tinstr & 0x0700) << (16 - 8)) /* Rn */
118 |((tinstr & 0x0700) << (12 - 8)); /* Rd */
119 }
120 break;
121 case 8: /* Arithmetic and high register transfers */
122 /* TODO: Since the subsets for both Format 4 and Format 5
123 instructions are made up of different ARM encodings, we could
124 save the following conditional, and just have one large
125 subset. */
126 if ((tinstr & (1 << 10)) == 0) {
127 typedef enum
128 { t_norm, t_shift, t_neg, t_mul }otype_t;
129
130 /* Format 4 */
131 struct
132 {
133 ARMword opcode;
134 otype_t otype;
135 }
136 subset[16] = {
137 {
138 0xE0100000, t_norm}, /* ANDS Rd,Rd,Rs */
139 {
140 0xE0300000, t_norm}, /* EORS Rd,Rd,Rs */
141 {
142 0xE1B00010, t_shift}, /* MOVS Rd,Rd,LSL Rs */
143 {
144 0xE1B00030, t_shift}, /* MOVS Rd,Rd,LSR Rs */
145 {
146 0xE1B00050, t_shift}, /* MOVS Rd,Rd,ASR Rs */
147 {
148 0xE0B00000, t_norm}, /* ADCS Rd,Rd,Rs */
149 {
150 0xE0D00000, t_norm}, /* SBCS Rd,Rd,Rs */
151 {
152 0xE1B00070, t_shift}, /* MOVS Rd,Rd,ROR Rs */
153 {
154 0xE1100000, t_norm}, /* TST Rd,Rs */
155 {
156 0xE2700000, t_neg}, /* RSBS Rd,Rs,#0 */
157 {
158 0xE1500000, t_norm}, /* CMP Rd,Rs */
159 {
160 0xE1700000, t_norm}, /* CMN Rd,Rs */
161 {
162 0xE1900000, t_norm}, /* ORRS Rd,Rd,Rs */
163 {
164 0xE0100090, t_mul}, /* MULS Rd,Rd,Rs */
165 {
166 0xE1D00000, t_norm}, /* BICS Rd,Rd,Rs */
167 {
168 0xE1F00000, t_norm} /* MVNS Rd,Rs */
169 };
170 *ainstr = subset[(tinstr & 0x03C0) >> 6].opcode; /* base */
171 switch (subset[(tinstr & 0x03C0) >> 6].otype) {
172 case t_norm:
173 *ainstr |= ((tinstr & 0x0007) << 16) /* Rn */
174 |((tinstr & 0x0007) << 12) /* Rd */
175 |((tinstr & 0x0038) >> 3); /* Rs */
176 break;
177 case t_shift:
178 *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */
179 |((tinstr & 0x0007) >> 0) /* Rm */
180 |((tinstr & 0x0038) << (8 - 3)); /* Rs */
181 break;
182 case t_neg:
183 *ainstr |= ((tinstr & 0x0007) << 12) /* Rd */
184 |((tinstr & 0x0038) << (16 - 3)); /* Rn */
185 break;
186 case t_mul:
187 *ainstr |= ((tinstr & 0x0007) << 16) /* Rd */
188 |((tinstr & 0x0007) << 8) /* Rs */
189 |((tinstr & 0x0038) >> 3); /* Rm */
190 break;
191 }
192 }
193 else {
194 /* Format 5 */
195 ARMword Rd = ((tinstr & 0x0007) >> 0);
196 ARMword Rs = ((tinstr & 0x0038) >> 3);
197 if (tinstr & (1 << 7))
198 Rd += 8;
199 if (tinstr & (1 << 6))
200 Rs += 8;
201 switch ((tinstr & 0x03C0) >> 6) {
202 case 0x1: /* ADD Rd,Rd,Hs */
203 case 0x2: /* ADD Hd,Hd,Rs */
204 case 0x3: /* ADD Hd,Hd,Hs */
205 *ainstr = 0xE0800000 /* base */
206 | (Rd << 16) /* Rn */
207 |(Rd << 12) /* Rd */
208 |(Rs << 0); /* Rm */
209 break;
210 case 0x5: /* CMP Rd,Hs */
211 case 0x6: /* CMP Hd,Rs */
212 case 0x7: /* CMP Hd,Hs */
213 *ainstr = 0xE1500000 /* base */
214 | (Rd << 16) /* Rn */
215 |(Rd << 12) /* Rd */
216 |(Rs << 0); /* Rm */
217 break;
218 case 0x9: /* MOV Rd,Hs */
219 case 0xA: /* MOV Hd,Rs */
220 case 0xB: /* MOV Hd,Hs */
221 *ainstr = 0xE1A00000 /* base */
222 | (Rd << 16) /* Rn */
223 |(Rd << 12) /* Rd */
224 |(Rs << 0); /* Rm */
225 break;
226 case 0xC: /* BX Rs */
227 case 0xD: /* BX Hs */
228 *ainstr = 0xE12FFF10 /* base */
229 | ((tinstr & 0x0078) >> 3); /* Rd */
230 break;
231 case 0x0: /* UNDEFINED */
232 case 0x4: /* UNDEFINED */
233 case 0x8: /* UNDEFINED */
234 valid = t_undefined;
235 break;
236 case 0xE: /* BLX */
237 case 0xF: /* BLX */
238
239 //if (state->is_v5) {
240 if(1){
241 //valid = t_branch;
242 #if 1
243 *ainstr = 0xE1200030 /* base */
244 |(Rs << 0); /* Rm */
245 #endif
246 } else {
247 valid = t_undefined;
248 }
249 break;
250 }
251 }
252 break;
253 case 9: /* LDR Rd,[PC,#imm8] */
254 /* Format 6 */
255 *ainstr = 0xE59F0000 /* base */
256 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
257 |((tinstr & 0x00FF) << (2 - 0)); /* off8 */
258 break;
259 case 10:
260 case 11:
261 /* TODO: Format 7 and Format 8 perform the same ARM encoding, so
262 the following could be merged into a single subset, saving on
263 the following boolean: */
264 if ((tinstr & (1 << 9)) == 0) {
265 /* Format 7 */
266 ARMword subset[4] = {
267 0xE7800000, /* STR Rd,[Rb,Ro] */
268 0xE7C00000, /* STRB Rd,[Rb,Ro] */
269 0xE7900000, /* LDR Rd,[Rb,Ro] */
270 0xE7D00000 /* LDRB Rd,[Rb,Ro] */
271 };
272 *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */
273 |((tinstr & 0x0007) << (12 - 0)) /* Rd */
274 |((tinstr & 0x0038) << (16 - 3)) /* Rb */
275 |((tinstr & 0x01C0) >> 6); /* Ro */
276 }
277 else {
278 /* Format 8 */
279 ARMword subset[4] = {
280 0xE18000B0, /* STRH Rd,[Rb,Ro] */
281 0xE19000D0, /* LDRSB Rd,[Rb,Ro] */
282 0xE19000B0, /* LDRH Rd,[Rb,Ro] */
283 0xE19000F0 /* LDRSH Rd,[Rb,Ro] */
284 };
285 *ainstr = subset[(tinstr & 0x0C00) >> 10] /* base */
286 |((tinstr & 0x0007) << (12 - 0)) /* Rd */
287 |((tinstr & 0x0038) << (16 - 3)) /* Rb */
288 |((tinstr & 0x01C0) >> 6); /* Ro */
289 }
290 break;
291 case 12: /* STR Rd,[Rb,#imm5] */
292 case 13: /* LDR Rd,[Rb,#imm5] */
293 case 14: /* STRB Rd,[Rb,#imm5] */
294 case 15: /* LDRB Rd,[Rb,#imm5] */
295 /* Format 9 */
296 {
297 ARMword subset[4] = {
298 0xE5800000, /* STR Rd,[Rb,#imm5] */
299 0xE5900000, /* LDR Rd,[Rb,#imm5] */
300 0xE5C00000, /* STRB Rd,[Rb,#imm5] */
301 0xE5D00000 /* LDRB Rd,[Rb,#imm5] */
302 };
303 /* The offset range defends on whether we are transferring a
304 byte or word value: */
305 *ainstr = subset[(tinstr & 0x1800) >> 11] /* base */
306 |((tinstr & 0x0007) << (12 - 0)) /* Rd */
307 |((tinstr & 0x0038) << (16 - 3)) /* Rb */
308 |((tinstr & 0x07C0) >> (6 - ((tinstr & (1 << 12)) ? 0 : 2))); /* off5 */
309 }
310 break;
311 case 16: /* STRH Rd,[Rb,#imm5] */
312 case 17: /* LDRH Rd,[Rb,#imm5] */
313 /* Format 10 */
314 *ainstr = ((tinstr & (1 << 11)) /* base */
315 ? 0xE1D000B0 /* LDRH */
316 : 0xE1C000B0) /* STRH */
317 |((tinstr & 0x0007) << (12 - 0)) /* Rd */
318 |((tinstr & 0x0038) << (16 - 3)) /* Rb */
319 |((tinstr & 0x01C0) >> (6 - 1)) /* off5, low nibble */
320 |((tinstr & 0x0600) >> (9 - 8)); /* off5, high nibble */
321 break;
322 case 18: /* STR Rd,[SP,#imm8] */
323 case 19: /* LDR Rd,[SP,#imm8] */
324 /* Format 11 */
325 *ainstr = ((tinstr & (1 << 11)) /* base */
326 ? 0xE59D0000 /* LDR */
327 : 0xE58D0000) /* STR */
328 |((tinstr & 0x0700) << (12 - 8)) /* Rd */
329 |((tinstr & 0x00FF) << 2); /* off8 */
330 break;
331 case 20: /* ADD Rd,PC,#imm8 */
332 case 21: /* ADD Rd,SP,#imm8 */
333 /* Format 12 */
334 if ((tinstr & (1 << 11)) == 0) {
335 /* NOTE: The PC value used here should by word aligned */
336 /* We encode shift-left-by-2 in the rotate immediate field,
337 so no shift of off8 is needed. */
338 *ainstr = 0xE28F0F00 /* base */
339 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
340 |(tinstr & 0x00FF); /* off8 */
341 }
342 else {
343 /* We encode shift-left-by-2 in the rotate immediate field,
344 so no shift of off8 is needed. */
345 *ainstr = 0xE28D0F00 /* base */
346 | ((tinstr & 0x0700) << (12 - 8)) /* Rd */
347 |(tinstr & 0x00FF); /* off8 */
348 }
349 break;
350 case 22:
351 case 23:
352 if ((tinstr & 0x0F00) == 0x0000) {
353 /* Format 13 */
354 /* NOTE: The instruction contains a shift left of 2
355 equivalent (implemented as ROR #30): */
356 *ainstr = ((tinstr & (1 << 7)) /* base */
357 ? 0xE24DDF00 /* SUB */
358 : 0xE28DDF00) /* ADD */
359 |(tinstr & 0x007F); /* off7 */
360 }
361 else if ((tinstr & 0x0F00) == 0x0e00)
362 *ainstr = 0xEF000000 | SWI_Breakpoint;
363 else {
364 /* Format 14 */
365 ARMword subset[4] = {
366 0xE92D0000, /* STMDB sp!,{rlist} */
367 0xE92D4000, /* STMDB sp!,{rlist,lr} */
368 0xE8BD0000, /* LDMIA sp!,{rlist} */
369 0xE8BD8000 /* LDMIA sp!,{rlist,pc} */
370 };
371 *ainstr = subset[((tinstr & (1 << 11)) >> 10) | ((tinstr & (1 << 8)) >> 8)] /* base */
372 |(tinstr & 0x00FF); /* mask8 */
373 }
374 break;
375 case 24: /* STMIA */
376 case 25: /* LDMIA */
377 /* Format 15 */
378 *ainstr = ((tinstr & (1 << 11)) /* base */
379 ? 0xE8B00000 /* LDMIA */
380 : 0xE8A00000) /* STMIA */
381 |((tinstr & 0x0700) << (16 - 8)) /* Rb */
382 |(tinstr & 0x00FF); /* mask8 */
383 break;
384 case 26: /* Bcc */
385 case 27: /* Bcc/SWI */
386 if ((tinstr & 0x0F00) == 0x0F00) {
387 #if 0
388 if (tinstr == (ARMul_ABORTWORD & 0xffff) &&
389 state->AbortAddr == pc) {
390 *ainstr = ARMul_ABORTWORD;
391 break;
392 }
393 #endif
394 /* Format 17 : SWI */
395 *ainstr = 0xEF000000;
396 /* Breakpoint must be handled specially. */
397 if ((tinstr & 0x00FF) == 0x18)
398 *ainstr |= ((tinstr & 0x00FF) << 16);
399 /* New breakpoint value. See gdb/arm-tdep.c */
400 else if ((tinstr & 0x00FF) == 0xFE)
401 *ainstr |= SWI_Breakpoint;
402 else
403 *ainstr |= (tinstr & 0x00FF);
404 }
405 else if ((tinstr & 0x0F00) != 0x0E00) {
406 /* Format 16 */
407 #if 0
408 int doit = FALSE;
409 /* TODO: Since we are doing a switch here, we could just add
410 the SWI and undefined instruction checks into this
411 switch to same on a couple of conditionals: */
412 switch ((tinstr & 0x0F00) >> 8) {
413 case EQ:
414 doit = ZFLAG;
415 break;
416 case NE:
417 doit = !ZFLAG;
418 break;
419 case VS:
420 doit = VFLAG;
421 break;
422 case VC:
423 doit = !VFLAG;
424 break;
425 case MI:
426 doit = NFLAG;
427 break;
428 case PL:
429 doit = !NFLAG;
430 break;
431 case CS:
432 doit = CFLAG;
433 break;
434 case CC:
435 doit = !CFLAG;
436 break;
437 case HI:
438 doit = (CFLAG && !ZFLAG);
439 break;
440 case LS:
441 doit = (!CFLAG || ZFLAG);
442 break;
443 case GE:
444 doit = ((!NFLAG && !VFLAG)
445 || (NFLAG && VFLAG));
446 break;
447 case LT:
448 doit = ((NFLAG && !VFLAG)
449 || (!NFLAG && VFLAG));
450 break;
451 case GT:
452 doit = ((!NFLAG && !VFLAG && !ZFLAG)
453 || (NFLAG && VFLAG && !ZFLAG));
454 break;
455 case LE:
456 doit = ((NFLAG && !VFLAG)
457 || (!NFLAG && VFLAG)) || ZFLAG;
458 break;
459 }
460 if (doit) {
461 state->Reg[15] = (pc + 4
462 + (((tinstr & 0x7F) << 1)
463 | ((tinstr & (1 << 7)) ?
464 0xFFFFFF00 : 0)));
465 FLUSHPIPE;
466 }
467 #endif
468 valid = t_branch;
469 }
470 else /* UNDEFINED : cc=1110(AL) uses different format */
471 valid = t_undefined;
472 break;
473 case 28: /* B */
474 /* Format 18 */
475 #if 0
476 state->Reg[15] = (pc + 4 + (((tinstr & 0x3FF) << 1)
477 | ((tinstr & (1 << 10)) ?
478 0xFFFFF800 : 0)));
479 #endif
480 //FLUSHPIPE;
481 valid = t_branch;
482 break;
483 case 29:
484 if(tinstr & 0x1)
485 valid = t_undefined;
486 else{
487 /* BLX 1 for armv5t and above */
488 //printf("In %s, After BLX(1),LR=0x%x,PC=0x%x, offset=0x%x\n", __FUNCTION__, state->Reg[14], state->Reg[15], (tinstr &0x7FF) << 1);
489 valid = t_branch;
490 }
491 break;
492 case 30: /* BL instruction 1 */
493 /* Format 19 */
494 /* There is no single ARM instruction equivalent for this Thumb
495 instruction. To keep the simulation simple (from the user
496 perspective) we check if the following instruction is the
497 second half of this BL, and if it is we simulate it
498 immediately. */
499 valid = t_branch;
500 break;
501 case 31: /* BL instruction 2 */
502 /* Format 19 */
503 /* There is no single ARM instruction equivalent for this
504 instruction. Also, it should only ever be matched with the
505 fmt19 "BL instruction 1" instruction. However, we do allow
506 the simulation of it on its own, with undefined results if
507 r14 is not suitably initialised. */
508 {
509 #if 0
510 ARMword tmp = (pc + 2);
511 state->Reg[15] =
512 (state->Reg[14] + ((tinstr & 0x07FF) << 1));
513 state->Reg[14] = (tmp | 1);
514 #endif
515 valid = t_branch;
516 }
517 break;
518 }
519 *inst_size = 2;
520 return valid;
521} 376}
diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp
index e2aa5ce92..80ebc359e 100644
--- a/src/core/arm/interpreter/arm_interpreter.cpp
+++ b/src/core/arm/interpreter/arm_interpreter.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/arm/interpreter/arm_interpreter.h" 5#include "core/arm/interpreter/arm_interpreter.h"
@@ -38,78 +38,43 @@ ARM_Interpreter::~ARM_Interpreter() {
38 delete state; 38 delete state;
39} 39}
40 40
41/**
42 * Set the Program Counter to an address
43 * @param addr Address to set PC to
44 */
45void ARM_Interpreter::SetPC(u32 pc) { 41void ARM_Interpreter::SetPC(u32 pc) {
46 state->pc = state->Reg[15] = pc; 42 state->pc = state->Reg[15] = pc;
47} 43}
48 44
49/*
50 * Get the current Program Counter
51 * @return Returns current PC
52 */
53u32 ARM_Interpreter::GetPC() const { 45u32 ARM_Interpreter::GetPC() const {
54 return state->pc; 46 return state->pc;
55} 47}
56 48
57/**
58 * Get an ARM register
59 * @param index Register index (0-15)
60 * @return Returns the value in the register
61 */
62u32 ARM_Interpreter::GetReg(int index) const { 49u32 ARM_Interpreter::GetReg(int index) const {
63 return state->Reg[index]; 50 return state->Reg[index];
64} 51}
65 52
66/**
67 * Set an ARM register
68 * @param index Register index (0-15)
69 * @param value Value to set register to
70 */
71void ARM_Interpreter::SetReg(int index, u32 value) { 53void ARM_Interpreter::SetReg(int index, u32 value) {
72 state->Reg[index] = value; 54 state->Reg[index] = value;
73} 55}
74 56
75/**
76 * Get the current CPSR register
77 * @return Returns the value of the CPSR register
78 */
79u32 ARM_Interpreter::GetCPSR() const { 57u32 ARM_Interpreter::GetCPSR() const {
80 return state->Cpsr; 58 return state->Cpsr;
81} 59}
82 60
83/**
84 * Set the current CPSR register
85 * @param cpsr Value to set CPSR to
86 */
87void ARM_Interpreter::SetCPSR(u32 cpsr) { 61void ARM_Interpreter::SetCPSR(u32 cpsr) {
88 state->Cpsr = cpsr; 62 state->Cpsr = cpsr;
89} 63}
90 64
91/**
92 * Returns the number of clock ticks since the last reset
93 * @return Returns number of clock ticks
94 */
95u64 ARM_Interpreter::GetTicks() const { 65u64 ARM_Interpreter::GetTicks() const {
96 return ARMul_Time(state); 66 return state->NumInstrs;
67}
68
69void ARM_Interpreter::AddTicks(u64 ticks) {
70 state->NumInstrs += ticks;
97} 71}
98 72
99/**
100 * Executes the given number of instructions
101 * @param num_instructions Number of instructions to executes
102 */
103void ARM_Interpreter::ExecuteInstructions(int num_instructions) { 73void ARM_Interpreter::ExecuteInstructions(int num_instructions) {
104 state->NumInstrsToExecute = num_instructions - 1; 74 state->NumInstrsToExecute = num_instructions - 1;
105 ARMul_Emulate32(state); 75 ARMul_Emulate32(state);
106} 76}
107 77
108/**
109 * Saves the current CPU context
110 * @param ctx Thread context to save
111 * @todo Do we need to save Reg[15] and NextInstr?
112 */
113void ARM_Interpreter::SaveContext(ThreadContext& ctx) { 78void ARM_Interpreter::SaveContext(ThreadContext& ctx) {
114 memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers)); 79 memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers));
115 memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers)); 80 memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers));
@@ -126,11 +91,6 @@ void ARM_Interpreter::SaveContext(ThreadContext& ctx) {
126 ctx.mode = state->NextInstr; 91 ctx.mode = state->NextInstr;
127} 92}
128 93
129/**
130 * Loads a CPU context
131 * @param ctx Thread context to load
132 * @param Do we need to load Reg[15] and NextInstr?
133 */
134void ARM_Interpreter::LoadContext(const ThreadContext& ctx) { 94void ARM_Interpreter::LoadContext(const ThreadContext& ctx) {
135 memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers)); 95 memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers));
136 memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers)); 96 memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers));
@@ -147,7 +107,6 @@ void ARM_Interpreter::LoadContext(const ThreadContext& ctx) {
147 state->NextInstr = ctx.mode; 107 state->NextInstr = ctx.mode;
148} 108}
149 109
150/// Prepare core for thread reschedule (if needed to correctly handle state)
151void ARM_Interpreter::PrepareReschedule() { 110void ARM_Interpreter::PrepareReschedule() {
152 state->NumInstrsToExecute = 0; 111 state->NumInstrsToExecute = 0;
153} 112}
diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h
index ed53d997c..019dad5df 100644
--- a/src/core/arm/interpreter/arm_interpreter.h
+++ b/src/core/arm/interpreter/arm_interpreter.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -61,6 +61,12 @@ public:
61 u64 GetTicks() const override; 61 u64 GetTicks() const override;
62 62
63 /** 63 /**
64 * Advance the CPU core by the specified number of ticks (e.g. to simulate CPU execution time)
65 * @param ticks Number of ticks to advance the CPU core
66 */
67 void AddTicks(u64 ticks) override;
68
69 /**
64 * Saves the current CPU context 70 * Saves the current CPU context
65 * @param ctx Thread context to save 71 * @param ctx Thread context to save
66 */ 72 */
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp
index 73223874e..b9c2aa6c2 100644
--- a/src/core/arm/interpreter/armemu.cpp
+++ b/src/core/arm/interpreter/armemu.cpp
@@ -949,7 +949,7 @@ ARMul_Emulate26 (ARMul_State * state)
949 //printf("t decode %04lx -> %08lx\n", instr & 0xffff, armOp); 949 //printf("t decode %04lx -> %08lx\n", instr & 0xffff, armOp);
950 950
951 if (armOp == 0xDEADC0DE) { 951 if (armOp == 0xDEADC0DE) {
952 DEBUG("Failed to decode thumb opcode %04X at %08X\n", instr, pc); 952 LOG_ERROR(Core_ARM11, "Failed to decode thumb opcode %04X at %08X", instr, pc);
953 } 953 }
954 954
955 instr = armOp; 955 instr = armOp;
@@ -1166,7 +1166,7 @@ mainswitch:
1166 else if ((((int)BITS(21, 27)) == 0x3e) && ((int)BITS(4, 6) == 0x1)) { 1166 else if ((((int)BITS(21, 27)) == 0x3e) && ((int)BITS(4, 6) == 0x1)) {
1167 //(ARMword)(instr<<(31-(n))) >> ((31-(n))+(m)) 1167 //(ARMword)(instr<<(31-(n))) >> ((31-(n))+(m))
1168 unsigned msb ,tmp_rn, tmp_rd, dst; 1168 unsigned msb ,tmp_rn, tmp_rd, dst;
1169 msb = tmp_rd = tmp_rn = dst = 0; 1169 tmp_rd = tmp_rn = dst = 0;
1170 Rd = BITS(12, 15); 1170 Rd = BITS(12, 15);
1171 Rn = BITS(0, 3); 1171 Rn = BITS(0, 3);
1172 lsb = BITS(7, 11); 1172 lsb = BITS(7, 11);
@@ -1356,7 +1356,13 @@ mainswitch:
1356 } 1356 }
1357 break; 1357 break;
1358 1358
1359 case 0x04: /* SUB reg */ 1359 case 0x04: /* SUB reg */
1360 // Signifies UMAAL
1361 if (state->is_v6 && BITS(4, 7) == 0x09) {
1362 if (handle_v6_insn(state, instr))
1363 break;
1364 }
1365
1360#ifdef MODET 1366#ifdef MODET
1361 if (BITS (4, 7) == 0xB) { 1367 if (BITS (4, 7) == 0xB) {
1362 /* STRH immediate offset, no write-back, down, post indexed. */ 1368 /* STRH immediate offset, no write-back, down, post indexed. */
@@ -1664,7 +1670,7 @@ mainswitch:
1664 op1 *= op2; 1670 op1 *= op2;
1665 //printf("SMLA_INST:BB,op1=0x%x, op2=0x%x. Rn=0x%x\n", op1, op2, Rn); 1671 //printf("SMLA_INST:BB,op1=0x%x, op2=0x%x. Rn=0x%x\n", op1, op2, Rn);
1666 if (AddOverflow(op1, Rn, op1 + Rn)) 1672 if (AddOverflow(op1, Rn, op1 + Rn))
1667 SETS; 1673 SETQ;
1668 state->Reg[BITS (16, 19)] = op1 + Rn; 1674 state->Reg[BITS (16, 19)] = op1 + Rn;
1669 break; 1675 break;
1670 } 1676 }
@@ -1676,7 +1682,7 @@ mainswitch:
1676 ARMword result = op1 + op2; 1682 ARMword result = op1 + op2;
1677 if (AddOverflow(op1, op2, result)) { 1683 if (AddOverflow(op1, op2, result)) {
1678 result = POS (result) ? 0x80000000 : 0x7fffffff; 1684 result = POS (result) ? 0x80000000 : 0x7fffffff;
1679 SETS; 1685 SETQ;
1680 } 1686 }
1681 state->Reg[BITS (12, 15)] = result; 1687 state->Reg[BITS (12, 15)] = result;
1682 break; 1688 break;
@@ -1718,7 +1724,7 @@ mainswitch:
1718 TAKEABORT; 1724 TAKEABORT;
1719 } else if ((BITS (0, 11) == 0) && (LHSReg == 15)) { /* MRS CPSR */ 1725 } else if ((BITS (0, 11) == 0) && (LHSReg == 15)) { /* MRS CPSR */
1720 UNDEF_MRSPC; 1726 UNDEF_MRSPC;
1721 DEST = ECC | EINT | EMODE; 1727 DEST = ARMul_GetCPSR(state);
1722 } else { 1728 } else {
1723 UNDEF_Test; 1729 UNDEF_Test;
1724 } 1730 }
@@ -1737,7 +1743,7 @@ mainswitch:
1737 //chy 2006-02-15 if in user mode, can not set cpsr 0:23 1743 //chy 2006-02-15 if in user mode, can not set cpsr 0:23
1738 //from p165 of ARMARM book 1744 //from p165 of ARMARM book
1739 state->Cpsr = GETSPSR (state->Bank); 1745 state->Cpsr = GETSPSR (state->Bank);
1740 //ARMul_CPSRAltered (state); 1746 ARMul_CPSRAltered (state);
1741#else 1747#else
1742 rhs = DPRegRHS; 1748 rhs = DPRegRHS;
1743 temp = LHS & rhs; 1749 temp = LHS & rhs;
@@ -1789,7 +1795,7 @@ mainswitch:
1789 ARMword Rn = state->Reg[BITS(12, 15)]; 1795 ARMword Rn = state->Reg[BITS(12, 15)];
1790 1796
1791 if (AddOverflow((ARMword)result, Rn, (ARMword)(result + Rn))) 1797 if (AddOverflow((ARMword)result, Rn, (ARMword)(result + Rn)))
1792 SETS; 1798 SETQ;
1793 result += Rn; 1799 result += Rn;
1794 } 1800 }
1795 state->Reg[BITS (16, 19)] = (ARMword)result; 1801 state->Reg[BITS (16, 19)] = (ARMword)result;
@@ -1805,7 +1811,7 @@ mainswitch:
1805 if (SubOverflow 1811 if (SubOverflow
1806 (op1, op2, result)) { 1812 (op1, op2, result)) {
1807 result = POS (result) ? 0x80000000 : 0x7fffffff; 1813 result = POS (result) ? 0x80000000 : 0x7fffffff;
1808 SETS; 1814 SETQ;
1809 } 1815 }
1810 1816
1811 state->Reg[BITS (12, 15)] = result; 1817 state->Reg[BITS (12, 15)] = result;
@@ -1877,7 +1883,7 @@ mainswitch:
1877 /* TEQP reg */ 1883 /* TEQP reg */
1878#ifdef MODE32 1884#ifdef MODE32
1879 state->Cpsr = GETSPSR (state->Bank); 1885 state->Cpsr = GETSPSR (state->Bank);
1880 //ARMul_CPSRAltered (state); 1886 ARMul_CPSRAltered (state);
1881#else 1887#else
1882 rhs = DPRegRHS; 1888 rhs = DPRegRHS;
1883 temp = LHS ^ rhs; 1889 temp = LHS ^ rhs;
@@ -1928,13 +1934,13 @@ mainswitch:
1928 1934
1929 if (AddOverflow 1935 if (AddOverflow
1930 (op2, op2, op2d)) { 1936 (op2, op2, op2d)) {
1931 SETS; 1937 SETQ;
1932 op2d = POS (op2d) ? 0x80000000 : 0x7fffffff; 1938 op2d = POS (op2d) ? 0x80000000 : 0x7fffffff;
1933 } 1939 }
1934 1940
1935 result = op1 + op2d; 1941 result = op1 + op2d;
1936 if (AddOverflow(op1, op2d, result)) { 1942 if (AddOverflow(op1, op2d, result)) {
1937 SETS; 1943 SETQ;
1938 result = POS (result) ? 0x80000000 : 0x7fffffff; 1944 result = POS (result) ? 0x80000000 : 0x7fffffff;
1939 } 1945 }
1940 1946
@@ -1993,7 +1999,7 @@ mainswitch:
1993 /* CMPP reg. */ 1999 /* CMPP reg. */
1994#ifdef MODE32 2000#ifdef MODE32
1995 state->Cpsr = GETSPSR (state->Bank); 2001 state->Cpsr = GETSPSR (state->Bank);
1996 //ARMul_CPSRAltered (state); 2002 ARMul_CPSRAltered (state);
1997#else 2003#else
1998 rhs = DPRegRHS; 2004 rhs = DPRegRHS;
1999 temp = LHS - rhs; 2005 temp = LHS - rhs;
@@ -2047,13 +2053,13 @@ mainswitch:
2047 ARMword result; 2053 ARMword result;
2048 2054
2049 if (AddOverflow(op2, op2, op2d)) { 2055 if (AddOverflow(op2, op2, op2d)) {
2050 SETS; 2056 SETQ;
2051 op2d = POS (op2d) ? 0x80000000 : 0x7fffffff; 2057 op2d = POS (op2d) ? 0x80000000 : 0x7fffffff;
2052 } 2058 }
2053 2059
2054 result = op1 - op2d; 2060 result = op1 - op2d;
2055 if (SubOverflow(op1, op2d, result)) { 2061 if (SubOverflow(op1, op2d, result)) {
2056 SETS; 2062 SETQ;
2057 result = POS (result) ? 0x80000000 : 0x7fffffff; 2063 result = POS (result) ? 0x80000000 : 0x7fffffff;
2058 } 2064 }
2059 2065
@@ -2112,7 +2118,7 @@ mainswitch:
2112 if (DESTReg == 15) { 2118 if (DESTReg == 15) {
2113#ifdef MODE32 2119#ifdef MODE32
2114 state->Cpsr = GETSPSR (state->Bank); 2120 state->Cpsr = GETSPSR (state->Bank);
2115 //ARMul_CPSRAltered (state); 2121 ARMul_CPSRAltered (state);
2116#else 2122#else
2117 rhs = DPRegRHS; 2123 rhs = DPRegRHS;
2118 temp = LHS + rhs; 2124 temp = LHS + rhs;
@@ -2200,17 +2206,57 @@ mainswitch:
2200 Handle_Store_Double (state, instr); 2206 Handle_Store_Double (state, instr);
2201 break; 2207 break;
2202 } 2208 }
2209 if (BITS(4, 11) == 0xF9) { //strexd
2210 u32 l = LHSReg;
2211
2212 bool enter = false;
2213
2214 if (state->currentexval == (u32)ARMul_ReadWord(state, state->currentexaddr)&&
2215 state->currentexvald == (u32)ARMul_ReadWord(state, state->currentexaddr + 4))
2216 enter = true;
2217
2218
2219 //todo bug this and STREXD and LDREXD http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0360e/CHDGJGGC.html
2220
2221
2222 if (enter) {
2223 ARMul_StoreWordN(state, LHS, state->Reg[RHSReg]);
2224 ARMul_StoreWordN(state,LHS + 4 , state->Reg[RHSReg + 1]);
2225 state->Reg[DESTReg] = 0;
2226 } else {
2227 state->Reg[DESTReg] = 1;
2228 }
2229
2230 break;
2231 }
2203#endif 2232#endif
2204 dest = DPRegRHS; 2233 dest = DPRegRHS;
2205 WRITEDEST (dest); 2234 WRITEDEST (dest);
2206 break; 2235 break;
2207 2236
2208 case 0x1b: /* MOVS reg */ 2237 case 0x1B: /* MOVS reg */
2209#ifdef MODET 2238#ifdef MODET
2239 /* ldrexd ichfly */
2240 if (BITS(0, 11) == 0xF9F) { //strexd
2241 lhs = LHS;
2242
2243 state->currentexaddr = lhs;
2244 state->currentexval = (u32)ARMul_ReadWord(state, lhs);
2245 state->currentexvald = (u32)ARMul_ReadWord(state, lhs + 4);
2246
2247 state->Reg[DESTReg] = ARMul_LoadWordN(state, lhs);
2248 state->Reg[DESTReg] = ARMul_LoadWordN(state, lhs + 4);
2249 break;
2250 }
2251
2210 if ((BITS (4, 11) & 0xF9) == 0x9) 2252 if ((BITS (4, 11) & 0xF9) == 0x9)
2211 /* LDR register offset, write-back, up, pre indexed. */ 2253 /* LDR register offset, write-back, up, pre indexed. */
2212 LHPREUPWB (); 2254 LHPREUPWB ();
2213 /* Continue with remaining instruction decoding. */ 2255 /* Continue with remaining instruction decoding. */
2256
2257
2258
2259
2214#endif 2260#endif
2215 dest = DPSRegRHS; 2261 dest = DPSRegRHS;
2216 WRITESDEST (dest); 2262 WRITESDEST (dest);
@@ -2297,12 +2343,12 @@ mainswitch:
2297 if (state->currentexval == (u32)ARMul_LoadHalfWord(state, state->currentexaddr))enter = true; 2343 if (state->currentexval == (u32)ARMul_LoadHalfWord(state, state->currentexaddr))enter = true;
2298 2344
2299 2345
2300 ARMul_StoreHalfWord(state, lhs, RHS);
2301 //StoreWord(state, lhs, RHS) 2346 //StoreWord(state, lhs, RHS)
2302 if (state->Aborted) { 2347 if (state->Aborted) {
2303 TAKEABORT; 2348 TAKEABORT;
2304 } 2349 }
2305 if (enter) { 2350 if (enter) {
2351 ARMul_StoreHalfWord(state, lhs, RHS);
2306 state->Reg[DESTReg] = 0; 2352 state->Reg[DESTReg] = 0;
2307 } else { 2353 } else {
2308 state->Reg[DESTReg] = 1; 2354 state->Reg[DESTReg] = 1;
@@ -2520,7 +2566,7 @@ mainswitch:
2520 /* TSTP immed. */ 2566 /* TSTP immed. */
2521#ifdef MODE32 2567#ifdef MODE32
2522 state->Cpsr = GETSPSR (state->Bank); 2568 state->Cpsr = GETSPSR (state->Bank);
2523 //ARMul_CPSRAltered (state); 2569 ARMul_CPSRAltered (state);
2524#else 2570#else
2525 temp = LHS & DPImmRHS; 2571 temp = LHS & DPImmRHS;
2526 SETR15PSR (temp); 2572 SETR15PSR (temp);
@@ -2547,7 +2593,7 @@ mainswitch:
2547 /* TEQP immed. */ 2593 /* TEQP immed. */
2548#ifdef MODE32 2594#ifdef MODE32
2549 state->Cpsr = GETSPSR (state->Bank); 2595 state->Cpsr = GETSPSR (state->Bank);
2550 //ARMul_CPSRAltered (state); 2596 ARMul_CPSRAltered (state);
2551#else 2597#else
2552 temp = LHS ^ DPImmRHS; 2598 temp = LHS ^ DPImmRHS;
2553 SETR15PSR (temp); 2599 SETR15PSR (temp);
@@ -2568,7 +2614,7 @@ mainswitch:
2568 /* CMPP immed. */ 2614 /* CMPP immed. */
2569#ifdef MODE32 2615#ifdef MODE32
2570 state->Cpsr = GETSPSR (state->Bank); 2616 state->Cpsr = GETSPSR (state->Bank);
2571 //ARMul_CPSRAltered (state); 2617 ARMul_CPSRAltered (state);
2572#else 2618#else
2573 temp = LHS - DPImmRHS; 2619 temp = LHS - DPImmRHS;
2574 SETR15PSR (temp); 2620 SETR15PSR (temp);
@@ -2604,7 +2650,7 @@ mainswitch:
2604 /* CMNP immed. */ 2650 /* CMNP immed. */
2605#ifdef MODE32 2651#ifdef MODE32
2606 state->Cpsr = GETSPSR (state->Bank); 2652 state->Cpsr = GETSPSR (state->Bank);
2607 //ARMul_CPSRAltered (state); 2653 ARMul_CPSRAltered (state);
2608#else 2654#else
2609 temp = LHS + DPImmRHS; 2655 temp = LHS + DPImmRHS;
2610 SETR15PSR (temp); 2656 SETR15PSR (temp);
@@ -3054,27 +3100,21 @@ mainswitch:
3054 break; 3100 break;
3055 3101
3056 case 0x68: /* Store Word, No WriteBack, Post Inc, Reg. */ 3102 case 0x68: /* Store Word, No WriteBack, Post Inc, Reg. */
3057 //ichfly PKHBT PKHTB todo check this 3103 if ((instr & 0x70) == 0x10) { //pkhbt
3058 if ((instr & 0x70) == 0x10) //pkhbt
3059 {
3060 u8 idest = BITS(12, 15); 3104 u8 idest = BITS(12, 15);
3061 u8 rfis = BITS(16, 19); 3105 u8 rfis = BITS(16, 19);
3062 u8 rlast = BITS(0, 3); 3106 u8 rlast = BITS(0, 3);
3063 u8 ishi = BITS(7,11); 3107 u8 ishi = BITS(7,11);
3064 state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000); 3108 state->Reg[idest] = (state->Reg[rfis] & 0xFFFF) | ((state->Reg[rlast] << ishi) & 0xFFFF0000);
3065 break; 3109 break;
3066 } 3110 } else if ((instr & 0x70) == 0x50) { //pkhtb
3067 else if ((instr & 0x70) == 0x50)//pkhtb 3111 u8 rd_idx = BITS(12, 15);
3068 { 3112 u8 rn_idx = BITS(16, 19);
3069 u8 idest = BITS(12, 15); 3113 u8 rm_idx = BITS(0, 3);
3070 u8 rfis = BITS(16, 19); 3114 u8 imm5 = BITS(7, 11) ? BITS(7, 11) : 31;
3071 u8 rlast = BITS(0, 3); 3115 state->Reg[rd_idx] = ((static_cast<s32>(state->Reg[rm_idx]) >> imm5) & 0xFFFF) | ((state->Reg[rn_idx]) & 0xFFFF0000);
3072 u8 ishi = BITS(7, 11);
3073 if (ishi == 0)ishi = 0x20;
3074 state->Reg[idest] = (((int)(state->Reg[rlast]) >> (int)(ishi))& 0xFFFF) | ((state->Reg[rfis]) & 0xFFFF0000);
3075 break; 3116 break;
3076 } 3117 } else if (BIT (4)) {
3077 else if (BIT (4)) {
3078#ifdef MODE32 3118#ifdef MODE32
3079 if (state->is_v6 3119 if (state->is_v6
3080 && handle_v6_insn (state, instr)) 3120 && handle_v6_insn (state, instr))
@@ -3437,7 +3477,7 @@ mainswitch:
3437 3477
3438 case 0x7f: /* Load Byte, WriteBack, Pre Inc, Reg. */ 3478 case 0x7f: /* Load Byte, WriteBack, Pre Inc, Reg. */
3439 if (BIT (4)) { 3479 if (BIT (4)) {
3440 DEBUG("got unhandled special breakpoint\n"); 3480 LOG_DEBUG(Core_ARM11, "got unhandled special breakpoint");
3441 return 1; 3481 return 1;
3442 } 3482 }
3443 UNDEF_LSRBaseEQOffWb; 3483 UNDEF_LSRBaseEQOffWb;
@@ -3686,13 +3726,11 @@ mainswitch:
3686 3726
3687 /* Co-Processor Data Transfers. */ 3727 /* Co-Processor Data Transfers. */
3688 case 0xc4: 3728 case 0xc4:
3689 if ((instr & 0x0FF00FF0) == 0xC400B10) //vmov BIT(0-3), BIT(12-15), BIT(16-20), vmov d0, r0, r0 3729 if ((instr & 0x0FF00FF0) == 0xC400B10) { //vmov BIT(0-3), BIT(12-15), BIT(16-20), vmov d0, r0, r0
3690 {
3691 state->ExtReg[BITS(0, 3) << 1] = state->Reg[BITS(12, 15)]; 3730 state->ExtReg[BITS(0, 3) << 1] = state->Reg[BITS(12, 15)];
3692 state->ExtReg[(BITS(0, 3) << 1) + 1] = state->Reg[BITS(16, 20)]; 3731 state->ExtReg[(BITS(0, 3) << 1) + 1] = state->Reg[BITS(16, 20)];
3693 break; 3732 break;
3694 } 3733 } else if (state->is_v5) {
3695 else if (state->is_v5) {
3696 /* Reading from R15 is UNPREDICTABLE. */ 3734 /* Reading from R15 is UNPREDICTABLE. */
3697 if (BITS (12, 15) == 15 || BITS (16, 19) == 15) 3735 if (BITS (12, 15) == 15 || BITS (16, 19) == 15)
3698 ARMul_UndefInstr (state, instr); 3736 ARMul_UndefInstr (state, instr);
@@ -3712,22 +3750,18 @@ mainswitch:
3712 break; 3750 break;
3713 3751
3714 case 0xc5: 3752 case 0xc5:
3715 if ((instr & 0x00000FF0) == 0xB10) //vmov BIT(12-15), BIT(16-20), BIT(0-3) vmov r0, r0, d0 3753 if ((instr & 0x00000FF0) == 0xB10) { //vmov BIT(12-15), BIT(16-20), BIT(0-3) vmov r0, r0, d0
3716 {
3717 state->Reg[BITS(12, 15)] = state->ExtReg[BITS(0, 3) << 1]; 3754 state->Reg[BITS(12, 15)] = state->ExtReg[BITS(0, 3) << 1];
3718 state->Reg[BITS(16, 19)] = state->ExtReg[(BITS(0, 3) << 1) + 1]; 3755 state->Reg[BITS(16, 19)] = state->ExtReg[(BITS(0, 3) << 1) + 1];
3719 break; 3756 break;
3720 } 3757 } else if (state->is_v5) {
3721 else if (state->is_v5) {
3722 /* Writes to R15 are UNPREDICATABLE. */ 3758 /* Writes to R15 are UNPREDICATABLE. */
3723 if (DESTReg == 15 || LHSReg == 15) 3759 if (DESTReg == 15 || LHSReg == 15)
3724 ARMul_UndefInstr (state, instr); 3760 ARMul_UndefInstr (state, instr);
3725 /* Is access to the coprocessor allowed ? */ 3761 /* Is access to the coprocessor allowed ? */
3726 else if (!CP_ACCESS_ALLOWED(state, CPNum)) 3762 else if (!CP_ACCESS_ALLOWED(state, CPNum)) {
3727 {
3728 ARMul_UndefInstr(state, instr); 3763 ARMul_UndefInstr(state, instr);
3729 } 3764 } else {
3730 else {
3731 /* MRRC, ARMv5TE and up */ 3765 /* MRRC, ARMv5TE and up */
3732 ARMul_MRRC (state, instr, &DEST, &(state->Reg[LHSReg])); 3766 ARMul_MRRC (state, instr, &DEST, &(state->Reg[LHSReg]));
3733 break; 3767 break;
@@ -4565,7 +4599,7 @@ out:
4565#ifdef MODE32 4599#ifdef MODE32
4566 if (state->Bank > 0) { 4600 if (state->Bank > 0) {
4567 state->Cpsr = state->Spsr[state->Bank]; 4601 state->Cpsr = state->Spsr[state->Bank];
4568 //ARMul_CPSRAltered (state); 4602 ARMul_CPSRAltered (state);
4569 } 4603 }
4570#ifdef MODET 4604#ifdef MODET
4571 if (TFLAG) 4605 if (TFLAG)
@@ -5256,7 +5290,7 @@ L_ldm_s_makeabort:
5256 //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode 5290 //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode
5257 if (state->Mode != USER26MODE && state->Mode != USER32MODE ) { 5291 if (state->Mode != USER26MODE && state->Mode != USER32MODE ) {
5258 state->Cpsr = GETSPSR (state->Bank); 5292 state->Cpsr = GETSPSR (state->Bank);
5259 //ARMul_CPSRAltered (state); 5293 ARMul_CPSRAltered (state);
5260 } 5294 }
5261 5295
5262 WriteR15 (state, PC); 5296 WriteR15 (state, PC);
@@ -5639,37 +5673,29 @@ L_stm_s_takeabort:
5639 /* Attempt to emulate an ARMv6 instruction. 5673 /* Attempt to emulate an ARMv6 instruction.
5640 Returns non-zero upon success. */ 5674 Returns non-zero upon success. */
5641 5675
5642 static int 5676 static int handle_v6_insn(ARMul_State* state, ARMword instr) {
5643 handle_v6_insn (ARMul_State * state, ARMword instr) { 5677 switch (BITS(20, 27)) {
5644 switch (BITS (20, 27)) {
5645 //ichfly
5646 case 0x66: //UQSUB8
5647 if ((instr & 0x0FF00FF0) == 0x06600FF0) {
5648 u32 rd = (instr >> 12) & 0xF;
5649 u32 rm = (instr >> 16) & 0xF;
5650 u32 rn = (instr >> 0) & 0xF;
5651 u32 subfrom = state->Reg[rm];
5652 u32 tosub = state->Reg[rn];
5653
5654 u8 b1 = (u8)((u8)(subfrom)-(u8)(tosub));
5655 if (b1 > (u8)(subfrom)) b1 = 0;
5656 u8 b2 = (u8)((u8)(subfrom >> 8) - (u8)(tosub >> 8));
5657 if (b2 > (u8)(subfrom >> 8)) b2 = 0;
5658 u8 b3 = (u8)((u8)(subfrom >> 16) - (u8)(tosub >> 16));
5659 if (b3 > (u8)(subfrom >> 16)) b3 = 0;
5660 u8 b4 = (u8)((u8)(subfrom >> 24) - (u8)(tosub >> 24));
5661 if (b4 > (u8)(subfrom >> 24)) b4 = 0;
5662 state->Reg[rd] = (u32)(b1 | b2 << 8 | b3 << 16 | b4 << 24);
5663 return 1;
5664 } else {
5665 printf("UQSUB8 decoding fail %08X",instr);
5666 }
5667#if 0
5668 case 0x03: 5678 case 0x03:
5669 printf ("Unhandled v6 insn: ldr\n"); 5679 printf ("Unhandled v6 insn: ldr\n");
5670 break; 5680 break;
5671 case 0x04: 5681 case 0x04: // UMAAL
5672 printf ("Unhandled v6 insn: umaal\n"); 5682 {
5683 const u8 rm_idx = BITS(8, 11);
5684 const u8 rn_idx = BITS(0, 3);
5685 const u8 rd_lo_idx = BITS(12, 15);
5686 const u8 rd_hi_idx = BITS(16, 19);
5687
5688 const u32 rm_val = state->Reg[rm_idx];
5689 const u32 rn_val = state->Reg[rn_idx];
5690 const u32 rd_lo_val = state->Reg[rd_lo_idx];
5691 const u32 rd_hi_val = state->Reg[rd_hi_idx];
5692
5693 const u64 result = (rn_val * rm_val) + rd_lo_val + rd_hi_val;
5694
5695 state->Reg[rd_lo_idx] = (result & 0xFFFFFFFF);
5696 state->Reg[rd_hi_idx] = ((result >> 32) & 0xFFFFFFFF);
5697 return 1;
5698 }
5673 break; 5699 break;
5674 case 0x06: 5700 case 0x06:
5675 printf ("Unhandled v6 insn: mls/str\n"); 5701 printf ("Unhandled v6 insn: mls/str\n");
@@ -5678,9 +5704,43 @@ L_stm_s_takeabort:
5678 printf ("Unhandled v6 insn: smi\n"); 5704 printf ("Unhandled v6 insn: smi\n");
5679 break; 5705 break;
5680 case 0x18: 5706 case 0x18:
5707 if (BITS(4, 7) == 0x9) {
5708 /* strex */
5709 u32 l = LHSReg;
5710 u32 r = RHSReg;
5711 u32 lhs = LHS;
5712
5713 bool enter = false;
5714
5715 if (state->currentexval == (u32)ARMul_ReadWord(state, state->currentexaddr))enter = true;
5716 //StoreWord(state, lhs, RHS)
5717 if (state->Aborted) {
5718 TAKEABORT;
5719 }
5720
5721 if (enter) {
5722 ARMul_StoreWordS(state, lhs, RHS);
5723 state->Reg[DESTReg] = 0;
5724 }
5725 else {
5726 state->Reg[DESTReg] = 1;
5727 }
5728
5729 return 1;
5730 }
5681 printf ("Unhandled v6 insn: strex\n"); 5731 printf ("Unhandled v6 insn: strex\n");
5682 break; 5732 break;
5683 case 0x19: 5733 case 0x19:
5734 /* ldrex */
5735 if (BITS(4, 7) == 0x9) {
5736 u32 lhs = LHS;
5737
5738 state->currentexaddr = lhs;
5739 state->currentexval = ARMul_ReadWord(state, lhs);
5740
5741 LoadWord(state, instr, lhs);
5742 return 1;
5743 }
5684 printf ("Unhandled v6 insn: ldrex\n"); 5744 printf ("Unhandled v6 insn: ldrex\n");
5685 break; 5745 break;
5686 case 0x1a: 5746 case 0x1a:
@@ -5690,9 +5750,52 @@ L_stm_s_takeabort:
5690 printf ("Unhandled v6 insn: ldrexd\n"); 5750 printf ("Unhandled v6 insn: ldrexd\n");
5691 break; 5751 break;
5692 case 0x1c: 5752 case 0x1c:
5753 if (BITS(4, 7) == 0x9) {
5754 /* strexb */
5755 u32 lhs = LHS;
5756
5757 bool enter = false;
5758
5759 if (state->currentexval == (u32)ARMul_ReadByte(state, state->currentexaddr))enter = true;
5760
5761 BUSUSEDINCPCN;
5762 if (state->Aborted) {
5763 TAKEABORT;
5764 }
5765
5766
5767 if (enter) {
5768 ARMul_StoreByte(state, lhs, RHS);
5769 state->Reg[DESTReg] = 0;
5770 }
5771 else {
5772 state->Reg[DESTReg] = 1;
5773 }
5774
5775 //printf("In %s, strexb not implemented\n", __FUNCTION__);
5776 UNDEF_LSRBPC;
5777 /* WRITESDEST (dest); */
5778 return 1;
5779 }
5693 printf ("Unhandled v6 insn: strexb\n"); 5780 printf ("Unhandled v6 insn: strexb\n");
5694 break; 5781 break;
5695 case 0x1d: 5782 case 0x1d:
5783 if ((BITS(4, 7)) == 0x9) {
5784 /* ldrexb */
5785 u32 lhs = LHS;
5786 LoadByte(state, instr, lhs, LUNSIGNED);
5787
5788 state->currentexaddr = lhs;
5789 state->currentexval = (u32)ARMul_ReadByte(state, lhs);
5790
5791 //state->Reg[BITS(12, 15)] = ARMul_LoadByte(state, state->Reg[BITS(16, 19)]);
5792 //printf("ldrexb\n");
5793 //printf("instr is %x rm is %d\n", instr, BITS(16, 19));
5794 //exit(-1);
5795
5796 //printf("In %s, ldrexb not implemented\n", __FUNCTION__);
5797 return 1;
5798 }
5696 printf ("Unhandled v6 insn: ldrexb\n"); 5799 printf ("Unhandled v6 insn: ldrexb\n");
5697 break; 5800 break;
5698 case 0x1e: 5801 case 0x1e:
@@ -5713,510 +5816,801 @@ L_stm_s_takeabort:
5713 case 0x3f: 5816 case 0x3f:
5714 printf ("Unhandled v6 insn: rbit\n"); 5817 printf ("Unhandled v6 insn: rbit\n");
5715 break; 5818 break;
5716#endif 5819 case 0x61: // SADD16, SASX, SSAX, and SSUB16
5717 case 0x61: 5820 if ((instr & 0xFF0) == 0xf10 || (instr & 0xFF0) == 0xf30 ||
5718 if ((instr & 0xFF0) == 0xf70)//ssub16 5821 (instr & 0xFF0) == 0xf50 || (instr & 0xFF0) == 0xf70)
5719 {
5720 u8 tar = BITS(12, 15);
5721 u8 src1 = BITS(16, 19);
5722 u8 src2 = BITS(0, 3);
5723 s16 a1 = (state->Reg[src1] & 0xFFFF);
5724 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
5725 s16 b1 = (state->Reg[src2] & 0xFFFF);
5726 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
5727 state->Reg[tar] = (a1 - a2)&0xFFFF | (((b1 - b2)&0xFFFF)<< 0x10);
5728 return 1;
5729 }
5730 else if ((instr & 0xFF0) == 0xf10)//sadd16
5731 { 5822 {
5732 u8 tar = BITS(12, 15); 5823 const u8 rd_idx = BITS(12, 15);
5733 u8 src1 = BITS(16, 19); 5824 const u8 rm_idx = BITS(0, 3);
5734 u8 src2 = BITS(0, 3); 5825 const u8 rn_idx = BITS(16, 19);
5735 s16 a1 = (state->Reg[src1] & 0xFFFF); 5826 const s16 rn_lo = (state->Reg[rn_idx] & 0xFFFF);
5736 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); 5827 const s16 rn_hi = ((state->Reg[rn_idx] >> 16) & 0xFFFF);
5737 s16 b1 = (state->Reg[src2] & 0xFFFF); 5828 const s16 rm_lo = (state->Reg[rm_idx] & 0xFFFF);
5738 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); 5829 const s16 rm_hi = ((state->Reg[rm_idx] >> 16) & 0xFFFF);
5739 state->Reg[tar] = (a1 + a2)&0xFFFF | (((b1 + b2)&0xFFFF)<< 0x10); 5830
5831 s32 lo_result;
5832 s32 hi_result;
5833
5834 // SADD16
5835 if ((instr & 0xFF0) == 0xf10) {
5836 lo_result = (rn_lo + rm_lo);
5837 hi_result = (rn_hi + rm_hi);
5838 }
5839 // SASX
5840 else if ((instr & 0xFF0) == 0xf30) {
5841 lo_result = (rn_lo - rm_hi);
5842 hi_result = (rn_hi + rm_lo);
5843 }
5844 // SSAX
5845 else if ((instr & 0xFF0) == 0xf50) {
5846 lo_result = (rn_lo + rm_hi);
5847 hi_result = (rn_hi - rm_lo);
5848 }
5849 // SSUB16
5850 else {
5851 lo_result = (rn_lo - rm_lo);
5852 hi_result = (rn_hi - rm_hi);
5853 }
5854
5855 state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);
5856
5857 if (lo_result >= 0) {
5858 state->GEFlag |= (1 << 16);
5859 state->GEFlag |= (1 << 17);
5860 } else {
5861 state->GEFlag &= ~(1 << 16);
5862 state->GEFlag &= ~(1 << 17);
5863 }
5864
5865 if (hi_result >= 0) {
5866 state->GEFlag |= (1 << 18);
5867 state->GEFlag |= (1 << 19);
5868 } else {
5869 state->GEFlag &= ~(1 << 18);
5870 state->GEFlag &= ~(1 << 19);
5871 }
5872
5740 return 1; 5873 return 1;
5741 } 5874 }
5742 else if ((instr & 0xFF0) == 0xf50)//ssax 5875 // SADD8/SSUB8
5876 else if ((instr & 0xFF0) == 0xf90 || (instr & 0xFF0) == 0xff0)
5743 { 5877 {
5744 u8 tar = BITS(12, 15); 5878 const u8 rd_idx = BITS(12, 15);
5745 u8 src1 = BITS(16, 19); 5879 const u8 rm_idx = BITS(0, 3);
5746 u8 src2 = BITS(0, 3); 5880 const u8 rn_idx = BITS(16, 19);
5747 s16 a1 = (state->Reg[src1] & 0xFFFF); 5881 const u32 rm_val = state->Reg[rm_idx];
5748 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); 5882 const u32 rn_val = state->Reg[rn_idx];
5749 s16 b1 = (state->Reg[src2] & 0xFFFF); 5883
5750 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); 5884 u8 lo_val1;
5751 state->Reg[tar] = (a1 - b2) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10); 5885 u8 lo_val2;
5886 u8 hi_val1;
5887 u8 hi_val2;
5888
5889 // SADD8
5890 if ((instr & 0xFF0) == 0xf90) {
5891 lo_val1 = (u8)((rn_val & 0xFF) + (rm_val & 0xFF));
5892 lo_val2 = (u8)(((rn_val >> 8) & 0xFF) + ((rm_val >> 8) & 0xFF));
5893 hi_val1 = (u8)(((rn_val >> 16) & 0xFF) + ((rm_val >> 16) & 0xFF));
5894 hi_val2 = (u8)(((rn_val >> 24) & 0xFF) + ((rm_val >> 24) & 0xFF));
5895
5896 if (lo_val1 & 0x80)
5897 state->GEFlag |= (1 << 16);
5898 else
5899 state->GEFlag &= ~(1 << 16);
5900
5901 if (lo_val2 & 0x80)
5902 state->GEFlag |= (1 << 17);
5903 else
5904 state->GEFlag &= ~(1 << 17);
5905
5906 if (hi_val1 & 0x80)
5907 state->GEFlag |= (1 << 18);
5908 else
5909 state->GEFlag &= ~(1 << 18);
5910
5911 if (hi_val2 & 0x80)
5912 state->GEFlag |= (1 << 19);
5913 else
5914 state->GEFlag &= ~(1 << 19);
5915 }
5916 // SSUB8
5917 else {
5918 lo_val1 = (u8)((rn_val & 0xFF) - (rm_val & 0xFF));
5919 lo_val2 = (u8)(((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF));
5920 hi_val1 = (u8)(((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF));
5921 hi_val2 = (u8)(((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF));
5922
5923 if (!(lo_val1 & 0x80))
5924 state->GEFlag |= (1 << 16);
5925 else
5926 state->GEFlag &= ~(1 << 16);
5927
5928 if (!(lo_val2 & 0x80))
5929 state->GEFlag |= (1 << 17);
5930 else
5931 state->GEFlag &= ~(1 << 17);
5932
5933 if (!(hi_val1 & 0x80))
5934 state->GEFlag |= (1 << 18);
5935 else
5936 state->GEFlag &= ~(1 << 18);
5937
5938 if (!(hi_val2 & 0x80))
5939 state->GEFlag |= (1 << 19);
5940 else
5941 state->GEFlag &= ~(1 << 19);
5942 }
5943
5944 state->Reg[rd_idx] = (lo_val1 | lo_val2 << 8 | hi_val1 << 16 | hi_val2 << 24);
5752 return 1; 5945 return 1;
5753 } 5946 }
5754 else if ((instr & 0xFF0) == 0xf30)//sasx 5947 else {
5755 { 5948 printf("Unhandled v6 insn: %08x", instr);
5756 u8 tar = BITS(12, 15);
5757 u8 src1 = BITS(16, 19);
5758 u8 src2 = BITS(0, 3);
5759 s16 a1 = (state->Reg[src1] & 0xFFFF);
5760 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
5761 s16 b1 = (state->Reg[src2] & 0xFFFF);
5762 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
5763 state->Reg[tar] = (a2 - b1) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10);
5764 return 1;
5765 } 5949 }
5766 else printf ("Unhandled v6 insn: sadd/ssub\n");
5767 break; 5950 break;
5768 case 0x62: 5951 case 0x62: // QADD16, QASX, QSAX, QSUB16, QADD8, and QSUB8
5769 if ((instr & 0xFF0) == 0xf70)//QSUB16
5770 { 5952 {
5771 u8 tar = BITS(12, 15); 5953 const u8 op2 = BITS(5, 7);
5772 u8 src1 = BITS(16, 19); 5954
5773 u8 src2 = BITS(0, 3); 5955 const u8 rd_idx = BITS(12, 15);
5774 s16 a1 = (state->Reg[src1] & 0xFFFF); 5956 const u8 rn_idx = BITS(16, 19);
5775 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); 5957 const u8 rm_idx = BITS(0, 3);
5776 s16 b1 = (state->Reg[src2] & 0xFFFF); 5958 const u16 rm_lo = (state->Reg[rm_idx] & 0xFFFF);
5777 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); 5959 const u16 rm_hi = ((state->Reg[rm_idx] >> 0x10) & 0xFFFF);
5778 s32 res1 = (a1 - b1); 5960 const u16 rn_lo = (state->Reg[rn_idx] & 0xFFFF);
5779 s32 res2 = (a2 - b2); 5961 const u16 rn_hi = ((state->Reg[rn_idx] >> 0x10) & 0xFFFF);
5780 if (res1 > 0x7FFF) res1 = 0x7FFF; 5962
5781 if (res2 > 0x7FFF) res2 = 0x7FFF; 5963 u16 lo_result = 0;
5782 if (res1 < 0x7FFF) res1 = -0x8000; 5964 u16 hi_result = 0;
5783 if (res2 < 0x7FFF) res2 = -0x8000; 5965
5784 state->Reg[tar] = (res1 & 0xFFFF) | ((res2 & 0xFFFF) << 0x10); 5966 // QADD16
5785 return 1; 5967 if (op2 == 0x00) {
5786 } 5968 lo_result = ARMul_SignedSaturatedAdd16(rn_lo, rm_lo);
5787 else if ((instr & 0xFF0) == 0xf10)//QADD16 5969 hi_result = ARMul_SignedSaturatedAdd16(rn_hi, rm_hi);
5788 { 5970 }
5789 u8 tar = BITS(12, 15); 5971 // QASX
5790 u8 src1 = BITS(16, 19); 5972 else if (op2 == 0x01) {
5791 u8 src2 = BITS(0, 3); 5973 lo_result = ARMul_SignedSaturatedSub16(rn_lo, rm_hi);
5792 s16 a1 = (state->Reg[src1] & 0xFFFF); 5974 hi_result = ARMul_SignedSaturatedAdd16(rn_hi, rm_lo);
5793 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); 5975 }
5794 s16 b1 = (state->Reg[src2] & 0xFFFF); 5976 // QSAX
5795 s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF); 5977 else if (op2 == 0x02) {
5796 s32 res1 = (a1 + b1); 5978 lo_result = ARMul_SignedSaturatedAdd16(rn_lo, rm_hi);
5797 s32 res2 = (a2 + b2); 5979 hi_result = ARMul_SignedSaturatedSub16(rn_hi, rm_lo);
5798 if (res1 > 0x7FFF) res1 = 0x7FFF; 5980 }
5799 if (res2 > 0x7FFF) res2 = 0x7FFF; 5981 // QSUB16
5800 if (res1 < 0x7FFF) res1 = -0x8000; 5982 else if (op2 == 0x03) {
5801 if (res2 < 0x7FFF) res2 = -0x8000; 5983 lo_result = ARMul_SignedSaturatedSub16(rn_lo, rm_lo);
5802 state->Reg[tar] = ((res1) & 0xFFFF) | (((res2) & 0xFFFF) << 0x10); 5984 hi_result = ARMul_SignedSaturatedSub16(rn_hi, rm_hi);
5985 }
5986 // QADD8
5987 else if (op2 == 0x04) {
5988 lo_result = ARMul_SignedSaturatedAdd8(rn_lo & 0xFF, rm_lo & 0xFF) |
5989 ARMul_SignedSaturatedAdd8(rn_lo >> 8, rm_lo >> 8) << 8;
5990 hi_result = ARMul_SignedSaturatedAdd8(rn_hi & 0xFF, rm_hi & 0xFF) |
5991 ARMul_SignedSaturatedAdd8(rn_hi >> 8, rm_hi >> 8) << 8;
5992 }
5993 // QSUB8
5994 else if (op2 == 0x07) {
5995 lo_result = ARMul_SignedSaturatedSub8(rn_lo & 0xFF, rm_lo & 0xFF) |
5996 ARMul_SignedSaturatedSub8(rn_lo >> 8, rm_lo >> 8) << 8;
5997 hi_result = ARMul_SignedSaturatedSub8(rn_hi & 0xFF, rm_hi & 0xFF) |
5998 ARMul_SignedSaturatedSub8(rn_hi >> 8, rm_hi >> 8) << 8;
5999 }
6000
6001 state->Reg[rd_idx] = (lo_result & 0xFFFF) | ((hi_result & 0xFFFF) << 16);
5803 return 1; 6002 return 1;
5804 } 6003 }
5805 else printf ("Unhandled v6 insn: qadd/qsub\n");
5806 break; 6004 break;
5807#if 0
5808 case 0x63: 6005 case 0x63:
5809 printf ("Unhandled v6 insn: shadd/shsub\n"); 6006 printf ("Unhandled v6 insn: shadd/shsub\n");
5810 break; 6007 break;
5811 case 0x65: 6008 case 0x65:
5812 printf ("Unhandled v6 insn: uadd/usub\n"); 6009 {
5813 break; 6010 u32 rd = (instr >> 12) & 0xF;
5814 case 0x66: 6011 u32 rn = (instr >> 16) & 0xF;
5815 printf ("Unhandled v6 insn: uqadd/uqsub\n"); 6012 u32 rm = (instr >> 0) & 0xF;
5816 break; 6013 u32 from = state->Reg[rn];
5817 case 0x67: 6014 u32 to = state->Reg[rm];
5818 printf ("Unhandled v6 insn: uhadd/uhsub\n"); 6015
5819 break; 6016 if ((instr & 0xFF0) == 0xF10 || (instr & 0xFF0) == 0xF70) { // UADD16/USUB16
5820 case 0x68: 6017 u32 h1, h2;
5821 printf ("Unhandled v6 insn: pkh/sxtab/selsxtb\n"); 6018 state->Cpsr &= 0xfff0ffff;
5822 break; 6019 if ((instr & 0x0F0) == 0x070) { // USUB16
5823#endif 6020 h1 = ((u16)from - (u16)to);
5824 case 0x6c: 6021 h2 = ((u16)(from >> 16) - (u16)(to >> 16));
5825 if ((instr & 0xf03f0) == 0xf0070) //uxtb16 6022
5826 { 6023 if (!(h1 & 0xffff0000))
5827 u8 src1 = BITS(0, 3); 6024 state->GEFlag |= (3 << 16);
5828 u8 tar = BITS(12, 15); 6025 else
5829 u32 base = state->Reg[src1]; 6026 state->GEFlag &= ~(3 << 16);
5830 u32 shamt = BITS(9,10)* 8;
5831 u32 in = ((base << (32 - shamt)) | (base >> shamt));
5832 state->Reg[tar] = in & 0x00FF00FF;
5833 return 1;
5834 }
5835 else
5836 printf ("Unhandled v6 insn: uxtb16/uxtab16\n");
5837 break;
5838 case 0x70:
5839 if ((instr & 0xf0d0) == 0xf010)//smuad //ichfly
5840 {
5841 u8 tar = BITS(16, 19);
5842 u8 src1 = BITS(0, 3);
5843 u8 src2 = BITS(8, 11);
5844 u8 swap = BIT(5);
5845 s16 a1 = (state->Reg[src1] & 0xFFFF);
5846 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
5847 s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF);
5848 s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF);
5849 state->Reg[tar] = a1*a2 + b1*b2;
5850 return 1;
5851 6027
5852 } 6028 if (!(h2 & 0xffff0000))
5853 else if ((instr & 0xf0d0) == 0xf050)//smusd 6029 state->GEFlag |= (3 << 18);
5854 { 6030 else
5855 u8 tar = BITS(16, 19); 6031 state->GEFlag &= ~(3 << 18);
5856 u8 src1 = BITS(0, 3); 6032 }
5857 u8 src2 = BITS(8, 11); 6033 else { // UADD16
5858 u8 swap = BIT(5); 6034 h1 = ((u16)from + (u16)to);
5859 s16 a1 = (state->Reg[src1] & 0xFFFF); 6035 h2 = ((u16)(from >> 16) + (u16)(to >> 16));
5860 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF); 6036
5861 s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF); 6037 if (h1 & 0xffff0000)
5862 s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF); 6038 state->GEFlag |= (3 << 16);
5863 state->Reg[tar] = a1*a2 - b1*b2; 6039 else
5864 return 1; 6040 state->GEFlag &= ~(3 << 16);
5865 } 6041
5866 else if ((instr & 0xd0) == 0x10)//smlad 6042 if (h2 & 0xffff0000)
5867 { 6043 state->GEFlag |= (3 << 18);
5868 u8 tar = BITS(16, 19); 6044 else
5869 u8 src1 = BITS(0, 3); 6045 state->GEFlag &= ~(3 << 18);
5870 u8 src2 = BITS(8, 11); 6046 }
5871 u8 src3 = BITS(12, 15); 6047
5872 u8 swap = BIT(5); 6048 state->Reg[rd] = (u32)((h1 & 0xffff) | ((h2 & 0xffff) << 16));
5873
5874 u32 a3 = state->Reg[src3];
5875
5876 s16 a1 = (state->Reg[src1] & 0xFFFF);
5877 s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
5878 s16 b1 = swap ? ((state->Reg[src2] >> 0x10) & 0xFFFF) : (state->Reg[src2] & 0xFFFF);
5879 s16 b2 = swap ? (state->Reg[src2] & 0xFFFF) : ((state->Reg[src2] >> 0x10) & 0xFFFF);
5880 state->Reg[tar] = a1*a2 + b1*b2 + a3;
5881 return 1; 6049 return 1;
5882 } 6050 }
5883 else printf ("Unhandled v6 insn: smuad/smusd/smlad/smlsd\n"); 6051 else
5884 break; 6052 if ((instr & 0xFF0) == 0xF90 || (instr & 0xFF0) == 0xFF0) { // UADD8/USUB8
5885 case 0x74: 6053 u32 b1, b2, b3, b4;
5886 printf ("Unhandled v6 insn: smlald/smlsld\n"); 6054 state->Cpsr &= 0xfff0ffff;
5887 break; 6055 if ((instr & 0x0F0) == 0x0F0) { // USUB8
5888 case 0x75: 6056 b1 = ((u8)from - (u8)to);
5889 printf ("Unhandled v6 insn: smmla/smmls/smmul\n"); 6057 b2 = ((u8)(from >> 8) - (u8)(to >> 8));
5890 break; 6058 b3 = ((u8)(from >> 16) - (u8)(to >> 16));
5891 case 0x78: 6059 b4 = ((u8)(from >> 24) - (u8)(to >> 24));
5892 printf ("Unhandled v6 insn: usad/usada8\n"); 6060
5893 break; 6061 if (!(b1 & 0xffffff00))
5894#if 0 6062 state->GEFlag |= (1 << 16);
5895 case 0x7a: 6063 else
5896 printf ("Unhandled v6 insn: usbfx\n"); 6064 state->GEFlag &= ~(1 << 16);
5897 break;
5898 case 0x7c:
5899 printf ("Unhandled v6 insn: bfc/bfi\n");
5900 break;
5901#endif
5902 6065
6066 if (!(b2 & 0xffffff00))
6067 state->GEFlag |= (1 << 17);
6068 else
6069 state->GEFlag &= ~(1 << 17);
5903 6070
5904 /* add new instr for arm v6. */ 6071 if (!(b3 & 0xffffff00))
5905 ARMword lhs, temp; 6072 state->GEFlag |= (1 << 18);
5906 case 0x18: { /* ORR reg */ 6073 else
5907 /* dyf add armv6 instr strex 2010.9.17 */ 6074 state->GEFlag &= ~(1 << 18);
5908 if (BITS (4, 7) == 0x9) {
5909 u32 l = LHSReg;
5910 u32 r = RHSReg;
5911 lhs = LHS;
5912 6075
5913 bool enter = false; 6076 if (!(b4 & 0xffffff00))
6077 state->GEFlag |= (1 << 19);
6078 else
6079 state->GEFlag &= ~(1 << 19);
6080 }
6081 else { // UADD8
6082 b1 = ((u8)from + (u8)to);
6083 b2 = ((u8)(from >> 8) + (u8)(to >> 8));
6084 b3 = ((u8)(from >> 16) + (u8)(to >> 16));
6085 b4 = ((u8)(from >> 24) + (u8)(to >> 24));
5914 6086
5915 if (state->currentexval == (u32)ARMul_ReadWord(state, state->currentexaddr))enter = true; 6087 if (b1 & 0xffffff00)
5916 ARMul_StoreWordS(state, lhs, RHS); 6088 state->GEFlag |= (1 << 16);
5917 //StoreWord(state, lhs, RHS) 6089 else
5918 if (state->Aborted) { 6090 state->GEFlag &= ~(1 << 16);
5919 TAKEABORT;
5920 }
5921 6091
5922 if (enter) { 6092 if (b2 & 0xffffff00)
5923 state->Reg[DESTReg] = 0; 6093 state->GEFlag |= (1 << 17);
5924 } else { 6094 else
5925 state->Reg[DESTReg] = 1; 6095 state->GEFlag &= ~(1 << 17);
5926 }
5927 6096
5928 return 1; 6097 if (b3 & 0xffffff00)
5929 } 6098 state->GEFlag |= (1 << 18);
5930 break; 6099 else
5931 } 6100 state->GEFlag &= ~(1 << 18);
5932 6101
5933 case 0x19: { /* orrs reg */ 6102 if (b4 & 0xffffff00)
5934 /* dyf add armv6 instr ldrex */ 6103 state->GEFlag |= (1 << 19);
5935 if (BITS (4, 7) == 0x9) { 6104 else
5936 lhs = LHS; 6105 state->GEFlag &= ~(1 << 19);
6106 }
5937 6107
5938 state->currentexaddr = lhs; 6108 state->Reg[rd] = (u32)(b1 | (b2 & 0xff) << 8 | (b3 & 0xff) << 16 | (b4 & 0xff) << 24);
5939 state->currentexval = ARMul_ReadWord(state, lhs); 6109 return 1;
6110 }
6111 }
6112 printf("Unhandled v6 insn: uasx/usax\n");
6113 break;
6114 case 0x66: // UQADD16, UQASX, UQSAX, UQSUB16, UQADD8, and UQSUB8
6115 {
6116 const u8 rd_idx = BITS(12, 15);
6117 const u8 rm_idx = BITS(0, 3);
6118 const u8 rn_idx = BITS(16, 19);
6119 const u8 op2 = BITS(5, 7);
6120 const u32 rm_val = state->Reg[rm_idx];
6121 const u32 rn_val = state->Reg[rn_idx];
6122
6123 u16 lo_val = 0;
6124 u16 hi_val = 0;
6125
6126 // UQADD16
6127 if (op2 == 0x00) {
6128 lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, rm_val & 0xFFFF);
6129 hi_val = ARMul_UnsignedSaturatedAdd16((rn_val >> 16) & 0xFFFF, (rm_val >> 16) & 0xFFFF);
6130 }
6131 // UQASX
6132 else if (op2 == 0x01) {
6133 lo_val = ARMul_UnsignedSaturatedSub16(rn_val & 0xFFFF, (rm_val >> 16) & 0xFFFF);
6134 hi_val = ARMul_UnsignedSaturatedAdd16((rn_val >> 16) & 0xFFFF, rm_val & 0xFFFF);
6135 }
6136 // UQSAX
6137 else if (op2 == 0x02) {
6138 lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, (rm_val >> 16) & 0xFFFF);
6139 hi_val = ARMul_UnsignedSaturatedSub16((rn_val >> 16) & 0xFFFF, rm_val & 0xFFFF);
6140 }
6141 // UQSUB16
6142 else if (op2 == 0x03) {
6143 lo_val = ARMul_UnsignedSaturatedSub16(rn_val & 0xFFFF, rm_val & 0xFFFF);
6144 hi_val = ARMul_UnsignedSaturatedSub16((rn_val >> 16) & 0xFFFF, (rm_val >> 16) & 0xFFFF);
6145 }
6146 // UQADD8
6147 else if (op2 == 0x04) {
6148 lo_val = ARMul_UnsignedSaturatedAdd8(rn_val, rm_val) |
6149 ARMul_UnsignedSaturatedAdd8(rn_val >> 8, rm_val >> 8) << 8;
6150 hi_val = ARMul_UnsignedSaturatedAdd8(rn_val >> 16, rm_val >> 16) |
6151 ARMul_UnsignedSaturatedAdd8(rn_val >> 24, rm_val >> 24) << 8;
6152 }
6153 // UQSUB8
6154 else {
6155 lo_val = ARMul_UnsignedSaturatedSub8(rn_val, rm_val) |
6156 ARMul_UnsignedSaturatedSub8(rn_val >> 8, rm_val >> 8) << 8;
6157 hi_val = ARMul_UnsignedSaturatedSub8(rn_val >> 16, rm_val >> 16) |
6158 ARMul_UnsignedSaturatedSub8(rn_val >> 24, rm_val >> 24) << 8;
6159 }
5940 6160
5941 LoadWord (state, instr, lhs); 6161 state->Reg[rd_idx] = ((lo_val & 0xFFFF) | hi_val << 16);
5942 return 1; 6162 return 1;
5943 } 6163 }
5944 break; 6164 break;
5945 } 6165 case 0x67: // UHADD16, UHASX, UHSAX, UHSUB16, UHADD8, and UHSUB8.
6166 {
6167 const u8 op2 = BITS(5, 7);
5946 6168
5947 case 0x1c: { /* BIC reg */ 6169 const u8 rm_idx = BITS(0, 3);
5948 /* dyf add for STREXB */ 6170 const u8 rn_idx = BITS(16, 19);
5949 if (BITS (4, 7) == 0x9) { 6171 const u8 rd_idx = BITS(12, 15);
5950 lhs = LHS;
5951 6172
5952 bool enter = false; 6173 const u32 rm_val = state->Reg[rm_idx];
6174 const u32 rn_val = state->Reg[rn_idx];
5953 6175
5954 if (state->currentexval == (u32)ARMul_ReadByte(state, state->currentexaddr))enter = true; 6176 if (op2 == 0x00 || op2 == 0x01 || op2 == 0x02 || op2 == 0x03)
6177 {
6178 u32 lo_val = 0;
6179 u32 hi_val = 0;
5955 6180
5956 ARMul_StoreByte (state, lhs, RHS); 6181 // UHADD16
5957 BUSUSEDINCPCN; 6182 if (op2 == 0x00) {
5958 if (state->Aborted) { 6183 lo_val = (rn_val & 0xFFFF) + (rm_val & 0xFFFF);
5959 TAKEABORT; 6184 hi_val = ((rn_val >> 16) & 0xFFFF) + ((rm_val >> 16) & 0xFFFF);
5960 } 6185 }
6186 // UHASX
6187 else if (op2 == 0x01) {
6188 lo_val = (rn_val & 0xFFFF) - ((rm_val >> 16) & 0xFFFF);
6189 hi_val = ((rn_val >> 16) & 0xFFFF) + (rm_val & 0xFFFF);
6190 }
6191 // UHSAX
6192 else if (op2 == 0x02) {
6193 lo_val = (rn_val & 0xFFFF) + ((rm_val >> 16) & 0xFFFF);
6194 hi_val = ((rn_val >> 16) & 0xFFFF) - (rm_val & 0xFFFF);
6195 }
6196 // UHSUB16
6197 else if (op2 == 0x03) {
6198 lo_val = (rn_val & 0xFFFF) - (rm_val & 0xFFFF);
6199 hi_val = ((rn_val >> 16) & 0xFFFF) - ((rm_val >> 16) & 0xFFFF);
6200 }
5961 6201
6202 lo_val >>= 1;
6203 hi_val >>= 1;
5962 6204
5963 if (enter) { 6205 state->Reg[rd_idx] = (lo_val & 0xFFFF) | ((hi_val & 0xFFFF) << 16);
5964 state->Reg[DESTReg] = 0; 6206 return 1;
5965 } else { 6207 }
5966 state->Reg[DESTReg] = 1; 6208 else if (op2 == 0x04 || op2 == 0x07) {
6209 u32 sum1;
6210 u32 sum2;
6211 u32 sum3;
6212 u32 sum4;
6213
6214 // UHADD8
6215 if (op2 == 0x04) {
6216 sum1 = (rn_val & 0xFF) + (rm_val & 0xFF);
6217 sum2 = ((rn_val >> 8) & 0xFF) + ((rm_val >> 8) & 0xFF);
6218 sum3 = ((rn_val >> 16) & 0xFF) + ((rm_val >> 16) & 0xFF);
6219 sum4 = ((rn_val >> 24) & 0xFF) + ((rm_val >> 24) & 0xFF);
6220 }
6221 // UHSUB8
6222 else {
6223 sum1 = (rn_val & 0xFF) - (rm_val & 0xFF);
6224 sum2 = ((rn_val >> 8) & 0xFF) - ((rm_val >> 8) & 0xFF);
6225 sum3 = ((rn_val >> 16) & 0xFF) - ((rm_val >> 16) & 0xFF);
6226 sum4 = ((rn_val >> 24) & 0xFF) - ((rm_val >> 24) & 0xFF);
6227 }
6228
6229 sum1 >>= 1;
6230 sum2 >>= 1;
6231 sum3 >>= 1;
6232 sum4 >>= 1;
6233
6234 state->Reg[rd_idx] = (sum1 & 0xFF) | ((sum2 & 0xFF) << 8) | ((sum3 & 0xFF) << 16) | ((sum4 & 0xFF) << 24);
6235 return 1;
5967 } 6236 }
5968
5969 //printf("In %s, strexb not implemented\n", __FUNCTION__);
5970 UNDEF_LSRBPC;
5971 /* WRITESDEST (dest); */
5972 return 1;
5973 } 6237 }
5974 break; 6238 break;
6239 case 0x68:
6240 {
6241 u32 rd = (instr >> 12) & 0xF;
6242 u32 rn = (instr >> 16) & 0xF;
6243 u32 rm = (instr >> 0) & 0xF;
6244 u32 from = state->Reg[rn];
6245 u32 to = state->Reg[rm];
6246 u32 cpsr = ARMul_GetCPSR(state);
6247 if ((instr & 0xFF0) == 0xFB0) { // SEL
6248 u32 result;
6249 if (cpsr & (1 << 16))
6250 result = from & 0xff;
6251 else
6252 result = to & 0xff;
6253 if (cpsr & (1 << 17))
6254 result |= from & 0x0000ff00;
6255 else
6256 result |= to & 0x0000ff00;
6257 if (cpsr & (1 << 18))
6258 result |= from & 0x00ff0000;
6259 else
6260 result |= to & 0x00ff0000;
6261 if (cpsr & (1 << 19))
6262 result |= from & 0xff000000;
6263 else
6264 result |= to & 0xff000000;
6265 state->Reg[rd] = result;
6266 return 1;
6267 }
5975 } 6268 }
6269 printf("Unhandled v6 insn: pkh/sxtab/selsxtb\n");
6270 break;
6271
6272 case 0x6a: // SSAT, SSAT16, SXTB, and SXTAB
6273 {
6274 const u8 op2 = BITS(5, 7);
6275
6276 // SSAT16
6277 if (op2 == 0x01) {
6278 const u8 rd_idx = BITS(12, 15);
6279 const u8 rn_idx = BITS(0, 3);
6280 const u8 num_bits = BITS(16, 19) + 1;
6281 const s16 min = -(0x8000 >> (16 - num_bits));
6282 const s16 max = (0x7FFF >> (16 - num_bits));
6283 s16 rn_lo = (state->Reg[rn_idx]);
6284 s16 rn_hi = (state->Reg[rn_idx] >> 16);
6285
6286 if (rn_lo > max) {
6287 rn_lo = max;
6288 SETQ;
6289 } else if (rn_lo < min) {
6290 rn_lo = min;
6291 SETQ;
6292 }
6293
6294 if (rn_hi > max) {
6295 rn_hi = max;
6296 SETQ;
6297 } else if (rn_hi < min) {
6298 rn_hi = min;
6299 SETQ;
6300 }
6301
6302 state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi & 0xFFFF) << 16);
6303 return 1;
6304 }
6305 else if (op2 == 0x03) {
6306 const u8 rotation = BITS(10, 11) * 8;
6307 u32 rm = ((state->Reg[BITS(0, 3)] >> rotation) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - rotation)) & 0xFF) & 0xFF);
6308 if (rm & 0x80)
6309 rm |= 0xffffff00;
6310
6311 // SXTB, otherwise SXTAB
6312 if (BITS(16, 19) == 0xf)
6313 state->Reg[BITS(12, 15)] = rm;
6314 else
6315 state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + rm;
6316
6317 return 1;
6318 }
6319 else {
6320 printf("Unimplemented op: SSAT");
6321 }
6322 }
6323 break;
6324
6325 case 0x6b: // REV, REV16, SXTH, and SXTAH
6326 {
6327 const u8 op2 = BITS(5, 7);
6328
6329 // REV
6330 if (op2 == 0x01) {
6331 DEST = ((RHS & 0xFF) << 24) | ((RHS & 0xFF00)) << 8 | ((RHS & 0xFF0000) >> 8) | ((RHS & 0xFF000000) >> 24);
6332 return 1;
6333 }
6334 // REV16
6335 else if (op2 == 0x05) {
6336 DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00)) >> 8 | ((RHS & 0xFF0000) << 8) | ((RHS & 0xFF000000) >> 8);
6337 return 1;
6338 }
6339 else if (op2 == 0x03) {
6340 const u8 rotate = BITS(10, 11) * 8;
6341
6342 u32 rm = ((state->Reg[BITS(0, 3)] >> rotate) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - rotate)) & 0xFFFF) & 0xFFFF);
6343 if (rm & 0x8000)
6344 rm |= 0xffff0000;
6345
6346 // SXTH, otherwise SXTAH
6347 if (BITS(16, 19) == 15)
6348 state->Reg[BITS(12, 15)] = rm;
6349 else
6350 state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + rm;
6351
6352 return 1;
6353 }
6354 }
6355 break;
6356
6357 case 0x6c: // UXTB16 and UXTAB16
6358 {
6359 const u8 rm_idx = BITS(0, 3);
6360 const u8 rn_idx = BITS(16, 19);
6361 const u8 rd_idx = BITS(12, 15);
6362 const u32 rm_val = state->Reg[rm_idx];
6363 const u32 rn_val = state->Reg[rn_idx];
6364 const u32 rotation = BITS(10, 11) * 8;
6365 const u32 rotated_rm = ((rm_val << (32 - rotation)) | (rm_val >> rotation));
6366
6367 // UXTB16
6368 if ((instr & 0xf03f0) == 0xf0070) {
6369 state->Reg[rd_idx] = rotated_rm & 0x00FF00FF;
6370 }
6371 else { // UXTAB16
6372 const u8 lo_rotated = (rotated_rm & 0xFF);
6373 const u16 lo_result = (rn_val & 0xFFFF) + (u16)lo_rotated;
6374
6375 const u8 hi_rotated = (rotated_rm >> 16) & 0xFF;
6376 const u16 hi_result = (rn_val >> 16) + (u16)hi_rotated;
6377
6378 state->Reg[rd_idx] = ((hi_result << 16) | (lo_result & 0xFFFF));
6379 }
6380
6381 return 1;
6382 }
6383 break;
6384 case 0x6e: // USAT, USAT16, UXTB, and UXTAB
6385 {
6386 const u8 op2 = BITS(5, 7);
6387
6388 // USAT16
6389 if (op2 == 0x01) {
6390 const u8 rd_idx = BITS(12, 15);
6391 const u8 rn_idx = BITS(0, 3);
6392 const u8 num_bits = BITS(16, 19);
6393 const s16 max = 0xFFFF >> (16 - num_bits);
6394 s16 rn_lo = (state->Reg[rn_idx]);
6395 s16 rn_hi = (state->Reg[rn_idx] >> 16);
6396
6397 if (max < rn_lo) {
6398 rn_lo = max;
6399 SETQ;
6400 } else if (rn_lo < 0) {
6401 rn_lo = 0;
6402 SETQ;
6403 }
6404
6405 if (max < rn_hi) {
6406 rn_hi = max;
6407 SETQ;
6408 } else if (rn_hi < 0) {
6409 rn_hi = 0;
6410 SETQ;
6411 }
6412
6413 state->Reg[rd_idx] = (rn_lo & 0xFFFF) | ((rn_hi << 16) & 0xFFFF);
6414 return 1;
6415 }
6416 else if (op2 == 0x03) {
6417 const u8 rotate = BITS(10, 11) * 8;
6418 const u32 rm = ((state->Reg[BITS(0, 3)] >> rotate) & 0xFF) | (((state->Reg[BITS(0, 3)] << (32 - rotate)) & 0xFF) & 0xFF);
6419
6420 if (BITS(16, 19) == 0xf)
6421 /* UXTB */
6422 state->Reg[BITS(12, 15)] = rm;
6423 else
6424 /* UXTAB */
6425 state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + rm;
6426
6427 return 1;
6428 }
6429 else {
6430 printf("Unimplemented op: USAT");
6431 }
6432 }
6433 break;
6434
6435 case 0x6f: // UXTH, UXTAH, and REVSH.
6436 {
6437 const u8 op2 = BITS(5, 7);
6438
6439 // REVSH
6440 if (op2 == 0x05) {
6441 DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00) >> 8);
6442 if (DEST & 0x8000)
6443 DEST |= 0xffff0000;
6444 return 1;
6445 }
6446 // UXTH and UXTAH
6447 else if (op2 == 0x03) {
6448 const u8 rotate = BITS(10, 11) * 8;
6449 const ARMword rm = ((state->Reg[BITS(0, 3)] >> rotate) & 0xFFFF) | (((state->Reg[BITS(0, 3)] << (32 - rotate)) & 0xFFFF) & 0xFFFF);
6450
6451 // UXTH
6452 if (BITS(16, 19) == 0xf) {
6453 state->Reg[BITS(12, 15)] = rm;
6454 }
6455 // UXTAH
6456 else {
6457 state->Reg[BITS(12, 15)] = state->Reg[BITS(16, 19)] + rm;
6458 }
6459
6460 return 1;
6461 }
6462 }
6463 case 0x70:
6464 // ichfly
6465 // SMUAD, SMUSD, SMLAD, and SMLSD
6466 if ((instr & 0xf0d0) == 0xf010 || (instr & 0xf0d0) == 0xf050 ||
6467 (instr & 0xd0) == 0x10 || (instr & 0xd0) == 0x50)
6468 {
6469 const u8 rd_idx = BITS(16, 19);
6470 const u8 rn_idx = BITS(0, 3);
6471 const u8 rm_idx = BITS(8, 11);
6472 const u8 ra_idx = BITS(12, 15);
6473 const bool do_swap = (BIT(5) == 1);
5976 6474
5977 case 0x1d: { /* BICS reg */ 6475 u32 rm_val = state->Reg[rm_idx];
5978 if ((BITS (4, 7)) == 0x9) { 6476 const u32 rn_val = state->Reg[rn_idx];
5979 /* ldrexb */
5980 temp = LHS;
5981 LoadByte (state, instr, temp, LUNSIGNED);
5982 6477
5983 state->currentexaddr = temp; 6478 if (do_swap)
5984 state->currentexval = (u32)ARMul_ReadByte(state, temp); 6479 rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16));
5985 6480
5986 //state->Reg[BITS(12, 15)] = ARMul_LoadByte(state, state->Reg[BITS(16, 19)]); 6481 const s16 rm_lo = (rm_val & 0xFFFF);
5987 //printf("ldrexb\n"); 6482 const s16 rm_hi = ((rm_val >> 16) & 0xFFFF);
5988 //printf("instr is %x rm is %d\n", instr, BITS(16, 19)); 6483 const s16 rn_lo = (rn_val & 0xFFFF);
5989 //exit(-1); 6484 const s16 rn_hi = ((rn_val >> 16) & 0xFFFF);
5990 6485
5991 //printf("In %s, ldrexb not implemented\n", __FUNCTION__); 6486 const u32 product1 = (rn_lo * rm_lo);
5992 return 1; 6487 const u32 product2 = (rn_hi * rm_hi);
5993 }
5994 break;
5995 }
5996 /* add end */
5997 6488
5998 case 0x6a: { 6489 // SMUAD and SMLAD
5999 ARMword Rm; 6490 if (BIT(6) == 0) {
6000 int ror = -1; 6491 state->Reg[rd_idx] = product1 + product2;
6001 6492
6002 switch (BITS (4, 11)) { 6493 if (BITS(12, 15) != 15) {
6003 case 0x07: 6494 state->Reg[rd_idx] += state->Reg[ra_idx];
6004 ror = 0; 6495 ARMul_AddOverflowQ(state, product1 + product2, state->Reg[ra_idx]);
6005 break; 6496 }
6006 case 0x47:
6007 ror = 8;
6008 break;
6009 case 0x87:
6010 ror = 16;
6011 break;
6012 case 0xc7:
6013 ror = 24;
6014 break;
6015 6497
6016 case 0x01: 6498 ARMul_AddOverflowQ(state, product1, product2);
6017 case 0xf3: 6499 }
6018 //ichfly 6500 // SMUSD and SMLSD
6019 //SSAT16 6501 else {
6020 { 6502 state->Reg[rd_idx] = product1 - product2;
6021 u8 tar = BITS(12,15); 6503
6022 u8 src = BITS(0, 3); 6504 if (BITS(12, 15) != 15)
6023 u8 val = BITS(16, 19) + 1; 6505 state->Reg[rd_idx] += state->Reg[ra_idx];
6024 s16 a1 = (state->Reg[src]); 6506 }
6025 s16 a2 = (state->Reg[src] >> 0x10);
6026 s16 min = (s16)(0x8000) >> (16 - val);
6027 s16 max = 0x7FFF >> (16 - val);
6028 if (min > a1) a1 = min;
6029 if (max < a1) a1 = max;
6030 if (min > a2) a2 = min;
6031 if (max < a2) a2 = max;
6032 u32 temp2 = ((u32)(a2)) << 0x10;
6033 state->Reg[tar] = (a1&0xFFFF) | (temp2);
6034 }
6035 6507
6036 return 1; 6508 return 1;
6037 default:
6038 break;
6039 } 6509 }
6040 6510 break;
6041 if (ror == -1) { 6511 case 0x74: // SMLALD and SMLSLD
6042 if (BITS (4, 6) == 0x7) { 6512 {
6043 printf ("Unhandled v6 insn: ssat\n"); 6513 const u8 rm_idx = BITS(8, 11);
6044 return 0; 6514 const u8 rn_idx = BITS(0, 3);
6515 const u8 rdlo_idx = BITS(12, 15);
6516 const u8 rdhi_idx = BITS(16, 19);
6517 const bool do_swap = (BIT(5) == 1);
6518
6519 const u32 rdlo_val = state->Reg[rdlo_idx];
6520 const u32 rdhi_val = state->Reg[rdhi_idx];
6521 const u32 rn_val = state->Reg[rn_idx];
6522 u32 rm_val = state->Reg[rm_idx];
6523
6524 if (do_swap)
6525 rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16));
6526
6527 const s32 product1 = (s16)(rn_val & 0xFFFF) * (s16)(rm_val & 0xFFFF);
6528 const s32 product2 = (s16)((rn_val >> 16) & 0xFFFF) * (s16)((rm_val >> 16) & 0xFFFF);
6529 s64 result;
6530
6531 // SMLALD
6532 if (BIT(6) == 0) {
6533 result = (product1 + product2) + (s64)(rdlo_val | ((s64)rdhi_val << 32));
6534 }
6535 // SMLSLD
6536 else {
6537 result = (product1 - product2) + (s64)(rdlo_val | ((s64)rdhi_val << 32));
6045 } 6538 }
6046 break;
6047 }
6048
6049 Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFF);
6050 if (Rm & 0x80)
6051 Rm |= 0xffffff00;
6052
6053 if (BITS (16, 19) == 0xf)
6054 /* SXTB */
6055 state->Reg[BITS (12, 15)] = Rm;
6056 else
6057 /* SXTAB */
6058 state->Reg[BITS (12, 15)] += Rm;
6059 }
6060 return 1;
6061
6062 case 0x6b: {
6063 ARMword Rm;
6064 int ror = -1;
6065
6066 switch (BITS (4, 11)) {
6067 case 0x07:
6068 ror = 0;
6069 break;
6070 case 0x47:
6071 ror = 8;
6072 break;
6073 case 0x87:
6074 ror = 16;
6075 break;
6076 case 0xc7:
6077 ror = 24;
6078 break;
6079 6539
6080 case 0xf3: 6540 state->Reg[rdlo_idx] = (result & 0xFFFFFFFF);
6081 DEST = ((RHS & 0xFF) << 24) | ((RHS & 0xFF00)) << 8 | ((RHS & 0xFF0000) >> 8) | ((RHS & 0xFF000000) >> 24); 6541 state->Reg[rdhi_idx] = ((result >> 32) & 0xFFFFFFFF);
6082 return 1; 6542 return 1;
6083 case 0xfb:
6084 DEST = ((RHS & 0xFF) << 8) | ((RHS & 0xFF00)) >> 8 | ((RHS & 0xFF0000) << 8) | ((RHS & 0xFF000000) >> 8);
6085 return 1;
6086 default:
6087 break;
6088 } 6543 }
6544 break;
6545 case 0x75: // SMMLA, SMMUL, and SMMLS
6546 {
6547 const u8 rm_idx = BITS(8, 11);
6548 const u8 rn_idx = BITS(0, 3);
6549 const u8 ra_idx = BITS(12, 15);
6550 const u8 rd_idx = BITS(16, 19);
6551 const bool do_round = (BIT(5) == 1);
6089 6552
6090 if (ror == -1) 6553 const u32 rm_val = state->Reg[rm_idx];
6091 break; 6554 const u32 rn_val = state->Reg[rn_idx];
6092 6555
6093 Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFFFF); 6556 // Assume SMMUL by default.
6094 if (Rm & 0x8000) 6557 s64 result = (s64)(s32)rn_val * (s64)(s32)rm_val;
6095 Rm |= 0xffff0000;
6096 6558
6097 if (BITS (16, 19) == 0xf) 6559 if (ra_idx != 15) {
6098 /* SXTH */ 6560 const u32 ra_val = state->Reg[ra_idx];
6099 state->Reg[BITS (12, 15)] = Rm;
6100 else
6101 /* SXTAH */
6102 state->Reg[BITS (12, 15)] = state->Reg[BITS (16, 19)] + Rm;
6103 }
6104 return 1;
6105 6561
6106 case 0x6e: { 6562 // SMMLA, otherwise SMMLS
6107 ARMword Rm; 6563 if (BIT(6) == 0)
6108 int ror = -1; 6564 result += ((s64)ra_val << 32);
6565 else
6566 result = ((s64)ra_val << 32) - result;
6567 }
6109 6568
6110 switch (BITS (4, 11)) { 6569 if (do_round)
6111 case 0x07: 6570 result += 0x80000000;
6112 ror = 0;
6113 break;
6114 case 0x47:
6115 ror = 8;
6116 break;
6117 case 0x87:
6118 ror = 16;
6119 break;
6120 case 0xc7:
6121 ror = 24;
6122 break;
6123 6571
6124 case 0x01: 6572 state->Reg[rd_idx] = ((result >> 32) & 0xFFFFFFFF);
6125 case 0xf3:
6126 //ichfly
6127 //USAT16
6128 {
6129 u8 tar = BITS(12, 15);
6130 u8 src = BITS(0, 3);
6131 u8 val = BITS(16, 19);
6132 s16 a1 = (state->Reg[src]);
6133 s16 a2 = (state->Reg[src] >> 0x10);
6134 s16 max = 0xFFFF >> (16 - val);
6135 if (max < a1) a1 = max;
6136 if (max < a2) a2 = max;
6137 u32 temp2 = ((u32)(a2)) << 0x10;
6138 state->Reg[tar] = (a1 & 0xFFFF) | (temp2);
6139 }
6140 return 1; 6573 return 1;
6141 default:
6142 break;
6143 }
6144
6145 if (ror == -1) {
6146 if (BITS (4, 6) == 0x7) {
6147 printf ("Unhandled v6 insn: usat\n");
6148 return 0;
6149 }
6150 break;
6151 } 6574 }
6575 break;
6576 case 0x78:
6577 if (BITS(20, 24) == 0x18)
6578 {
6579 const u8 rm_idx = BITS(8, 11);
6580 const u8 rn_idx = BITS(0, 3);
6581 const u8 rd_idx = BITS(16, 19);
6152 6582
6153 Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFF); 6583 const u32 rm_val = state->Reg[rm_idx];
6154 6584 const u32 rn_val = state->Reg[rn_idx];
6155 if (BITS (16, 19) == 0xf)
6156 /* UXTB */
6157 state->Reg[BITS (12, 15)] = Rm;
6158 else
6159 /* UXTAB */
6160 state->Reg[BITS (12, 15)] = state->Reg[BITS (16, 19)] + Rm;
6161 }
6162 return 1;
6163 6585
6164 case 0x6f: { 6586 const u8 diff1 = ARMul_UnsignedAbsoluteDifference(rn_val & 0xFF, rm_val & 0xFF);
6165 ARMword Rm; 6587 const u8 diff2 = ARMul_UnsignedAbsoluteDifference((rn_val >> 8) & 0xFF, (rm_val >> 8) & 0xFF);
6166 int ror = -1; 6588 const u8 diff3 = ARMul_UnsignedAbsoluteDifference((rn_val >> 16) & 0xFF, (rm_val >> 16) & 0xFF);
6589 const u8 diff4 = ARMul_UnsignedAbsoluteDifference((rn_val >> 24) & 0xFF, (rm_val >> 24) & 0xFF);
6167 6590
6168 switch (BITS (4, 11)) { 6591 u32 finalDif = (diff1 + diff2 + diff3 + diff4);
6169 case 0x07:
6170 ror = 0;
6171 break;
6172 case 0x47:
6173 ror = 8;
6174 break;
6175 case 0x87:
6176 ror = 16;
6177 break;
6178 case 0xc7:
6179 ror = 24;
6180 break;
6181 6592
6182 case 0xfb: 6593 // Op is USADA8 if true.
6183 printf ("Unhandled v6 insn: revsh\n"); 6594 const u8 ra_idx = BITS(12, 15);
6184 return 0; 6595 if (ra_idx != 15)
6185 default: 6596 finalDif += state->Reg[ra_idx];
6186 break;
6187 }
6188 6597
6189 if (ror == -1) 6598 state->Reg[rd_idx] = finalDif;
6190 break; 6599 return 1;
6191
6192 Rm = ((state->Reg[BITS (0, 3)] >> ror) & 0xFFFF);
6193
6194 /* UXT */
6195 /* state->Reg[BITS (12, 15)] = Rm; */
6196 /* dyf add */
6197 if (BITS (16, 19) == 0xf) {
6198 state->Reg[BITS (12, 15)] = (Rm >> (8 * BITS(10, 11))) & 0x0000FFFF;
6199 } else {
6200 /* UXTAH */
6201 /* state->Reg[BITS (12, 15)] = state->Reg [BITS (16, 19)] + Rm; */
6202// printf("rd is %x rn is %x rm is %x rotate is %x\n", state->Reg[BITS (12, 15)], state->Reg[BITS (16, 19)]
6203// , Rm, BITS(10, 11));
6204// printf("icounter is %lld\n", state->NumInstrs);
6205 state->Reg[BITS (12, 15)] = (state->Reg[BITS (16, 19)] >> (8 * (BITS(10, 11)))) + Rm;
6206// printf("rd is %x\n", state->Reg[BITS (12, 15)]);
6207// exit(-1);
6208 } 6600 }
6209 } 6601 break;
6210 return 1; 6602 case 0x7a:
6211 6603 printf ("Unhandled v6 insn: usbfx\n");
6212#if 0 6604 break;
6605 case 0x7c:
6606 printf ("Unhandled v6 insn: bfc/bfi\n");
6607 break;
6213 case 0x84: 6608 case 0x84:
6214 printf ("Unhandled v6 insn: srs\n"); 6609 printf ("Unhandled v6 insn: srs\n");
6215 break; 6610 break;
6216#endif
6217 default: 6611 default:
6218 break; 6612 break;
6219 } 6613 }
6220 printf("Unhandled v6 insn: UNKNOWN: %08x %08X\n", instr, BITS(20, 27)); 6614 printf("Unhandled v6 insn: UNKNOWN: %08x %08X\n", instr, BITS(20, 27));
6221 return 0; 6615 return 0;
6222 } 6616 } \ No newline at end of file
diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp
index 2568b93ef..426b67831 100644
--- a/src/core/arm/interpreter/armsupp.cpp
+++ b/src/core/arm/interpreter/armsupp.cpp
@@ -227,8 +227,9 @@ ARMul_CPSRAltered (ARMul_State * state)
227 //state->Cpsr &= ~CBIT; 227 //state->Cpsr &= ~CBIT;
228 ASSIGNV ((state->Cpsr & VBIT) != 0); 228 ASSIGNV ((state->Cpsr & VBIT) != 0);
229 //state->Cpsr &= ~VBIT; 229 //state->Cpsr &= ~VBIT;
230 ASSIGNS ((state->Cpsr & SBIT) != 0); 230 ASSIGNQ ((state->Cpsr & QBIT) != 0);
231 //state->Cpsr &= ~SBIT; 231 //state->Cpsr &= ~QBIT;
232 state->GEFlag = (state->Cpsr & 0x000F0000);
232#ifdef MODET 233#ifdef MODET
233 ASSIGNT ((state->Cpsr & TBIT) != 0); 234 ASSIGNT ((state->Cpsr & TBIT) != 0);
234 //state->Cpsr &= ~TBIT; 235 //state->Cpsr &= ~TBIT;
@@ -391,6 +392,15 @@ ARMul_NthReg (ARMword instr, unsigned number)
391 return (bit - 1); 392 return (bit - 1);
392} 393}
393 394
395/* Unsigned sum of absolute difference */
396u8 ARMul_UnsignedAbsoluteDifference(u8 left, u8 right)
397{
398 if (left > right)
399 return left - right;
400
401 return right - left;
402}
403
394/* Assigns the N and Z flags depending on the value of result. */ 404/* Assigns the N and Z flags depending on the value of result. */
395 405
396void 406void
@@ -443,6 +453,14 @@ ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
443 ASSIGNV (AddOverflow (a, b, result)); 453 ASSIGNV (AddOverflow (a, b, result));
444} 454}
445 455
456/* Assigns the Q flag if the given result is considered an overflow from the addition of a and b */
457void ARMul_AddOverflowQ(ARMul_State* state, ARMword a, ARMword b)
458{
459 u32 result = a + b;
460 if (((result ^ a) & (u32)0x80000000) && ((a ^ b) & (u32)0x80000000) == 0)
461 SETQ;
462}
463
446/* Assigns the C flag after an subtraction of a and b to give result. */ 464/* Assigns the C flag after an subtraction of a and b to give result. */
447 465
448void 466void
@@ -460,6 +478,142 @@ ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result)
460 ASSIGNV (SubOverflow (a, b, result)); 478 ASSIGNV (SubOverflow (a, b, result));
461} 479}
462 480
481/* 8-bit signed saturated addition */
482u8 ARMul_SignedSaturatedAdd8(u8 left, u8 right)
483{
484 u8 result = left + right;
485
486 if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) == 0) {
487 if (left & 0x80)
488 result = 0x80;
489 else
490 result = 0x7F;
491 }
492
493 return result;
494}
495
496/* 8-bit signed saturated subtraction */
497u8 ARMul_SignedSaturatedSub8(u8 left, u8 right)
498{
499 u8 result = left - right;
500
501 if (((result ^ left) & 0x80) && ((left ^ right) & 0x80) != 0) {
502 if (left & 0x80)
503 result = 0x80;
504 else
505 result = 0x7F;
506 }
507
508 return result;
509}
510
511/* 16-bit signed saturated addition */
512u16 ARMul_SignedSaturatedAdd16(u16 left, u16 right)
513{
514 u16 result = left + right;
515
516 if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) == 0) {
517 if (left & 0x8000)
518 result = 0x8000;
519 else
520 result = 0x7FFF;
521 }
522
523 return result;
524}
525
526/* 16-bit signed saturated subtraction */
527u16 ARMul_SignedSaturatedSub16(u16 left, u16 right)
528{
529 u16 result = left - right;
530
531 if (((result ^ left) & 0x8000) && ((left ^ right) & 0x8000) != 0) {
532 if (left & 0x8000)
533 result = 0x8000;
534 else
535 result = 0x7FFF;
536 }
537
538 return result;
539}
540
541/* 8-bit unsigned saturated addition */
542u8 ARMul_UnsignedSaturatedAdd8(u8 left, u8 right)
543{
544 u8 result = left + right;
545
546 if (result < left)
547 result = 0xFF;
548
549 return result;
550}
551
552/* 16-bit unsigned saturated addition */
553u16 ARMul_UnsignedSaturatedAdd16(u16 left, u16 right)
554{
555 u16 result = left + right;
556
557 if (result < left)
558 result = 0xFFFF;
559
560 return result;
561}
562
563/* 8-bit unsigned saturated subtraction */
564u8 ARMul_UnsignedSaturatedSub8(u8 left, u8 right)
565{
566 if (left <= right)
567 return 0;
568
569 return left - right;
570}
571
572/* 16-bit unsigned saturated subtraction */
573u16 ARMul_UnsignedSaturatedSub16(u16 left, u16 right)
574{
575 if (left <= right)
576 return 0;
577
578 return left - right;
579}
580
581// Signed saturation.
582u32 ARMul_SignedSatQ(s32 value, u8 shift, bool* saturation_occurred)
583{
584 const u32 max = (1 << shift) - 1;
585 const s32 top = (value >> shift);
586
587 if (top > 0) {
588 *saturation_occurred = true;
589 return max;
590 }
591 else if (top < -1) {
592 *saturation_occurred = true;
593 return ~max;
594 }
595
596 *saturation_occurred = false;
597 return (u32)value;
598}
599
600// Unsigned saturation
601u32 ARMul_UnsignedSatQ(s32 value, u8 shift, bool* saturation_occurred)
602{
603 const u32 max = (1 << shift) - 1;
604
605 if (value < 0) {
606 *saturation_occurred = true;
607 return 0;
608 } else if ((u32)value > max) {
609 *saturation_occurred = true;
610 return max;
611 }
612
613 *saturation_occurred = false;
614 return (u32)value;
615}
616
463/* This function does the work of generating the addresses used in an 617/* This function does the work of generating the addresses used in an
464 LDC instruction. The code here is always post-indexed, it's up to the 618 LDC instruction. The code here is always post-indexed, it's up to the
465 caller to get the input address correct and to handle base register 619 caller to get the input address correct and to handle base register
@@ -665,7 +819,7 @@ ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source)
665 //if (!CP_ACCESS_ALLOWED (state, CPNum)) { 819 //if (!CP_ACCESS_ALLOWED (state, CPNum)) {
666 if (!state->MCR[CPNum]) { 820 if (!state->MCR[CPNum]) {
667 //chy 2004-07-19 should fix in the future ????!!!! 821 //chy 2004-07-19 should fix in the future ????!!!!
668 DEBUG("SKYEYE ARMul_MCR, ACCESS_not ALLOWed, UndefinedInstr CPnum is %x, source %x\n",CPNum, source); 822 LOG_ERROR(Core_ARM11, "SKYEYE ARMul_MCR, ACCESS_not ALLOWed, UndefinedInstr CPnum is %x, source %x",CPNum, source);
669 ARMul_UndefInstr (state, instr); 823 ARMul_UndefInstr (state, instr);
670 return; 824 return;
671 } 825 }
@@ -690,7 +844,7 @@ ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source)
690 } 844 }
691 845
692 if (cpab == ARMul_CANT) { 846 if (cpab == ARMul_CANT) {
693 DEBUG("SKYEYE ARMul_MCR, CANT, UndefinedInstr %x CPnum is %x, source %x\n", instr, CPNum, source); //ichfly todo 847 LOG_ERROR(Core_ARM11, "SKYEYE ARMul_MCR, CANT, UndefinedInstr %x CPnum is %x, source %x", instr, CPNum, source); //ichfly todo
694 //ARMul_Abort (state, ARMul_UndefinedInstrV); 848 //ARMul_Abort (state, ARMul_UndefinedInstrV);
695 } else { 849 } else {
696 BUSUSEDINCPCN; 850 BUSUSEDINCPCN;
@@ -762,7 +916,7 @@ ARMword ARMul_MRC (ARMul_State * state, ARMword instr)
762 //if (!CP_ACCESS_ALLOWED (state, CPNum)) { 916 //if (!CP_ACCESS_ALLOWED (state, CPNum)) {
763 if (!state->MRC[CPNum]) { 917 if (!state->MRC[CPNum]) {
764 //chy 2004-07-19 should fix in the future????!!!! 918 //chy 2004-07-19 should fix in the future????!!!!
765 DEBUG("SKYEYE ARMul_MRC,NOT ALLOWed UndefInstr CPnum is %x, instr %x\n", CPNum, instr); 919 LOG_ERROR(Core_ARM11, "SKYEYE ARMul_MRC,NOT ALLOWed UndefInstr CPnum is %x, instr %x", CPNum, instr);
766 ARMul_UndefInstr (state, instr); 920 ARMul_UndefInstr (state, instr);
767 return -1; 921 return -1;
768 } 922 }
@@ -865,7 +1019,7 @@ void
865ARMul_UndefInstr (ARMul_State * state, ARMword instr) 1019ARMul_UndefInstr (ARMul_State * state, ARMword instr)
866{ 1020{
867 std::string disasm = ARM_Disasm::Disassemble(state->pc, instr); 1021 std::string disasm = ARM_Disasm::Disassemble(state->pc, instr);
868 ERROR_LOG(ARM11, "Undefined instruction!! Disasm: %s Opcode: 0x%x", disasm.c_str(), instr); 1022 LOG_ERROR(Core_ARM11, "Undefined instruction!! Disasm: %s Opcode: 0x%x", disasm.c_str(), instr);
869 ARMul_Abort (state, ARMul_UndefinedInstrV); 1023 ARMul_Abort (state, ARMul_UndefinedInstrV);
870} 1024}
871 1025
diff --git a/src/core/arm/interpreter/thumbemu.cpp b/src/core/arm/interpreter/thumbemu.cpp
index f7f11f714..9cf80672d 100644
--- a/src/core/arm/interpreter/thumbemu.cpp
+++ b/src/core/arm/interpreter/thumbemu.cpp
@@ -467,7 +467,7 @@ ARMul_ThumbDecode (
467 (state->Reg[14] + ((tinstr & 0x07FF) << 1)) & 0xFFFFFFFC; 467 (state->Reg[14] + ((tinstr & 0x07FF) << 1)) & 0xFFFFFFFC;
468 state->Reg[14] = (tmp | 1); 468 state->Reg[14] = (tmp | 1);
469 CLEART; 469 CLEART;
470 DEBUG_LOG(ARM11, "In %s, After BLX(1),LR=0x%x,PC=0x%x, offset=0x%x\n", __FUNCTION__, state->Reg[14], state->Reg[15], (tinstr &0x7FF) << 1); 470 LOG_DEBUG(Core_ARM11, "After BLX(1),LR=0x%x,PC=0x%x, offset=0x%x", state->Reg[14], state->Reg[15], (tinstr &0x7FF) << 1);
471 valid = t_branch; 471 valid = t_branch;
472 FLUSHPIPE; 472 FLUSHPIPE;
473 } 473 }
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h
index 8343aaa01..8611d7392 100644
--- a/src/core/arm/skyeye_common/armdefs.h
+++ b/src/core/arm/skyeye_common/armdefs.h
@@ -18,38 +18,26 @@
18#ifndef _ARMDEFS_H_ 18#ifndef _ARMDEFS_H_
19#define _ARMDEFS_H_ 19#define _ARMDEFS_H_
20 20
21#include <stdio.h> 21#include <cerrno>
22#include <stdlib.h> 22#include <csignal>
23#include <errno.h> 23#include <cstdio>
24 24#include <cstdlib>
25#include "common/platform.h" 25#include <cstring>
26 26#include <fcntl.h>
27//teawater add for arm2x86 2005.02.14------------------------------------------- 27#include <sys/stat.h>
28// koodailar remove it for mingw 2005.12.18---------------- 28#include <sys/types.h>
29//anthonylee modify it for portable 2007.01.30
30//#include "portable/mman.h"
31 29
32#include "arm_regformat.h" 30#include "arm_regformat.h"
31#include "common/common_types.h"
33#include "common/platform.h" 32#include "common/platform.h"
33#include "core/arm/skyeye_common/armmmu.h"
34#include "core/arm/skyeye_common/skyeye_defs.h" 34#include "core/arm/skyeye_common/skyeye_defs.h"
35 35
36//AJ2D--------------------------------------------------------------------------
37
38//teawater add for arm2x86 2005.07.03-------------------------------------------
39
40#include <sys/types.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#if EMU_PLATFORM == PLATFORM_LINUX 36#if EMU_PLATFORM == PLATFORM_LINUX
37#include <sys/time.h>
45#include <unistd.h> 38#include <unistd.h>
46#endif 39#endif
47#include <errno.h>
48#include <sys/stat.h>
49#include <fcntl.h>
50 40
51//#include <memory_space.h>
52//AJ2D--------------------------------------------------------------------------
53#if 0 41#if 0
54#if 0 42#if 0
55#define DIFF_STATE 1 43#define DIFF_STATE 1
@@ -70,25 +58,8 @@
70#define LOWHIGH 1 58#define LOWHIGH 1
71#define HIGHLOW 2 59#define HIGHLOW 2
72 60
73//teawater add DBCT_TEST_SPEED 2005.10.04---------------------------------------
74#include <signal.h>
75
76#include "common/platform.h"
77
78#if EMU_PLATFORM == PLATFORM_LINUX
79#include <sys/time.h>
80#endif
81
82//#define DBCT_TEST_SPEED 61//#define DBCT_TEST_SPEED
83#define DBCT_TEST_SPEED_SEC 10 62#define DBCT_TEST_SPEED_SEC 10
84//AJ2D--------------------------------------------------------------------------
85
86//teawater add compile switch for DBCT GDB RSP function 2005.10.21--------------
87//#define DBCT_GDBRSP
88//AJ2D--------------------------------------------------------------------------
89
90//#include <skyeye_defs.h>
91//#include <skyeye_types.h>
92 63
93#define ARM_BYTE_TYPE 0 64#define ARM_BYTE_TYPE 0
94#define ARM_HALFWORD_TYPE 1 65#define ARM_HALFWORD_TYPE 1
@@ -103,71 +74,34 @@
103typedef char *VoidStar; 74typedef char *VoidStar;
104#endif 75#endif
105 76
106typedef unsigned long long ARMdword; /* must be 64 bits wide */ 77typedef u64 ARMdword; // must be 64 bits wide
107typedef unsigned int ARMword; /* must be 32 bits wide */ 78typedef u32 ARMword; // must be 32 bits wide
108typedef unsigned char ARMbyte; /* must be 8 bits wide */ 79typedef u16 ARMhword; // must be 16 bits wide
109typedef unsigned short ARMhword; /* must be 16 bits wide */ 80typedef u8 ARMbyte; // must be 8 bits wide
110typedef struct ARMul_State ARMul_State; 81typedef struct ARMul_State ARMul_State;
111typedef struct ARMul_io ARMul_io; 82typedef struct ARMul_io ARMul_io;
112typedef struct ARMul_Energy ARMul_Energy; 83typedef struct ARMul_Energy ARMul_Energy;
113 84
114//teawater add for arm2x86 2005.06.24-------------------------------------------
115#include <stdint.h>
116//AJ2D--------------------------------------------------------------------------
117/*
118//chy 2005-05-11
119#ifndef __CYGWIN__
120//teawater add for arm2x86 2005.02.14-------------------------------------------
121typedef unsigned char uint8_t;
122typedef unsigned short uint16_t;
123typedef unsigned int u32;
124#if defined (__x86_64__)
125typedef unsigned long uint64_t;
126#else
127typedef unsigned long long uint64_t;
128#endif
129////AJ2D--------------------------------------------------------------------------
130#endif
131*/
132 85
133#include "core/arm/skyeye_common/armmmu.h" 86typedef unsigned ARMul_CPInits(ARMul_State* state);
134//#include "lcd/skyeye_lcd.h" 87typedef unsigned ARMul_CPExits(ARMul_State* state);
135 88typedef unsigned ARMul_LDCs(ARMul_State* state, unsigned type, ARMword instr, ARMword value);
136 89typedef unsigned ARMul_STCs(ARMul_State* state, unsigned type, ARMword instr, ARMword* value);
137//#include "skyeye.h" 90typedef unsigned ARMul_MRCs(ARMul_State* state, unsigned type, ARMword instr, ARMword* value);
138//#include "skyeye_device.h" 91typedef unsigned ARMul_MCRs(ARMul_State* state, unsigned type, ARMword instr, ARMword value);
139//#include "net/skyeye_net.h" 92typedef unsigned ARMul_MRRCs(ARMul_State* state, unsigned type, ARMword instr, ARMword* value1, ARMword* value2);
140//#include "skyeye_config.h" 93typedef unsigned ARMul_MCRRs(ARMul_State* state, unsigned type, ARMword instr, ARMword value1, ARMword value2);
141 94typedef unsigned ARMul_CDPs(ARMul_State* state, unsigned type, ARMword instr);
142 95typedef unsigned ARMul_CPReads(ARMul_State* state, unsigned reg, ARMword* value);
143typedef unsigned ARMul_CPInits (ARMul_State * state); 96typedef unsigned ARMul_CPWrites(ARMul_State* state, unsigned reg, ARMword value);
144typedef unsigned ARMul_CPExits (ARMul_State * state);
145typedef unsigned ARMul_LDCs (ARMul_State * state, unsigned type,
146 ARMword instr, ARMword value);
147typedef unsigned ARMul_STCs (ARMul_State * state, unsigned type,
148 ARMword instr, ARMword * value);
149typedef unsigned ARMul_MRCs (ARMul_State * state, unsigned type,
150 ARMword instr, ARMword * value);
151typedef unsigned ARMul_MCRs (ARMul_State * state, unsigned type,
152 ARMword instr, ARMword value);
153typedef unsigned ARMul_MRRCs (ARMul_State * state, unsigned type,
154 ARMword instr, ARMword * value1, ARMword * value2);
155typedef unsigned ARMul_MCRRs (ARMul_State * state, unsigned type,
156 ARMword instr, ARMword value1, ARMword value2);
157typedef unsigned ARMul_CDPs (ARMul_State * state, unsigned type,
158 ARMword instr);
159typedef unsigned ARMul_CPReads (ARMul_State * state, unsigned reg,
160 ARMword * value);
161typedef unsigned ARMul_CPWrites (ARMul_State * state, unsigned reg,
162 ARMword value);
163 97
164 98
165//added by ksh,2004-3-5 99//added by ksh,2004-3-5
166struct ARMul_io 100struct ARMul_io
167{ 101{
168 ARMword *instr; //to display the current interrupt state 102 ARMword *instr; // to display the current interrupt state
169 ARMword *net_flag; //to judge if network is enabled 103 ARMword *net_flag; // to judge if network is enabled
170 ARMword *net_int; //netcard interrupt 104 ARMword *net_int; // netcard interrupt
171 105
172 //ywc,2004-04-01 106 //ywc,2004-04-01
173 ARMword *ts_int; 107 ARMword *ts_int;
@@ -180,17 +114,17 @@ struct ARMul_io
180/* added by ksh,2004-11-26,some energy profiling */ 114/* added by ksh,2004-11-26,some energy profiling */
181struct ARMul_Energy 115struct ARMul_Energy
182{ 116{
183 int energy_prof; /* <tktan> BUG200103282109 : for energy profiling */ 117 int energy_prof; /* <tktan> BUG200103282109 : for energy profiling */
184 int enable_func_energy; /* <tktan> BUG200105181702 */ 118 int enable_func_energy; /* <tktan> BUG200105181702 */
185 char *func_energy; 119 char *func_energy;
186 int func_display; /* <tktan> BUG200103311509 : for function call display */ 120 int func_display; /* <tktan> BUG200103311509 : for function call display */
187 int func_disp_start; /* <tktan> BUG200104191428 : to start func profiling */ 121 int func_disp_start; /* <tktan> BUG200104191428 : to start func profiling */
188 char *start_func; /* <tktan> BUG200104191428 */ 122 char *start_func; /* <tktan> BUG200104191428 */
189 123
190 FILE *outfile; /* <tktan> BUG200105201531 : direct console to file */ 124 FILE *outfile; /* <tktan> BUG200105201531 : direct console to file */
191 long long tcycle, pcycle; 125 long long tcycle, pcycle;
192 float t_energy; 126 float t_energy;
193 void *cur_task; /* <tktan> BUG200103291737 */ 127 void *cur_task; /* <tktan> BUG200103291737 */
194 long long t_mem_cycle, t_idle_cycle, t_uart_cycle; 128 long long t_mem_cycle, t_idle_cycle, t_uart_cycle;
195 long long p_mem_cycle, p_idle_cycle, p_uart_cycle; 129 long long p_mem_cycle, p_idle_cycle, p_uart_cycle;
196 long long p_io_update_tcycle; 130 long long p_io_update_tcycle;
@@ -203,13 +137,12 @@ struct ARMul_Energy
203 137
204typedef struct mem_bank 138typedef struct mem_bank
205{ 139{
206 ARMword (*read_byte) (ARMul_State * state, ARMword addr); 140 ARMword (*read_byte) (ARMul_State* state, ARMword addr);
207 void (*write_byte) (ARMul_State * state, ARMword addr, ARMword data); 141 void (*write_byte) (ARMul_State* state, ARMword addr, ARMword data);
208 ARMword (*read_halfword) (ARMul_State * state, ARMword addr); 142 ARMword (*read_halfword) (ARMul_State* state, ARMword addr);
209 void (*write_halfword) (ARMul_State * state, ARMword addr, 143 void (*write_halfword) (ARMul_State* state, ARMword addr, ARMword data);
210 ARMword data); 144 ARMword (*read_word) (ARMul_State* state, ARMword addr);
211 ARMword (*read_word) (ARMul_State * state, ARMword addr); 145 void (*write_word) (ARMul_State* state, ARMword addr, ARMword data);
212 void (*write_word) (ARMul_State * state, ARMword addr, ARMword data);
213 unsigned int addr, len; 146 unsigned int addr, len;
214 char filename[MAX_STR]; 147 char filename[MAX_STR];
215 unsigned type; //chy 2003-09-21: maybe io,ram,rom 148 unsigned type; //chy 2003-09-21: maybe io,ram,rom
@@ -224,24 +157,24 @@ typedef struct
224#define VFP_REG_NUM 64 157#define VFP_REG_NUM 64
225struct ARMul_State 158struct ARMul_State
226{ 159{
227 ARMword Emulate; /* to start and stop emulation */ 160 ARMword Emulate; /* to start and stop emulation */
228 unsigned EndCondition; /* reason for stopping */ 161 unsigned EndCondition; /* reason for stopping */
229 unsigned ErrorCode; /* type of illegal instruction */ 162 unsigned ErrorCode; /* type of illegal instruction */
230 163
231 /* Order of the following register should not be modified */ 164 /* Order of the following register should not be modified */
232 ARMword Reg[16]; /* the current register file */ 165 ARMword Reg[16]; /* the current register file */
233 ARMword Cpsr; /* the current psr */ 166 ARMword Cpsr; /* the current psr */
234 ARMword Spsr_copy; 167 ARMword Spsr_copy;
235 ARMword phys_pc; 168 ARMword phys_pc;
236 ARMword Reg_usr[2]; 169 ARMword Reg_usr[2];
237 ARMword Reg_svc[2]; /* R13_SVC R14_SVC */ 170 ARMword Reg_svc[2]; /* R13_SVC R14_SVC */
238 ARMword Reg_abort[2]; /* R13_ABORT R14_ABORT */ 171 ARMword Reg_abort[2]; /* R13_ABORT R14_ABORT */
239 ARMword Reg_undef[2]; /* R13 UNDEF R14 UNDEF */ 172 ARMword Reg_undef[2]; /* R13 UNDEF R14 UNDEF */
240 ARMword Reg_irq[2]; /* R13_IRQ R14_IRQ */ 173 ARMword Reg_irq[2]; /* R13_IRQ R14_IRQ */
241 ARMword Reg_firq[7]; /* R8---R14 FIRQ */ 174 ARMword Reg_firq[7]; /* R8---R14 FIRQ */
242 ARMword Spsr[7]; /* the exception psr's */ 175 ARMword Spsr[7]; /* the exception psr's */
243 ARMword Mode; /* the current mode */ 176 ARMword Mode; /* the current mode */
244 ARMword Bank; /* the current register bank */ 177 ARMword Bank; /* the current register bank */
245 ARMword exclusive_tag; 178 ARMword exclusive_tag;
246 ARMword exclusive_state; 179 ARMword exclusive_state;
247 ARMword exclusive_result; 180 ARMword exclusive_result;
@@ -265,7 +198,7 @@ struct ARMul_State
265 //ARMword translate_pc; 198 //ARMword translate_pc;
266 199
267 /* add armv6 flags dyf:2010-08-09 */ 200 /* add armv6 flags dyf:2010-08-09 */
268 ARMword GEFlag, EFlag, AFlag, QFlags; 201 ARMword GEFlag, EFlag, AFlag, QFlag;
269 //chy:2003-08-19, used in arm v5e|xscale 202 //chy:2003-08-19, used in arm v5e|xscale
270 ARMword SFlag; 203 ARMword SFlag;
271#ifdef MODET 204#ifdef MODET
@@ -281,38 +214,39 @@ struct ARMul_State
281 214
282 ARMword currentexaddr; 215 ARMword currentexaddr;
283 ARMword currentexval; 216 ARMword currentexval;
217 ARMword currentexvald;
284 ARMword servaddr; 218 ARMword servaddr;
285 219
286 unsigned NextInstr; 220 unsigned NextInstr;
287 unsigned VectorCatch; /* caught exception mask */ 221 unsigned VectorCatch; /* caught exception mask */
288 unsigned CallDebug; /* set to call the debugger */ 222 unsigned CallDebug; /* set to call the debugger */
289 unsigned CanWatch; /* set by memory interface if its willing to suffer the 223 unsigned CanWatch; /* set by memory interface if its willing to suffer the
290 overhead of checking for watchpoints on each memory 224 overhead of checking for watchpoints on each memory
291 access */ 225 access */
292 unsigned int StopHandle; 226 unsigned int StopHandle;
293 227
294 char *CommandLine; /* Command Line from ARMsd */ 228 char *CommandLine; /* Command Line from ARMsd */
295 229
296 ARMul_CPInits *CPInit[16]; /* coprocessor initialisers */ 230 ARMul_CPInits *CPInit[16]; /* coprocessor initialisers */
297 ARMul_CPExits *CPExit[16]; /* coprocessor finalisers */ 231 ARMul_CPExits *CPExit[16]; /* coprocessor finalisers */
298 ARMul_LDCs *LDC[16]; /* LDC instruction */ 232 ARMul_LDCs *LDC[16]; /* LDC instruction */
299 ARMul_STCs *STC[16]; /* STC instruction */ 233 ARMul_STCs *STC[16]; /* STC instruction */
300 ARMul_MRCs *MRC[16]; /* MRC instruction */ 234 ARMul_MRCs *MRC[16]; /* MRC instruction */
301 ARMul_MCRs *MCR[16]; /* MCR instruction */ 235 ARMul_MCRs *MCR[16]; /* MCR instruction */
302 ARMul_MRRCs *MRRC[16]; /* MRRC instruction */ 236 ARMul_MRRCs *MRRC[16]; /* MRRC instruction */
303 ARMul_MCRRs *MCRR[16]; /* MCRR instruction */ 237 ARMul_MCRRs *MCRR[16]; /* MCRR instruction */
304 ARMul_CDPs *CDP[16]; /* CDP instruction */ 238 ARMul_CDPs *CDP[16]; /* CDP instruction */
305 ARMul_CPReads *CPRead[16]; /* Read CP register */ 239 ARMul_CPReads *CPRead[16]; /* Read CP register */
306 ARMul_CPWrites *CPWrite[16]; /* Write CP register */ 240 ARMul_CPWrites *CPWrite[16]; /* Write CP register */
307 unsigned char *CPData[16]; /* Coprocessor data */ 241 unsigned char *CPData[16]; /* Coprocessor data */
308 unsigned char const *CPRegWords[16]; /* map of coprocessor register sizes */ 242 unsigned char const *CPRegWords[16]; /* map of coprocessor register sizes */
309 243
310 unsigned EventSet; /* the number of events in the queue */ 244 unsigned EventSet; /* the number of events in the queue */
311 unsigned int Now; /* time to the nearest cycle */ 245 unsigned int Now; /* time to the nearest cycle */
312 struct EventNode **EventPtr; /* the event list */ 246 struct EventNode **EventPtr; /* the event list */
313 247
314 unsigned Debug; /* show instructions as they are executed */ 248 unsigned Debug; /* show instructions as they are executed */
315 unsigned NresetSig; /* reset the processor */ 249 unsigned NresetSig; /* reset the processor */
316 unsigned NfiqSig; 250 unsigned NfiqSig;
317 unsigned NirqSig; 251 unsigned NirqSig;
318 252
@@ -356,12 +290,12 @@ So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model)
356*/ 290*/
357 unsigned lateabtSig; 291 unsigned lateabtSig;
358 292
359 ARMword Vector; /* synthesize aborts in cycle modes */ 293 ARMword Vector; /* synthesize aborts in cycle modes */
360 ARMword Aborted; /* sticky flag for aborts */ 294 ARMword Aborted; /* sticky flag for aborts */
361 ARMword Reseted; /* sticky flag for Reset */ 295 ARMword Reseted; /* sticky flag for Reset */
362 ARMword Inted, LastInted; /* sticky flags for interrupts */ 296 ARMword Inted, LastInted; /* sticky flags for interrupts */
363 ARMword Base; /* extra hand for base writeback */ 297 ARMword Base; /* extra hand for base writeback */
364 ARMword AbortAddr; /* to keep track of Prefetch aborts */ 298 ARMword AbortAddr; /* to keep track of Prefetch aborts */
365 299
366 const struct Dbg_HostosInterface *hostif; 300 const struct Dbg_HostosInterface *hostif;
367 301
@@ -378,7 +312,7 @@ So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model)
378 //chy: 2003-08-11, for different arm core type 312 //chy: 2003-08-11, for different arm core type
379 unsigned is_v4; /* Are we emulating a v4 architecture (or higher) ? */ 313 unsigned is_v4; /* Are we emulating a v4 architecture (or higher) ? */
380 unsigned is_v5; /* Are we emulating a v5 architecture ? */ 314 unsigned is_v5; /* Are we emulating a v5 architecture ? */
381 unsigned is_v5e; /* Are we emulating a v5e architecture ? */ 315 unsigned is_v5e; /* Are we emulating a v5e architecture ? */
382 unsigned is_v6; /* Are we emulating a v6 architecture ? */ 316 unsigned is_v6; /* Are we emulating a v6 architecture ? */
383 unsigned is_v7; /* Are we emulating a v7 architecture ? */ 317 unsigned is_v7; /* Are we emulating a v7 architecture ? */
384 unsigned is_XScale; /* Are we emulating an XScale architecture ? */ 318 unsigned is_XScale; /* Are we emulating an XScale architecture ? */
@@ -387,51 +321,43 @@ So, if lateabtSig=1, then it means Late Abort Model(Base Updated Abort Model)
387 //chy 2005-09-19 321 //chy 2005-09-19
388 unsigned is_pxa27x; /* Are we emulating a Intel PXA27x co-processor ? */ 322 unsigned is_pxa27x; /* Are we emulating a Intel PXA27x co-processor ? */
389 //chy: seems only used in xscale's CP14 323 //chy: seems only used in xscale's CP14
390 unsigned int LastTime; /* Value of last call to ARMul_Time() */ 324 unsigned int LastTime; /* Value of last call to ARMul_Time() */
391 ARMword CP14R0_CCD; /* used to count 64 clock cycles with CP14 R0 bit 3 set */ 325 ARMword CP14R0_CCD; /* used to count 64 clock cycles with CP14 R0 bit 3 set */
392 326
393 327
394//added by ksh:for handle different machs io 2004-3-5 328 //added by ksh:for handle different machs io 2004-3-5
395 ARMul_io mach_io; 329 ARMul_io mach_io;
396 330
397/*added by ksh,2004-11-26,some energy profiling*/ 331 /*added by ksh,2004-11-26,some energy profiling*/
398 ARMul_Energy energy; 332 ARMul_Energy energy;
399 333
400//teawater add for next_dis 2004.10.27----------------------- 334 //teawater add for next_dis 2004.10.27-----------------------
401 int disassemble; 335 int disassemble;
402//AJ2D------------------------------------------
403 336
404//teawater add for arm2x86 2005.02.15------------------------------------------- 337
338 //teawater add for arm2x86 2005.02.15-------------------------------------------
405 u32 trap; 339 u32 trap;
406 u32 tea_break_addr; 340 u32 tea_break_addr;
407 u32 tea_break_ok; 341 u32 tea_break_ok;
408 int tea_pc; 342 int tea_pc;
409//AJ2D--------------------------------------------------------------------------
410//teawater add for arm2x86 2005.07.03-------------------------------------------
411
412 /*
413 * 2007-01-24 removed the term-io functions by Anthony Lee,
414 * moved to "device/uart/skyeye_uart_stdio.c".
415 */
416 343
417//AJ2D-------------------------------------------------------------------------- 344 //teawater add for arm2x86 2005.07.05-------------------------------------------
418//teawater add for arm2x86 2005.07.05-------------------------------------------
419 //arm_arm A2-18 345 //arm_arm A2-18
420 int abort_model; //0 Base Restored Abort Model, 1 the Early Abort Model, 2 Base Updated Abort Model 346 int abort_model; //0 Base Restored Abort Model, 1 the Early Abort Model, 2 Base Updated Abort Model
421//AJ2D-------------------------------------------------------------------------- 347
422//teawater change for return if running tb dirty 2005.07.09--------------------- 348 //teawater change for return if running tb dirty 2005.07.09---------------------
423 void *tb_now; 349 void *tb_now;
424//AJ2D--------------------------------------------------------------------------
425 350
426//teawater add for record reg value to ./reg.txt 2005.07.10--------------------- 351
352 //teawater add for record reg value to ./reg.txt 2005.07.10---------------------
427 FILE *tea_reg_fd; 353 FILE *tea_reg_fd;
428//AJ2D--------------------------------------------------------------------------
429 354
430/*added by ksh in 2005-10-1*/ 355
356 /*added by ksh in 2005-10-1*/
431 cpu_config_t *cpu; 357 cpu_config_t *cpu;
432 //mem_config_t *mem_bank; 358 //mem_config_t *mem_bank;
433 359
434/* added LPC remap function */ 360 /* added LPC remap function */
435 int vector_remap_flag; 361 int vector_remap_flag;
436 u32 vector_remap_addr; 362 u32 vector_remap_addr;
437 u32 vector_remap_size; 363 u32 vector_remap_size;
@@ -486,17 +412,14 @@ typedef ARMul_State arm_core_t;
486#define ARM_Debug_Prop 0x10 412#define ARM_Debug_Prop 0x10
487#define ARM_Isync_Prop ARM_Debug_Prop 413#define ARM_Isync_Prop ARM_Debug_Prop
488#define ARM_Lock_Prop 0x20 414#define ARM_Lock_Prop 0x20
489//chy 2003-08-11
490#define ARM_v4_Prop 0x40 415#define ARM_v4_Prop 0x40
491#define ARM_v5_Prop 0x80 416#define ARM_v5_Prop 0x80
492/*jeff.du 2010-08-05 */
493#define ARM_v6_Prop 0xc0 417#define ARM_v6_Prop 0xc0
494 418
495#define ARM_v5e_Prop 0x100 419#define ARM_v5e_Prop 0x100
496#define ARM_XScale_Prop 0x200 420#define ARM_XScale_Prop 0x200
497#define ARM_ep9312_Prop 0x400 421#define ARM_ep9312_Prop 0x400
498#define ARM_iWMMXt_Prop 0x800 422#define ARM_iWMMXt_Prop 0x800
499//chy 2005-09-19
500#define ARM_PXA27X_Prop 0x1000 423#define ARM_PXA27X_Prop 0x1000
501#define ARM_v7_Prop 0x2000 424#define ARM_v7_Prop 0x2000
502 425
@@ -591,47 +514,44 @@ typedef ARMul_State arm_core_t;
591#ifdef __cplusplus 514#ifdef __cplusplus
592extern "C" { 515extern "C" {
593#endif 516#endif
594extern void ARMul_EmulateInit (void); 517extern void ARMul_EmulateInit();
595extern void ARMul_Reset (ARMul_State * state); 518extern void ARMul_Reset(ARMul_State* state);
596#ifdef __cplusplus 519#ifdef __cplusplus
597 } 520 }
598#endif 521#endif
599extern ARMul_State *ARMul_NewState (ARMul_State * state); 522extern ARMul_State *ARMul_NewState(ARMul_State* state);
600extern ARMword ARMul_DoProg (ARMul_State * state); 523extern ARMword ARMul_DoProg(ARMul_State* state);
601extern ARMword ARMul_DoInstr (ARMul_State * state); 524extern ARMword ARMul_DoInstr(ARMul_State* state);
602/***************************************************************************\ 525/***************************************************************************\
603* Definitons of things for event handling * 526* Definitons of things for event handling *
604\***************************************************************************/ 527\***************************************************************************/
605 528
606extern void ARMul_ScheduleEvent (ARMul_State * state, unsigned int delay, 529extern void ARMul_ScheduleEvent(ARMul_State* state, unsigned int delay, unsigned(*func) ());
607 unsigned (*func) ()); 530extern void ARMul_EnvokeEvent(ARMul_State* state);
608extern void ARMul_EnvokeEvent (ARMul_State * state); 531extern unsigned int ARMul_Time(ARMul_State* state);
609extern unsigned int ARMul_Time (ARMul_State * state);
610 532
611/***************************************************************************\ 533/***************************************************************************\
612* Useful support routines * 534* Useful support routines *
613\***************************************************************************/ 535\***************************************************************************/
614 536
615extern ARMword ARMul_GetReg (ARMul_State * state, unsigned mode, 537extern ARMword ARMul_GetReg (ARMul_State* state, unsigned mode, unsigned reg);
616 unsigned reg); 538extern void ARMul_SetReg (ARMul_State* state, unsigned mode, unsigned reg, ARMword value);
617extern void ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg, 539extern ARMword ARMul_GetPC(ARMul_State* state);
618 ARMword value); 540extern ARMword ARMul_GetNextPC(ARMul_State* state);
619extern ARMword ARMul_GetPC (ARMul_State * state); 541extern void ARMul_SetPC(ARMul_State* state, ARMword value);
620extern ARMword ARMul_GetNextPC (ARMul_State * state); 542extern ARMword ARMul_GetR15(ARMul_State* state);
621extern void ARMul_SetPC (ARMul_State * state, ARMword value); 543extern void ARMul_SetR15(ARMul_State* state, ARMword value);
622extern ARMword ARMul_GetR15 (ARMul_State * state); 544
623extern void ARMul_SetR15 (ARMul_State * state, ARMword value); 545extern ARMword ARMul_GetCPSR(ARMul_State* state);
624 546extern void ARMul_SetCPSR(ARMul_State* state, ARMword value);
625extern ARMword ARMul_GetCPSR (ARMul_State * state); 547extern ARMword ARMul_GetSPSR(ARMul_State* state, ARMword mode);
626extern void ARMul_SetCPSR (ARMul_State * state, ARMword value); 548extern void ARMul_SetSPSR(ARMul_State* state, ARMword mode, ARMword value);
627extern ARMword ARMul_GetSPSR (ARMul_State * state, ARMword mode);
628extern void ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value);
629 549
630/***************************************************************************\ 550/***************************************************************************\
631* Definitons of things to handle aborts * 551* Definitons of things to handle aborts *
632\***************************************************************************/ 552\***************************************************************************/
633 553
634extern void ARMul_Abort (ARMul_State * state, ARMword address); 554extern void ARMul_Abort(ARMul_State* state, ARMword address);
635#ifdef MODET 555#ifdef MODET
636#define ARMul_ABORTWORD (state->TFlag ? 0xefffdfff : 0xefffffff) /* SWI -1 */ 556#define ARMul_ABORTWORD (state->TFlag ? 0xefffdfff : 0xefffffff) /* SWI -1 */
637#define ARMul_PREFETCHABORT(address) if (state->AbortAddr == 1) \ 557#define ARMul_PREFETCHABORT(address) if (state->AbortAddr == 1) \
@@ -649,54 +569,40 @@ extern void ARMul_Abort (ARMul_State * state, ARMword address);
649* Definitons of things in the memory interface * 569* Definitons of things in the memory interface *
650\***************************************************************************/ 570\***************************************************************************/
651 571
652extern unsigned ARMul_MemoryInit (ARMul_State * state, 572extern unsigned ARMul_MemoryInit(ARMul_State* state, unsigned int initmemsize);
653 unsigned int initmemsize); 573extern void ARMul_MemoryExit(ARMul_State* state);
654extern void ARMul_MemoryExit (ARMul_State * state);
655 574
656extern ARMword ARMul_LoadInstrS (ARMul_State * state, ARMword address, 575extern ARMword ARMul_LoadInstrS(ARMul_State* state, ARMword address, ARMword isize);
657 ARMword isize); 576extern ARMword ARMul_LoadInstrN(ARMul_State* state, ARMword address, ARMword isize);
658extern ARMword ARMul_LoadInstrN (ARMul_State * state, ARMword address,
659 ARMword isize);
660#ifdef __cplusplus 577#ifdef __cplusplus
661extern "C" { 578extern "C" {
662#endif 579#endif
663extern ARMword ARMul_ReLoadInstr (ARMul_State * state, ARMword address, 580extern ARMword ARMul_ReLoadInstr(ARMul_State* state, ARMword address, ARMword isize);
664 ARMword isize);
665#ifdef __cplusplus 581#ifdef __cplusplus
666 } 582 }
667#endif 583#endif
668extern ARMword ARMul_LoadWordS (ARMul_State * state, ARMword address); 584extern ARMword ARMul_LoadWordS(ARMul_State* state, ARMword address);
669extern ARMword ARMul_LoadWordN (ARMul_State * state, ARMword address); 585extern ARMword ARMul_LoadWordN(ARMul_State* state, ARMword address);
670extern ARMword ARMul_LoadHalfWord (ARMul_State * state, ARMword address); 586extern ARMword ARMul_LoadHalfWord(ARMul_State* state, ARMword address);
671extern ARMword ARMul_LoadByte (ARMul_State * state, ARMword address); 587extern ARMword ARMul_LoadByte(ARMul_State* state, ARMword address);
672 588
673extern void ARMul_StoreWordS (ARMul_State * state, ARMword address, 589extern void ARMul_StoreWordS(ARMul_State* state, ARMword address, ARMword data);
674 ARMword data); 590extern void ARMul_StoreWordN(ARMul_State* state, ARMword address, ARMword data);
675extern void ARMul_StoreWordN (ARMul_State * state, ARMword address, 591extern void ARMul_StoreHalfWord(ARMul_State* state, ARMword address, ARMword data);
676 ARMword data); 592extern void ARMul_StoreByte(ARMul_State* state, ARMword address, ARMword data);
677extern void ARMul_StoreHalfWord (ARMul_State * state, ARMword address, 593
678 ARMword data); 594extern ARMword ARMul_SwapWord(ARMul_State* state, ARMword address, ARMword data);
679extern void ARMul_StoreByte (ARMul_State * state, ARMword address, 595extern ARMword ARMul_SwapByte(ARMul_State* state, ARMword address, ARMword data);
680 ARMword data); 596
681 597extern void ARMul_Icycles(ARMul_State* state, unsigned number, ARMword address);
682extern ARMword ARMul_SwapWord (ARMul_State * state, ARMword address, 598extern void ARMul_Ccycles(ARMul_State* state, unsigned number, ARMword address);
683 ARMword data); 599
684extern ARMword ARMul_SwapByte (ARMul_State * state, ARMword address, 600extern ARMword ARMul_ReadWord(ARMul_State* state, ARMword address);
685 ARMword data); 601extern ARMword ARMul_ReadByte(ARMul_State* state, ARMword address);
686 602extern void ARMul_WriteWord(ARMul_State* state, ARMword address, ARMword data);
687extern void ARMul_Icycles (ARMul_State * state, unsigned number, 603extern void ARMul_WriteByte(ARMul_State* state, ARMword address, ARMword data);
688 ARMword address); 604
689extern void ARMul_Ccycles (ARMul_State * state, unsigned number, 605extern ARMword ARMul_MemAccess(ARMul_State* state, ARMword, ARMword,
690 ARMword address);
691
692extern ARMword ARMul_ReadWord (ARMul_State * state, ARMword address);
693extern ARMword ARMul_ReadByte (ARMul_State * state, ARMword address);
694extern void ARMul_WriteWord (ARMul_State * state, ARMword address,
695 ARMword data);
696extern void ARMul_WriteByte (ARMul_State * state, ARMword address,
697 ARMword data);
698
699extern ARMword ARMul_MemAccess (ARMul_State * state, ARMword, ARMword,
700 ARMword, ARMword, ARMword, ARMword, ARMword, 606 ARMword, ARMword, ARMword, ARMword, ARMword,
701 ARMword, ARMword, ARMword); 607 ARMword, ARMword, ARMword);
702 608
@@ -739,66 +645,40 @@ extern ARMword ARMul_MemAccess (ARMul_State * state, ARMword, ARMword,
739#define ARMul_CP15_DBCON_E1 0x000c 645#define ARMul_CP15_DBCON_E1 0x000c
740#define ARMul_CP15_DBCON_E0 0x0003 646#define ARMul_CP15_DBCON_E0 0x0003
741 647
742extern unsigned ARMul_CoProInit (ARMul_State * state); 648extern unsigned ARMul_CoProInit(ARMul_State* state);
743extern void ARMul_CoProExit (ARMul_State * state); 649extern void ARMul_CoProExit(ARMul_State* state);
744extern void ARMul_CoProAttach (ARMul_State * state, unsigned number, 650extern void ARMul_CoProAttach (ARMul_State* state, unsigned number,
745 ARMul_CPInits * init, ARMul_CPExits * exit, 651 ARMul_CPInits* init, ARMul_CPExits* exit,
746 ARMul_LDCs * ldc, ARMul_STCs * stc, 652 ARMul_LDCs* ldc, ARMul_STCs* stc,
747 ARMul_MRCs * mrc, ARMul_MCRs * mcr, 653 ARMul_MRCs* mrc, ARMul_MCRs* mcr,
748 ARMul_MRRCs * mrrc, ARMul_MCRRs * mcrr, 654 ARMul_MRRCs* mrrc, ARMul_MCRRs* mcrr,
749 ARMul_CDPs * cdp, 655 ARMul_CDPs* cdp,
750 ARMul_CPReads * read, ARMul_CPWrites * write); 656 ARMul_CPReads* read, ARMul_CPWrites* write);
751extern void ARMul_CoProDetach (ARMul_State * state, unsigned number); 657extern void ARMul_CoProDetach(ARMul_State* state, unsigned number);
752 658
753/***************************************************************************\ 659/***************************************************************************\
754* Definitons of things in the host environment * 660* Definitons of things in the host environment *
755\***************************************************************************/ 661\***************************************************************************/
756 662
757extern unsigned ARMul_OSInit (ARMul_State * state); 663extern unsigned ARMul_OSInit(ARMul_State* state);
758extern void ARMul_OSExit (ARMul_State * state); 664extern void ARMul_OSExit(ARMul_State* state);
759 665
760#ifdef __cplusplus 666#ifdef __cplusplus
761 extern "C" { 667 extern "C" {
762#endif 668#endif
763 669
764extern unsigned ARMul_OSHandleSWI (ARMul_State * state, ARMword number); 670extern unsigned ARMul_OSHandleSWI(ARMul_State* state, ARMword number);
765#ifdef __cplusplus 671#ifdef __cplusplus
766} 672}
767#endif 673#endif
768 674
769 675
770extern ARMword ARMul_OSLastErrorP (ARMul_State * state); 676extern ARMword ARMul_OSLastErrorP(ARMul_State* state);
771 677
772extern ARMword ARMul_Debug (ARMul_State * state, ARMword pc, ARMword instr); 678extern ARMword ARMul_Debug(ARMul_State* state, ARMword pc, ARMword instr);
773extern unsigned ARMul_OSException (ARMul_State * state, ARMword vector, 679extern unsigned ARMul_OSException(ARMul_State* state, ARMword vector, ARMword pc);
774 ARMword pc);
775extern int rdi_log; 680extern int rdi_log;
776 681
777/***************************************************************************\
778* Host-dependent stuff *
779\***************************************************************************/
780
781#ifdef macintosh
782pascal void SpinCursor (short increment); /* copied from CursorCtl.h */
783# define HOURGLASS SpinCursor( 1 )
784# define HOURGLASS_RATE 1023 /* 2^n - 1 */
785#endif
786
787//teawater add for arm2x86 2005.02.14-------------------------------------------
788/*ywc 2005-03-31*/
789/*
790#include "arm2x86.h"
791#include "arm2x86_dp.h"
792#include "arm2x86_movl.h"
793#include "arm2x86_psr.h"
794#include "arm2x86_shift.h"
795#include "arm2x86_mem.h"
796#include "arm2x86_mul.h"
797#include "arm2x86_test.h"
798#include "arm2x86_other.h"
799#include "list.h"
800#include "tb.h"
801*/
802enum ConditionCode { 682enum ConditionCode {
803 EQ = 0, 683 EQ = 0,
804 NE = 1, 684 NE = 1,
@@ -851,32 +731,16 @@ enum ConditionCode {
851#define ZBIT_SHIFT 30 731#define ZBIT_SHIFT 30
852#define CBIT_SHIFT 29 732#define CBIT_SHIFT 29
853#define VBIT_SHIFT 28 733#define VBIT_SHIFT 28
854#ifdef DBCT 734
855//teawater change for local tb branch directly jump 2005.10.18------------------
856#include "dbct/list.h"
857#include "dbct/arm2x86.h"
858#include "dbct/arm2x86_dp.h"
859#include "dbct/arm2x86_movl.h"
860#include "dbct/arm2x86_psr.h"
861#include "dbct/arm2x86_shift.h"
862#include "dbct/arm2x86_mem.h"
863#include "dbct/arm2x86_mul.h"
864#include "dbct/arm2x86_test.h"
865#include "dbct/arm2x86_other.h"
866#include "dbct/arm2x86_coproc.h"
867#include "dbct/tb.h"
868#endif
869//AJ2D--------------------------------------------------------------------------
870//AJ2D--------------------------------------------------------------------------
871#define SKYEYE_OUTREGS(fd) { fprintf ((fd), "R %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,C %x,S %x,%x,%x,%x,%x,%x,%x,M %x,B %x,E %x,I %x,P %x,T %x,L %x,D %x,",\ 735#define SKYEYE_OUTREGS(fd) { fprintf ((fd), "R %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,C %x,S %x,%x,%x,%x,%x,%x,%x,M %x,B %x,E %x,I %x,P %x,T %x,L %x,D %x,",\
872 state->Reg[0],state->Reg[1],state->Reg[2],state->Reg[3], \ 736 state->Reg[0],state->Reg[1],state->Reg[2],state->Reg[3], \
873 state->Reg[4],state->Reg[5],state->Reg[6],state->Reg[7], \ 737 state->Reg[4],state->Reg[5],state->Reg[6],state->Reg[7], \
874 state->Reg[8],state->Reg[9],state->Reg[10],state->Reg[11], \ 738 state->Reg[8],state->Reg[9],state->Reg[10],state->Reg[11], \
875 state->Reg[12],state->Reg[13],state->Reg[14],state->Reg[15], \ 739 state->Reg[12],state->Reg[13],state->Reg[14],state->Reg[15], \
876 state->Cpsr, state->Spsr[0], state->Spsr[1], state->Spsr[2],\ 740 state->Cpsr, state->Spsr[0], state->Spsr[1], state->Spsr[2],\
877 state->Spsr[3],state->Spsr[4], state->Spsr[5], state->Spsr[6],\ 741 state->Spsr[3],state->Spsr[4], state->Spsr[5], state->Spsr[6],\
878 state->Mode,state->Bank,state->ErrorCode,state->instr,state->pc,\ 742 state->Mode,state->Bank,state->ErrorCode,state->instr,state->pc,\
879 state->temp,state->loaded,state->decoded);} 743 state->temp,state->loaded,state->decoded);}
880 744
881#define SKYEYE_OUTMOREREGS(fd) { fprintf ((fd),"\ 745#define SKYEYE_OUTMOREREGS(fd) { fprintf ((fd),"\
882RUs %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,\ 746RUs %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,\
@@ -914,17 +778,30 @@ RUn %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x\n",\
914 778
915#define SA1110 0x6901b110 779#define SA1110 0x6901b110
916#define SA1100 0x4401a100 780#define SA1100 0x4401a100
917#define PXA250 0x69052100 781#define PXA250 0x69052100
918#define PXA270 0x69054110 782#define PXA270 0x69054110
919//#define PXA250 0x69052903 783//#define PXA250 0x69052903
920// 0x69052903; //PXA250 B1 from intel 278522-001.pdf 784// 0x69052903; //PXA250 B1 from intel 278522-001.pdf
921 785
922 786
923extern void ARMul_UndefInstr (ARMul_State *, ARMword); 787extern void ARMul_UndefInstr(ARMul_State*, ARMword);
924extern void ARMul_FixCPSR (ARMul_State *, ARMword, ARMword); 788extern void ARMul_FixCPSR(ARMul_State*, ARMword, ARMword);
925extern void ARMul_FixSPSR (ARMul_State *, ARMword, ARMword); 789extern void ARMul_FixSPSR(ARMul_State*, ARMword, ARMword);
926extern void ARMul_ConsolePrint (ARMul_State *, const char *, ...); 790extern void ARMul_ConsolePrint(ARMul_State*, const char*, ...);
927extern void ARMul_SelectProcessor (ARMul_State *, unsigned); 791extern void ARMul_SelectProcessor(ARMul_State*, unsigned);
792
793extern u8 ARMul_SignedSaturatedAdd8(u8, u8);
794extern u8 ARMul_SignedSaturatedSub8(u8, u8);
795extern u16 ARMul_SignedSaturatedAdd16(u16, u16);
796extern u16 ARMul_SignedSaturatedSub16(u16, u16);
797
798extern u8 ARMul_UnsignedSaturatedAdd8(u8, u8);
799extern u16 ARMul_UnsignedSaturatedAdd16(u16, u16);
800extern u8 ARMul_UnsignedSaturatedSub8(u8, u8);
801extern u16 ARMul_UnsignedSaturatedSub16(u16, u16);
802extern u8 ARMul_UnsignedAbsoluteDifference(u8, u8);
803extern u32 ARMul_SignedSatQ(s32, u8, bool*);
804extern u32 ARMul_UnsignedSatQ(s32, u8, bool*);
928 805
929#define DIFF_LOG 0 806#define DIFF_LOG 0
930#define SAVE_LOG 0 807#define SAVE_LOG 0
diff --git a/src/core/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h
index 075fc7e9e..3ea14b5a3 100644
--- a/src/core/arm/skyeye_common/armemu.h
+++ b/src/core/arm/skyeye_common/armemu.h
@@ -23,8 +23,6 @@
23 23
24//extern ARMword isize; 24//extern ARMword isize;
25 25
26#define DEBUG(...) DEBUG_LOG(ARM11, __VA_ARGS__)
27
28/* Shift Opcodes. */ 26/* Shift Opcodes. */
29#define LSL 0 27#define LSL 0
30#define LSR 1 28#define LSR 1
@@ -36,7 +34,7 @@
36#define ZBIT (1L << 30) 34#define ZBIT (1L << 30)
37#define CBIT (1L << 29) 35#define CBIT (1L << 29)
38#define VBIT (1L << 28) 36#define VBIT (1L << 28)
39#define SBIT (1L << 27) 37#define QBIT (1L << 27)
40#define IBIT (1L << 7) 38#define IBIT (1L << 7)
41#define FBIT (1L << 6) 39#define FBIT (1L << 6)
42#define IFBITS (3L << 6) 40#define IFBITS (3L << 6)
@@ -158,13 +156,14 @@
158#define R15PCMODE (state->Reg[15] & (R15PCBITS | R15MODEBITS)) 156#define R15PCMODE (state->Reg[15] & (R15PCBITS | R15MODEBITS))
159#define R15MODE (state->Reg[15] & R15MODEBITS) 157#define R15MODE (state->Reg[15] & R15MODEBITS)
160 158
161#define ECC ((NFLAG << 31) | (ZFLAG << 30) | (CFLAG << 29) | (VFLAG << 28) | (SFLAG << 27)) 159#define ECC ((NFLAG << 31) | (ZFLAG << 30) | (CFLAG << 29) | (VFLAG << 28) | (QFLAG << 27))
162#define EINT (IFFLAGS << 6) 160#define EINT (IFFLAGS << 6)
163#define ER15INT (IFFLAGS << 26) 161#define ER15INT (IFFLAGS << 26)
164#define EMODE (state->Mode) 162#define EMODE (state->Mode)
163#define EGEBITS (state->GEFlag & 0x000F0000)
165 164
166#ifdef MODET 165#ifdef MODET
167#define CPSR (ECC | EINT | EMODE | (TFLAG << 5)) 166#define CPSR (ECC | EGEBITS | (EFLAG << 9) | (AFLAG << 8) | EINT | (TFLAG << 5) | EMODE)
168#else 167#else
169#define CPSR (ECC | EINT | EMODE) 168#define CPSR (ECC | EINT | EMODE)
170#endif 169#endif
@@ -485,7 +484,7 @@ tdstate;
485 * out-of-updated with the newer ISA. 484 * out-of-updated with the newer ISA.
486 * -- Michael.Kang 485 * -- Michael.Kang
487 ********************************************************************************/ 486 ********************************************************************************/
488#define UNDEF_WARNING WARN_LOG(ARM11, "undefined or unpredicted behavior for arm instruction.\n"); 487#define UNDEF_WARNING LOG_WARNING(Core_ARM11, "undefined or unpredicted behavior for arm instruction.");
489 488
490/* Macros to scrutinize instructions. */ 489/* Macros to scrutinize instructions. */
491#define UNDEF_Test UNDEF_WARNING 490#define UNDEF_Test UNDEF_WARNING
@@ -603,6 +602,7 @@ extern ARMword ARMul_SwitchMode (ARMul_State *, ARMword, ARMword);
603extern void ARMul_MSRCpsr (ARMul_State *, ARMword, ARMword); 602extern void ARMul_MSRCpsr (ARMul_State *, ARMword, ARMword);
604extern void ARMul_SubOverflow (ARMul_State *, ARMword, ARMword, ARMword); 603extern void ARMul_SubOverflow (ARMul_State *, ARMword, ARMword, ARMword);
605extern void ARMul_AddOverflow (ARMul_State *, ARMword, ARMword, ARMword); 604extern void ARMul_AddOverflow (ARMul_State *, ARMword, ARMword, ARMword);
605extern void ARMul_AddOverflowQ(ARMul_State*, ARMword, ARMword);
606extern void ARMul_SubCarry (ARMul_State *, ARMword, ARMword, ARMword); 606extern void ARMul_SubCarry (ARMul_State *, ARMword, ARMword, ARMword);
607extern void ARMul_AddCarry (ARMul_State *, ARMword, ARMword, ARMword); 607extern void ARMul_AddCarry (ARMul_State *, ARMword, ARMword, ARMword);
608extern tdstate ARMul_ThumbDecode (ARMul_State *, ARMword, ARMword, ARMword *); 608extern tdstate ARMul_ThumbDecode (ARMul_State *, ARMword, ARMword, ARMword *);
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp
index 454f60099..5c036caeb 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfp.cpp
@@ -32,8 +32,7 @@
32 32
33//ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */ 33//ARMul_State* persistent_state; /* function calls from SoftFloat lib don't have an access to ARMul_state. */
34 34
35unsigned 35unsigned VFPInit(ARMul_State* state)
36VFPInit (ARMul_State *state)
37{ 36{
38 state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 | 37 state->VFP[VFP_OFFSET(VFP_FPSID)] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
39 VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION; 38 VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
@@ -46,8 +45,7 @@ VFPInit (ARMul_State *state)
46 return 0; 45 return 0;
47} 46}
48 47
49unsigned 48unsigned VFPMRC(ARMul_State* state, unsigned type, u32 instr, u32* value)
50VFPMRC (ARMul_State * state, unsigned type, u32 instr, u32 * value)
51{ 49{
52 /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */ 50 /* MRC<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
53 int CoProc = BITS (8, 11); /* 10 or 11 */ 51 int CoProc = BITS (8, 11); /* 10 or 11 */
@@ -61,10 +59,21 @@ VFPMRC (ARMul_State * state, unsigned type, u32 instr, u32 * value)
61 59
62 /* CRn/opc1 CRm/opc2 */ 60 /* CRn/opc1 CRm/opc2 */
63 61
64 if (CoProc == 10 || CoProc == 11) { 62 if (CoProc == 10 || CoProc == 11)
65#define VFP_MRC_TRANS 63 {
66#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 64 if (OPC_1 == 0x0 && CRm == 0 && (OPC_2 & 0x3) == 0)
67#undef VFP_MRC_TRANS 65 {
66 /* VMOV r to s */
67 /* Transfering Rt is not mandatory, as the value of interest is pointed by value */
68 VMOVBRS(state, BIT(20), Rt, BIT(7)|CRn<<1, value);
69 return ARMul_DONE;
70 }
71
72 if (OPC_1 == 0x7 && CRm == 0 && OPC_2 == 0)
73 {
74 VMRS(state, CRn, Rt, value);
75 return ARMul_DONE;
76 }
68 } 77 }
69 DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n", 78 DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
70 instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2); 79 instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
@@ -72,8 +81,7 @@ VFPMRC (ARMul_State * state, unsigned type, u32 instr, u32 * value)
72 return ARMul_CANT; 81 return ARMul_CANT;
73} 82}
74 83
75unsigned 84unsigned VFPMCR(ARMul_State* state, unsigned type, u32 instr, u32 value)
76VFPMCR (ARMul_State * state, unsigned type, u32 instr, u32 value)
77{ 85{
78 /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */ 86 /* MCR<c> <coproc>,<opc1>,<Rt>,<CRn>,<CRm>{,<opc2>} */
79 int CoProc = BITS (8, 11); /* 10 or 11 */ 87 int CoProc = BITS (8, 11); /* 10 or 11 */
@@ -86,10 +94,33 @@ VFPMCR (ARMul_State * state, unsigned type, u32 instr, u32 value)
86 /* TODO check access permission */ 94 /* TODO check access permission */
87 95
88 /* CRn/opc1 CRm/opc2 */ 96 /* CRn/opc1 CRm/opc2 */
89 if (CoProc == 10 || CoProc == 11) { 97 if (CoProc == 10 || CoProc == 11)
90#define VFP_MCR_TRANS 98 {
91#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 99 if (OPC_1 == 0x0 && CRm == 0 && (OPC_2 & 0x3) == 0)
92#undef VFP_MCR_TRANS 100 {
101 /* VMOV s to r */
102 /* Transfering Rt is not mandatory, as the value of interest is pointed by value */
103 VMOVBRS(state, BIT(20), Rt, BIT(7)|CRn<<1, &value);
104 return ARMul_DONE;
105 }
106
107 if (OPC_1 == 0x7 && CRm == 0 && OPC_2 == 0)
108 {
109 VMSR(state, CRn, Rt);
110 return ARMul_DONE;
111 }
112
113 if ((OPC_1 & 0x4) == 0 && CoProc == 11 && CRm == 0)
114 {
115 VFP_DEBUG_UNIMPLEMENTED(VMOVBRC);
116 return ARMul_DONE;
117 }
118
119 if (CoProc == 11 && CRm == 0)
120 {
121 VFP_DEBUG_UNIMPLEMENTED(VMOVBCR);
122 return ARMul_DONE;
123 }
93 } 124 }
94 DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n", 125 DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, CRn %x, CRm %x, OPC_2 %x\n",
95 instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2); 126 instr, CoProc, OPC_1, Rt, CRn, CRm, OPC_2);
@@ -97,8 +128,7 @@ VFPMCR (ARMul_State * state, unsigned type, u32 instr, u32 value)
97 return ARMul_CANT; 128 return ARMul_CANT;
98} 129}
99 130
100unsigned 131unsigned VFPMRRC(ARMul_State* state, unsigned type, u32 instr, u32* value1, u32* value2)
101VFPMRRC (ARMul_State * state, unsigned type, u32 instr, u32 * value1, u32 * value2)
102{ 132{
103 /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */ 133 /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
104 int CoProc = BITS (8, 11); /* 10 or 11 */ 134 int CoProc = BITS (8, 11); /* 10 or 11 */
@@ -107,10 +137,20 @@ VFPMRRC (ARMul_State * state, unsigned type, u32 instr, u32 * value1, u32 * valu
107 int Rt2 = BITS (16, 19); 137 int Rt2 = BITS (16, 19);
108 int CRm = BITS (0, 3); 138 int CRm = BITS (0, 3);
109 139
110 if (CoProc == 10 || CoProc == 11) { 140 if (CoProc == 10 || CoProc == 11)
111#define VFP_MRRC_TRANS 141 {
112#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 142 if (CoProc == 10 && (OPC_1 & 0xD) == 1)
113#undef VFP_MRRC_TRANS 143 {
144 VFP_DEBUG_UNIMPLEMENTED(VMOVBRRSS);
145 return ARMul_DONE;
146 }
147
148 if (CoProc == 11 && (OPC_1 & 0xD) == 1)
149 {
150 /* Transfering Rt and Rt2 is not mandatory, as the value of interest is pointed by value1 and value2 */
151 VMOVBRRD(state, BIT(20), Rt, Rt2, BIT(5)<<4|CRm, value1, value2);
152 return ARMul_DONE;
153 }
114 } 154 }
115 DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n", 155 DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
116 instr, CoProc, OPC_1, Rt, Rt2, CRm); 156 instr, CoProc, OPC_1, Rt, Rt2, CRm);
@@ -118,8 +158,7 @@ VFPMRRC (ARMul_State * state, unsigned type, u32 instr, u32 * value1, u32 * valu
118 return ARMul_CANT; 158 return ARMul_CANT;
119} 159}
120 160
121unsigned 161unsigned VFPMCRR(ARMul_State* state, unsigned type, u32 instr, u32 value1, u32 value2)
122VFPMCRR (ARMul_State * state, unsigned type, u32 instr, u32 value1, u32 value2)
123{ 162{
124 /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */ 163 /* MCRR<c> <coproc>,<opc1>,<Rt>,<Rt2>,<CRm> */
125 int CoProc = BITS (8, 11); /* 10 or 11 */ 164 int CoProc = BITS (8, 11); /* 10 or 11 */
@@ -132,10 +171,20 @@ VFPMCRR (ARMul_State * state, unsigned type, u32 instr, u32 value1, u32 value2)
132 171
133 /* CRn/opc1 CRm/opc2 */ 172 /* CRn/opc1 CRm/opc2 */
134 173
135 if (CoProc == 11 || CoProc == 10) { 174 if (CoProc == 11 || CoProc == 10)
136#define VFP_MCRR_TRANS 175 {
137#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 176 if (CoProc == 10 && (OPC_1 & 0xD) == 1)
138#undef VFP_MCRR_TRANS 177 {
178 VFP_DEBUG_UNIMPLEMENTED(VMOVBRRSS);
179 return ARMul_DONE;
180 }
181
182 if (CoProc == 11 && (OPC_1 & 0xD) == 1)
183 {
184 /* Transfering Rt and Rt2 is not mandatory, as the value of interest is pointed by value1 and value2 */
185 VMOVBRRD(state, BIT(20), Rt, Rt2, BIT(5)<<4|CRm, &value1, &value2);
186 return ARMul_DONE;
187 }
139 } 188 }
140 DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n", 189 DEBUG("Can't identify %x, CoProc %x, OPC_1 %x, Rt %x, Rt2 %x, CRm %x\n",
141 instr, CoProc, OPC_1, Rt, Rt2, CRm); 190 instr, CoProc, OPC_1, Rt, Rt2, CRm);
@@ -143,8 +192,7 @@ VFPMCRR (ARMul_State * state, unsigned type, u32 instr, u32 value1, u32 value2)
143 return ARMul_CANT; 192 return ARMul_CANT;
144} 193}
145 194
146unsigned 195unsigned VFPSTC(ARMul_State* state, unsigned type, u32 instr, u32 * value)
147VFPSTC (ARMul_State * state, unsigned type, u32 instr, u32 * value)
148{ 196{
149 /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */ 197 /* STC{L}<c> <coproc>,<CRd>,[<Rn>],<option> */
150 int CoProc = BITS (8, 11); /* 10 or 11 */ 198 int CoProc = BITS (8, 11); /* 10 or 11 */
@@ -175,9 +223,17 @@ VFPSTC (ARMul_State * state, unsigned type, u32 instr, u32 * value)
175 } 223 }
176#endif 224#endif
177 225
178#define VFP_STC_TRANS 226 if (P == 1 && W == 0)
179#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 227 {
180#undef VFP_STC_TRANS 228 return VSTR(state, type, instr, value);
229 }
230
231 if (P == 1 && U == 0 && W == 1 && Rn == 0xD)
232 {
233 return VPUSH(state, type, instr, value);
234 }
235
236 return VSTM(state, type, instr, value);
181 } 237 }
182 DEBUG("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n", 238 DEBUG("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
183 instr, CoProc, CRd, Rn, imm8, P, U, D, W); 239 instr, CoProc, CRd, Rn, imm8, P, U, D, W);
@@ -185,8 +241,7 @@ VFPSTC (ARMul_State * state, unsigned type, u32 instr, u32 * value)
185 return ARMul_CANT; 241 return ARMul_CANT;
186} 242}
187 243
188unsigned 244unsigned VFPLDC(ARMul_State* state, unsigned type, u32 instr, u32 value)
189VFPLDC (ARMul_State * state, unsigned type, u32 instr, u32 value)
190{ 245{
191 /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */ 246 /* LDC{L}<c> <coproc>,<CRd>,[<Rn>] */
192 int CoProc = BITS (8, 11); /* 10 or 11 */ 247 int CoProc = BITS (8, 11); /* 10 or 11 */
@@ -204,10 +259,19 @@ VFPLDC (ARMul_State * state, unsigned type, u32 instr, u32 value)
204 DEBUG("In %s, UNDEFINED\n", __FUNCTION__); 259 DEBUG("In %s, UNDEFINED\n", __FUNCTION__);
205 exit(-1); 260 exit(-1);
206 } 261 }
207 if (CoProc == 10 || CoProc == 11) { 262 if (CoProc == 10 || CoProc == 11)
208#define VFP_LDC_TRANS 263 {
209#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 264 if (P == 1 && W == 0)
210#undef VFP_LDC_TRANS 265 {
266 return VLDR(state, type, instr, value);
267 }
268
269 if (P == 0 && U == 1 && W == 1 && Rn == 0xD)
270 {
271 return VPOP(state, type, instr, value);
272 }
273
274 return VLDM(state, type, instr, value);
211 } 275 }
212 DEBUG("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n", 276 DEBUG("Can't identify %x, CoProc %x, CRd %x, Rn %x, imm8 %x, P %x, U %x, D %x, W %x\n",
213 instr, CoProc, CRd, Rn, imm8, P, U, D, W); 277 instr, CoProc, CRd, Rn, imm8, P, U, D, W);
@@ -215,8 +279,7 @@ VFPLDC (ARMul_State * state, unsigned type, u32 instr, u32 value)
215 return ARMul_CANT; 279 return ARMul_CANT;
216} 280}
217 281
218unsigned 282unsigned VFPCDP(ARMul_State* state, unsigned type, u32 instr)
219VFPCDP (ARMul_State * state, unsigned type, u32 instr)
220{ 283{
221 /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */ 284 /* CDP<c> <coproc>,<opc1>,<CRd>,<CRn>,<CRm>,<opc2> */
222 int CoProc = BITS (8, 11); /* 10 or 11 */ 285 int CoProc = BITS (8, 11); /* 10 or 11 */
@@ -275,10 +338,83 @@ VFPCDP (ARMul_State * state, unsigned type, u32 instr)
275 338
276 /* CRn/opc1 CRm/opc2 */ 339 /* CRn/opc1 CRm/opc2 */
277 340
278 if (CoProc == 10 || CoProc == 11) { 341 if (CoProc == 10 || CoProc == 11)
279#define VFP_CDP_TRANS 342 {
280#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 343 if ((OPC_1 & 0xB) == 0 && (OPC_2 & 0x2) == 0)
281#undef VFP_CDP_TRANS 344 DBG("VMLA :\n");
345
346 if ((OPC_1 & 0xB) == 0 && (OPC_2 & 0x2) == 2)
347 DBG("VMLS :\n");
348
349 if ((OPC_1 & 0xB) == 1 && (OPC_2 & 0x2) == 2)
350 DBG("VNMLA :\n");
351
352 if ((OPC_1 & 0xB) == 1 && (OPC_2 & 0x2) == 0)
353 DBG("VNMLS :\n");
354
355 if ((OPC_1 & 0xB) == 2 && (OPC_2 & 0x2) == 2)
356 DBG("VNMUL :\n");
357
358 if ((OPC_1 & 0xB) == 2 && (OPC_2 & 0x2) == 0)
359 DBG("VMUL :\n");
360
361 if ((OPC_1 & 0xB) == 3 && (OPC_2 & 0x2) == 0)
362 DBG("VADD :\n");
363
364 if ((OPC_1 & 0xB) == 3 && (OPC_2 & 0x2) == 2)
365 DBG("VSUB :\n");
366
367 if ((OPC_1 & 0xB) == 0xA && (OPC_2 & 0x2) == 0)
368 DBG("VDIV :\n");
369
370 if ((OPC_1 & 0xB) == 0xB && BITS(4, 7) == 0)
371 {
372 unsigned int single = BIT(8) == 0;
373 unsigned int d = (single ? BITS(12,15)<<1 | BIT(22) : BITS(12,15) | BIT(22)<<4);
374 unsigned int imm;
375 instr = BITS(16, 19) << 4 | BITS(0, 3); /* FIXME dirty workaround to get a correct imm */
376
377 if (single)
378 imm = BIT(7)<<31 | (BIT(6)==0)<<30 | (BIT(6) ? 0x1f : 0)<<25 | BITS(0, 5)<<19;
379 else
380 imm = BIT(7)<<31 | (BIT(6)==0)<<30 | (BIT(6) ? 0xff : 0)<<22 | BITS(0, 5)<<16;
381
382 VMOVI(state, single, d, imm);
383 return ARMul_DONE;
384 }
385
386 if ((OPC_1 & 0xB) == 0xB && CRn == 0 && (OPC_2 & 0x6) == 0x2)
387 {
388 unsigned int single = BIT(8) == 0;
389 unsigned int d = (single ? BITS(12,15)<<1 | BIT(22) : BITS(12,15) | BIT(22)<<4);
390 unsigned int m = (single ? BITS( 0, 3)<<1 | BIT( 5) : BITS( 0, 3) | BIT( 5)<<4);;
391 VMOVR(state, single, d, m);
392 return ARMul_DONE;
393 }
394
395 if ((OPC_1 & 0xB) == 0xB && CRn == 0 && (OPC_2 & 0x7) == 6)
396 DBG("VABS :\n");
397
398 if ((OPC_1 & 0xB) == 0xB && CRn == 1 && (OPC_2 & 0x7) == 2)
399 DBG("VNEG :\n");
400
401 if ((OPC_1 & 0xB) == 0xB && CRn == 1 && (OPC_2 & 0x7) == 6)
402 DBG("VSQRT :\n");
403
404 if ((OPC_1 & 0xB) == 0xB && CRn == 4 && (OPC_2 & 0x2) == 2)
405 DBG("VCMP(1) :\n");
406
407 if ((OPC_1 & 0xB) == 0xB && CRn == 5 && (OPC_2 & 0x2) == 2 && CRm == 0)
408 DBG("VCMP(2) :\n");
409
410 if ((OPC_1 & 0xB) == 0xB && CRn == 7 && (OPC_2 & 0x6) == 6)
411 DBG("VCVT(BDS) :\n");
412
413 if ((OPC_1 & 0xB) == 0xB && CRn >= 0xA && (OPC_2 & 0x2) == 2)
414 DBG("VCVT(BFF) :\n");
415
416 if ((OPC_1 & 0xB) == 0xB && CRn > 7 && (OPC_2 & 0x2) == 2)
417 DBG("VCVT(BFI) :\n");
282 418
283 int exceptions = 0; 419 int exceptions = 0;
284 if (CoProc == 10) 420 if (CoProc == 10)
@@ -296,23 +432,93 @@ VFPCDP (ARMul_State * state, unsigned type, u32 instr)
296 432
297 433
298/* ----------- MRC ------------ */ 434/* ----------- MRC ------------ */
299#define VFP_MRC_IMPL 435void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value)
300#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 436{
301#undef VFP_MRC_IMPL 437 DBG("VMOV(BRS) :\n");
302 438 if (to_arm)
303#define VFP_MRRC_IMPL 439 {
304#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 440 DBG("\tr%d <= s%d=[%x]\n", t, n, state->ExtReg[n]);
305#undef VFP_MRRC_IMPL 441 *value = state->ExtReg[n];
306 442 }
443 else
444 {
445 DBG("\ts%d <= r%d=[%x]\n", n, t, *value);
446 state->ExtReg[n] = *value;
447 }
448}
449void VMRS(ARMul_State* state, ARMword reg, ARMword Rt, ARMword* value)
450{
451 DBG("VMRS :");
452 if (reg == 1)
453 {
454 if (Rt != 15)
455 {
456 *value = state->VFP[VFP_OFFSET(VFP_FPSCR)];
457 DBG("\tr%d <= fpscr[%08x]\n", Rt, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
458 }
459 else
460 {
461 *value = state->VFP[VFP_OFFSET(VFP_FPSCR)] ;
462 DBG("\tflags <= fpscr[%1xxxxxxxx]\n", state->VFP[VFP_OFFSET(VFP_FPSCR)]>>28);
463 }
464 }
465 else
466 {
467 switch (reg)
468 {
469 case 0:
470 *value = state->VFP[VFP_OFFSET(VFP_FPSID)];
471 DBG("\tr%d <= fpsid[%08x]\n", Rt, state->VFP[VFP_OFFSET(VFP_FPSID)]);
472 break;
473 case 6:
474 /* MVFR1, VFPv3 only ? */
475 DBG("\tr%d <= MVFR1 unimplemented\n", Rt);
476 break;
477 case 7:
478 /* MVFR0, VFPv3 only? */
479 DBG("\tr%d <= MVFR0 unimplemented\n", Rt);
480 break;
481 case 8:
482 *value = state->VFP[VFP_OFFSET(VFP_FPEXC)];
483 DBG("\tr%d <= fpexc[%08x]\n", Rt, state->VFP[VFP_OFFSET(VFP_FPEXC)]);
484 break;
485 default:
486 DBG("\tSUBARCHITECTURE DEFINED\n");
487 break;
488 }
489 }
490}
491void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2)
492{
493 DBG("VMOV(BRRD) :\n");
494 if (to_arm)
495 {
496 DBG("\tr[%d-%d] <= s[%d-%d]=[%x-%x]\n", t2, t, n*2+1, n*2, state->ExtReg[n*2+1], state->ExtReg[n*2]);
497 *value2 = state->ExtReg[n*2+1];
498 *value1 = state->ExtReg[n*2];
499 }
500 else
501 {
502 DBG("\ts[%d-%d] <= r[%d-%d]=[%x-%x]\n", n*2+1, n*2, t2, t, *value2, *value1);
503 state->ExtReg[n*2+1] = *value2;
504 state->ExtReg[n*2] = *value1;
505 }
506}
307 507
308/* ----------- MCR ------------ */ 508/* ----------- MCR ------------ */
309#define VFP_MCR_IMPL 509void VMSR(ARMul_State* state, ARMword reg, ARMword Rt)
310#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 510{
311#undef VFP_MCR_IMPL 511 if (reg == 1)
312 512 {
313#define VFP_MCRR_IMPL 513 DBG("VMSR :\tfpscr <= r%d=[%x]\n", Rt, state->Reg[Rt]);
314#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 514 state->VFP[VFP_OFFSET(VFP_FPSCR)] = state->Reg[Rt];
315#undef VFP_MCRR_IMPL 515 }
516 else if (reg == 8)
517 {
518 DBG("VMSR :\tfpexc <= r%d=[%x]\n", Rt, state->Reg[Rt]);
519 state->VFP[VFP_OFFSET(VFP_FPEXC)] = state->Reg[Rt];
520 }
521}
316 522
317/* Memory operation are not inlined, as old Interpreter and Fast interpreter 523/* Memory operation are not inlined, as old Interpreter and Fast interpreter
318 don't have the same memory operation interface. 524 don't have the same memory operation interface.
@@ -322,21 +528,342 @@ VFPCDP (ARMul_State * state, unsigned type, u32 instr)
322 of vfp instructions in old interpreter and fast interpreter are separate. */ 528 of vfp instructions in old interpreter and fast interpreter are separate. */
323 529
324/* ----------- STC ------------ */ 530/* ----------- STC ------------ */
325#define VFP_STC_IMPL 531int VSTR(ARMul_State* state, int type, ARMword instr, ARMword* value)
326#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 532{
327#undef VFP_STC_IMPL 533 static int i = 0;
534 static int single_reg, add, d, n, imm32, regs;
535 if (type == ARMul_FIRST)
536 {
537 single_reg = BIT(8) == 0; /* Double precision */
538 add = BIT(23); /* */
539 imm32 = BITS(0,7)<<2; /* may not be used */
540 d = single_reg ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */
541 n = BITS(16, 19); /* destination register */
328 542
543 DBG("VSTR :\n");
544
545 i = 0;
546 regs = 1;
547
548 return ARMul_DONE;
549 }
550 else if (type == ARMul_DATA)
551 {
552 if (single_reg)
553 {
554 *value = state->ExtReg[d+i];
555 DBG("\taddr[?] <= s%d=[%x]\n", d+i, state->ExtReg[d+i]);
556 i++;
557 if (i < regs)
558 return ARMul_INC;
559 else
560 return ARMul_DONE;
561 }
562 else
563 {
564 /* FIXME Careful of endianness, may need to rework this */
565 *value = state->ExtReg[d*2+i];
566 DBG("\taddr[?] <= s[%d]=[%x]\n", d*2+i, state->ExtReg[d*2+i]);
567 i++;
568 if (i < regs*2)
569 return ARMul_INC;
570 else
571 return ARMul_DONE;
572 }
573 }
574
575 return -1;
576}
577int VPUSH(ARMul_State* state, int type, ARMword instr, ARMword* value)
578{
579 static int i = 0;
580 static int single_regs, add, wback, d, n, imm32, regs;
581 if (type == ARMul_FIRST)
582 {
583 single_regs = BIT(8) == 0; /* Single precision */
584 d = single_regs ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */
585 imm32 = BITS(0,7)<<2; /* may not be used */
586 regs = single_regs ? BITS(0, 7) : BITS(1, 7); /* FSTMX if regs is odd */
587
588 DBG("VPUSH :\n");
589 DBG("\tsp[%x]", state->Reg[R13]);
590 state->Reg[R13] = state->Reg[R13] - imm32;
591 DBG("=>[%x]\n", state->Reg[R13]);
592
593 i = 0;
594
595 return ARMul_DONE;
596 }
597 else if (type == ARMul_DATA)
598 {
599 if (single_regs)
600 {
601 *value = state->ExtReg[d + i];
602 DBG("\taddr[?] <= s%d=[%x]\n", d+i, state->ExtReg[d + i]);
603 i++;
604 if (i < regs)
605 return ARMul_INC;
606 else
607 return ARMul_DONE;
608 }
609 else
610 {
611 /* FIXME Careful of endianness, may need to rework this */
612 *value = state->ExtReg[d*2 + i];
613 DBG("\taddr[?] <= s[%d]=[%x]\n", d*2 + i, state->ExtReg[d*2 + i]);
614 i++;
615 if (i < regs*2)
616 return ARMul_INC;
617 else
618 return ARMul_DONE;
619 }
620 }
621
622 return -1;
623}
624int VSTM(ARMul_State* state, int type, ARMword instr, ARMword* value)
625{
626 static int i = 0;
627 static int single_regs, add, wback, d, n, imm32, regs;
628 if (type == ARMul_FIRST)
629 {
630 single_regs = BIT(8) == 0; /* Single precision */
631 add = BIT(23); /* */
632 wback = BIT(21); /* write-back */
633 d = single_regs ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */
634 n = BITS(16, 19); /* destination register */
635 imm32 = BITS(0,7) * 4; /* may not be used */
636 regs = single_regs ? BITS(0, 7) : BITS(0, 7)>>1; /* FSTMX if regs is odd */
637
638 DBG("VSTM :\n");
639
640 if (wback) {
641 state->Reg[n] = (add ? state->Reg[n] + imm32 : state->Reg[n] - imm32);
642 DBG("\twback r%d[%x]\n", n, state->Reg[n]);
643 }
644
645 i = 0;
646
647 return ARMul_DONE;
648 }
649 else if (type == ARMul_DATA)
650 {
651 if (single_regs)
652 {
653 *value = state->ExtReg[d + i];
654 DBG("\taddr[?] <= s%d=[%x]\n", d+i, state->ExtReg[d + i]);
655 i++;
656 if (i < regs)
657 return ARMul_INC;
658 else
659 return ARMul_DONE;
660 }
661 else
662 {
663 /* FIXME Careful of endianness, may need to rework this */
664 *value = state->ExtReg[d*2 + i];
665 DBG("\taddr[?] <= s[%d]=[%x]\n", d*2 + i, state->ExtReg[d*2 + i]);
666 i++;
667 if (i < regs*2)
668 return ARMul_INC;
669 else
670 return ARMul_DONE;
671 }
672 }
673
674 return -1;
675}
329 676
330/* ----------- LDC ------------ */ 677/* ----------- LDC ------------ */
331#define VFP_LDC_IMPL 678int VPOP(ARMul_State* state, int type, ARMword instr, ARMword value)
332#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 679{
333#undef VFP_LDC_IMPL 680 static int i = 0;
681 static int single_regs, add, wback, d, n, imm32, regs;
682 if (type == ARMul_FIRST)
683 {
684 single_regs = BIT(8) == 0; /* Single precision */
685 d = single_regs ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */
686 imm32 = BITS(0,7)<<2; /* may not be used */
687 regs = single_regs ? BITS(0, 7) : BITS(1, 7); /* FLDMX if regs is odd */
334 688
689 DBG("VPOP :\n");
690 DBG("\tsp[%x]", state->Reg[R13]);
691 state->Reg[R13] = state->Reg[R13] + imm32;
692 DBG("=>[%x]\n", state->Reg[R13]);
693
694 i = 0;
695
696 return ARMul_DONE;
697 }
698 else if (type == ARMul_TRANSFER)
699 {
700 return ARMul_DONE;
701 }
702 else if (type == ARMul_DATA)
703 {
704 if (single_regs)
705 {
706 state->ExtReg[d + i] = value;
707 DBG("\ts%d <= [%x]\n", d + i, value);
708 i++;
709 if (i < regs)
710 return ARMul_INC;
711 else
712 return ARMul_DONE;
713 }
714 else
715 {
716 /* FIXME Careful of endianness, may need to rework this */
717 state->ExtReg[d*2 + i] = value;
718 DBG("\ts%d <= [%x]\n", d*2 + i, value);
719 i++;
720 if (i < regs*2)
721 return ARMul_INC;
722 else
723 return ARMul_DONE;
724 }
725 }
726
727 return -1;
728}
729int VLDR(ARMul_State* state, int type, ARMword instr, ARMword value)
730{
731 static int i = 0;
732 static int single_reg, add, d, n, imm32, regs;
733 if (type == ARMul_FIRST)
734 {
735 single_reg = BIT(8) == 0; /* Double precision */
736 add = BIT(23); /* */
737 imm32 = BITS(0,7)<<2; /* may not be used */
738 d = single_reg ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */
739 n = BITS(16, 19); /* destination register */
740
741 DBG("VLDR :\n");
742
743 i = 0;
744 regs = 1;
745
746 return ARMul_DONE;
747 }
748 else if (type == ARMul_TRANSFER)
749 {
750 return ARMul_DONE;
751 }
752 else if (type == ARMul_DATA)
753 {
754 if (single_reg)
755 {
756 state->ExtReg[d+i] = value;
757 DBG("\ts%d <= [%x]\n", d+i, value);
758 i++;
759 if (i < regs)
760 return ARMul_INC;
761 else
762 return ARMul_DONE;
763 }
764 else
765 {
766 /* FIXME Careful of endianness, may need to rework this */
767 state->ExtReg[d*2+i] = value;
768 DBG("\ts[%d] <= [%x]\n", d*2+i, value);
769 i++;
770 if (i < regs*2)
771 return ARMul_INC;
772 else
773 return ARMul_DONE;
774 }
775 }
776
777 return -1;
778}
779int VLDM(ARMul_State* state, int type, ARMword instr, ARMword value)
780{
781 static int i = 0;
782 static int single_regs, add, wback, d, n, imm32, regs;
783 if (type == ARMul_FIRST)
784 {
785 single_regs = BIT(8) == 0; /* Single precision */
786 add = BIT(23); /* */
787 wback = BIT(21); /* write-back */
788 d = single_regs ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */
789 n = BITS(16, 19); /* destination register */
790 imm32 = BITS(0,7) * 4; /* may not be used */
791 regs = single_regs ? BITS(0, 7) : BITS(0, 7)>>1; /* FLDMX if regs is odd */
792
793 DBG("VLDM :\n");
794
795 if (wback) {
796 state->Reg[n] = (add ? state->Reg[n] + imm32 : state->Reg[n] - imm32);
797 DBG("\twback r%d[%x]\n", n, state->Reg[n]);
798 }
799
800 i = 0;
801
802 return ARMul_DONE;
803 }
804 else if (type == ARMul_DATA)
805 {
806 if (single_regs)
807 {
808 state->ExtReg[d + i] = value;
809 DBG("\ts%d <= [%x] addr[?]\n", d+i, state->ExtReg[d + i]);
810 i++;
811 if (i < regs)
812 return ARMul_INC;
813 else
814 return ARMul_DONE;
815 }
816 else
817 {
818 /* FIXME Careful of endianness, may need to rework this */
819 state->ExtReg[d*2 + i] = value;
820 DBG("\ts[%d] <= [%x] addr[?]\n", d*2 + i, state->ExtReg[d*2 + i]);
821 i++;
822 if (i < regs*2)
823 return ARMul_INC;
824 else
825 return ARMul_DONE;
826 }
827 }
828
829 return -1;
830}
335 831
336/* ----------- CDP ------------ */ 832/* ----------- CDP ------------ */
337#define VFP_CDP_IMPL 833void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm)
338#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 834{
339#undef VFP_CDP_IMPL 835 DBG("VMOV(I) :\n");
836
837 if (single)
838 {
839 DBG("\ts%d <= [%x]\n", d, imm);
840 state->ExtReg[d] = imm;
841 }
842 else
843 {
844 /* Check endian please */
845 DBG("\ts[%d-%d] <= [%x-%x]\n", d*2+1, d*2, imm, 0);
846 state->ExtReg[d*2+1] = imm;
847 state->ExtReg[d*2] = 0;
848 }
849}
850void VMOVR(ARMul_State* state, ARMword single, ARMword d, ARMword m)
851{
852 DBG("VMOV(R) :\n");
853
854 if (single)
855 {
856 DBG("\ts%d <= s%d[%x]\n", d, m, state->ExtReg[m]);
857 state->ExtReg[d] = state->ExtReg[m];
858 }
859 else
860 {
861 /* Check endian please */
862 DBG("\ts[%d-%d] <= s[%d-%d][%x-%x]\n", d*2+1, d*2, m*2+1, m*2, state->ExtReg[m*2+1], state->ExtReg[m*2]);
863 state->ExtReg[d*2+1] = state->ExtReg[m*2+1];
864 state->ExtReg[d*2] = state->ExtReg[m*2];
865 }
866}
340 867
341/* Miscellaneous functions */ 868/* Miscellaneous functions */
342int32_t vfp_get_float(arm_core_t* state, unsigned int reg) 869int32_t vfp_get_float(arm_core_t* state, unsigned int reg)
@@ -366,8 +893,6 @@ void vfp_put_double(arm_core_t* state, uint64_t val, unsigned int reg)
366 state->ExtReg[reg*2+1] = (uint32_t) (val>>32); 893 state->ExtReg[reg*2+1] = (uint32_t) (val>>32);
367} 894}
368 895
369
370
371/* 896/*
372 * Process bitmask of exception conditions. (from vfpmodule.c) 897 * Process bitmask of exception conditions. (from vfpmodule.c)
373 */ 898 */
diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h
index 7256701f3..f9e8d521d 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.h
+++ b/src/core/arm/skyeye_common/vfp/vfp.h
@@ -27,6 +27,12 @@
27 27
28#include "core/arm/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */ 28#include "core/arm/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */
29 29
30#define VFP_DEBUG_TRANSLATE DBG("in func %s, %x\n", __FUNCTION__, inst);
31#define VFP_DEBUG_UNIMPLEMENTED(x) printf("in func %s, " #x " unimplemented\n", __FUNCTION__); exit(-1);
32#define VFP_DEBUG_UNTESTED(x) printf("in func %s, " #x " untested\n", __FUNCTION__);
33#define CHECK_VFP_ENABLED
34#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]); //if (ret == -1) {printf("VFP CDP FAILURE %x\n", inst_cream->instr); exit(-1);}
35
30unsigned VFPInit (ARMul_State *state); 36unsigned VFPInit (ARMul_State *state);
31unsigned VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value); 37unsigned VFPMRC (ARMul_State * state, unsigned type, ARMword instr, ARMword * value);
32unsigned VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value); 38unsigned VFPMCR (ARMul_State * state, unsigned type, ARMword instr, ARMword value);
diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
index 45208fb13..27dc8a008 100644
--- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
@@ -28,34 +28,19 @@
28/* ----------------------------------------------------------------------- */ 28/* ----------------------------------------------------------------------- */
29/* VMLA */ 29/* VMLA */
30/* cond 1110 0D00 Vn-- Vd-- 101X N0M0 Vm-- */ 30/* cond 1110 0D00 Vn-- Vd-- 101X N0M0 Vm-- */
31#define vfpinstr vmla
32#define vfpinstr_inst vmla_inst
33#define VFPLABEL_INST VMLA_INST
34#ifdef VFP_DECODE
35{"vmla", 4, ARMVFP2, 23, 27, 0x1c, 20, 21, 0x0, 9, 11, 0x5, 4, 4, 0},
36#endif
37#ifdef VFP_DECODE_EXCLUSION
38{"vmla", 0, ARMVFP2, 0},
39#endif
40#ifdef VFP_INTERPRETER_TABLE
41INTERPRETER_TRANSLATE(vfpinstr),
42#endif
43#ifdef VFP_INTERPRETER_LABEL
44&&VFPLABEL_INST,
45#endif
46#ifdef VFP_INTERPRETER_STRUCT 31#ifdef VFP_INTERPRETER_STRUCT
47typedef struct _vmla_inst { 32typedef struct _vmla_inst {
48 unsigned int instr; 33 unsigned int instr;
49 unsigned int dp_operation; 34 unsigned int dp_operation;
50} vfpinstr_inst; 35} vmla_inst;
51#endif 36#endif
52#ifdef VFP_INTERPRETER_TRANS 37#ifdef VFP_INTERPRETER_TRANS
53ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 38ARM_INST_PTR INTERPRETER_TRANSLATE(vmla)(unsigned int inst, int index)
54{ 39{
55 VFP_DEBUG_TRANSLATE; 40 VFP_DEBUG_TRANSLATE;
56 41
57 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 42 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vmla_inst));
58 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 43 vmla_inst *inst_cream = (vmla_inst *)inst_base->component;
59 44
60 inst_base->cond = BITS(inst, 28, 31); 45 inst_base->cond = BITS(inst, 28, 31);
61 inst_base->idx = index; 46 inst_base->idx = index;
@@ -69,15 +54,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
69} 54}
70#endif 55#endif
71#ifdef VFP_INTERPRETER_IMPL 56#ifdef VFP_INTERPRETER_IMPL
72VFPLABEL_INST: 57VMLA_INST:
73{ 58{
74 INC_ICOUNTER;
75 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 59 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
76 CHECK_VFP_ENABLED; 60 CHECK_VFP_ENABLED;
77 61
78 DBG("VMLA :\n"); 62 DBG("VMLA :\n");
79 63
80 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 64 vmla_inst *inst_cream = (vmla_inst *)inst_base->component;
81 65
82 int ret; 66 int ret;
83 67
@@ -89,22 +73,17 @@ VFPLABEL_INST:
89 CHECK_VFP_CDP_RET; 73 CHECK_VFP_CDP_RET;
90 } 74 }
91 cpu->Reg[15] += GET_INST_SIZE(cpu); 75 cpu->Reg[15] += GET_INST_SIZE(cpu);
92 INC_PC(sizeof(vfpinstr_inst)); 76 INC_PC(sizeof(vmla_inst));
93 FETCH_INST; 77 FETCH_INST;
94 GOTO_NEXT_INST; 78 GOTO_NEXT_INST;
95} 79}
96#endif 80#endif
97#ifdef VFP_CDP_TRANS 81
98if ((OPC_1 & 0xB) == 0 && (OPC_2 & 0x2) == 0)
99{
100 DBG("VMLA :\n");
101}
102#endif
103#ifdef VFP_DYNCOM_TABLE 82#ifdef VFP_DYNCOM_TABLE
104DYNCOM_FILL_ACTION(vfpinstr), 83DYNCOM_FILL_ACTION(vmla),
105#endif 84#endif
106#ifdef VFP_DYNCOM_TAG 85#ifdef VFP_DYNCOM_TAG
107int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 86int DYNCOM_TAG(vmla)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
108{ 87{
109 int instr_size = INSTR_SIZE; 88 int instr_size = INSTR_SIZE;
110 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 89 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -114,7 +93,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
114} 93}
115#endif 94#endif
116#ifdef VFP_DYNCOM_TRANS 95#ifdef VFP_DYNCOM_TRANS
117int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 96int DYNCOM_TRANS(vmla)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
118 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 97 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
119 //arch_arm_undef(cpu, bb, instr); 98 //arch_arm_undef(cpu, bb, instr);
120 int m; 99 int m;
@@ -168,41 +147,23 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
168 return No_exp; 147 return No_exp;
169} 148}
170#endif 149#endif
171#undef vfpinstr
172#undef vfpinstr_inst
173#undef VFPLABEL_INST
174 150
175/* ----------------------------------------------------------------------- */ 151/* ----------------------------------------------------------------------- */
176/* VNMLS */ 152/* VNMLS */
177/* cond 1110 0D00 Vn-- Vd-- 101X N1M0 Vm-- */ 153/* cond 1110 0D00 Vn-- Vd-- 101X N1M0 Vm-- */
178#define vfpinstr vmls
179#define vfpinstr_inst vmls_inst
180#define VFPLABEL_INST VMLS_INST
181#ifdef VFP_DECODE
182{"vmls", 7, ARMVFP2, 28 , 31, 0xF, 25, 27, 0x1, 23, 23, 1, 11, 11, 0, 8, 9, 0x2, 6, 6, 1, 4, 4, 0},
183#endif
184#ifdef VFP_DECODE_EXCLUSION
185{"vmls", 0, ARMVFP2, 0},
186#endif
187#ifdef VFP_INTERPRETER_TABLE
188INTERPRETER_TRANSLATE(vfpinstr),
189#endif
190#ifdef VFP_INTERPRETER_LABEL
191&&VFPLABEL_INST,
192#endif
193#ifdef VFP_INTERPRETER_STRUCT 154#ifdef VFP_INTERPRETER_STRUCT
194typedef struct _vmls_inst { 155typedef struct _vmls_inst {
195 unsigned int instr; 156 unsigned int instr;
196 unsigned int dp_operation; 157 unsigned int dp_operation;
197} vfpinstr_inst; 158} vmls_inst;
198#endif 159#endif
199#ifdef VFP_INTERPRETER_TRANS 160#ifdef VFP_INTERPRETER_TRANS
200ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 161ARM_INST_PTR INTERPRETER_TRANSLATE(vmls)(unsigned int inst, int index)
201{ 162{
202 VFP_DEBUG_TRANSLATE; 163 VFP_DEBUG_TRANSLATE;
203 164
204 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 165 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vmls_inst));
205 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 166 vmls_inst *inst_cream = (vmls_inst *)inst_base->component;
206 167
207 inst_base->cond = BITS(inst, 28, 31); 168 inst_base->cond = BITS(inst, 28, 31);
208 inst_base->idx = index; 169 inst_base->idx = index;
@@ -216,15 +177,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
216} 177}
217#endif 178#endif
218#ifdef VFP_INTERPRETER_IMPL 179#ifdef VFP_INTERPRETER_IMPL
219VFPLABEL_INST: 180VMLS_INST:
220{ 181{
221 INC_ICOUNTER;
222 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 182 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
223 CHECK_VFP_ENABLED; 183 CHECK_VFP_ENABLED;
224 184
225 DBG("VMLS :\n"); 185 DBG("VMLS :\n");
226 186
227 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 187 vmls_inst *inst_cream = (vmls_inst *)inst_base->component;
228 188
229 int ret; 189 int ret;
230 190
@@ -236,22 +196,17 @@ VFPLABEL_INST:
236 CHECK_VFP_CDP_RET; 196 CHECK_VFP_CDP_RET;
237 } 197 }
238 cpu->Reg[15] += GET_INST_SIZE(cpu); 198 cpu->Reg[15] += GET_INST_SIZE(cpu);
239 INC_PC(sizeof(vfpinstr_inst)); 199 INC_PC(sizeof(vmls_inst));
240 FETCH_INST; 200 FETCH_INST;
241 GOTO_NEXT_INST; 201 GOTO_NEXT_INST;
242} 202}
243#endif 203#endif
244#ifdef VFP_CDP_TRANS 204
245if ((OPC_1 & 0xB) == 0 && (OPC_2 & 0x2) == 2)
246{
247 DBG("VMLS :\n");
248}
249#endif
250#ifdef VFP_DYNCOM_TABLE 205#ifdef VFP_DYNCOM_TABLE
251DYNCOM_FILL_ACTION(vfpinstr), 206DYNCOM_FILL_ACTION(vmls),
252#endif 207#endif
253#ifdef VFP_DYNCOM_TAG 208#ifdef VFP_DYNCOM_TAG
254int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 209int DYNCOM_TAG(vmls)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
255{ 210{
256 int instr_size = INSTR_SIZE; 211 int instr_size = INSTR_SIZE;
257 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 212 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -261,7 +216,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
261} 216}
262#endif 217#endif
263#ifdef VFP_DYNCOM_TRANS 218#ifdef VFP_DYNCOM_TRANS
264int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 219int DYNCOM_TRANS(vmls)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
265 DBG("\t\tin %s VMLS instruction is executed out of here.\n", __FUNCTION__); 220 DBG("\t\tin %s VMLS instruction is executed out of here.\n", __FUNCTION__);
266 //arch_arm_undef(cpu, bb, instr); 221 //arch_arm_undef(cpu, bb, instr);
267 int m; 222 int m;
@@ -315,47 +270,23 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
315 return No_exp; 270 return No_exp;
316} 271}
317#endif 272#endif
318#undef vfpinstr
319#undef vfpinstr_inst
320#undef VFPLABEL_INST
321 273
322/* ----------------------------------------------------------------------- */ 274/* ----------------------------------------------------------------------- */
323/* VNMLA */ 275/* VNMLA */
324/* cond 1110 0D01 Vn-- Vd-- 101X N1M0 Vm-- */ 276/* cond 1110 0D01 Vn-- Vd-- 101X N1M0 Vm-- */
325#define vfpinstr vnmla
326#define vfpinstr_inst vnmla_inst
327#define VFPLABEL_INST VNMLA_INST
328#ifdef VFP_DECODE
329//{"vnmla", 5, ARMVFP2, 23, 27, 0x1c, 20, 21, 0x0, 9, 11, 0x5, 6, 6, 1, 4, 4, 0},
330{"vnmla", 4, ARMVFP2, 23, 27, 0x1c, 20, 21, 0x1, 9, 11, 0x5, 4, 4, 0},
331{"vnmla", 5, ARMVFP2, 23, 27, 0x1c, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 1, 4, 4, 0},
332//{"vnmla", 5, ARMVFP2, 23, 27, 0x1c, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 1, 4, 4, 0},
333#endif
334#ifdef VFP_DECODE_EXCLUSION
335{"vnmla", 0, ARMVFP2, 0},
336{"vnmla", 0, ARMVFP2, 0},
337#endif
338#ifdef VFP_INTERPRETER_TABLE
339INTERPRETER_TRANSLATE(vfpinstr),
340INTERPRETER_TRANSLATE(vfpinstr),
341#endif
342#ifdef VFP_INTERPRETER_LABEL
343&&VFPLABEL_INST,
344&&VFPLABEL_INST,
345#endif
346#ifdef VFP_INTERPRETER_STRUCT 277#ifdef VFP_INTERPRETER_STRUCT
347typedef struct _vnmla_inst { 278typedef struct _vnmla_inst {
348 unsigned int instr; 279 unsigned int instr;
349 unsigned int dp_operation; 280 unsigned int dp_operation;
350} vfpinstr_inst; 281} vnmla_inst;
351#endif 282#endif
352#ifdef VFP_INTERPRETER_TRANS 283#ifdef VFP_INTERPRETER_TRANS
353ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 284ARM_INST_PTR INTERPRETER_TRANSLATE(vnmla)(unsigned int inst, int index)
354{ 285{
355 VFP_DEBUG_TRANSLATE; 286 VFP_DEBUG_TRANSLATE;
356 287
357 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 288 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vnmla_inst));
358 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 289 vnmla_inst *inst_cream = (vnmla_inst *)inst_base->component;
359 290
360 inst_base->cond = BITS(inst, 28, 31); 291 inst_base->cond = BITS(inst, 28, 31);
361 inst_base->idx = index; 292 inst_base->idx = index;
@@ -369,15 +300,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
369} 300}
370#endif 301#endif
371#ifdef VFP_INTERPRETER_IMPL 302#ifdef VFP_INTERPRETER_IMPL
372VFPLABEL_INST: 303VNMLA_INST:
373{ 304{
374 INC_ICOUNTER;
375 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 305 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
376 CHECK_VFP_ENABLED; 306 CHECK_VFP_ENABLED;
377 307
378 DBG("VNMLA :\n"); 308 DBG("VNMLA :\n");
379 309
380 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 310 vnmla_inst *inst_cream = (vnmla_inst *)inst_base->component;
381 311
382 int ret; 312 int ret;
383 313
@@ -389,23 +319,18 @@ VFPLABEL_INST:
389 CHECK_VFP_CDP_RET; 319 CHECK_VFP_CDP_RET;
390 } 320 }
391 cpu->Reg[15] += GET_INST_SIZE(cpu); 321 cpu->Reg[15] += GET_INST_SIZE(cpu);
392 INC_PC(sizeof(vfpinstr_inst)); 322 INC_PC(sizeof(vnmla_inst));
393 FETCH_INST; 323 FETCH_INST;
394 GOTO_NEXT_INST; 324 GOTO_NEXT_INST;
395} 325}
396#endif 326#endif
397#ifdef VFP_CDP_TRANS 327
398if ((OPC_1 & 0xB) == 1 && (OPC_2 & 0x2) == 2)
399{
400 DBG("VNMLA :\n");
401}
402#endif
403#ifdef VFP_DYNCOM_TABLE 328#ifdef VFP_DYNCOM_TABLE
404DYNCOM_FILL_ACTION(vfpinstr), 329DYNCOM_FILL_ACTION(vnmla),
405DYNCOM_FILL_ACTION(vfpinstr), 330DYNCOM_FILL_ACTION(vnmla),
406#endif 331#endif
407#ifdef VFP_DYNCOM_TAG 332#ifdef VFP_DYNCOM_TAG
408int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 333int DYNCOM_TAG(vnmla)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
409{ 334{
410 int instr_size = INSTR_SIZE; 335 int instr_size = INSTR_SIZE;
411 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 336 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -415,7 +340,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
415} 340}
416#endif 341#endif
417#ifdef VFP_DYNCOM_TRANS 342#ifdef VFP_DYNCOM_TRANS
418int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 343int DYNCOM_TRANS(vnmla)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
419 DBG("\t\tin %s VNMLA instruction is executed out of here.\n", __FUNCTION__); 344 DBG("\t\tin %s VNMLA instruction is executed out of here.\n", __FUNCTION__);
420 //arch_arm_undef(cpu, bb, instr); 345 //arch_arm_undef(cpu, bb, instr);
421 int m; 346 int m;
@@ -469,41 +394,24 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
469 return No_exp; 394 return No_exp;
470} 395}
471#endif 396#endif
472#undef vfpinstr
473#undef vfpinstr_inst
474#undef VFPLABEL_INST
475 397
476/* ----------------------------------------------------------------------- */ 398/* ----------------------------------------------------------------------- */
477/* VNMLS */ 399/* VNMLS */
478/* cond 1110 0D01 Vn-- Vd-- 101X N0M0 Vm-- */ 400/* cond 1110 0D01 Vn-- Vd-- 101X N0M0 Vm-- */
479#define vfpinstr vnmls 401
480#define vfpinstr_inst vnmls_inst
481#define VFPLABEL_INST VNMLS_INST
482#ifdef VFP_DECODE
483{"vnmls", 5, ARMVFP2, 23, 27, 0x1c, 20, 21, 0x1, 9, 11, 0x5, 6, 6, 0, 4, 4, 0},
484#endif
485#ifdef VFP_DECODE_EXCLUSION
486{"vnmls", 0, ARMVFP2, 0},
487#endif
488#ifdef VFP_INTERPRETER_TABLE
489INTERPRETER_TRANSLATE(vfpinstr),
490#endif
491#ifdef VFP_INTERPRETER_LABEL
492&&VFPLABEL_INST,
493#endif
494#ifdef VFP_INTERPRETER_STRUCT 402#ifdef VFP_INTERPRETER_STRUCT
495typedef struct _vnmls_inst { 403typedef struct _vnmls_inst {
496 unsigned int instr; 404 unsigned int instr;
497 unsigned int dp_operation; 405 unsigned int dp_operation;
498} vfpinstr_inst; 406} vnmls_inst;
499#endif 407#endif
500#ifdef VFP_INTERPRETER_TRANS 408#ifdef VFP_INTERPRETER_TRANS
501ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 409ARM_INST_PTR INTERPRETER_TRANSLATE(vnmls)(unsigned int inst, int index)
502{ 410{
503 VFP_DEBUG_TRANSLATE; 411 VFP_DEBUG_TRANSLATE;
504 412
505 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 413 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vnmls_inst));
506 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 414 vnmls_inst *inst_cream = (vnmls_inst *)inst_base->component;
507 415
508 inst_base->cond = BITS(inst, 28, 31); 416 inst_base->cond = BITS(inst, 28, 31);
509 inst_base->idx = index; 417 inst_base->idx = index;
@@ -517,15 +425,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
517} 425}
518#endif 426#endif
519#ifdef VFP_INTERPRETER_IMPL 427#ifdef VFP_INTERPRETER_IMPL
520VFPLABEL_INST: 428VNMLS_INST:
521{ 429{
522 INC_ICOUNTER;
523 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 430 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
524 CHECK_VFP_ENABLED; 431 CHECK_VFP_ENABLED;
525 432
526 DBG("VNMLS :\n"); 433 DBG("VNMLS :\n");
527 434
528 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 435 vnmls_inst *inst_cream = (vnmls_inst *)inst_base->component;
529 436
530 int ret; 437 int ret;
531 438
@@ -537,22 +444,17 @@ VFPLABEL_INST:
537 CHECK_VFP_CDP_RET; 444 CHECK_VFP_CDP_RET;
538 } 445 }
539 cpu->Reg[15] += GET_INST_SIZE(cpu); 446 cpu->Reg[15] += GET_INST_SIZE(cpu);
540 INC_PC(sizeof(vfpinstr_inst)); 447 INC_PC(sizeof(vnmls_inst));
541 FETCH_INST; 448 FETCH_INST;
542 GOTO_NEXT_INST; 449 GOTO_NEXT_INST;
543} 450}
544#endif 451#endif
545#ifdef VFP_CDP_TRANS 452
546if ((OPC_1 & 0xB) == 1 && (OPC_2 & 0x2) == 0)
547{
548 DBG("VNMLS :\n");
549}
550#endif
551#ifdef VFP_DYNCOM_TABLE 453#ifdef VFP_DYNCOM_TABLE
552DYNCOM_FILL_ACTION(vfpinstr), 454DYNCOM_FILL_ACTION(vnmls),
553#endif 455#endif
554#ifdef VFP_DYNCOM_TAG 456#ifdef VFP_DYNCOM_TAG
555int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 457int DYNCOM_TAG(vnmls)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
556{ 458{
557 int instr_size = INSTR_SIZE; 459 int instr_size = INSTR_SIZE;
558 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 460 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -562,7 +464,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
562} 464}
563#endif 465#endif
564#ifdef VFP_DYNCOM_TRANS 466#ifdef VFP_DYNCOM_TRANS
565int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 467int DYNCOM_TRANS(vnmls)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
566 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 468 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
567 //arch_arm_undef(cpu, bb, instr); 469 //arch_arm_undef(cpu, bb, instr);
568 int m; 470 int m;
@@ -616,41 +518,23 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
616 return No_exp; 518 return No_exp;
617} 519}
618#endif 520#endif
619#undef vfpinstr
620#undef vfpinstr_inst
621#undef VFPLABEL_INST
622 521
623/* ----------------------------------------------------------------------- */ 522/* ----------------------------------------------------------------------- */
624/* VNMUL */ 523/* VNMUL */
625/* cond 1110 0D10 Vn-- Vd-- 101X N0M0 Vm-- */ 524/* cond 1110 0D10 Vn-- Vd-- 101X N0M0 Vm-- */
626#define vfpinstr vnmul
627#define vfpinstr_inst vnmul_inst
628#define VFPLABEL_INST VNMUL_INST
629#ifdef VFP_DECODE
630{"vnmul", 5, ARMVFP2, 23, 27, 0x1c, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 1, 4, 4, 0},
631#endif
632#ifdef VFP_DECODE_EXCLUSION
633{"vnmul", 0, ARMVFP2, 0},
634#endif
635#ifdef VFP_INTERPRETER_TABLE
636INTERPRETER_TRANSLATE(vfpinstr),
637#endif
638#ifdef VFP_INTERPRETER_LABEL
639&&VFPLABEL_INST,
640#endif
641#ifdef VFP_INTERPRETER_STRUCT 525#ifdef VFP_INTERPRETER_STRUCT
642typedef struct _vnmul_inst { 526typedef struct _vnmul_inst {
643 unsigned int instr; 527 unsigned int instr;
644 unsigned int dp_operation; 528 unsigned int dp_operation;
645} vfpinstr_inst; 529} vnmul_inst;
646#endif 530#endif
647#ifdef VFP_INTERPRETER_TRANS 531#ifdef VFP_INTERPRETER_TRANS
648ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 532ARM_INST_PTR INTERPRETER_TRANSLATE(vnmul)(unsigned int inst, int index)
649{ 533{
650 VFP_DEBUG_TRANSLATE; 534 VFP_DEBUG_TRANSLATE;
651 535
652 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 536 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vnmul_inst));
653 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 537 vnmul_inst *inst_cream = (vnmul_inst *)inst_base->component;
654 538
655 inst_base->cond = BITS(inst, 28, 31); 539 inst_base->cond = BITS(inst, 28, 31);
656 inst_base->idx = index; 540 inst_base->idx = index;
@@ -664,15 +548,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
664} 548}
665#endif 549#endif
666#ifdef VFP_INTERPRETER_IMPL 550#ifdef VFP_INTERPRETER_IMPL
667VFPLABEL_INST: 551VNMUL_INST:
668{ 552{
669 INC_ICOUNTER;
670 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 553 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
671 CHECK_VFP_ENABLED; 554 CHECK_VFP_ENABLED;
672 555
673 DBG("VNMUL :\n"); 556 DBG("VNMUL :\n");
674 557
675 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 558 vnmul_inst *inst_cream = (vnmul_inst *)inst_base->component;
676 559
677 int ret; 560 int ret;
678 561
@@ -684,22 +567,17 @@ VFPLABEL_INST:
684 CHECK_VFP_CDP_RET; 567 CHECK_VFP_CDP_RET;
685 } 568 }
686 cpu->Reg[15] += GET_INST_SIZE(cpu); 569 cpu->Reg[15] += GET_INST_SIZE(cpu);
687 INC_PC(sizeof(vfpinstr_inst)); 570 INC_PC(sizeof(vnmul_inst));
688 FETCH_INST; 571 FETCH_INST;
689 GOTO_NEXT_INST; 572 GOTO_NEXT_INST;
690} 573}
691#endif 574#endif
692#ifdef VFP_CDP_TRANS 575
693if ((OPC_1 & 0xB) == 2 && (OPC_2 & 0x2) == 2)
694{
695 DBG("VNMUL :\n");
696}
697#endif
698#ifdef VFP_DYNCOM_TABLE 576#ifdef VFP_DYNCOM_TABLE
699DYNCOM_FILL_ACTION(vfpinstr), 577DYNCOM_FILL_ACTION(vnmul),
700#endif 578#endif
701#ifdef VFP_DYNCOM_TAG 579#ifdef VFP_DYNCOM_TAG
702int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 580int DYNCOM_TAG(vnmul)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
703{ 581{
704 int instr_size = INSTR_SIZE; 582 int instr_size = INSTR_SIZE;
705 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 583 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -709,7 +587,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
709} 587}
710#endif 588#endif
711#ifdef VFP_DYNCOM_TRANS 589#ifdef VFP_DYNCOM_TRANS
712int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 590int DYNCOM_TRANS(vnmul)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
713 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 591 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
714 //arch_arm_undef(cpu, bb, instr); 592 //arch_arm_undef(cpu, bb, instr);
715 int m; 593 int m;
@@ -753,41 +631,24 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
753 return No_exp; 631 return No_exp;
754} 632}
755#endif 633#endif
756#undef vfpinstr 634
757#undef vfpinstr_inst
758#undef VFPLABEL_INST
759 635
760/* ----------------------------------------------------------------------- */ 636/* ----------------------------------------------------------------------- */
761/* VMUL */ 637/* VMUL */
762/* cond 1110 0D10 Vn-- Vd-- 101X N0M0 Vm-- */ 638/* cond 1110 0D10 Vn-- Vd-- 101X N0M0 Vm-- */
763#define vfpinstr vmul
764#define vfpinstr_inst vmul_inst
765#define VFPLABEL_INST VMUL_INST
766#ifdef VFP_DECODE
767{"vmul", 5, ARMVFP2, 23, 27, 0x1c, 20, 21, 0x2, 9, 11, 0x5, 6, 6, 0, 4, 4, 0},
768#endif
769#ifdef VFP_DECODE_EXCLUSION
770{"vmul", 0, ARMVFP2, 0},
771#endif
772#ifdef VFP_INTERPRETER_TABLE
773INTERPRETER_TRANSLATE(vfpinstr),
774#endif
775#ifdef VFP_INTERPRETER_LABEL
776&&VFPLABEL_INST,
777#endif
778#ifdef VFP_INTERPRETER_STRUCT 639#ifdef VFP_INTERPRETER_STRUCT
779typedef struct _vmul_inst { 640typedef struct _vmul_inst {
780 unsigned int instr; 641 unsigned int instr;
781 unsigned int dp_operation; 642 unsigned int dp_operation;
782} vfpinstr_inst; 643} vmul_inst;
783#endif 644#endif
784#ifdef VFP_INTERPRETER_TRANS 645#ifdef VFP_INTERPRETER_TRANS
785ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 646ARM_INST_PTR INTERPRETER_TRANSLATE(vmul)(unsigned int inst, int index)
786{ 647{
787 VFP_DEBUG_TRANSLATE; 648 VFP_DEBUG_TRANSLATE;
788 649
789 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 650 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vmul_inst));
790 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 651 vmul_inst *inst_cream = (vmul_inst *)inst_base->component;
791 652
792 inst_base->cond = BITS(inst, 28, 31); 653 inst_base->cond = BITS(inst, 28, 31);
793 inst_base->idx = index; 654 inst_base->idx = index;
@@ -801,15 +662,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
801} 662}
802#endif 663#endif
803#ifdef VFP_INTERPRETER_IMPL 664#ifdef VFP_INTERPRETER_IMPL
804VFPLABEL_INST: 665VMUL_INST:
805{ 666{
806 INC_ICOUNTER;
807 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 667 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
808 CHECK_VFP_ENABLED; 668 CHECK_VFP_ENABLED;
809 669
810 DBG("VMUL :\n"); 670 DBG("VMUL :\n");
811 671
812 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 672 vmul_inst *inst_cream = (vmul_inst *)inst_base->component;
813 673
814 int ret; 674 int ret;
815 675
@@ -821,22 +681,17 @@ VFPLABEL_INST:
821 CHECK_VFP_CDP_RET; 681 CHECK_VFP_CDP_RET;
822 } 682 }
823 cpu->Reg[15] += GET_INST_SIZE(cpu); 683 cpu->Reg[15] += GET_INST_SIZE(cpu);
824 INC_PC(sizeof(vfpinstr_inst)); 684 INC_PC(sizeof(vmul_inst));
825 FETCH_INST; 685 FETCH_INST;
826 GOTO_NEXT_INST; 686 GOTO_NEXT_INST;
827} 687}
828#endif 688#endif
829#ifdef VFP_CDP_TRANS 689
830if ((OPC_1 & 0xB) == 2 && (OPC_2 & 0x2) == 0)
831{
832 DBG("VMUL :\n");
833}
834#endif
835#ifdef VFP_DYNCOM_TABLE 690#ifdef VFP_DYNCOM_TABLE
836DYNCOM_FILL_ACTION(vfpinstr), 691DYNCOM_FILL_ACTION(vmul),
837#endif 692#endif
838#ifdef VFP_DYNCOM_TAG 693#ifdef VFP_DYNCOM_TAG
839int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 694int DYNCOM_TAG(vmul)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
840{ 695{
841 int instr_size = INSTR_SIZE; 696 int instr_size = INSTR_SIZE;
842 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 697 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -846,7 +701,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
846} 701}
847#endif 702#endif
848#ifdef VFP_DYNCOM_TRANS 703#ifdef VFP_DYNCOM_TRANS
849int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 704int DYNCOM_TRANS(vmul)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
850 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 705 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
851 //printf("\n\n\t\tin %s instruction is executed out.\n\n", __FUNCTION__); 706 //printf("\n\n\t\tin %s instruction is executed out.\n\n", __FUNCTION__);
852 //arch_arm_undef(cpu, bb, instr); 707 //arch_arm_undef(cpu, bb, instr);
@@ -904,41 +759,23 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
904 return No_exp; 759 return No_exp;
905} 760}
906#endif 761#endif
907#undef vfpinstr
908#undef vfpinstr_inst
909#undef VFPLABEL_INST
910 762
911/* ----------------------------------------------------------------------- */ 763/* ----------------------------------------------------------------------- */
912/* VADD */ 764/* VADD */
913/* cond 1110 0D11 Vn-- Vd-- 101X N0M0 Vm-- */ 765/* cond 1110 0D11 Vn-- Vd-- 101X N0M0 Vm-- */
914#define vfpinstr vadd
915#define vfpinstr_inst vadd_inst
916#define VFPLABEL_INST VADD_INST
917#ifdef VFP_DECODE
918{"vadd", 5, ARMVFP2, 23, 27, 0x1c, 20, 21, 0x3, 9, 11, 0x5, 6, 6, 0, 4, 4, 0},
919#endif
920#ifdef VFP_DECODE_EXCLUSION
921{"vadd", 0, ARMVFP2, 0},
922#endif
923#ifdef VFP_INTERPRETER_TABLE
924INTERPRETER_TRANSLATE(vfpinstr),
925#endif
926#ifdef VFP_INTERPRETER_LABEL
927&&VFPLABEL_INST,
928#endif
929#ifdef VFP_INTERPRETER_STRUCT 766#ifdef VFP_INTERPRETER_STRUCT
930typedef struct _vadd_inst { 767typedef struct _vadd_inst {
931 unsigned int instr; 768 unsigned int instr;
932 unsigned int dp_operation; 769 unsigned int dp_operation;
933} vfpinstr_inst; 770} vadd_inst;
934#endif 771#endif
935#ifdef VFP_INTERPRETER_TRANS 772#ifdef VFP_INTERPRETER_TRANS
936ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 773ARM_INST_PTR INTERPRETER_TRANSLATE(vadd)(unsigned int inst, int index)
937{ 774{
938 VFP_DEBUG_TRANSLATE; 775 VFP_DEBUG_TRANSLATE;
939 776
940 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 777 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vadd_inst));
941 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 778 vadd_inst *inst_cream = (vadd_inst *)inst_base->component;
942 779
943 inst_base->cond = BITS(inst, 28, 31); 780 inst_base->cond = BITS(inst, 28, 31);
944 inst_base->idx = index; 781 inst_base->idx = index;
@@ -952,15 +789,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
952} 789}
953#endif 790#endif
954#ifdef VFP_INTERPRETER_IMPL 791#ifdef VFP_INTERPRETER_IMPL
955VFPLABEL_INST: 792VADD_INST:
956{ 793{
957 INC_ICOUNTER;
958 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 794 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
959 CHECK_VFP_ENABLED; 795 CHECK_VFP_ENABLED;
960 796
961 DBG("VADD :\n"); 797 DBG("VADD :\n");
962 798
963 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 799 vadd_inst *inst_cream = (vadd_inst *)inst_base->component;
964 800
965 int ret; 801 int ret;
966 802
@@ -972,22 +808,17 @@ VFPLABEL_INST:
972 CHECK_VFP_CDP_RET; 808 CHECK_VFP_CDP_RET;
973 } 809 }
974 cpu->Reg[15] += GET_INST_SIZE(cpu); 810 cpu->Reg[15] += GET_INST_SIZE(cpu);
975 INC_PC(sizeof(vfpinstr_inst)); 811 INC_PC(sizeof(vadd_inst));
976 FETCH_INST; 812 FETCH_INST;
977 GOTO_NEXT_INST; 813 GOTO_NEXT_INST;
978} 814}
979#endif 815#endif
980#ifdef VFP_CDP_TRANS 816
981if ((OPC_1 & 0xB) == 3 && (OPC_2 & 0x2) == 0)
982{
983 DBG("VADD :\n");
984}
985#endif
986#ifdef VFP_DYNCOM_TABLE 817#ifdef VFP_DYNCOM_TABLE
987DYNCOM_FILL_ACTION(vfpinstr), 818DYNCOM_FILL_ACTION(vadd),
988#endif 819#endif
989#ifdef VFP_DYNCOM_TAG 820#ifdef VFP_DYNCOM_TAG
990int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 821int DYNCOM_TAG(vadd)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
991{ 822{
992 int instr_size = INSTR_SIZE; 823 int instr_size = INSTR_SIZE;
993 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 824 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -997,7 +828,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
997} 828}
998#endif 829#endif
999#ifdef VFP_DYNCOM_TRANS 830#ifdef VFP_DYNCOM_TRANS
1000int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 831int DYNCOM_TRANS(vadd)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
1001 DBG("\t\tin %s instruction will implement out of JIT.\n", __FUNCTION__); 832 DBG("\t\tin %s instruction will implement out of JIT.\n", __FUNCTION__);
1002 //arch_arm_undef(cpu, bb, instr); 833 //arch_arm_undef(cpu, bb, instr);
1003 int m; 834 int m;
@@ -1049,41 +880,23 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
1049 return No_exp; 880 return No_exp;
1050} 881}
1051#endif 882#endif
1052#undef vfpinstr
1053#undef vfpinstr_inst
1054#undef VFPLABEL_INST
1055 883
1056/* ----------------------------------------------------------------------- */ 884/* ----------------------------------------------------------------------- */
1057/* VSUB */ 885/* VSUB */
1058/* cond 1110 0D11 Vn-- Vd-- 101X N1M0 Vm-- */ 886/* cond 1110 0D11 Vn-- Vd-- 101X N1M0 Vm-- */
1059#define vfpinstr vsub
1060#define vfpinstr_inst vsub_inst
1061#define VFPLABEL_INST VSUB_INST
1062#ifdef VFP_DECODE
1063{"vsub", 5, ARMVFP2, 23, 27, 0x1c, 20, 21, 0x3, 9, 11, 0x5, 6, 6, 1, 4, 4, 0},
1064#endif
1065#ifdef VFP_DECODE_EXCLUSION
1066{"vsub", 0, ARMVFP2, 0},
1067#endif
1068#ifdef VFP_INTERPRETER_TABLE
1069INTERPRETER_TRANSLATE(vfpinstr),
1070#endif
1071#ifdef VFP_INTERPRETER_LABEL
1072&&VFPLABEL_INST,
1073#endif
1074#ifdef VFP_INTERPRETER_STRUCT 887#ifdef VFP_INTERPRETER_STRUCT
1075typedef struct _vsub_inst { 888typedef struct _vsub_inst {
1076 unsigned int instr; 889 unsigned int instr;
1077 unsigned int dp_operation; 890 unsigned int dp_operation;
1078} vfpinstr_inst; 891} vsub_inst;
1079#endif 892#endif
1080#ifdef VFP_INTERPRETER_TRANS 893#ifdef VFP_INTERPRETER_TRANS
1081ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 894ARM_INST_PTR INTERPRETER_TRANSLATE(vsub)(unsigned int inst, int index)
1082{ 895{
1083 VFP_DEBUG_TRANSLATE; 896 VFP_DEBUG_TRANSLATE;
1084 897
1085 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 898 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vsub_inst));
1086 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 899 vsub_inst *inst_cream = (vsub_inst *)inst_base->component;
1087 900
1088 inst_base->cond = BITS(inst, 28, 31); 901 inst_base->cond = BITS(inst, 28, 31);
1089 inst_base->idx = index; 902 inst_base->idx = index;
@@ -1097,15 +910,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
1097} 910}
1098#endif 911#endif
1099#ifdef VFP_INTERPRETER_IMPL 912#ifdef VFP_INTERPRETER_IMPL
1100VFPLABEL_INST: 913VSUB_INST:
1101{ 914{
1102 INC_ICOUNTER;
1103 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 915 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
1104 CHECK_VFP_ENABLED; 916 CHECK_VFP_ENABLED;
1105 917
1106 DBG("VSUB :\n"); 918 DBG("VSUB :\n");
1107 919
1108 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 920 vsub_inst *inst_cream = (vsub_inst *)inst_base->component;
1109 921
1110 int ret; 922 int ret;
1111 923
@@ -1117,22 +929,16 @@ VFPLABEL_INST:
1117 CHECK_VFP_CDP_RET; 929 CHECK_VFP_CDP_RET;
1118 } 930 }
1119 cpu->Reg[15] += GET_INST_SIZE(cpu); 931 cpu->Reg[15] += GET_INST_SIZE(cpu);
1120 INC_PC(sizeof(vfpinstr_inst)); 932 INC_PC(sizeof(vsub_inst));
1121 FETCH_INST; 933 FETCH_INST;
1122 GOTO_NEXT_INST; 934 GOTO_NEXT_INST;
1123} 935}
1124#endif 936#endif
1125#ifdef VFP_CDP_TRANS
1126if ((OPC_1 & 0xB) == 3 && (OPC_2 & 0x2) == 2)
1127{
1128 DBG("VSUB :\n");
1129}
1130#endif
1131#ifdef VFP_DYNCOM_TABLE 937#ifdef VFP_DYNCOM_TABLE
1132DYNCOM_FILL_ACTION(vfpinstr), 938DYNCOM_FILL_ACTION(vsub),
1133#endif 939#endif
1134#ifdef VFP_DYNCOM_TAG 940#ifdef VFP_DYNCOM_TAG
1135int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 941int DYNCOM_TAG(vsub)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
1136{ 942{
1137 int instr_size = INSTR_SIZE; 943 int instr_size = INSTR_SIZE;
1138 //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); 944 //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc);
@@ -1141,7 +947,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
1141} 947}
1142#endif 948#endif
1143#ifdef VFP_DYNCOM_TRANS 949#ifdef VFP_DYNCOM_TRANS
1144int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 950int DYNCOM_TRANS(vsub)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
1145 DBG("\t\tin %s instr=0x%x, instruction is executed out of JIT.\n", __FUNCTION__, instr); 951 DBG("\t\tin %s instr=0x%x, instruction is executed out of JIT.\n", __FUNCTION__, instr);
1146 //arch_arm_undef(cpu, bb, instr); 952 //arch_arm_undef(cpu, bb, instr);
1147 int m; 953 int m;
@@ -1193,41 +999,23 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
1193 return No_exp; 999 return No_exp;
1194} 1000}
1195#endif 1001#endif
1196#undef vfpinstr
1197#undef vfpinstr_inst
1198#undef VFPLABEL_INST
1199 1002
1200/* ----------------------------------------------------------------------- */ 1003/* ----------------------------------------------------------------------- */
1201/* VDIV */ 1004/* VDIV */
1202/* cond 1110 1D00 Vn-- Vd-- 101X N0M0 Vm-- */ 1005/* cond 1110 1D00 Vn-- Vd-- 101X N0M0 Vm-- */
1203#define vfpinstr vdiv
1204#define vfpinstr_inst vdiv_inst
1205#define VFPLABEL_INST VDIV_INST
1206#ifdef VFP_DECODE
1207{"vdiv", 5, ARMVFP2, 23, 27, 0x1d, 20, 21, 0x0, 9, 11, 0x5, 6, 6, 0, 4, 4, 0},
1208#endif
1209#ifdef VFP_DECODE_EXCLUSION
1210{"vdiv", 0, ARMVFP2, 0},
1211#endif
1212#ifdef VFP_INTERPRETER_TABLE
1213INTERPRETER_TRANSLATE(vfpinstr),
1214#endif
1215#ifdef VFP_INTERPRETER_LABEL
1216&&VFPLABEL_INST,
1217#endif
1218#ifdef VFP_INTERPRETER_STRUCT 1006#ifdef VFP_INTERPRETER_STRUCT
1219typedef struct _vdiv_inst { 1007typedef struct _vdiv_inst {
1220 unsigned int instr; 1008 unsigned int instr;
1221 unsigned int dp_operation; 1009 unsigned int dp_operation;
1222} vfpinstr_inst; 1010} vdiv_inst;
1223#endif 1011#endif
1224#ifdef VFP_INTERPRETER_TRANS 1012#ifdef VFP_INTERPRETER_TRANS
1225ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 1013ARM_INST_PTR INTERPRETER_TRANSLATE(vdiv)(unsigned int inst, int index)
1226{ 1014{
1227 VFP_DEBUG_TRANSLATE; 1015 VFP_DEBUG_TRANSLATE;
1228 1016
1229 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 1017 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vdiv_inst));
1230 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1018 vdiv_inst *inst_cream = (vdiv_inst *)inst_base->component;
1231 1019
1232 inst_base->cond = BITS(inst, 28, 31); 1020 inst_base->cond = BITS(inst, 28, 31);
1233 inst_base->idx = index; 1021 inst_base->idx = index;
@@ -1241,15 +1029,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
1241} 1029}
1242#endif 1030#endif
1243#ifdef VFP_INTERPRETER_IMPL 1031#ifdef VFP_INTERPRETER_IMPL
1244VFPLABEL_INST: 1032VDIV_INST:
1245{ 1033{
1246 INC_ICOUNTER;
1247 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1034 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
1248 CHECK_VFP_ENABLED; 1035 CHECK_VFP_ENABLED;
1249 1036
1250 DBG("VDIV :\n"); 1037 DBG("VDIV :\n");
1251 1038
1252 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1039 vdiv_inst *inst_cream = (vdiv_inst *)inst_base->component;
1253 1040
1254 int ret; 1041 int ret;
1255 1042
@@ -1261,22 +1048,17 @@ VFPLABEL_INST:
1261 CHECK_VFP_CDP_RET; 1048 CHECK_VFP_CDP_RET;
1262 } 1049 }
1263 cpu->Reg[15] += GET_INST_SIZE(cpu); 1050 cpu->Reg[15] += GET_INST_SIZE(cpu);
1264 INC_PC(sizeof(vfpinstr_inst)); 1051 INC_PC(sizeof(vdiv_inst));
1265 FETCH_INST; 1052 FETCH_INST;
1266 GOTO_NEXT_INST; 1053 GOTO_NEXT_INST;
1267} 1054}
1268#endif 1055#endif
1269#ifdef VFP_CDP_TRANS 1056
1270if ((OPC_1 & 0xB) == 0xA && (OPC_2 & 0x2) == 0)
1271{
1272 DBG("VDIV :\n");
1273}
1274#endif
1275#ifdef VFP_DYNCOM_TABLE 1057#ifdef VFP_DYNCOM_TABLE
1276DYNCOM_FILL_ACTION(vfpinstr), 1058DYNCOM_FILL_ACTION(vdiv),
1277#endif 1059#endif
1278#ifdef VFP_DYNCOM_TAG 1060#ifdef VFP_DYNCOM_TAG
1279int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 1061int DYNCOM_TAG(vdiv)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
1280{ 1062{
1281 int instr_size = INSTR_SIZE; 1063 int instr_size = INSTR_SIZE;
1282 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 1064 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -1286,7 +1068,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
1286} 1068}
1287#endif 1069#endif
1288#ifdef VFP_DYNCOM_TRANS 1070#ifdef VFP_DYNCOM_TRANS
1289int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 1071int DYNCOM_TRANS(vdiv)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
1290 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 1072 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
1291 //arch_arm_undef(cpu, bb, instr); 1073 //arch_arm_undef(cpu, bb, instr);
1292 int m; 1074 int m;
@@ -1338,43 +1120,25 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
1338 return No_exp; 1120 return No_exp;
1339} 1121}
1340#endif 1122#endif
1341#undef vfpinstr
1342#undef vfpinstr_inst
1343#undef VFPLABEL_INST
1344 1123
1345/* ----------------------------------------------------------------------- */ 1124/* ----------------------------------------------------------------------- */
1346/* VMOVI move immediate */ 1125/* VMOVI move immediate */
1347/* cond 1110 1D11 im4H Vd-- 101X 0000 im4L */ 1126/* cond 1110 1D11 im4H Vd-- 101X 0000 im4L */
1348/* cond 1110 opc1 CRn- CRd- copr op20 CRm- CDP */ 1127/* cond 1110 opc1 CRn- CRd- copr op20 CRm- CDP */
1349#define vfpinstr vmovi
1350#define vfpinstr_inst vmovi_inst
1351#define VFPLABEL_INST VMOVI_INST
1352#ifdef VFP_DECODE
1353{"vmov(i)", 4, ARMVFP3, 23, 27, 0x1d, 20, 21, 0x3, 9, 11, 0x5, 4, 7, 0},
1354#endif
1355#ifdef VFP_DECODE_EXCLUSION
1356{"vmov(i)", 0, ARMVFP3, 0},
1357#endif
1358#ifdef VFP_INTERPRETER_TABLE
1359INTERPRETER_TRANSLATE(vfpinstr),
1360#endif
1361#ifdef VFP_INTERPRETER_LABEL
1362&&VFPLABEL_INST,
1363#endif
1364#ifdef VFP_INTERPRETER_STRUCT 1128#ifdef VFP_INTERPRETER_STRUCT
1365typedef struct _vmovi_inst { 1129typedef struct _vmovi_inst {
1366 unsigned int single; 1130 unsigned int single;
1367 unsigned int d; 1131 unsigned int d;
1368 unsigned int imm; 1132 unsigned int imm;
1369} vfpinstr_inst; 1133} vmovi_inst;
1370#endif 1134#endif
1371#ifdef VFP_INTERPRETER_TRANS 1135#ifdef VFP_INTERPRETER_TRANS
1372ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 1136ARM_INST_PTR INTERPRETER_TRANSLATE(vmovi)(unsigned int inst, int index)
1373{ 1137{
1374 VFP_DEBUG_TRANSLATE; 1138 VFP_DEBUG_TRANSLATE;
1375 1139
1376 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 1140 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vmovi_inst));
1377 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1141 vmovi_inst *inst_cream = (vmovi_inst *)inst_base->component;
1378 1142
1379 inst_base->cond = BITS(inst, 28, 31); 1143 inst_base->cond = BITS(inst, 28, 31);
1380 inst_base->idx = index; 1144 inst_base->idx = index;
@@ -1392,62 +1156,27 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
1392} 1156}
1393#endif 1157#endif
1394#ifdef VFP_INTERPRETER_IMPL 1158#ifdef VFP_INTERPRETER_IMPL
1395VFPLABEL_INST: 1159VMOVI_INST:
1396{ 1160{
1397 INC_ICOUNTER;
1398 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1161 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
1399 CHECK_VFP_ENABLED; 1162 CHECK_VFP_ENABLED;
1400 1163
1401 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1164 vmovi_inst *inst_cream = (vmovi_inst *)inst_base->component;
1402 1165
1403 VMOVI(cpu, inst_cream->single, inst_cream->d, inst_cream->imm); 1166 VMOVI(cpu, inst_cream->single, inst_cream->d, inst_cream->imm);
1404 } 1167 }
1405 cpu->Reg[15] += GET_INST_SIZE(cpu); 1168 cpu->Reg[15] += GET_INST_SIZE(cpu);
1406 INC_PC(sizeof(vfpinstr_inst)); 1169 INC_PC(sizeof(vmovi_inst));
1407 FETCH_INST; 1170 FETCH_INST;
1408 GOTO_NEXT_INST; 1171 GOTO_NEXT_INST;
1409} 1172}
1410#endif 1173#endif
1411#ifdef VFP_CDP_TRANS 1174
1412if ( (OPC_1 & 0xb) == 0xb && BITS(4, 7) == 0)
1413{
1414 unsigned int single = BIT(8) == 0;
1415 unsigned int d = (single ? BITS(12,15)<<1 | BIT(22) : BITS(12,15) | BIT(22)<<4);
1416 unsigned int imm;
1417 instr = BITS(16, 19) << 4 | BITS(0, 3); /* FIXME dirty workaround to get a correct imm */
1418 if (single) {
1419 imm = BIT(7)<<31 | (BIT(6)==0)<<30 | (BIT(6) ? 0x1f : 0)<<25 | BITS(0, 5)<<19;
1420 } else {
1421 imm = BIT(7)<<31 | (BIT(6)==0)<<30 | (BIT(6) ? 0xff : 0)<<22 | BITS(0, 5)<<16;
1422 }
1423 VMOVI(state, single, d, imm);
1424 return ARMul_DONE;
1425}
1426#endif
1427#ifdef VFP_CDP_IMPL
1428void VMOVI(ARMul_State * state, ARMword single, ARMword d, ARMword imm)
1429{
1430 DBG("VMOV(I) :\n");
1431
1432 if (single)
1433 {
1434 DBG("\ts%d <= [%x]\n", d, imm);
1435 state->ExtReg[d] = imm;
1436 }
1437 else
1438 {
1439 /* Check endian please */
1440 DBG("\ts[%d-%d] <= [%x-%x]\n", d*2+1, d*2, imm, 0);
1441 state->ExtReg[d*2+1] = imm;
1442 state->ExtReg[d*2] = 0;
1443 }
1444}
1445#endif
1446#ifdef VFP_DYNCOM_TABLE 1175#ifdef VFP_DYNCOM_TABLE
1447DYNCOM_FILL_ACTION(vfpinstr), 1176DYNCOM_FILL_ACTION(vmovi),
1448#endif 1177#endif
1449#ifdef VFP_DYNCOM_TAG 1178#ifdef VFP_DYNCOM_TAG
1450int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 1179int DYNCOM_TAG(vmovi)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
1451{ 1180{
1452 int instr_size = INSTR_SIZE; 1181 int instr_size = INSTR_SIZE;
1453 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 1182 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -1456,7 +1185,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
1456} 1185}
1457#endif 1186#endif
1458#ifdef VFP_DYNCOM_TRANS 1187#ifdef VFP_DYNCOM_TRANS
1459int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 1188int DYNCOM_TRANS(vmovi)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
1460 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 1189 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
1461 //arch_arm_undef(cpu, bb, instr); 1190 //arch_arm_undef(cpu, bb, instr);
1462 int single = (BIT(8) == 0); 1191 int single = (BIT(8) == 0);
@@ -1482,44 +1211,26 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
1482 return No_exp; 1211 return No_exp;
1483} 1212}
1484#endif 1213#endif
1485#undef vfpinstr
1486#undef vfpinstr_inst
1487#undef VFPLABEL_INST
1488 1214
1489/* ----------------------------------------------------------------------- */ 1215/* ----------------------------------------------------------------------- */
1490/* VMOVR move register */ 1216/* VMOVR move register */
1491/* cond 1110 1D11 0000 Vd-- 101X 01M0 Vm-- */ 1217/* cond 1110 1D11 0000 Vd-- 101X 01M0 Vm-- */
1492/* cond 1110 opc1 CRn- CRd- copr op20 CRm- CDP */ 1218/* cond 1110 opc1 CRn- CRd- copr op20 CRm- CDP */
1493#define vfpinstr vmovr
1494#define vfpinstr_inst vmovr_inst
1495#define VFPLABEL_INST VMOVR_INST
1496#ifdef VFP_DECODE
1497{"vmov(r)", 5, ARMVFP3, 23, 27, 0x1d, 16, 21, 0x30, 9, 11, 0x5, 6, 7, 1, 4, 4, 0},
1498#endif
1499#ifdef VFP_DECODE_EXCLUSION
1500{"vmov(r)", 0, ARMVFP3, 0},
1501#endif
1502#ifdef VFP_INTERPRETER_TABLE
1503INTERPRETER_TRANSLATE(vfpinstr),
1504#endif
1505#ifdef VFP_INTERPRETER_LABEL
1506&&VFPLABEL_INST,
1507#endif
1508#ifdef VFP_INTERPRETER_STRUCT 1219#ifdef VFP_INTERPRETER_STRUCT
1509typedef struct _vmovr_inst { 1220typedef struct _vmovr_inst {
1510 unsigned int single; 1221 unsigned int single;
1511 unsigned int d; 1222 unsigned int d;
1512 unsigned int m; 1223 unsigned int m;
1513} vfpinstr_inst; 1224} vmovr_inst;
1514#endif 1225#endif
1515#ifdef VFP_INTERPRETER_TRANS 1226#ifdef VFP_INTERPRETER_TRANS
1516ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 1227ARM_INST_PTR INTERPRETER_TRANSLATE(vmovr)(unsigned int inst, int index)
1517{ 1228{
1518 VFP_DEBUG_TRANSLATE; 1229 VFP_DEBUG_TRANSLATE;
1519 VFP_DEBUG_UNTESTED(VMOVR); 1230 VFP_DEBUG_UNTESTED(VMOVR);
1520 1231
1521 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 1232 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vmovr_inst));
1522 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1233 vmovr_inst *inst_cream = (vmovr_inst *)inst_base->component;
1523 1234
1524 inst_base->cond = BITS(inst, 28, 31); 1235 inst_base->cond = BITS(inst, 28, 31);
1525 inst_base->idx = index; 1236 inst_base->idx = index;
@@ -1533,56 +1244,27 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
1533} 1244}
1534#endif 1245#endif
1535#ifdef VFP_INTERPRETER_IMPL 1246#ifdef VFP_INTERPRETER_IMPL
1536VFPLABEL_INST: 1247VMOVR_INST:
1537{ 1248{
1538 INC_ICOUNTER;
1539 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1249 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
1540 CHECK_VFP_ENABLED; 1250 CHECK_VFP_ENABLED;
1541 1251
1542 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1252 vmovr_inst *inst_cream = (vmovr_inst *)inst_base->component;
1543 1253
1544 VMOVR(cpu, inst_cream->single, inst_cream->d, inst_cream->m); 1254 VMOVR(cpu, inst_cream->single, inst_cream->d, inst_cream->m);
1545 } 1255 }
1546 cpu->Reg[15] += GET_INST_SIZE(cpu); 1256 cpu->Reg[15] += GET_INST_SIZE(cpu);
1547 INC_PC(sizeof(vfpinstr_inst)); 1257 INC_PC(sizeof(vmovr_inst));
1548 FETCH_INST; 1258 FETCH_INST;
1549 GOTO_NEXT_INST; 1259 GOTO_NEXT_INST;
1550} 1260}
1551#endif 1261#endif
1552#ifdef VFP_CDP_TRANS 1262
1553if ( (OPC_1 & 0xb) == 0xb && CRn == 0 && (OPC_2 & 0x6) == 0x2 )
1554{
1555 unsigned int single = BIT(8) == 0;
1556 unsigned int d = (single ? BITS(12,15)<<1 | BIT(22) : BITS(12,15) | BIT(22)<<4);
1557 unsigned int m = (single ? BITS( 0, 3)<<1 | BIT( 5) : BITS( 0, 3) | BIT( 5)<<4);;
1558 VMOVR(state, single, d, m);
1559 return ARMul_DONE;
1560}
1561#endif
1562#ifdef VFP_CDP_IMPL
1563void VMOVR(ARMul_State * state, ARMword single, ARMword d, ARMword m)
1564{
1565 DBG("VMOV(R) :\n");
1566
1567 if (single)
1568 {
1569 DBG("\ts%d <= s%d[%x]\n", d, m, state->ExtReg[m]);
1570 state->ExtReg[d] = state->ExtReg[m];
1571 }
1572 else
1573 {
1574 /* Check endian please */
1575 DBG("\ts[%d-%d] <= s[%d-%d][%x-%x]\n", d*2+1, d*2, m*2+1, m*2, state->ExtReg[m*2+1], state->ExtReg[m*2]);
1576 state->ExtReg[d*2+1] = state->ExtReg[m*2+1];
1577 state->ExtReg[d*2] = state->ExtReg[m*2];
1578 }
1579}
1580#endif
1581#ifdef VFP_DYNCOM_TABLE 1263#ifdef VFP_DYNCOM_TABLE
1582DYNCOM_FILL_ACTION(vfpinstr), 1264DYNCOM_FILL_ACTION(vmovr),
1583#endif 1265#endif
1584#ifdef VFP_DYNCOM_TAG 1266#ifdef VFP_DYNCOM_TAG
1585int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 1267int DYNCOM_TAG(vmovr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
1586{ 1268{
1587 int instr_size = INSTR_SIZE; 1269 int instr_size = INSTR_SIZE;
1588 arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); 1270 arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc);
@@ -1594,7 +1276,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
1594} 1276}
1595#endif 1277#endif
1596#ifdef VFP_DYNCOM_TRANS 1278#ifdef VFP_DYNCOM_TRANS
1597int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 1279int DYNCOM_TRANS(vmovr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
1598 DBG("\t\tin %s VMOV \n", __FUNCTION__); 1280 DBG("\t\tin %s VMOV \n", __FUNCTION__);
1599 int single = BIT(8) == 0; 1281 int single = BIT(8) == 0;
1600 int d = (single ? BITS(12,15)<<1 | BIT(22) : BIT(22) << 4 | BITS(12,15)); 1282 int d = (single ? BITS(12,15)<<1 | BIT(22) : BIT(22) << 4 | BITS(12,15));
@@ -1613,41 +1295,23 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
1613 return No_exp; 1295 return No_exp;
1614} 1296}
1615#endif 1297#endif
1616#undef vfpinstr
1617#undef vfpinstr_inst
1618#undef VFPLABEL_INST
1619 1298
1620/* ----------------------------------------------------------------------- */ 1299/* ----------------------------------------------------------------------- */
1621/* VABS */ 1300/* VABS */
1622/* cond 1110 1D11 0000 Vd-- 101X 11M0 Vm-- */ 1301/* cond 1110 1D11 0000 Vd-- 101X 11M0 Vm-- */
1623#define vfpinstr vabs
1624#define vfpinstr_inst vabs_inst
1625#define VFPLABEL_INST VABS_INST
1626#ifdef VFP_DECODE
1627{"vabs", 5, ARMVFP2, 23, 27, 0x1d, 16, 21, 0x30, 9, 11, 0x5, 6, 7, 3, 4, 4, 0},
1628#endif
1629#ifdef VFP_DECODE_EXCLUSION
1630{"vabs", 0, ARMVFP2, 0},
1631#endif
1632#ifdef VFP_INTERPRETER_TABLE
1633INTERPRETER_TRANSLATE(vfpinstr),
1634#endif
1635#ifdef VFP_INTERPRETER_LABEL
1636&&VFPLABEL_INST,
1637#endif
1638#ifdef VFP_INTERPRETER_STRUCT 1302#ifdef VFP_INTERPRETER_STRUCT
1639typedef struct _vabs_inst { 1303typedef struct _vabs_inst {
1640 unsigned int instr; 1304 unsigned int instr;
1641 unsigned int dp_operation; 1305 unsigned int dp_operation;
1642} vfpinstr_inst; 1306} vabs_inst;
1643#endif 1307#endif
1644#ifdef VFP_INTERPRETER_TRANS 1308#ifdef VFP_INTERPRETER_TRANS
1645ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 1309ARM_INST_PTR INTERPRETER_TRANSLATE(vabs)(unsigned int inst, int index)
1646{ 1310{
1647 VFP_DEBUG_TRANSLATE;VFP_DEBUG_UNTESTED(VABS); 1311 VFP_DEBUG_TRANSLATE;VFP_DEBUG_UNTESTED(VABS);
1648 1312
1649 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 1313 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vabs_inst));
1650 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1314 vabs_inst *inst_cream = (vabs_inst *)inst_base->component;
1651 1315
1652 inst_base->cond = BITS(inst, 28, 31); 1316 inst_base->cond = BITS(inst, 28, 31);
1653 inst_base->idx = index; 1317 inst_base->idx = index;
@@ -1661,15 +1325,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
1661} 1325}
1662#endif 1326#endif
1663#ifdef VFP_INTERPRETER_IMPL 1327#ifdef VFP_INTERPRETER_IMPL
1664VFPLABEL_INST: 1328VABS_INST:
1665{ 1329{
1666 INC_ICOUNTER;
1667 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1330 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
1668 CHECK_VFP_ENABLED; 1331 CHECK_VFP_ENABLED;
1669 1332
1670 DBG("VABS :\n"); 1333 DBG("VABS :\n");
1671 1334
1672 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1335 vabs_inst *inst_cream = (vabs_inst *)inst_base->component;
1673 1336
1674 int ret; 1337 int ret;
1675 1338
@@ -1681,22 +1344,17 @@ VFPLABEL_INST:
1681 CHECK_VFP_CDP_RET; 1344 CHECK_VFP_CDP_RET;
1682 } 1345 }
1683 cpu->Reg[15] += GET_INST_SIZE(cpu); 1346 cpu->Reg[15] += GET_INST_SIZE(cpu);
1684 INC_PC(sizeof(vfpinstr_inst)); 1347 INC_PC(sizeof(vabs_inst));
1685 FETCH_INST; 1348 FETCH_INST;
1686 GOTO_NEXT_INST; 1349 GOTO_NEXT_INST;
1687} 1350}
1688#endif 1351#endif
1689#ifdef VFP_CDP_TRANS 1352
1690if ((OPC_1 & 0xB) == 0xB && CRn == 0 && (OPC_2 & 0x7) == 6)
1691{
1692 DBG("VABS :\n");
1693}
1694#endif
1695#ifdef VFP_DYNCOM_TABLE 1353#ifdef VFP_DYNCOM_TABLE
1696DYNCOM_FILL_ACTION(vfpinstr), 1354DYNCOM_FILL_ACTION(vabs),
1697#endif 1355#endif
1698#ifdef VFP_DYNCOM_TAG 1356#ifdef VFP_DYNCOM_TAG
1699int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 1357int DYNCOM_TAG(vabs)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
1700{ 1358{
1701 int instr_size = INSTR_SIZE; 1359 int instr_size = INSTR_SIZE;
1702 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 1360 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -1706,7 +1364,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
1706} 1364}
1707#endif 1365#endif
1708#ifdef VFP_DYNCOM_TRANS 1366#ifdef VFP_DYNCOM_TRANS
1709int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 1367int DYNCOM_TRANS(vabs)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
1710 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 1368 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
1711 //arch_arm_undef(cpu, bb, instr); 1369 //arch_arm_undef(cpu, bb, instr);
1712 int single = BIT(8) == 0; 1370 int single = BIT(8) == 0;
@@ -1744,42 +1402,24 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
1744 return No_exp; 1402 return No_exp;
1745} 1403}
1746#endif 1404#endif
1747#undef vfpinstr
1748#undef vfpinstr_inst
1749#undef VFPLABEL_INST
1750 1405
1751/* ----------------------------------------------------------------------- */ 1406/* ----------------------------------------------------------------------- */
1752/* VNEG */ 1407/* VNEG */
1753/* cond 1110 1D11 0001 Vd-- 101X 11M0 Vm-- */ 1408/* cond 1110 1D11 0001 Vd-- 101X 11M0 Vm-- */
1754#define vfpinstr vneg 1409
1755#define vfpinstr_inst vneg_inst
1756#define VFPLABEL_INST VNEG_INST
1757#ifdef VFP_DECODE
1758//{"vneg", 5, ARMVFP2, 23, 27, 0x1d, 16, 21, 0x30, 9, 11, 0x5, 6, 7, 1, 4, 4, 0},
1759{"vneg", 5, ARMVFP2, 23, 27, 0x1d, 17, 21, 0x18, 9, 11, 0x5, 6, 7, 1, 4, 4, 0},
1760#endif
1761#ifdef VFP_DECODE_EXCLUSION
1762{"vneg", 0, ARMVFP2, 0},
1763#endif
1764#ifdef VFP_INTERPRETER_TABLE
1765INTERPRETER_TRANSLATE(vfpinstr),
1766#endif
1767#ifdef VFP_INTERPRETER_LABEL
1768&&VFPLABEL_INST,
1769#endif
1770#ifdef VFP_INTERPRETER_STRUCT 1410#ifdef VFP_INTERPRETER_STRUCT
1771typedef struct _vneg_inst { 1411typedef struct _vneg_inst {
1772 unsigned int instr; 1412 unsigned int instr;
1773 unsigned int dp_operation; 1413 unsigned int dp_operation;
1774} vfpinstr_inst; 1414} vneg_inst;
1775#endif 1415#endif
1776#ifdef VFP_INTERPRETER_TRANS 1416#ifdef VFP_INTERPRETER_TRANS
1777ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 1417ARM_INST_PTR INTERPRETER_TRANSLATE(vneg)(unsigned int inst, int index)
1778{ 1418{
1779 VFP_DEBUG_TRANSLATE;VFP_DEBUG_UNTESTED(VNEG); 1419 VFP_DEBUG_TRANSLATE;VFP_DEBUG_UNTESTED(VNEG);
1780 1420
1781 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 1421 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vneg_inst));
1782 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1422 vneg_inst *inst_cream = (vneg_inst *)inst_base->component;
1783 1423
1784 inst_base->cond = BITS(inst, 28, 31); 1424 inst_base->cond = BITS(inst, 28, 31);
1785 inst_base->idx = index; 1425 inst_base->idx = index;
@@ -1793,15 +1433,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
1793} 1433}
1794#endif 1434#endif
1795#ifdef VFP_INTERPRETER_IMPL 1435#ifdef VFP_INTERPRETER_IMPL
1796VFPLABEL_INST: 1436VNEG_INST:
1797{ 1437{
1798 INC_ICOUNTER;
1799 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1438 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
1800 CHECK_VFP_ENABLED; 1439 CHECK_VFP_ENABLED;
1801 1440
1802 DBG("VNEG :\n"); 1441 DBG("VNEG :\n");
1803 1442
1804 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1443 vneg_inst *inst_cream = (vneg_inst *)inst_base->component;
1805 1444
1806 int ret; 1445 int ret;
1807 1446
@@ -1813,22 +1452,17 @@ VFPLABEL_INST:
1813 CHECK_VFP_CDP_RET; 1452 CHECK_VFP_CDP_RET;
1814 } 1453 }
1815 cpu->Reg[15] += GET_INST_SIZE(cpu); 1454 cpu->Reg[15] += GET_INST_SIZE(cpu);
1816 INC_PC(sizeof(vfpinstr_inst)); 1455 INC_PC(sizeof(vneg_inst));
1817 FETCH_INST; 1456 FETCH_INST;
1818 GOTO_NEXT_INST; 1457 GOTO_NEXT_INST;
1819} 1458}
1820#endif 1459#endif
1821#ifdef VFP_CDP_TRANS 1460
1822if ((OPC_1 & 0xB) == 0xB && CRn == 1 && (OPC_2 & 0x7) == 2)
1823{
1824 DBG("VNEG :\n");
1825}
1826#endif
1827#ifdef VFP_DYNCOM_TABLE 1461#ifdef VFP_DYNCOM_TABLE
1828DYNCOM_FILL_ACTION(vfpinstr), 1462DYNCOM_FILL_ACTION(vneg),
1829#endif 1463#endif
1830#ifdef VFP_DYNCOM_TAG 1464#ifdef VFP_DYNCOM_TAG
1831int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 1465int DYNCOM_TAG(vneg)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
1832{ 1466{
1833 int instr_size = INSTR_SIZE; 1467 int instr_size = INSTR_SIZE;
1834 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 1468 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -1838,7 +1472,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
1838} 1472}
1839#endif 1473#endif
1840#ifdef VFP_DYNCOM_TRANS 1474#ifdef VFP_DYNCOM_TRANS
1841int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 1475int DYNCOM_TRANS(vneg)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
1842 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 1476 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
1843 //arch_arm_undef(cpu, bb, instr); 1477 //arch_arm_undef(cpu, bb, instr);
1844 int single = BIT(8) == 0; 1478 int single = BIT(8) == 0;
@@ -1876,41 +1510,23 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
1876 return No_exp; 1510 return No_exp;
1877} 1511}
1878#endif 1512#endif
1879#undef vfpinstr
1880#undef vfpinstr_inst
1881#undef VFPLABEL_INST
1882 1513
1883/* ----------------------------------------------------------------------- */ 1514/* ----------------------------------------------------------------------- */
1884/* VSQRT */ 1515/* VSQRT */
1885/* cond 1110 1D11 0001 Vd-- 101X 11M0 Vm-- */ 1516/* cond 1110 1D11 0001 Vd-- 101X 11M0 Vm-- */
1886#define vfpinstr vsqrt
1887#define vfpinstr_inst vsqrt_inst
1888#define VFPLABEL_INST VSQRT_INST
1889#ifdef VFP_DECODE
1890{"vsqrt", 5, ARMVFP2, 23, 27, 0x1d, 16, 21, 0x31, 9, 11, 0x5, 6, 7, 3, 4, 4, 0},
1891#endif
1892#ifdef VFP_DECODE_EXCLUSION
1893{"vsqrt", 0, ARMVFP2, 0},
1894#endif
1895#ifdef VFP_INTERPRETER_TABLE
1896INTERPRETER_TRANSLATE(vfpinstr),
1897#endif
1898#ifdef VFP_INTERPRETER_LABEL
1899&&VFPLABEL_INST,
1900#endif
1901#ifdef VFP_INTERPRETER_STRUCT 1517#ifdef VFP_INTERPRETER_STRUCT
1902typedef struct _vsqrt_inst { 1518typedef struct _vsqrt_inst {
1903 unsigned int instr; 1519 unsigned int instr;
1904 unsigned int dp_operation; 1520 unsigned int dp_operation;
1905} vfpinstr_inst; 1521} vsqrt_inst;
1906#endif 1522#endif
1907#ifdef VFP_INTERPRETER_TRANS 1523#ifdef VFP_INTERPRETER_TRANS
1908ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 1524ARM_INST_PTR INTERPRETER_TRANSLATE(vsqrt)(unsigned int inst, int index)
1909{ 1525{
1910 VFP_DEBUG_TRANSLATE; 1526 VFP_DEBUG_TRANSLATE;
1911 1527
1912 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 1528 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vsqrt_inst));
1913 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1529 vsqrt_inst *inst_cream = (vsqrt_inst *)inst_base->component;
1914 1530
1915 inst_base->cond = BITS(inst, 28, 31); 1531 inst_base->cond = BITS(inst, 28, 31);
1916 inst_base->idx = index; 1532 inst_base->idx = index;
@@ -1924,15 +1540,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
1924} 1540}
1925#endif 1541#endif
1926#ifdef VFP_INTERPRETER_IMPL 1542#ifdef VFP_INTERPRETER_IMPL
1927VFPLABEL_INST: 1543VSQRT_INST:
1928{ 1544{
1929 INC_ICOUNTER;
1930 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1545 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
1931 CHECK_VFP_ENABLED; 1546 CHECK_VFP_ENABLED;
1932 1547
1933 DBG("VSQRT :\n"); 1548 DBG("VSQRT :\n");
1934 1549
1935 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1550 vsqrt_inst *inst_cream = (vsqrt_inst *)inst_base->component;
1936 1551
1937 int ret; 1552 int ret;
1938 1553
@@ -1944,22 +1559,17 @@ VFPLABEL_INST:
1944 CHECK_VFP_CDP_RET; 1559 CHECK_VFP_CDP_RET;
1945 } 1560 }
1946 cpu->Reg[15] += GET_INST_SIZE(cpu); 1561 cpu->Reg[15] += GET_INST_SIZE(cpu);
1947 INC_PC(sizeof(vfpinstr_inst)); 1562 INC_PC(sizeof(vsqrt_inst));
1948 FETCH_INST; 1563 FETCH_INST;
1949 GOTO_NEXT_INST; 1564 GOTO_NEXT_INST;
1950} 1565}
1951#endif 1566#endif
1952#ifdef VFP_CDP_TRANS 1567
1953if ((OPC_1 & 0xB) == 0xB && CRn == 1 && (OPC_2 & 0x7) == 6)
1954{
1955 DBG("VSQRT :\n");
1956}
1957#endif
1958#ifdef VFP_DYNCOM_TABLE 1568#ifdef VFP_DYNCOM_TABLE
1959DYNCOM_FILL_ACTION(vfpinstr), 1569DYNCOM_FILL_ACTION(vsqrt),
1960#endif 1570#endif
1961#ifdef VFP_DYNCOM_TAG 1571#ifdef VFP_DYNCOM_TAG
1962int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 1572int DYNCOM_TAG(vsqrt)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
1963{ 1573{
1964 int instr_size = INSTR_SIZE; 1574 int instr_size = INSTR_SIZE;
1965 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 1575 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -1969,7 +1579,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
1969} 1579}
1970#endif 1580#endif
1971#ifdef VFP_DYNCOM_TRANS 1581#ifdef VFP_DYNCOM_TRANS
1972int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 1582int DYNCOM_TRANS(vsqrt)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
1973 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 1583 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
1974 //arch_arm_undef(cpu, bb, instr); 1584 //arch_arm_undef(cpu, bb, instr);
1975 int dp_op = (BIT(8) == 1); 1585 int dp_op = (BIT(8) == 1);
@@ -1995,41 +1605,23 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
1995 return No_exp; 1605 return No_exp;
1996} 1606}
1997#endif 1607#endif
1998#undef vfpinstr
1999#undef vfpinstr_inst
2000#undef VFPLABEL_INST
2001 1608
2002/* ----------------------------------------------------------------------- */ 1609/* ----------------------------------------------------------------------- */
2003/* VCMP VCMPE */ 1610/* VCMP VCMPE */
2004/* cond 1110 1D11 0100 Vd-- 101X E1M0 Vm-- Encoding 1 */ 1611/* cond 1110 1D11 0100 Vd-- 101X E1M0 Vm-- Encoding 1 */
2005#define vfpinstr vcmp
2006#define vfpinstr_inst vcmp_inst
2007#define VFPLABEL_INST VCMP_INST
2008#ifdef VFP_DECODE
2009{"vcmp", 5, ARMVFP2, 23, 27, 0x1d, 16, 21, 0x34, 9, 11, 0x5, 6, 6, 1, 4, 4, 0},
2010#endif
2011#ifdef VFP_DECODE_EXCLUSION
2012{"vcmp", 0, ARMVFP2, 0},
2013#endif
2014#ifdef VFP_INTERPRETER_TABLE
2015INTERPRETER_TRANSLATE(vfpinstr),
2016#endif
2017#ifdef VFP_INTERPRETER_LABEL
2018&&VFPLABEL_INST,
2019#endif
2020#ifdef VFP_INTERPRETER_STRUCT 1612#ifdef VFP_INTERPRETER_STRUCT
2021typedef struct _vcmp_inst { 1613typedef struct _vcmp_inst {
2022 unsigned int instr; 1614 unsigned int instr;
2023 unsigned int dp_operation; 1615 unsigned int dp_operation;
2024} vfpinstr_inst; 1616} vcmp_inst;
2025#endif 1617#endif
2026#ifdef VFP_INTERPRETER_TRANS 1618#ifdef VFP_INTERPRETER_TRANS
2027ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 1619ARM_INST_PTR INTERPRETER_TRANSLATE(vcmp)(unsigned int inst, int index)
2028{ 1620{
2029 VFP_DEBUG_TRANSLATE; 1621 VFP_DEBUG_TRANSLATE;
2030 1622
2031 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 1623 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vcmp_inst));
2032 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1624 vcmp_inst *inst_cream = (vcmp_inst *)inst_base->component;
2033 1625
2034 inst_base->cond = BITS(inst, 28, 31); 1626 inst_base->cond = BITS(inst, 28, 31);
2035 inst_base->idx = index; 1627 inst_base->idx = index;
@@ -2043,15 +1635,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
2043} 1635}
2044#endif 1636#endif
2045#ifdef VFP_INTERPRETER_IMPL 1637#ifdef VFP_INTERPRETER_IMPL
2046VFPLABEL_INST: 1638VCMP_INST:
2047{ 1639{
2048 INC_ICOUNTER;
2049 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1640 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
2050 CHECK_VFP_ENABLED; 1641 CHECK_VFP_ENABLED;
2051 1642
2052 DBG("VCMP(1) :\n"); 1643 DBG("VCMP(1) :\n");
2053 1644
2054 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1645 vcmp_inst *inst_cream = (vcmp_inst *)inst_base->component;
2055 1646
2056 int ret; 1647 int ret;
2057 1648
@@ -2063,22 +1654,17 @@ VFPLABEL_INST:
2063 CHECK_VFP_CDP_RET; 1654 CHECK_VFP_CDP_RET;
2064 } 1655 }
2065 cpu->Reg[15] += GET_INST_SIZE(cpu); 1656 cpu->Reg[15] += GET_INST_SIZE(cpu);
2066 INC_PC(sizeof(vfpinstr_inst)); 1657 INC_PC(sizeof(vcmp_inst));
2067 FETCH_INST; 1658 FETCH_INST;
2068 GOTO_NEXT_INST; 1659 GOTO_NEXT_INST;
2069} 1660}
2070#endif 1661#endif
2071#ifdef VFP_CDP_TRANS 1662
2072if ((OPC_1 & 0xB) == 0xB && CRn == 4 && (OPC_2 & 0x2) == 2)
2073{
2074 DBG("VCMP(1) :\n");
2075}
2076#endif
2077#ifdef VFP_DYNCOM_TABLE 1663#ifdef VFP_DYNCOM_TABLE
2078DYNCOM_FILL_ACTION(vfpinstr), 1664DYNCOM_FILL_ACTION(vcmp),
2079#endif 1665#endif
2080#ifdef VFP_DYNCOM_TAG 1666#ifdef VFP_DYNCOM_TAG
2081int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 1667int DYNCOM_TAG(vcmp)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
2082{ 1668{
2083 int instr_size = INSTR_SIZE; 1669 int instr_size = INSTR_SIZE;
2084 //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); 1670 //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc);
@@ -2087,7 +1673,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
2087} 1673}
2088#endif 1674#endif
2089#ifdef VFP_DYNCOM_TRANS 1675#ifdef VFP_DYNCOM_TRANS
2090int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 1676int DYNCOM_TRANS(vcmp)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
2091 DBG("\t\tin %s instruction is executed out of JIT.\n", __FUNCTION__); 1677 DBG("\t\tin %s instruction is executed out of JIT.\n", __FUNCTION__);
2092 //arch_arm_undef(cpu, bb, instr); 1678 //arch_arm_undef(cpu, bb, instr);
2093 int dp_op = (BIT(8) == 1); 1679 int dp_op = (BIT(8) == 1);
@@ -2141,41 +1727,23 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
2141 return No_exp; 1727 return No_exp;
2142} 1728}
2143#endif 1729#endif
2144#undef vfpinstr
2145#undef vfpinstr_inst
2146#undef VFPLABEL_INST
2147 1730
2148/* ----------------------------------------------------------------------- */ 1731/* ----------------------------------------------------------------------- */
2149/* VCMP VCMPE */ 1732/* VCMP VCMPE */
2150/* cond 1110 1D11 0100 Vd-- 101X E1M0 Vm-- Encoding 2 */ 1733/* cond 1110 1D11 0100 Vd-- 101X E1M0 Vm-- Encoding 2 */
2151#define vfpinstr vcmp2
2152#define vfpinstr_inst vcmp2_inst
2153#define VFPLABEL_INST VCMP2_INST
2154#ifdef VFP_DECODE
2155{"vcmp2", 5, ARMVFP2, 23, 27, 0x1d, 16, 21, 0x35, 9, 11, 0x5, 0, 6, 0x40},
2156#endif
2157#ifdef VFP_DECODE_EXCLUSION
2158{"vcmp2", 0, ARMVFP2, 0},
2159#endif
2160#ifdef VFP_INTERPRETER_TABLE
2161INTERPRETER_TRANSLATE(vfpinstr),
2162#endif
2163#ifdef VFP_INTERPRETER_LABEL
2164&&VFPLABEL_INST,
2165#endif
2166#ifdef VFP_INTERPRETER_STRUCT 1734#ifdef VFP_INTERPRETER_STRUCT
2167typedef struct _vcmp2_inst { 1735typedef struct _vcmp2_inst {
2168 unsigned int instr; 1736 unsigned int instr;
2169 unsigned int dp_operation; 1737 unsigned int dp_operation;
2170} vfpinstr_inst; 1738} vcmp2_inst;
2171#endif 1739#endif
2172#ifdef VFP_INTERPRETER_TRANS 1740#ifdef VFP_INTERPRETER_TRANS
2173ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 1741ARM_INST_PTR INTERPRETER_TRANSLATE(vcmp2)(unsigned int inst, int index)
2174{ 1742{
2175 VFP_DEBUG_TRANSLATE; 1743 VFP_DEBUG_TRANSLATE;
2176 1744
2177 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 1745 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vcmp2_inst));
2178 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1746 vcmp2_inst *inst_cream = (vcmp2_inst *)inst_base->component;
2179 1747
2180 inst_base->cond = BITS(inst, 28, 31); 1748 inst_base->cond = BITS(inst, 28, 31);
2181 inst_base->idx = index; 1749 inst_base->idx = index;
@@ -2189,15 +1757,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
2189} 1757}
2190#endif 1758#endif
2191#ifdef VFP_INTERPRETER_IMPL 1759#ifdef VFP_INTERPRETER_IMPL
2192VFPLABEL_INST: 1760VCMP2_INST:
2193{ 1761{
2194 INC_ICOUNTER;
2195 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1762 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
2196 CHECK_VFP_ENABLED; 1763 CHECK_VFP_ENABLED;
2197 1764
2198 DBG("VCMP(2) :\n"); 1765 DBG("VCMP(2) :\n");
2199 1766
2200 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1767 vcmp2_inst *inst_cream = (vcmp2_inst *)inst_base->component;
2201 1768
2202 int ret; 1769 int ret;
2203 1770
@@ -2209,22 +1776,17 @@ VFPLABEL_INST:
2209 CHECK_VFP_CDP_RET; 1776 CHECK_VFP_CDP_RET;
2210 } 1777 }
2211 cpu->Reg[15] += GET_INST_SIZE(cpu); 1778 cpu->Reg[15] += GET_INST_SIZE(cpu);
2212 INC_PC(sizeof(vfpinstr_inst)); 1779 INC_PC(sizeof(vcmp2_inst));
2213 FETCH_INST; 1780 FETCH_INST;
2214 GOTO_NEXT_INST; 1781 GOTO_NEXT_INST;
2215} 1782}
2216#endif 1783#endif
2217#ifdef VFP_CDP_TRANS 1784
2218if ((OPC_1 & 0xB) == 0xB && CRn == 5 && (OPC_2 & 0x2) == 2 && CRm == 0)
2219{
2220 DBG("VCMP(2) :\n");
2221}
2222#endif
2223#ifdef VFP_DYNCOM_TABLE 1785#ifdef VFP_DYNCOM_TABLE
2224DYNCOM_FILL_ACTION(vfpinstr), 1786DYNCOM_FILL_ACTION(vcmp2),
2225#endif 1787#endif
2226#ifdef VFP_DYNCOM_TAG 1788#ifdef VFP_DYNCOM_TAG
2227int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 1789int DYNCOM_TAG(vcmp2)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
2228{ 1790{
2229 int instr_size = INSTR_SIZE; 1791 int instr_size = INSTR_SIZE;
2230 //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); 1792 //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc);
@@ -2233,7 +1795,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
2233} 1795}
2234#endif 1796#endif
2235#ifdef VFP_DYNCOM_TRANS 1797#ifdef VFP_DYNCOM_TRANS
2236int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 1798int DYNCOM_TRANS(vcmp2)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
2237 DBG("\t\tin %s instruction will executed out of JIT.\n", __FUNCTION__); 1799 DBG("\t\tin %s instruction will executed out of JIT.\n", __FUNCTION__);
2238 //arch_arm_undef(cpu, bb, instr); 1800 //arch_arm_undef(cpu, bb, instr);
2239 int dp_op = (BIT(8) == 1); 1801 int dp_op = (BIT(8) == 1);
@@ -2287,41 +1849,23 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
2287 return No_exp; 1849 return No_exp;
2288} 1850}
2289#endif 1851#endif
2290#undef vfpinstr
2291#undef vfpinstr_inst
2292#undef VFPLABEL_INST
2293 1852
2294/* ----------------------------------------------------------------------- */ 1853/* ----------------------------------------------------------------------- */
2295/* VCVTBDS between double and single */ 1854/* VCVTBDS between double and single */
2296/* cond 1110 1D11 0111 Vd-- 101X 11M0 Vm-- */ 1855/* cond 1110 1D11 0111 Vd-- 101X 11M0 Vm-- */
2297#define vfpinstr vcvtbds
2298#define vfpinstr_inst vcvtbds_inst
2299#define VFPLABEL_INST VCVTBDS_INST
2300#ifdef VFP_DECODE
2301{"vcvt(bds)", 5, ARMVFP2, 23, 27, 0x1d, 16, 21, 0x37, 9, 11, 0x5, 6, 7, 3, 4, 4, 0},
2302#endif
2303#ifdef VFP_DECODE_EXCLUSION
2304{"vcvt(bds)", 0, ARMVFP2, 0},
2305#endif
2306#ifdef VFP_INTERPRETER_TABLE
2307INTERPRETER_TRANSLATE(vfpinstr),
2308#endif
2309#ifdef VFP_INTERPRETER_LABEL
2310&&VFPLABEL_INST,
2311#endif
2312#ifdef VFP_INTERPRETER_STRUCT 1856#ifdef VFP_INTERPRETER_STRUCT
2313typedef struct _vcvtbds_inst { 1857typedef struct _vcvtbds_inst {
2314 unsigned int instr; 1858 unsigned int instr;
2315 unsigned int dp_operation; 1859 unsigned int dp_operation;
2316} vfpinstr_inst; 1860} vcvtbds_inst;
2317#endif 1861#endif
2318#ifdef VFP_INTERPRETER_TRANS 1862#ifdef VFP_INTERPRETER_TRANS
2319ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 1863ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbds)(unsigned int inst, int index)
2320{ 1864{
2321 VFP_DEBUG_TRANSLATE; 1865 VFP_DEBUG_TRANSLATE;
2322 1866
2323 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 1867 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vcvtbds_inst));
2324 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1868 vcvtbds_inst *inst_cream = (vcvtbds_inst *)inst_base->component;
2325 1869
2326 inst_base->cond = BITS(inst, 28, 31); 1870 inst_base->cond = BITS(inst, 28, 31);
2327 inst_base->idx = index; 1871 inst_base->idx = index;
@@ -2335,15 +1879,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
2335} 1879}
2336#endif 1880#endif
2337#ifdef VFP_INTERPRETER_IMPL 1881#ifdef VFP_INTERPRETER_IMPL
2338VFPLABEL_INST: 1882VCVTBDS_INST:
2339{ 1883{
2340 INC_ICOUNTER;
2341 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1884 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
2342 CHECK_VFP_ENABLED; 1885 CHECK_VFP_ENABLED;
2343 1886
2344 DBG("VCVT(BDS) :\n"); 1887 DBG("VCVT(BDS) :\n");
2345 1888
2346 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1889 vcvtbds_inst *inst_cream = (vcvtbds_inst *)inst_base->component;
2347 1890
2348 int ret; 1891 int ret;
2349 1892
@@ -2355,22 +1898,17 @@ VFPLABEL_INST:
2355 CHECK_VFP_CDP_RET; 1898 CHECK_VFP_CDP_RET;
2356 } 1899 }
2357 cpu->Reg[15] += GET_INST_SIZE(cpu); 1900 cpu->Reg[15] += GET_INST_SIZE(cpu);
2358 INC_PC(sizeof(vfpinstr_inst)); 1901 INC_PC(sizeof(vcvtbds_inst));
2359 FETCH_INST; 1902 FETCH_INST;
2360 GOTO_NEXT_INST; 1903 GOTO_NEXT_INST;
2361} 1904}
2362#endif 1905#endif
2363#ifdef VFP_CDP_TRANS 1906
2364if ((OPC_1 & 0xB) == 0xB && CRn == 7 && (OPC_2 & 0x6) == 6)
2365{
2366 DBG("VCVT(BDS) :\n");
2367}
2368#endif
2369#ifdef VFP_DYNCOM_TABLE 1907#ifdef VFP_DYNCOM_TABLE
2370DYNCOM_FILL_ACTION(vfpinstr), 1908DYNCOM_FILL_ACTION(vcvtbds),
2371#endif 1909#endif
2372#ifdef VFP_DYNCOM_TAG 1910#ifdef VFP_DYNCOM_TAG
2373int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 1911int DYNCOM_TAG(vcvtbds)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
2374{ 1912{
2375 int instr_size = INSTR_SIZE; 1913 int instr_size = INSTR_SIZE;
2376 //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc); 1914 //arm_tag_trap(cpu, pc, instr, tag, new_pc, next_pc);
@@ -2379,7 +1917,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
2379} 1917}
2380#endif 1918#endif
2381#ifdef VFP_DYNCOM_TRANS 1919#ifdef VFP_DYNCOM_TRANS
2382int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 1920int DYNCOM_TRANS(vcvtbds)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
2383 DBG("\t\tin %s instruction is executed out.\n", __FUNCTION__); 1921 DBG("\t\tin %s instruction is executed out.\n", __FUNCTION__);
2384 //arch_arm_undef(cpu, bb, instr); 1922 //arch_arm_undef(cpu, bb, instr);
2385 int dp_op = (BIT(8) == 1); 1923 int dp_op = (BIT(8) == 1);
@@ -2407,41 +1945,23 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
2407 return No_exp; 1945 return No_exp;
2408} 1946}
2409#endif 1947#endif
2410#undef vfpinstr
2411#undef vfpinstr_inst
2412#undef VFPLABEL_INST
2413 1948
2414/* ----------------------------------------------------------------------- */ 1949/* ----------------------------------------------------------------------- */
2415/* VCVTBFF between floating point and fixed point */ 1950/* VCVTBFF between floating point and fixed point */
2416/* cond 1110 1D11 1op2 Vd-- 101X X1M0 Vm-- */ 1951/* cond 1110 1D11 1op2 Vd-- 101X X1M0 Vm-- */
2417#define vfpinstr vcvtbff
2418#define vfpinstr_inst vcvtbff_inst
2419#define VFPLABEL_INST VCVTBFF_INST
2420#ifdef VFP_DECODE
2421{"vcvt(bff)", 6, ARMVFP3, 23, 27, 0x1d, 19, 21, 0x7, 17, 17, 0x1, 9, 11, 0x5, 6, 6, 1},
2422#endif
2423#ifdef VFP_DECODE_EXCLUSION
2424{"vcvt(bff)", 0, ARMVFP3, 4, 4, 1},
2425#endif
2426#ifdef VFP_INTERPRETER_TABLE
2427INTERPRETER_TRANSLATE(vfpinstr),
2428#endif
2429#ifdef VFP_INTERPRETER_LABEL
2430&&VFPLABEL_INST,
2431#endif
2432#ifdef VFP_INTERPRETER_STRUCT 1952#ifdef VFP_INTERPRETER_STRUCT
2433typedef struct _vcvtbff_inst { 1953typedef struct _vcvtbff_inst {
2434 unsigned int instr; 1954 unsigned int instr;
2435 unsigned int dp_operation; 1955 unsigned int dp_operation;
2436} vfpinstr_inst; 1956} vcvtbff_inst;
2437#endif 1957#endif
2438#ifdef VFP_INTERPRETER_TRANS 1958#ifdef VFP_INTERPRETER_TRANS
2439ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 1959ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbff)(unsigned int inst, int index)
2440{ 1960{
2441 VFP_DEBUG_TRANSLATE;VFP_DEBUG_UNTESTED(VCVTBFF); 1961 VFP_DEBUG_TRANSLATE;VFP_DEBUG_UNTESTED(VCVTBFF);
2442 1962
2443 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 1963 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vcvtbff_inst));
2444 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1964 vcvtbff_inst *inst_cream = (vcvtbff_inst *)inst_base->component;
2445 1965
2446 inst_base->cond = BITS(inst, 28, 31); 1966 inst_base->cond = BITS(inst, 28, 31);
2447 inst_base->idx = index; 1967 inst_base->idx = index;
@@ -2455,15 +1975,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
2455} 1975}
2456#endif 1976#endif
2457#ifdef VFP_INTERPRETER_IMPL 1977#ifdef VFP_INTERPRETER_IMPL
2458VFPLABEL_INST: 1978VCVTBFF_INST:
2459{ 1979{
2460 INC_ICOUNTER;
2461 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1980 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
2462 CHECK_VFP_ENABLED; 1981 CHECK_VFP_ENABLED;
2463 1982
2464 DBG("VCVT(BFF) :\n"); 1983 DBG("VCVT(BFF) :\n");
2465 1984
2466 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 1985 vcvtbff_inst *inst_cream = (vcvtbff_inst *)inst_base->component;
2467 1986
2468 int ret; 1987 int ret;
2469 1988
@@ -2475,22 +1994,17 @@ VFPLABEL_INST:
2475 CHECK_VFP_CDP_RET; 1994 CHECK_VFP_CDP_RET;
2476 } 1995 }
2477 cpu->Reg[15] += GET_INST_SIZE(cpu); 1996 cpu->Reg[15] += GET_INST_SIZE(cpu);
2478 INC_PC(sizeof(vfpinstr_inst)); 1997 INC_PC(sizeof(vcvtbff_inst));
2479 FETCH_INST; 1998 FETCH_INST;
2480 GOTO_NEXT_INST; 1999 GOTO_NEXT_INST;
2481} 2000}
2482#endif 2001#endif
2483#ifdef VFP_CDP_TRANS 2002
2484if ((OPC_1 & 0xB) == 0xB && CRn >= 0xA && (OPC_2 & 0x2) == 2)
2485{
2486 DBG("VCVT(BFF) :\n");
2487}
2488#endif
2489#ifdef VFP_DYNCOM_TABLE 2003#ifdef VFP_DYNCOM_TABLE
2490DYNCOM_FILL_ACTION(vfpinstr), 2004DYNCOM_FILL_ACTION(vcvtbff),
2491#endif 2005#endif
2492#ifdef VFP_DYNCOM_TAG 2006#ifdef VFP_DYNCOM_TAG
2493int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 2007int DYNCOM_TAG(vcvtbff)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
2494{ 2008{
2495 int instr_size = INSTR_SIZE; 2009 int instr_size = INSTR_SIZE;
2496 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 2010 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -2499,47 +2013,29 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
2499} 2013}
2500#endif 2014#endif
2501#ifdef VFP_DYNCOM_TRANS 2015#ifdef VFP_DYNCOM_TRANS
2502int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 2016int DYNCOM_TRANS(vcvtbff)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
2503 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 2017 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
2504 arch_arm_undef(cpu, bb, instr); 2018 arch_arm_undef(cpu, bb, instr);
2505 return No_exp; 2019 return No_exp;
2506} 2020}
2507#endif 2021#endif
2508#undef vfpinstr
2509#undef vfpinstr_inst
2510#undef VFPLABEL_INST
2511 2022
2512/* ----------------------------------------------------------------------- */ 2023/* ----------------------------------------------------------------------- */
2513/* VCVTBFI between floating point and integer */ 2024/* VCVTBFI between floating point and integer */
2514/* cond 1110 1D11 1op2 Vd-- 101X X1M0 Vm-- */ 2025/* cond 1110 1D11 1op2 Vd-- 101X X1M0 Vm-- */
2515#define vfpinstr vcvtbfi
2516#define vfpinstr_inst vcvtbfi_inst
2517#define VFPLABEL_INST VCVTBFI_INST
2518#ifdef VFP_DECODE
2519{"vcvt(bfi)", 5, ARMVFP2, 23, 27, 0x1d, 19, 21, 0x7, 9, 11, 0x5, 6, 6, 1, 4, 4, 0},
2520#endif
2521#ifdef VFP_DECODE_EXCLUSION
2522{"vcvt(bfi)", 0, ARMVFP2, 0},
2523#endif
2524#ifdef VFP_INTERPRETER_TABLE
2525INTERPRETER_TRANSLATE(vfpinstr),
2526#endif
2527#ifdef VFP_INTERPRETER_LABEL
2528&&VFPLABEL_INST,
2529#endif
2530#ifdef VFP_INTERPRETER_STRUCT 2026#ifdef VFP_INTERPRETER_STRUCT
2531typedef struct _vcvtbfi_inst { 2027typedef struct _vcvtbfi_inst {
2532 unsigned int instr; 2028 unsigned int instr;
2533 unsigned int dp_operation; 2029 unsigned int dp_operation;
2534} vfpinstr_inst; 2030} vcvtbfi_inst;
2535#endif 2031#endif
2536#ifdef VFP_INTERPRETER_TRANS 2032#ifdef VFP_INTERPRETER_TRANS
2537ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 2033ARM_INST_PTR INTERPRETER_TRANSLATE(vcvtbfi)(unsigned int inst, int index)
2538{ 2034{
2539 VFP_DEBUG_TRANSLATE; 2035 VFP_DEBUG_TRANSLATE;
2540 2036
2541 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 2037 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vcvtbfi_inst));
2542 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2038 vcvtbfi_inst *inst_cream = (vcvtbfi_inst *)inst_base->component;
2543 2039
2544 inst_base->cond = BITS(inst, 28, 31); 2040 inst_base->cond = BITS(inst, 28, 31);
2545 inst_base->idx = index; 2041 inst_base->idx = index;
@@ -2554,15 +2050,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
2554} 2050}
2555#endif 2051#endif
2556#ifdef VFP_INTERPRETER_IMPL 2052#ifdef VFP_INTERPRETER_IMPL
2557VFPLABEL_INST: 2053VCVTBFI_INST:
2558{ 2054{
2559 INC_ICOUNTER;
2560 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 2055 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
2561 CHECK_VFP_ENABLED; 2056 CHECK_VFP_ENABLED;
2562 2057
2563 DBG("VCVT(BFI) :\n"); 2058 DBG("VCVT(BFI) :\n");
2564 2059
2565 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2060 vcvtbfi_inst *inst_cream = (vcvtbfi_inst *)inst_base->component;
2566 2061
2567 int ret; 2062 int ret;
2568 2063
@@ -2574,22 +2069,17 @@ VFPLABEL_INST:
2574 CHECK_VFP_CDP_RET; 2069 CHECK_VFP_CDP_RET;
2575 } 2070 }
2576 cpu->Reg[15] += GET_INST_SIZE(cpu); 2071 cpu->Reg[15] += GET_INST_SIZE(cpu);
2577 INC_PC(sizeof(vfpinstr_inst)); 2072 INC_PC(sizeof(vcvtbfi_inst));
2578 FETCH_INST; 2073 FETCH_INST;
2579 GOTO_NEXT_INST; 2074 GOTO_NEXT_INST;
2580} 2075}
2581#endif 2076#endif
2582#ifdef VFP_CDP_TRANS 2077
2583if ((OPC_1 & 0xB) == 0xB && CRn > 7 && (OPC_2 & 0x2) == 2)
2584{
2585 DBG("VCVT(BFI) :\n");
2586}
2587#endif
2588#ifdef VFP_DYNCOM_TABLE 2078#ifdef VFP_DYNCOM_TABLE
2589DYNCOM_FILL_ACTION(vfpinstr), 2079DYNCOM_FILL_ACTION(vcvtbfi),
2590#endif 2080#endif
2591#ifdef VFP_DYNCOM_TAG 2081#ifdef VFP_DYNCOM_TAG
2592int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 2082int DYNCOM_TAG(vcvtbfi)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
2593{ 2083{
2594 int instr_size = INSTR_SIZE; 2084 int instr_size = INSTR_SIZE;
2595 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 2085 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -2600,7 +2090,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
2600} 2090}
2601#endif 2091#endif
2602#ifdef VFP_DYNCOM_TRANS 2092#ifdef VFP_DYNCOM_TRANS
2603int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 2093int DYNCOM_TRANS(vcvtbfi)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
2604 DBG("\t\tin %s, instruction will be executed out of JIT.\n", __FUNCTION__); 2094 DBG("\t\tin %s, instruction will be executed out of JIT.\n", __FUNCTION__);
2605 //arch_arm_undef(cpu, bb, instr); 2095 //arch_arm_undef(cpu, bb, instr);
2606 unsigned int opc2 = BITS(16,18); 2096 unsigned int opc2 = BITS(16,18);
@@ -2694,9 +2184,6 @@ int vcvtbfi_instr_impl(arm_core_t* cpu, uint32 instr){
2694 return 0; 2184 return 0;
2695} 2185}
2696#endif 2186#endif
2697#undef vfpinstr
2698#undef vfpinstr_inst
2699#undef VFPLABEL_INST
2700 2187
2701/* ----------------------------------------------------------------------- */ 2188/* ----------------------------------------------------------------------- */
2702/* MRC / MCR instructions */ 2189/* MRC / MCR instructions */
@@ -2707,35 +2194,20 @@ int vcvtbfi_instr_impl(arm_core_t* cpu, uint32 instr){
2707/* VMOVBRS between register and single precision */ 2194/* VMOVBRS between register and single precision */
2708/* cond 1110 000o Vn-- Rt-- 1010 N001 0000 */ 2195/* cond 1110 000o Vn-- Rt-- 1010 N001 0000 */
2709/* cond 1110 op11 CRn- Rt-- copr op21 CRm- MRC */ 2196/* cond 1110 op11 CRn- Rt-- copr op21 CRm- MRC */
2710#define vfpinstr vmovbrs
2711#define vfpinstr_inst vmovbrs_inst
2712#define VFPLABEL_INST VMOVBRS_INST
2713#ifdef VFP_DECODE
2714{"vmovbrs", 3, ARMVFP2, 21, 27, 0x70, 8, 11, 0xA, 0, 6, 0x10},
2715#endif
2716#ifdef VFP_DECODE_EXCLUSION
2717{"vmovbrs", 0, ARMVFP2, 0},
2718#endif
2719#ifdef VFP_INTERPRETER_TABLE
2720INTERPRETER_TRANSLATE(vfpinstr),
2721#endif
2722#ifdef VFP_INTERPRETER_LABEL
2723&&VFPLABEL_INST,
2724#endif
2725#ifdef VFP_INTERPRETER_STRUCT 2197#ifdef VFP_INTERPRETER_STRUCT
2726typedef struct _vmovbrs_inst { 2198typedef struct _vmovbrs_inst {
2727 unsigned int to_arm; 2199 unsigned int to_arm;
2728 unsigned int t; 2200 unsigned int t;
2729 unsigned int n; 2201 unsigned int n;
2730} vfpinstr_inst; 2202} vmovbrs_inst;
2731#endif 2203#endif
2732#ifdef VFP_INTERPRETER_TRANS 2204#ifdef VFP_INTERPRETER_TRANS
2733ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 2205ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrs)(unsigned int inst, int index)
2734{ 2206{
2735 VFP_DEBUG_TRANSLATE; 2207 VFP_DEBUG_TRANSLATE;
2736 2208
2737 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 2209 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbrs_inst));
2738 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2210 vmovbrs_inst *inst_cream = (vmovbrs_inst *)inst_base->component;
2739 2211
2740 inst_base->cond = BITS(inst, 28, 31); 2212 inst_base->cond = BITS(inst, 28, 31);
2741 inst_base->idx = index; 2213 inst_base->idx = index;
@@ -2750,61 +2222,27 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
2750} 2222}
2751#endif 2223#endif
2752#ifdef VFP_INTERPRETER_IMPL 2224#ifdef VFP_INTERPRETER_IMPL
2753VFPLABEL_INST: 2225VMOVBRS_INST:
2754{ 2226{
2755 INC_ICOUNTER;
2756 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 2227 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
2757 CHECK_VFP_ENABLED; 2228 CHECK_VFP_ENABLED;
2758 2229
2759 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2230 vmovbrs_inst *inst_cream = (vmovbrs_inst *)inst_base->component;
2760 2231
2761 VMOVBRS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->n, &(cpu->Reg[inst_cream->t])); 2232 VMOVBRS(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->n, &(cpu->Reg[inst_cream->t]));
2762 } 2233 }
2763 cpu->Reg[15] += GET_INST_SIZE(cpu); 2234 cpu->Reg[15] += GET_INST_SIZE(cpu);
2764 INC_PC(sizeof(vfpinstr_inst)); 2235 INC_PC(sizeof(vmovbrs_inst));
2765 FETCH_INST; 2236 FETCH_INST;
2766 GOTO_NEXT_INST; 2237 GOTO_NEXT_INST;
2767} 2238}
2768#endif 2239#endif
2769#ifdef VFP_MRC_TRANS 2240
2770if (OPC_1 == 0x0 && CRm == 0 && (OPC_2 & 0x3) == 0)
2771{
2772 /* VMOV r to s */
2773 /* Transfering Rt is not mandatory, as the value of interest is pointed by value */
2774 VMOVBRS(state, BIT(20), Rt, BIT(7)|CRn<<1, value);
2775 return ARMul_DONE;
2776}
2777#endif
2778#ifdef VFP_MCR_TRANS
2779if (OPC_1 == 0x0 && CRm == 0 && (OPC_2 & 0x3) == 0)
2780{
2781 /* VMOV s to r */
2782 /* Transfering Rt is not mandatory, as the value of interest is pointed by value */
2783 VMOVBRS(state, BIT(20), Rt, BIT(7)|CRn<<1, &value);
2784 return ARMul_DONE;
2785}
2786#endif
2787#ifdef VFP_MRC_IMPL
2788void VMOVBRS(ARMul_State * state, ARMword to_arm, ARMword t, ARMword n, ARMword *value)
2789{
2790 DBG("VMOV(BRS) :\n");
2791 if (to_arm)
2792 {
2793 DBG("\tr%d <= s%d=[%x]\n", t, n, state->ExtReg[n]);
2794 *value = state->ExtReg[n];
2795 }
2796 else
2797 {
2798 DBG("\ts%d <= r%d=[%x]\n", n, t, *value);
2799 state->ExtReg[n] = *value;
2800 }
2801}
2802#endif
2803#ifdef VFP_DYNCOM_TABLE 2241#ifdef VFP_DYNCOM_TABLE
2804DYNCOM_FILL_ACTION(vfpinstr), 2242DYNCOM_FILL_ACTION(vmovbrs),
2805#endif 2243#endif
2806#ifdef VFP_DYNCOM_TAG 2244#ifdef VFP_DYNCOM_TAG
2807int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 2245int DYNCOM_TAG(vmovbrs)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
2808{ 2246{
2809 int instr_size = INSTR_SIZE; 2247 int instr_size = INSTR_SIZE;
2810 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 2248 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -2813,7 +2251,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
2813} 2251}
2814#endif 2252#endif
2815#ifdef VFP_DYNCOM_TRANS 2253#ifdef VFP_DYNCOM_TRANS
2816int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 2254int DYNCOM_TRANS(vmovbrs)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
2817 DBG("VMOV(BRS) :\n"); 2255 DBG("VMOV(BRS) :\n");
2818 int to_arm = BIT(20) == 1; 2256 int to_arm = BIT(20) == 1;
2819 int t = BITS(12, 15); 2257 int t = BITS(12, 15);
@@ -2832,42 +2270,24 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
2832 return No_exp; 2270 return No_exp;
2833} 2271}
2834#endif 2272#endif
2835#undef vfpinstr
2836#undef vfpinstr_inst
2837#undef VFPLABEL_INST
2838 2273
2839/* ----------------------------------------------------------------------- */ 2274/* ----------------------------------------------------------------------- */
2840/* VMSR */ 2275/* VMSR */
2841/* cond 1110 1110 reg- Rt-- 1010 0001 0000 */ 2276/* cond 1110 1110 reg- Rt-- 1010 0001 0000 */
2842/* cond 1110 op10 CRn- Rt-- copr op21 CRm- MCR */ 2277/* cond 1110 op10 CRn- Rt-- copr op21 CRm- MCR */
2843#define vfpinstr vmsr
2844#define vfpinstr_inst vmsr_inst
2845#define VFPLABEL_INST VMSR_INST
2846#ifdef VFP_DECODE
2847{"vmsr", 2, ARMVFP2, 20, 27, 0xEE, 0, 11, 0xA10},
2848#endif
2849#ifdef VFP_DECODE_EXCLUSION
2850{"vmsr", 0, ARMVFP2, 0},
2851#endif
2852#ifdef VFP_INTERPRETER_TABLE
2853INTERPRETER_TRANSLATE(vfpinstr),
2854#endif
2855#ifdef VFP_INTERPRETER_LABEL
2856&&VFPLABEL_INST,
2857#endif
2858#ifdef VFP_INTERPRETER_STRUCT 2278#ifdef VFP_INTERPRETER_STRUCT
2859typedef struct _vmsr_inst { 2279typedef struct _vmsr_inst {
2860 unsigned int reg; 2280 unsigned int reg;
2861 unsigned int Rd; 2281 unsigned int Rd;
2862} vfpinstr_inst; 2282} vmsr_inst;
2863#endif 2283#endif
2864#ifdef VFP_INTERPRETER_TRANS 2284#ifdef VFP_INTERPRETER_TRANS
2865ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 2285ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index)
2866{ 2286{
2867 VFP_DEBUG_TRANSLATE; 2287 VFP_DEBUG_TRANSLATE;
2868 2288
2869 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 2289 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vmsr_inst));
2870 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2290 vmsr_inst *inst_cream = (vmsr_inst *)inst_base->component;
2871 2291
2872 inst_base->cond = BITS(inst, 28, 31); 2292 inst_base->cond = BITS(inst, 28, 31);
2873 inst_base->idx = index; 2293 inst_base->idx = index;
@@ -2881,52 +2301,30 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
2881} 2301}
2882#endif 2302#endif
2883#ifdef VFP_INTERPRETER_IMPL 2303#ifdef VFP_INTERPRETER_IMPL
2884VFPLABEL_INST: 2304VMSR_INST:
2885{ 2305{
2886 INC_ICOUNTER;
2887 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 2306 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
2888 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled , 2307 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled ,
2889 and in privilegied mode */ 2308 and in privilegied mode */
2890 /* Exceptions must be checked, according to v7 ref manual */ 2309 /* Exceptions must be checked, according to v7 ref manual */
2891 CHECK_VFP_ENABLED; 2310 CHECK_VFP_ENABLED;
2892 2311
2893 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2312 vmsr_inst *inst_cream = (vmsr_inst *)inst_base->component;
2894 2313
2895 VMSR(cpu, inst_cream->reg, inst_cream->Rd); 2314 VMSR(cpu, inst_cream->reg, inst_cream->Rd);
2896 } 2315 }
2897 cpu->Reg[15] += GET_INST_SIZE(cpu); 2316 cpu->Reg[15] += GET_INST_SIZE(cpu);
2898 INC_PC(sizeof(vfpinstr_inst)); 2317 INC_PC(sizeof(vmsr_inst));
2899 FETCH_INST; 2318 FETCH_INST;
2900 GOTO_NEXT_INST; 2319 GOTO_NEXT_INST;
2901} 2320}
2902#endif 2321#endif
2903#ifdef VFP_MCR_TRANS 2322
2904if (OPC_1 == 0x7 && CRm == 0 && OPC_2 == 0)
2905{
2906 VMSR(state, CRn, Rt);
2907 return ARMul_DONE;
2908}
2909#endif
2910#ifdef VFP_MCR_IMPL
2911void VMSR(ARMul_State * state, ARMword reg, ARMword Rt)
2912{
2913 if (reg == 1)
2914 {
2915 DBG("VMSR :\tfpscr <= r%d=[%x]\n", Rt, state->Reg[Rt]);
2916 state->VFP[VFP_OFFSET(VFP_FPSCR)] = state->Reg[Rt];
2917 }
2918 else if (reg == 8)
2919 {
2920 DBG("VMSR :\tfpexc <= r%d=[%x]\n", Rt, state->Reg[Rt]);
2921 state->VFP[VFP_OFFSET(VFP_FPEXC)] = state->Reg[Rt];
2922 }
2923}
2924#endif
2925#ifdef VFP_DYNCOM_TABLE 2323#ifdef VFP_DYNCOM_TABLE
2926DYNCOM_FILL_ACTION(vfpinstr), 2324DYNCOM_FILL_ACTION(vmsr),
2927#endif 2325#endif
2928#ifdef VFP_DYNCOM_TAG 2326#ifdef VFP_DYNCOM_TAG
2929int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 2327int DYNCOM_TAG(vmsr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
2930{ 2328{
2931 int instr_size = INSTR_SIZE; 2329 int instr_size = INSTR_SIZE;
2932 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 2330 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -2936,7 +2334,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
2936} 2334}
2937#endif 2335#endif
2938#ifdef VFP_DYNCOM_TRANS 2336#ifdef VFP_DYNCOM_TRANS
2939int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 2337int DYNCOM_TRANS(vmsr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
2940 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 2338 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
2941 //arch_arm_undef(cpu, bb, instr); 2339 //arch_arm_undef(cpu, bb, instr);
2942 DBG("VMSR :"); 2340 DBG("VMSR :");
@@ -2969,44 +2367,26 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
2969 return No_exp; 2367 return No_exp;
2970} 2368}
2971#endif 2369#endif
2972#undef vfpinstr
2973#undef vfpinstr_inst
2974#undef VFPLABEL_INST
2975 2370
2976/* ----------------------------------------------------------------------- */ 2371/* ----------------------------------------------------------------------- */
2977/* VMOVBRC register to scalar */ 2372/* VMOVBRC register to scalar */
2978/* cond 1110 0XX0 Vd-- Rt-- 1011 DXX1 0000 */ 2373/* cond 1110 0XX0 Vd-- Rt-- 1011 DXX1 0000 */
2979/* cond 1110 op10 CRn- Rt-- copr op21 CRm- MCR */ 2374/* cond 1110 op10 CRn- Rt-- copr op21 CRm- MCR */
2980#define vfpinstr vmovbrc
2981#define vfpinstr_inst vmovbrc_inst
2982#define VFPLABEL_INST VMOVBRC_INST
2983#ifdef VFP_DECODE
2984{"vmovbrc", 4, ARMVFP2, 23, 27, 0x1C, 20, 20, 0x0, 8,11,0xB, 0,4,0x10},
2985#endif
2986#ifdef VFP_DECODE_EXCLUSION
2987{"vmovbrc", 0, ARMVFP2, 0},
2988#endif
2989#ifdef VFP_INTERPRETER_TABLE
2990INTERPRETER_TRANSLATE(vfpinstr),
2991#endif
2992#ifdef VFP_INTERPRETER_LABEL
2993&&VFPLABEL_INST,
2994#endif
2995#ifdef VFP_INTERPRETER_STRUCT 2375#ifdef VFP_INTERPRETER_STRUCT
2996typedef struct _vmovbrc_inst { 2376typedef struct _vmovbrc_inst {
2997 unsigned int esize; 2377 unsigned int esize;
2998 unsigned int index; 2378 unsigned int index;
2999 unsigned int d; 2379 unsigned int d;
3000 unsigned int t; 2380 unsigned int t;
3001} vfpinstr_inst; 2381} vmovbrc_inst;
3002#endif 2382#endif
3003#ifdef VFP_INTERPRETER_TRANS 2383#ifdef VFP_INTERPRETER_TRANS
3004ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 2384ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrc)(unsigned int inst, int index)
3005{ 2385{
3006 VFP_DEBUG_TRANSLATE; 2386 VFP_DEBUG_TRANSLATE;
3007 2387
3008 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 2388 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbrc_inst));
3009 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2389 vmovbrc_inst *inst_cream = (vmovbrc_inst *)inst_base->component;
3010 2390
3011 inst_base->cond = BITS(inst, 28, 31); 2391 inst_base->cond = BITS(inst, 28, 31);
3012 inst_base->idx = index; 2392 inst_base->idx = index;
@@ -3023,34 +2403,27 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
3023} 2403}
3024#endif 2404#endif
3025#ifdef VFP_INTERPRETER_IMPL 2405#ifdef VFP_INTERPRETER_IMPL
3026VFPLABEL_INST: 2406VMOVBRC_INST:
3027{ 2407{
3028 INC_ICOUNTER;
3029 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 2408 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
3030 CHECK_VFP_ENABLED; 2409 CHECK_VFP_ENABLED;
3031 2410
3032 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2411 vmovbrc_inst *inst_cream = (vmovbrc_inst *)inst_base->component;
3033 2412
3034 VFP_DEBUG_UNIMPLEMENTED(VMOVBRC); 2413 VFP_DEBUG_UNIMPLEMENTED(VMOVBRC);
3035 } 2414 }
3036 cpu->Reg[15] += GET_INST_SIZE(cpu); 2415 cpu->Reg[15] += GET_INST_SIZE(cpu);
3037 INC_PC(sizeof(vfpinstr_inst)); 2416 INC_PC(sizeof(vmovbrc_inst));
3038 FETCH_INST; 2417 FETCH_INST;
3039 GOTO_NEXT_INST; 2418 GOTO_NEXT_INST;
3040} 2419}
3041#endif 2420#endif
3042#ifdef VFP_MCR_TRANS 2421
3043if ((OPC_1 & 0x4) == 0 && CoProc == 11 && CRm == 0)
3044{
3045 VFP_DEBUG_UNIMPLEMENTED(VMOVBRC);
3046 return ARMul_DONE;
3047}
3048#endif
3049#ifdef VFP_DYNCOM_TABLE 2422#ifdef VFP_DYNCOM_TABLE
3050DYNCOM_FILL_ACTION(vfpinstr), 2423DYNCOM_FILL_ACTION(vmovbrc),
3051#endif 2424#endif
3052#ifdef VFP_DYNCOM_TAG 2425#ifdef VFP_DYNCOM_TAG
3053int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 2426int DYNCOM_TAG(vmovbrc)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
3054{ 2427{
3055 int instr_size = INSTR_SIZE; 2428 int instr_size = INSTR_SIZE;
3056 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 2429 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -3059,48 +2432,30 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
3059} 2432}
3060#endif 2433#endif
3061#ifdef VFP_DYNCOM_TRANS 2434#ifdef VFP_DYNCOM_TRANS
3062int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 2435int DYNCOM_TRANS(vmovbrc)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
3063 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 2436 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
3064 arch_arm_undef(cpu, bb, instr); 2437 arch_arm_undef(cpu, bb, instr);
3065 return No_exp; 2438 return No_exp;
3066} 2439}
3067#endif 2440#endif
3068#undef vfpinstr
3069#undef vfpinstr_inst
3070#undef VFPLABEL_INST
3071 2441
3072/* ----------------------------------------------------------------------- */ 2442/* ----------------------------------------------------------------------- */
3073/* VMRS */ 2443/* VMRS */
3074/* cond 1110 1111 CRn- Rt-- 1010 0001 0000 */ 2444/* cond 1110 1111 CRn- Rt-- 1010 0001 0000 */
3075/* cond 1110 op11 CRn- Rt-- copr op21 CRm- MRC */ 2445/* cond 1110 op11 CRn- Rt-- copr op21 CRm- MRC */
3076#define vfpinstr vmrs
3077#define vfpinstr_inst vmrs_inst
3078#define VFPLABEL_INST VMRS_INST
3079#ifdef VFP_DECODE
3080{"vmrs", 2, ARMVFP2, 20, 27, 0xEF, 0, 11, 0xa10},
3081#endif
3082#ifdef VFP_DECODE_EXCLUSION
3083{"vmrs", 0, ARMVFP2, 0},
3084#endif
3085#ifdef VFP_INTERPRETER_TABLE
3086INTERPRETER_TRANSLATE(vfpinstr),
3087#endif
3088#ifdef VFP_INTERPRETER_LABEL
3089&&VFPLABEL_INST,
3090#endif
3091#ifdef VFP_INTERPRETER_STRUCT 2446#ifdef VFP_INTERPRETER_STRUCT
3092typedef struct _vmrs_inst { 2447typedef struct _vmrs_inst {
3093 unsigned int reg; 2448 unsigned int reg;
3094 unsigned int Rt; 2449 unsigned int Rt;
3095} vfpinstr_inst; 2450} vmrs_inst;
3096#endif 2451#endif
3097#ifdef VFP_INTERPRETER_TRANS 2452#ifdef VFP_INTERPRETER_TRANS
3098ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 2453ARM_INST_PTR INTERPRETER_TRANSLATE(vmrs)(unsigned int inst, int index)
3099{ 2454{
3100 VFP_DEBUG_TRANSLATE; 2455 VFP_DEBUG_TRANSLATE;
3101 2456
3102 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 2457 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vmrs_inst));
3103 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2458 vmrs_inst *inst_cream = (vmrs_inst *)inst_base->component;
3104 2459
3105 inst_base->cond = BITS(inst, 28, 31); 2460 inst_base->cond = BITS(inst, 28, 31);
3106 inst_base->idx = index; 2461 inst_base->idx = index;
@@ -3109,21 +2464,20 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
3109 2464
3110 inst_cream->reg = BITS(inst, 16, 19); 2465 inst_cream->reg = BITS(inst, 16, 19);
3111 inst_cream->Rt = BITS(inst, 12, 15); 2466 inst_cream->Rt = BITS(inst, 12, 15);
3112 2467
3113 return inst_base; 2468 return inst_base;
3114} 2469}
3115#endif 2470#endif
3116#ifdef VFP_INTERPRETER_IMPL 2471#ifdef VFP_INTERPRETER_IMPL
3117VFPLABEL_INST: 2472VMRS_INST:
3118{ 2473{
3119 INC_ICOUNTER;
3120 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 2474 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
3121 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled, 2475 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled,
3122 and in privilegied mode */ 2476 and in privilegied mode */
3123 /* Exceptions must be checked, according to v7 ref manual */ 2477 /* Exceptions must be checked, according to v7 ref manual */
3124 CHECK_VFP_ENABLED; 2478 CHECK_VFP_ENABLED;
3125 2479
3126 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2480 vmrs_inst *inst_cream = (vmrs_inst *)inst_base->component;
3127 2481
3128 DBG("VMRS :"); 2482 DBG("VMRS :");
3129 2483
@@ -3170,67 +2524,17 @@ VFPLABEL_INST:
3170 } 2524 }
3171 } 2525 }
3172 cpu->Reg[15] += GET_INST_SIZE(cpu); 2526 cpu->Reg[15] += GET_INST_SIZE(cpu);
3173 INC_PC(sizeof(vfpinstr_inst)); 2527 INC_PC(sizeof(vmrs_inst));
3174 FETCH_INST; 2528 FETCH_INST;
3175 GOTO_NEXT_INST; 2529 GOTO_NEXT_INST;
3176} 2530}
3177#endif 2531#endif
3178#ifdef VFP_MRC_TRANS 2532
3179if (OPC_1 == 0x7 && CRm == 0 && OPC_2 == 0)
3180{
3181 VMRS(state, CRn, Rt, value);
3182 return ARMul_DONE;
3183}
3184#endif
3185#ifdef VFP_MRC_IMPL
3186void VMRS(ARMul_State * state, ARMword reg, ARMword Rt, ARMword * value)
3187{
3188 DBG("VMRS :");
3189 if (reg == 1)
3190 {
3191 if (Rt != 15)
3192 {
3193 *value = state->VFP[VFP_OFFSET(VFP_FPSCR)];
3194 DBG("\tr%d <= fpscr[%08x]\n", Rt, state->VFP[VFP_OFFSET(VFP_FPSCR)]);
3195 }
3196 else
3197 {
3198 *value = state->VFP[VFP_OFFSET(VFP_FPSCR)] ;
3199 DBG("\tflags <= fpscr[%1xxxxxxxx]\n", state->VFP[VFP_OFFSET(VFP_FPSCR)]>>28);
3200 }
3201 }
3202 else
3203 {
3204 switch (reg)
3205 {
3206 case 0:
3207 *value = state->VFP[VFP_OFFSET(VFP_FPSID)];
3208 DBG("\tr%d <= fpsid[%08x]\n", Rt, state->VFP[VFP_OFFSET(VFP_FPSID)]);
3209 break;
3210 case 6:
3211 /* MVFR1, VFPv3 only ? */
3212 DBG("\tr%d <= MVFR1 unimplemented\n", Rt);
3213 break;
3214 case 7:
3215 /* MVFR0, VFPv3 only? */
3216 DBG("\tr%d <= MVFR0 unimplemented\n", Rt);
3217 break;
3218 case 8:
3219 *value = state->VFP[VFP_OFFSET(VFP_FPEXC)];
3220 DBG("\tr%d <= fpexc[%08x]\n", Rt, state->VFP[VFP_OFFSET(VFP_FPEXC)]);
3221 break;
3222 default:
3223 DBG("\tSUBARCHITECTURE DEFINED\n");
3224 break;
3225 }
3226 }
3227}
3228#endif
3229#ifdef VFP_DYNCOM_TABLE 2533#ifdef VFP_DYNCOM_TABLE
3230DYNCOM_FILL_ACTION(vfpinstr), 2534DYNCOM_FILL_ACTION(vmrs),
3231#endif 2535#endif
3232#ifdef VFP_DYNCOM_TAG 2536#ifdef VFP_DYNCOM_TAG
3233int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 2537int DYNCOM_TAG(vmrs)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
3234{ 2538{
3235 int instr_size = INSTR_SIZE; 2539 int instr_size = INSTR_SIZE;
3236 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 2540 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -3241,7 +2545,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
3241} 2545}
3242#endif 2546#endif
3243#ifdef VFP_DYNCOM_TRANS 2547#ifdef VFP_DYNCOM_TRANS
3244int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 2548int DYNCOM_TRANS(vmrs)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
3245 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 2549 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
3246 //arch_arm_undef(cpu, bb, instr); 2550 //arch_arm_undef(cpu, bb, instr);
3247 2551
@@ -3292,44 +2596,26 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
3292 return No_exp; 2596 return No_exp;
3293} 2597}
3294#endif 2598#endif
3295#undef vfpinstr
3296#undef vfpinstr_inst
3297#undef VFPLABEL_INST
3298 2599
3299/* ----------------------------------------------------------------------- */ 2600/* ----------------------------------------------------------------------- */
3300/* VMOVBCR scalar to register */ 2601/* VMOVBCR scalar to register */
3301/* cond 1110 XXX1 Vd-- Rt-- 1011 NXX1 0000 */ 2602/* cond 1110 XXX1 Vd-- Rt-- 1011 NXX1 0000 */
3302/* cond 1110 op11 CRn- Rt-- copr op21 CRm- MCR */ 2603/* cond 1110 op11 CRn- Rt-- copr op21 CRm- MCR */
3303#define vfpinstr vmovbcr
3304#define vfpinstr_inst vmovbcr_inst
3305#define VFPLABEL_INST VMOVBCR_INST
3306#ifdef VFP_DECODE
3307{"vmovbcr", 4, ARMVFP2, 24, 27, 0xE, 20, 20, 1, 8, 11,0xB, 0,4, 0x10},
3308#endif
3309#ifdef VFP_DECODE_EXCLUSION
3310{"vmovbcr", 0, ARMVFP2, 0},
3311#endif
3312#ifdef VFP_INTERPRETER_TABLE
3313INTERPRETER_TRANSLATE(vfpinstr),
3314#endif
3315#ifdef VFP_INTERPRETER_LABEL
3316&&VFPLABEL_INST,
3317#endif
3318#ifdef VFP_INTERPRETER_STRUCT 2604#ifdef VFP_INTERPRETER_STRUCT
3319typedef struct _vmovbcr_inst { 2605typedef struct _vmovbcr_inst {
3320 unsigned int esize; 2606 unsigned int esize;
3321 unsigned int index; 2607 unsigned int index;
3322 unsigned int d; 2608 unsigned int d;
3323 unsigned int t; 2609 unsigned int t;
3324} vfpinstr_inst; 2610} vmovbcr_inst;
3325#endif 2611#endif
3326#ifdef VFP_INTERPRETER_TRANS 2612#ifdef VFP_INTERPRETER_TRANS
3327ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 2613ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbcr)(unsigned int inst, int index)
3328{ 2614{
3329 VFP_DEBUG_TRANSLATE; 2615 VFP_DEBUG_TRANSLATE;
3330 2616
3331 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 2617 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbcr_inst));
3332 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2618 vmovbcr_inst *inst_cream = (vmovbcr_inst *)inst_base->component;
3333 2619
3334 inst_base->cond = BITS(inst, 28, 31); 2620 inst_base->cond = BITS(inst, 28, 31);
3335 inst_base->idx = index; 2621 inst_base->idx = index;
@@ -3346,34 +2632,27 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
3346} 2632}
3347#endif 2633#endif
3348#ifdef VFP_INTERPRETER_IMPL 2634#ifdef VFP_INTERPRETER_IMPL
3349VFPLABEL_INST: 2635VMOVBCR_INST:
3350{ 2636{
3351 INC_ICOUNTER;
3352 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 2637 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
3353 CHECK_VFP_ENABLED; 2638 CHECK_VFP_ENABLED;
3354 2639
3355 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2640 vmovbcr_inst *inst_cream = (vmovbcr_inst *)inst_base->component;
3356 2641
3357 VFP_DEBUG_UNIMPLEMENTED(VMOVBCR); 2642 VFP_DEBUG_UNIMPLEMENTED(VMOVBCR);
3358 } 2643 }
3359 cpu->Reg[15] += GET_INST_SIZE(cpu); 2644 cpu->Reg[15] += GET_INST_SIZE(cpu);
3360 INC_PC(sizeof(vfpinstr_inst)); 2645 INC_PC(sizeof(vmovbcr_inst));
3361 FETCH_INST; 2646 FETCH_INST;
3362 GOTO_NEXT_INST; 2647 GOTO_NEXT_INST;
3363} 2648}
3364#endif 2649#endif
3365#ifdef VFP_MCR_TRANS 2650
3366if (CoProc == 11 && CRm == 0)
3367{
3368 VFP_DEBUG_UNIMPLEMENTED(VMOVBCR);
3369 return ARMul_DONE;
3370}
3371#endif
3372#ifdef VFP_DYNCOM_TABLE 2651#ifdef VFP_DYNCOM_TABLE
3373DYNCOM_FILL_ACTION(vfpinstr), 2652DYNCOM_FILL_ACTION(vmovbcr),
3374#endif 2653#endif
3375#ifdef VFP_DYNCOM_TAG 2654#ifdef VFP_DYNCOM_TAG
3376int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 2655int DYNCOM_TAG(vmovbcr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
3377{ 2656{
3378 int instr_size = INSTR_SIZE; 2657 int instr_size = INSTR_SIZE;
3379 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 2658 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -3382,15 +2661,12 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
3382} 2661}
3383#endif 2662#endif
3384#ifdef VFP_DYNCOM_TRANS 2663#ifdef VFP_DYNCOM_TRANS
3385int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 2664int DYNCOM_TRANS(vmovbcr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
3386 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 2665 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
3387 arch_arm_undef(cpu, bb, instr); 2666 arch_arm_undef(cpu, bb, instr);
3388 return No_exp; 2667 return No_exp;
3389} 2668}
3390#endif 2669#endif
3391#undef vfpinstr
3392#undef vfpinstr_inst
3393#undef VFPLABEL_INST
3394 2670
3395/* ----------------------------------------------------------------------- */ 2671/* ----------------------------------------------------------------------- */
3396/* MRRC / MCRR instructions */ 2672/* MRRC / MCRR instructions */
@@ -3401,36 +2677,21 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
3401/* VMOVBRRSS between 2 registers to 2 singles */ 2677/* VMOVBRRSS between 2 registers to 2 singles */
3402/* cond 1100 010X Rt2- Rt-- 1010 00X1 Vm-- */ 2678/* cond 1100 010X Rt2- Rt-- 1010 00X1 Vm-- */
3403/* cond 1100 0101 Rt2- Rt-- copr opc1 CRm- MRRC */ 2679/* cond 1100 0101 Rt2- Rt-- copr opc1 CRm- MRRC */
3404#define vfpinstr vmovbrrss
3405#define vfpinstr_inst vmovbrrss_inst
3406#define VFPLABEL_INST VMOVBRRSS_INST
3407#ifdef VFP_DECODE
3408{"vmovbrrss", 3, ARMVFP2, 21, 27, 0x62, 8, 11, 0xA, 4, 4, 1},
3409#endif
3410#ifdef VFP_DECODE_EXCLUSION
3411{"vmovbrrss", 0, ARMVFP2, 0},
3412#endif
3413#ifdef VFP_INTERPRETER_TABLE
3414INTERPRETER_TRANSLATE(vfpinstr),
3415#endif
3416#ifdef VFP_INTERPRETER_LABEL
3417&&VFPLABEL_INST,
3418#endif
3419#ifdef VFP_INTERPRETER_STRUCT 2680#ifdef VFP_INTERPRETER_STRUCT
3420typedef struct _vmovbrrss_inst { 2681typedef struct _vmovbrrss_inst {
3421 unsigned int to_arm; 2682 unsigned int to_arm;
3422 unsigned int t; 2683 unsigned int t;
3423 unsigned int t2; 2684 unsigned int t2;
3424 unsigned int m; 2685 unsigned int m;
3425} vfpinstr_inst; 2686} vmovbrrss_inst;
3426#endif 2687#endif
3427#ifdef VFP_INTERPRETER_TRANS 2688#ifdef VFP_INTERPRETER_TRANS
3428ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 2689ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrrss)(unsigned int inst, int index)
3429{ 2690{
3430 VFP_DEBUG_TRANSLATE; 2691 VFP_DEBUG_TRANSLATE;
3431 2692
3432 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 2693 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbrrss_inst));
3433 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2694 vmovbrrss_inst *inst_cream = (vmovbrrss_inst *)inst_base->component;
3434 2695
3435 inst_base->cond = BITS(inst, 28, 31); 2696 inst_base->cond = BITS(inst, 28, 31);
3436 inst_base->idx = index; 2697 inst_base->idx = index;
@@ -3446,41 +2707,26 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
3446} 2707}
3447#endif 2708#endif
3448#ifdef VFP_INTERPRETER_IMPL 2709#ifdef VFP_INTERPRETER_IMPL
3449VFPLABEL_INST: 2710VMOVBRRSS_INST:
3450{ 2711{
3451 INC_ICOUNTER;
3452 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 2712 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
3453 CHECK_VFP_ENABLED; 2713 CHECK_VFP_ENABLED;
3454 2714
3455 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2715 vmovbrrss_inst *inst_cream = (vmovbrrss_inst *)inst_base->component;
3456 2716
3457 VFP_DEBUG_UNIMPLEMENTED(VMOVBRRSS); 2717 VFP_DEBUG_UNIMPLEMENTED(VMOVBRRSS);
3458 } 2718 }
3459 cpu->Reg[15] += GET_INST_SIZE(cpu); 2719 cpu->Reg[15] += GET_INST_SIZE(cpu);
3460 INC_PC(sizeof(vfpinstr_inst)); 2720 INC_PC(sizeof(vmovbrrss_inst));
3461 FETCH_INST; 2721 FETCH_INST;
3462 GOTO_NEXT_INST; 2722 GOTO_NEXT_INST;
3463} 2723}
3464#endif 2724#endif
3465#ifdef VFP_MCRR_TRANS
3466if (CoProc == 10 && (OPC_1 & 0xD) == 1)
3467{
3468 VFP_DEBUG_UNIMPLEMENTED(VMOVBRRSS);
3469 return ARMul_DONE;
3470}
3471#endif
3472#ifdef VFP_MRRC_TRANS
3473if (CoProc == 10 && (OPC_1 & 0xD) == 1)
3474{
3475 VFP_DEBUG_UNIMPLEMENTED(VMOVBRRSS);
3476 return ARMul_DONE;
3477}
3478#endif
3479#ifdef VFP_DYNCOM_TABLE 2725#ifdef VFP_DYNCOM_TABLE
3480DYNCOM_FILL_ACTION(vfpinstr), 2726DYNCOM_FILL_ACTION(vmovbrrss),
3481#endif 2727#endif
3482#ifdef VFP_DYNCOM_TAG 2728#ifdef VFP_DYNCOM_TAG
3483int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 2729int DYNCOM_TAG(vmovbrrss)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
3484{ 2730{
3485 int instr_size = INSTR_SIZE; 2731 int instr_size = INSTR_SIZE;
3486 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 2732 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -3489,50 +2735,32 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
3489} 2735}
3490#endif 2736#endif
3491#ifdef VFP_DYNCOM_TRANS 2737#ifdef VFP_DYNCOM_TRANS
3492int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 2738int DYNCOM_TRANS(vmovbrrss)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
3493 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 2739 DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
3494 arch_arm_undef(cpu, bb, instr); 2740 arch_arm_undef(cpu, bb, instr);
3495 return No_exp; 2741 return No_exp;
3496} 2742}
3497#endif 2743#endif
3498#undef vfpinstr
3499#undef vfpinstr_inst
3500#undef VFPLABEL_INST
3501 2744
3502/* ----------------------------------------------------------------------- */ 2745/* ----------------------------------------------------------------------- */
3503/* VMOVBRRD between 2 registers and 1 double */ 2746/* VMOVBRRD between 2 registers and 1 double */
3504/* cond 1100 010X Rt2- Rt-- 1011 00X1 Vm-- */ 2747/* cond 1100 010X Rt2- Rt-- 1011 00X1 Vm-- */
3505/* cond 1100 0101 Rt2- Rt-- copr opc1 CRm- MRRC */ 2748/* cond 1100 0101 Rt2- Rt-- copr opc1 CRm- MRRC */
3506#define vfpinstr vmovbrrd
3507#define vfpinstr_inst vmovbrrd_inst
3508#define VFPLABEL_INST VMOVBRRD_INST
3509#ifdef VFP_DECODE
3510{"vmovbrrd", 3, ARMVFP2, 21, 27, 0x62, 6, 11, 0x2c, 4, 4, 1},
3511#endif
3512#ifdef VFP_DECODE_EXCLUSION
3513{"vmovbrrd", 0, ARMVFP2, 0},
3514#endif
3515#ifdef VFP_INTERPRETER_TABLE
3516INTERPRETER_TRANSLATE(vfpinstr),
3517#endif
3518#ifdef VFP_INTERPRETER_LABEL
3519&&VFPLABEL_INST,
3520#endif
3521#ifdef VFP_INTERPRETER_STRUCT 2749#ifdef VFP_INTERPRETER_STRUCT
3522typedef struct _vmovbrrd_inst { 2750typedef struct _vmovbrrd_inst {
3523 unsigned int to_arm; 2751 unsigned int to_arm;
3524 unsigned int t; 2752 unsigned int t;
3525 unsigned int t2; 2753 unsigned int t2;
3526 unsigned int m; 2754 unsigned int m;
3527} vfpinstr_inst; 2755} vmovbrrd_inst;
3528#endif 2756#endif
3529#ifdef VFP_INTERPRETER_TRANS 2757#ifdef VFP_INTERPRETER_TRANS
3530ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 2758ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrrd)(unsigned int inst, int index)
3531{ 2759{
3532 VFP_DEBUG_TRANSLATE; 2760 VFP_DEBUG_TRANSLATE;
3533 2761
3534 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 2762 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vmovbrrd_inst));
3535 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2763 vmovbrrd_inst *inst_cream = (vmovbrrd_inst *)inst_base->component;
3536 2764
3537 inst_base->cond = BITS(inst, 28, 31); 2765 inst_base->cond = BITS(inst, 28, 31);
3538 inst_base->idx = index; 2766 inst_base->idx = index;
@@ -3548,63 +2776,28 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
3548} 2776}
3549#endif 2777#endif
3550#ifdef VFP_INTERPRETER_IMPL 2778#ifdef VFP_INTERPRETER_IMPL
3551VFPLABEL_INST: 2779VMOVBRRD_INST:
3552{ 2780{
3553 INC_ICOUNTER;
3554 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 2781 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
3555 CHECK_VFP_ENABLED; 2782 CHECK_VFP_ENABLED;
3556 2783
3557 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2784 vmovbrrd_inst *inst_cream = (vmovbrrd_inst *)inst_base->component;
3558 2785
3559 VMOVBRRD(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m, 2786 VMOVBRRD(cpu, inst_cream->to_arm, inst_cream->t, inst_cream->t2, inst_cream->m,
3560 &(cpu->Reg[inst_cream->t]), &(cpu->Reg[inst_cream->t2])); 2787 &(cpu->Reg[inst_cream->t]), &(cpu->Reg[inst_cream->t2]));
3561 } 2788 }
3562 cpu->Reg[15] += GET_INST_SIZE(cpu); 2789 cpu->Reg[15] += GET_INST_SIZE(cpu);
3563 INC_PC(sizeof(vfpinstr_inst)); 2790 INC_PC(sizeof(vmovbrrd_inst));
3564 FETCH_INST; 2791 FETCH_INST;
3565 GOTO_NEXT_INST; 2792 GOTO_NEXT_INST;
3566} 2793}
3567#endif 2794#endif
3568#ifdef VFP_MCRR_TRANS
3569if (CoProc == 11 && (OPC_1 & 0xD) == 1)
3570{
3571 /* Transfering Rt and Rt2 is not mandatory, as the value of interest is pointed by value1 and value2 */
3572 VMOVBRRD(state, BIT(20), Rt, Rt2, BIT(5)<<4|CRm, &value1, &value2);
3573 return ARMul_DONE;
3574}
3575#endif
3576#ifdef VFP_MRRC_TRANS
3577if (CoProc == 11 && (OPC_1 & 0xD) == 1)
3578{
3579 /* Transfering Rt and Rt2 is not mandatory, as the value of interest is pointed by value1 and value2 */
3580 VMOVBRRD(state, BIT(20), Rt, Rt2, BIT(5)<<4|CRm, value1, value2);
3581 return ARMul_DONE;
3582}
3583#endif
3584#ifdef VFP_MRRC_IMPL
3585void VMOVBRRD(ARMul_State * state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword *value1, ARMword *value2)
3586{
3587 DBG("VMOV(BRRD) :\n");
3588 if (to_arm)
3589 {
3590 DBG("\tr[%d-%d] <= s[%d-%d]=[%x-%x]\n", t2, t, n*2+1, n*2, state->ExtReg[n*2+1], state->ExtReg[n*2]);
3591 *value2 = state->ExtReg[n*2+1];
3592 *value1 = state->ExtReg[n*2];
3593 }
3594 else
3595 {
3596 DBG("\ts[%d-%d] <= r[%d-%d]=[%x-%x]\n", n*2+1, n*2, t2, t, *value2, *value1);
3597 state->ExtReg[n*2+1] = *value2;
3598 state->ExtReg[n*2] = *value1;
3599 }
3600}
3601 2795
3602#endif
3603#ifdef VFP_DYNCOM_TABLE 2796#ifdef VFP_DYNCOM_TABLE
3604DYNCOM_FILL_ACTION(vfpinstr), 2797DYNCOM_FILL_ACTION(vmovbrrd),
3605#endif 2798#endif
3606#ifdef VFP_DYNCOM_TAG 2799#ifdef VFP_DYNCOM_TAG
3607int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 2800int DYNCOM_TAG(vmovbrrd)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
3608{ 2801{
3609 int instr_size = INSTR_SIZE; 2802 int instr_size = INSTR_SIZE;
3610 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 2803 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -3615,7 +2808,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
3615} 2808}
3616#endif 2809#endif
3617#ifdef VFP_DYNCOM_TRANS 2810#ifdef VFP_DYNCOM_TRANS
3618int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 2811int DYNCOM_TRANS(vmovbrrd)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
3619 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 2812 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
3620 //arch_arm_undef(cpu, bb, instr); 2813 //arch_arm_undef(cpu, bb, instr);
3621 int to_arm = BIT(20) == 1; 2814 int to_arm = BIT(20) == 1;
@@ -3633,9 +2826,6 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
3633 return No_exp; 2826 return No_exp;
3634} 2827}
3635#endif 2828#endif
3636#undef vfpinstr
3637#undef vfpinstr_inst
3638#undef VFPLABEL_INST
3639 2829
3640/* ----------------------------------------------------------------------- */ 2830/* ----------------------------------------------------------------------- */
3641/* LDC/STC between 2 registers and 1 double */ 2831/* LDC/STC between 2 registers and 1 double */
@@ -3645,21 +2835,6 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
3645/* ----------------------------------------------------------------------- */ 2835/* ----------------------------------------------------------------------- */
3646/* VSTR */ 2836/* VSTR */
3647/* cond 1101 UD00 Rn-- Vd-- 101X imm8 imm8 */ 2837/* cond 1101 UD00 Rn-- Vd-- 101X imm8 imm8 */
3648#define vfpinstr vstr
3649#define vfpinstr_inst vstr_inst
3650#define VFPLABEL_INST VSTR_INST
3651#ifdef VFP_DECODE
3652{"vstr", 3, ARMVFP2, 24, 27, 0xd, 20, 21, 0, 9, 11, 0x5},
3653#endif
3654#ifdef VFP_DECODE_EXCLUSION
3655{"vstr", 0, ARMVFP2, 0},
3656#endif
3657#ifdef VFP_INTERPRETER_TABLE
3658INTERPRETER_TRANSLATE(vfpinstr),
3659#endif
3660#ifdef VFP_INTERPRETER_LABEL
3661&&VFPLABEL_INST,
3662#endif
3663#ifdef VFP_INTERPRETER_STRUCT 2838#ifdef VFP_INTERPRETER_STRUCT
3664typedef struct _vstr_inst { 2839typedef struct _vstr_inst {
3665 unsigned int single; 2840 unsigned int single;
@@ -3667,15 +2842,15 @@ typedef struct _vstr_inst {
3667 unsigned int d; 2842 unsigned int d;
3668 unsigned int imm32; 2843 unsigned int imm32;
3669 unsigned int add; 2844 unsigned int add;
3670} vfpinstr_inst; 2845} vstr_inst;
3671#endif 2846#endif
3672#ifdef VFP_INTERPRETER_TRANS 2847#ifdef VFP_INTERPRETER_TRANS
3673ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 2848ARM_INST_PTR INTERPRETER_TRANSLATE(vstr)(unsigned int inst, int index)
3674{ 2849{
3675 VFP_DEBUG_TRANSLATE; 2850 VFP_DEBUG_TRANSLATE;
3676 2851
3677 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 2852 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vstr_inst));
3678 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2853 vstr_inst *inst_cream = (vstr_inst *)inst_base->component;
3679 2854
3680 inst_base->cond = BITS(inst, 28, 31); 2855 inst_base->cond = BITS(inst, 28, 31);
3681 inst_base->idx = index; 2856 inst_base->idx = index;
@@ -3692,13 +2867,12 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
3692} 2867}
3693#endif 2868#endif
3694#ifdef VFP_INTERPRETER_IMPL 2869#ifdef VFP_INTERPRETER_IMPL
3695VFPLABEL_INST: 2870VSTR_INST:
3696{ 2871{
3697 INC_ICOUNTER;
3698 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 2872 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
3699 CHECK_VFP_ENABLED; 2873 CHECK_VFP_ENABLED;
3700 2874
3701 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2875 vstr_inst *inst_cream = (vstr_inst *)inst_base->component;
3702 2876
3703 unsigned int base = (inst_cream->n == 15 ? (cpu->Reg[inst_cream->n] & 0xFFFFFFFC) + 8 : cpu->Reg[inst_cream->n]); 2877 unsigned int base = (inst_cream->n == 15 ? (cpu->Reg[inst_cream->n] & 0xFFFFFFFC) + 8 : cpu->Reg[inst_cream->n]);
3704 addr = (inst_cream->add ? base + inst_cream->imm32 : base - inst_cream->imm32); 2878 addr = (inst_cream->add ? base + inst_cream->imm32 : base - inst_cream->imm32);
@@ -3736,65 +2910,12 @@ VFPLABEL_INST:
3736 GOTO_NEXT_INST; 2910 GOTO_NEXT_INST;
3737} 2911}
3738#endif 2912#endif
3739#ifdef VFP_STC_TRANS
3740if (P == 1 && W == 0)
3741{
3742 return VSTR(state, type, instr, value);
3743}
3744#endif
3745#ifdef VFP_STC_IMPL
3746int VSTR(ARMul_State * state, int type, ARMword instr, ARMword * value)
3747{
3748 static int i = 0;
3749 static int single_reg, add, d, n, imm32, regs;
3750 if (type == ARMul_FIRST)
3751 {
3752 single_reg = BIT(8) == 0; /* Double precision */
3753 add = BIT(23); /* */
3754 imm32 = BITS(0,7)<<2; /* may not be used */
3755 d = single_reg ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */
3756 n = BITS(16, 19); /* destination register */
3757
3758 DBG("VSTR :\n");
3759
3760 i = 0;
3761 regs = 1;
3762
3763 return ARMul_DONE;
3764 }
3765 else if (type == ARMul_DATA)
3766 {
3767 if (single_reg)
3768 {
3769 *value = state->ExtReg[d+i];
3770 DBG("\taddr[?] <= s%d=[%x]\n", d+i, state->ExtReg[d+i]);
3771 i++;
3772 if (i < regs)
3773 return ARMul_INC;
3774 else
3775 return ARMul_DONE;
3776 }
3777 else
3778 {
3779 /* FIXME Careful of endianness, may need to rework this */
3780 *value = state->ExtReg[d*2+i];
3781 DBG("\taddr[?] <= s[%d]=[%x]\n", d*2+i, state->ExtReg[d*2+i]);
3782 i++;
3783 if (i < regs*2)
3784 return ARMul_INC;
3785 else
3786 return ARMul_DONE;
3787 }
3788 }
3789 2913
3790 return -1;
3791}
3792#endif
3793#ifdef VFP_DYNCOM_TABLE 2914#ifdef VFP_DYNCOM_TABLE
3794DYNCOM_FILL_ACTION(vfpinstr), 2915DYNCOM_FILL_ACTION(vstr),
3795#endif 2916#endif
3796#ifdef VFP_DYNCOM_TAG 2917#ifdef VFP_DYNCOM_TAG
3797int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 2918int DYNCOM_TAG(vstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
3798{ 2919{
3799 int instr_size = INSTR_SIZE; 2920 int instr_size = INSTR_SIZE;
3800 arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); 2921 arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc);
@@ -3807,7 +2928,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
3807} 2928}
3808#endif 2929#endif
3809#ifdef VFP_DYNCOM_TRANS 2930#ifdef VFP_DYNCOM_TRANS
3810int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 2931int DYNCOM_TRANS(vstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
3811 int single = BIT(8) == 0; 2932 int single = BIT(8) == 0;
3812 int add = BIT(23); 2933 int add = BIT(23);
3813 int imm32 = BITS(0,7) << 2; 2934 int imm32 = BITS(0,7) << 2;
@@ -3853,43 +2974,25 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
3853 return No_exp; 2974 return No_exp;
3854} 2975}
3855#endif 2976#endif
3856#undef vfpinstr
3857#undef vfpinstr_inst
3858#undef VFPLABEL_INST
3859 2977
3860/* ----------------------------------------------------------------------- */ 2978/* ----------------------------------------------------------------------- */
3861/* VPUSH */ 2979/* VPUSH */
3862/* cond 1101 0D10 1101 Vd-- 101X imm8 imm8 */ 2980/* cond 1101 0D10 1101 Vd-- 101X imm8 imm8 */
3863#define vfpinstr vpush
3864#define vfpinstr_inst vpush_inst
3865#define VFPLABEL_INST VPUSH_INST
3866#ifdef VFP_DECODE
3867{"vpush", 3, ARMVFP2, 23, 27, 0x1a, 16, 21, 0x2d, 9, 11, 0x5},
3868#endif
3869#ifdef VFP_DECODE_EXCLUSION
3870{"vpush", 0, ARMVFP2, 0},
3871#endif
3872#ifdef VFP_INTERPRETER_TABLE
3873INTERPRETER_TRANSLATE(vfpinstr),
3874#endif
3875#ifdef VFP_INTERPRETER_LABEL
3876&&VFPLABEL_INST,
3877#endif
3878#ifdef VFP_INTERPRETER_STRUCT 2981#ifdef VFP_INTERPRETER_STRUCT
3879typedef struct _vpush_inst { 2982typedef struct _vpush_inst {
3880 unsigned int single; 2983 unsigned int single;
3881 unsigned int d; 2984 unsigned int d;
3882 unsigned int imm32; 2985 unsigned int imm32;
3883 unsigned int regs; 2986 unsigned int regs;
3884} vfpinstr_inst; 2987} vpush_inst;
3885#endif 2988#endif
3886#ifdef VFP_INTERPRETER_TRANS 2989#ifdef VFP_INTERPRETER_TRANS
3887ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 2990ARM_INST_PTR INTERPRETER_TRANSLATE(vpush)(unsigned int inst, int index)
3888{ 2991{
3889 VFP_DEBUG_TRANSLATE; 2992 VFP_DEBUG_TRANSLATE;
3890 2993
3891 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 2994 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vpush_inst));
3892 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 2995 vpush_inst *inst_cream = (vpush_inst *)inst_base->component;
3893 2996
3894 inst_base->cond = BITS(inst, 28, 31); 2997 inst_base->cond = BITS(inst, 28, 31);
3895 inst_base->idx = index; 2998 inst_base->idx = index;
@@ -3905,15 +3008,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
3905} 3008}
3906#endif 3009#endif
3907#ifdef VFP_INTERPRETER_IMPL 3010#ifdef VFP_INTERPRETER_IMPL
3908VFPLABEL_INST: 3011VPUSH_INST:
3909{ 3012{
3910 INC_ICOUNTER;
3911 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 3013 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
3912 CHECK_VFP_ENABLED; 3014 CHECK_VFP_ENABLED;
3913 3015
3914 int i; 3016 int i;
3915 3017
3916 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 3018 vpush_inst *inst_cream = (vpush_inst *)inst_base->component;
3917 3019
3918 DBG("VPUSH :\n"); 3020 DBG("VPUSH :\n");
3919 3021
@@ -3958,66 +3060,11 @@ VFPLABEL_INST:
3958 GOTO_NEXT_INST; 3060 GOTO_NEXT_INST;
3959} 3061}
3960#endif 3062#endif
3961#ifdef VFP_STC_TRANS
3962if (P == 1 && U == 0 && W == 1 && Rn == 0xD)
3963{
3964 return VPUSH(state, type, instr, value);
3965}
3966#endif
3967#ifdef VFP_STC_IMPL
3968int VPUSH(ARMul_State * state, int type, ARMword instr, ARMword * value)
3969{
3970 static int i = 0;
3971 static int single_regs, add, wback, d, n, imm32, regs;
3972 if (type == ARMul_FIRST)
3973 {
3974 single_regs = BIT(8) == 0; /* Single precision */
3975 d = single_regs ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */
3976 imm32 = BITS(0,7)<<2; /* may not be used */
3977 regs = single_regs ? BITS(0, 7) : BITS(1, 7); /* FSTMX if regs is odd */
3978
3979 DBG("VPUSH :\n");
3980 DBG("\tsp[%x]", state->Reg[R13]);
3981 state->Reg[R13] = state->Reg[R13] - imm32;
3982 DBG("=>[%x]\n", state->Reg[R13]);
3983
3984 i = 0;
3985
3986 return ARMul_DONE;
3987 }
3988 else if (type == ARMul_DATA)
3989 {
3990 if (single_regs)
3991 {
3992 *value = state->ExtReg[d + i];
3993 DBG("\taddr[?] <= s%d=[%x]\n", d+i, state->ExtReg[d + i]);
3994 i++;
3995 if (i < regs)
3996 return ARMul_INC;
3997 else
3998 return ARMul_DONE;
3999 }
4000 else
4001 {
4002 /* FIXME Careful of endianness, may need to rework this */
4003 *value = state->ExtReg[d*2 + i];
4004 DBG("\taddr[?] <= s[%d]=[%x]\n", d*2 + i, state->ExtReg[d*2 + i]);
4005 i++;
4006 if (i < regs*2)
4007 return ARMul_INC;
4008 else
4009 return ARMul_DONE;
4010 }
4011 }
4012
4013 return -1;
4014}
4015#endif
4016#ifdef VFP_DYNCOM_TABLE 3063#ifdef VFP_DYNCOM_TABLE
4017DYNCOM_FILL_ACTION(vfpinstr), 3064DYNCOM_FILL_ACTION(vpush),
4018#endif 3065#endif
4019#ifdef VFP_DYNCOM_TAG 3066#ifdef VFP_DYNCOM_TAG
4020int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 3067int DYNCOM_TAG(vpush)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
4021{ 3068{
4022 int instr_size = INSTR_SIZE; 3069 int instr_size = INSTR_SIZE;
4023 arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc); 3070 arm_tag_continue(cpu, pc, instr, tag, new_pc, next_pc);
@@ -4030,7 +3077,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
4030} 3077}
4031#endif 3078#endif
4032#ifdef VFP_DYNCOM_TRANS 3079#ifdef VFP_DYNCOM_TRANS
4033int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 3080int DYNCOM_TRANS(vpush)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
4034 int single = BIT(8) == 0; 3081 int single = BIT(8) == 0;
4035 int d = (single ? BITS(12, 15)<<1|BIT(22) : BITS(12, 15)|(BIT(22)<<4)); 3082 int d = (single ? BITS(12, 15)<<1|BIT(22) : BITS(12, 15)|(BIT(22)<<4));
4036 int imm32 = BITS(0, 7)<<2; 3083 int imm32 = BITS(0, 7)<<2;
@@ -4087,28 +3134,10 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
4087 return No_exp; 3134 return No_exp;
4088} 3135}
4089#endif 3136#endif
4090#undef vfpinstr
4091#undef vfpinstr_inst
4092#undef VFPLABEL_INST
4093 3137
4094/* ----------------------------------------------------------------------- */ 3138/* ----------------------------------------------------------------------- */
4095/* VSTM */ 3139/* VSTM */
4096/* cond 110P UDW0 Rn-- Vd-- 101X imm8 imm8 */ 3140/* cond 110P UDW0 Rn-- Vd-- 101X imm8 imm8 */
4097#define vfpinstr vstm
4098#define vfpinstr_inst vstm_inst
4099#define VFPLABEL_INST VSTM_INST
4100#ifdef VFP_DECODE
4101{"vstm", 3, ARMVFP2, 25, 27, 0x6, 20, 20, 0, 9, 11, 0x5},
4102#endif
4103#ifdef VFP_DECODE_EXCLUSION
4104{"vstm", 0, ARMVFP2, 0},
4105#endif
4106#ifdef VFP_INTERPRETER_TABLE
4107INTERPRETER_TRANSLATE(vfpinstr),
4108#endif
4109#ifdef VFP_INTERPRETER_LABEL
4110&&VFPLABEL_INST,
4111#endif
4112#ifdef VFP_INTERPRETER_STRUCT 3141#ifdef VFP_INTERPRETER_STRUCT
4113typedef struct _vstm_inst { 3142typedef struct _vstm_inst {
4114 unsigned int single; 3143 unsigned int single;
@@ -4118,15 +3147,15 @@ typedef struct _vstm_inst {
4118 unsigned int n; 3147 unsigned int n;
4119 unsigned int imm32; 3148 unsigned int imm32;
4120 unsigned int regs; 3149 unsigned int regs;
4121} vfpinstr_inst; 3150} vstm_inst;
4122#endif 3151#endif
4123#ifdef VFP_INTERPRETER_TRANS 3152#ifdef VFP_INTERPRETER_TRANS
4124ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 3153ARM_INST_PTR INTERPRETER_TRANSLATE(vstm)(unsigned int inst, int index)
4125{ 3154{
4126 VFP_DEBUG_TRANSLATE; 3155 VFP_DEBUG_TRANSLATE;
4127 3156
4128 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 3157 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vstm_inst));
4129 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 3158 vstm_inst *inst_cream = (vstm_inst *)inst_base->component;
4130 3159
4131 inst_base->cond = BITS(inst, 28, 31); 3160 inst_base->cond = BITS(inst, 28, 31);
4132 inst_base->idx = index; 3161 inst_base->idx = index;
@@ -4145,15 +3174,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
4145} 3174}
4146#endif 3175#endif
4147#ifdef VFP_INTERPRETER_IMPL 3176#ifdef VFP_INTERPRETER_IMPL
4148VFPLABEL_INST: /* encoding 1 */ 3177VSTM_INST: /* encoding 1 */
4149{ 3178{
4150 INC_ICOUNTER;
4151 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 3179 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4152 CHECK_VFP_ENABLED; 3180 CHECK_VFP_ENABLED;
4153 3181
4154 int i; 3182 int i;
4155 3183
4156 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 3184 vstm_inst *inst_cream = (vstm_inst *)inst_base->component;
4157 3185
4158 addr = (inst_cream->add ? cpu->Reg[inst_cream->n] : cpu->Reg[inst_cream->n] - inst_cream->imm32); 3186 addr = (inst_cream->add ? cpu->Reg[inst_cream->n] : cpu->Reg[inst_cream->n] - inst_cream->imm32);
4159 DBG("VSTM : addr[%x]\n", addr); 3187 DBG("VSTM : addr[%x]\n", addr);
@@ -4203,69 +3231,12 @@ VFPLABEL_INST: /* encoding 1 */
4203 GOTO_NEXT_INST; 3231 GOTO_NEXT_INST;
4204} 3232}
4205#endif 3233#endif
4206#ifdef VFP_STC_TRANS
4207/* Should be the last operation of STC */
4208return VSTM(state, type, instr, value);
4209#endif
4210#ifdef VFP_STC_IMPL
4211int VSTM(ARMul_State * state, int type, ARMword instr, ARMword * value)
4212{
4213 static int i = 0;
4214 static int single_regs, add, wback, d, n, imm32, regs;
4215 if (type == ARMul_FIRST)
4216 {
4217 single_regs = BIT(8) == 0; /* Single precision */
4218 add = BIT(23); /* */
4219 wback = BIT(21); /* write-back */
4220 d = single_regs ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */
4221 n = BITS(16, 19); /* destination register */
4222 imm32 = BITS(0,7) * 4; /* may not be used */
4223 regs = single_regs ? BITS(0, 7) : BITS(0, 7)>>1; /* FSTMX if regs is odd */
4224
4225 DBG("VSTM :\n");
4226
4227 if (wback) {
4228 state->Reg[n] = (add ? state->Reg[n] + imm32 : state->Reg[n] - imm32);
4229 DBG("\twback r%d[%x]\n", n, state->Reg[n]);
4230 }
4231
4232 i = 0;
4233
4234 return ARMul_DONE;
4235 }
4236 else if (type == ARMul_DATA)
4237 {
4238 if (single_regs)
4239 {
4240 *value = state->ExtReg[d + i];
4241 DBG("\taddr[?] <= s%d=[%x]\n", d+i, state->ExtReg[d + i]);
4242 i++;
4243 if (i < regs)
4244 return ARMul_INC;
4245 else
4246 return ARMul_DONE;
4247 }
4248 else
4249 {
4250 /* FIXME Careful of endianness, may need to rework this */
4251 *value = state->ExtReg[d*2 + i];
4252 DBG("\taddr[?] <= s[%d]=[%x]\n", d*2 + i, state->ExtReg[d*2 + i]);
4253 i++;
4254 if (i < regs*2)
4255 return ARMul_INC;
4256 else
4257 return ARMul_DONE;
4258 }
4259 }
4260 3234
4261 return -1;
4262}
4263#endif
4264#ifdef VFP_DYNCOM_TABLE 3235#ifdef VFP_DYNCOM_TABLE
4265DYNCOM_FILL_ACTION(vfpinstr), 3236DYNCOM_FILL_ACTION(vstm),
4266#endif 3237#endif
4267#ifdef VFP_DYNCOM_TAG 3238#ifdef VFP_DYNCOM_TAG
4268int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 3239int DYNCOM_TAG(vstm)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
4269{ 3240{
4270 int instr_size = INSTR_SIZE; 3241 int instr_size = INSTR_SIZE;
4271 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 3242 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -4280,7 +3251,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
4280} 3251}
4281#endif 3252#endif
4282#ifdef VFP_DYNCOM_TRANS 3253#ifdef VFP_DYNCOM_TRANS
4283int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 3254int DYNCOM_TRANS(vstm)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
4284 //arch_arm_undef(cpu, bb, instr); 3255 //arch_arm_undef(cpu, bb, instr);
4285 int single = BIT(8) == 0; 3256 int single = BIT(8) == 0;
4286 int add = BIT(23); 3257 int add = BIT(23);
@@ -4356,43 +3327,25 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
4356 return No_exp; 3327 return No_exp;
4357} 3328}
4358#endif 3329#endif
4359#undef vfpinstr
4360#undef vfpinstr_inst
4361#undef VFPLABEL_INST
4362 3330
4363/* ----------------------------------------------------------------------- */ 3331/* ----------------------------------------------------------------------- */
4364/* VPOP */ 3332/* VPOP */
4365/* cond 1100 1D11 1101 Vd-- 101X imm8 imm8 */ 3333/* cond 1100 1D11 1101 Vd-- 101X imm8 imm8 */
4366#define vfpinstr vpop
4367#define vfpinstr_inst vpop_inst
4368#define VFPLABEL_INST VPOP_INST
4369#ifdef VFP_DECODE
4370{"vpop", 3, ARMVFP2, 23, 27, 0x19, 16, 21, 0x3d, 9, 11, 0x5},
4371#endif
4372#ifdef VFP_DECODE_EXCLUSION
4373{"vpop", 0, ARMVFP2, 0},
4374#endif
4375#ifdef VFP_INTERPRETER_TABLE
4376INTERPRETER_TRANSLATE(vfpinstr),
4377#endif
4378#ifdef VFP_INTERPRETER_LABEL
4379&&VFPLABEL_INST,
4380#endif
4381#ifdef VFP_INTERPRETER_STRUCT 3334#ifdef VFP_INTERPRETER_STRUCT
4382typedef struct _vpop_inst { 3335typedef struct _vpop_inst {
4383 unsigned int single; 3336 unsigned int single;
4384 unsigned int d; 3337 unsigned int d;
4385 unsigned int imm32; 3338 unsigned int imm32;
4386 unsigned int regs; 3339 unsigned int regs;
4387} vfpinstr_inst; 3340} vpop_inst;
4388#endif 3341#endif
4389#ifdef VFP_INTERPRETER_TRANS 3342#ifdef VFP_INTERPRETER_TRANS
4390ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 3343ARM_INST_PTR INTERPRETER_TRANSLATE(vpop)(unsigned int inst, int index)
4391{ 3344{
4392 VFP_DEBUG_TRANSLATE; 3345 VFP_DEBUG_TRANSLATE;
4393 3346
4394 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 3347 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vpop_inst));
4395 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 3348 vpop_inst *inst_cream = (vpop_inst *)inst_base->component;
4396 3349
4397 inst_base->cond = BITS(inst, 28, 31); 3350 inst_base->cond = BITS(inst, 28, 31);
4398 inst_base->idx = index; 3351 inst_base->idx = index;
@@ -4408,16 +3361,15 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
4408} 3361}
4409#endif 3362#endif
4410#ifdef VFP_INTERPRETER_IMPL 3363#ifdef VFP_INTERPRETER_IMPL
4411VFPLABEL_INST: 3364VPOP_INST:
4412{ 3365{
4413 INC_ICOUNTER;
4414 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 3366 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4415 CHECK_VFP_ENABLED; 3367 CHECK_VFP_ENABLED;
4416 3368
4417 int i; 3369 int i;
4418 unsigned int value1, value2; 3370 unsigned int value1, value2;
4419 3371
4420 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 3372 vpop_inst *inst_cream = (vpop_inst *)inst_base->component;
4421 3373
4422 DBG("VPOP :\n"); 3374 DBG("VPOP :\n");
4423 3375
@@ -4468,70 +3420,12 @@ VFPLABEL_INST:
4468 GOTO_NEXT_INST; 3420 GOTO_NEXT_INST;
4469} 3421}
4470#endif 3422#endif
4471#ifdef VFP_LDC_TRANS
4472if (P == 0 && U == 1 && W == 1 && Rn == 0xD)
4473{
4474 return VPOP(state, type, instr, value);
4475}
4476#endif
4477#ifdef VFP_LDC_IMPL
4478int VPOP(ARMul_State * state, int type, ARMword instr, ARMword value)
4479{
4480 static int i = 0;
4481 static int single_regs, add, wback, d, n, imm32, regs;
4482 if (type == ARMul_FIRST)
4483 {
4484 single_regs = BIT(8) == 0; /* Single precision */
4485 d = single_regs ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */
4486 imm32 = BITS(0,7)<<2; /* may not be used */
4487 regs = single_regs ? BITS(0, 7) : BITS(1, 7); /* FLDMX if regs is odd */
4488 3423
4489 DBG("VPOP :\n");
4490 DBG("\tsp[%x]", state->Reg[R13]);
4491 state->Reg[R13] = state->Reg[R13] + imm32;
4492 DBG("=>[%x]\n", state->Reg[R13]);
4493
4494 i = 0;
4495
4496 return ARMul_DONE;
4497 }
4498 else if (type == ARMul_TRANSFER)
4499 {
4500 return ARMul_DONE;
4501 }
4502 else if (type == ARMul_DATA)
4503 {
4504 if (single_regs)
4505 {
4506 state->ExtReg[d + i] = value;
4507 DBG("\ts%d <= [%x]\n", d + i, value);
4508 i++;
4509 if (i < regs)
4510 return ARMul_INC;
4511 else
4512 return ARMul_DONE;
4513 }
4514 else
4515 {
4516 /* FIXME Careful of endianness, may need to rework this */
4517 state->ExtReg[d*2 + i] = value;
4518 DBG("\ts%d <= [%x]\n", d*2 + i, value);
4519 i++;
4520 if (i < regs*2)
4521 return ARMul_INC;
4522 else
4523 return ARMul_DONE;
4524 }
4525 }
4526
4527 return -1;
4528}
4529#endif
4530#ifdef VFP_DYNCOM_TABLE 3424#ifdef VFP_DYNCOM_TABLE
4531DYNCOM_FILL_ACTION(vfpinstr), 3425DYNCOM_FILL_ACTION(vpop),
4532#endif 3426#endif
4533#ifdef VFP_DYNCOM_TAG 3427#ifdef VFP_DYNCOM_TAG
4534int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 3428int DYNCOM_TAG(vpop)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
4535{ 3429{
4536 int instr_size = INSTR_SIZE; 3430 int instr_size = INSTR_SIZE;
4537 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 3431 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -4547,7 +3441,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
4547} 3441}
4548#endif 3442#endif
4549#ifdef VFP_DYNCOM_TRANS 3443#ifdef VFP_DYNCOM_TRANS
4550int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 3444int DYNCOM_TRANS(vpop)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
4551 DBG("\t\tin %s instruction .\n", __FUNCTION__); 3445 DBG("\t\tin %s instruction .\n", __FUNCTION__);
4552 //arch_arm_undef(cpu, bb, instr); 3446 //arch_arm_undef(cpu, bb, instr);
4553 int single = BIT(8) == 0; 3447 int single = BIT(8) == 0;
@@ -4611,28 +3505,10 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
4611 return No_exp; 3505 return No_exp;
4612} 3506}
4613#endif 3507#endif
4614#undef vfpinstr
4615#undef vfpinstr_inst
4616#undef VFPLABEL_INST
4617 3508
4618/* ----------------------------------------------------------------------- */ 3509/* ----------------------------------------------------------------------- */
4619/* VLDR */ 3510/* VLDR */
4620/* cond 1101 UD01 Rn-- Vd-- 101X imm8 imm8 */ 3511/* cond 1101 UD01 Rn-- Vd-- 101X imm8 imm8 */
4621#define vfpinstr vldr
4622#define vfpinstr_inst vldr_inst
4623#define VFPLABEL_INST VLDR_INST
4624#ifdef VFP_DECODE
4625{"vldr", 3, ARMVFP2, 24, 27, 0xd, 20, 21, 0x1, 9, 11, 0x5},
4626#endif
4627#ifdef VFP_DECODE_EXCLUSION
4628{"vldr", 0, ARMVFP2, 0},
4629#endif
4630#ifdef VFP_INTERPRETER_TABLE
4631INTERPRETER_TRANSLATE(vfpinstr),
4632#endif
4633#ifdef VFP_INTERPRETER_LABEL
4634&&VFPLABEL_INST,
4635#endif
4636#ifdef VFP_INTERPRETER_STRUCT 3512#ifdef VFP_INTERPRETER_STRUCT
4637typedef struct _vldr_inst { 3513typedef struct _vldr_inst {
4638 unsigned int single; 3514 unsigned int single;
@@ -4640,15 +3516,15 @@ typedef struct _vldr_inst {
4640 unsigned int d; 3516 unsigned int d;
4641 unsigned int imm32; 3517 unsigned int imm32;
4642 unsigned int add; 3518 unsigned int add;
4643} vfpinstr_inst; 3519} vldr_inst;
4644#endif 3520#endif
4645#ifdef VFP_INTERPRETER_TRANS 3521#ifdef VFP_INTERPRETER_TRANS
4646ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 3522ARM_INST_PTR INTERPRETER_TRANSLATE(vldr)(unsigned int inst, int index)
4647{ 3523{
4648 VFP_DEBUG_TRANSLATE; 3524 VFP_DEBUG_TRANSLATE;
4649 3525
4650 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 3526 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vldr_inst));
4651 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 3527 vldr_inst *inst_cream = (vldr_inst *)inst_base->component;
4652 3528
4653 inst_base->cond = BITS(inst, 28, 31); 3529 inst_base->cond = BITS(inst, 28, 31);
4654 inst_base->idx = index; 3530 inst_base->idx = index;
@@ -4665,13 +3541,12 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
4665} 3541}
4666#endif 3542#endif
4667#ifdef VFP_INTERPRETER_IMPL 3543#ifdef VFP_INTERPRETER_IMPL
4668VFPLABEL_INST: 3544VLDR_INST:
4669{ 3545{
4670 INC_ICOUNTER;
4671 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 3546 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4672 CHECK_VFP_ENABLED; 3547 CHECK_VFP_ENABLED;
4673 3548
4674 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 3549 vldr_inst *inst_cream = (vldr_inst *)inst_base->component;
4675 3550
4676 unsigned int base = (inst_cream->n == 15 ? (cpu->Reg[inst_cream->n] & 0xFFFFFFFC) + 8 : cpu->Reg[inst_cream->n]); 3551 unsigned int base = (inst_cream->n == 15 ? (cpu->Reg[inst_cream->n] & 0xFFFFFFFC) + 8 : cpu->Reg[inst_cream->n]);
4677 addr = (inst_cream->add ? base + inst_cream->imm32 : base - inst_cream->imm32); 3552 addr = (inst_cream->add ? base + inst_cream->imm32 : base - inst_cream->imm32);
@@ -4710,69 +3585,12 @@ VFPLABEL_INST:
4710 GOTO_NEXT_INST; 3585 GOTO_NEXT_INST;
4711} 3586}
4712#endif 3587#endif
4713#ifdef VFP_LDC_TRANS
4714if (P == 1 && W == 0)
4715{
4716 return VLDR(state, type, instr, value);
4717}
4718#endif
4719#ifdef VFP_LDC_IMPL
4720int VLDR(ARMul_State * state, int type, ARMword instr, ARMword value)
4721{
4722 static int i = 0;
4723 static int single_reg, add, d, n, imm32, regs;
4724 if (type == ARMul_FIRST)
4725 {
4726 single_reg = BIT(8) == 0; /* Double precision */
4727 add = BIT(23); /* */
4728 imm32 = BITS(0,7)<<2; /* may not be used */
4729 d = single_reg ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */
4730 n = BITS(16, 19); /* destination register */
4731
4732 DBG("VLDR :\n");
4733
4734 i = 0;
4735 regs = 1;
4736
4737 return ARMul_DONE;
4738 }
4739 else if (type == ARMul_TRANSFER)
4740 {
4741 return ARMul_DONE;
4742 }
4743 else if (type == ARMul_DATA)
4744 {
4745 if (single_reg)
4746 {
4747 state->ExtReg[d+i] = value;
4748 DBG("\ts%d <= [%x]\n", d+i, value);
4749 i++;
4750 if (i < regs)
4751 return ARMul_INC;
4752 else
4753 return ARMul_DONE;
4754 }
4755 else
4756 {
4757 /* FIXME Careful of endianness, may need to rework this */
4758 state->ExtReg[d*2+i] = value;
4759 DBG("\ts[%d] <= [%x]\n", d*2+i, value);
4760 i++;
4761 if (i < regs*2)
4762 return ARMul_INC;
4763 else
4764 return ARMul_DONE;
4765 }
4766 }
4767 3588
4768 return -1;
4769}
4770#endif
4771#ifdef VFP_DYNCOM_TABLE 3589#ifdef VFP_DYNCOM_TABLE
4772DYNCOM_FILL_ACTION(vfpinstr), 3590DYNCOM_FILL_ACTION(vldr),
4773#endif 3591#endif
4774#ifdef VFP_DYNCOM_TAG 3592#ifdef VFP_DYNCOM_TAG
4775int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 3593int DYNCOM_TAG(vldr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
4776{ 3594{
4777 int instr_size = INSTR_SIZE; 3595 int instr_size = INSTR_SIZE;
4778 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 3596 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -4788,7 +3606,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
4788} 3606}
4789#endif 3607#endif
4790#ifdef VFP_DYNCOM_TRANS 3608#ifdef VFP_DYNCOM_TRANS
4791int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 3609int DYNCOM_TRANS(vldr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
4792 int single = BIT(8) == 0; 3610 int single = BIT(8) == 0;
4793 int add = BIT(23); 3611 int add = BIT(23);
4794 int wback = BIT(21); 3612 int wback = BIT(21);
@@ -4846,28 +3664,10 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
4846 return No_exp; 3664 return No_exp;
4847} 3665}
4848#endif 3666#endif
4849#undef vfpinstr
4850#undef vfpinstr_inst
4851#undef VFPLABEL_INST
4852 3667
4853/* ----------------------------------------------------------------------- */ 3668/* ----------------------------------------------------------------------- */
4854/* VLDM */ 3669/* VLDM */
4855/* cond 110P UDW1 Rn-- Vd-- 101X imm8 imm8 */ 3670/* cond 110P UDW1 Rn-- Vd-- 101X imm8 imm8 */
4856#define vfpinstr vldm
4857#define vfpinstr_inst vldm_inst
4858#define VFPLABEL_INST VLDM_INST
4859#ifdef VFP_DECODE
4860{"vldm", 3, ARMVFP2, 25, 27, 0x6, 20, 20, 1, 9, 11, 0x5},
4861#endif
4862#ifdef VFP_DECODE_EXCLUSION
4863{"vldm", 0, ARMVFP2, 0},
4864#endif
4865#ifdef VFP_INTERPRETER_TABLE
4866INTERPRETER_TRANSLATE(vfpinstr),
4867#endif
4868#ifdef VFP_INTERPRETER_LABEL
4869&&VFPLABEL_INST,
4870#endif
4871#ifdef VFP_INTERPRETER_STRUCT 3671#ifdef VFP_INTERPRETER_STRUCT
4872typedef struct _vldm_inst { 3672typedef struct _vldm_inst {
4873 unsigned int single; 3673 unsigned int single;
@@ -4877,15 +3677,15 @@ typedef struct _vldm_inst {
4877 unsigned int n; 3677 unsigned int n;
4878 unsigned int imm32; 3678 unsigned int imm32;
4879 unsigned int regs; 3679 unsigned int regs;
4880} vfpinstr_inst; 3680} vldm_inst;
4881#endif 3681#endif
4882#ifdef VFP_INTERPRETER_TRANS 3682#ifdef VFP_INTERPRETER_TRANS
4883ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index) 3683ARM_INST_PTR INTERPRETER_TRANSLATE(vldm)(unsigned int inst, int index)
4884{ 3684{
4885 VFP_DEBUG_TRANSLATE; 3685 VFP_DEBUG_TRANSLATE;
4886 3686
4887 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vfpinstr_inst)); 3687 arm_inst *inst_base = (arm_inst *)AllocBuffer(sizeof(arm_inst) + sizeof(vldm_inst));
4888 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 3688 vldm_inst *inst_cream = (vldm_inst *)inst_base->component;
4889 3689
4890 inst_base->cond = BITS(inst, 28, 31); 3690 inst_base->cond = BITS(inst, 28, 31);
4891 inst_base->idx = index; 3691 inst_base->idx = index;
@@ -4904,15 +3704,14 @@ ARM_INST_PTR INTERPRETER_TRANSLATE(vfpinstr)(unsigned int inst, int index)
4904} 3704}
4905#endif 3705#endif
4906#ifdef VFP_INTERPRETER_IMPL 3706#ifdef VFP_INTERPRETER_IMPL
4907VFPLABEL_INST: 3707VLDM_INST:
4908{ 3708{
4909 INC_ICOUNTER;
4910 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 3709 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) {
4911 CHECK_VFP_ENABLED; 3710 CHECK_VFP_ENABLED;
4912 3711
4913 int i; 3712 int i;
4914 3713
4915 vfpinstr_inst *inst_cream = (vfpinstr_inst *)inst_base->component; 3714 vldm_inst *inst_cream = (vldm_inst *)inst_base->component;
4916 3715
4917 addr = (inst_cream->add ? cpu->Reg[inst_cream->n] : cpu->Reg[inst_cream->n] - inst_cream->imm32); 3716 addr = (inst_cream->add ? cpu->Reg[inst_cream->n] : cpu->Reg[inst_cream->n] - inst_cream->imm32);
4918 DBG("VLDM : addr[%x]\n", addr); 3717 DBG("VLDM : addr[%x]\n", addr);
@@ -4952,74 +3751,17 @@ VFPLABEL_INST:
4952 3751
4953 } 3752 }
4954 cpu->Reg[15] += GET_INST_SIZE(cpu); 3753 cpu->Reg[15] += GET_INST_SIZE(cpu);
4955 INC_PC(sizeof(vfpinstr_inst)); 3754 INC_PC(sizeof(vldm_inst));
4956 FETCH_INST; 3755 FETCH_INST;
4957 GOTO_NEXT_INST; 3756 GOTO_NEXT_INST;
4958} 3757}
4959#endif 3758#endif
4960#ifdef VFP_LDC_TRANS
4961/* Should be the last operation of LDC */
4962return VLDM(state, type, instr, value);
4963#endif
4964#ifdef VFP_LDC_IMPL
4965int VLDM(ARMul_State * state, int type, ARMword instr, ARMword value)
4966{
4967 static int i = 0;
4968 static int single_regs, add, wback, d, n, imm32, regs;
4969 if (type == ARMul_FIRST)
4970 {
4971 single_regs = BIT(8) == 0; /* Single precision */
4972 add = BIT(23); /* */
4973 wback = BIT(21); /* write-back */
4974 d = single_regs ? BITS(12, 15)<<1|BIT(22) : BIT(22)<<4|BITS(12, 15); /* Base register */
4975 n = BITS(16, 19); /* destination register */
4976 imm32 = BITS(0,7) * 4; /* may not be used */
4977 regs = single_regs ? BITS(0, 7) : BITS(0, 7)>>1; /* FLDMX if regs is odd */
4978
4979 DBG("VLDM :\n");
4980
4981 if (wback) {
4982 state->Reg[n] = (add ? state->Reg[n] + imm32 : state->Reg[n] - imm32);
4983 DBG("\twback r%d[%x]\n", n, state->Reg[n]);
4984 }
4985
4986 i = 0;
4987
4988 return ARMul_DONE;
4989 }
4990 else if (type == ARMul_DATA)
4991 {
4992 if (single_regs)
4993 {
4994 state->ExtReg[d + i] = value;
4995 DBG("\ts%d <= [%x] addr[?]\n", d+i, state->ExtReg[d + i]);
4996 i++;
4997 if (i < regs)
4998 return ARMul_INC;
4999 else
5000 return ARMul_DONE;
5001 }
5002 else
5003 {
5004 /* FIXME Careful of endianness, may need to rework this */
5005 state->ExtReg[d*2 + i] = value;
5006 DBG("\ts[%d] <= [%x] addr[?]\n", d*2 + i, state->ExtReg[d*2 + i]);
5007 i++;
5008 if (i < regs*2)
5009 return ARMul_INC;
5010 else
5011 return ARMul_DONE;
5012 }
5013 }
5014 3759
5015 return -1;
5016}
5017#endif
5018#ifdef VFP_DYNCOM_TABLE 3760#ifdef VFP_DYNCOM_TABLE
5019DYNCOM_FILL_ACTION(vfpinstr), 3761DYNCOM_FILL_ACTION(vldm),
5020#endif 3762#endif
5021#ifdef VFP_DYNCOM_TAG 3763#ifdef VFP_DYNCOM_TAG
5022int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc) 3764int DYNCOM_TAG(vldm)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr_t *new_pc, addr_t *next_pc)
5023{ 3765{
5024 int instr_size = INSTR_SIZE; 3766 int instr_size = INSTR_SIZE;
5025 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__); 3767 //DBG("\t\tin %s instruction is not implemented.\n", __FUNCTION__);
@@ -5034,7 +3776,7 @@ int DYNCOM_TAG(vfpinstr)(cpu_t *cpu, addr_t pc, uint32_t instr, tag_t *tag, addr
5034} 3776}
5035#endif 3777#endif
5036#ifdef VFP_DYNCOM_TRANS 3778#ifdef VFP_DYNCOM_TRANS
5037int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){ 3779int DYNCOM_TRANS(vldm)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc){
5038 int single = BIT(8) == 0; 3780 int single = BIT(8) == 0;
5039 int add = BIT(23); 3781 int add = BIT(23);
5040 int wback = BIT(21); 3782 int wback = BIT(21);
@@ -5110,14 +3852,3 @@ int DYNCOM_TRANS(vfpinstr)(cpu_t *cpu, uint32_t instr, BasicBlock *bb, addr_t pc
5110 return No_exp; 3852 return No_exp;
5111} 3853}
5112#endif 3854#endif
5113#undef vfpinstr
5114#undef vfpinstr_inst
5115#undef VFPLABEL_INST
5116
5117#define VFP_DEBUG_TRANSLATE DBG("in func %s, %x\n", __FUNCTION__, inst);
5118#define VFP_DEBUG_UNIMPLEMENTED(x) printf("in func %s, " #x " unimplemented\n", __FUNCTION__); exit(-1);
5119#define VFP_DEBUG_UNTESTED(x) printf("in func %s, " #x " untested\n", __FUNCTION__);
5120
5121#define CHECK_VFP_ENABLED
5122
5123#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_OFFSET(VFP_FPSCR)]); //if (ret == -1) {printf("VFP CDP FAILURE %x\n", inst_cream->instr); exit(-1);}
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
index 07d0c1f44..6c33d8b78 100644
--- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
@@ -522,8 +522,7 @@ static s64 vfp_single_to_doubleintern(ARMul_State* state, s32 m, u32 fpscr) //ic
522 if (tm == VFP_QNAN) 522 if (tm == VFP_QNAN)
523 vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN; 523 vdd.significand |= VFP_DOUBLE_SIGNIFICAND_QNAN;
524 goto pack_nan; 524 goto pack_nan;
525 } 525 } else if (tm & VFP_ZERO)
526 else if (tm & VFP_ZERO)
527 vdd.exponent = 0; 526 vdd.exponent = 0;
528 else 527 else
529 vdd.exponent = vsm.exponent + (1023 - 127); 528 vdd.exponent = vsm.exponent + (1023 - 127);
@@ -615,12 +614,12 @@ static u32 vfp_single_ftoui(ARMul_State* state, int sd, int unused, s32 m, u32 f
615 exceptions |= FPSCR_IDC; 614 exceptions |= FPSCR_IDC;
616 615
617 if (tm & VFP_NAN) 616 if (tm & VFP_NAN)
618 vsm.sign = 0; 617 vsm.sign = 1;
619 618
620 if (vsm.exponent >= 127 + 32) { 619 if (vsm.exponent >= 127 + 32) {
621 d = vsm.sign ? 0 : 0xffffffff; 620 d = vsm.sign ? 0 : 0xffffffff;
622 exceptions = FPSCR_IOC; 621 exceptions = FPSCR_IOC;
623 } else if (vsm.exponent >= 127 - 1) { 622 } else if (vsm.exponent >= 127) {
624 int shift = 127 + 31 - vsm.exponent; 623 int shift = 127 + 31 - vsm.exponent;
625 u32 rem, incr = 0; 624 u32 rem, incr = 0;
626 625
@@ -705,7 +704,7 @@ static u32 vfp_single_ftosi(ARMul_State* state, int sd, int unused, s32 m, u32 f
705 if (vsm.sign) 704 if (vsm.sign)
706 d = ~d; 705 d = ~d;
707 exceptions |= FPSCR_IOC; 706 exceptions |= FPSCR_IOC;
708 } else if (vsm.exponent >= 127 - 1) { 707 } else if (vsm.exponent >= 127) {
709 int shift = 127 + 31 - vsm.exponent; 708 int shift = 127 + 31 - vsm.exponent;
710 u32 rem, incr = 0; 709 u32 rem, incr = 0;
711 710
@@ -1149,7 +1148,10 @@ static u32 vfp_single_fsub(ARMul_State* state, int sd, int sn, s32 m, u32 fpscr)
1149 /* 1148 /*
1150 * Subtraction is addition with one sign inverted. 1149 * Subtraction is addition with one sign inverted.
1151 */ 1150 */
1152 return vfp_single_fadd(state, sd, sn, vfp_single_packed_negate(m), fpscr); 1151 if (m != 0x7FC00000) // Only negate if m isn't NaN.
1152 m = vfp_single_packed_negate(m);
1153
1154 return vfp_single_fadd(state, sd, sn, m, fpscr);
1153} 1155}
1154 1156
1155/* 1157/*
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 865898b24..22213d647 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
@@ -47,7 +47,7 @@ void Stop() {
47 47
48/// Initialize the core 48/// Initialize the core
49int Init() { 49int Init() {
50 NOTICE_LOG(MASTER_LOG, "initialized OK"); 50 LOG_DEBUG(Core, "initialized OK");
51 51
52 disasm = new ARM_Disasm(); 52 disasm = new ARM_Disasm();
53 g_sys_core = new ARM_Interpreter(); 53 g_sys_core = new ARM_Interpreter();
@@ -72,7 +72,7 @@ void Shutdown() {
72 delete g_app_core; 72 delete g_app_core;
73 delete g_sys_core; 73 delete g_sys_core;
74 74
75 NOTICE_LOG(MASTER_LOG, "shutdown OK"); 75 LOG_DEBUG(Core, "shutdown OK");
76} 76}
77 77
78} // namespace 78} // namespace
diff --git a/src/core/core.h b/src/core/core.h
index 850bb0ab4..05dbe0ae5 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 558c6cbf7..321648b37 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <vector> 5#include <vector>
@@ -67,7 +67,7 @@ s64 idledCycles;
67static std::recursive_mutex externalEventSection; 67static std::recursive_mutex externalEventSection;
68 68
69// Warning: not included in save state. 69// Warning: not included in save state.
70void(*advanceCallback)(int cyclesExecuted) = NULL; 70void(*advanceCallback)(int cyclesExecuted) = nullptr;
71 71
72void SetClockFrequencyMHz(int cpuMhz) 72void SetClockFrequencyMHz(int cpuMhz)
73{ 73{
@@ -124,7 +124,7 @@ int RegisterEvent(const char *name, TimedCallback callback)
124 124
125void AntiCrashCallback(u64 userdata, int cyclesLate) 125void AntiCrashCallback(u64 userdata, int cyclesLate)
126{ 126{
127 ERROR_LOG(TIME, "Savestate broken: an unregistered event was called."); 127 LOG_CRITICAL(Core, "Savestate broken: an unregistered event was called.");
128 Core::Halt("invalid timing events"); 128 Core::Halt("invalid timing events");
129} 129}
130 130
@@ -176,7 +176,7 @@ void Shutdown()
176 176
177u64 GetTicks() 177u64 GetTicks()
178{ 178{
179 ERROR_LOG(TIME, "Unimplemented function!"); 179 LOG_ERROR(Core, "Unimplemented function!");
180 return 0; 180 return 0;
181 //return (u64)globalTimer + slicelength - currentMIPS->downcount; 181 //return (u64)globalTimer + slicelength - currentMIPS->downcount;
182} 182}
@@ -231,7 +231,7 @@ void ClearPendingEvents()
231 231
232void AddEventToQueue(Event* ne) 232void AddEventToQueue(Event* ne)
233{ 233{
234 Event* prev = NULL; 234 Event* prev = nullptr;
235 Event** pNext = &first; 235 Event** pNext = &first;
236 for (;;) 236 for (;;)
237 { 237 {
@@ -327,7 +327,7 @@ s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata)
327 } 327 }
328 if (!tsFirst) 328 if (!tsFirst)
329 { 329 {
330 tsLast = NULL; 330 tsLast = nullptr;
331 return result; 331 return result;
332 } 332 }
333 333
@@ -433,7 +433,7 @@ void RemoveThreadsafeEvent(int event_type)
433 } 433 }
434 if (!tsFirst) 434 if (!tsFirst)
435 { 435 {
436 tsLast = NULL; 436 tsLast = nullptr;
437 return; 437 return;
438 } 438 }
439 Event *prev = tsFirst; 439 Event *prev = tsFirst;
@@ -495,7 +495,7 @@ void MoveEvents()
495 AddEventToQueue(tsFirst); 495 AddEventToQueue(tsFirst);
496 tsFirst = next; 496 tsFirst = next;
497 } 497 }
498 tsLast = NULL; 498 tsLast = nullptr;
499 499
500 // Move free events to threadsafe pool 500 // Move free events to threadsafe pool
501 while (allocatedTsEvents > 0 && eventPool) 501 while (allocatedTsEvents > 0 && eventPool)
@@ -510,7 +510,7 @@ void MoveEvents()
510 510
511void Advance() 511void Advance()
512{ 512{
513 ERROR_LOG(TIME, "Unimplemented function!"); 513 LOG_ERROR(Core, "Unimplemented function!");
514 //int cyclesExecuted = slicelength - currentMIPS->downcount; 514 //int cyclesExecuted = slicelength - currentMIPS->downcount;
515 //globalTimer += cyclesExecuted; 515 //globalTimer += cyclesExecuted;
516 //currentMIPS->downcount = slicelength; 516 //currentMIPS->downcount = slicelength;
@@ -547,7 +547,7 @@ void LogPendingEvents()
547 547
548void Idle(int maxIdle) 548void Idle(int maxIdle)
549{ 549{
550 ERROR_LOG(TIME, "Unimplemented function!"); 550 LOG_ERROR(Core, "Unimplemented function!");
551 //int cyclesDown = currentMIPS->downcount; 551 //int cyclesDown = currentMIPS->downcount;
552 //if (maxIdle != 0 && cyclesDown > maxIdle) 552 //if (maxIdle != 0 && cyclesDown > maxIdle)
553 // cyclesDown = maxIdle; 553 // cyclesDown = maxIdle;
@@ -614,7 +614,7 @@ void DoState(PointerWrap &p)
614 // These (should) be filled in later by the modules. 614 // These (should) be filled in later by the modules.
615 event_types.resize(n, EventType(AntiCrashCallback, "INVALID EVENT")); 615 event_types.resize(n, EventType(AntiCrashCallback, "INVALID EVENT"));
616 616
617 p.DoLinkedList<BaseEvent, GetNewEvent, FreeEvent, Event_DoState>(first, (Event **)NULL); 617 p.DoLinkedList<BaseEvent, GetNewEvent, FreeEvent, Event_DoState>(first, (Event **)nullptr);
618 p.DoLinkedList<BaseEvent, GetNewTsEvent, FreeTsEvent, Event_DoState>(tsFirst, &tsLast); 618 p.DoLinkedList<BaseEvent, GetNewTsEvent, FreeTsEvent, Event_DoState>(tsFirst, &tsLast);
619 619
620 p.Do(g_clock_rate_arm11); 620 p.Do(g_clock_rate_arm11);
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index b197cf40c..496234538 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/core/file_sys/archive.h b/src/core/file_sys/archive.h
deleted file mode 100644
index 2e79bb883..000000000
--- a/src/core/file_sys/archive.h
+++ /dev/null
@@ -1,246 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8
9#include "common/common_types.h"
10#include "common/string_util.h"
11#include "common/bit_field.h"
12
13#include "core/file_sys/file.h"
14#include "core/file_sys/directory.h"
15
16#include "core/mem_map.h"
17#include "core/hle/kernel/kernel.h"
18
19////////////////////////////////////////////////////////////////////////////////////////////////////
20// FileSys namespace
21
22namespace FileSys {
23
24// Path string type
25enum LowPathType : u32 {
26 Invalid = 0,
27 Empty = 1,
28 Binary = 2,
29 Char = 3,
30 Wchar = 4
31};
32
33union Mode {
34 u32 hex;
35 BitField<0, 1, u32> read_flag;
36 BitField<1, 1, u32> write_flag;
37 BitField<2, 1, u32> create_flag;
38};
39
40class Path {
41public:
42
43 Path():
44 type(Invalid)
45 {
46 }
47
48 Path(LowPathType type, u32 size, u32 pointer):
49 type(type)
50 {
51 switch (type) {
52 case Binary:
53 {
54 u8* data = Memory::GetPointer(pointer);
55 binary = std::vector<u8>(data, data + size);
56 break;
57 }
58 case Char:
59 {
60 const char* data = reinterpret_cast<const char*>(Memory::GetPointer(pointer));
61 string = std::string(data, size - 1); // Data is always null-terminated.
62 break;
63 }
64 case Wchar:
65 {
66 const char16_t* data = reinterpret_cast<const char16_t*>(Memory::GetPointer(pointer));
67 u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated.
68 break;
69 }
70 }
71 }
72
73 LowPathType GetType() const {
74 return type;
75 }
76
77 /**
78 * Gets the string representation of the path for debugging
79 * @return String representation of the path for debugging
80 */
81 const std::string DebugStr() const {
82 switch (GetType()) {
83 case Invalid:
84 return "[Invalid]";
85 case Empty:
86 return "[Empty]";
87 case Binary:
88 {
89 std::stringstream res;
90 res << "[Binary: ";
91 for (unsigned byte : binary)
92 res << std::hex << std::setw(2) << std::setfill('0') << byte;
93 res << ']';
94 return res.str();
95 }
96 case Char:
97 return "[Char: " + AsString() + ']';
98 case Wchar:
99 return "[Wchar: " + AsString() + ']';
100 default:
101 ERROR_LOG(KERNEL, "LowPathType cannot be converted to string!");
102 return {};
103 }
104 }
105
106 const std::string AsString() const {
107 switch (GetType()) {
108 case Char:
109 return string;
110 case Wchar:
111 return Common::UTF16ToUTF8(u16str);
112 case Empty:
113 return {};
114 default:
115 ERROR_LOG(KERNEL, "LowPathType cannot be converted to string!");
116 return {};
117 }
118 }
119
120 const std::u16string AsU16Str() const {
121 switch (GetType()) {
122 case Char:
123 return Common::UTF8ToUTF16(string);
124 case Wchar:
125 return u16str;
126 case Empty:
127 return {};
128 default:
129 ERROR_LOG(KERNEL, "LowPathType cannot be converted to u16string!");
130 return {};
131 }
132 }
133
134 const std::vector<u8> AsBinary() const {
135 switch (GetType()) {
136 case Binary:
137 return binary;
138 case Char:
139 return std::vector<u8>(string.begin(), string.end());
140 case Wchar:
141 return std::vector<u8>(u16str.begin(), u16str.end());
142 case Empty:
143 return {};
144 default:
145 ERROR_LOG(KERNEL, "LowPathType cannot be converted to binary!");
146 return {};
147 }
148 }
149
150private:
151 LowPathType type;
152 std::vector<u8> binary;
153 std::string string;
154 std::u16string u16str;
155};
156
157class Archive : NonCopyable {
158public:
159 /// Supported archive types
160 enum class IdCode : u32 {
161 RomFS = 0x00000003,
162 SaveData = 0x00000004,
163 ExtSaveData = 0x00000006,
164 SharedExtSaveData = 0x00000007,
165 SystemSaveData = 0x00000008,
166 SDMC = 0x00000009,
167 SDMCWriteOnly = 0x0000000A,
168 };
169
170 Archive() { }
171 virtual ~Archive() { }
172
173 /**
174 * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.)
175 * @return IdCode of the archive
176 */
177 virtual IdCode GetIdCode() const = 0;
178
179 /**
180 * Open a file specified by its path, using the specified mode
181 * @param path Path relative to the archive
182 * @param mode Mode to open the file with
183 * @return Opened file, or nullptr
184 */
185 virtual std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const = 0;
186
187 /**
188 * Delete a file specified by its path
189 * @param path Path relative to the archive
190 * @return Whether the file could be deleted
191 */
192 virtual bool DeleteFile(const FileSys::Path& path) const = 0;
193
194 /**
195 * Delete a directory specified by its path
196 * @param path Path relative to the archive
197 * @return Whether the directory could be deleted
198 */
199 virtual bool DeleteDirectory(const FileSys::Path& path) const = 0;
200
201 /**
202 * Create a directory specified by its path
203 * @param path Path relative to the archive
204 * @return Whether the directory could be created
205 */
206 virtual bool CreateDirectory(const Path& path) const = 0;
207
208 /**
209 * Open a directory specified by its path
210 * @param path Path relative to the archive
211 * @return Opened directory, or nullptr
212 */
213 virtual std::unique_ptr<Directory> OpenDirectory(const Path& path) const = 0;
214
215 /**
216 * Read data from the archive
217 * @param offset Offset in bytes to start reading data from
218 * @param length Length in bytes of data to read from archive
219 * @param buffer Buffer to read data into
220 * @return Number of bytes read
221 */
222 virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0;
223
224 /**
225 * Write data to the archive
226 * @param offset Offset in bytes to start writing data to
227 * @param length Length in bytes of data to write to archive
228 * @param buffer Buffer to write data from
229 * @param flush The flush parameters (0 == do not flush)
230 * @return Number of bytes written
231 */
232 virtual size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) = 0;
233
234 /**
235 * Get the size of the archive in bytes
236 * @return Size of the archive in bytes
237 */
238 virtual size_t GetSize() const = 0;
239
240 /**
241 * Set the size of the archive in bytes
242 */
243 virtual void SetSize(const u64 size) = 0;
244};
245
246} // namespace FileSys
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h
new file mode 100644
index 000000000..e153917ea
--- /dev/null
+++ b/src/core/file_sys/archive_backend.h
@@ -0,0 +1,243 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8
9#include "common/common_types.h"
10#include "common/string_util.h"
11#include "common/bit_field.h"
12
13#include "core/file_sys/file_backend.h"
14#include "core/file_sys/directory_backend.h"
15
16#include "core/mem_map.h"
17#include "core/hle/kernel/kernel.h"
18
19////////////////////////////////////////////////////////////////////////////////////////////////////
20// FileSys namespace
21
22namespace FileSys {
23
24// Path string type
25enum LowPathType : u32 {
26 Invalid = 0,
27 Empty = 1,
28 Binary = 2,
29 Char = 3,
30 Wchar = 4
31};
32
33union Mode {
34 u32 hex;
35 BitField<0, 1, u32> read_flag;
36 BitField<1, 1, u32> write_flag;
37 BitField<2, 1, u32> create_flag;
38};
39
40class Path {
41public:
42
43 Path() : type(Invalid) {
44 }
45
46 Path(const char* path) : type(Char), string(path) {
47 }
48
49 Path(LowPathType type, u32 size, u32 pointer) : type(type) {
50 switch (type) {
51 case Binary:
52 {
53 u8* data = Memory::GetPointer(pointer);
54 binary = std::vector<u8>(data, data + size);
55 break;
56 }
57
58 case Char:
59 {
60 const char* data = reinterpret_cast<const char*>(Memory::GetPointer(pointer));
61 string = std::string(data, size - 1); // Data is always null-terminated.
62 break;
63 }
64
65 case Wchar:
66 {
67 const char16_t* data = reinterpret_cast<const char16_t*>(Memory::GetPointer(pointer));
68 u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated.
69 break;
70 }
71
72 default:
73 break;
74 }
75 }
76
77 LowPathType GetType() const {
78 return type;
79 }
80
81 /**
82 * Gets the string representation of the path for debugging
83 * @return String representation of the path for debugging
84 */
85 const std::string DebugStr() const {
86 switch (GetType()) {
87 case Invalid:
88 return "[Invalid]";
89 case Empty:
90 return "[Empty]";
91 case Binary:
92 {
93 std::stringstream res;
94 res << "[Binary: ";
95 for (unsigned byte : binary)
96 res << std::hex << std::setw(2) << std::setfill('0') << byte;
97 res << ']';
98 return res.str();
99 }
100 case Char:
101 return "[Char: " + AsString() + ']';
102 case Wchar:
103 return "[Wchar: " + AsString() + ']';
104 }
105 }
106
107 const std::string AsString() const {
108 switch (GetType()) {
109 case Char:
110 return string;
111 case Wchar:
112 return Common::UTF16ToUTF8(u16str);
113 case Empty:
114 return {};
115 case Invalid:
116 case Binary:
117 // TODO(yuriks): Add assert
118 LOG_ERROR(Service_FS, "LowPathType cannot be converted to string!");
119 return {};
120 }
121 }
122
123 const std::u16string AsU16Str() const {
124 switch (GetType()) {
125 case Char:
126 return Common::UTF8ToUTF16(string);
127 case Wchar:
128 return u16str;
129 case Empty:
130 return {};
131 case Invalid:
132 case Binary:
133 // TODO(yuriks): Add assert
134 LOG_ERROR(Service_FS, "LowPathType cannot be converted to u16string!");
135 return {};
136 }
137 }
138
139 const std::vector<u8> AsBinary() const {
140 switch (GetType()) {
141 case Binary:
142 return binary;
143 case Char:
144 return std::vector<u8>(string.begin(), string.end());
145 case Wchar:
146 {
147 // use two u8 for each character of u16str
148 std::vector<u8> to_return(u16str.size() * 2);
149 for (size_t i = 0; i < u16str.size(); ++i) {
150 u16 tmp_char = u16str.at(i);
151 to_return[i*2] = (tmp_char & 0xFF00) >> 8;
152 to_return[i*2 + 1] = (tmp_char & 0x00FF);
153 }
154 return to_return;
155 }
156 case Empty:
157 return {};
158 case Invalid:
159 // TODO(yuriks): Add assert
160 LOG_ERROR(Service_FS, "LowPathType cannot be converted to binary!");
161 return {};
162 }
163 }
164
165private:
166 LowPathType type;
167 std::vector<u8> binary;
168 std::string string;
169 std::u16string u16str;
170};
171
172class ArchiveBackend : NonCopyable {
173public:
174 virtual ~ArchiveBackend() {
175 }
176
177 /**
178 * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.)
179 */
180 virtual std::string GetName() const = 0;
181
182 /**
183 * Open a file specified by its path, using the specified mode
184 * @param path Path relative to the archive
185 * @param mode Mode to open the file with
186 * @return Opened file, or nullptr
187 */
188 virtual std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const = 0;
189
190 /**
191 * Delete a file specified by its path
192 * @param path Path relative to the archive
193 * @return Whether the file could be deleted
194 */
195 virtual bool DeleteFile(const Path& path) const = 0;
196
197 /**
198 * Rename a File specified by its path
199 * @param src_path Source path relative to the archive
200 * @param dest_path Destination path relative to the archive
201 * @return Whether rename succeeded
202 */
203 virtual bool RenameFile(const Path& src_path, const Path& dest_path) const = 0;
204
205 /**
206 * Delete a directory specified by its path
207 * @param path Path relative to the archive
208 * @return Whether the directory could be deleted
209 */
210 virtual bool DeleteDirectory(const Path& path) const = 0;
211
212 /**
213 * Create a file specified by its path
214 * @param path Path relative to the Archive
215 * @param size The size of the new file, filled with zeroes
216 * @return File creation result code
217 */
218 virtual ResultCode CreateFile(const Path& path, u32 size) const = 0;
219
220 /**
221 * Create a directory specified by its path
222 * @param path Path relative to the archive
223 * @return Whether the directory could be created
224 */
225 virtual bool CreateDirectory(const Path& path) const = 0;
226
227 /**
228 * Rename a Directory specified by its path
229 * @param src_path Source path relative to the archive
230 * @param dest_path Destination path relative to the archive
231 * @return Whether rename succeeded
232 */
233 virtual bool RenameDirectory(const Path& src_path, const Path& dest_path) const = 0;
234
235 /**
236 * Open a directory specified by its path
237 * @param path Path relative to the archive
238 * @return Opened directory, or nullptr
239 */
240 virtual std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const = 0;
241};
242
243} // namespace FileSys
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp
index 53dc57954..fdaf73179 100644
--- a/src/core/file_sys/archive_romfs.cpp
+++ b/src/core/file_sys/archive_romfs.cpp
@@ -1,8 +1,11 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <memory>
6
5#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/make_unique.h"
6 9
7#include "core/file_sys/archive_romfs.h" 10#include "core/file_sys/archive_romfs.h"
8#include "core/file_sys/directory_romfs.h" 11#include "core/file_sys/directory_romfs.h"
@@ -16,101 +19,47 @@ namespace FileSys {
16Archive_RomFS::Archive_RomFS(const Loader::AppLoader& app_loader) { 19Archive_RomFS::Archive_RomFS(const Loader::AppLoader& app_loader) {
17 // Load the RomFS from the app 20 // Load the RomFS from the app
18 if (Loader::ResultStatus::Success != app_loader.ReadRomFS(raw_data)) { 21 if (Loader::ResultStatus::Success != app_loader.ReadRomFS(raw_data)) {
19 WARN_LOG(FILESYS, "Unable to read RomFS!"); 22 LOG_ERROR(Service_FS, "Unable to read RomFS!");
20 } 23 }
21} 24}
22 25
23Archive_RomFS::~Archive_RomFS() { 26std::unique_ptr<FileBackend> Archive_RomFS::OpenFile(const Path& path, const Mode mode) const {
24} 27 return Common::make_unique<File_RomFS>(this);
25
26/**
27 * Open a file specified by its path, using the specified mode
28 * @param path Path relative to the archive
29 * @param mode Mode to open the file with
30 * @return Opened file, or nullptr
31 */
32std::unique_ptr<File> Archive_RomFS::OpenFile(const Path& path, const Mode mode) const {
33 return std::unique_ptr<File>(new File_RomFS);
34} 28}
35 29
36/** 30bool Archive_RomFS::DeleteFile(const Path& path) const {
37 * Delete a file specified by its path 31 LOG_WARNING(Service_FS, "Attempted to delete a file from ROMFS.");
38 * @param path Path relative to the archive
39 * @return Whether the file could be deleted
40 */
41bool Archive_RomFS::DeleteFile(const FileSys::Path& path) const {
42 ERROR_LOG(FILESYS, "Attempted to delete a file from ROMFS.");
43 return false; 32 return false;
44} 33}
45 34
46/** 35bool Archive_RomFS::RenameFile(const Path& src_path, const Path& dest_path) const {
47 * Delete a directory specified by its path 36 LOG_WARNING(Service_FS, "Attempted to rename a file within ROMFS.");
48 * @param path Path relative to the archive
49 * @return Whether the directory could be deleted
50 */
51bool Archive_RomFS::DeleteDirectory(const FileSys::Path& path) const {
52 ERROR_LOG(FILESYS, "Attempted to delete a directory from ROMFS.");
53 return false; 37 return false;
54} 38}
55 39
56/** 40bool Archive_RomFS::DeleteDirectory(const Path& path) const {
57 * Create a directory specified by its path 41 LOG_WARNING(Service_FS, "Attempted to delete a directory from ROMFS.");
58 * @param path Path relative to the archive
59 * @return Whether the directory could be created
60 */
61bool Archive_RomFS::CreateDirectory(const Path& path) const {
62 ERROR_LOG(FILESYS, "Attempted to create a directory in ROMFS.");
63 return false; 42 return false;
64} 43}
65 44
66/** 45ResultCode Archive_RomFS::CreateFile(const Path& path, u32 size) const {
67 * Open a directory specified by its path 46 LOG_WARNING(Service_FS, "Attempted to create a file in ROMFS.");
68 * @param path Path relative to the archive 47 // TODO: Verify error code
69 * @return Opened directory, or nullptr 48 return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::FS, ErrorSummary::NotSupported, ErrorLevel::Permanent);
70 */
71std::unique_ptr<Directory> Archive_RomFS::OpenDirectory(const Path& path) const {
72 return std::unique_ptr<Directory>(new Directory_RomFS);
73} 49}
74 50
75/** 51bool Archive_RomFS::CreateDirectory(const Path& path) const {
76 * Read data from the archive 52 LOG_WARNING(Service_FS, "Attempted to create a directory in ROMFS.");
77 * @param offset Offset in bytes to start reading data from 53 return false;
78 * @param length Length in bytes of data to read from archive
79 * @param buffer Buffer to read data into
80 * @return Number of bytes read
81 */
82size_t Archive_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const {
83 DEBUG_LOG(FILESYS, "called offset=%llu, length=%d", offset, length);
84 memcpy(buffer, &raw_data[(u32)offset], length);
85 return length;
86}
87
88/**
89 * Write data to the archive
90 * @param offset Offset in bytes to start writing data to
91 * @param length Length in bytes of data to write to archive
92 * @param buffer Buffer to write data from
93 * @param flush The flush parameters (0 == do not flush)
94 * @return Number of bytes written
95 */
96size_t Archive_RomFS::Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) {
97 ERROR_LOG(FILESYS, "Attempted to write to ROMFS.");
98 return 0;
99} 54}
100 55
101/** 56bool Archive_RomFS::RenameDirectory(const Path& src_path, const Path& dest_path) const {
102 * Get the size of the archive in bytes 57 LOG_WARNING(Service_FS, "Attempted to rename a file within ROMFS.");
103 * @return Size of the archive in bytes 58 return false;
104 */
105size_t Archive_RomFS::GetSize() const {
106 return sizeof(u8) * raw_data.size();
107} 59}
108 60
109/** 61std::unique_ptr<DirectoryBackend> Archive_RomFS::OpenDirectory(const Path& path) const {
110 * Set the size of the archive in bytes 62 return Common::make_unique<Directory_RomFS>();
111 */
112void Archive_RomFS::SetSize(const u64 size) {
113 ERROR_LOG(FILESYS, "Attempted to set the size of ROMFS");
114} 63}
115 64
116} // namespace FileSys 65} // namespace FileSys
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h
index 0649dde99..5e918f92d 100644
--- a/src/core/file_sys/archive_romfs.h
+++ b/src/core/file_sys/archive_romfs.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -8,7 +8,7 @@
8 8
9#include "common/common_types.h" 9#include "common/common_types.h"
10 10
11#include "core/file_sys/archive.h" 11#include "core/file_sys/archive_backend.h"
12#include "core/loader/loader.h" 12#include "core/loader/loader.h"
13 13
14//////////////////////////////////////////////////////////////////////////////////////////////////// 14////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -17,16 +17,11 @@
17namespace FileSys { 17namespace FileSys {
18 18
19/// File system interface to the RomFS archive 19/// File system interface to the RomFS archive
20class Archive_RomFS final : public Archive { 20class Archive_RomFS final : public ArchiveBackend {
21public: 21public:
22 Archive_RomFS(const Loader::AppLoader& app_loader); 22 Archive_RomFS(const Loader::AppLoader& app_loader);
23 ~Archive_RomFS() override;
24 23
25 /** 24 std::string GetName() const override { return "RomFS"; }
26 * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.)
27 * @return IdCode of the archive
28 */
29 IdCode GetIdCode() const override { return IdCode::RomFS; }
30 25
31 /** 26 /**
32 * Open a file specified by its path, using the specified mode 27 * Open a file specified by its path, using the specified mode
@@ -34,67 +29,63 @@ public:
34 * @param mode Mode to open the file with 29 * @param mode Mode to open the file with
35 * @return Opened file, or nullptr 30 * @return Opened file, or nullptr
36 */ 31 */
37 std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const override; 32 std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override;
38 33
39 /** 34 /**
40 * Delete a file specified by its path 35 * Delete a file specified by its path
41 * @param path Path relative to the archive 36 * @param path Path relative to the archive
42 * @return Whether the file could be deleted 37 * @return Whether the file could be deleted
43 */ 38 */
44 bool DeleteFile(const FileSys::Path& path) const override; 39 bool DeleteFile(const Path& path) const override;
45
46 /**
47 * Delete a directory specified by its path
48 * @param path Path relative to the archive
49 * @return Whether the directory could be deleted
50 */
51 bool DeleteDirectory(const FileSys::Path& path) const override;
52 40
53 /** 41 /**
54 * Create a directory specified by its path 42 * Rename a File specified by its path
55 * @param path Path relative to the archive 43 * @param src_path Source path relative to the archive
56 * @return Whether the directory could be created 44 * @param dest_path Destination path relative to the archive
45 * @return Whether rename succeeded
57 */ 46 */
58 bool CreateDirectory(const Path& path) const override; 47 bool RenameFile(const Path& src_path, const Path& dest_path) const override;
59 48
60 /** 49 /**
61 * Open a directory specified by its path 50 * Delete a directory specified by its path
62 * @param path Path relative to the archive 51 * @param path Path relative to the archive
63 * @return Opened directory, or nullptr 52 * @return Whether the directory could be deleted
64 */ 53 */
65 std::unique_ptr<Directory> OpenDirectory(const Path& path) const override; 54 bool DeleteDirectory(const Path& path) const override;
66 55
67 /** 56 /**
68 * Read data from the archive 57 * Create a file specified by its path
69 * @param offset Offset in bytes to start reading data from 58 * @param path Path relative to the Archive
70 * @param length Length in bytes of data to read from archive 59 * @param size The size of the new file, filled with zeroes
71 * @param buffer Buffer to read data into 60 * @return File creation result code
72 * @return Number of bytes read
73 */ 61 */
74 size_t Read(const u64 offset, const u32 length, u8* buffer) const override; 62 ResultCode CreateFile(const Path& path, u32 size) const override;
75 63
76 /** 64 /**
77 * Write data to the archive 65 * Create a directory specified by its path
78 * @param offset Offset in bytes to start writing data to 66 * @param path Path relative to the archive
79 * @param length Length in bytes of data to write to archive 67 * @return Whether the directory could be created
80 * @param buffer Buffer to write data from
81 * @param flush The flush parameters (0 == do not flush)
82 * @return Number of bytes written
83 */ 68 */
84 size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) override; 69 bool CreateDirectory(const Path& path) const override;
85 70
86 /** 71 /**
87 * Get the size of the archive in bytes 72 * Rename a Directory specified by its path
88 * @return Size of the archive in bytes 73 * @param src_path Source path relative to the archive
74 * @param dest_path Destination path relative to the archive
75 * @return Whether rename succeeded
89 */ 76 */
90 size_t GetSize() const override; 77 bool RenameDirectory(const Path& src_path, const Path& dest_path) const override;
91 78
92 /** 79 /**
93 * Set the size of the archive in bytes 80 * Open a directory specified by its path
81 * @param path Path relative to the archive
82 * @return Opened directory, or nullptr
94 */ 83 */
95 void SetSize(const u64 size) override; 84 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
96 85
97private: 86private:
87 friend class File_RomFS;
88
98 std::vector<u8> raw_data; 89 std::vector<u8> raw_data;
99}; 90};
100 91
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
new file mode 100644
index 000000000..97853567c
--- /dev/null
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -0,0 +1,33 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/archive_savedata.h"
11#include "core/file_sys/disk_archive.h"
12#include "core/settings.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace
16
17namespace FileSys {
18
19Archive_SaveData::Archive_SaveData(const std::string& mount_point, u64 program_id)
20 : DiskArchive(mount_point + Common::StringFromFormat("%016X", program_id) + DIR_SEP) {
21 LOG_INFO(Service_FS, "Directory %s set as SaveData.", this->mount_point.c_str());
22}
23
24bool Archive_SaveData::Initialize() {
25 if (!FileUtil::CreateFullPath(mount_point)) {
26 LOG_ERROR(Service_FS, "Unable to create SaveData path.");
27 return false;
28 }
29
30 return true;
31}
32
33} // namespace FileSys
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h
new file mode 100644
index 000000000..5b0ce29e6
--- /dev/null
+++ b/src/core/file_sys/archive_savedata.h
@@ -0,0 +1,31 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/file_sys/disk_archive.h"
10#include "core/loader/loader.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace
14
15namespace FileSys {
16
17/// File system interface to the SaveData archive
18class Archive_SaveData final : public DiskArchive {
19public:
20 Archive_SaveData(const std::string& mount_point, u64 program_id);
21
22 /**
23 * Initialize the archive.
24 * @return true if it initialized successfully
25 */
26 bool Initialize();
27
28 std::string GetName() const override { return "SaveData"; }
29};
30
31} // namespace FileSys
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index c2ffcd40d..1c1c170b6 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <sys/stat.h> 5#include <sys/stat.h>
@@ -8,8 +8,7 @@
8#include "common/file_util.h" 8#include "common/file_util.h"
9 9
10#include "core/file_sys/archive_sdmc.h" 10#include "core/file_sys/archive_sdmc.h"
11#include "core/file_sys/directory_sdmc.h" 11#include "core/file_sys/disk_archive.h"
12#include "core/file_sys/file_sdmc.h"
13#include "core/settings.h" 12#include "core/settings.h"
14 13
15//////////////////////////////////////////////////////////////////////////////////////////////////// 14////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -17,131 +16,22 @@
17 16
18namespace FileSys { 17namespace FileSys {
19 18
20Archive_SDMC::Archive_SDMC(const std::string& mount_point) { 19Archive_SDMC::Archive_SDMC(const std::string& mount_point) : DiskArchive(mount_point) {
21 this->mount_point = mount_point; 20 LOG_INFO(Service_FS, "Directory %s set as SDMC.", mount_point.c_str());
22 DEBUG_LOG(FILESYS, "Directory %s set as SDMC.", mount_point.c_str());
23} 21}
24 22
25Archive_SDMC::~Archive_SDMC() {
26}
27
28/**
29 * Initialize the archive.
30 * @return true if it initialized successfully
31 */
32bool Archive_SDMC::Initialize() { 23bool Archive_SDMC::Initialize() {
33 if (!Settings::values.use_virtual_sd) { 24 if (!Settings::values.use_virtual_sd) {
34 WARN_LOG(FILESYS, "SDMC disabled by config."); 25 LOG_WARNING(Service_FS, "SDMC disabled by config.");
35 return false; 26 return false;
36 } 27 }
37 28
38 if (!FileUtil::CreateFullPath(mount_point)) { 29 if (!FileUtil::CreateFullPath(mount_point)) {
39 WARN_LOG(FILESYS, "Unable to create SDMC path."); 30 LOG_ERROR(Service_FS, "Unable to create SDMC path.");
40 return false; 31 return false;
41 } 32 }
42 33
43 return true; 34 return true;
44} 35}
45 36
46/**
47 * Open a file specified by its path, using the specified mode
48 * @param path Path relative to the archive
49 * @param mode Mode to open the file with
50 * @return Opened file, or nullptr
51 */
52std::unique_ptr<File> Archive_SDMC::OpenFile(const Path& path, const Mode mode) const {
53 DEBUG_LOG(FILESYS, "called path=%s mode=%d", path.DebugStr().c_str(), mode);
54 File_SDMC* file = new File_SDMC(this, path, mode);
55 if (!file->Open())
56 return nullptr;
57 return std::unique_ptr<File>(file);
58}
59
60/**
61 * Delete a file specified by its path
62 * @param path Path relative to the archive
63 * @return Whether the file could be deleted
64 */
65bool Archive_SDMC::DeleteFile(const FileSys::Path& path) const {
66 return FileUtil::Delete(GetMountPoint() + path.AsString());
67}
68
69/**
70 * Delete a directory specified by its path
71 * @param path Path relative to the archive
72 * @return Whether the directory could be deleted
73 */
74bool Archive_SDMC::DeleteDirectory(const FileSys::Path& path) const {
75 return FileUtil::DeleteDir(GetMountPoint() + path.AsString());
76}
77
78/**
79 * Create a directory specified by its path
80 * @param path Path relative to the archive
81 * @return Whether the directory could be created
82 */
83bool Archive_SDMC::CreateDirectory(const Path& path) const {
84 return FileUtil::CreateDir(GetMountPoint() + path.AsString());
85}
86
87/**
88 * Open a directory specified by its path
89 * @param path Path relative to the archive
90 * @return Opened directory, or nullptr
91 */
92std::unique_ptr<Directory> Archive_SDMC::OpenDirectory(const Path& path) const {
93 DEBUG_LOG(FILESYS, "called path=%s", path.DebugStr().c_str());
94 Directory_SDMC* directory = new Directory_SDMC(this, path);
95 return std::unique_ptr<Directory>(directory);
96}
97
98/**
99 * Read data from the archive
100 * @param offset Offset in bytes to start reading archive from
101 * @param length Length in bytes to read data from archive
102 * @param buffer Buffer to read data into
103 * @return Number of bytes read
104 */
105size_t Archive_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const {
106 ERROR_LOG(FILESYS, "(UNIMPLEMENTED)");
107 return -1;
108}
109
110/**
111 * Write data to the archive
112 * @param offset Offset in bytes to start writing data to
113 * @param length Length in bytes of data to write to archive
114 * @param buffer Buffer to write data from
115 * @param flush The flush parameters (0 == do not flush)
116 * @return Number of bytes written
117 */
118size_t Archive_SDMC::Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) {
119 ERROR_LOG(FILESYS, "(UNIMPLEMENTED)");
120 return -1;
121}
122
123/**
124 * Get the size of the archive in bytes
125 * @return Size of the archive in bytes
126 */
127size_t Archive_SDMC::GetSize() const {
128 ERROR_LOG(FILESYS, "(UNIMPLEMENTED)");
129 return 0;
130}
131
132/**
133 * Set the size of the archive in bytes
134 */
135void Archive_SDMC::SetSize(const u64 size) {
136 ERROR_LOG(FILESYS, "(UNIMPLEMENTED)");
137}
138
139/**
140 * Getter for the path used for this Archive
141 * @return Mount point of that passthrough archive
142 */
143std::string Archive_SDMC::GetMountPoint() const {
144 return mount_point;
145}
146
147} // namespace FileSys 37} // namespace FileSys
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index 74ce29c0d..1b801f217 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -1,12 +1,12 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8 8
9#include "core/file_sys/archive.h" 9#include "core/file_sys/disk_archive.h"
10#include "core/loader/loader.h" 10#include "core/loader/loader.h"
11 11
12//////////////////////////////////////////////////////////////////////////////////////////////////// 12////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -15,10 +15,9 @@
15namespace FileSys { 15namespace FileSys {
16 16
17/// File system interface to the SDMC archive 17/// File system interface to the SDMC archive
18class Archive_SDMC final : public Archive { 18class Archive_SDMC final : public DiskArchive {
19public: 19public:
20 Archive_SDMC(const std::string& mount_point); 20 Archive_SDMC(const std::string& mount_point);
21 ~Archive_SDMC() override;
22 21
23 /** 22 /**
24 * Initialize the archive. 23 * Initialize the archive.
@@ -26,86 +25,7 @@ public:
26 */ 25 */
27 bool Initialize(); 26 bool Initialize();
28 27
29 /** 28 std::string GetName() const override { return "SDMC"; }
30 * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.)
31 * @return IdCode of the archive
32 */
33 IdCode GetIdCode() const override { return IdCode::SDMC; }
34
35 /**
36 * Open a file specified by its path, using the specified mode
37 * @param path Path relative to the archive
38 * @param mode Mode to open the file with
39 * @return Opened file, or nullptr
40 */
41 std::unique_ptr<File> OpenFile(const Path& path, const Mode mode) const override;
42
43 /**
44 * Delete a file specified by its path
45 * @param path Path relative to the archive
46 * @return Whether the file could be deleted
47 */
48 bool DeleteFile(const FileSys::Path& path) const override;
49
50 /**
51 * Delete a directory specified by its path
52 * @param path Path relative to the archive
53 * @return Whether the directory could be deleted
54 */
55 bool DeleteDirectory(const FileSys::Path& path) const override;
56
57 /**
58 * Create a directory specified by its path
59 * @param path Path relative to the archive
60 * @return Whether the directory could be created
61 */
62 bool CreateDirectory(const Path& path) const override;
63
64 /**
65 * Open a directory specified by its path
66 * @param path Path relative to the archive
67 * @return Opened directory, or nullptr
68 */
69 std::unique_ptr<Directory> OpenDirectory(const Path& path) const override;
70
71 /**
72 * Read data from the archive
73 * @param offset Offset in bytes to start reading archive from
74 * @param length Length in bytes to read data from archive
75 * @param buffer Buffer to read data into
76 * @return Number of bytes read
77 */
78 size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
79
80 /**
81 * Write data to the archive
82 * @param offset Offset in bytes to start writing data to
83 * @param length Length in bytes of data to write to archive
84 * @param buffer Buffer to write data from
85 * @param flush The flush parameters (0 == do not flush)
86 * @return Number of bytes written
87 */
88 size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) override;
89
90 /**
91 * Get the size of the archive in bytes
92 * @return Size of the archive in bytes
93 */
94 size_t GetSize() const override;
95
96 /**
97 * Set the size of the archive in bytes
98 */
99 void SetSize(const u64 size) override;
100
101 /**
102 * Getter for the path used for this Archive
103 * @return Mount point of that passthrough archive
104 */
105 std::string GetMountPoint() const;
106
107private:
108 std::string mount_point;
109}; 29};
110 30
111} // namespace FileSys 31} // namespace FileSys
diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp
new file mode 100644
index 000000000..0da32d510
--- /dev/null
+++ b/src/core/file_sys/archive_systemsavedata.cpp
@@ -0,0 +1,39 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/archive_systemsavedata.h"
11#include "core/file_sys/disk_archive.h"
12#include "core/settings.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace
16
17namespace FileSys {
18
19static std::string GetSystemSaveDataPath(const std::string& mount_point, u64 save_id) {
20 u32 save_high = static_cast<u32>((save_id >> 32) & 0xFFFFFFFF);
21 u32 save_low = static_cast<u32>(save_id & 0xFFFFFFFF);
22 return Common::StringFromFormat("%s%08X/%08X/", mount_point.c_str(), save_low, save_high);
23}
24
25Archive_SystemSaveData::Archive_SystemSaveData(const std::string& mount_point, u64 save_id)
26 : DiskArchive(GetSystemSaveDataPath(mount_point, save_id)) {
27 LOG_INFO(Service_FS, "Directory %s set as SystemSaveData.", this->mount_point.c_str());
28}
29
30bool Archive_SystemSaveData::Initialize() {
31 if (!FileUtil::CreateFullPath(mount_point)) {
32 LOG_ERROR(Service_FS, "Unable to create SystemSaveData path.");
33 return false;
34 }
35
36 return true;
37}
38
39} // namespace FileSys
diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h
new file mode 100644
index 000000000..55d85193c
--- /dev/null
+++ b/src/core/file_sys/archive_systemsavedata.h
@@ -0,0 +1,33 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/file_sys/disk_archive.h"
10#include "core/loader/loader.h"
11
12////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace
14
15namespace FileSys {
16
17/// File system interface to the SystemSaveData archive
18/// TODO(Subv): This archive should point to a location in the NAND,
19/// specifically nand:/data/<ID0>/sysdata/<SaveID-Low>/<SaveID-High>
20class Archive_SystemSaveData final : public DiskArchive {
21public:
22 Archive_SystemSaveData(const std::string& mount_point, u64 save_id);
23
24 /**
25 * Initialize the archive.
26 * @return true if it initialized successfully
27 */
28 bool Initialize();
29
30 std::string GetName() const override { return "SystemSaveData"; }
31};
32
33} // namespace FileSys
diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory_backend.h
index e10431337..7f327dc42 100644
--- a/src/core/file_sys/directory.h
+++ b/src/core/file_sys/directory_backend.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -36,10 +36,16 @@ static_assert(offsetof(Entry, extension) == 0x216, "Wrong offset for extension i
36static_assert(offsetof(Entry, is_archive) == 0x21E, "Wrong offset for is_archive in Entry."); 36static_assert(offsetof(Entry, is_archive) == 0x21E, "Wrong offset for is_archive in Entry.");
37static_assert(offsetof(Entry, file_size) == 0x220, "Wrong offset for file_size in Entry."); 37static_assert(offsetof(Entry, file_size) == 0x220, "Wrong offset for file_size in Entry.");
38 38
39class Directory : NonCopyable { 39class DirectoryBackend : NonCopyable {
40public: 40public:
41 Directory() { } 41 DirectoryBackend() { }
42 virtual ~Directory() { } 42 virtual ~DirectoryBackend() { }
43
44 /**
45 * Open the directory
46 * @return true if the directory opened correctly
47 */
48 virtual bool Open() = 0;
43 49
44 /** 50 /**
45 * List files contained in the directory 51 * List files contained in the directory
diff --git a/src/core/file_sys/directory_romfs.cpp b/src/core/file_sys/directory_romfs.cpp
index 4e8f4c04d..e130aca17 100644
--- a/src/core/file_sys/directory_romfs.cpp
+++ b/src/core/file_sys/directory_romfs.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
@@ -17,20 +17,14 @@ Directory_RomFS::Directory_RomFS() {
17Directory_RomFS::~Directory_RomFS() { 17Directory_RomFS::~Directory_RomFS() {
18} 18}
19 19
20/** 20bool Directory_RomFS::Open() {
21 * List files contained in the directory 21 return false;
22 * @param count Number of entries to return at once in entries 22}
23 * @param entries Buffer to read data into 23
24 * @return Number of entries listed
25 */
26u32 Directory_RomFS::Read(const u32 count, Entry* entries) { 24u32 Directory_RomFS::Read(const u32 count, Entry* entries) {
27 return 0; 25 return 0;
28} 26}
29 27
30/**
31 * Close the directory
32 * @return true if the directory closed correctly
33 */
34bool Directory_RomFS::Close() const { 28bool Directory_RomFS::Close() const {
35 return false; 29 return false;
36} 30}
diff --git a/src/core/file_sys/directory_romfs.h b/src/core/file_sys/directory_romfs.h
index 4b71c4b13..2297f1645 100644
--- a/src/core/file_sys/directory_romfs.h
+++ b/src/core/file_sys/directory_romfs.h
@@ -1,12 +1,12 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8 8
9#include "core/file_sys/directory.h" 9#include "core/file_sys/directory_backend.h"
10#include "core/loader/loader.h" 10#include "core/loader/loader.h"
11 11
12//////////////////////////////////////////////////////////////////////////////////////////////////// 12////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -14,12 +14,18 @@
14 14
15namespace FileSys { 15namespace FileSys {
16 16
17class Directory_RomFS final : public Directory { 17class Directory_RomFS final : public DirectoryBackend {
18public: 18public:
19 Directory_RomFS(); 19 Directory_RomFS();
20 ~Directory_RomFS() override; 20 ~Directory_RomFS() override;
21 21
22 /** 22 /**
23 * Open the directory
24 * @return true if the directory opened correctly
25 */
26 bool Open() override;
27
28 /**
23 * List files contained in the directory 29 * List files contained in the directory
24 * @param count Number of entries to return at once in entries 30 * @param count Number of entries to return at once in entries
25 * @param entries Buffer to read data into 31 * @param entries Buffer to read data into
diff --git a/src/core/file_sys/directory_sdmc.cpp b/src/core/file_sys/directory_sdmc.cpp
deleted file mode 100644
index 60a197ce9..000000000
--- a/src/core/file_sys/directory_sdmc.cpp
+++ /dev/null
@@ -1,81 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/directory_sdmc.h"
11#include "core/file_sys/archive_sdmc.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// FileSys namespace
15
16namespace FileSys {
17
18Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const Path& path) {
19 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
20 // the root directory we set while opening the archive.
21 // For example, opening /../../usr/bin can give the emulated program your installed programs.
22 std::string absolute_path = archive->GetMountPoint() + path.AsString();
23 FileUtil::ScanDirectoryTree(absolute_path, directory);
24 children_iterator = directory.children.begin();
25}
26
27Directory_SDMC::~Directory_SDMC() {
28 Close();
29}
30
31/**
32 * List files contained in the directory
33 * @param count Number of entries to return at once in entries
34 * @param entries Buffer to read data into
35 * @return Number of entries listed
36 */
37u32 Directory_SDMC::Read(const u32 count, Entry* entries) {
38 u32 entries_read = 0;
39
40 while (entries_read < count && children_iterator != directory.children.cend()) {
41 const FileUtil::FSTEntry& file = *children_iterator;
42 const std::string& filename = file.virtualName;
43 Entry& entry = entries[entries_read];
44
45 WARN_LOG(FILESYS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory);
46
47 // TODO(Link Mauve): use a proper conversion to UTF-16.
48 for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
49 entry.filename[j] = filename[j];
50 if (!filename[j])
51 break;
52 }
53
54 FileUtil::SplitFilename83(filename, entry.short_name, entry.extension);
55
56 entry.is_directory = file.isDirectory;
57 entry.is_hidden = (filename[0] == '.');
58 entry.is_read_only = 0;
59 entry.file_size = file.size;
60
61 // We emulate a SD card where the archive bit has never been cleared, as it would be on
62 // most user SD cards.
63 // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a
64 // file bit.
65 entry.is_archive = !file.isDirectory;
66
67 ++entries_read;
68 ++children_iterator;
69 }
70 return entries_read;
71}
72
73/**
74 * Close the directory
75 * @return true if the directory closed correctly
76 */
77bool Directory_SDMC::Close() const {
78 return true;
79}
80
81} // namespace FileSys
diff --git a/src/core/file_sys/directory_sdmc.h b/src/core/file_sys/directory_sdmc.h
deleted file mode 100644
index 4520d0401..000000000
--- a/src/core/file_sys/directory_sdmc.h
+++ /dev/null
@@ -1,48 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/directory.h"
11#include "core/file_sys/archive_sdmc.h"
12#include "core/loader/loader.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace
16
17namespace FileSys {
18
19class Directory_SDMC final : public Directory {
20public:
21 Directory_SDMC();
22 Directory_SDMC(const Archive_SDMC* archive, const Path& path);
23 ~Directory_SDMC() override;
24
25 /**
26 * List files contained in the directory
27 * @param count Number of entries to return at once in entries
28 * @param entries Buffer to read data into
29 * @return Number of entries listed
30 */
31 u32 Read(const u32 count, Entry* entries) override;
32
33 /**
34 * Close the directory
35 * @return true if the directory closed correctly
36 */
37 bool Close() const override;
38
39private:
40 u32 total_entries_in_directory;
41 FileUtil::FSTEntry directory;
42
43 // We need to remember the last entry we returned, so a subsequent call to Read will continue
44 // from the next one. This iterator will always point to the next unread entry.
45 std::vector<FileUtil::FSTEntry>::iterator children_iterator;
46};
47
48} // namespace FileSys
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp
new file mode 100644
index 000000000..0197f727d
--- /dev/null
+++ b/src/core/file_sys/disk_archive.cpp
@@ -0,0 +1,188 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/disk_archive.h"
11#include "core/settings.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// FileSys namespace
15
16namespace FileSys {
17
18std::unique_ptr<FileBackend> DiskArchive::OpenFile(const Path& path, const Mode mode) const {
19 LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex);
20 DiskFile* file = new DiskFile(this, path, mode);
21 if (!file->Open())
22 return nullptr;
23 return std::unique_ptr<FileBackend>(file);
24}
25
26bool DiskArchive::DeleteFile(const Path& path) const {
27 return FileUtil::Delete(GetMountPoint() + path.AsString());
28}
29
30bool DiskArchive::RenameFile(const Path& src_path, const Path& dest_path) const {
31 return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
32}
33
34bool DiskArchive::DeleteDirectory(const Path& path) const {
35 return FileUtil::DeleteDir(GetMountPoint() + path.AsString());
36}
37
38ResultCode DiskArchive::CreateFile(const FileSys::Path& path, u32 size) const {
39 std::string full_path = GetMountPoint() + path.AsString();
40
41 if (FileUtil::Exists(full_path))
42 return ResultCode(ErrorDescription::AlreadyExists, ErrorModule::FS, ErrorSummary::NothingHappened, ErrorLevel::Info);
43
44 if (size == 0) {
45 FileUtil::CreateEmptyFile(full_path);
46 return RESULT_SUCCESS;
47 }
48
49 FileUtil::IOFile file(full_path, "wb");
50 // Creates a sparse file (or a normal file on filesystems without the concept of sparse files)
51 // We do this by seeking to the right size, then writing a single null byte.
52 if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1)
53 return RESULT_SUCCESS;
54
55 return ResultCode(ErrorDescription::TooLarge, ErrorModule::FS, ErrorSummary::OutOfResource, ErrorLevel::Info);
56}
57
58
59bool DiskArchive::CreateDirectory(const Path& path) const {
60 return FileUtil::CreateDir(GetMountPoint() + path.AsString());
61}
62
63bool DiskArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const {
64 return FileUtil::Rename(GetMountPoint() + src_path.AsString(), GetMountPoint() + dest_path.AsString());
65}
66
67std::unique_ptr<DirectoryBackend> DiskArchive::OpenDirectory(const Path& path) const {
68 LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str());
69 DiskDirectory* directory = new DiskDirectory(this, path);
70 if (!directory->Open())
71 return nullptr;
72 return std::unique_ptr<DirectoryBackend>(directory);
73}
74
75////////////////////////////////////////////////////////////////////////////////////////////////////
76
77DiskFile::DiskFile(const DiskArchive* archive, const Path& path, const Mode mode) {
78 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
79 // the root directory we set while opening the archive.
80 // For example, opening /../../etc/passwd can give the emulated program your users list.
81 this->path = archive->GetMountPoint() + path.AsString();
82 this->mode.hex = mode.hex;
83 this->archive = archive;
84}
85
86bool DiskFile::Open() {
87 if (!mode.create_flag && !FileUtil::Exists(path)) {
88 LOG_ERROR(Service_FS, "Non-existing file %s can't be open without mode create.", path.c_str());
89 return false;
90 }
91
92 std::string mode_string;
93 if (mode.create_flag)
94 mode_string = "w+";
95 else if (mode.write_flag)
96 mode_string = "r+"; // Files opened with Write access can be read from
97 else if (mode.read_flag)
98 mode_string = "r";
99
100 // Open the file in binary mode, to avoid problems with CR/LF on Windows systems
101 mode_string += "b";
102
103 file = new FileUtil::IOFile(path, mode_string.c_str());
104 return true;
105}
106
107size_t DiskFile::Read(const u64 offset, const u32 length, u8* buffer) const {
108 file->Seek(offset, SEEK_SET);
109 return file->ReadBytes(buffer, length);
110}
111
112size_t DiskFile::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const {
113 file->Seek(offset, SEEK_SET);
114 size_t written = file->WriteBytes(buffer, length);
115 if (flush)
116 file->Flush();
117 return written;
118}
119
120size_t DiskFile::GetSize() const {
121 return static_cast<size_t>(file->GetSize());
122}
123
124bool DiskFile::SetSize(const u64 size) const {
125 file->Resize(size);
126 file->Flush();
127 return true;
128}
129
130bool DiskFile::Close() const {
131 return file->Close();
132}
133
134////////////////////////////////////////////////////////////////////////////////////////////////////
135
136DiskDirectory::DiskDirectory(const DiskArchive* archive, const Path& path) {
137 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
138 // the root directory we set while opening the archive.
139 // For example, opening /../../usr/bin can give the emulated program your installed programs.
140 this->path = archive->GetMountPoint() + path.AsString();
141 this->archive = archive;
142}
143
144bool DiskDirectory::Open() {
145 if (!FileUtil::IsDirectory(path))
146 return false;
147 FileUtil::ScanDirectoryTree(path, directory);
148 children_iterator = directory.children.begin();
149 return true;
150}
151
152u32 DiskDirectory::Read(const u32 count, Entry* entries) {
153 u32 entries_read = 0;
154
155 while (entries_read < count && children_iterator != directory.children.cend()) {
156 const FileUtil::FSTEntry& file = *children_iterator;
157 const std::string& filename = file.virtualName;
158 Entry& entry = entries[entries_read];
159
160 LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, file.isDirectory);
161
162 // TODO(Link Mauve): use a proper conversion to UTF-16.
163 for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
164 entry.filename[j] = filename[j];
165 if (!filename[j])
166 break;
167 }
168
169 FileUtil::SplitFilename83(filename, entry.short_name, entry.extension);
170
171 entry.is_directory = file.isDirectory;
172 entry.is_hidden = (filename[0] == '.');
173 entry.is_read_only = 0;
174 entry.file_size = file.size;
175
176 // We emulate a SD card where the archive bit has never been cleared, as it would be on
177 // most user SD cards.
178 // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a
179 // file bit.
180 entry.is_archive = !file.isDirectory;
181
182 ++entries_read;
183 ++children_iterator;
184 }
185 return entries_read;
186}
187
188} // namespace FileSys
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h
new file mode 100644
index 000000000..018ebd2ed
--- /dev/null
+++ b/src/core/file_sys/disk_archive.h
@@ -0,0 +1,103 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/archive_backend.h"
11#include "core/loader/loader.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// FileSys namespace
15
16namespace FileSys {
17
18/**
19 * Helper which implements a backend accessing the host machine's filesystem.
20 * This should be subclassed by concrete archive types, which will provide the
21 * base directory on the host filesystem and override any required functionality.
22 */
23class DiskArchive : public ArchiveBackend {
24public:
25 DiskArchive(const std::string& mount_point_) : mount_point(mount_point_) {}
26
27 virtual std::string GetName() const = 0;
28 std::unique_ptr<FileBackend> OpenFile(const Path& path, const Mode mode) const override;
29 bool DeleteFile(const Path& path) const override;
30 bool RenameFile(const Path& src_path, const Path& dest_path) const override;
31 bool DeleteDirectory(const Path& path) const override;
32 ResultCode CreateFile(const Path& path, u32 size) const override;
33 bool CreateDirectory(const Path& path) const override;
34 bool RenameDirectory(const Path& src_path, const Path& dest_path) const override;
35 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
36
37 /**
38 * Getter for the path used for this Archive
39 * @return Mount point of that passthrough archive
40 */
41 const std::string& GetMountPoint() const {
42 return mount_point;
43 }
44
45protected:
46 std::string mount_point;
47};
48
49class DiskFile : public FileBackend {
50public:
51 DiskFile();
52 DiskFile(const DiskArchive* archive, const Path& path, const Mode mode);
53
54 ~DiskFile() override {
55 Close();
56 }
57
58 bool Open() override;
59 size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
60 size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override;
61 size_t GetSize() const override;
62 bool SetSize(const u64 size) const override;
63 bool Close() const override;
64
65 void Flush() const override {
66 file->Flush();
67 }
68
69protected:
70 const DiskArchive* archive;
71 std::string path;
72 Mode mode;
73 FileUtil::IOFile* file;
74};
75
76class DiskDirectory : public DirectoryBackend {
77public:
78 DiskDirectory();
79 DiskDirectory(const DiskArchive* archive, const Path& path);
80
81 ~DiskDirectory() override {
82 Close();
83 }
84
85 bool Open() override;
86 u32 Read(const u32 count, Entry* entries) override;
87
88 bool Close() const override {
89 return true;
90 }
91
92protected:
93 const DiskArchive* archive;
94 std::string path;
95 u32 total_entries_in_directory;
96 FileUtil::FSTEntry directory;
97
98 // We need to remember the last entry we returned, so a subsequent call to Read will continue
99 // from the next one. This iterator will always point to the next unread entry.
100 std::vector<FileUtil::FSTEntry>::iterator children_iterator;
101};
102
103} // namespace FileSys
diff --git a/src/core/file_sys/file.h b/src/core/file_sys/file_backend.h
index 4013b6c3e..35890af1f 100644
--- a/src/core/file_sys/file.h
+++ b/src/core/file_sys/file_backend.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -13,10 +13,10 @@
13 13
14namespace FileSys { 14namespace FileSys {
15 15
16class File : NonCopyable { 16class FileBackend : NonCopyable {
17public: 17public:
18 File() { } 18 FileBackend() { }
19 virtual ~File() { } 19 virtual ~FileBackend() { }
20 20
21 /** 21 /**
22 * Open the file 22 * Open the file
@@ -61,6 +61,11 @@ public:
61 * @return true if the file closed correctly 61 * @return true if the file closed correctly
62 */ 62 */
63 virtual bool Close() const = 0; 63 virtual bool Close() const = 0;
64
65 /**
66 * Flushes the file
67 */
68 virtual void Flush() const = 0;
64}; 69};
65 70
66} // namespace FileSys 71} // namespace FileSys
diff --git a/src/core/file_sys/file_romfs.cpp b/src/core/file_sys/file_romfs.cpp
index b55708df4..7467d6d31 100644
--- a/src/core/file_sys/file_romfs.cpp
+++ b/src/core/file_sys/file_romfs.cpp
@@ -1,74 +1,41 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
6 6
7#include "core/file_sys/file_romfs.h" 7#include "core/file_sys/file_romfs.h"
8#include "core/file_sys/archive_romfs.h"
8 9
9//////////////////////////////////////////////////////////////////////////////////////////////////// 10////////////////////////////////////////////////////////////////////////////////////////////////////
10// FileSys namespace 11// FileSys namespace
11 12
12namespace FileSys { 13namespace FileSys {
13 14
14File_RomFS::File_RomFS() {
15}
16
17File_RomFS::~File_RomFS() {
18}
19
20/**
21 * Open the file
22 * @return true if the file opened correctly
23 */
24bool File_RomFS::Open() { 15bool File_RomFS::Open() {
25 return false; 16 return true;
26} 17}
27 18
28/**
29 * Read data from the file
30 * @param offset Offset in bytes to start reading data from
31 * @param length Length in bytes of data to read from file
32 * @param buffer Buffer to read data into
33 * @return Number of bytes read
34 */
35size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { 19size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const {
36 return -1; 20 LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length);
21 memcpy(buffer, &archive->raw_data[(u32)offset], length);
22 return length;
37} 23}
38 24
39/**
40 * Write data to the file
41 * @param offset Offset in bytes to start writing data to
42 * @param length Length in bytes of data to write to file
43 * @param flush The flush parameters (0 == do not flush)
44 * @param buffer Buffer to read data from
45 * @return Number of bytes written
46 */
47size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { 25size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const {
48 return -1; 26 LOG_WARNING(Service_FS, "Attempted to write to ROMFS.");
27 return 0;
49} 28}
50 29
51/**
52 * Get the size of the file in bytes
53 * @return Size of the file in bytes
54 */
55size_t File_RomFS::GetSize() const { 30size_t File_RomFS::GetSize() const {
56 return -1; 31 return sizeof(u8) * archive->raw_data.size();
57} 32}
58 33
59/**
60 * Set the size of the file in bytes
61 * @param size New size of the file
62 * @return true if successful
63 */
64bool File_RomFS::SetSize(const u64 size) const { 34bool File_RomFS::SetSize(const u64 size) const {
35 LOG_WARNING(Service_FS, "Attempted to set the size of ROMFS");
65 return false; 36 return false;
66} 37}
67 38
68/**
69 * Close the file
70 * @return true if the file closed correctly
71 */
72bool File_RomFS::Close() const { 39bool File_RomFS::Close() const {
73 return false; 40 return false;
74} 41}
diff --git a/src/core/file_sys/file_romfs.h b/src/core/file_sys/file_romfs.h
index 5196701d3..04d8a16a2 100644
--- a/src/core/file_sys/file_romfs.h
+++ b/src/core/file_sys/file_romfs.h
@@ -1,12 +1,12 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8 8
9#include "core/file_sys/file.h" 9#include "core/file_sys/file_backend.h"
10#include "core/loader/loader.h" 10#include "core/loader/loader.h"
11 11
12//////////////////////////////////////////////////////////////////////////////////////////////////// 12////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -14,10 +14,11 @@
14 14
15namespace FileSys { 15namespace FileSys {
16 16
17class File_RomFS final : public File { 17class Archive_RomFS;
18
19class File_RomFS final : public FileBackend {
18public: 20public:
19 File_RomFS(); 21 File_RomFS(const Archive_RomFS* archive) : archive(archive) {}
20 ~File_RomFS() override;
21 22
22 /** 23 /**
23 * Open the file 24 * Open the file
@@ -62,6 +63,11 @@ public:
62 * @return true if the file closed correctly 63 * @return true if the file closed correctly
63 */ 64 */
64 bool Close() const override; 65 bool Close() const override;
66
67 void Flush() const override { }
68
69private:
70 const Archive_RomFS* archive;
65}; 71};
66 72
67} // namespace FileSys 73} // namespace FileSys
diff --git a/src/core/file_sys/file_sdmc.cpp b/src/core/file_sys/file_sdmc.cpp
deleted file mode 100644
index a4b90670a..000000000
--- a/src/core/file_sys/file_sdmc.cpp
+++ /dev/null
@@ -1,107 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include <sys/stat.h>
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/file_sdmc.h"
11#include "core/file_sys/archive_sdmc.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// FileSys namespace
15
16namespace FileSys {
17
18File_SDMC::File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode) {
19 // TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
20 // the root directory we set while opening the archive.
21 // For example, opening /../../etc/passwd can give the emulated program your users list.
22 this->path = archive->GetMountPoint() + path.AsString();
23 this->mode.hex = mode.hex;
24}
25
26File_SDMC::~File_SDMC() {
27 Close();
28}
29
30/**
31 * Open the file
32 * @return true if the file opened correctly
33 */
34bool File_SDMC::Open() {
35 if (!mode.create_flag && !FileUtil::Exists(path)) {
36 ERROR_LOG(FILESYS, "Non-existing file %s can’t be open without mode create.", path.c_str());
37 return false;
38 }
39
40 std::string mode_string;
41 if (mode.read_flag && mode.write_flag)
42 mode_string = "w+";
43 else if (mode.read_flag)
44 mode_string = "r";
45 else if (mode.write_flag)
46 mode_string = "w";
47
48 file = new FileUtil::IOFile(path, mode_string.c_str());
49 return true;
50}
51
52/**
53 * Read data from the file
54 * @param offset Offset in bytes to start reading data from
55 * @param length Length in bytes of data to read from file
56 * @param buffer Buffer to read data into
57 * @return Number of bytes read
58 */
59size_t File_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const {
60 file->Seek(offset, SEEK_SET);
61 return file->ReadBytes(buffer, length);
62}
63
64/**
65 * Write data to the file
66 * @param offset Offset in bytes to start writing data to
67 * @param length Length in bytes of data to write to file
68 * @param flush The flush parameters (0 == do not flush)
69 * @param buffer Buffer to read data from
70 * @return Number of bytes written
71 */
72size_t File_SDMC::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const {
73 file->Seek(offset, SEEK_SET);
74 size_t written = file->WriteBytes(buffer, length);
75 if (flush)
76 file->Flush();
77 return written;
78}
79
80/**
81 * Get the size of the file in bytes
82 * @return Size of the file in bytes
83 */
84size_t File_SDMC::GetSize() const {
85 return static_cast<size_t>(file->GetSize());
86}
87
88/**
89 * Set the size of the file in bytes
90 * @param size New size of the file
91 * @return true if successful
92 */
93bool File_SDMC::SetSize(const u64 size) const {
94 file->Resize(size);
95 file->Flush();
96 return true;
97}
98
99/**
100 * Close the file
101 * @return true if the file closed correctly
102 */
103bool File_SDMC::Close() const {
104 return file->Close();
105}
106
107} // namespace FileSys
diff --git a/src/core/file_sys/file_sdmc.h b/src/core/file_sys/file_sdmc.h
deleted file mode 100644
index 80b445968..000000000
--- a/src/core/file_sys/file_sdmc.h
+++ /dev/null
@@ -1,75 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/file_util.h"
9
10#include "core/file_sys/file.h"
11#include "core/file_sys/archive_sdmc.h"
12#include "core/loader/loader.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace
16
17namespace FileSys {
18
19class File_SDMC final : public File {
20public:
21 File_SDMC();
22 File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode);
23 ~File_SDMC() override;
24
25 /**
26 * Open the file
27 * @return true if the file opened correctly
28 */
29 bool Open() override;
30
31 /**
32 * Read data from the file
33 * @param offset Offset in bytes to start reading data from
34 * @param length Length in bytes of data to read from file
35 * @param buffer Buffer to read data into
36 * @return Number of bytes read
37 */
38 size_t Read(const u64 offset, const u32 length, u8* buffer) const override;
39
40 /**
41 * Write data to the file
42 * @param offset Offset in bytes to start writing data to
43 * @param length Length in bytes of data to write to file
44 * @param flush The flush parameters (0 == do not flush)
45 * @param buffer Buffer to read data from
46 * @return Number of bytes written
47 */
48 size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override;
49
50 /**
51 * Get the size of the file in bytes
52 * @return Size of the file in bytes
53 */
54 size_t GetSize() const override;
55
56 /**
57 * Set the size of the file in bytes
58 * @param size New size of the file
59 * @return true if successful
60 */
61 bool SetSize(const u64 size) const override;
62
63 /**
64 * Close the file
65 * @return true if the file closed correctly
66 */
67 bool Close() const override;
68
69private:
70 std::string path;
71 Mode mode;
72 FileUtil::IOFile* file;
73};
74
75} // namespace FileSys
diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp
index c7cf5b1d3..721a600b5 100644
--- a/src/core/hle/config_mem.cpp
+++ b/src/core/hle/config_mem.cpp
@@ -1,8 +1,9 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
6#include "common/log.h"
6 7
7#include "core/hle/config_mem.h" 8#include "core/hle/config_mem.h"
8 9
@@ -54,7 +55,7 @@ inline void Read(T &var, const u32 addr) {
54 break; 55 break;
55 56
56 default: 57 default:
57 ERROR_LOG(HLE, "unknown addr=0x%08X", addr); 58 LOG_ERROR(Kernel, "unknown addr=0x%08X", addr);
58 } 59 }
59} 60}
60 61
diff --git a/src/core/hle/config_mem.h b/src/core/hle/config_mem.h
index fa01b5cdb..3975af18f 100644
--- a/src/core/hle/config_mem.h
+++ b/src/core/hle/config_mem.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/core/hle/coprocessor.cpp b/src/core/hle/coprocessor.cpp
index e34229a57..425959be4 100644
--- a/src/core/hle/coprocessor.cpp
+++ b/src/core/hle/coprocessor.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/coprocessor.h" 5#include "core/hle/coprocessor.h"
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 3dbe25037..3259ce9eb 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -114,6 +114,20 @@ template<s32 func(u32*, const char*)> void Wrap() {
114 FuncReturn(retval); 114 FuncReturn(retval);
115} 115}
116 116
117template<s32 func(u32*, s32, s32)> void Wrap() {
118 u32 param_1 = 0;
119 u32 retval = func(&param_1, PARAM(1), PARAM(2));
120 Core::g_app_core->SetReg(1, param_1);
121 FuncReturn(retval);
122}
123
124template<s32 func(s32*, u32, s32)> void Wrap() {
125 s32 param_1 = 0;
126 u32 retval = func(&param_1, PARAM(1), PARAM(2));
127 Core::g_app_core->SetReg(1, param_1);
128 FuncReturn(retval);
129}
130
117//////////////////////////////////////////////////////////////////////////////////////////////////// 131////////////////////////////////////////////////////////////////////////////////////////////////////
118// Function wrappers that return type u32 132// Function wrappers that return type u32
119 133
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
index b8ac186f6..33ac12507 100644
--- a/src/core/hle/hle.cpp
+++ b/src/core/hle/hle.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <vector> 5#include <vector>
@@ -8,6 +8,8 @@
8#include "core/hle/hle.h" 8#include "core/hle/hle.h"
9#include "core/hle/kernel/thread.h" 9#include "core/hle/kernel/thread.h"
10#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
11#include "core/hle/service/fs/archive.h"
12#include "core/hle/service/cfg/cfg.h"
11 13
12//////////////////////////////////////////////////////////////////////////////////////////////////// 14////////////////////////////////////////////////////////////////////////////////////////////////////
13 15
@@ -20,7 +22,7 @@ bool g_reschedule = false; ///< If true, immediately reschedules the CPU to a n
20const FunctionDef* GetSVCInfo(u32 opcode) { 22const FunctionDef* GetSVCInfo(u32 opcode) {
21 u32 func_num = opcode & 0xFFFFFF; // 8 bits 23 u32 func_num = opcode & 0xFFFFFF; // 8 bits
22 if (func_num > 0xFF) { 24 if (func_num > 0xFF) {
23 ERROR_LOG(HLE,"unknown svc=0x%02X", func_num); 25 LOG_ERROR(Kernel_SVC,"unknown svc=0x%02X", func_num);
24 return nullptr; 26 return nullptr;
25 } 27 }
26 return &g_module_db[0].func_table[func_num]; 28 return &g_module_db[0].func_table[func_num];
@@ -35,15 +37,21 @@ void CallSVC(u32 opcode) {
35 if (info->func) { 37 if (info->func) {
36 info->func(); 38 info->func();
37 } else { 39 } else {
38 ERROR_LOG(HLE, "unimplemented SVC function %s(..)", info->name.c_str()); 40 LOG_ERROR(Kernel_SVC, "unimplemented SVC function %s(..)", info->name.c_str());
39 } 41 }
40} 42}
41 43
42void Reschedule(const char *reason) { 44void Reschedule(const char *reason) {
43#ifdef _DEBUG 45 _dbg_assert_msg_(Kernel, reason != 0 && strlen(reason) < 256, "Reschedule: Invalid or too long reason.");
44 _dbg_assert_msg_(HLE, reason != 0 && strlen(reason) < 256, "Reschedule: Invalid or too long reason."); 46
45#endif 47 // TODO(bunnei): It seems that games depend on some CPU execution time elapsing during HLE
48 // routines. This simulates that time by artificially advancing the number of CPU "ticks".
49 // The value was chosen empirically, it seems to work well enough for everything tested, but
50 // is likely not ideal. We should find a more accurate way to simulate timing with HLE.
51 Core::g_app_core->AddTicks(4000);
52
46 Core::g_app_core->PrepareReschedule(); 53 Core::g_app_core->PrepareReschedule();
54
47 g_reschedule = true; 55 g_reschedule = true;
48} 56}
49 57
@@ -58,18 +66,22 @@ void RegisterAllModules() {
58 66
59void Init() { 67void Init() {
60 Service::Init(); 68 Service::Init();
69 Service::FS::ArchiveInit();
70 Service::CFG::CFGInit();
61 71
62 RegisterAllModules(); 72 RegisterAllModules();
63 73
64 NOTICE_LOG(HLE, "initialized OK"); 74 LOG_DEBUG(Kernel, "initialized OK");
65} 75}
66 76
67void Shutdown() { 77void Shutdown() {
78 Service::CFG::CFGShutdown();
79 Service::FS::ArchiveShutdown();
68 Service::Shutdown(); 80 Service::Shutdown();
69 81
70 g_module_db.clear(); 82 g_module_db.clear();
71 83
72 NOTICE_LOG(HLE, "shutdown OK"); 84 LOG_DEBUG(Kernel, "shutdown OK");
73} 85}
74 86
75} // namespace 87} // namespace
diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h
index 4ab258c69..59b770f02 100644
--- a/src/core/hle/hle.h
+++ b/src/core/hle/hle.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index db571b895..38705e3cd 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
@@ -20,16 +20,10 @@ public:
20 std::string GetTypeName() const override { return "Arbiter"; } 20 std::string GetTypeName() const override { return "Arbiter"; }
21 std::string GetName() const override { return name; } 21 std::string GetName() const override { return name; }
22 22
23 static Kernel::HandleType GetStaticHandleType() { return HandleType::AddressArbiter; } 23 static const HandleType HANDLE_TYPE = HandleType::AddressArbiter;
24 Kernel::HandleType GetHandleType() const override { return HandleType::AddressArbiter; } 24 HandleType GetHandleType() const override { return HANDLE_TYPE; }
25 25
26 std::string name; ///< Name of address arbiter object (optional) 26 std::string name; ///< Name of address arbiter object (optional)
27
28 ResultVal<bool> WaitSynchronization() override {
29 // TODO(bunnei): ImplementMe
30 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
31 return UnimplementedFunction(ErrorModule::OS);
32 }
33}; 27};
34 28
35//////////////////////////////////////////////////////////////////////////////////////////////////// 29////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -53,13 +47,13 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3
53 // Wait current thread (acquire the arbiter)... 47 // Wait current thread (acquire the arbiter)...
54 case ArbitrationType::WaitIfLessThan: 48 case ArbitrationType::WaitIfLessThan:
55 if ((s32)Memory::Read32(address) <= value) { 49 if ((s32)Memory::Read32(address) <= value) {
56 Kernel::WaitCurrentThread(WAITTYPE_ARB, handle); 50 Kernel::WaitCurrentThread(WAITTYPE_ARB, handle, address);
57 HLE::Reschedule(__func__); 51 HLE::Reschedule(__func__);
58 } 52 }
59 break; 53 break;
60 54
61 default: 55 default:
62 ERROR_LOG(KERNEL, "unknown type=%d", type); 56 LOG_ERROR(Kernel, "unknown type=%d", type);
63 return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, ErrorSummary::WrongArgument, ErrorLevel::Usage); 57 return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, ErrorSummary::WrongArgument, ErrorLevel::Usage);
64 } 58 }
65 return RESULT_SUCCESS; 59 return RESULT_SUCCESS;
@@ -68,7 +62,8 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3
68/// Create an address arbiter 62/// Create an address arbiter
69AddressArbiter* CreateAddressArbiter(Handle& handle, const std::string& name) { 63AddressArbiter* CreateAddressArbiter(Handle& handle, const std::string& name) {
70 AddressArbiter* address_arbiter = new AddressArbiter; 64 AddressArbiter* address_arbiter = new AddressArbiter;
71 handle = Kernel::g_object_pool.Create(address_arbiter); 65 // TOOD(yuriks): Fix error reporting
66 handle = Kernel::g_handle_table.Create(address_arbiter).ValueOr(INVALID_HANDLE);
72 address_arbiter->name = name; 67 address_arbiter->name = name;
73 return address_arbiter; 68 return address_arbiter;
74} 69}
diff --git a/src/core/hle/kernel/address_arbiter.h b/src/core/hle/kernel/address_arbiter.h
index 8a5fb10b4..030e7ad7b 100644
--- a/src/core/hle/kernel/address_arbiter.h
+++ b/src/core/hle/kernel/address_arbiter.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp
deleted file mode 100644
index e273444c9..000000000
--- a/src/core/hle/kernel/archive.cpp
+++ /dev/null
@@ -1,429 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/common_types.h"
6#include "common/file_util.h"
7#include "common/math_util.h"
8
9#include "core/file_sys/archive.h"
10#include "core/file_sys/archive_sdmc.h"
11#include "core/file_sys/directory.h"
12#include "core/hle/kernel/archive.h"
13#include "core/hle/result.h"
14#include "core/hle/service/service.h"
15
16////////////////////////////////////////////////////////////////////////////////////////////////////
17// Kernel namespace
18
19namespace Kernel {
20
21// Command to access archive file
22enum class FileCommand : u32 {
23 Dummy1 = 0x000100C6,
24 Control = 0x040100C4,
25 OpenSubFile = 0x08010100,
26 Read = 0x080200C2,
27 Write = 0x08030102,
28 GetSize = 0x08040000,
29 SetSize = 0x08050080,
30 GetAttributes = 0x08060000,
31 SetAttributes = 0x08070040,
32 Close = 0x08080000,
33 Flush = 0x08090000,
34};
35
36// Command to access directory
37enum class DirectoryCommand : u32 {
38 Dummy1 = 0x000100C6,
39 Control = 0x040100C4,
40 Read = 0x08010042,
41 Close = 0x08020000,
42};
43
44class Archive : public Object {
45public:
46 std::string GetTypeName() const override { return "Archive"; }
47 std::string GetName() const override { return name; }
48
49 static Kernel::HandleType GetStaticHandleType() { return HandleType::Archive; }
50 Kernel::HandleType GetHandleType() const override { return HandleType::Archive; }
51
52 std::string name; ///< Name of archive (optional)
53 FileSys::Archive* backend; ///< Archive backend interface
54
55 ResultVal<bool> SyncRequest() override {
56 u32* cmd_buff = Service::GetCommandBuffer();
57 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
58
59 switch (cmd) {
60 // Read from archive...
61 case FileCommand::Read:
62 {
63 u64 offset = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
64 u32 length = cmd_buff[3];
65 u32 address = cmd_buff[5];
66
67 // Number of bytes read
68 cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address));
69 break;
70 }
71 // Write to archive...
72 case FileCommand::Write:
73 {
74 u64 offset = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
75 u32 length = cmd_buff[3];
76 u32 flush = cmd_buff[4];
77 u32 address = cmd_buff[6];
78
79 // Number of bytes written
80 cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address));
81 break;
82 }
83 case FileCommand::GetSize:
84 {
85 u64 filesize = (u64) backend->GetSize();
86 cmd_buff[2] = (u32) filesize; // Lower word
87 cmd_buff[3] = (u32) (filesize >> 32); // Upper word
88 break;
89 }
90 case FileCommand::SetSize:
91 {
92 backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32));
93 break;
94 }
95 case FileCommand::Close:
96 {
97 DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
98 CloseArchive(backend->GetIdCode());
99 break;
100 }
101 // Unknown command...
102 default:
103 {
104 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
105 return UnimplementedFunction(ErrorModule::FS);
106 }
107 }
108 cmd_buff[1] = 0; // No error
109 return MakeResult<bool>(false);
110 }
111
112 ResultVal<bool> WaitSynchronization() override {
113 // TODO(bunnei): ImplementMe
114 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
115 return UnimplementedFunction(ErrorModule::FS);
116 }
117};
118
119class File : public Object {
120public:
121 std::string GetTypeName() const override { return "File"; }
122 std::string GetName() const override { return path.DebugStr(); }
123
124 static Kernel::HandleType GetStaticHandleType() { return HandleType::File; }
125 Kernel::HandleType GetHandleType() const override { return HandleType::File; }
126
127 FileSys::Path path; ///< Path of the file
128 std::unique_ptr<FileSys::File> backend; ///< File backend interface
129
130 ResultVal<bool> SyncRequest() override {
131 u32* cmd_buff = Service::GetCommandBuffer();
132 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
133 switch (cmd) {
134
135 // Read from file...
136 case FileCommand::Read:
137 {
138 u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32;
139 u32 length = cmd_buff[3];
140 u32 address = cmd_buff[5];
141 DEBUG_LOG(KERNEL, "Read %s %s: offset=0x%llx length=%d address=0x%x",
142 GetTypeName().c_str(), GetName().c_str(), offset, length, address);
143 cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address));
144 break;
145 }
146
147 // Write to file...
148 case FileCommand::Write:
149 {
150 u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32;
151 u32 length = cmd_buff[3];
152 u32 flush = cmd_buff[4];
153 u32 address = cmd_buff[6];
154 DEBUG_LOG(KERNEL, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
155 GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
156 cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address));
157 break;
158 }
159
160 case FileCommand::GetSize:
161 {
162 DEBUG_LOG(KERNEL, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str());
163 u64 size = backend->GetSize();
164 cmd_buff[2] = (u32)size;
165 cmd_buff[3] = size >> 32;
166 break;
167 }
168
169 case FileCommand::SetSize:
170 {
171 u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
172 DEBUG_LOG(KERNEL, "SetSize %s %s size=%llu",
173 GetTypeName().c_str(), GetName().c_str(), size);
174 backend->SetSize(size);
175 break;
176 }
177
178 case FileCommand::Close:
179 {
180 DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
181 Kernel::g_object_pool.Destroy<File>(GetHandle());
182 break;
183 }
184
185 // Unknown command...
186 default:
187 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
188 ResultCode error = UnimplementedFunction(ErrorModule::FS);
189 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
190 return error;
191 }
192 cmd_buff[1] = 0; // No error
193 return MakeResult<bool>(false);
194 }
195
196 ResultVal<bool> WaitSynchronization() override {
197 // TODO(bunnei): ImplementMe
198 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
199 return UnimplementedFunction(ErrorModule::FS);
200 }
201};
202
203class Directory : public Object {
204public:
205 std::string GetTypeName() const override { return "Directory"; }
206 std::string GetName() const override { return path.DebugStr(); }
207
208 static Kernel::HandleType GetStaticHandleType() { return HandleType::Directory; }
209 Kernel::HandleType GetHandleType() const override { return HandleType::Directory; }
210
211 FileSys::Path path; ///< Path of the directory
212 std::unique_ptr<FileSys::Directory> backend; ///< File backend interface
213
214 ResultVal<bool> SyncRequest() override {
215 u32* cmd_buff = Service::GetCommandBuffer();
216 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
217 switch (cmd) {
218
219 // Read from directory...
220 case DirectoryCommand::Read:
221 {
222 u32 count = cmd_buff[1];
223 u32 address = cmd_buff[3];
224 auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address));
225 DEBUG_LOG(KERNEL, "Read %s %s: count=%d",
226 GetTypeName().c_str(), GetName().c_str(), count);
227
228 // Number of entries actually read
229 cmd_buff[2] = backend->Read(count, entries);
230 break;
231 }
232
233 case DirectoryCommand::Close:
234 {
235 DEBUG_LOG(KERNEL, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
236 Kernel::g_object_pool.Destroy<Directory>(GetHandle());
237 break;
238 }
239
240 // Unknown command...
241 default:
242 ERROR_LOG(KERNEL, "Unknown command=0x%08X!", cmd);
243 ResultCode error = UnimplementedFunction(ErrorModule::FS);
244 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
245 return error;
246 }
247 cmd_buff[1] = 0; // No error
248 return MakeResult<bool>(false);
249 }
250
251 ResultVal<bool> WaitSynchronization() override {
252 // TODO(bunnei): ImplementMe
253 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
254 return UnimplementedFunction(ErrorModule::FS);
255 }
256};
257
258////////////////////////////////////////////////////////////////////////////////////////////////////
259
260std::map<FileSys::Archive::IdCode, Handle> g_archive_map; ///< Map of file archives by IdCode
261
262ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code) {
263 auto itr = g_archive_map.find(id_code);
264 if (itr == g_archive_map.end()) {
265 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
266 ErrorSummary::NotFound, ErrorLevel::Permanent);
267 }
268
269 return MakeResult<Handle>(itr->second);
270}
271
272ResultCode CloseArchive(FileSys::Archive::IdCode id_code) {
273 auto itr = g_archive_map.find(id_code);
274 if (itr == g_archive_map.end()) {
275 ERROR_LOG(KERNEL, "Cannot close archive %d, does not exist!", (int)id_code);
276 return InvalidHandle(ErrorModule::FS);
277 }
278
279 INFO_LOG(KERNEL, "Closed archive %d", (int) id_code);
280 return RESULT_SUCCESS;
281}
282
283/**
284 * Mounts an archive
285 * @param archive Pointer to the archive to mount
286 */
287ResultCode MountArchive(Archive* archive) {
288 FileSys::Archive::IdCode id_code = archive->backend->GetIdCode();
289 ResultVal<Handle> archive_handle = OpenArchive(id_code);
290 if (archive_handle.Succeeded()) {
291 ERROR_LOG(KERNEL, "Cannot mount two archives with the same ID code! (%d)", (int) id_code);
292 return archive_handle.Code();
293 }
294 g_archive_map[id_code] = archive->GetHandle();
295 INFO_LOG(KERNEL, "Mounted archive %s", archive->GetName().c_str());
296 return RESULT_SUCCESS;
297}
298
299ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) {
300 Archive* archive = new Archive;
301 Handle handle = Kernel::g_object_pool.Create(archive);
302 archive->name = name;
303 archive->backend = backend;
304
305 ResultCode result = MountArchive(archive);
306 if (result.IsError()) {
307 return result;
308 }
309
310 return RESULT_SUCCESS;
311}
312
313ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) {
314 // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create
315 // the archive file handles at app loading, and then keep them persistent throughout execution.
316 // Archives file handles are just reused and not actually freed until emulation shut down.
317 // Verify if real hardware works this way, or if new handles are created each time
318 if (path.GetType() == FileSys::Binary)
319 // TODO(bunnei): FixMe - this is a hack to compensate for an incorrect FileSys backend
320 // design. While the functionally of this is OK, our implementation decision to separate
321 // normal files from archive file pointers is very likely wrong.
322 // See https://github.com/citra-emu/citra/issues/205
323 return MakeResult<Handle>(archive_handle);
324
325 File* file = new File;
326 Handle handle = Kernel::g_object_pool.Create(file);
327
328 Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle);
329 if (archive == nullptr) {
330 return InvalidHandle(ErrorModule::FS);
331 }
332 file->path = path;
333 file->backend = archive->backend->OpenFile(path, mode);
334
335 if (!file->backend) {
336 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
337 ErrorSummary::NotFound, ErrorLevel::Permanent);
338 }
339
340 return MakeResult<Handle>(handle);
341}
342
343/**
344 * Delete a File from an Archive
345 * @param archive_handle Handle to an open Archive object
346 * @param path Path to the File inside of the Archive
347 * @return Whether deletion succeeded
348 */
349Result DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path) {
350 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
351 if (archive == nullptr)
352 return -1;
353 if (archive->backend->DeleteFile(path))
354 return 0;
355 return -1;
356}
357
358/**
359 * Delete a Directory from an Archive
360 * @param archive_handle Handle to an open Archive object
361 * @param path Path to the Directory inside of the Archive
362 * @return Whether deletion succeeded
363 */
364Result DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
365 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
366 if (archive == nullptr)
367 return -1;
368 if (archive->backend->DeleteDirectory(path))
369 return 0;
370 return -1;
371}
372
373/**
374 * Create a Directory from an Archive
375 * @param archive_handle Handle to an open Archive object
376 * @param path Path to the Directory inside of the Archive
377 * @return Whether creation succeeded
378 */
379Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
380 Archive* archive = Kernel::g_object_pool.GetFast<Archive>(archive_handle);
381 if (archive == nullptr)
382 return -1;
383 if (archive->backend->CreateDirectory(path))
384 return 0;
385 return -1;
386}
387
388/**
389 * Open a Directory from an Archive
390 * @param archive_handle Handle to an open Archive object
391 * @param path Path to the Directory inside of the Archive
392 * @return Opened Directory object
393 */
394ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) {
395 Directory* directory = new Directory;
396 Handle handle = Kernel::g_object_pool.Create(directory);
397
398 Archive* archive = Kernel::g_object_pool.Get<Archive>(archive_handle);
399 if (archive == nullptr) {
400 return InvalidHandle(ErrorModule::FS);
401 }
402 directory->path = path;
403 directory->backend = archive->backend->OpenDirectory(path);
404
405 return MakeResult<Handle>(handle);
406}
407
408/// Initialize archives
409void ArchiveInit() {
410 g_archive_map.clear();
411
412 // TODO(Link Mauve): Add the other archive types (see here for the known types:
413 // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). Currently the only half-finished
414 // archive type is SDMC, so it is the only one getting exposed.
415
416 std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX);
417 auto archive = new FileSys::Archive_SDMC(sdmc_directory);
418 if (archive->Initialize())
419 CreateArchive(archive, "SDMC");
420 else
421 ERROR_LOG(KERNEL, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
422}
423
424/// Shutdown archives
425void ArchiveShutdown() {
426 g_archive_map.clear();
427}
428
429} // namespace Kernel
diff --git a/src/core/hle/kernel/archive.h b/src/core/hle/kernel/archive.h
deleted file mode 100644
index 6fc4f0f25..000000000
--- a/src/core/hle/kernel/archive.h
+++ /dev/null
@@ -1,85 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/file_sys/archive.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/result.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// Kernel namespace
15
16namespace Kernel {
17
18/**
19 * Opens an archive
20 * @param id_code IdCode of the archive to open
21 * @return Handle to the opened archive
22 */
23ResultVal<Handle> OpenArchive(FileSys::Archive::IdCode id_code);
24
25/**
26 * Closes an archive
27 * @param id_code IdCode of the archive to open
28 */
29ResultCode CloseArchive(FileSys::Archive::IdCode id_code);
30
31/**
32 * Creates an Archive
33 * @param backend File system backend interface to the archive
34 * @param name Name of Archive
35 */
36ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name);
37
38/**
39 * Open a File from an Archive
40 * @param archive_handle Handle to an open Archive object
41 * @param path Path to the File inside of the Archive
42 * @param mode Mode under which to open the File
43 * @return Handle to the opened File object
44 */
45ResultVal<Handle> OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode);
46
47/**
48 * Delete a File from an Archive
49 * @param archive_handle Handle to an open Archive object
50 * @param path Path to the File inside of the Archive
51 * @return Whether deletion succeeded
52 */
53Result DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path);
54
55/**
56 * Delete a Directory from an Archive
57 * @param archive_handle Handle to an open Archive object
58 * @param path Path to the Directory inside of the Archive
59 * @return Whether deletion succeeded
60 */
61Result DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path);
62
63/**
64 * Create a Directory from an Archive
65 * @param archive_handle Handle to an open Archive object
66 * @param path Path to the Directory inside of the Archive
67 * @return Whether creation of directory succeeded
68 */
69Result CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path);
70
71/**
72 * Open a Directory from an Archive
73 * @param archive_handle Handle to an open Archive object
74 * @param path Path to the Directory inside of the Archive
75 * @return Handle to the opened File object
76 */
77ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path);
78
79/// Initialize archives
80void ArchiveInit();
81
82/// Shutdown archives
83void ArchiveShutdown();
84
85} // namespace FileSys
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index 288080209..e43c3ee4e 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map> 5#include <map>
@@ -19,8 +19,8 @@ public:
19 std::string GetTypeName() const override { return "Event"; } 19 std::string GetTypeName() const override { return "Event"; }
20 std::string GetName() const override { return name; } 20 std::string GetName() const override { return name; }
21 21
22 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Event; } 22 static const HandleType HANDLE_TYPE = HandleType::Event;
23 Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Event; } 23 HandleType GetHandleType() const override { return HANDLE_TYPE; }
24 24
25 ResetType intitial_reset_type; ///< ResetType specified at Event initialization 25 ResetType intitial_reset_type; ///< ResetType specified at Event initialization
26 ResetType reset_type; ///< Current ResetType 26 ResetType reset_type; ///< Current ResetType
@@ -53,7 +53,7 @@ public:
53 * @return Result of operation, 0 on success, otherwise error code 53 * @return Result of operation, 0 on success, otherwise error code
54 */ 54 */
55ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) { 55ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) {
56 Event* evt = g_object_pool.Get<Event>(handle); 56 Event* evt = g_handle_table.Get<Event>(handle);
57 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); 57 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
58 58
59 evt->permanent_locked = permanent_locked; 59 evt->permanent_locked = permanent_locked;
@@ -67,7 +67,7 @@ ResultCode SetPermanentLock(Handle handle, const bool permanent_locked) {
67 * @return Result of operation, 0 on success, otherwise error code 67 * @return Result of operation, 0 on success, otherwise error code
68 */ 68 */
69ResultCode SetEventLocked(const Handle handle, const bool locked) { 69ResultCode SetEventLocked(const Handle handle, const bool locked) {
70 Event* evt = g_object_pool.Get<Event>(handle); 70 Event* evt = g_handle_table.Get<Event>(handle);
71 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); 71 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
72 72
73 if (!evt->permanent_locked) { 73 if (!evt->permanent_locked) {
@@ -82,7 +82,7 @@ ResultCode SetEventLocked(const Handle handle, const bool locked) {
82 * @return Result of operation, 0 on success, otherwise error code 82 * @return Result of operation, 0 on success, otherwise error code
83 */ 83 */
84ResultCode SignalEvent(const Handle handle) { 84ResultCode SignalEvent(const Handle handle) {
85 Event* evt = g_object_pool.Get<Event>(handle); 85 Event* evt = g_handle_table.Get<Event>(handle);
86 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); 86 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
87 87
88 // Resume threads waiting for event to signal 88 // Resume threads waiting for event to signal
@@ -110,7 +110,7 @@ ResultCode SignalEvent(const Handle handle) {
110 * @return Result of operation, 0 on success, otherwise error code 110 * @return Result of operation, 0 on success, otherwise error code
111 */ 111 */
112ResultCode ClearEvent(Handle handle) { 112ResultCode ClearEvent(Handle handle) {
113 Event* evt = g_object_pool.Get<Event>(handle); 113 Event* evt = g_handle_table.Get<Event>(handle);
114 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel); 114 if (evt == nullptr) return InvalidHandle(ErrorModule::Kernel);
115 115
116 if (!evt->permanent_locked) { 116 if (!evt->permanent_locked) {
@@ -129,7 +129,8 @@ ResultCode ClearEvent(Handle handle) {
129Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string& name) { 129Event* CreateEvent(Handle& handle, const ResetType reset_type, const std::string& name) {
130 Event* evt = new Event; 130 Event* evt = new Event;
131 131
132 handle = Kernel::g_object_pool.Create(evt); 132 // TOOD(yuriks): Fix error reporting
133 handle = Kernel::g_handle_table.Create(evt).ValueOr(INVALID_HANDLE);
133 134
134 evt->locked = true; 135 evt->locked = true;
135 evt->permanent_locked = false; 136 evt->permanent_locked = false;
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index 73aec4e79..da793df1a 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 018000abd..e59ed1b57 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -1,106 +1,117 @@
1// Copyright 2014 Citra Emulator Project / PPSSPP Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6
5#include "common/common.h" 7#include "common/common.h"
6 8
7#include "core/core.h" 9#include "core/core.h"
8#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
9#include "core/hle/kernel/thread.h" 11#include "core/hle/kernel/thread.h"
10#include "core/hle/kernel/archive.h"
11 12
12namespace Kernel { 13namespace Kernel {
13 14
14Handle g_main_thread = 0; 15Handle g_main_thread = 0;
15ObjectPool g_object_pool; 16HandleTable g_handle_table;
17u64 g_program_id = 0;
16 18
17ObjectPool::ObjectPool() { 19HandleTable::HandleTable() {
18 next_id = INITIAL_NEXT_ID; 20 next_generation = 1;
21 Clear();
19} 22}
20 23
21Handle ObjectPool::Create(Object* obj, int range_bottom, int range_top) { 24ResultVal<Handle> HandleTable::Create(Object* obj) {
22 if (range_top > MAX_COUNT) { 25 _dbg_assert_(Kernel, obj != nullptr);
23 range_top = MAX_COUNT; 26
24 } 27 u16 slot = next_free_slot;
25 if (next_id >= range_bottom && next_id < range_top) { 28 if (slot >= generations.size()) {
26 range_bottom = next_id++; 29 LOG_ERROR(Kernel, "Unable to allocate Handle, too many slots in use.");
27 } 30 return ERR_OUT_OF_HANDLES;
28 for (int i = range_bottom; i < range_top; i++) {
29 if (!occupied[i]) {
30 occupied[i] = true;
31 pool[i] = obj;
32 pool[i]->handle = i + HANDLE_OFFSET;
33 return i + HANDLE_OFFSET;
34 }
35 } 31 }
36 ERROR_LOG(HLE, "Unable to allocate kernel object, too many objects slots in use."); 32 next_free_slot = generations[slot];
37 return 0; 33
38} 34 u16 generation = next_generation++;
39 35
40bool ObjectPool::IsValid(Handle handle) { 36 // Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
41 int index = handle - HANDLE_OFFSET; 37 // CTR-OS doesn't use generation 0, so skip straight to 1.
42 if (index < 0) 38 if (next_generation >= (1 << 15)) next_generation = 1;
43 return false;
44 if (index >= MAX_COUNT)
45 return false;
46 39
47 return occupied[index]; 40 generations[slot] = generation;
41 intrusive_ptr_add_ref(obj);
42 objects[slot] = obj;
43
44 Handle handle = generation | (slot << 15);
45 obj->handle = handle;
46 return MakeResult<Handle>(handle);
48} 47}
49 48
50void ObjectPool::Clear() { 49ResultVal<Handle> HandleTable::Duplicate(Handle handle) {
51 for (int i = 0; i < MAX_COUNT; i++) { 50 Object* object = GetGeneric(handle);
52 //brutally clear everything, no validation 51 if (object == nullptr) {
53 if (occupied[i]) 52 LOG_ERROR(Kernel, "Tried to duplicate invalid handle: %08X", handle);
54 delete pool[i]; 53 return ERR_INVALID_HANDLE;
55 occupied[i] = false;
56 } 54 }
57 pool.fill(nullptr); 55 return Create(object);
58 next_id = INITIAL_NEXT_ID; 56}
57
58ResultCode HandleTable::Close(Handle handle) {
59 if (!IsValid(handle))
60 return ERR_INVALID_HANDLE;
61
62 size_t slot = GetSlot(handle);
63 u16 generation = GetGeneration(handle);
64
65 intrusive_ptr_release(objects[slot]);
66 objects[slot] = nullptr;
67
68 generations[generation] = next_free_slot;
69 next_free_slot = slot;
70 return RESULT_SUCCESS;
59} 71}
60 72
61Object* &ObjectPool::operator [](Handle handle) 73bool HandleTable::IsValid(Handle handle) const {
62{ 74 size_t slot = GetSlot(handle);
63 _dbg_assert_msg_(KERNEL, IsValid(handle), "GRABBING UNALLOCED KERNEL OBJ"); 75 u16 generation = GetGeneration(handle);
64 return pool[handle - HANDLE_OFFSET]; 76
77 return slot < MAX_COUNT && objects[slot] != nullptr && generations[slot] == generation;
65} 78}
66 79
67void ObjectPool::List() { 80Object* HandleTable::GetGeneric(Handle handle) const {
68 for (int i = 0; i < MAX_COUNT; i++) { 81 if (handle == CurrentThread) {
69 if (occupied[i]) { 82 // TODO(yuriks) Directly return the pointer once this is possible.
70 if (pool[i]) { 83 handle = GetCurrentThreadHandle();
71 INFO_LOG(KERNEL, "KO %i: %s \"%s\"", i + HANDLE_OFFSET, pool[i]->GetTypeName().c_str(), 84 } else if (handle == CurrentProcess) {
72 pool[i]->GetName().c_str()); 85 LOG_ERROR(Kernel, "Current process (%08X) pseudo-handle not supported", CurrentProcess);
73 } 86 return nullptr;
74 }
75 } 87 }
76}
77 88
78int ObjectPool::GetCount() { 89 if (!IsValid(handle)) {
79 int count = 0; 90 return nullptr;
80 for (int i = 0; i < MAX_COUNT; i++) {
81 if (occupied[i])
82 count++;
83 } 91 }
84 return count; 92 return objects[GetSlot(handle)];
85} 93}
86 94
87Object* ObjectPool::CreateByIDType(int type) { 95void HandleTable::Clear() {
88 ERROR_LOG(COMMON, "Unimplemented: %d.", type); 96 for (size_t i = 0; i < MAX_COUNT; ++i) {
89 return nullptr; 97 generations[i] = i + 1;
98 if (objects[i] != nullptr)
99 intrusive_ptr_release(objects[i]);
100 objects[i] = nullptr;
101 }
102 next_free_slot = 0;
90} 103}
91 104
92/// Initialize the kernel 105/// Initialize the kernel
93void Init() { 106void Init() {
94 Kernel::ThreadingInit(); 107 Kernel::ThreadingInit();
95 Kernel::ArchiveInit();
96} 108}
97 109
98/// Shutdown the kernel 110/// Shutdown the kernel
99void Shutdown() { 111void Shutdown() {
100 Kernel::ThreadingShutdown(); 112 Kernel::ThreadingShutdown();
101 Kernel::ArchiveShutdown();
102 113
103 g_object_pool.Clear(); // Free all kernel objects 114 g_handle_table.Clear(); // Free all kernel objects
104} 115}
105 116
106/** 117/**
@@ -109,8 +120,6 @@ void Shutdown() {
109 * @return True on success, otherwise false 120 * @return True on success, otherwise false
110 */ 121 */
111bool LoadExec(u32 entry_point) { 122bool LoadExec(u32 entry_point) {
112 Init();
113
114 Core::g_app_core->SetPC(entry_point); 123 Core::g_app_core->SetPC(entry_point);
115 124
116 // 0x30 is the typical main thread priority I've seen used so far 125 // 0x30 is the typical main thread priority I've seen used so far
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 8d3937ce8..7f86fd07d 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project / PPSSPP Project 1// Copyright 2014 Citra Emulator Project / PPSSPP Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -12,9 +12,17 @@
12typedef u32 Handle; 12typedef u32 Handle;
13typedef s32 Result; 13typedef s32 Result;
14 14
15const Handle INVALID_HANDLE = 0;
16
15namespace Kernel { 17namespace Kernel {
16 18
17enum KernelHandle { 19// TODO: Verify code
20const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel,
21 ErrorSummary::OutOfResource, ErrorLevel::Temporary);
22// TOOD: Verify code
23const ResultCode ERR_INVALID_HANDLE = InvalidHandle(ErrorModule::Kernel);
24
25enum KernelHandle : Handle {
18 CurrentThread = 0xFFFF8000, 26 CurrentThread = 0xFFFF8000,
19 CurrentProcess = 0xFFFF8001, 27 CurrentProcess = 0xFFFF8001,
20}; 28};
@@ -22,7 +30,7 @@ enum KernelHandle {
22enum class HandleType : u32 { 30enum class HandleType : u32 {
23 Unknown = 0, 31 Unknown = 0,
24 Port = 1, 32 Port = 1,
25 Service = 2, 33 Session = 2,
26 Event = 3, 34 Event = 3,
27 Mutex = 4, 35 Mutex = 4,
28 SharedMemory = 5, 36 SharedMemory = 5,
@@ -30,20 +38,17 @@ enum class HandleType : u32 {
30 Thread = 7, 38 Thread = 7,
31 Process = 8, 39 Process = 8,
32 AddressArbiter = 9, 40 AddressArbiter = 9,
33 File = 10, 41 Semaphore = 10,
34 Semaphore = 11,
35 Archive = 12,
36 Directory = 13,
37}; 42};
38 43
39enum { 44enum {
40 DEFAULT_STACK_SIZE = 0x4000, 45 DEFAULT_STACK_SIZE = 0x4000,
41}; 46};
42 47
43class ObjectPool; 48class HandleTable;
44 49
45class Object : NonCopyable { 50class Object : NonCopyable {
46 friend class ObjectPool; 51 friend class HandleTable;
47 u32 handle; 52 u32 handle;
48public: 53public:
49 virtual ~Object() {} 54 virtual ~Object() {}
@@ -53,113 +58,145 @@ public:
53 virtual Kernel::HandleType GetHandleType() const = 0; 58 virtual Kernel::HandleType GetHandleType() const = 0;
54 59
55 /** 60 /**
56 * Synchronize kernel object. 61 * Wait for kernel object to synchronize.
57 * @return True if the current thread should wait as a result of the sync 62 * @return True if the current thread should wait as a result of the wait
58 */ 63 */
59 virtual ResultVal<bool> SyncRequest() { 64 virtual ResultVal<bool> WaitSynchronization() {
60 ERROR_LOG(KERNEL, "(UNIMPLEMENTED)"); 65 LOG_ERROR(Kernel, "(UNIMPLEMENTED)");
61 return UnimplementedFunction(ErrorModule::Kernel); 66 return UnimplementedFunction(ErrorModule::Kernel);
62 } 67 }
63 68
64 /** 69private:
65 * Wait for kernel object to synchronize. 70 friend void intrusive_ptr_add_ref(Object*);
66 * @return True if the current thread should wait as a result of the wait 71 friend void intrusive_ptr_release(Object*);
67 */ 72
68 virtual ResultVal<bool> WaitSynchronization() = 0; 73 unsigned int ref_count = 0;
69}; 74};
70 75
71class ObjectPool : NonCopyable { 76// Special functions that will later be used by boost::instrusive_ptr to do automatic ref-counting
72public: 77inline void intrusive_ptr_add_ref(Object* object) {
73 ObjectPool(); 78 ++object->ref_count;
74 ~ObjectPool() {} 79}
75 80
76 // Allocates a handle within the range and inserts the object into the map. 81inline void intrusive_ptr_release(Object* object) {
77 Handle Create(Object* obj, int range_bottom=INITIAL_NEXT_ID, int range_top=0x7FFFFFFF); 82 if (--object->ref_count == 0) {
83 delete object;
84 }
85}
78 86
79 static Object* CreateByIDType(int type); 87/**
88 * This class allows the creation of Handles, which are references to objects that can be tested
89 * for validity and looked up. Here they are used to pass references to kernel objects to/from the
90 * emulated process. it has been designed so that it follows the same handle format and has
91 * approximately the same restrictions as the handle manager in the CTR-OS.
92 *
93 * Handles contain two sub-fields: a slot index (bits 31:15) and a generation value (bits 14:0).
94 * The slot index is used to index into the arrays in this class to access the data corresponding
95 * to the Handle.
96 *
97 * To prevent accidental use of a freed Handle whose slot has already been reused, a global counter
98 * is kept and incremented every time a Handle is created. This is the Handle's "generation". The
99 * value of the counter is stored into the Handle as well as in the handle table (in the
100 * "generations" array). When looking up a handle, the Handle's generation must match with the
101 * value stored on the class, otherwise the Handle is considered invalid.
102 *
103 * To find free slots when allocating a Handle without needing to scan the entire object array, the
104 * generations field of unallocated slots is re-purposed as a linked list of indices to free slots.
105 * When a Handle is created, an index is popped off the list and used for the new Handle. When it
106 * is destroyed, it is again pushed onto the list to be re-used by the next allocation. It is
107 * likely that this allocation strategy differs from the one used in CTR-OS, but this hasn't been
108 * verified and isn't likely to cause any problems.
109 */
110class HandleTable final : NonCopyable {
111public:
112 HandleTable();
80 113
81 template <class T> 114 /**
82 void Destroy(Handle handle) { 115 * Allocates a handle for the given object.
83 if (Get<T>(handle)) { 116 * @return The created Handle or one of the following errors:
84 occupied[handle - HANDLE_OFFSET] = false; 117 * - `ERR_OUT_OF_HANDLES`: the maximum number of handles has been exceeded.
85 delete pool[handle - HANDLE_OFFSET]; 118 */
86 } 119 ResultVal<Handle> Create(Object* obj);
87 }
88 120
89 bool IsValid(Handle handle); 121 /**
122 * Returns a new handle that points to the same object as the passed in handle.
123 * @return The duplicated Handle or one of the following errors:
124 * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
125 * - Any errors returned by `Create()`.
126 */
127 ResultVal<Handle> Duplicate(Handle handle);
90 128
91 template <class T> 129 /**
92 T* Get(Handle handle) { 130 * Closes a handle, removing it from the table and decreasing the object's ref-count.
93 if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) { 131 * @return `RESULT_SUCCESS` or one of the following errors:
94 if (handle != 0) { 132 * - `ERR_INVALID_HANDLE`: an invalid handle was passed in.
95 WARN_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); 133 */
96 } 134 ResultCode Close(Handle handle);
97 return nullptr;
98 } else {
99 Object* t = pool[handle - HANDLE_OFFSET];
100 if (t->GetHandleType() != T::GetStaticHandleType()) {
101 WARN_LOG(KERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle);
102 return nullptr;
103 }
104 return static_cast<T*>(t);
105 }
106 }
107 135
108 // ONLY use this when you know the handle is valid. 136 /// Checks if a handle is valid and points to an existing object.
109 template <class T> 137 bool IsValid(Handle handle) const;
110 T *GetFast(Handle handle) {
111 const Handle realHandle = handle - HANDLE_OFFSET;
112 _dbg_assert_(KERNEL, realHandle >= 0 && realHandle < MAX_COUNT && occupied[realHandle]);
113 return static_cast<T*>(pool[realHandle]);
114 }
115 138
116 template <class T, typename ArgT> 139 /**
117 void Iterate(bool func(T*, ArgT), ArgT arg) { 140 * Looks up a handle.
118 int type = T::GetStaticIDType(); 141 * @returns Pointer to the looked-up object, or `nullptr` if the handle is not valid.
119 for (int i = 0; i < MAX_COUNT; i++) 142 */
120 { 143 Object* GetGeneric(Handle handle) const;
121 if (!occupied[i])
122 continue;
123 T* t = static_cast<T*>(pool[i]);
124 if (t->GetIDType() == type) {
125 if (!func(t, arg))
126 break;
127 }
128 }
129 }
130 144
131 bool GetIDType(Handle handle, HandleType* type) const { 145 /**
132 if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) || 146 * Looks up a handle while verifying its type.
133 !occupied[handle - HANDLE_OFFSET]) { 147 * @returns Pointer to the looked-up object, or `nullptr` if the handle is not valid or its
134 ERROR_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle); 148 * type differs from the handle type `T::HANDLE_TYPE`.
135 return false; 149 */
150 template <class T>
151 T* Get(Handle handle) const {
152 Object* object = GetGeneric(handle);
153 if (object != nullptr && object->GetHandleType() == T::HANDLE_TYPE) {
154 return static_cast<T*>(object);
136 } 155 }
137 Object* t = pool[handle - HANDLE_OFFSET]; 156 return nullptr;
138 *type = t->GetHandleType();
139 return true;
140 } 157 }
141 158
142 Object* &operator [](Handle handle); 159 /// Closes all handles held in this table.
143 void List();
144 void Clear(); 160 void Clear();
145 int GetCount();
146 161
147private: 162private:
163 /**
164 * This is the maximum limit of handles allowed per process in CTR-OS. It can be further
165 * reduced by ExHeader values, but this is not emulated here.
166 */
167 static const size_t MAX_COUNT = 4096;
148 168
149 enum { 169 static size_t GetSlot(Handle handle) { return handle >> 15; }
150 MAX_COUNT = 0x1000, 170 static u16 GetGeneration(Handle handle) { return handle & 0x7FFF; }
151 HANDLE_OFFSET = 0x100,
152 INITIAL_NEXT_ID = 0x10,
153 };
154 171
155 std::array<Object*, MAX_COUNT> pool; 172 /// Stores the Object referenced by the handle or null if the slot is empty.
156 std::array<bool, MAX_COUNT> occupied; 173 std::array<Object*, MAX_COUNT> objects;
157 int next_id; 174
175 /**
176 * The value of `next_generation` when the handle was created, used to check for validity. For
177 * empty slots, contains the index of the next free slot in the list.
178 */
179 std::array<u16, MAX_COUNT> generations;
180
181 /**
182 * Global counter of the number of created handles. Stored in `generations` when a handle is
183 * created, and wraps around to 1 when it hits 0x8000.
184 */
185 u16 next_generation;
186
187 /// Head of the free slots linked list.
188 u16 next_free_slot;
158}; 189};
159 190
160extern ObjectPool g_object_pool; 191extern HandleTable g_handle_table;
161extern Handle g_main_thread; 192extern Handle g_main_thread;
162 193
194/// The ID code of the currently running game
195/// TODO(Subv): This variable should not be here,
196/// we need a way to store information about the currently loaded application
197/// for later query during runtime, maybe using the LDR service?
198extern u64 g_program_id;
199
163/// Initialize the kernel 200/// Initialize the kernel
164void Init(); 201void Init();
165 202
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index b303ba128..558068c79 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map> 5#include <map>
@@ -18,8 +18,8 @@ public:
18 std::string GetTypeName() const override { return "Mutex"; } 18 std::string GetTypeName() const override { return "Mutex"; }
19 std::string GetName() const override { return name; } 19 std::string GetName() const override { return name; }
20 20
21 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; } 21 static const HandleType HANDLE_TYPE = HandleType::Mutex;
22 Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Mutex; } 22 HandleType GetHandleType() const override { return HANDLE_TYPE; }
23 23
24 bool initial_locked; ///< Initial lock state when mutex was created 24 bool initial_locked; ///< Initial lock state when mutex was created
25 bool locked; ///< Current locked state 25 bool locked; ///< Current locked state
@@ -27,21 +27,7 @@ public:
27 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex 27 std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex
28 std::string name; ///< Name of mutex (optional) 28 std::string name; ///< Name of mutex (optional)
29 29
30 ResultVal<bool> SyncRequest() override { 30 ResultVal<bool> WaitSynchronization() override;
31 // TODO(bunnei): ImplementMe
32 locked = true;
33 return MakeResult<bool>(false);
34 }
35
36 ResultVal<bool> WaitSynchronization() override {
37 // TODO(bunnei): ImplementMe
38 bool wait = locked;
39 if (locked) {
40 Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle());
41 }
42
43 return MakeResult<bool>(wait);
44 }
45}; 31};
46 32
47//////////////////////////////////////////////////////////////////////////////////////////////////// 33////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -49,21 +35,46 @@ public:
49typedef std::multimap<Handle, Handle> MutexMap; 35typedef std::multimap<Handle, Handle> MutexMap;
50static MutexMap g_mutex_held_locks; 36static MutexMap g_mutex_held_locks;
51 37
52void MutexAcquireLock(Mutex* mutex, Handle thread) { 38/**
39 * Acquires the specified mutex for the specified thread
40 * @param mutex Mutex that is to be acquired
41 * @param thread Thread that will acquired
42 */
43void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThreadHandle()) {
53 g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle())); 44 g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle()));
54 mutex->lock_thread = thread; 45 mutex->lock_thread = thread;
55} 46}
56 47
57void MutexAcquireLock(Mutex* mutex) { 48bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
58 Handle thread = GetCurrentThreadHandle();
59 MutexAcquireLock(mutex, thread); 49 MutexAcquireLock(mutex, thread);
50 Kernel::ResumeThreadFromWait(thread);
51 return true;
52}
53
54/**
55 * Resumes a thread waiting for the specified mutex
56 * @param mutex The mutex that some thread is waiting on
57 */
58void ResumeWaitingThread(Mutex* mutex) {
59 // Find the next waiting thread for the mutex...
60 if (mutex->waiting_threads.empty()) {
61 // Reset mutex lock thread handle, nothing is waiting
62 mutex->locked = false;
63 mutex->lock_thread = -1;
64 }
65 else {
66 // Resume the next waiting thread and re-lock the mutex
67 std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
68 ReleaseMutexForThread(mutex, *iter);
69 mutex->waiting_threads.erase(iter);
70 }
60} 71}
61 72
62void MutexEraseLock(Mutex* mutex) { 73void MutexEraseLock(Mutex* mutex) {
63 Handle handle = mutex->GetHandle(); 74 Handle handle = mutex->GetHandle();
64 auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread); 75 auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread);
65 for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) { 76 for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
66 if ((*iter).second == handle) { 77 if (iter->second == handle) {
67 g_mutex_held_locks.erase(iter); 78 g_mutex_held_locks.erase(iter);
68 break; 79 break;
69 } 80 }
@@ -71,6 +82,19 @@ void MutexEraseLock(Mutex* mutex) {
71 mutex->lock_thread = -1; 82 mutex->lock_thread = -1;
72} 83}
73 84
85void ReleaseThreadMutexes(Handle thread) {
86 auto locked = g_mutex_held_locks.equal_range(thread);
87
88 // Release every mutex that the thread holds, and resume execution on the waiting threads
89 for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
90 Mutex* mutex = g_handle_table.Get<Mutex>(iter->second);
91 ResumeWaitingThread(mutex);
92 }
93
94 // Erase all the locks that this thread holds
95 g_mutex_held_locks.erase(thread);
96}
97
74bool LockMutex(Mutex* mutex) { 98bool LockMutex(Mutex* mutex) {
75 // Mutex alread locked? 99 // Mutex alread locked?
76 if (mutex->locked) { 100 if (mutex->locked) {
@@ -80,28 +104,10 @@ bool LockMutex(Mutex* mutex) {
80 return true; 104 return true;
81} 105}
82 106
83bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
84 MutexAcquireLock(mutex, thread);
85 Kernel::ResumeThreadFromWait(thread);
86 return true;
87}
88
89bool ReleaseMutex(Mutex* mutex) { 107bool ReleaseMutex(Mutex* mutex) {
90 MutexEraseLock(mutex); 108 MutexEraseLock(mutex);
91 bool woke_threads = false; 109 ResumeWaitingThread(mutex);
92 110 return true;
93 // Find the next waiting thread for the mutex...
94 while (!woke_threads && !mutex->waiting_threads.empty()) {
95 std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
96 woke_threads |= ReleaseMutexForThread(mutex, *iter);
97 mutex->waiting_threads.erase(iter);
98 }
99 // Reset mutex lock thread handle, nothing is waiting
100 if (!woke_threads) {
101 mutex->locked = false;
102 mutex->lock_thread = -1;
103 }
104 return woke_threads;
105} 111}
106 112
107/** 113/**
@@ -109,7 +115,7 @@ bool ReleaseMutex(Mutex* mutex) {
109 * @param handle Handle to mutex to release 115 * @param handle Handle to mutex to release
110 */ 116 */
111ResultCode ReleaseMutex(Handle handle) { 117ResultCode ReleaseMutex(Handle handle) {
112 Mutex* mutex = Kernel::g_object_pool.Get<Mutex>(handle); 118 Mutex* mutex = Kernel::g_handle_table.Get<Mutex>(handle);
113 if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel); 119 if (mutex == nullptr) return InvalidHandle(ErrorModule::Kernel);
114 120
115 if (!ReleaseMutex(mutex)) { 121 if (!ReleaseMutex(mutex)) {
@@ -130,7 +136,8 @@ ResultCode ReleaseMutex(Handle handle) {
130 */ 136 */
131Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) { 137Mutex* CreateMutex(Handle& handle, bool initial_locked, const std::string& name) {
132 Mutex* mutex = new Mutex; 138 Mutex* mutex = new Mutex;
133 handle = Kernel::g_object_pool.Create(mutex); 139 // TODO(yuriks): Fix error reporting
140 handle = Kernel::g_handle_table.Create(mutex).ValueOr(INVALID_HANDLE);
134 141
135 mutex->locked = mutex->initial_locked = initial_locked; 142 mutex->locked = mutex->initial_locked = initial_locked;
136 mutex->name = name; 143 mutex->name = name;
@@ -158,4 +165,17 @@ Handle CreateMutex(bool initial_locked, const std::string& name) {
158 return handle; 165 return handle;
159} 166}
160 167
168ResultVal<bool> Mutex::WaitSynchronization() {
169 bool wait = locked;
170 if (locked) {
171 Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle());
172 }
173 else {
174 // Lock the mutex when the first thread accesses it
175 locked = true;
176 MutexAcquireLock(this);
177 }
178
179 return MakeResult<bool>(wait);
180}
161} // namespace 181} // namespace
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 155449f95..a8ca97014 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -24,4 +24,10 @@ ResultCode ReleaseMutex(Handle handle);
24 */ 24 */
25Handle CreateMutex(bool initial_locked, const std::string& name="Unknown"); 25Handle CreateMutex(bool initial_locked, const std::string& name="Unknown");
26 26
27/**
28 * Releases all the mutexes held by the specified thread
29 * @param thread Thread that is holding the mutexes
30 */
31void ReleaseThreadMutexes(Handle thread);
32
27} // namespace 33} // namespace
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
new file mode 100644
index 000000000..6bc8066a6
--- /dev/null
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -0,0 +1,95 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <queue>
6
7#include "common/common.h"
8
9#include "core/hle/kernel/kernel.h"
10#include "core/hle/kernel/semaphore.h"
11#include "core/hle/kernel/thread.h"
12
13namespace Kernel {
14
15class Semaphore : public Object {
16public:
17 std::string GetTypeName() const override { return "Semaphore"; }
18 std::string GetName() const override { return name; }
19
20 static const HandleType HANDLE_TYPE = HandleType::Semaphore;
21 HandleType GetHandleType() const override { return HANDLE_TYPE; }
22
23 s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have
24 s32 available_count; ///< Number of free slots left in the semaphore
25 std::queue<Handle> waiting_threads; ///< Threads that are waiting for the semaphore
26 std::string name; ///< Name of semaphore (optional)
27
28 /**
29 * Tests whether a semaphore still has free slots
30 * @return Whether the semaphore is available
31 */
32 bool IsAvailable() const {
33 return available_count > 0;
34 }
35
36 ResultVal<bool> WaitSynchronization() override {
37 bool wait = !IsAvailable();
38
39 if (wait) {
40 Kernel::WaitCurrentThread(WAITTYPE_SEMA, GetHandle());
41 waiting_threads.push(GetCurrentThreadHandle());
42 } else {
43 --available_count;
44 }
45
46 return MakeResult<bool>(wait);
47 }
48};
49
50////////////////////////////////////////////////////////////////////////////////////////////////////
51
52ResultCode CreateSemaphore(Handle* handle, s32 initial_count,
53 s32 max_count, const std::string& name) {
54
55 if (initial_count > max_count)
56 return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel,
57 ErrorSummary::WrongArgument, ErrorLevel::Permanent);
58
59 Semaphore* semaphore = new Semaphore;
60 // TOOD(yuriks): Fix error reporting
61 *handle = g_handle_table.Create(semaphore).ValueOr(INVALID_HANDLE);
62
63 // When the semaphore is created, some slots are reserved for other threads,
64 // and the rest is reserved for the caller thread
65 semaphore->max_count = max_count;
66 semaphore->available_count = initial_count;
67 semaphore->name = name;
68
69 return RESULT_SUCCESS;
70}
71
72ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count) {
73 Semaphore* semaphore = g_handle_table.Get<Semaphore>(handle);
74 if (semaphore == nullptr)
75 return InvalidHandle(ErrorModule::Kernel);
76
77 if (semaphore->max_count - semaphore->available_count < release_count)
78 return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel,
79 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
80
81 *count = semaphore->available_count;
82 semaphore->available_count += release_count;
83
84 // Notify some of the threads that the semaphore has been released
85 // stop once the semaphore is full again or there are no more waiting threads
86 while (!semaphore->waiting_threads.empty() && semaphore->IsAvailable()) {
87 Kernel::ResumeThreadFromWait(semaphore->waiting_threads.front());
88 semaphore->waiting_threads.pop();
89 --semaphore->available_count;
90 }
91
92 return RESULT_SUCCESS;
93}
94
95} // namespace
diff --git a/src/core/hle/kernel/semaphore.h b/src/core/hle/kernel/semaphore.h
new file mode 100644
index 000000000..8644ecf0c
--- /dev/null
+++ b/src/core/hle/kernel/semaphore.h
@@ -0,0 +1,32 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/hle/kernel/kernel.h"
10
11namespace Kernel {
12
13/**
14 * Creates a semaphore.
15 * @param handle Pointer to the handle of the newly created object
16 * @param initial_count Number of slots reserved for other threads
17 * @param max_count Maximum number of slots the semaphore can have
18 * @param name Optional name of semaphore
19 * @return ResultCode of the error
20 */
21ResultCode CreateSemaphore(Handle* handle, s32 initial_count, s32 max_count, const std::string& name = "Unknown");
22
23/**
24 * Releases a certain number of slots from a semaphore.
25 * @param count The number of free slots the semaphore had before this call
26 * @param handle The handle of the semaphore to release
27 * @param release_count The number of slots to release
28 * @return ResultCode of the error
29 */
30ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count);
31
32} // namespace
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
new file mode 100644
index 000000000..91f3ffc2c
--- /dev/null
+++ b/src/core/hle/kernel/session.h
@@ -0,0 +1,58 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/kernel/kernel.h"
8
9namespace Kernel {
10
11static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header
12
13/**
14 * Returns a pointer to the command buffer in kernel memory
15 * @param offset Optional offset into command buffer
16 * @return Pointer to command buffer
17 */
18inline static u32* GetCommandBuffer(const int offset=0) {
19 return (u32*)Memory::GetPointer(Memory::KERNEL_MEMORY_VADDR + kCommandHeaderOffset + offset);
20}
21
22/**
23 * Kernel object representing the client endpoint of an IPC session. Sessions are the basic CTR-OS
24 * primitive for communication between different processes, and are used to implement service calls
25 * to the various system services.
26 *
27 * To make a service call, the client must write the command header and parameters to the buffer
28 * located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest
29 * SVC call with its Session handle. The kernel will read the command header, using it to marshall
30 * the parameters to the process at the server endpoint of the session. After the server replies to
31 * the request, the response is marshalled back to the caller's TLS buffer and control is
32 * transferred back to it.
33 *
34 * In Citra, only the client endpoint is currently implemented and only HLE calls, where the IPC
35 * request is answered by C++ code in the emulator, are supported. When SendSyncRequest is called
36 * with the session handle, this class's SyncRequest method is called, which should read the TLS
37 * buffer and emulate the call accordingly. Since the code can directly read the emulated memory,
38 * no parameter marshalling is done.
39 *
40 * In the long term, this should be turned into the full-fledged IPC mechanism implemented by
41 * CTR-OS so that IPC calls can be optionally handled by the real implementations of processes, as
42 * opposed to HLE simulations.
43 */
44class Session : public Object {
45public:
46 std::string GetTypeName() const override { return "Session"; }
47
48 static const HandleType HANDLE_TYPE = HandleType::Session;
49 HandleType GetHandleType() const override { return HANDLE_TYPE; }
50
51 /**
52 * Handles a synchronous call to this session using HLE emulation. Emulated <-> emulated calls
53 * aren't supported yet.
54 */
55 virtual ResultVal<bool> SyncRequest() = 0;
56};
57
58}
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index cfcc0e0b7..cea1f6fa1 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common.h" 5#include "common/common.h"
@@ -13,14 +13,8 @@ class SharedMemory : public Object {
13public: 13public:
14 std::string GetTypeName() const override { return "SharedMemory"; } 14 std::string GetTypeName() const override { return "SharedMemory"; }
15 15
16 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::SharedMemory; } 16 static const HandleType HANDLE_TYPE = HandleType::SharedMemory;
17 Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::SharedMemory; } 17 HandleType GetHandleType() const override { return HANDLE_TYPE; }
18
19 ResultVal<bool> WaitSynchronization() override {
20 // TODO(bunnei): ImplementMe
21 ERROR_LOG(OSHLE, "(UNIMPLEMENTED)");
22 return UnimplementedFunction(ErrorModule::OS);
23 }
24 18
25 u32 base_address; ///< Address of shared memory block in RAM 19 u32 base_address; ///< Address of shared memory block in RAM
26 MemoryPermission permissions; ///< Permissions of shared memory block (SVC field) 20 MemoryPermission permissions; ///< Permissions of shared memory block (SVC field)
@@ -38,7 +32,8 @@ public:
38 */ 32 */
39SharedMemory* CreateSharedMemory(Handle& handle, const std::string& name) { 33SharedMemory* CreateSharedMemory(Handle& handle, const std::string& name) {
40 SharedMemory* shared_memory = new SharedMemory; 34 SharedMemory* shared_memory = new SharedMemory;
41 handle = Kernel::g_object_pool.Create(shared_memory); 35 // TOOD(yuriks): Fix error reporting
36 handle = Kernel::g_handle_table.Create(shared_memory).ValueOr(INVALID_HANDLE);
42 shared_memory->name = name; 37 shared_memory->name = name;
43 return shared_memory; 38 return shared_memory;
44} 39}
@@ -61,12 +56,12 @@ ResultCode MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions
61 MemoryPermission other_permissions) { 56 MemoryPermission other_permissions) {
62 57
63 if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) { 58 if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) {
64 ERROR_LOG(KERNEL, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!", 59 LOG_ERROR(Kernel_SVC, "cannot map handle=0x%08X, address=0x%08X outside of shared mem bounds!",
65 handle, address); 60 handle, address);
66 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, 61 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
67 ErrorSummary::InvalidArgument, ErrorLevel::Permanent); 62 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
68 } 63 }
69 SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle); 64 SharedMemory* shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle);
70 if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); 65 if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel);
71 66
72 shared_memory->base_address = address; 67 shared_memory->base_address = address;
@@ -77,13 +72,13 @@ ResultCode MapSharedMemory(u32 handle, u32 address, MemoryPermission permissions
77} 72}
78 73
79ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) { 74ResultVal<u8*> GetSharedMemoryPointer(Handle handle, u32 offset) {
80 SharedMemory* shared_memory = Kernel::g_object_pool.Get<SharedMemory>(handle); 75 SharedMemory* shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle);
81 if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel); 76 if (shared_memory == nullptr) return InvalidHandle(ErrorModule::Kernel);
82 77
83 if (0 != shared_memory->base_address) 78 if (0 != shared_memory->base_address)
84 return MakeResult<u8*>(Memory::GetPointer(shared_memory->base_address + offset)); 79 return MakeResult<u8*>(Memory::GetPointer(shared_memory->base_address + offset));
85 80
86 ERROR_LOG(KERNEL, "memory block handle=0x%08X not mapped!", handle); 81 LOG_ERROR(Kernel_SVC, "memory block handle=0x%08X not mapped!", handle);
87 // TODO(yuriks): Verify error code. 82 // TODO(yuriks): Verify error code.
88 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, 83 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
89 ErrorSummary::InvalidState, ErrorLevel::Permanent); 84 ErrorSummary::InvalidState, ErrorLevel::Permanent);
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 304cf5b67..bb65c7ccd 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -12,11 +12,15 @@ namespace Kernel {
12 12
13/// Permissions for mapped shared memory blocks 13/// Permissions for mapped shared memory blocks
14enum class MemoryPermission : u32 { 14enum class MemoryPermission : u32 {
15 None = 0, 15 None = 0,
16 Read = (1u << 0), 16 Read = (1u << 0),
17 Write = (1u << 1), 17 Write = (1u << 1),
18 ReadWrite = (Read | Write), 18 ReadWrite = (Read | Write),
19 DontCare = (1u << 28) 19 Execute = (1u << 2),
20 ReadExecute = (Read | Execute),
21 WriteExecute = (Write | Execute),
22 ReadWriteExecute = (Read | Write | Execute),
23 DontCare = (1u << 28)
20}; 24};
21 25
22/** 26/**
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index f3f54a4e9..872df2d14 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project / PPSSPP Project 1// Copyright 2014 Citra Emulator Project / PPSSPP Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
@@ -14,6 +14,7 @@
14#include "core/hle/hle.h" 14#include "core/hle/hle.h"
15#include "core/hle/kernel/kernel.h" 15#include "core/hle/kernel/kernel.h"
16#include "core/hle/kernel/thread.h" 16#include "core/hle/kernel/thread.h"
17#include "core/hle/kernel/mutex.h"
17#include "core/hle/result.h" 18#include "core/hle/result.h"
18#include "core/mem_map.h" 19#include "core/mem_map.h"
19 20
@@ -25,8 +26,8 @@ public:
25 std::string GetName() const override { return name; } 26 std::string GetName() const override { return name; }
26 std::string GetTypeName() const override { return "Thread"; } 27 std::string GetTypeName() const override { return "Thread"; }
27 28
28 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Thread; } 29 static const HandleType HANDLE_TYPE = HandleType::Thread;
29 Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Thread; } 30 HandleType GetHandleType() const override { return HANDLE_TYPE; }
30 31
31 inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; } 32 inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; }
32 inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; } 33 inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; }
@@ -49,6 +50,8 @@ public:
49 50
50 ThreadContext context; 51 ThreadContext context;
51 52
53 u32 thread_id;
54
52 u32 status; 55 u32 status;
53 u32 entry_point; 56 u32 entry_point;
54 u32 stack_top; 57 u32 stack_top;
@@ -61,6 +64,7 @@ public:
61 64
62 WaitType wait_type; 65 WaitType wait_type;
63 Handle wait_handle; 66 Handle wait_handle;
67 VAddr wait_address;
64 68
65 std::vector<Handle> waiting_threads; 69 std::vector<Handle> waiting_threads;
66 70
@@ -76,8 +80,10 @@ static Common::ThreadQueueList<Handle> thread_ready_queue;
76static Handle current_thread_handle; 80static Handle current_thread_handle;
77static Thread* current_thread; 81static Thread* current_thread;
78 82
79/// Gets the current thread 83static const u32 INITIAL_THREAD_ID = 1; ///< The first available thread id at startup
80inline Thread* GetCurrentThread() { 84static u32 next_thread_id; ///< The next available thread id
85
86Thread* GetCurrentThread() {
81 return current_thread; 87 return current_thread;
82} 88}
83 89
@@ -121,6 +127,7 @@ void ResetThread(Thread* t, u32 arg, s32 lowest_priority) {
121 } 127 }
122 t->wait_type = WAITTYPE_NONE; 128 t->wait_type = WAITTYPE_NONE;
123 t->wait_handle = 0; 129 t->wait_handle = 0;
130 t->wait_address = 0;
124} 131}
125 132
126/// Change a thread to "ready" state 133/// Change a thread to "ready" state
@@ -140,30 +147,43 @@ void ChangeReadyState(Thread* t, bool ready) {
140 } 147 }
141} 148}
142 149
143/// Verify that a thread has not been released from waiting 150/// Check if a thread is blocking on a specified wait type
144inline bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) { 151static bool CheckWaitType(const Thread* thread, WaitType type) {
145 _dbg_assert_(KERNEL, thread != nullptr); 152 return (type == thread->wait_type) && (thread->IsWaiting());
146 return type == thread->wait_type && wait_handle == thread->wait_handle; 153}
154
155/// Check if a thread is blocking on a specified wait type with a specified handle
156static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle) {
157 return CheckWaitType(thread, type) && (wait_handle == thread->wait_handle);
158}
159
160/// Check if a thread is blocking on a specified wait type with a specified handle and address
161static bool CheckWaitType(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) {
162 return CheckWaitType(thread, type, wait_handle) && (wait_address == thread->wait_address);
147} 163}
148 164
149/// Stops the current thread 165/// Stops the current thread
150ResultCode StopThread(Handle handle, const char* reason) { 166ResultCode StopThread(Handle handle, const char* reason) {
151 Thread* thread = g_object_pool.Get<Thread>(handle); 167 Thread* thread = g_handle_table.Get<Thread>(handle);
152 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); 168 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
153 169
170 // Release all the mutexes that this thread holds
171 ReleaseThreadMutexes(handle);
172
154 ChangeReadyState(thread, false); 173 ChangeReadyState(thread, false);
155 thread->status = THREADSTATUS_DORMANT; 174 thread->status = THREADSTATUS_DORMANT;
156 for (Handle waiting_handle : thread->waiting_threads) { 175 for (Handle waiting_handle : thread->waiting_threads) {
157 Thread* waiting_thread = g_object_pool.Get<Thread>(waiting_handle); 176 Thread* waiting_thread = g_handle_table.Get<Thread>(waiting_handle);
158 if (VerifyWait(waiting_thread, WAITTYPE_THREADEND, handle)) { 177
178 if (CheckWaitType(waiting_thread, WAITTYPE_THREADEND, handle))
159 ResumeThreadFromWait(waiting_handle); 179 ResumeThreadFromWait(waiting_handle);
160 }
161 } 180 }
162 thread->waiting_threads.clear(); 181 thread->waiting_threads.clear();
163 182
164 // Stopped threads are never waiting. 183 // Stopped threads are never waiting.
165 thread->wait_type = WAITTYPE_NONE; 184 thread->wait_type = WAITTYPE_NONE;
166 thread->wait_handle = 0; 185 thread->wait_handle = 0;
186 thread->wait_address = 0;
167 187
168 return RESULT_SUCCESS; 188 return RESULT_SUCCESS;
169} 189}
@@ -178,7 +198,7 @@ void ChangeThreadState(Thread* t, ThreadStatus new_status) {
178 198
179 if (new_status == THREADSTATUS_WAIT) { 199 if (new_status == THREADSTATUS_WAIT) {
180 if (t->wait_type == WAITTYPE_NONE) { 200 if (t->wait_type == WAITTYPE_NONE) {
181 ERROR_LOG(KERNEL, "Waittype none not allowed"); 201 LOG_ERROR(Kernel, "Waittype none not allowed");
182 } 202 }
183 } 203 }
184} 204}
@@ -190,14 +210,14 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
190 210
191 // Iterate through threads, find highest priority thread that is waiting to be arbitrated... 211 // Iterate through threads, find highest priority thread that is waiting to be arbitrated...
192 for (Handle handle : thread_queue) { 212 for (Handle handle : thread_queue) {
193 Thread* thread = g_object_pool.Get<Thread>(handle); 213 Thread* thread = g_handle_table.Get<Thread>(handle);
194 214
195 // TODO(bunnei): Verify arbiter address... 215 if (!CheckWaitType(thread, WAITTYPE_ARB, arbiter, address))
196 if (!VerifyWait(thread, WAITTYPE_ARB, arbiter))
197 continue; 216 continue;
198 217
199 if (thread == nullptr) 218 if (thread == nullptr)
200 continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up. 219 continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up.
220
201 if(thread->current_priority <= priority) { 221 if(thread->current_priority <= priority) {
202 highest_priority_thread = handle; 222 highest_priority_thread = handle;
203 priority = thread->current_priority; 223 priority = thread->current_priority;
@@ -215,10 +235,9 @@ void ArbitrateAllThreads(u32 arbiter, u32 address) {
215 235
216 // Iterate through threads, find highest priority thread that is waiting to be arbitrated... 236 // Iterate through threads, find highest priority thread that is waiting to be arbitrated...
217 for (Handle handle : thread_queue) { 237 for (Handle handle : thread_queue) {
218 Thread* thread = g_object_pool.Get<Thread>(handle); 238 Thread* thread = g_handle_table.Get<Thread>(handle);
219 239
220 // TODO(bunnei): Verify arbiter address... 240 if (CheckWaitType(thread, WAITTYPE_ARB, arbiter, address))
221 if (VerifyWait(thread, WAITTYPE_ARB, arbiter))
222 ResumeThreadFromWait(handle); 241 ResumeThreadFromWait(handle);
223 } 242 }
224} 243}
@@ -269,14 +288,9 @@ Thread* NextThread() {
269 if (next == 0) { 288 if (next == 0) {
270 return nullptr; 289 return nullptr;
271 } 290 }
272 return Kernel::g_object_pool.Get<Thread>(next); 291 return Kernel::g_handle_table.Get<Thread>(next);
273} 292}
274 293
275/**
276 * Puts the current thread in the wait state for the given type
277 * @param wait_type Type of wait
278 * @param wait_handle Handle of Kernel object that we are waiting on, defaults to current thread
279 */
280void WaitCurrentThread(WaitType wait_type, Handle wait_handle) { 294void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
281 Thread* thread = GetCurrentThread(); 295 Thread* thread = GetCurrentThread();
282 thread->wait_type = wait_type; 296 thread->wait_type = wait_type;
@@ -284,11 +298,18 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
284 ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND))); 298 ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
285} 299}
286 300
301void WaitCurrentThread(WaitType wait_type, Handle wait_handle, VAddr wait_address) {
302 WaitCurrentThread(wait_type, wait_handle);
303 GetCurrentThread()->wait_address = wait_address;
304}
305
287/// Resumes a thread from waiting by marking it as "ready" 306/// Resumes a thread from waiting by marking it as "ready"
288void ResumeThreadFromWait(Handle handle) { 307void ResumeThreadFromWait(Handle handle) {
289 Thread* thread = Kernel::g_object_pool.Get<Thread>(handle); 308 Thread* thread = Kernel::g_handle_table.Get<Thread>(handle);
290 if (thread) { 309 if (thread) {
291 thread->status &= ~THREADSTATUS_WAIT; 310 thread->status &= ~THREADSTATUS_WAIT;
311 thread->wait_handle = 0;
312 thread->wait_type = WAITTYPE_NONE;
292 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) { 313 if (!(thread->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
293 ChangeReadyState(thread, true); 314 ChangeReadyState(thread, true);
294 } 315 }
@@ -301,12 +322,12 @@ void DebugThreadQueue() {
301 if (!thread) { 322 if (!thread) {
302 return; 323 return;
303 } 324 }
304 INFO_LOG(KERNEL, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThreadHandle()); 325 LOG_DEBUG(Kernel, "0x%02X 0x%08X (current)", thread->current_priority, GetCurrentThreadHandle());
305 for (u32 i = 0; i < thread_queue.size(); i++) { 326 for (u32 i = 0; i < thread_queue.size(); i++) {
306 Handle handle = thread_queue[i]; 327 Handle handle = thread_queue[i];
307 s32 priority = thread_ready_queue.contains(handle); 328 s32 priority = thread_ready_queue.contains(handle);
308 if (priority != -1) { 329 if (priority != -1) {
309 INFO_LOG(KERNEL, "0x%02X 0x%08X", priority, handle); 330 LOG_DEBUG(Kernel, "0x%02X 0x%08X", priority, handle);
310 } 331 }
311 } 332 }
312} 333}
@@ -316,15 +337,17 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio
316 s32 processor_id, u32 stack_top, int stack_size) { 337 s32 processor_id, u32 stack_top, int stack_size) {
317 338
318 _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST), 339 _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST),
319 "CreateThread priority=%d, outside of allowable range!", priority) 340 "priority=%d, outside of allowable range!", priority)
320 341
321 Thread* thread = new Thread; 342 Thread* thread = new Thread;
322 343
323 handle = Kernel::g_object_pool.Create(thread); 344 // TOOD(yuriks): Fix error reporting
345 handle = Kernel::g_handle_table.Create(thread).ValueOr(INVALID_HANDLE);
324 346
325 thread_queue.push_back(handle); 347 thread_queue.push_back(handle);
326 thread_ready_queue.prepare(priority); 348 thread_ready_queue.prepare(priority);
327 349
350 thread->thread_id = next_thread_id++;
328 thread->status = THREADSTATUS_DORMANT; 351 thread->status = THREADSTATUS_DORMANT;
329 thread->entry_point = entry_point; 352 thread->entry_point = entry_point;
330 thread->stack_top = stack_top; 353 thread->stack_top = stack_top;
@@ -333,6 +356,7 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio
333 thread->processor_id = processor_id; 356 thread->processor_id = processor_id;
334 thread->wait_type = WAITTYPE_NONE; 357 thread->wait_type = WAITTYPE_NONE;
335 thread->wait_handle = 0; 358 thread->wait_handle = 0;
359 thread->wait_address = 0;
336 thread->name = name; 360 thread->name = name;
337 361
338 return thread; 362 return thread;
@@ -343,24 +367,24 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3
343 u32 stack_top, int stack_size) { 367 u32 stack_top, int stack_size) {
344 368
345 if (name == nullptr) { 369 if (name == nullptr) {
346 ERROR_LOG(KERNEL, "CreateThread(): nullptr name"); 370 LOG_ERROR(Kernel_SVC, "nullptr name");
347 return -1; 371 return -1;
348 } 372 }
349 if ((u32)stack_size < 0x200) { 373 if ((u32)stack_size < 0x200) {
350 ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid stack_size=0x%08X", name, 374 LOG_ERROR(Kernel_SVC, "(name=%s): invalid stack_size=0x%08X", name,
351 stack_size); 375 stack_size);
352 return -1; 376 return -1;
353 } 377 }
354 if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { 378 if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
355 s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); 379 s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
356 WARN_LOG(KERNEL, "CreateThread(name=%s): invalid priority=0x%08X, clamping to %08X", 380 LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d",
357 name, priority, new_priority); 381 name, priority, new_priority);
358 // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm 382 // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
359 // validity of this 383 // validity of this
360 priority = new_priority; 384 priority = new_priority;
361 } 385 }
362 if (!Memory::GetPointer(entry_point)) { 386 if (!Memory::GetPointer(entry_point)) {
363 ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid entry %08x", name, entry_point); 387 LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name, entry_point);
364 return -1; 388 return -1;
365 } 389 }
366 Handle handle; 390 Handle handle;
@@ -375,7 +399,7 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3
375 399
376/// Get the priority of the thread specified by handle 400/// Get the priority of the thread specified by handle
377ResultVal<u32> GetThreadPriority(const Handle handle) { 401ResultVal<u32> GetThreadPriority(const Handle handle) {
378 Thread* thread = g_object_pool.Get<Thread>(handle); 402 Thread* thread = g_handle_table.Get<Thread>(handle);
379 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel); 403 if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
380 404
381 return MakeResult<u32>(thread->current_priority); 405 return MakeResult<u32>(thread->current_priority);
@@ -387,7 +411,7 @@ ResultCode SetThreadPriority(Handle handle, s32 priority) {
387 if (!handle) { 411 if (!handle) {
388 thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior? 412 thread = GetCurrentThread(); // TODO(bunnei): Is this correct behavior?
389 } else { 413 } else {
390 thread = g_object_pool.Get<Thread>(handle); 414 thread = g_handle_table.Get<Thread>(handle);
391 if (thread == nullptr) { 415 if (thread == nullptr) {
392 return InvalidHandle(ErrorModule::Kernel); 416 return InvalidHandle(ErrorModule::Kernel);
393 } 417 }
@@ -397,7 +421,7 @@ ResultCode SetThreadPriority(Handle handle, s32 priority) {
397 // If priority is invalid, clamp to valid range 421 // If priority is invalid, clamp to valid range
398 if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) { 422 if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
399 s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST); 423 s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
400 WARN_LOG(KERNEL, "invalid priority=0x%08X, clamping to %08X", priority, new_priority); 424 LOG_WARNING(Kernel_SVC, "invalid priority=%d, clamping to %d", priority, new_priority);
401 // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm 425 // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
402 // validity of this 426 // validity of this
403 priority = new_priority; 427 priority = new_priority;
@@ -450,24 +474,44 @@ void Reschedule() {
450 Thread* prev = GetCurrentThread(); 474 Thread* prev = GetCurrentThread();
451 Thread* next = NextThread(); 475 Thread* next = NextThread();
452 HLE::g_reschedule = false; 476 HLE::g_reschedule = false;
453 if (next > 0) {
454 INFO_LOG(KERNEL, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle());
455 477
478 if (next != nullptr) {
479 LOG_TRACE(Kernel, "context switch 0x%08X -> 0x%08X", prev->GetHandle(), next->GetHandle());
456 SwitchContext(next); 480 SwitchContext(next);
481 } else {
482 LOG_TRACE(Kernel, "cannot context switch from 0x%08X, no higher priority thread!", prev->GetHandle());
457 483
458 // Hack - There is no mechanism yet to waken the primary thread if it has been put to sleep 484 for (Handle handle : thread_queue) {
459 // by a simulated VBLANK thread switch. So, we'll just immediately set it to "ready" again. 485 Thread* thread = g_handle_table.Get<Thread>(handle);
460 // This results in the current thread yielding on a VBLANK once, and then it will be 486 LOG_TRACE(Kernel, "\thandle=0x%08X prio=0x%02X, status=0x%08X wait_type=0x%08X wait_handle=0x%08X",
461 // immediately placed back in the queue for execution. 487 thread->GetHandle(), thread->current_priority, thread->status, thread->wait_type, thread->wait_handle);
462 if (prev->wait_type == WAITTYPE_VBLANK) {
463 ResumeThreadFromWait(prev->GetHandle());
464 } 488 }
465 } 489 }
490
491 // TODO(bunnei): Hack - There is no timing mechanism yet to wake up a thread if it has been put
492 // to sleep. So, we'll just immediately set it to "ready" again after an attempted context
493 // switch has occurred. This results in the current thread yielding on a sleep once, and then it
494 // will immediately be placed back in the queue for execution.
495
496 if (CheckWaitType(prev, WAITTYPE_SLEEP))
497 ResumeThreadFromWait(prev->GetHandle());
498}
499
500ResultCode GetThreadId(u32* thread_id, Handle handle) {
501 Thread* thread = g_handle_table.Get<Thread>(handle);
502 if (thread == nullptr)
503 return ResultCode(ErrorDescription::InvalidHandle, ErrorModule::OS,
504 ErrorSummary::WrongArgument, ErrorLevel::Permanent);
505
506 *thread_id = thread->thread_id;
507
508 return RESULT_SUCCESS;
466} 509}
467 510
468//////////////////////////////////////////////////////////////////////////////////////////////////// 511////////////////////////////////////////////////////////////////////////////////////////////////////
469 512
470void ThreadingInit() { 513void ThreadingInit() {
514 next_thread_id = INITIAL_THREAD_ID;
471} 515}
472 516
473void ThreadingShutdown() { 517void ThreadingShutdown() {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index ce63a70d3..0e1397cd9 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -1,10 +1,13 @@
1// Copyright 2014 Citra Emulator Project / PPSSPP Project 1// Copyright 2014 Citra Emulator Project / PPSSPP Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8
9#include "core/mem_map.h"
10
8#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
9#include "core/hle/result.h" 12#include "core/hle/result.h"
10 13
@@ -37,7 +40,6 @@ enum WaitType {
37 WAITTYPE_SEMA, 40 WAITTYPE_SEMA,
38 WAITTYPE_EVENT, 41 WAITTYPE_EVENT,
39 WAITTYPE_THREADEND, 42 WAITTYPE_THREADEND,
40 WAITTYPE_VBLANK,
41 WAITTYPE_MUTEX, 43 WAITTYPE_MUTEX,
42 WAITTYPE_SYNCH, 44 WAITTYPE_SYNCH,
43 WAITTYPE_ARB, 45 WAITTYPE_ARB,
@@ -58,6 +60,14 @@ void Reschedule();
58/// Stops the current thread 60/// Stops the current thread
59ResultCode StopThread(Handle thread, const char* reason); 61ResultCode StopThread(Handle thread, const char* reason);
60 62
63/**
64 * Retrieves the ID of the specified thread handle
65 * @param thread_id Will contain the output thread id
66 * @param handle Handle to the thread we want
67 * @return Whether the function was successful or not
68 */
69ResultCode GetThreadId(u32* thread_id, Handle handle);
70
61/// Resumes a thread from waiting by marking it as "ready" 71/// Resumes a thread from waiting by marking it as "ready"
62void ResumeThreadFromWait(Handle handle); 72void ResumeThreadFromWait(Handle handle);
63 73
@@ -77,6 +87,14 @@ Handle GetCurrentThreadHandle();
77 */ 87 */
78void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHandle()); 88void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHandle());
79 89
90/**
91 * Puts the current thread in the wait state for the given type
92 * @param wait_type Type of wait
93 * @param wait_handle Handle of Kernel object that we are waiting on, defaults to current thread
94 * @param wait_address Arbitration address used to resume from wait
95 */
96void WaitCurrentThread(WaitType wait_type, Handle wait_handle, VAddr wait_address);
97
80/// Put current thread in a wait state - on WaitSynchronization 98/// Put current thread in a wait state - on WaitSynchronization
81void WaitThread_Synchronization(); 99void WaitThread_Synchronization();
82 100
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 15c4a2677..0e9c213e0 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -17,6 +17,8 @@
17/// Detailed description of the error. This listing is likely incomplete. 17/// Detailed description of the error. This listing is likely incomplete.
18enum class ErrorDescription : u32 { 18enum class ErrorDescription : u32 {
19 Success = 0, 19 Success = 0,
20 FS_NotFound = 100,
21 FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
20 InvalidSection = 1000, 22 InvalidSection = 1000,
21 TooLarge = 1001, 23 TooLarge = 1001,
22 NotAuthorized = 1002, 24 NotAuthorized = 1002,
diff --git a/src/core/hle/service/ac_u.cpp b/src/core/hle/service/ac_u.cpp
index 9af96f6b8..20a3fa2e5 100644
--- a/src/core/hle/service/ac_u.cpp
+++ b/src/core/hle/service/ac_u.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h" 5#include "common/log.h"
@@ -11,6 +11,24 @@
11 11
12namespace AC_U { 12namespace AC_U {
13 13
14/**
15 * AC_U::GetWifiStatus service function
16 * Outputs:
17 * 1 : Result of function, 0 on success, otherwise error code
18 * 2 : Output connection type, 0 = none, 1 = Old3DS Internet, 2 = New3DS Internet.
19 */
20void GetWifiStatus(Service::Interface* self) {
21 u32* cmd_buff = Kernel::GetCommandBuffer();
22
23 // TODO(purpasmart96): This function is only a stub,
24 // it returns a valid result without implementing full functionality.
25
26 cmd_buff[1] = 0; // No error
27 cmd_buff[2] = 0; // Connection type set to none
28
29 LOG_WARNING(Service_AC, "(STUBBED) called");
30}
31
14const Interface::FunctionInfo FunctionTable[] = { 32const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010000, nullptr, "CreateDefaultConfig"}, 33 {0x00010000, nullptr, "CreateDefaultConfig"},
16 {0x00040006, nullptr, "ConnectAsync"}, 34 {0x00040006, nullptr, "ConnectAsync"},
@@ -18,7 +36,7 @@ const Interface::FunctionInfo FunctionTable[] = {
18 {0x00080004, nullptr, "CloseAsync"}, 36 {0x00080004, nullptr, "CloseAsync"},
19 {0x00090002, nullptr, "GetCloseResult"}, 37 {0x00090002, nullptr, "GetCloseResult"},
20 {0x000A0000, nullptr, "GetLastErrorCode"}, 38 {0x000A0000, nullptr, "GetLastErrorCode"},
21 {0x000D0000, nullptr, "GetWifiStatus"}, 39 {0x000D0000, GetWifiStatus, "GetWifiStatus"},
22 {0x000E0042, nullptr, "GetCurrentAPInfo"}, 40 {0x000E0042, nullptr, "GetCurrentAPInfo"},
23 {0x00100042, nullptr, "GetCurrentNZoneInfo"}, 41 {0x00100042, nullptr, "GetCurrentNZoneInfo"},
24 {0x00110042, nullptr, "GetNZoneApNumService"}, 42 {0x00110042, nullptr, "GetNZoneApNumService"},
@@ -38,7 +56,4 @@ Interface::Interface() {
38 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 56 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
39} 57}
40 58
41Interface::~Interface() {
42}
43
44} // namespace 59} // namespace
diff --git a/src/core/hle/service/ac_u.h b/src/core/hle/service/ac_u.h
index c91b28353..f1d26ebe8 100644
--- a/src/core/hle/service/ac_u.h
+++ b/src/core/hle/service/ac_u.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -16,11 +16,7 @@ namespace AC_U {
16class Interface : public Service::Interface { 16class Interface : public Service::Interface {
17public: 17public:
18 Interface(); 18 Interface();
19 ~Interface(); 19
20 /**
21 * Gets the string port name used by CTROS for the service
22 * @return Port name of service
23 */
24 std::string GetPortName() const override { 20 std::string GetPortName() const override {
25 return "ac:u"; 21 return "ac:u";
26 } 22 }
diff --git a/src/core/hle/service/act_u.cpp b/src/core/hle/service/act_u.cpp
new file mode 100644
index 000000000..10870f14b
--- /dev/null
+++ b/src/core/hle/service/act_u.cpp
@@ -0,0 +1,24 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/act_u.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace ACT_U
11
12namespace ACT_U {
13
14// Empty arrays are illegal -- commented out until an entry is added.
15//const Interface::FunctionInfo FunctionTable[] = { };
16
17////////////////////////////////////////////////////////////////////////////////////////////////////
18// Interface class
19
20Interface::Interface() {
21 //Register(FunctionTable, ARRAY_SIZE(FunctionTable));
22}
23
24} // namespace
diff --git a/src/core/hle/service/act_u.h b/src/core/hle/service/act_u.h
new file mode 100644
index 000000000..be41454a4
--- /dev/null
+++ b/src/core/hle/service/act_u.h
@@ -0,0 +1,23 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace ACT_U
11
12namespace ACT_U {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "act:u";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/am_app.cpp b/src/core/hle/service/am_app.cpp
new file mode 100644
index 000000000..0b396b6d3
--- /dev/null
+++ b/src/core/hle/service/am_app.cpp
@@ -0,0 +1,24 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/am_app.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace AM_APP
11
12namespace AM_APP {
13
14// Empty arrays are illegal -- commented out until an entry is added.
15//const Interface::FunctionInfo FunctionTable[] = { };
16
17////////////////////////////////////////////////////////////////////////////////////////////////////
18// Interface class
19
20Interface::Interface() {
21 //Register(FunctionTable, ARRAY_SIZE(FunctionTable));
22}
23
24} // namespace
diff --git a/src/core/hle/service/am_app.h b/src/core/hle/service/am_app.h
new file mode 100644
index 000000000..50dc2f5a2
--- /dev/null
+++ b/src/core/hle/service/am_app.h
@@ -0,0 +1,23 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace AM_APP
11
12namespace AM_APP {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "am:app";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/am_net.cpp b/src/core/hle/service/am_net.cpp
index 403cac353..112844e5b 100644
--- a/src/core/hle/service/am_net.cpp
+++ b/src/core/hle/service/am_net.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h" 5#include "common/log.h"
@@ -41,7 +41,4 @@ Interface::Interface() {
41 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 41 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
42} 42}
43 43
44Interface::~Interface() {
45}
46
47} // namespace 44} // namespace
diff --git a/src/core/hle/service/am_net.h b/src/core/hle/service/am_net.h
index 4816e1697..616c33ee8 100644
--- a/src/core/hle/service/am_net.h
+++ b/src/core/hle/service/am_net.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -14,11 +14,7 @@ namespace AM_NET {
14class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15public: 15public:
16 Interface(); 16 Interface();
17 ~Interface(); 17
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const override { 18 std::string GetPortName() const override {
23 return "am:net"; 19 return "am:net";
24 } 20 }
diff --git a/src/core/hle/service/apt_a.cpp b/src/core/hle/service/apt_a.cpp
new file mode 100644
index 000000000..dcf5ec4fe
--- /dev/null
+++ b/src/core/hle/service/apt_a.cpp
@@ -0,0 +1,34 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/apt_a.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace APT_A
11
12namespace APT_A {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010040, nullptr, "GetLockHandle?"},
16 {0x00020080, nullptr, "Initialize?"},
17 {0x00030040, nullptr, "Enable?"},
18 {0x00040040, nullptr, "Finalize?"},
19 {0x00050040, nullptr, "GetAppletManInfo?"},
20 {0x00060040, nullptr, "GetAppletInfo?"},
21 {0x003B0040, nullptr, "CancelLibraryApplet?"},
22 {0x00430040, nullptr, "NotifyToWait?"},
23 {0x004B00C2, nullptr, "AppletUtility?"},
24 {0x00550040, nullptr, "WriteInputToNsState?"},
25};
26
27////////////////////////////////////////////////////////////////////////////////////////////////////
28// Interface class
29
30Interface::Interface() {
31 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
32}
33
34} // namespace
diff --git a/src/core/hle/service/apt_a.h b/src/core/hle/service/apt_a.h
new file mode 100644
index 000000000..6cbf1288f
--- /dev/null
+++ b/src/core/hle/service/apt_a.h
@@ -0,0 +1,23 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace APT_A
11
12namespace APT_A {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "APT:A";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/apt_u.cpp b/src/core/hle/service/apt_u.cpp
index 4bb05ce40..d8b261ba7 100644
--- a/src/core/hle/service/apt_u.cpp
+++ b/src/core/hle/service/apt_u.cpp
@@ -1,13 +1,15 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5 5
6#include "common/common.h" 6#include "common/common.h"
7#include "common/file_util.h"
7 8
8#include "core/hle/hle.h" 9#include "core/hle/hle.h"
9#include "core/hle/kernel/event.h" 10#include "core/hle/kernel/event.h"
10#include "core/hle/kernel/mutex.h" 11#include "core/hle/kernel/mutex.h"
12#include "core/hle/kernel/shared_memory.h"
11#include "apt_u.h" 13#include "apt_u.h"
12 14
13//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -15,7 +17,19 @@
15 17
16namespace APT_U { 18namespace APT_U {
17 19
20// Address used for shared font (as observed on HW)
21// TODO(bunnei): This is the hard-coded address where we currently dump the shared font from via
22// https://github.com/citra-emu/3dsutils. This is technically a hack, and will not work at any
23// address other than 0x18000000 due to internal pointers in the shared font dump that would need to
24// be relocated. This might be fixed by dumping the shared font @ address 0x00000000 and then
25// correctly mapping it in Citra, however we still do not understand how the mapping is determined.
26static const VAddr SHARED_FONT_VADDR = 0x18000000;
27
28// Handle to shared memory region designated to for shared system font
29static Handle shared_font_mem = 0;
30
18static Handle lock_handle = 0; 31static Handle lock_handle = 0;
32static std::vector<u8> shared_font;
19 33
20/// Signals used by APT functions 34/// Signals used by APT functions
21enum class SignalType : u32 { 35enum class SignalType : u32 {
@@ -26,7 +40,7 @@ enum class SignalType : u32 {
26}; 40};
27 41
28void Initialize(Service::Interface* self) { 42void Initialize(Service::Interface* self) {
29 u32* cmd_buff = Service::GetCommandBuffer(); 43 u32* cmd_buff = Kernel::GetCommandBuffer();
30 44
31 cmd_buff[3] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Menu"); // APT menu event handle 45 cmd_buff[3] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Menu"); // APT menu event handle
32 cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Pause"); // APT pause event handle 46 cmd_buff[4] = Kernel::CreateEvent(RESETTYPE_ONESHOT, "APT_U:Pause"); // APT pause event handle
@@ -39,11 +53,11 @@ void Initialize(Service::Interface* self) {
39 53
40 cmd_buff[1] = 0; // No error 54 cmd_buff[1] = 0; // No error
41 55
42 DEBUG_LOG(KERNEL, "called"); 56 LOG_DEBUG(Service_APT, "called");
43} 57}
44 58
45void GetLockHandle(Service::Interface* self) { 59void GetLockHandle(Service::Interface* self) {
46 u32* cmd_buff = Service::GetCommandBuffer(); 60 u32* cmd_buff = Kernel::GetCommandBuffer();
47 u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field 61 u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
48 62
49 if (0 == lock_handle) { 63 if (0 == lock_handle) {
@@ -60,22 +74,22 @@ void GetLockHandle(Service::Interface* self) {
60 cmd_buff[4] = 0; 74 cmd_buff[4] = 0;
61 75
62 cmd_buff[5] = lock_handle; 76 cmd_buff[5] = lock_handle;
63 DEBUG_LOG(KERNEL, "called handle=0x%08X", cmd_buff[5]); 77 LOG_TRACE(Service_APT, "called handle=0x%08X", cmd_buff[5]);
64} 78}
65 79
66void Enable(Service::Interface* self) { 80void Enable(Service::Interface* self) {
67 u32* cmd_buff = Service::GetCommandBuffer(); 81 u32* cmd_buff = Kernel::GetCommandBuffer();
68 u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for? 82 u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for?
69 cmd_buff[1] = 0; // No error 83 cmd_buff[1] = 0; // No error
70 WARN_LOG(KERNEL, "(STUBBED) called unk=0x%08X", unk); 84 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk);
71} 85}
72 86
73void InquireNotification(Service::Interface* self) { 87void InquireNotification(Service::Interface* self) {
74 u32* cmd_buff = Service::GetCommandBuffer(); 88 u32* cmd_buff = Kernel::GetCommandBuffer();
75 u32 app_id = cmd_buff[2]; 89 u32 app_id = cmd_buff[2];
76 cmd_buff[1] = 0; // No error 90 cmd_buff[1] = 0; // No error
77 cmd_buff[2] = static_cast<u32>(SignalType::None); // Signal type 91 cmd_buff[2] = static_cast<u32>(SignalType::None); // Signal type
78 WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X", app_id); 92 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id);
79} 93}
80 94
81/** 95/**
@@ -84,21 +98,21 @@ void InquireNotification(Service::Interface* self) {
84 * state so that this command will return an error if this command is used again if parameters were 98 * state so that this command will return an error if this command is used again if parameters were
85 * not set again. This is called when the second Initialize event is triggered. It returns a signal 99 * not set again. This is called when the second Initialize event is triggered. It returns a signal
86 * type indicating why it was triggered. 100 * type indicating why it was triggered.
87 * Inputs: 101 * Inputs:
88 * 1 : AppID 102 * 1 : AppID
89 * 2 : Parameter buffer size, max size is 0x1000 103 * 2 : Parameter buffer size, max size is 0x1000
90 * Outputs: 104 * Outputs:
91 * 1 : Result of function, 0 on success, otherwise error code 105 * 1 : Result of function, 0 on success, otherwise error code
92 * 2 : Unknown, for now assume AppID of the process which sent these parameters 106 * 2 : Unknown, for now assume AppID of the process which sent these parameters
93 * 3 : Unknown, for now assume Signal type 107 * 3 : Unknown, for now assume Signal type
94 * 4 : Actual parameter buffer size, this is <= to the the input size 108 * 4 : Actual parameter buffer size, this is <= to the the input size
95 * 5 : Value 109 * 5 : Value
96 * 6 : Handle from the source process which set the parameters, likely used for shared memory 110 * 6 : Handle from the source process which set the parameters, likely used for shared memory
97 * 7 : Size 111 * 7 : Size
98 * 8 : Output parameter buffer ptr 112 * 8 : Output parameter buffer ptr
99 */ 113 */
100void ReceiveParameter(Service::Interface* self) { 114void ReceiveParameter(Service::Interface* self) {
101 u32* cmd_buff = Service::GetCommandBuffer(); 115 u32* cmd_buff = Kernel::GetCommandBuffer();
102 u32 app_id = cmd_buff[1]; 116 u32 app_id = cmd_buff[1];
103 u32 buffer_size = cmd_buff[2]; 117 u32 buffer_size = cmd_buff[2];
104 cmd_buff[1] = 0; // No error 118 cmd_buff[1] = 0; // No error
@@ -108,28 +122,28 @@ void ReceiveParameter(Service::Interface* self) {
108 cmd_buff[5] = 0; 122 cmd_buff[5] = 0;
109 cmd_buff[6] = 0; 123 cmd_buff[6] = 0;
110 cmd_buff[7] = 0; 124 cmd_buff[7] = 0;
111 WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); 125 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
112} 126}
113 127
114/** 128/**
115 * APT_U::GlanceParameter service function. This is exactly the same as APT_U::ReceiveParameter 129 * APT_U::GlanceParameter service function. This is exactly the same as APT_U::ReceiveParameter
116 * (except for the word value prior to the output handle), except this will not clear the flag 130 * (except for the word value prior to the output handle), except this will not clear the flag
117 * (except when responseword[3]==8 || responseword[3]==9) in NS state. 131 * (except when responseword[3]==8 || responseword[3]==9) in NS state.
118 * Inputs: 132 * Inputs:
119 * 1 : AppID 133 * 1 : AppID
120 * 2 : Parameter buffer size, max size is 0x1000 134 * 2 : Parameter buffer size, max size is 0x1000
121 * Outputs: 135 * Outputs:
122 * 1 : Result of function, 0 on success, otherwise error code 136 * 1 : Result of function, 0 on success, otherwise error code
123 * 2 : Unknown, for now assume AppID of the process which sent these parameters 137 * 2 : Unknown, for now assume AppID of the process which sent these parameters
124 * 3 : Unknown, for now assume Signal type 138 * 3 : Unknown, for now assume Signal type
125 * 4 : Actual parameter buffer size, this is <= to the the input size 139 * 4 : Actual parameter buffer size, this is <= to the the input size
126 * 5 : Value 140 * 5 : Value
127 * 6 : Handle from the source process which set the parameters, likely used for shared memory 141 * 6 : Handle from the source process which set the parameters, likely used for shared memory
128 * 7 : Size 142 * 7 : Size
129 * 8 : Output parameter buffer ptr 143 * 8 : Output parameter buffer ptr
130 */ 144 */
131void GlanceParameter(Service::Interface* self) { 145void GlanceParameter(Service::Interface* self) {
132 u32* cmd_buff = Service::GetCommandBuffer(); 146 u32* cmd_buff = Kernel::GetCommandBuffer();
133 u32 app_id = cmd_buff[1]; 147 u32 app_id = cmd_buff[1];
134 u32 buffer_size = cmd_buff[2]; 148 u32 buffer_size = cmd_buff[2];
135 149
@@ -141,22 +155,22 @@ void GlanceParameter(Service::Interface* self) {
141 cmd_buff[6] = 0; 155 cmd_buff[6] = 0;
142 cmd_buff[7] = 0; 156 cmd_buff[7] = 0;
143 157
144 WARN_LOG(KERNEL, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); 158 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
145} 159}
146 160
147/** 161/**
148 * APT_U::AppletUtility service function 162 * APT_U::AppletUtility service function
149 * Inputs: 163 * Inputs:
150 * 1 : Unknown, but clearly used for something 164 * 1 : Unknown, but clearly used for something
151 * 2 : Buffer 1 size (purpose is unknown) 165 * 2 : Buffer 1 size (purpose is unknown)
152 * 3 : Buffer 2 size (purpose is unknown) 166 * 3 : Buffer 2 size (purpose is unknown)
153 * 5 : Buffer 1 address (purpose is unknown) 167 * 5 : Buffer 1 address (purpose is unknown)
154 * 65 : Buffer 2 address (purpose is unknown) 168 * 65 : Buffer 2 address (purpose is unknown)
155 * Outputs: 169 * Outputs:
156 * 1 : Result of function, 0 on success, otherwise error code 170 * 1 : Result of function, 0 on success, otherwise error code
157 */ 171 */
158void AppletUtility(Service::Interface* self) { 172void AppletUtility(Service::Interface* self) {
159 u32* cmd_buff = Service::GetCommandBuffer(); 173 u32* cmd_buff = Kernel::GetCommandBuffer();
160 174
161 // These are from 3dbrew - I'm not really sure what they're used for. 175 // These are from 3dbrew - I'm not really sure what they're used for.
162 u32 unk = cmd_buff[1]; 176 u32 unk = cmd_buff[1];
@@ -167,11 +181,39 @@ void AppletUtility(Service::Interface* self) {
167 181
168 cmd_buff[1] = 0; // No error 182 cmd_buff[1] = 0; // No error
169 183
170 WARN_LOG(KERNEL, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, " 184 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, "
171 "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size, 185 "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size,
172 buffer1_addr, buffer2_addr); 186 buffer1_addr, buffer2_addr);
173} 187}
174 188
189/**
190 * APT_U::GetSharedFont service function
191 * Outputs:
192 * 1 : Result of function, 0 on success, otherwise error code
193 * 2 : Virtual address of where shared font will be loaded in memory
194 * 4 : Handle to shared font memory
195 */
196void GetSharedFont(Service::Interface* self) {
197 LOG_TRACE(Kernel_SVC, "called");
198
199 u32* cmd_buff = Kernel::GetCommandBuffer();
200
201 if (!shared_font.empty()) {
202 // TODO(bunnei): This function shouldn't copy the shared font every time it's called.
203 // Instead, it should probably map the shared font as RO memory. We don't currently have
204 // an easy way to do this, but the copy should be sufficient for now.
205 memcpy(Memory::GetPointer(SHARED_FONT_VADDR), shared_font.data(), shared_font.size());
206
207 cmd_buff[0] = 0x00440082;
208 cmd_buff[1] = 0; // No error
209 cmd_buff[2] = SHARED_FONT_VADDR;
210 cmd_buff[4] = shared_font_mem;
211 } else {
212 cmd_buff[1] = -1; // Generic error (not really possible to verify this on hardware)
213 LOG_ERROR(Kernel_SVC, "called, but %s has not been loaded!", SHARED_FONT);
214 }
215}
216
175const Interface::FunctionInfo FunctionTable[] = { 217const Interface::FunctionInfo FunctionTable[] = {
176 {0x00010040, GetLockHandle, "GetLockHandle"}, 218 {0x00010040, GetLockHandle, "GetLockHandle"},
177 {0x00020080, Initialize, "Initialize"}, 219 {0x00020080, Initialize, "Initialize"},
@@ -240,7 +282,7 @@ const Interface::FunctionInfo FunctionTable[] = {
240 {0x00410040, nullptr, "ReceiveCaptureBufferInfo"}, 282 {0x00410040, nullptr, "ReceiveCaptureBufferInfo"},
241 {0x00420080, nullptr, "SleepSystem"}, 283 {0x00420080, nullptr, "SleepSystem"},
242 {0x00430040, nullptr, "NotifyToWait"}, 284 {0x00430040, nullptr, "NotifyToWait"},
243 {0x00440000, nullptr, "GetSharedFont"}, 285 {0x00440000, GetSharedFont, "GetSharedFont"},
244 {0x00450040, nullptr, "GetWirelessRebootInfo"}, 286 {0x00450040, nullptr, "GetWirelessRebootInfo"},
245 {0x00460104, nullptr, "Wrap"}, 287 {0x00460104, nullptr, "Wrap"},
246 {0x00470104, nullptr, "Unwrap"}, 288 {0x00470104, nullptr, "Unwrap"},
@@ -259,12 +301,33 @@ const Interface::FunctionInfo FunctionTable[] = {
259// Interface class 301// Interface class
260 302
261Interface::Interface() { 303Interface::Interface() {
262 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 304 // Load the shared system font (if available).
305 // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header
306 // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided
307 // a homebrew app to do this: https://github.com/citra-emu/3dsutils. Put the resulting file
308 // "shared_font.bin" in the Citra "sysdata" directory.
309
310 shared_font.clear();
311 std::string filepath = FileUtil::GetUserPath(D_SYSDATA_IDX) + SHARED_FONT;
312
313 FileUtil::CreateFullPath(filepath); // Create path if not already created
314 FileUtil::IOFile file(filepath, "rb");
315
316 if (file.IsOpen()) {
317 // Read shared font data
318 shared_font.resize((size_t)file.GetSize());
319 file.ReadBytes(shared_font.data(), (size_t)file.GetSize());
320
321 // Create shared font memory object
322 shared_font_mem = Kernel::CreateSharedMemory("APT_U:shared_font_mem");
323 } else {
324 LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str());
325 shared_font_mem = 0;
326 }
263 327
264 lock_handle = 0; 328 lock_handle = 0;
265}
266 329
267Interface::~Interface() { 330 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
268} 331}
269 332
270} // namespace 333} // namespace
diff --git a/src/core/hle/service/apt_u.h b/src/core/hle/service/apt_u.h
index 306730400..aad918cfc 100644
--- a/src/core/hle/service/apt_u.h
+++ b/src/core/hle/service/apt_u.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -20,15 +20,8 @@ namespace APT_U {
20/// Interface to "APT:U" service 20/// Interface to "APT:U" service
21class Interface : public Service::Interface { 21class Interface : public Service::Interface {
22public: 22public:
23
24 Interface(); 23 Interface();
25 24
26 ~Interface();
27
28 /**
29 * Gets the string port name used by CTROS for the service
30 * @return Port name of service
31 */
32 std::string GetPortName() const override { 25 std::string GetPortName() const override {
33 return "APT:U"; 26 return "APT:U";
34 } 27 }
diff --git a/src/core/hle/service/boss_u.cpp b/src/core/hle/service/boss_u.cpp
index b2ff4a756..1820ea7ad 100644
--- a/src/core/hle/service/boss_u.cpp
+++ b/src/core/hle/service/boss_u.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h" 5#include "common/log.h"
@@ -11,18 +11,15 @@
11 11
12namespace BOSS_U { 12namespace BOSS_U {
13 13
14 const Interface::FunctionInfo FunctionTable[] = { 14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00020100, nullptr, "GetStorageInfo"}, 15 {0x00020100, nullptr, "GetStorageInfo"},
16 }; 16};
17 17
18 //////////////////////////////////////////////////////////////////////////////////////////////////// 18////////////////////////////////////////////////////////////////////////////////////////////////////
19 // Interface class 19// Interface class
20
21 Interface::Interface() {
22 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
23 }
24 20
25 Interface::~Interface() { 21Interface::Interface() {
26 } 22 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
23}
27 24
28} // namespace 25} // namespace
diff --git a/src/core/hle/service/boss_u.h b/src/core/hle/service/boss_u.h
index af39b8e65..2668f2dfd 100644
--- a/src/core/hle/service/boss_u.h
+++ b/src/core/hle/service/boss_u.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -11,17 +11,13 @@
11 11
12namespace BOSS_U { 12namespace BOSS_U {
13 13
14 class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15 public: 15public:
16 Interface(); 16 Interface();
17 ~Interface(); 17
18 /** 18 std::string GetPortName() const override {
19 * Gets the string port name used by CTROS for the service 19 return "boss:U";
20 * @return Port name of service 20 }
21 */ 21};
22 std::string GetPortName() const {
23 return "boss:U";
24 }
25 };
26 22
27} // namespace 23} // namespace
diff --git a/src/core/hle/service/cecd_u.cpp b/src/core/hle/service/cecd_u.cpp
new file mode 100644
index 000000000..b7655ef0b
--- /dev/null
+++ b/src/core/hle/service/cecd_u.cpp
@@ -0,0 +1,24 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/cecd_u.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace CECD_U
11
12namespace CECD_U {
13
14// Empty arrays are illegal -- commented out until an entry is added.
15//const Interface::FunctionInfo FunctionTable[] = { };
16
17////////////////////////////////////////////////////////////////////////////////////////////////////
18// Interface class
19
20Interface::Interface() {
21 //Register(FunctionTable, ARRAY_SIZE(FunctionTable));
22}
23
24} // namespace
diff --git a/src/core/hle/service/cecd_u.h b/src/core/hle/service/cecd_u.h
new file mode 100644
index 000000000..e67564135
--- /dev/null
+++ b/src/core/hle/service/cecd_u.h
@@ -0,0 +1,23 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace CECD_U
11
12namespace CECD_U {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "cecd:u";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
new file mode 100644
index 000000000..161aa8531
--- /dev/null
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -0,0 +1,202 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include "common/log.h"
7#include "common/make_unique.h"
8#include "core/file_sys/archive_systemsavedata.h"
9#include "core/hle/service/cfg/cfg.h"
10
11namespace Service {
12namespace CFG {
13
14const u64 CFG_SAVE_ID = 0x00010017;
15const u64 CONSOLE_UNIQUE_ID = 0xDEADC0DE;
16const ConsoleModelInfo CONSOLE_MODEL = { NINTENDO_3DS_XL, { 0, 0, 0 } };
17const u8 CONSOLE_LANGUAGE = LANGUAGE_EN;
18const char CONSOLE_USERNAME[0x14] = "CITRA";
19/// This will be initialized in CFGInit, and will be used when creating the block
20UsernameBlock CONSOLE_USERNAME_BLOCK;
21/// TODO(Subv): Find out what this actually is
22const u8 SOUND_OUTPUT_MODE = 2;
23const u8 UNITED_STATES_COUNTRY_ID = 49;
24/// TODO(Subv): Find what the other bytes are
25const ConsoleCountryInfo COUNTRY_INFO = { { 0, 0, 0 }, UNITED_STATES_COUNTRY_ID };
26
27/**
28 * TODO(Subv): Find out what this actually is, these values fix some NaN uniforms in some games,
29 * for example Nintendo Zone
30 * Thanks Normmatt for providing this information
31 */
32const std::array<float, 8> STEREO_CAMERA_SETTINGS = {
33 62.0f, 289.0f, 76.80000305175781f, 46.08000183105469f,
34 10.0f, 5.0f, 55.58000183105469f, 21.56999969482422f
35};
36
37static const u32 CONFIG_SAVEFILE_SIZE = 0x8000;
38static std::array<u8, CONFIG_SAVEFILE_SIZE> cfg_config_file_buffer;
39
40static std::unique_ptr<FileSys::Archive_SystemSaveData> cfg_system_save_data;
41
42ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, u8* output) {
43 // Read the header
44 SaveFileConfig* config = reinterpret_cast<SaveFileConfig*>(cfg_config_file_buffer.data());
45
46 auto itr = std::find_if(std::begin(config->block_entries), std::end(config->block_entries),
47 [&](const SaveConfigBlockEntry& entry) {
48 return entry.block_id == block_id && entry.size == size && (entry.flags & flag);
49 });
50
51 if (itr == std::end(config->block_entries)) {
52 LOG_ERROR(Service_CFG, "Config block %u with size %u and flags %u not found", block_id, size, flag);
53 return ResultCode(-1); // TODO(Subv): Find the correct error code
54 }
55
56 // The data is located in the block header itself if the size is less than 4 bytes
57 if (itr->size <= 4)
58 memcpy(output, &itr->offset_or_data, itr->size);
59 else
60 memcpy(output, &cfg_config_file_buffer[itr->offset_or_data], itr->size);
61
62 return RESULT_SUCCESS;
63}
64
65ResultCode CreateConfigInfoBlk(u32 block_id, u16 size, u16 flags, const u8* data) {
66 SaveFileConfig* config = reinterpret_cast<SaveFileConfig*>(cfg_config_file_buffer.data());
67 if (config->total_entries >= CONFIG_FILE_MAX_BLOCK_ENTRIES)
68 return ResultCode(-1); // TODO(Subv): Find the right error code
69
70 // Insert the block header with offset 0 for now
71 config->block_entries[config->total_entries] = { block_id, 0, size, flags };
72 if (size > 4) {
73 u32 offset = config->data_entries_offset;
74 // Perform a search to locate the next offset for the new data
75 // use the offset and size of the previous block to determine the new position
76 for (int i = config->total_entries - 1; i >= 0; --i) {
77 // Ignore the blocks that don't have a separate data offset
78 if (config->block_entries[i].size > 4) {
79 offset = config->block_entries[i].offset_or_data +
80 config->block_entries[i].size;
81 break;
82 }
83 }
84
85 config->block_entries[config->total_entries].offset_or_data = offset;
86
87 // Write the data at the new offset
88 memcpy(&cfg_config_file_buffer[offset], data, size);
89 }
90 else {
91 // The offset_or_data field in the header contains the data itself if it's 4 bytes or less
92 memcpy(&config->block_entries[config->total_entries].offset_or_data, data, size);
93 }
94
95 ++config->total_entries;
96 return RESULT_SUCCESS;
97}
98
99ResultCode DeleteConfigNANDSaveFile() {
100 FileSys::Path path("config");
101 if (cfg_system_save_data->DeleteFile(path))
102 return RESULT_SUCCESS;
103 return ResultCode(-1); // TODO(Subv): Find the right error code
104}
105
106ResultCode UpdateConfigNANDSavegame() {
107 FileSys::Mode mode = {};
108 mode.write_flag = 1;
109 mode.create_flag = 1;
110 FileSys::Path path("config");
111 auto file = cfg_system_save_data->OpenFile(path, mode);
112 _assert_msg_(Service_CFG, file != nullptr, "could not open file");
113 file->Write(0, CONFIG_SAVEFILE_SIZE, 1, cfg_config_file_buffer.data());
114 return RESULT_SUCCESS;
115}
116
117ResultCode FormatConfig() {
118 ResultCode res = DeleteConfigNANDSaveFile();
119 if (!res.IsSuccess())
120 return res;
121 // Delete the old data
122 cfg_config_file_buffer.fill(0);
123 // Create the header
124 SaveFileConfig* config = reinterpret_cast<SaveFileConfig*>(cfg_config_file_buffer.data());
125 // This value is hardcoded, taken from 3dbrew, verified by hardware, it's always the same value
126 config->data_entries_offset = 0x455C;
127 // Insert the default blocks
128 res = CreateConfigInfoBlk(0x00050005, sizeof(STEREO_CAMERA_SETTINGS), 0xE,
129 reinterpret_cast<const u8*>(STEREO_CAMERA_SETTINGS.data()));
130 if (!res.IsSuccess())
131 return res;
132 res = CreateConfigInfoBlk(0x00090001, sizeof(CONSOLE_UNIQUE_ID), 0xE,
133 reinterpret_cast<const u8*>(&CONSOLE_UNIQUE_ID));
134 if (!res.IsSuccess())
135 return res;
136 res = CreateConfigInfoBlk(0x000F0004, sizeof(CONSOLE_MODEL), 0x8,
137 reinterpret_cast<const u8*>(&CONSOLE_MODEL));
138 if (!res.IsSuccess())
139 return res;
140 res = CreateConfigInfoBlk(0x000A0002, sizeof(CONSOLE_LANGUAGE), 0xA, &CONSOLE_LANGUAGE);
141 if (!res.IsSuccess())
142 return res;
143 res = CreateConfigInfoBlk(0x00070001, sizeof(SOUND_OUTPUT_MODE), 0xE, &SOUND_OUTPUT_MODE);
144 if (!res.IsSuccess())
145 return res;
146 res = CreateConfigInfoBlk(0x000B0000, sizeof(COUNTRY_INFO), 0xE,
147 reinterpret_cast<const u8*>(&COUNTRY_INFO));
148 if (!res.IsSuccess())
149 return res;
150 res = CreateConfigInfoBlk(0x000A0000, sizeof(CONSOLE_USERNAME_BLOCK), 0xE,
151 reinterpret_cast<const u8*>(&CONSOLE_USERNAME_BLOCK));
152 if (!res.IsSuccess())
153 return res;
154 // Save the buffer to the file
155 res = UpdateConfigNANDSavegame();
156 if (!res.IsSuccess())
157 return res;
158 return RESULT_SUCCESS;
159}
160
161void CFGInit() {
162 // TODO(Subv): In the future we should use the FS service to query this archive,
163 // currently it is not possible because you can only have one open archive of the same type at any time
164 std::string syssavedata_directory = FileUtil::GetUserPath(D_SYSSAVEDATA_IDX);
165 cfg_system_save_data = Common::make_unique<FileSys::Archive_SystemSaveData>(
166 syssavedata_directory, CFG_SAVE_ID);
167 if (!cfg_system_save_data->Initialize()) {
168 LOG_CRITICAL(Service_CFG, "Could not initialize SystemSaveData archive for the CFG:U service");
169 return;
170 }
171
172 // TODO(Subv): All this code should be moved to cfg:i,
173 // it's only here because we do not currently emulate the lower level code that uses that service
174 // Try to open the file in read-only mode to check its existence
175 FileSys::Mode mode = {};
176 mode.read_flag = 1;
177 FileSys::Path path("config");
178 auto file = cfg_system_save_data->OpenFile(path, mode);
179
180 // Load the config if it already exists
181 if (file != nullptr) {
182 file->Read(0, CONFIG_SAVEFILE_SIZE, cfg_config_file_buffer.data());
183 return;
184 }
185
186 // Initialize the Username block
187 // TODO(Subv): Initialize this directly in the variable when MSVC supports char16_t string literals
188 CONSOLE_USERNAME_BLOCK.ng_word = 0;
189 CONSOLE_USERNAME_BLOCK.zero = 0;
190 // Copy string to buffer and pad with zeros at the end
191 auto size = Common::UTF8ToUTF16(CONSOLE_USERNAME).copy(CONSOLE_USERNAME_BLOCK.username, 0x14);
192 std::fill(std::begin(CONSOLE_USERNAME_BLOCK.username) + size,
193 std::end(CONSOLE_USERNAME_BLOCK.username), 0);
194 FormatConfig();
195}
196
197void CFGShutdown() {
198
199}
200
201} // namespace CFG
202} // namespace Service
diff --git a/src/core/hle/service/cfg/cfg.h b/src/core/hle/service/cfg/cfg.h
new file mode 100644
index 000000000..c74527ca4
--- /dev/null
+++ b/src/core/hle/service/cfg/cfg.h
@@ -0,0 +1,144 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <array>
8#include "core/hle/result.h"
9
10namespace Service {
11namespace CFG {
12
13enum SystemModel {
14 NINTENDO_3DS = 0,
15 NINTENDO_3DS_XL = 1,
16 NEW_NINTENDO_3DS = 2,
17 NINTENDO_2DS = 3,
18 NEW_NINTENDO_3DS_XL = 4
19};
20
21enum SystemLanguage {
22 LANGUAGE_JP = 0,
23 LANGUAGE_EN = 1,
24 LANGUAGE_FR = 2,
25 LANGUAGE_DE = 3,
26 LANGUAGE_IT = 4,
27 LANGUAGE_ES = 5,
28 LANGUAGE_ZH = 6,
29 LANGUAGE_KO = 7,
30 LANGUAGE_NL = 8,
31 LANGUAGE_PT = 9,
32 LANGUAGE_RU = 10
33};
34
35/// Block header in the config savedata file
36struct SaveConfigBlockEntry {
37 u32 block_id; ///< The id of the current block
38 u32 offset_or_data; ///< This is the absolute offset to the block data if the size is greater than 4 bytes, otherwise it contains the data itself
39 u16 size; ///< The size of the block
40 u16 flags; ///< The flags of the block, possibly used for access control
41};
42
43/// The maximum number of block entries that can exist in the config file
44static const u32 CONFIG_FILE_MAX_BLOCK_ENTRIES = 1479;
45
46/**
47* The header of the config savedata file,
48* contains information about the blocks in the file
49*/
50struct SaveFileConfig {
51 u16 total_entries; ///< The total number of set entries in the config file
52 u16 data_entries_offset; ///< The offset where the data for the blocks start, this is hardcoded to 0x455C as per hardware
53 SaveConfigBlockEntry block_entries[CONFIG_FILE_MAX_BLOCK_ENTRIES]; ///< The block headers, the maximum possible value is 1479 as per hardware
54 u32 unknown; ///< This field is unknown, possibly padding, 0 has been observed in hardware
55};
56static_assert(sizeof(SaveFileConfig) == 0x455C, "The SaveFileConfig header must be exactly 0x455C bytes");
57
58struct UsernameBlock {
59 char16_t username[10]; ///< Exactly 20 bytes long, padded with zeros at the end if necessary
60 u32 zero;
61 u32 ng_word;
62};
63static_assert(sizeof(UsernameBlock) == 0x1C, "Size of UsernameBlock must be 0x1C");
64
65struct ConsoleModelInfo {
66 u8 model; ///< The console model (3DS, 2DS, etc)
67 u8 unknown[3]; ///< Unknown data
68};
69static_assert(sizeof(ConsoleModelInfo) == 4, "ConsoleModelInfo must be exactly 4 bytes");
70
71struct ConsoleCountryInfo {
72 u8 unknown[3]; ///< Unknown data
73 u8 country_code; ///< The country code of the console
74};
75static_assert(sizeof(ConsoleCountryInfo) == 4, "ConsoleCountryInfo must be exactly 4 bytes");
76
77extern const u64 CFG_SAVE_ID;
78extern const u64 CONSOLE_UNIQUE_ID;
79extern const ConsoleModelInfo CONSOLE_MODEL;
80extern const u8 CONSOLE_LANGUAGE;
81extern const char CONSOLE_USERNAME[0x14];
82/// This will be initialized in the Interface constructor, and will be used when creating the block
83extern UsernameBlock CONSOLE_USERNAME_BLOCK;
84/// TODO(Subv): Find out what this actually is
85extern const u8 SOUND_OUTPUT_MODE;
86extern const u8 UNITED_STATES_COUNTRY_ID;
87/// TODO(Subv): Find what the other bytes are
88extern const ConsoleCountryInfo COUNTRY_INFO;
89extern const std::array<float, 8> STEREO_CAMERA_SETTINGS;
90
91static_assert(sizeof(STEREO_CAMERA_SETTINGS) == 0x20, "STEREO_CAMERA_SETTINGS must be exactly 0x20 bytes");
92static_assert(sizeof(CONSOLE_UNIQUE_ID) == 8, "CONSOLE_UNIQUE_ID must be exactly 8 bytes");
93static_assert(sizeof(CONSOLE_LANGUAGE) == 1, "CONSOLE_LANGUAGE must be exactly 1 byte");
94static_assert(sizeof(SOUND_OUTPUT_MODE) == 1, "SOUND_OUTPUT_MODE must be exactly 1 byte");
95
96/**
97 * Reads a block with the specified id and flag from the Config savegame buffer
98 * and writes the output to output.
99 * The input size must match exactly the size of the requested block
100 * @param block_id The id of the block we want to read
101 * @param size The size of the block we want to read
102 * @param flag The requested block must have this flag set
103 * @param output A pointer where we will write the read data
104 * @returns ResultCode indicating the result of the operation, 0 on success
105 */
106ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, u8* output);
107
108/**
109 * Creates a block with the specified id and writes the input data to the cfg savegame buffer in memory.
110 * The config savegame file in the filesystem is not updated.
111 * @param block_id The id of the block we want to create
112 * @param size The size of the block we want to create
113 * @param flag The flags of the new block
114 * @param data A pointer containing the data we will write to the new block
115 * @returns ResultCode indicating the result of the operation, 0 on success
116 */
117ResultCode CreateConfigInfoBlk(u32 block_id, u16 size, u16 flags, const u8* data);
118
119/**
120 * Deletes the config savegame file from the filesystem, the buffer in memory is not affected
121 * @returns ResultCode indicating the result of the operation, 0 on success
122 */
123ResultCode DeleteConfigNANDSaveFile();
124
125/**
126 * Writes the config savegame memory buffer to the config savegame file in the filesystem
127 * @returns ResultCode indicating the result of the operation, 0 on success
128 */
129ResultCode UpdateConfigNANDSavegame();
130
131/**
132 * Re-creates the config savegame file in memory and the filesystem with the default blocks
133 * @returns ResultCode indicating the result of the operation, 0 on success
134 */
135ResultCode FormatConfig();
136
137/// Initialize the config service
138void CFGInit();
139
140/// Shutdown the config service
141void CFGShutdown();
142
143} // namespace CFG
144} // namespace Service
diff --git a/src/core/hle/service/cfg/cfg_i.cpp b/src/core/hle/service/cfg/cfg_i.cpp
new file mode 100644
index 000000000..7c1ee8ac3
--- /dev/null
+++ b/src/core/hle/service/cfg/cfg_i.cpp
@@ -0,0 +1,110 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/cfg/cfg.h"
8#include "core/hle/service/cfg/cfg_i.h"
9
10////////////////////////////////////////////////////////////////////////////////////////////////////
11// Namespace CFG_I
12
13namespace CFG_I {
14
15/**
16 * CFG_I::GetConfigInfoBlk8 service function
17 * This function is called by two command headers,
18 * there appears to be no difference between them according to 3dbrew
19 * Inputs:
20 * 0 : 0x04010082 / 0x08010082
21 * 1 : Size
22 * 2 : Block ID
23 * 3 : Descriptor for the output buffer
24 * 4 : Output buffer pointer
25 * Outputs:
26 * 1 : Result of function, 0 on success, otherwise error code
27 */
28static void GetConfigInfoBlk8(Service::Interface* self) {
29 u32* cmd_buffer = Kernel::GetCommandBuffer();
30 u32 size = cmd_buffer[1];
31 u32 block_id = cmd_buffer[2];
32 u8* data_pointer = Memory::GetPointer(cmd_buffer[4]);
33
34 if (data_pointer == nullptr) {
35 cmd_buffer[1] = -1; // TODO(Subv): Find the right error code
36 return;
37 }
38
39 cmd_buffer[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x8, data_pointer).raw;
40}
41
42/**
43 * CFG_I::UpdateConfigNANDSavegame service function
44 * This function is called by two command headers,
45 * there appears to be no difference between them according to 3dbrew
46 * Inputs:
47 * 0 : 0x04030000 / 0x08030000
48 * Outputs:
49 * 1 : Result of function, 0 on success, otherwise error code
50 */
51static void UpdateConfigNANDSavegame(Service::Interface* self) {
52 u32* cmd_buffer = Kernel::GetCommandBuffer();
53 cmd_buffer[1] = Service::CFG::UpdateConfigNANDSavegame().raw;
54}
55
56/**
57 * CFG_I::FormatConfig service function
58 * Inputs:
59 * 0 : 0x08060000
60 * Outputs:
61 * 1 : Result of function, 0 on success, otherwise error code
62 */
63static void FormatConfig(Service::Interface* self) {
64 u32* cmd_buffer = Kernel::GetCommandBuffer();
65 cmd_buffer[1] = Service::CFG::FormatConfig().raw;
66}
67
68const Interface::FunctionInfo FunctionTable[] = {
69 {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
70 {0x04020082, nullptr, "SetConfigInfoBlk4"},
71 {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
72 {0x04040042, nullptr, "GetLocalFriendCodeSeedData"},
73 {0x04050000, nullptr, "GetLocalFriendCodeSeed"},
74 {0x04060000, nullptr, "SecureInfoGetRegion"},
75 {0x04070000, nullptr, "SecureInfoGetByte101"},
76 {0x04080042, nullptr, "SecureInfoGetSerialNo"},
77 {0x04090000, nullptr, "UpdateConfigBlk00040003"},
78 {0x08010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
79 {0x08020082, nullptr, "SetConfigInfoBlk4"},
80 {0x08030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
81 {0x080400C2, nullptr, "CreateConfigInfoBlk"},
82 {0x08050000, nullptr, "DeleteConfigNANDSavefile"},
83 {0x08060000, FormatConfig, "FormatConfig"},
84 {0x08080000, nullptr, "UpdateConfigBlk1"},
85 {0x08090000, nullptr, "UpdateConfigBlk2"},
86 {0x080A0000, nullptr, "UpdateConfigBlk3"},
87 {0x080B0082, nullptr, "SetGetLocalFriendCodeSeedData"},
88 {0x080C0042, nullptr, "SetLocalFriendCodeSeedSignature"},
89 {0x080D0000, nullptr, "DeleteCreateNANDLocalFriendCodeSeed"},
90 {0x080E0000, nullptr, "VerifySigLocalFriendCodeSeed"},
91 {0x080F0042, nullptr, "GetLocalFriendCodeSeedData"},
92 {0x08100000, nullptr, "GetLocalFriendCodeSeed"},
93 {0x08110084, nullptr, "SetSecureInfo"},
94 {0x08120000, nullptr, "DeleteCreateNANDSecureInfo"},
95 {0x08130000, nullptr, "VerifySigSecureInfo"},
96 {0x08140042, nullptr, "SecureInfoGetData"},
97 {0x08150042, nullptr, "SecureInfoGetSignature"},
98 {0x08160000, nullptr, "SecureInfoGetRegion"},
99 {0x08170000, nullptr, "SecureInfoGetByte101"},
100 {0x08180042, nullptr, "SecureInfoGetSerialNo"},
101};
102
103////////////////////////////////////////////////////////////////////////////////////////////////////
104// Interface class
105
106Interface::Interface() {
107 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
108}
109
110} // namespace
diff --git a/src/core/hle/service/cfg_i.h b/src/core/hle/service/cfg/cfg_i.h
index fe343c968..a498dd589 100644
--- a/src/core/hle/service/cfg_i.h
+++ b/src/core/hle/service/cfg/cfg_i.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -14,11 +14,7 @@ namespace CFG_I {
14class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15public: 15public:
16 Interface(); 16 Interface();
17 ~Interface(); 17
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const override { 18 std::string GetPortName() const override {
23 return "cfg:i"; 19 return "cfg:i";
24 } 20 }
diff --git a/src/core/hle/service/cfg/cfg_u.cpp b/src/core/hle/service/cfg/cfg_u.cpp
new file mode 100644
index 000000000..03c01cf90
--- /dev/null
+++ b/src/core/hle/service/cfg/cfg_u.cpp
@@ -0,0 +1,192 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/file_util.h"
6#include "common/log.h"
7#include "common/string_util.h"
8#include "core/file_sys/archive_systemsavedata.h"
9#include "core/hle/hle.h"
10#include "core/hle/service/cfg/cfg.h"
11#include "core/hle/service/cfg/cfg_u.h"
12
13////////////////////////////////////////////////////////////////////////////////////////////////////
14// Namespace CFG_U
15
16namespace CFG_U {
17
18// TODO(Link Mauve): use a constexpr once MSVC starts supporting it.
19#define C(code) ((code)[0] | ((code)[1] << 8))
20
21static const std::array<u16, 187> country_codes = {
22 0, C("JP"), 0, 0, 0, 0, 0, 0, // 0-7
23 C("AI"), C("AG"), C("AR"), C("AW"), C("BS"), C("BB"), C("BZ"), C("BO"), // 8-15
24 C("BR"), C("VG"), C("CA"), C("KY"), C("CL"), C("CO"), C("CR"), C("DM"), // 16-23
25 C("DO"), C("EC"), C("SV"), C("GF"), C("GD"), C("GP"), C("GT"), C("GY"), // 24-31
26 C("HT"), C("HN"), C("JM"), C("MQ"), C("MX"), C("MS"), C("AN"), C("NI"), // 32-39
27 C("PA"), C("PY"), C("PE"), C("KN"), C("LC"), C("VC"), C("SR"), C("TT"), // 40-47
28 C("TC"), C("US"), C("UY"), C("VI"), C("VE"), 0, 0, 0, // 48-55
29 0, 0, 0, 0, 0, 0, 0, 0, // 56-63
30 C("AL"), C("AU"), C("AT"), C("BE"), C("BA"), C("BW"), C("BG"), C("HR"), // 64-71
31 C("CY"), C("CZ"), C("DK"), C("EE"), C("FI"), C("FR"), C("DE"), C("GR"), // 72-79
32 C("HU"), C("IS"), C("IE"), C("IT"), C("LV"), C("LS"), C("LI"), C("LT"), // 80-87
33 C("LU"), C("MK"), C("MT"), C("ME"), C("MZ"), C("NA"), C("NL"), C("NZ"), // 88-95
34 C("NO"), C("PL"), C("PT"), C("RO"), C("RU"), C("RS"), C("SK"), C("SI"), // 96-103
35 C("ZA"), C("ES"), C("SZ"), C("SE"), C("CH"), C("TR"), C("GB"), C("ZM"), // 104-111
36 C("ZW"), C("AZ"), C("MR"), C("ML"), C("NE"), C("TD"), C("SD"), C("ER"), // 112-119
37 C("DJ"), C("SO"), C("AD"), C("GI"), C("GG"), C("IM"), C("JE"), C("MC"), // 120-127
38 C("TW"), 0, 0, 0, 0, 0, 0, 0, // 128-135
39 C("KR"), 0, 0, 0, 0, 0, 0, 0, // 136-143
40 C("HK"), C("MO"), 0, 0, 0, 0, 0, 0, // 144-151
41 C("ID"), C("SG"), C("TH"), C("PH"), C("MY"), 0, 0, 0, // 152-159
42 C("CN"), 0, 0, 0, 0, 0, 0, 0, // 160-167
43 C("AE"), C("IN"), C("EG"), C("OM"), C("QA"), C("KW"), C("SA"), C("SY"), // 168-175
44 C("BH"), C("JO"), 0, 0, 0, 0, 0, 0, // 176-183
45 C("SM"), C("VA"), C("BM") // 184-186
46};
47
48#undef C
49
50/**
51 * CFG_User::GetCountryCodeString service function
52 * Inputs:
53 * 1 : Country Code ID
54 * Outputs:
55 * 1 : Result of function, 0 on success, otherwise error code
56 * 2 : Country's 2-char string
57 */
58static void GetCountryCodeString(Service::Interface* self) {
59 u32* cmd_buffer = Kernel::GetCommandBuffer();
60 u32 country_code_id = cmd_buffer[1];
61
62 if (country_code_id >= country_codes.size() || 0 == country_codes[country_code_id]) {
63 LOG_ERROR(Service_CFG, "requested country code id=%d is invalid", country_code_id);
64 cmd_buffer[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw;
65 return;
66 }
67
68 cmd_buffer[1] = 0;
69 cmd_buffer[2] = country_codes[country_code_id];
70}
71
72/**
73 * CFG_User::GetCountryCodeID service function
74 * Inputs:
75 * 1 : Country Code 2-char string
76 * Outputs:
77 * 1 : Result of function, 0 on success, otherwise error code
78 * 2 : Country Code ID
79 */
80static void GetCountryCodeID(Service::Interface* self) {
81 u32* cmd_buffer = Kernel::GetCommandBuffer();
82 u16 country_code = cmd_buffer[1];
83 u16 country_code_id = 0;
84
85 // The following algorithm will fail if the first country code isn't 0.
86 _dbg_assert_(Service_CFG, country_codes[0] == 0);
87
88 for (size_t id = 0; id < country_codes.size(); ++id) {
89 if (country_codes[id] == country_code) {
90 country_code_id = id;
91 break;
92 }
93 }
94
95 if (0 == country_code_id) {
96 LOG_ERROR(Service_CFG, "requested country code name=%c%c is invalid", country_code & 0xff, country_code >> 8);
97 cmd_buffer[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw;
98 cmd_buffer[2] = 0xFFFF;
99 return;
100 }
101
102 cmd_buffer[1] = 0;
103 cmd_buffer[2] = country_code_id;
104}
105
106/**
107 * CFG_User::GetConfigInfoBlk2 service function
108 * Inputs:
109 * 0 : 0x00010082
110 * 1 : Size
111 * 2 : Block ID
112 * 3 : Descriptor for the output buffer
113 * 4 : Output buffer pointer
114 * Outputs:
115 * 1 : Result of function, 0 on success, otherwise error code
116 */
117static void GetConfigInfoBlk2(Service::Interface* self) {
118 u32* cmd_buffer = Kernel::GetCommandBuffer();
119 u32 size = cmd_buffer[1];
120 u32 block_id = cmd_buffer[2];
121 u8* data_pointer = Memory::GetPointer(cmd_buffer[4]);
122
123 if (data_pointer == nullptr) {
124 cmd_buffer[1] = -1; // TODO(Subv): Find the right error code
125 return;
126 }
127
128 cmd_buffer[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x2, data_pointer).raw;
129}
130
131/**
132 * CFG_User::GetSystemModel service function
133 * Inputs:
134 * 0 : 0x00050000
135 * Outputs:
136 * 1 : Result of function, 0 on success, otherwise error code
137 * 2 : Model of the console
138 */
139static void GetSystemModel(Service::Interface* self) {
140 u32* cmd_buffer = Kernel::GetCommandBuffer();
141 u32 data;
142
143 // TODO(Subv): Find out the correct error codes
144 cmd_buffer[1] = Service::CFG::GetConfigInfoBlock(0x000F0004, 4, 0x8,
145 reinterpret_cast<u8*>(&data)).raw;
146 cmd_buffer[2] = data & 0xFF;
147}
148
149/**
150 * CFG_User::GetModelNintendo2DS service function
151 * Inputs:
152 * 0 : 0x00060000
153 * Outputs:
154 * 1 : Result of function, 0 on success, otherwise error code
155 * 2 : 0 if the system is a Nintendo 2DS, 1 otherwise
156 */
157static void GetModelNintendo2DS(Service::Interface* self) {
158 u32* cmd_buffer = Kernel::GetCommandBuffer();
159 u32 data;
160
161 // TODO(Subv): Find out the correct error codes
162 cmd_buffer[1] = Service::CFG::GetConfigInfoBlock(0x000F0004, 4, 0x8,
163 reinterpret_cast<u8*>(&data)).raw;
164
165 u8 model = data & 0xFF;
166 if (model == Service::CFG::NINTENDO_2DS)
167 cmd_buffer[2] = 0;
168 else
169 cmd_buffer[2] = 1;
170}
171
172const Interface::FunctionInfo FunctionTable[] = {
173 {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"},
174 {0x00020000, nullptr, "SecureInfoGetRegion"},
175 {0x00030000, nullptr, "GenHashConsoleUnique"},
176 {0x00040000, nullptr, "GetRegionCanadaUSA"},
177 {0x00050000, GetSystemModel, "GetSystemModel"},
178 {0x00060000, GetModelNintendo2DS, "GetModelNintendo2DS"},
179 {0x00070040, nullptr, "unknown"},
180 {0x00080080, nullptr, "unknown"},
181 {0x00090040, GetCountryCodeString, "GetCountryCodeString"},
182 {0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
183};
184
185////////////////////////////////////////////////////////////////////////////////////////////////////
186// Interface class
187
188Interface::Interface() {
189 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
190}
191
192} // namespace
diff --git a/src/core/hle/service/cfg_u.h b/src/core/hle/service/cfg/cfg_u.h
index 8075d19a8..9ad73f355 100644
--- a/src/core/hle/service/cfg_u.h
+++ b/src/core/hle/service/cfg/cfg_u.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -14,11 +14,7 @@ namespace CFG_U {
14class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15public: 15public:
16 Interface(); 16 Interface();
17 ~Interface(); 17
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const override { 18 std::string GetPortName() const override {
23 return "cfg:u"; 19 return "cfg:u";
24 } 20 }
diff --git a/src/core/hle/service/cfg_i.cpp b/src/core/hle/service/cfg_i.cpp
deleted file mode 100644
index 88d13d459..000000000
--- a/src/core/hle/service/cfg_i.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/cfg_i.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace CFG_I
11
12namespace CFG_I {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x04010082, nullptr, "GetConfigInfoBlk8"},
16 {0x04020082, nullptr, "GetConfigInfoBlk4"},
17 {0x04030000, nullptr, "UpdateConfigNANDSavegame"},
18 {0x04040042, nullptr, "GetLocalFriendCodeSeedData"},
19 {0x04050000, nullptr, "GetLocalFriendCodeSeed"},
20 {0x04060000, nullptr, "SecureInfoGetRegion"},
21 {0x04070000, nullptr, "SecureInfoGetByte101"},
22 {0x04080042, nullptr, "SecureInfoGetSerialNo"},
23 {0x04090000, nullptr, "UpdateConfigBlk00040003"},
24 {0x08010082, nullptr, "GetConfigInfoBlk8"},
25 {0x08020082, nullptr, "GetConfigInfoBlk4"},
26 {0x08030000, nullptr, "UpdateConfigNANDSavegame"},
27 {0x080400C2, nullptr, "CreateConfigInfoBlk"},
28 {0x08050000, nullptr, "DeleteConfigNANDSavefile"},
29 {0x08060000, nullptr, "FormatConfig"},
30 {0x08070000, nullptr, "Unknown"},
31 {0x08080000, nullptr, "UpdateConfigBlk1"},
32 {0x08090000, nullptr, "UpdateConfigBlk2"},
33 {0x080A0000, nullptr, "UpdateConfigBlk3"},
34 {0x080B0082, nullptr, "SetGetLocalFriendCodeSeedData"},
35 {0x080C0042, nullptr, "SetLocalFriendCodeSeedSignature"},
36 {0x080D0000, nullptr, "DeleteCreateNANDLocalFriendCodeSeed"},
37 {0x080E0000, nullptr, "VerifySigLocalFriendCodeSeed"},
38 {0x080F0042, nullptr, "GetLocalFriendCodeSeedData"},
39 {0x08100000, nullptr, "GetLocalFriendCodeSeed"},
40 {0x08110084, nullptr, "SetSecureInfo"},
41 {0x08120000, nullptr, "DeleteCreateNANDSecureInfo"},
42 {0x08130000, nullptr, "VerifySigSecureInfo"},
43 {0x08140042, nullptr, "SecureInfoGetData"},
44 {0x08150042, nullptr, "SecureInfoGetSignature"},
45 {0x08160000, nullptr, "SecureInfoGetRegion"},
46 {0x08170000, nullptr, "SecureInfoGetByte101"},
47 {0x08180042, nullptr, "SecureInfoGetSerialNo"},
48};
49////////////////////////////////////////////////////////////////////////////////////////////////////
50// Interface class
51
52Interface::Interface() {
53 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
54}
55
56Interface::~Interface() {
57}
58
59} // namespace
diff --git a/src/core/hle/service/cfg_u.cpp b/src/core/hle/service/cfg_u.cpp
deleted file mode 100644
index 822b0e2b8..000000000
--- a/src/core/hle/service/cfg_u.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/cfg_u.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace CFG_U
11
12namespace CFG_U {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010082, nullptr, "GetConfigInfoBlk2"},
16 {0x00020000, nullptr, "SecureInfoGetRegion"},
17 {0x00030000, nullptr, "GenHashConsoleUnique"},
18 {0x00040000, nullptr, "GetRegionCanadaUSA"},
19 {0x00050000, nullptr, "GetSystemModel"},
20 {0x00060000, nullptr, "GetModelNintendo2DS"},
21 {0x00070040, nullptr, "unknown"},
22 {0x00080080, nullptr, "unknown"},
23 {0x00090080, nullptr, "GetCountryCodeString"},
24 {0x000A0040, nullptr, "GetCountryCodeID"},
25};
26////////////////////////////////////////////////////////////////////////////////////////////////////
27// Interface class
28
29Interface::Interface() {
30 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
31}
32
33Interface::~Interface() {
34}
35
36} // namespace
diff --git a/src/core/hle/service/csnd_snd.cpp b/src/core/hle/service/csnd_snd.cpp
index 6e59a9bf3..aef8cfbca 100644
--- a/src/core/hle/service/csnd_snd.cpp
+++ b/src/core/hle/service/csnd_snd.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h" 5#include "common/log.h"
@@ -33,7 +33,4 @@ Interface::Interface() {
33 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 33 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
34} 34}
35 35
36Interface::~Interface() {
37}
38
39} // namespace 36} // namespace
diff --git a/src/core/hle/service/csnd_snd.h b/src/core/hle/service/csnd_snd.h
index 31cc85b07..a84752473 100644
--- a/src/core/hle/service/csnd_snd.h
+++ b/src/core/hle/service/csnd_snd.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -14,11 +14,7 @@ namespace CSND_SND {
14class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15public: 15public:
16 Interface(); 16 Interface();
17 ~Interface(); 17
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const override { 18 std::string GetPortName() const override {
23 return "csnd:SND"; 19 return "csnd:SND";
24 } 20 }
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index bbcf26f61..2cf4d118f 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -1,9 +1,10 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h" 5#include "common/log.h"
6#include "core/hle/hle.h" 6#include "core/hle/hle.h"
7#include "core/hle/kernel/event.h"
7#include "core/hle/service/dsp_dsp.h" 8#include "core/hle/service/dsp_dsp.h"
8 9
9//////////////////////////////////////////////////////////////////////////////////////////////////// 10////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -11,42 +12,182 @@
11 12
12namespace DSP_DSP { 13namespace DSP_DSP {
13 14
15static u32 read_pipe_count;
16static Handle semaphore_event;
17static Handle interrupt_event;
18
19/**
20 * DSP_DSP::ConvertProcessAddressFromDspDram service function
21 * Inputs:
22 * 1 : Address
23 * Outputs:
24 * 1 : Result of function, 0 on success, otherwise error code
25 * 2 : (inaddr << 1) + 0x1FF40000 (where 0x1FF00000 is the DSP RAM address)
26 */
27void ConvertProcessAddressFromDspDram(Service::Interface* self) {
28 u32* cmd_buff = Kernel::GetCommandBuffer();
29
30 u32 addr = cmd_buff[1];
31
32 cmd_buff[1] = 0; // No error
33 cmd_buff[2] = (addr << 1) + (Memory::DSP_MEMORY_VADDR + 0x40000);
34
35 LOG_WARNING(Service_DSP, "(STUBBED) called with address %u", addr);
36}
37
38/**
39 * DSP_DSP::LoadComponent service function
40 * Inputs:
41 * 1 : Size
42 * 2 : Unknown (observed only half word used)
43 * 3 : Unknown (observed only half word used)
44 * 4 : (size << 4) | 0xA
45 * 5 : Buffer address
46 * Outputs:
47 * 1 : Result of function, 0 on success, otherwise error code
48 * 2 : Component loaded, 0 on not loaded, 1 on loaded
49 */
50void LoadComponent(Service::Interface* self) {
51 u32* cmd_buff = Kernel::GetCommandBuffer();
52
53 cmd_buff[1] = 0; // No error
54 cmd_buff[2] = 1; // Pretend that we actually loaded the DSP firmware
55
56 // TODO(bunnei): Implement real DSP firmware loading
57
58 LOG_WARNING(Service_DSP, "(STUBBED) called");
59}
60
61/**
62 * DSP_DSP::GetSemaphoreEventHandle service function
63 * Outputs:
64 * 1 : Result of function, 0 on success, otherwise error code
65 * 3 : Semaphore event handle
66 */
67void GetSemaphoreEventHandle(Service::Interface* self) {
68 u32* cmd_buff = Kernel::GetCommandBuffer();
69
70 cmd_buff[1] = 0; // No error
71 cmd_buff[3] = semaphore_event; // Event handle
72
73 LOG_WARNING(Service_DSP, "(STUBBED) called");
74}
75
76/**
77 * DSP_DSP::RegisterInterruptEvents service function
78 * Inputs:
79 * 1 : Parameter 0 (purpose unknown)
80 * 2 : Parameter 1 (purpose unknown)
81 * 4 : Interrupt event handle
82 * Outputs:
83 * 1 : Result of function, 0 on success, otherwise error code
84 */
85void RegisterInterruptEvents(Service::Interface* self) {
86 u32* cmd_buff = Kernel::GetCommandBuffer();
87
88 interrupt_event = static_cast<Handle>(cmd_buff[4]);
89
90 cmd_buff[1] = 0; // No error
91
92 LOG_WARNING(Service_DSP, "(STUBBED) called");
93}
94
95/**
96 * DSP_DSP::WriteReg0x10 service function
97 * Inputs:
98 * 1 : Unknown (observed only half word used)
99 * Outputs:
100 * 1 : Result of function, 0 on success, otherwise error code
101 */
102void WriteReg0x10(Service::Interface* self) {
103 u32* cmd_buff = Kernel::GetCommandBuffer();
104
105 Kernel::SignalEvent(interrupt_event);
106
107 cmd_buff[1] = 0; // No error
108
109 LOG_WARNING(Service_DSP, "(STUBBED) called");
110}
111
112/**
113 * DSP_DSP::ReadPipeIfPossible service function
114 * Inputs:
115 * 1 : Unknown
116 * 2 : Unknown
117 * 3 : Size in bytes of read (observed only lower half word used)
118 * 0x41 : Virtual address to read from DSP pipe to in memory
119 * Outputs:
120 * 1 : Result of function, 0 on success, otherwise error code
121 * 2 : Number of bytes read from pipe
122 */
123void ReadPipeIfPossible(Service::Interface* self) {
124 u32* cmd_buff = Kernel::GetCommandBuffer();
125
126 u32 size = cmd_buff[3] & 0xFFFF;// Lower 16 bits are size
127 VAddr addr = cmd_buff[0x41];
128
129 // Canned DSP responses that games expect. These were taken from HW by 3dmoo team.
130 // TODO: Remove this hack :)
131 static const std::array<u16, 16> canned_read_pipe = {
132 0x000F, 0xBFFF, 0x9E8E, 0x8680, 0xA78E, 0x9430, 0x8400, 0x8540,
133 0x948E, 0x8710, 0x8410, 0xA90E, 0xAA0E, 0xAACE, 0xAC4E, 0xAC58
134 };
135
136 u32 initial_size = read_pipe_count;
137
138 for (unsigned offset = 0; offset < size; offset += sizeof(u16)) {
139 if (read_pipe_count < canned_read_pipe.size()) {
140 Memory::Write16(addr + offset, canned_read_pipe[read_pipe_count]);
141 read_pipe_count++;
142 } else {
143 LOG_ERROR(Service_DSP, "canned read pipe log exceeded!");
144 break;
145 }
146 }
147
148 cmd_buff[1] = 0; // No error
149 cmd_buff[2] = (read_pipe_count - initial_size) * sizeof(u16);
150
151 LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%08X, buffer=0x%08X", size, addr);
152}
153
14const Interface::FunctionInfo FunctionTable[] = { 154const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010040, nullptr, "RecvData"}, 155 {0x00010040, nullptr, "RecvData"},
16 {0x00020040, nullptr, "RecvDataIsReady"}, 156 {0x00020040, nullptr, "RecvDataIsReady"},
17 {0x00030080, nullptr, "SendData"}, 157 {0x00030080, nullptr, "SendData"},
18 {0x00040040, nullptr, "SendDataIsEmpty"}, 158 {0x00040040, nullptr, "SendDataIsEmpty"},
19 {0x00070040, nullptr, "WriteReg0x10"}, 159 {0x00070040, WriteReg0x10, "WriteReg0x10"},
20 {0x00080000, nullptr, "GetSemaphore"}, 160 {0x00080000, nullptr, "GetSemaphore"},
21 {0x00090040, nullptr, "ClearSemaphore"}, 161 {0x00090040, nullptr, "ClearSemaphore"},
22 {0x000B0000, nullptr, "CheckSemaphoreRequest"}, 162 {0x000B0000, nullptr, "CheckSemaphoreRequest"},
23 {0x000C0040, nullptr, "ConvertProcessAddressFromDspDram"}, 163 {0x000C0040, ConvertProcessAddressFromDspDram, "ConvertProcessAddressFromDspDram"},
24 {0x000D0082, nullptr, "WriteProcessPipe"}, 164 {0x000D0082, nullptr, "WriteProcessPipe"},
25 {0x001000C0, nullptr, "ReadPipeIfPossible"}, 165 {0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"},
26 {0x001100C2, nullptr, "LoadComponent"}, 166 {0x001100C2, LoadComponent, "LoadComponent"},
27 {0x00120000, nullptr, "UnloadComponent"}, 167 {0x00120000, nullptr, "UnloadComponent"},
28 {0x00130082, nullptr, "FlushDataCache"}, 168 {0x00130082, nullptr, "FlushDataCache"},
29 {0x00140082, nullptr, "InvalidateDCache"}, 169 {0x00140082, nullptr, "InvalidateDCache"},
30 {0x00150082, nullptr, "RegisterInterruptEvents"}, 170 {0x00150082, RegisterInterruptEvents, "RegisterInterruptEvents"},
31 {0x00160000, nullptr, "GetSemaphoreEventHandle"}, 171 {0x00160000, GetSemaphoreEventHandle, "GetSemaphoreEventHandle"},
32 {0x00170040, nullptr, "SetSemaphoreMask"}, 172 {0x00170040, nullptr, "SetSemaphoreMask"},
33 {0x00180040, nullptr, "GetPhysicalAddress"}, 173 {0x00180040, nullptr, "GetPhysicalAddress"},
34 {0x00190040, nullptr, "GetVirtualAddress"}, 174 {0x00190040, nullptr, "GetVirtualAddress"},
35 {0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"}, 175 {0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"},
36 {0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"}, 176 {0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"},
37 {0x001C0082, nullptr, "SetIirFilterEQ"}, 177 {0x001C0082, nullptr, "SetIirFilterEQ"},
38 {0x001F0000, nullptr, "GetHeadphoneStatus"}, 178 {0x001F0000, nullptr, "GetHeadphoneStatus"},
39 {0x00210000, nullptr, "GetIsDspOccupied"}, 179 {0x00210000, nullptr, "GetIsDspOccupied"},
40}; 180};
41 181
42//////////////////////////////////////////////////////////////////////////////////////////////////// 182////////////////////////////////////////////////////////////////////////////////////////////////////
43// Interface class 183// Interface class
44 184
45Interface::Interface() { 185Interface::Interface() {
46 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 186 semaphore_event = Kernel::CreateEvent(RESETTYPE_ONESHOT, "DSP_DSP::semaphore_event");
47} 187 interrupt_event = 0;
188 read_pipe_count = 0;
48 189
49Interface::~Interface() { 190 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
50} 191}
51 192
52} // namespace 193} // namespace
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h
index c4ce44245..0b8b64600 100644
--- a/src/core/hle/service/dsp_dsp.h
+++ b/src/core/hle/service/dsp_dsp.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -14,13 +14,9 @@ namespace DSP_DSP {
14class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15public: 15public:
16 Interface(); 16 Interface();
17 ~Interface(); 17
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const override { 18 std::string GetPortName() const override {
23 return "dsp:DSP"; 19 return "dsp::DSP";
24 } 20 }
25}; 21};
26 22
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp
index 785c351e9..8c900eabc 100644
--- a/src/core/hle/service/err_f.cpp
+++ b/src/core/hle/service/err_f.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h" 5#include "common/log.h"
@@ -11,17 +11,15 @@
11 11
12namespace ERR_F { 12namespace ERR_F {
13 13
14 const Interface::FunctionInfo FunctionTable[] = { 14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010800, nullptr, "ThrowFatalError"} 15 {0x00010800, nullptr, "ThrowFatalError"}
16 }; 16};
17 ////////////////////////////////////////////////////////////////////////////////////////////////////
18 // Interface class
19 17
20 Interface::Interface() { 18////////////////////////////////////////////////////////////////////////////////////////////////////
21 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 19// Interface class
22 }
23 20
24 Interface::~Interface() { 21Interface::Interface() {
25 } 22 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
23}
26 24
27} // namespace 25} // namespace
diff --git a/src/core/hle/service/err_f.h b/src/core/hle/service/err_f.h
index 6d7141c1b..892d8af9b 100644
--- a/src/core/hle/service/err_f.h
+++ b/src/core/hle/service/err_f.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -11,17 +11,13 @@
11 11
12namespace ERR_F { 12namespace ERR_F {
13 13
14 class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15 public: 15public:
16 Interface(); 16 Interface();
17 ~Interface(); 17
18 /** 18 std::string GetPortName() const override {
19 * Gets the string port name used by CTROS for the service 19 return "err:f";
20 * @return Port name of service 20 }
21 */ 21};
22 std::string GetPortName() const override {
23 return "err:f";
24 }
25 };
26 22
27} // namespace 23} // namespace
diff --git a/src/core/hle/service/frd_u.cpp b/src/core/hle/service/frd_u.cpp
index 58023e536..021186e57 100644
--- a/src/core/hle/service/frd_u.cpp
+++ b/src/core/hle/service/frd_u.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h" 5#include "common/log.h"
@@ -11,25 +11,23 @@
11 11
12namespace FRD_U { 12namespace FRD_U {
13 13
14 const Interface::FunctionInfo FunctionTable[] = { 14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00050000, nullptr, "GetFriendKey"}, 15 {0x00050000, nullptr, "GetFriendKey"},
16 {0x00080000, nullptr, "GetMyPresence"}, 16 {0x00080000, nullptr, "GetMyPresence"},
17 {0x00100040, nullptr, "GetPassword"}, 17 {0x00100040, nullptr, "GetPassword"},
18 {0x00190042, nullptr, "GetFriendFavoriteGame"}, 18 {0x00190042, nullptr, "GetFriendFavoriteGame"},
19 {0x001A00C4, nullptr, "GetFriendInfo"}, 19 {0x001A00C4, nullptr, "GetFriendInfo"},
20 {0x001B0080, nullptr, "IsOnFriendList"}, 20 {0x001B0080, nullptr, "IsOnFriendList"},
21 {0x001C0042, nullptr, "DecodeLocalFriendCode"}, 21 {0x001C0042, nullptr, "DecodeLocalFriendCode"},
22 {0x001D0002, nullptr, "SetCurrentlyPlayingText"}, 22 {0x001D0002, nullptr, "SetCurrentlyPlayingText"},
23 {0x00320042, nullptr, "SetClientSdkVersion"} 23 {0x00320042, nullptr, "SetClientSdkVersion"}
24 }; 24};
25 ////////////////////////////////////////////////////////////////////////////////////////////////////
26 // Interface class
27 25
28 Interface::Interface() { 26////////////////////////////////////////////////////////////////////////////////////////////////////
29 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 27// Interface class
30 }
31 28
32 Interface::~Interface() { 29Interface::Interface() {
33 } 30 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
31}
34 32
35} // namespace 33} // namespace
diff --git a/src/core/hle/service/frd_u.h b/src/core/hle/service/frd_u.h
index 4020c6664..ab8897d5b 100644
--- a/src/core/hle/service/frd_u.h
+++ b/src/core/hle/service/frd_u.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -11,17 +11,13 @@
11 11
12namespace FRD_U { 12namespace FRD_U {
13 13
14 class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15 public: 15public:
16 Interface(); 16 Interface();
17 ~Interface(); 17
18 /** 18 std::string GetPortName() const override {
19 * Gets the string port name used by CTROS for the service 19 return "frd:u";
20 * @return Port name of service 20 }
21 */ 21};
22 std::string GetPortName() const override {
23 return "frd:u";
24 }
25 };
26 22
27} // namespace 23} // namespace
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
new file mode 100644
index 000000000..487bf3aa7
--- /dev/null
+++ b/src/core/hle/service/fs/archive.cpp
@@ -0,0 +1,442 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <memory>
6#include <unordered_map>
7
8#include "common/common_types.h"
9#include "common/file_util.h"
10#include "common/make_unique.h"
11#include "common/math_util.h"
12
13#include "core/file_sys/archive_savedata.h"
14#include "core/file_sys/archive_backend.h"
15#include "core/file_sys/archive_sdmc.h"
16#include "core/file_sys/directory_backend.h"
17#include "core/hle/service/fs/archive.h"
18#include "core/hle/kernel/session.h"
19#include "core/hle/result.h"
20
21// Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map.
22// Workaroung for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970
23namespace std {
24 template <>
25 struct hash<Service::FS::ArchiveIdCode> {
26 typedef Service::FS::ArchiveIdCode argument_type;
27 typedef std::size_t result_type;
28
29 result_type operator()(const argument_type& id_code) const {
30 typedef std::underlying_type<argument_type>::type Type;
31 return std::hash<Type>()(static_cast<Type>(id_code));
32 }
33 };
34}
35
36namespace Service {
37namespace FS {
38
39// Command to access archive file
40enum class FileCommand : u32 {
41 Dummy1 = 0x000100C6,
42 Control = 0x040100C4,
43 OpenSubFile = 0x08010100,
44 Read = 0x080200C2,
45 Write = 0x08030102,
46 GetSize = 0x08040000,
47 SetSize = 0x08050080,
48 GetAttributes = 0x08060000,
49 SetAttributes = 0x08070040,
50 Close = 0x08080000,
51 Flush = 0x08090000,
52};
53
54// Command to access directory
55enum class DirectoryCommand : u32 {
56 Dummy1 = 0x000100C6,
57 Control = 0x040100C4,
58 Read = 0x08010042,
59 Close = 0x08020000,
60};
61
62class Archive {
63public:
64 Archive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code)
65 : backend(std::move(backend)), id_code(id_code) {
66 }
67
68 std::string GetName() const { return "Archive: " + backend->GetName(); }
69
70 ArchiveIdCode id_code; ///< Id code of the archive
71 std::unique_ptr<FileSys::ArchiveBackend> backend; ///< Archive backend interface
72};
73
74class File : public Kernel::Session {
75public:
76 File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path)
77 : backend(std::move(backend)), path(path) {
78 }
79
80 std::string GetName() const override { return "Path: " + path.DebugStr(); }
81
82 FileSys::Path path; ///< Path of the file
83 std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface
84
85 ResultVal<bool> SyncRequest() override {
86 u32* cmd_buff = Kernel::GetCommandBuffer();
87 FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
88 switch (cmd) {
89
90 // Read from file...
91 case FileCommand::Read:
92 {
93 u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32;
94 u32 length = cmd_buff[3];
95 u32 address = cmd_buff[5];
96 LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x",
97 GetTypeName().c_str(), GetName().c_str(), offset, length, address);
98 cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address));
99 break;
100 }
101
102 // Write to file...
103 case FileCommand::Write:
104 {
105 u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32;
106 u32 length = cmd_buff[3];
107 u32 flush = cmd_buff[4];
108 u32 address = cmd_buff[6];
109 LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
110 GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
111 cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address));
112 break;
113 }
114
115 case FileCommand::GetSize:
116 {
117 LOG_TRACE(Service_FS, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str());
118 u64 size = backend->GetSize();
119 cmd_buff[2] = (u32)size;
120 cmd_buff[3] = size >> 32;
121 break;
122 }
123
124 case FileCommand::SetSize:
125 {
126 u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
127 LOG_TRACE(Service_FS, "SetSize %s %s size=%llu",
128 GetTypeName().c_str(), GetName().c_str(), size);
129 backend->SetSize(size);
130 break;
131 }
132
133 case FileCommand::Close:
134 {
135 LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
136 backend->Close();
137 break;
138 }
139
140 case FileCommand::Flush:
141 {
142 LOG_TRACE(Service_FS, "Flush");
143 backend->Flush();
144 break;
145 }
146
147 // Unknown command...
148 default:
149 LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd);
150 ResultCode error = UnimplementedFunction(ErrorModule::FS);
151 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
152 return error;
153 }
154 cmd_buff[1] = 0; // No error
155 return MakeResult<bool>(false);
156 }
157};
158
159class Directory : public Kernel::Session {
160public:
161 Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path)
162 : backend(std::move(backend)), path(path) {
163 }
164
165 std::string GetName() const override { return "Directory: " + path.DebugStr(); }
166
167 FileSys::Path path; ///< Path of the directory
168 std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface
169
170 ResultVal<bool> SyncRequest() override {
171 u32* cmd_buff = Kernel::GetCommandBuffer();
172 DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
173 switch (cmd) {
174
175 // Read from directory...
176 case DirectoryCommand::Read:
177 {
178 u32 count = cmd_buff[1];
179 u32 address = cmd_buff[3];
180 auto entries = reinterpret_cast<FileSys::Entry*>(Memory::GetPointer(address));
181 LOG_TRACE(Service_FS, "Read %s %s: count=%d",
182 GetTypeName().c_str(), GetName().c_str(), count);
183
184 // Number of entries actually read
185 cmd_buff[2] = backend->Read(count, entries);
186 break;
187 }
188
189 case DirectoryCommand::Close:
190 {
191 LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
192 backend->Close();
193 break;
194 }
195
196 // Unknown command...
197 default:
198 LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd);
199 ResultCode error = UnimplementedFunction(ErrorModule::FS);
200 cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
201 return MakeResult<bool>(false);
202 }
203 cmd_buff[1] = 0; // No error
204 return MakeResult<bool>(false);
205 }
206};
207
208////////////////////////////////////////////////////////////////////////////////////////////////////
209
210/**
211 * Map of registered archives, identified by id code. Once an archive is registered here, it is
212 * never removed until the FS service is shut down.
213 */
214static std::unordered_map<ArchiveIdCode, std::unique_ptr<Archive>> id_code_map;
215
216/**
217 * Map of active archive handles. Values are pointers to the archives in `idcode_map`.
218 */
219static std::unordered_map<ArchiveHandle, Archive*> handle_map;
220static ArchiveHandle next_handle;
221
222static Archive* GetArchive(ArchiveHandle handle) {
223 auto itr = handle_map.find(handle);
224 return (itr == handle_map.end()) ? nullptr : itr->second;
225}
226
227ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code) {
228 LOG_TRACE(Service_FS, "Opening archive with id code 0x%08X", id_code);
229
230 auto itr = id_code_map.find(id_code);
231 if (itr == id_code_map.end()) {
232 if (id_code == ArchiveIdCode::SaveData) {
233 // When a SaveData archive is created for the first time, it is not yet formatted
234 // and the save file/directory structure expected by the game has not yet been initialized.
235 // Returning the NotFormatted error code will signal the game to provision the SaveData archive
236 // with the files and folders that it expects.
237 // The FormatSaveData service call will create the SaveData archive when it is called.
238 return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS,
239 ErrorSummary::InvalidState, ErrorLevel::Status);
240 }
241 // TODO: Verify error against hardware
242 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
243 ErrorSummary::NotFound, ErrorLevel::Permanent);
244 }
245
246 // This should never even happen in the first place with 64-bit handles,
247 while (handle_map.count(next_handle) != 0) {
248 ++next_handle;
249 }
250 handle_map.emplace(next_handle, itr->second.get());
251 return MakeResult<ArchiveHandle>(next_handle++);
252}
253
254ResultCode CloseArchive(ArchiveHandle handle) {
255 if (handle_map.erase(handle) == 0)
256 return InvalidHandle(ErrorModule::FS);
257 else
258 return RESULT_SUCCESS;
259}
260
261// TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in
262// http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22
263ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code) {
264 auto result = id_code_map.emplace(id_code, Common::make_unique<Archive>(std::move(backend), id_code));
265
266 bool inserted = result.second;
267 _dbg_assert_msg_(Service_FS, inserted, "Tried to register more than one archive with same id code");
268
269 auto& archive = result.first->second;
270 LOG_DEBUG(Service_FS, "Registered archive %s with id code 0x%08X", archive->GetName().c_str(), id_code);
271 return RESULT_SUCCESS;
272}
273
274ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) {
275 Archive* archive = GetArchive(archive_handle);
276 if (archive == nullptr)
277 return InvalidHandle(ErrorModule::FS);
278
279 std::unique_ptr<FileSys::FileBackend> backend = archive->backend->OpenFile(path, mode);
280 if (backend == nullptr) {
281 return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS,
282 ErrorSummary::NotFound, ErrorLevel::Status);
283 }
284
285 auto file = Common::make_unique<File>(std::move(backend), path);
286 // TOOD(yuriks): Fix error reporting
287 Handle handle = Kernel::g_handle_table.Create(file.release()).ValueOr(INVALID_HANDLE);
288 return MakeResult<Handle>(handle);
289}
290
291ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) {
292 Archive* archive = GetArchive(archive_handle);
293 if (archive == nullptr)
294 return InvalidHandle(ErrorModule::FS);
295
296 if (archive->backend->DeleteFile(path))
297 return RESULT_SUCCESS;
298 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
299 ErrorSummary::Canceled, ErrorLevel::Status);
300}
301
302ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path,
303 ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) {
304 Archive* src_archive = GetArchive(src_archive_handle);
305 Archive* dest_archive = GetArchive(dest_archive_handle);
306 if (src_archive == nullptr || dest_archive == nullptr)
307 return InvalidHandle(ErrorModule::FS);
308
309 if (src_archive == dest_archive) {
310 if (src_archive->backend->RenameFile(src_path, dest_path))
311 return RESULT_SUCCESS;
312 } else {
313 // TODO: Implement renaming across archives
314 return UnimplementedFunction(ErrorModule::FS);
315 }
316
317 // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't
318 // exist or similar. Verify.
319 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
320 ErrorSummary::NothingHappened, ErrorLevel::Status);
321}
322
323ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) {
324 Archive* archive = GetArchive(archive_handle);
325 if (archive == nullptr)
326 return InvalidHandle(ErrorModule::FS);
327
328 if (archive->backend->DeleteDirectory(path))
329 return RESULT_SUCCESS;
330 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
331 ErrorSummary::Canceled, ErrorLevel::Status);
332}
333
334ResultCode CreateFileInArchive(Handle archive_handle, const FileSys::Path& path, u32 file_size) {
335 Archive* archive = GetArchive(archive_handle);
336 if (archive == nullptr)
337 return InvalidHandle(ErrorModule::FS);
338
339 return archive->backend->CreateFile(path, file_size);
340}
341
342ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) {
343 Archive* archive = GetArchive(archive_handle);
344 if (archive == nullptr)
345 return InvalidHandle(ErrorModule::FS);
346
347 if (archive->backend->CreateDirectory(path))
348 return RESULT_SUCCESS;
349 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
350 ErrorSummary::Canceled, ErrorLevel::Status);
351}
352
353ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path,
354 ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) {
355 Archive* src_archive = GetArchive(src_archive_handle);
356 Archive* dest_archive = GetArchive(dest_archive_handle);
357 if (src_archive == nullptr || dest_archive == nullptr)
358 return InvalidHandle(ErrorModule::FS);
359
360 if (src_archive == dest_archive) {
361 if (src_archive->backend->RenameDirectory(src_path, dest_path))
362 return RESULT_SUCCESS;
363 } else {
364 // TODO: Implement renaming across archives
365 return UnimplementedFunction(ErrorModule::FS);
366 }
367
368 // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't
369 // exist or similar. Verify.
370 return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description
371 ErrorSummary::NothingHappened, ErrorLevel::Status);
372}
373
374/**
375 * Open a Directory from an Archive
376 * @param archive_handle Handle to an open Archive object
377 * @param path Path to the Directory inside of the Archive
378 * @return Opened Directory object
379 */
380ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) {
381 Archive* archive = GetArchive(archive_handle);
382 if (archive == nullptr)
383 return InvalidHandle(ErrorModule::FS);
384
385 std::unique_ptr<FileSys::DirectoryBackend> backend = archive->backend->OpenDirectory(path);
386 if (backend == nullptr) {
387 return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
388 ErrorSummary::NotFound, ErrorLevel::Permanent);
389 }
390
391 auto directory = Common::make_unique<Directory>(std::move(backend), path);
392 // TOOD(yuriks): Fix error reporting
393 Handle handle = Kernel::g_handle_table.Create(directory.release()).ValueOr(INVALID_HANDLE);
394 return MakeResult<Handle>(handle);
395}
396
397ResultCode FormatSaveData() {
398 // TODO(Subv): Actually wipe the savedata folder after creating or opening it
399
400 // Do not create the archive again if it already exists
401 if (id_code_map.find(ArchiveIdCode::SaveData) != id_code_map.end())
402 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the correct error code
403
404 // Create the SaveData archive
405 std::string savedata_directory = FileUtil::GetUserPath(D_SAVEDATA_IDX);
406 auto savedata_archive = Common::make_unique<FileSys::Archive_SaveData>(savedata_directory,
407 Kernel::g_program_id);
408
409 if (savedata_archive->Initialize()) {
410 CreateArchive(std::move(savedata_archive), ArchiveIdCode::SaveData);
411 return RESULT_SUCCESS;
412 } else {
413 LOG_ERROR(Service_FS, "Can't instantiate SaveData archive with path %s",
414 savedata_archive->GetMountPoint().c_str());
415 return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the proper error code
416 }
417}
418
419/// Initialize archives
420void ArchiveInit() {
421 next_handle = 1;
422
423 // TODO(Link Mauve): Add the other archive types (see here for the known types:
424 // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). Currently the only half-finished
425 // archive type is SDMC, so it is the only one getting exposed.
426
427 std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX);
428 auto sdmc_archive = Common::make_unique<FileSys::Archive_SDMC>(sdmc_directory);
429 if (sdmc_archive->Initialize())
430 CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC);
431 else
432 LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
433}
434
435/// Shutdown archives
436void ArchiveShutdown() {
437 handle_map.clear();
438 id_code_map.clear();
439}
440
441} // namespace FS
442} // namespace Service
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
new file mode 100644
index 000000000..b39bc41b6
--- /dev/null
+++ b/src/core/hle/service/fs/archive.h
@@ -0,0 +1,134 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9#include "core/file_sys/archive_backend.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/result.h"
12
13namespace Service {
14namespace FS {
15
16/// Supported archive types
17enum class ArchiveIdCode : u32 {
18 RomFS = 0x00000003,
19 SaveData = 0x00000004,
20 ExtSaveData = 0x00000006,
21 SharedExtSaveData = 0x00000007,
22 SystemSaveData = 0x00000008,
23 SDMC = 0x00000009,
24 SDMCWriteOnly = 0x0000000A,
25};
26
27typedef u64 ArchiveHandle;
28
29/**
30 * Opens an archive
31 * @param id_code IdCode of the archive to open
32 * @return Handle to the opened archive
33 */
34ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code);
35
36/**
37 * Closes an archive
38 * @param id_code IdCode of the archive to open
39 */
40ResultCode CloseArchive(ArchiveHandle handle);
41
42/**
43 * Creates an Archive
44 * @param backend File system backend interface to the archive
45 * @param id_code Id code used to access this type of archive
46 */
47ResultCode CreateArchive(std::unique_ptr<FileSys::ArchiveBackend>&& backend, ArchiveIdCode id_code);
48
49/**
50 * Open a File from an Archive
51 * @param archive_handle Handle to an open Archive object
52 * @param path Path to the File inside of the Archive
53 * @param mode Mode under which to open the File
54 * @return Handle to the opened File object
55 */
56ResultVal<Handle> OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode);
57
58/**
59 * Delete a File from an Archive
60 * @param archive_handle Handle to an open Archive object
61 * @param path Path to the File inside of the Archive
62 * @return Whether deletion succeeded
63 */
64ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);
65
66/**
67 * Rename a File between two Archives
68 * @param src_archive_handle Handle to the source Archive object
69 * @param src_path Path to the File inside of the source Archive
70 * @param dest_archive_handle Handle to the destination Archive object
71 * @param dest_path Path to the File inside of the destination Archive
72 * @return Whether rename succeeded
73 */
74ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path,
75 ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path);
76
77/**
78 * Delete a Directory from an Archive
79 * @param archive_handle Handle to an open Archive object
80 * @param path Path to the Directory inside of the Archive
81 * @return Whether deletion succeeded
82 */
83ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);
84
85/**
86 * Create a File in an Archive
87 * @param archive_handle Handle to an open Archive object
88 * @param path Path to the File inside of the Archive
89 * @param file_size The size of the new file, filled with zeroes
90 * @return File creation result code
91 */
92ResultCode CreateFileInArchive(Handle archive_handle, const FileSys::Path& path, u32 file_size);
93
94/**
95 * Create a Directory from an Archive
96 * @param archive_handle Handle to an open Archive object
97 * @param path Path to the Directory inside of the Archive
98 * @return Whether creation of directory succeeded
99 */
100ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);
101
102/**
103 * Rename a Directory between two Archives
104 * @param src_archive_handle Handle to the source Archive object
105 * @param src_path Path to the Directory inside of the source Archive
106 * @param dest_archive_handle Handle to the destination Archive object
107 * @param dest_path Path to the Directory inside of the destination Archive
108 * @return Whether rename succeeded
109 */
110ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path,
111 ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path);
112
113/**
114 * Open a Directory from an Archive
115 * @param archive_handle Handle to an open Archive object
116 * @param path Path to the Directory inside of the Archive
117 * @return Handle to the opened File object
118 */
119ResultVal<Handle> OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path);
120
121/**
122 * Creates a blank SaveData archive.
123 * @return ResultCode 0 on success or the corresponding code on error
124 */
125ResultCode FormatSaveData();
126
127/// Initialize archives
128void ArchiveInit();
129
130/// Shutdown archives
131void ArchiveShutdown();
132
133} // namespace FS
134} // namespace Service
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
new file mode 100644
index 000000000..b1a465274
--- /dev/null
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -0,0 +1,601 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/common.h"
6#include "common/file_util.h"
7#include "common/scope_exit.h"
8#include "common/string_util.h"
9#include "core/hle/result.h"
10#include "core/hle/service/fs/archive.h"
11#include "core/hle/service/fs/fs_user.h"
12#include "core/settings.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15// Namespace FS_User
16
17namespace Service {
18namespace FS {
19
20static ArchiveHandle MakeArchiveHandle(u32 low_word, u32 high_word) {
21 return (u64)low_word | ((u64)high_word << 32);
22}
23
24static void Initialize(Service::Interface* self) {
25 u32* cmd_buff = Kernel::GetCommandBuffer();
26
27 // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per
28 // http://3dbrew.org/wiki/FS:Initialize#Request
29 cmd_buff[1] = RESULT_SUCCESS.raw;
30
31 LOG_DEBUG(Service_FS, "called");
32}
33
34/**
35 * FS_User::OpenFile service function
36 * Inputs:
37 * 1 : Transaction
38 * 2 : Archive handle lower word
39 * 3 : Archive handle upper word
40 * 4 : Low path type
41 * 5 : Low path size
42 * 6 : Open flags
43 * 7 : Attributes
44 * 8 : (LowPathSize << 14) | 2
45 * 9 : Low path data pointer
46 * Outputs:
47 * 1 : Result of function, 0 on success, otherwise error code
48 * 3 : File handle
49 */
50static void OpenFile(Service::Interface* self) {
51 u32* cmd_buff = Kernel::GetCommandBuffer();
52
53 ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
54 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
55 u32 filename_size = cmd_buff[5];
56 FileSys::Mode mode; mode.hex = cmd_buff[6];
57 u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes.
58 u32 filename_ptr = cmd_buff[9];
59 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
60
61 LOG_DEBUG(Service_FS, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes);
62
63 ResultVal<Handle> handle = OpenFileFromArchive(archive_handle, file_path, mode);
64 cmd_buff[1] = handle.Code().raw;
65 if (handle.Succeeded()) {
66 cmd_buff[3] = *handle;
67 } else {
68 cmd_buff[3] = 0;
69 LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str());
70 }
71}
72
73/**
74 * FS_User::OpenFileDirectly service function
75 * Inputs:
76 * 1 : Transaction
77 * 2 : Archive ID
78 * 3 : Archive low path type
79 * 4 : Archive low path size
80 * 5 : File low path type
81 * 6 : File low path size
82 * 7 : Flags
83 * 8 : Attributes
84 * 9 : (ArchiveLowPathSize << 14) | 0x802
85 * 10 : Archive low path
86 * 11 : (FileLowPathSize << 14) | 2
87 * 12 : File low path
88 * Outputs:
89 * 1 : Result of function, 0 on success, otherwise error code
90 * 3 : File handle
91 */
92static void OpenFileDirectly(Service::Interface* self) {
93 u32* cmd_buff = Kernel::GetCommandBuffer();
94
95 auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[2]);
96 auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[3]);
97 u32 archivename_size = cmd_buff[4];
98 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[5]);
99 u32 filename_size = cmd_buff[6];
100 FileSys::Mode mode; mode.hex = cmd_buff[7];
101 u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes.
102 u32 archivename_ptr = cmd_buff[10];
103 u32 filename_ptr = cmd_buff[12];
104 FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
105 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
106
107 LOG_DEBUG(Service_FS, "archive_path=%s file_path=%s, mode=%u attributes=%d",
108 archive_path.DebugStr().c_str(), file_path.DebugStr().c_str(), mode.hex, attributes);
109
110 if (archive_path.GetType() != FileSys::Empty) {
111 LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported");
112 cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
113 cmd_buff[3] = 0;
114 return;
115 }
116
117 ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id);
118 if (archive_handle.Failed()) {
119 LOG_ERROR(Service_FS, "failed to get a handle for archive");
120 cmd_buff[1] = archive_handle.Code().raw;
121 cmd_buff[3] = 0;
122 return;
123 }
124 SCOPE_EXIT({ CloseArchive(*archive_handle); });
125
126 ResultVal<Handle> handle = OpenFileFromArchive(*archive_handle, file_path, mode);
127 cmd_buff[1] = handle.Code().raw;
128 if (handle.Succeeded()) {
129 cmd_buff[3] = *handle;
130 } else {
131 cmd_buff[3] = 0;
132 LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str());
133 }
134}
135
136/*
137 * FS_User::DeleteFile service function
138 * Inputs:
139 * 2 : Archive handle lower word
140 * 3 : Archive handle upper word
141 * 4 : File path string type
142 * 5 : File path string size
143 * 7 : File path string data
144 * Outputs:
145 * 1 : Result of function, 0 on success, otherwise error code
146 */
147static void DeleteFile(Service::Interface* self) {
148 u32* cmd_buff = Kernel::GetCommandBuffer();
149
150 ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
151 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
152 u32 filename_size = cmd_buff[5];
153 u32 filename_ptr = cmd_buff[7];
154
155 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
156
157 LOG_DEBUG(Service_FS, "type=%d size=%d data=%s",
158 filename_type, filename_size, file_path.DebugStr().c_str());
159
160 cmd_buff[1] = DeleteFileFromArchive(archive_handle, file_path).raw;
161}
162
163/*
164 * FS_User::RenameFile service function
165 * Inputs:
166 * 2 : Source archive handle lower word
167 * 3 : Source archive handle upper word
168 * 4 : Source file path type
169 * 5 : Source file path size
170 * 6 : Dest archive handle lower word
171 * 7 : Dest archive handle upper word
172 * 8 : Dest file path type
173 * 9 : Dest file path size
174 * 11: Source file path string data
175 * 13: Dest file path string
176 * Outputs:
177 * 1 : Result of function, 0 on success, otherwise error code
178 */
179static void RenameFile(Service::Interface* self) {
180 u32* cmd_buff = Kernel::GetCommandBuffer();
181
182 ArchiveHandle src_archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
183 auto src_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
184 u32 src_filename_size = cmd_buff[5];
185 ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]);;
186 auto dest_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[8]);
187 u32 dest_filename_size = cmd_buff[9];
188 u32 src_filename_ptr = cmd_buff[11];
189 u32 dest_filename_ptr = cmd_buff[13];
190
191 FileSys::Path src_file_path(src_filename_type, src_filename_size, src_filename_ptr);
192 FileSys::Path dest_file_path(dest_filename_type, dest_filename_size, dest_filename_ptr);
193
194 LOG_DEBUG(Service_FS, "src_type=%d src_size=%d src_data=%s dest_type=%d dest_size=%d dest_data=%s",
195 src_filename_type, src_filename_size, src_file_path.DebugStr().c_str(),
196 dest_filename_type, dest_filename_size, dest_file_path.DebugStr().c_str());
197
198 cmd_buff[1] = RenameFileBetweenArchives(src_archive_handle, src_file_path, dest_archive_handle, dest_file_path).raw;
199}
200
201/*
202 * FS_User::DeleteDirectory service function
203 * Inputs:
204 * 2 : Archive handle lower word
205 * 3 : Archive handle upper word
206 * 4 : Directory path string type
207 * 5 : Directory path string size
208 * 7 : Directory path string data
209 * Outputs:
210 * 1 : Result of function, 0 on success, otherwise error code
211 */
212static void DeleteDirectory(Service::Interface* self) {
213 u32* cmd_buff = Kernel::GetCommandBuffer();
214
215 ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
216 auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
217 u32 dirname_size = cmd_buff[5];
218 u32 dirname_ptr = cmd_buff[7];
219
220 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
221
222 LOG_DEBUG(Service_FS, "type=%d size=%d data=%s",
223 dirname_type, dirname_size, dir_path.DebugStr().c_str());
224
225 cmd_buff[1] = DeleteDirectoryFromArchive(archive_handle, dir_path).raw;
226}
227
228/*
229 * FS_User::CreateFile service function
230 * Inputs:
231 * 0 : Command header 0x08080202
232 * 2 : Archive handle lower word
233 * 3 : Archive handle upper word
234 * 4 : File path string type
235 * 5 : File path string size
236 * 7 : File size (filled with zeroes)
237 * 10: File path string data
238 * Outputs:
239 * 1 : Result of function, 0 on success, otherwise error code
240 */
241static void CreateFile(Service::Interface* self) {
242 u32* cmd_buff = Kernel::GetCommandBuffer();
243
244 ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
245 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
246 u32 filename_size = cmd_buff[5];
247 u32 file_size = cmd_buff[7];
248 u32 filename_ptr = cmd_buff[10];
249
250 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
251
252 LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", filename_type, filename_size, file_path.DebugStr().c_str());
253
254 cmd_buff[1] = CreateFileInArchive(archive_handle, file_path, file_size).raw;
255}
256
257/*
258 * FS_User::CreateDirectory service function
259 * Inputs:
260 * 2 : Archive handle lower word
261 * 3 : Archive handle upper word
262 * 4 : Directory path string type
263 * 5 : Directory path string size
264 * 8 : Directory path string data
265 * Outputs:
266 * 1 : Result of function, 0 on success, otherwise error code
267 */
268static void CreateDirectory(Service::Interface* self) {
269 u32* cmd_buff = Kernel::GetCommandBuffer();
270
271 ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
272 auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
273 u32 dirname_size = cmd_buff[5];
274 u32 dirname_ptr = cmd_buff[8];
275
276 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
277
278 LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str());
279
280 cmd_buff[1] = CreateDirectoryFromArchive(archive_handle, dir_path).raw;
281}
282
283/*
284 * FS_User::RenameDirectory service function
285 * Inputs:
286 * 2 : Source archive handle lower word
287 * 3 : Source archive handle upper word
288 * 4 : Source dir path type
289 * 5 : Source dir path size
290 * 6 : Dest archive handle lower word
291 * 7 : Dest archive handle upper word
292 * 8 : Dest dir path type
293 * 9 : Dest dir path size
294 * 11: Source dir path string data
295 * 13: Dest dir path string
296 * Outputs:
297 * 1 : Result of function, 0 on success, otherwise error code
298 */
299static void RenameDirectory(Service::Interface* self) {
300 u32* cmd_buff = Kernel::GetCommandBuffer();
301
302 ArchiveHandle src_archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
303 auto src_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
304 u32 src_dirname_size = cmd_buff[5];
305 ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]);
306 auto dest_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[8]);
307 u32 dest_dirname_size = cmd_buff[9];
308 u32 src_dirname_ptr = cmd_buff[11];
309 u32 dest_dirname_ptr = cmd_buff[13];
310
311 FileSys::Path src_dir_path(src_dirname_type, src_dirname_size, src_dirname_ptr);
312 FileSys::Path dest_dir_path(dest_dirname_type, dest_dirname_size, dest_dirname_ptr);
313
314 LOG_DEBUG(Service_FS, "src_type=%d src_size=%d src_data=%s dest_type=%d dest_size=%d dest_data=%s",
315 src_dirname_type, src_dirname_size, src_dir_path.DebugStr().c_str(),
316 dest_dirname_type, dest_dirname_size, dest_dir_path.DebugStr().c_str());
317
318 cmd_buff[1] = RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, dest_dir_path).raw;
319}
320
321/**
322 * FS_User::OpenDirectory service function
323 * Inputs:
324 * 1 : Archive handle low word
325 * 2 : Archive handle high word
326 * 3 : Low path type
327 * 4 : Low path size
328 * 7 : (LowPathSize << 14) | 2
329 * 8 : Low path data pointer
330 * Outputs:
331 * 1 : Result of function, 0 on success, otherwise error code
332 * 3 : Directory handle
333 */
334static void OpenDirectory(Service::Interface* self) {
335 u32* cmd_buff = Kernel::GetCommandBuffer();
336
337 ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]);
338 auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[3]);
339 u32 dirname_size = cmd_buff[4];
340 u32 dirname_ptr = cmd_buff[6];
341
342 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
343
344 LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str());
345
346 ResultVal<Handle> handle = OpenDirectoryFromArchive(archive_handle, dir_path);
347 cmd_buff[1] = handle.Code().raw;
348 if (handle.Succeeded()) {
349 cmd_buff[3] = *handle;
350 } else {
351 LOG_ERROR(Service_FS, "failed to get a handle for directory");
352 }
353}
354
355/**
356 * FS_User::OpenArchive service function
357 * Inputs:
358 * 1 : Archive ID
359 * 2 : Archive low path type
360 * 3 : Archive low path size
361 * 4 : (LowPathSize << 14) | 2
362 * 5 : Archive low path
363 * Outputs:
364 * 1 : Result of function, 0 on success, otherwise error code
365 * 2 : Archive handle lower word (unused)
366 * 3 : Archive handle upper word (same as file handle)
367 */
368static void OpenArchive(Service::Interface* self) {
369 u32* cmd_buff = Kernel::GetCommandBuffer();
370
371 auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]);
372 auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
373 u32 archivename_size = cmd_buff[3];
374 u32 archivename_ptr = cmd_buff[5];
375 FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
376
377 LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str());
378
379 if (archive_path.GetType() != FileSys::Empty) {
380 LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported");
381 cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
382 return;
383 }
384
385 ResultVal<ArchiveHandle> handle = OpenArchive(archive_id);
386 cmd_buff[1] = handle.Code().raw;
387 if (handle.Succeeded()) {
388 cmd_buff[2] = *handle & 0xFFFFFFFF;
389 cmd_buff[3] = (*handle >> 32) & 0xFFFFFFFF;
390 } else {
391 cmd_buff[2] = cmd_buff[3] = 0;
392 LOG_ERROR(Service_FS, "failed to get a handle for archive");
393 }
394}
395
396/**
397 * FS_User::CloseArchive service function
398 * Inputs:
399 * 0 : 0x080E0080
400 * 1 : Archive handle low word
401 * 2 : Archive handle high word
402 * Outputs:
403 * 0 : ??? TODO(yuriks): Verify return header
404 * 1 : Result of function, 0 on success, otherwise error code
405 */
406static void CloseArchive(Service::Interface* self) {
407 u32* cmd_buff = Kernel::GetCommandBuffer();
408
409 ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]);
410 cmd_buff[1] = CloseArchive(archive_handle).raw;
411}
412
413/*
414* FS_User::IsSdmcDetected service function
415* Outputs:
416* 1 : Result of function, 0 on success, otherwise error code
417* 2 : Whether the Sdmc could be detected
418*/
419static void IsSdmcDetected(Service::Interface* self) {
420 u32* cmd_buff = Kernel::GetCommandBuffer();
421
422 cmd_buff[1] = 0;
423 cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0;
424
425 LOG_DEBUG(Service_FS, "called");
426}
427
428/**
429 * FS_User::IsSdmcWriteable service function
430 * Outputs:
431 * 0 : Command header 0x08180000
432 * 1 : Result of function, 0 on success, otherwise error code
433 * 2 : Whether the Sdmc is currently writeable
434 */
435static void IsSdmcWriteable(Service::Interface* self) {
436 u32* cmd_buff = Kernel::GetCommandBuffer();
437
438 cmd_buff[1] = RESULT_SUCCESS.raw;
439 // If the SD isn't enabled, it can't be writeable...else, stubbed true
440 cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0;
441
442 LOG_DEBUG(Service_FS, " (STUBBED)");
443}
444
445/**
446 * FS_User::FormatSaveData service function,
447 * formats the SaveData specified by the input path.
448 * Inputs:
449 * 0 : 0x084C0242
450 * 1 : Archive ID
451 * 2 : Archive low path type
452 * 3 : Archive low path size
453 * 10 : (LowPathSize << 14) | 2
454 * 11 : Archive low path
455 * Outputs:
456 * 1 : Result of function, 0 on success, otherwise error code
457 */
458static void FormatSaveData(Service::Interface* self) {
459 // TODO(Subv): Find out what the other inputs and outputs of this function are
460 u32* cmd_buff = Kernel::GetCommandBuffer();
461 LOG_DEBUG(Service_FS, "(STUBBED)");
462
463 auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]);
464 auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
465 u32 archivename_size = cmd_buff[3];
466 u32 archivename_ptr = cmd_buff[11];
467 FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
468
469 LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str());
470
471 if (archive_id != FS::ArchiveIdCode::SaveData) {
472 // TODO(Subv): What should happen if somebody attempts to format a different archive?
473 LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", cmd_buff[1]);
474 cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
475 return;
476 }
477
478 if (archive_path.GetType() != FileSys::LowPathType::Empty) {
479 // TODO(Subv): Implement formatting the SaveData of other games
480 LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported");
481 cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
482 return;
483 }
484
485 cmd_buff[1] = FormatSaveData().raw;
486}
487
488/**
489 * FS_User::FormatThisUserSaveData service function
490 * Inputs:
491 * 0: 0x080F0180
492 * Outputs:
493 * 1 : Result of function, 0 on success, otherwise error code
494 */
495static void FormatThisUserSaveData(Service::Interface* self) {
496 u32* cmd_buff = Kernel::GetCommandBuffer();
497 LOG_DEBUG(Service_FS, "(STUBBED)");
498
499 // TODO(Subv): Find out what the inputs and outputs of this function are
500
501 cmd_buff[1] = FormatSaveData().raw;
502}
503
504const FSUserInterface::FunctionInfo FunctionTable[] = {
505 {0x000100C6, nullptr, "Dummy1"},
506 {0x040100C4, nullptr, "Control"},
507 {0x08010002, Initialize, "Initialize"},
508 {0x080201C2, OpenFile, "OpenFile"},
509 {0x08030204, OpenFileDirectly, "OpenFileDirectly"},
510 {0x08040142, DeleteFile, "DeleteFile"},
511 {0x08050244, RenameFile, "RenameFile"},
512 {0x08060142, DeleteDirectory, "DeleteDirectory"},
513 {0x08070142, nullptr, "DeleteDirectoryRecursively"},
514 {0x08080202, CreateFile, "CreateFile"},
515 {0x08090182, CreateDirectory, "CreateDirectory"},
516 {0x080A0244, RenameDirectory, "RenameDirectory"},
517 {0x080B0102, OpenDirectory, "OpenDirectory"},
518 {0x080C00C2, OpenArchive, "OpenArchive"},
519 {0x080D0144, nullptr, "ControlArchive"},
520 {0x080E0080, CloseArchive, "CloseArchive"},
521 {0x080F0180, FormatThisUserSaveData,"FormatThisUserSaveData"},
522 {0x08100200, nullptr, "CreateSystemSaveData"},
523 {0x08110040, nullptr, "DeleteSystemSaveData"},
524 {0x08120080, nullptr, "GetFreeBytes"},
525 {0x08130000, nullptr, "GetCardType"},
526 {0x08140000, nullptr, "GetSdmcArchiveResource"},
527 {0x08150000, nullptr, "GetNandArchiveResource"},
528 {0x08160000, nullptr, "GetSdmcFatfsErro"},
529 {0x08170000, IsSdmcDetected, "IsSdmcDetected"},
530 {0x08180000, IsSdmcWriteable, "IsSdmcWritable"},
531 {0x08190042, nullptr, "GetSdmcCid"},
532 {0x081A0042, nullptr, "GetNandCid"},
533 {0x081B0000, nullptr, "GetSdmcSpeedInfo"},
534 {0x081C0000, nullptr, "GetNandSpeedInfo"},
535 {0x081D0042, nullptr, "GetSdmcLog"},
536 {0x081E0042, nullptr, "GetNandLog"},
537 {0x081F0000, nullptr, "ClearSdmcLog"},
538 {0x08200000, nullptr, "ClearNandLog"},
539 {0x08210000, nullptr, "CardSlotIsInserted"},
540 {0x08220000, nullptr, "CardSlotPowerOn"},
541 {0x08230000, nullptr, "CardSlotPowerOff"},
542 {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"},
543 {0x08250040, nullptr, "CardNorDirectCommand"},
544 {0x08260080, nullptr, "CardNorDirectCommandWithAddress"},
545 {0x08270082, nullptr, "CardNorDirectRead"},
546 {0x082800C2, nullptr, "CardNorDirectReadWithAddress"},
547 {0x08290082, nullptr, "CardNorDirectWrite"},
548 {0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"},
549 {0x082B00C2, nullptr, "CardNorDirectRead_4xIO"},
550 {0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"},
551 {0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"},
552 {0x082E0040, nullptr, "GetProductInfo"},
553 {0x082F0040, nullptr, "GetProgramLaunchInfo"},
554 {0x08300182, nullptr, "CreateExtSaveData"},
555 {0x08310180, nullptr, "CreateSharedExtSaveData"},
556 {0x08320102, nullptr, "ReadExtSaveDataIcon"},
557 {0x08330082, nullptr, "EnumerateExtSaveData"},
558 {0x08340082, nullptr, "EnumerateSharedExtSaveData"},
559 {0x08350080, nullptr, "DeleteExtSaveData"},
560 {0x08360080, nullptr, "DeleteSharedExtSaveData"},
561 {0x08370040, nullptr, "SetCardSpiBaudRate"},
562 {0x08380040, nullptr, "SetCardSpiBusMode"},
563 {0x08390000, nullptr, "SendInitializeInfoTo9"},
564 {0x083A0100, nullptr, "GetSpecialContentIndex"},
565 {0x083B00C2, nullptr, "GetLegacyRomHeader"},
566 {0x083C00C2, nullptr, "GetLegacyBannerData"},
567 {0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"},
568 {0x083E00C2, nullptr, "QueryTotalQuotaSize"},
569 {0x083F00C0, nullptr, "GetExtDataBlockSize"},
570 {0x08400040, nullptr, "AbnegateAccessRight"},
571 {0x08410000, nullptr, "DeleteSdmcRoot"},
572 {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"},
573 {0x08430000, nullptr, "InitializeCtrFileSystem"},
574 {0x08440000, nullptr, "CreateSeed"},
575 {0x084500C2, nullptr, "GetFormatInfo"},
576 {0x08460102, nullptr, "GetLegacyRomHeader2"},
577 {0x08470180, nullptr, "FormatCtrCardUserSaveData"},
578 {0x08480042, nullptr, "GetSdmcCtrRootPath"},
579 {0x08490040, nullptr, "GetArchiveResource"},
580 {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"},
581 {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"},
582 {0x084C0242, FormatSaveData, "FormatSaveData"},
583 {0x084D0102, nullptr, "GetLegacySubBannerData"},
584 {0x084E0342, nullptr, "UpdateSha256Context"},
585 {0x084F0102, nullptr, "ReadSpecialFile"},
586 {0x08500040, nullptr, "GetSpecialFileSize"},
587 {0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"},
588 {0x08610042, nullptr, "InitializeWithSdkVersion"},
589 {0x08620040, nullptr, "SetPriority"},
590 {0x08630000, nullptr, "GetPriority"},
591};
592
593////////////////////////////////////////////////////////////////////////////////////////////////////
594// Interface class
595
596FSUserInterface::FSUserInterface() {
597 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
598}
599
600} // namespace FS
601} // namespace Service
diff --git a/src/core/hle/service/fs_user.h b/src/core/hle/service/fs/fs_user.h
index 005382540..2d896dd5f 100644
--- a/src/core/hle/service/fs_user.h
+++ b/src/core/hle/service/fs/fs_user.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -9,23 +9,18 @@
9//////////////////////////////////////////////////////////////////////////////////////////////////// 9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace FS_User 10// Namespace FS_User
11 11
12namespace FS_User { 12namespace Service {
13namespace FS {
13 14
14/// Interface to "fs:USER" service 15/// Interface to "fs:USER" service
15class Interface : public Service::Interface { 16class FSUserInterface : public Service::Interface {
16public: 17public:
18 FSUserInterface();
17 19
18 Interface();
19
20 ~Interface();
21
22 /**
23 * Gets the string port name used by CTROS for the service
24 * @return Port name of service
25 */
26 std::string GetPortName() const override { 20 std::string GetPortName() const override {
27 return "fs:USER"; 21 return "fs:USER";
28 } 22 }
29}; 23};
30 24
31} // namespace 25} // namespace FS
26} // namespace Service
diff --git a/src/core/hle/service/fs_user.cpp b/src/core/hle/service/fs_user.cpp
deleted file mode 100644
index 435be5b5d..000000000
--- a/src/core/hle/service/fs_user.cpp
+++ /dev/null
@@ -1,409 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/common.h"
6
7#include "common/string_util.h"
8#include "core/hle/kernel/archive.h"
9#include "core/hle/kernel/archive.h"
10#include "core/hle/result.h"
11#include "core/hle/service/fs_user.h"
12#include "core/settings.h"
13
14////////////////////////////////////////////////////////////////////////////////////////////////////
15// Namespace FS_User
16
17namespace FS_User {
18
19static void Initialize(Service::Interface* self) {
20 u32* cmd_buff = Service::GetCommandBuffer();
21
22 // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per
23 // http://3dbrew.org/wiki/FS:Initialize#Request
24 cmd_buff[1] = RESULT_SUCCESS.raw;
25
26 DEBUG_LOG(KERNEL, "called");
27}
28
29/**
30 * FS_User::OpenFile service function
31 * Inputs:
32 * 1 : Transaction
33 * 2 : Archive handle lower word
34 * 3 : Archive handle upper word
35 * 4 : Low path type
36 * 5 : Low path size
37 * 6 : Open flags
38 * 7 : Attributes
39 * 8 : (LowPathSize << 14) | 2
40 * 9 : Low path data pointer
41 * Outputs:
42 * 1 : Result of function, 0 on success, otherwise error code
43 * 3 : File handle
44 */
45static void OpenFile(Service::Interface* self) {
46 u32* cmd_buff = Service::GetCommandBuffer();
47
48 // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
49 // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
50 Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
51 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
52 u32 filename_size = cmd_buff[5];
53 FileSys::Mode mode; mode.hex = cmd_buff[6];
54 u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes.
55 u32 filename_ptr = cmd_buff[9];
56 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
57
58 DEBUG_LOG(KERNEL, "path=%s, mode=%d attrs=%d", file_path.DebugStr().c_str(), mode, attributes);
59
60 ResultVal<Handle> handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode);
61 cmd_buff[1] = handle.Code().raw;
62 if (handle.Succeeded()) {
63 cmd_buff[3] = *handle;
64 } else {
65 ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str());
66 }
67
68 DEBUG_LOG(KERNEL, "called");
69}
70
71/**
72 * FS_User::OpenFileDirectly service function
73 * Inputs:
74 * 1 : Transaction
75 * 2 : Archive ID
76 * 3 : Archive low path type
77 * 4 : Archive low path size
78 * 5 : File low path type
79 * 6 : File low path size
80 * 7 : Flags
81 * 8 : Attributes
82 * 9 : (ArchiveLowPathSize << 14) | 0x802
83 * 10 : Archive low path
84 * 11 : (FileLowPathSize << 14) | 2
85 * 12 : File low path
86 * Outputs:
87 * 1 : Result of function, 0 on success, otherwise error code
88 * 3 : File handle
89 */
90static void OpenFileDirectly(Service::Interface* self) {
91 u32* cmd_buff = Service::GetCommandBuffer();
92
93 auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[2]);
94 auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[3]);
95 u32 archivename_size = cmd_buff[4];
96 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[5]);
97 u32 filename_size = cmd_buff[6];
98 FileSys::Mode mode; mode.hex = cmd_buff[7];
99 u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes.
100 u32 archivename_ptr = cmd_buff[10];
101 u32 filename_ptr = cmd_buff[12];
102 FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
103 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
104
105 DEBUG_LOG(KERNEL, "archive_path=%s file_path=%s, mode=%d attributes=%d",
106 archive_path.DebugStr().c_str(), file_path.DebugStr().c_str(), mode, attributes);
107
108 if (archive_path.GetType() != FileSys::Empty) {
109 ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
110 cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
111 return;
112 }
113
114 // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it
115 // TODO(yuriks): Why is there all this duplicate (and seemingly useless) code up here?
116 ResultVal<Handle> archive_handle = Kernel::OpenArchive(archive_id);
117 cmd_buff[1] = archive_handle.Code().raw;
118 if (archive_handle.Failed()) {
119 ERROR_LOG(KERNEL, "failed to get a handle for archive");
120 return;
121 }
122 // cmd_buff[2] isn't used according to 3dmoo's implementation.
123 cmd_buff[3] = *archive_handle;
124
125 ResultVal<Handle> handle = Kernel::OpenFileFromArchive(*archive_handle, file_path, mode);
126 cmd_buff[1] = handle.Code().raw;
127 if (handle.Succeeded()) {
128 cmd_buff[3] = *handle;
129 } else {
130 ERROR_LOG(KERNEL, "failed to get a handle for file %s", file_path.DebugStr().c_str());
131 }
132
133 DEBUG_LOG(KERNEL, "called");
134}
135
136/*
137 * FS_User::DeleteFile service function
138 * Inputs:
139 * 2 : Archive handle lower word
140 * 3 : Archive handle upper word
141 * 4 : File path string type
142 * 5 : File path string size
143 * 7 : File path string data
144 * Outputs:
145 * 1 : Result of function, 0 on success, otherwise error code
146 */
147void DeleteFile(Service::Interface* self) {
148 u32* cmd_buff = Service::GetCommandBuffer();
149
150 // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
151 // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
152 Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
153 auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
154 u32 filename_size = cmd_buff[5];
155 u32 filename_ptr = cmd_buff[7];
156
157 FileSys::Path file_path(filename_type, filename_size, filename_ptr);
158
159 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s",
160 filename_type, filename_size, file_path.DebugStr().c_str());
161
162 cmd_buff[1] = Kernel::DeleteFileFromArchive(archive_handle, file_path);
163
164 DEBUG_LOG(KERNEL, "called");
165}
166
167/*
168 * FS_User::DeleteDirectory service function
169 * Inputs:
170 * 2 : Archive handle lower word
171 * 3 : Archive handle upper word
172 * 4 : Directory path string type
173 * 5 : Directory path string size
174 * 7 : Directory path string data
175 * Outputs:
176 * 1 : Result of function, 0 on success, otherwise error code
177 */
178void DeleteDirectory(Service::Interface* self) {
179 u32* cmd_buff = Service::GetCommandBuffer();
180
181 // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
182 // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
183 Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
184 auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
185 u32 dirname_size = cmd_buff[5];
186 u32 dirname_ptr = cmd_buff[7];
187
188 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
189
190 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s",
191 dirname_type, dirname_size, dir_path.DebugStr().c_str());
192
193 cmd_buff[1] = Kernel::DeleteDirectoryFromArchive(archive_handle, dir_path);
194
195 DEBUG_LOG(KERNEL, "called");
196}
197
198/*
199 * FS_User::CreateDirectory service function
200 * Inputs:
201 * 2 : Archive handle lower word
202 * 3 : Archive handle upper word
203 * 4 : Directory path string type
204 * 5 : Directory path string size
205 * 8 : Directory path string data
206 * Outputs:
207 * 1 : Result of function, 0 on success, otherwise error code
208 */
209static void CreateDirectory(Service::Interface* self) {
210 u32* cmd_buff = Service::GetCommandBuffer();
211
212 // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to
213 // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
214 Handle archive_handle = static_cast<Handle>(cmd_buff[3]);
215 auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
216 u32 dirname_size = cmd_buff[5];
217 u32 dirname_ptr = cmd_buff[8];
218
219 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
220
221 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str());
222
223 cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_path);
224
225 DEBUG_LOG(KERNEL, "called");
226}
227
228static void OpenDirectory(Service::Interface* self) {
229 u32* cmd_buff = Service::GetCommandBuffer();
230
231 // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to
232 // 3dmoo's or ctrulib's implementations. Triple check if it's really the case.
233 Handle archive_handle = static_cast<Handle>(cmd_buff[2]);
234 auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[3]);
235 u32 dirname_size = cmd_buff[4];
236 u32 dirname_ptr = cmd_buff[6];
237
238 FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
239
240 DEBUG_LOG(KERNEL, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str());
241
242 ResultVal<Handle> handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_path);
243 cmd_buff[1] = handle.Code().raw;
244 if (handle.Succeeded()) {
245 cmd_buff[3] = *handle;
246 } else {
247 ERROR_LOG(KERNEL, "failed to get a handle for directory");
248 }
249
250 DEBUG_LOG(KERNEL, "called");
251}
252
253/**
254 * FS_User::OpenArchive service function
255 * Inputs:
256 * 1 : Archive ID
257 * 2 : Archive low path type
258 * 3 : Archive low path size
259 * 4 : (LowPathSize << 14) | 2
260 * 5 : Archive low path
261 * Outputs:
262 * 1 : Result of function, 0 on success, otherwise error code
263 * 2 : Archive handle lower word (unused)
264 * 3 : Archive handle upper word (same as file handle)
265 */
266static void OpenArchive(Service::Interface* self) {
267 u32* cmd_buff = Service::GetCommandBuffer();
268
269 auto archive_id = static_cast<FileSys::Archive::IdCode>(cmd_buff[1]);
270 auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
271 u32 archivename_size = cmd_buff[3];
272 u32 archivename_ptr = cmd_buff[5];
273 FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
274
275 DEBUG_LOG(KERNEL, "archive_path=%s", archive_path.DebugStr().c_str());
276
277 if (archive_path.GetType() != FileSys::Empty) {
278 ERROR_LOG(KERNEL, "archive LowPath type other than empty is currently unsupported");
279 cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw;
280 return;
281 }
282
283 ResultVal<Handle> handle = Kernel::OpenArchive(archive_id);
284 cmd_buff[1] = handle.Code().raw;
285 if (handle.Succeeded()) {
286 // cmd_buff[2] isn't used according to 3dmoo's implementation.
287 cmd_buff[3] = *handle;
288 } else {
289 ERROR_LOG(KERNEL, "failed to get a handle for archive");
290 }
291
292 DEBUG_LOG(KERNEL, "called");
293}
294
295/*
296* FS_User::IsSdmcDetected service function
297* Outputs:
298* 1 : Result of function, 0 on success, otherwise error code
299* 2 : Whether the Sdmc could be detected
300*/
301static void IsSdmcDetected(Service::Interface* self) {
302 u32* cmd_buff = Service::GetCommandBuffer();
303
304 cmd_buff[1] = 0;
305 cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0;
306
307 DEBUG_LOG(KERNEL, "called");
308}
309
310const Interface::FunctionInfo FunctionTable[] = {
311 {0x000100C6, nullptr, "Dummy1"},
312 {0x040100C4, nullptr, "Control"},
313 {0x08010002, Initialize, "Initialize"},
314 {0x080201C2, OpenFile, "OpenFile"},
315 {0x08030204, OpenFileDirectly, "OpenFileDirectly"},
316 {0x08040142, DeleteFile, "DeleteFile"},
317 {0x08050244, nullptr, "RenameFile"},
318 {0x08060142, DeleteDirectory, "DeleteDirectory"},
319 {0x08070142, nullptr, "DeleteDirectoryRecursively"},
320 {0x08080202, nullptr, "CreateFile"},
321 {0x08090182, CreateDirectory, "CreateDirectory"},
322 {0x080A0244, nullptr, "RenameDirectory"},
323 {0x080B0102, OpenDirectory, "OpenDirectory"},
324 {0x080C00C2, OpenArchive, "OpenArchive"},
325 {0x080D0144, nullptr, "ControlArchive"},
326 {0x080E0080, nullptr, "CloseArchive"},
327 {0x080F0180, nullptr, "FormatThisUserSaveData"},
328 {0x08100200, nullptr, "CreateSystemSaveData"},
329 {0x08110040, nullptr, "DeleteSystemSaveData"},
330 {0x08120080, nullptr, "GetFreeBytes"},
331 {0x08130000, nullptr, "GetCardType"},
332 {0x08140000, nullptr, "GetSdmcArchiveResource"},
333 {0x08150000, nullptr, "GetNandArchiveResource"},
334 {0x08160000, nullptr, "GetSdmcFatfsErro"},
335 {0x08170000, IsSdmcDetected, "IsSdmcDetected"},
336 {0x08180000, nullptr, "IsSdmcWritable"},
337 {0x08190042, nullptr, "GetSdmcCid"},
338 {0x081A0042, nullptr, "GetNandCid"},
339 {0x081B0000, nullptr, "GetSdmcSpeedInfo"},
340 {0x081C0000, nullptr, "GetNandSpeedInfo"},
341 {0x081D0042, nullptr, "GetSdmcLog"},
342 {0x081E0042, nullptr, "GetNandLog"},
343 {0x081F0000, nullptr, "ClearSdmcLog"},
344 {0x08200000, nullptr, "ClearNandLog"},
345 {0x08210000, nullptr, "CardSlotIsInserted"},
346 {0x08220000, nullptr, "CardSlotPowerOn"},
347 {0x08230000, nullptr, "CardSlotPowerOff"},
348 {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"},
349 {0x08250040, nullptr, "CardNorDirectCommand"},
350 {0x08260080, nullptr, "CardNorDirectCommandWithAddress"},
351 {0x08270082, nullptr, "CardNorDirectRead"},
352 {0x082800C2, nullptr, "CardNorDirectReadWithAddress"},
353 {0x08290082, nullptr, "CardNorDirectWrite"},
354 {0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"},
355 {0x082B00C2, nullptr, "CardNorDirectRead_4xIO"},
356 {0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"},
357 {0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"},
358 {0x082E0040, nullptr, "GetProductInfo"},
359 {0x082F0040, nullptr, "GetProgramLaunchInfo"},
360 {0x08300182, nullptr, "CreateExtSaveData"},
361 {0x08310180, nullptr, "CreateSharedExtSaveData"},
362 {0x08320102, nullptr, "ReadExtSaveDataIcon"},
363 {0x08330082, nullptr, "EnumerateExtSaveData"},
364 {0x08340082, nullptr, "EnumerateSharedExtSaveData"},
365 {0x08350080, nullptr, "DeleteExtSaveData"},
366 {0x08360080, nullptr, "DeleteSharedExtSaveData"},
367 {0x08370040, nullptr, "SetCardSpiBaudRate"},
368 {0x08380040, nullptr, "SetCardSpiBusMode"},
369 {0x08390000, nullptr, "SendInitializeInfoTo9"},
370 {0x083A0100, nullptr, "GetSpecialContentIndex"},
371 {0x083B00C2, nullptr, "GetLegacyRomHeader"},
372 {0x083C00C2, nullptr, "GetLegacyBannerData"},
373 {0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"},
374 {0x083E00C2, nullptr, "QueryTotalQuotaSize"},
375 {0x083F00C0, nullptr, "GetExtDataBlockSize"},
376 {0x08400040, nullptr, "AbnegateAccessRight"},
377 {0x08410000, nullptr, "DeleteSdmcRoot"},
378 {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"},
379 {0x08430000, nullptr, "InitializeCtrFileSystem"},
380 {0x08440000, nullptr, "CreateSeed"},
381 {0x084500C2, nullptr, "GetFormatInfo"},
382 {0x08460102, nullptr, "GetLegacyRomHeader2"},
383 {0x08470180, nullptr, "FormatCtrCardUserSaveData"},
384 {0x08480042, nullptr, "GetSdmcCtrRootPath"},
385 {0x08490040, nullptr, "GetArchiveResource"},
386 {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"},
387 {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"},
388 {0x084C0242, nullptr, "FormatSaveData"},
389 {0x084D0102, nullptr, "GetLegacySubBannerData"},
390 {0x084E0342, nullptr, "UpdateSha256Context"},
391 {0x084F0102, nullptr, "ReadSpecialFile"},
392 {0x08500040, nullptr, "GetSpecialFileSize"},
393 {0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"},
394 {0x08610042, nullptr, "InitializeWithSdkVersion"},
395 {0x08620040, nullptr, "SetPriority"},
396 {0x08630000, nullptr, "GetPriority"},
397};
398
399////////////////////////////////////////////////////////////////////////////////////////////////////
400// Interface class
401
402Interface::Interface() {
403 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
404}
405
406Interface::~Interface() {
407}
408
409} // namespace
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index de1bd3f61..0127d4ee5 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5 5
@@ -33,7 +33,7 @@ static inline u8* GetCommandBuffer(u32 thread_id) {
33} 33}
34 34
35static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { 35static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) {
36 _dbg_assert_msg_(GSP, screen_index < 2, "Invalid screen index"); 36 _dbg_assert_msg_(Service_GSP, screen_index < 2, "Invalid screen index");
37 37
38 // For each thread there are two FrameBufferUpdate fields 38 // For each thread there are two FrameBufferUpdate fields
39 u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate); 39 u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate);
@@ -50,14 +50,14 @@ static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
50static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { 50static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
51 // TODO: Return proper error codes 51 // TODO: Return proper error codes
52 if (base_address + size_in_bytes >= 0x420000) { 52 if (base_address + size_in_bytes >= 0x420000) {
53 ERROR_LOG(GPU, "Write address out of range! (address=0x%08x, size=0x%08x)", 53 LOG_ERROR(Service_GSP, "Write address out of range! (address=0x%08x, size=0x%08x)",
54 base_address, size_in_bytes); 54 base_address, size_in_bytes);
55 return; 55 return;
56 } 56 }
57 57
58 // size should be word-aligned 58 // size should be word-aligned
59 if ((size_in_bytes % 4) != 0) { 59 if ((size_in_bytes % 4) != 0) {
60 ERROR_LOG(GPU, "Invalid size 0x%08x", size_in_bytes); 60 LOG_ERROR(Service_GSP, "Invalid size 0x%08x", size_in_bytes);
61 return; 61 return;
62 } 62 }
63 63
@@ -72,7 +72,7 @@ static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
72 72
73/// Write a GSP GPU hardware register 73/// Write a GSP GPU hardware register
74static void WriteHWRegs(Service::Interface* self) { 74static void WriteHWRegs(Service::Interface* self) {
75 u32* cmd_buff = Service::GetCommandBuffer(); 75 u32* cmd_buff = Kernel::GetCommandBuffer();
76 u32 reg_addr = cmd_buff[1]; 76 u32 reg_addr = cmd_buff[1];
77 u32 size = cmd_buff[2]; 77 u32 size = cmd_buff[2];
78 78
@@ -83,19 +83,19 @@ static void WriteHWRegs(Service::Interface* self) {
83 83
84/// Read a GSP GPU hardware register 84/// Read a GSP GPU hardware register
85static void ReadHWRegs(Service::Interface* self) { 85static void ReadHWRegs(Service::Interface* self) {
86 u32* cmd_buff = Service::GetCommandBuffer(); 86 u32* cmd_buff = Kernel::GetCommandBuffer();
87 u32 reg_addr = cmd_buff[1]; 87 u32 reg_addr = cmd_buff[1];
88 u32 size = cmd_buff[2]; 88 u32 size = cmd_buff[2];
89 89
90 // TODO: Return proper error codes 90 // TODO: Return proper error codes
91 if (reg_addr + size >= 0x420000) { 91 if (reg_addr + size >= 0x420000) {
92 ERROR_LOG(GPU, "Read address out of range! (address=0x%08x, size=0x%08x)", reg_addr, size); 92 LOG_ERROR(Service_GSP, "Read address out of range! (address=0x%08x, size=0x%08x)", reg_addr, size);
93 return; 93 return;
94 } 94 }
95 95
96 // size should be word-aligned 96 // size should be word-aligned
97 if ((size % 4) != 0) { 97 if ((size % 4) != 0) {
98 ERROR_LOG(GPU, "Invalid size 0x%08x", size); 98 LOG_ERROR(Service_GSP, "Invalid size 0x%08x", size);
99 return; 99 return;
100 } 100 }
101 101
@@ -136,7 +136,7 @@ static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
136 * 1: Result code 136 * 1: Result code
137 */ 137 */
138static void SetBufferSwap(Service::Interface* self) { 138static void SetBufferSwap(Service::Interface* self) {
139 u32* cmd_buff = Service::GetCommandBuffer(); 139 u32* cmd_buff = Kernel::GetCommandBuffer();
140 u32 screen_id = cmd_buff[1]; 140 u32 screen_id = cmd_buff[1];
141 FrameBufferInfo* fb_info = (FrameBufferInfo*)&cmd_buff[2]; 141 FrameBufferInfo* fb_info = (FrameBufferInfo*)&cmd_buff[2];
142 SetBufferSwap(screen_id, *fb_info); 142 SetBufferSwap(screen_id, *fb_info);
@@ -145,6 +145,30 @@ static void SetBufferSwap(Service::Interface* self) {
145} 145}
146 146
147/** 147/**
148 * GSP_GPU::FlushDataCache service function
149 *
150 * This Function is a no-op, We aren't emulating the CPU cache any time soon.
151 *
152 * Inputs:
153 * 1 : Address
154 * 2 : Size
155 * 3 : Value 0, some descriptor for the KProcess Handle
156 * 4 : KProcess handle
157 * Outputs:
158 * 1 : Result of function, 0 on success, otherwise error code
159 */
160static void FlushDataCache(Service::Interface* self) {
161 u32* cmd_buff = Kernel::GetCommandBuffer();
162 u32 address = cmd_buff[1];
163 u32 size = cmd_buff[2];
164 u32 process = cmd_buff[4];
165
166 // TODO(purpasmart96): Verify return header on HW
167
168 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
169}
170
171/**
148 * GSP_GPU::RegisterInterruptRelayQueue service function 172 * GSP_GPU::RegisterInterruptRelayQueue service function
149 * Inputs: 173 * Inputs:
150 * 1 : "Flags" field, purpose is unknown 174 * 1 : "Flags" field, purpose is unknown
@@ -155,14 +179,15 @@ static void SetBufferSwap(Service::Interface* self) {
155 * 4 : Handle to GSP shared memory 179 * 4 : Handle to GSP shared memory
156 */ 180 */
157static void RegisterInterruptRelayQueue(Service::Interface* self) { 181static void RegisterInterruptRelayQueue(Service::Interface* self) {
158 u32* cmd_buff = Service::GetCommandBuffer(); 182 u32* cmd_buff = Kernel::GetCommandBuffer();
159 u32 flags = cmd_buff[1]; 183 u32 flags = cmd_buff[1];
160 g_interrupt_event = cmd_buff[3]; 184 g_interrupt_event = cmd_buff[3];
161 g_shared_memory = Kernel::CreateSharedMemory("GSPSharedMem"); 185 g_shared_memory = Kernel::CreateSharedMemory("GSPSharedMem");
162 186
163 _assert_msg_(GSP, (g_interrupt_event != 0), "handle is not valid!"); 187 _assert_msg_(GSP, (g_interrupt_event != 0), "handle is not valid!");
164 188
165 cmd_buff[2] = g_thread_id++; // ThreadID 189 cmd_buff[1] = 0x2A07; // Value verified by 3dmoo team, purpose unknown, but needed for GSP init
190 cmd_buff[2] = g_thread_id++; // Thread ID
166 cmd_buff[4] = g_shared_memory; // GSP shared memory 191 cmd_buff[4] = g_shared_memory; // GSP shared memory
167 192
168 Kernel::SignalEvent(g_interrupt_event); // TODO(bunnei): Is this correct? 193 Kernel::SignalEvent(g_interrupt_event); // TODO(bunnei): Is this correct?
@@ -172,14 +197,15 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
172 * Signals that the specified interrupt type has occurred to userland code 197 * Signals that the specified interrupt type has occurred to userland code
173 * @param interrupt_id ID of interrupt that is being signalled 198 * @param interrupt_id ID of interrupt that is being signalled
174 * @todo This should probably take a thread_id parameter and only signal this thread? 199 * @todo This should probably take a thread_id parameter and only signal this thread?
200 * @todo This probably does not belong in the GSP module, instead move to video_core
175 */ 201 */
176void SignalInterrupt(InterruptId interrupt_id) { 202void SignalInterrupt(InterruptId interrupt_id) {
177 if (0 == g_interrupt_event) { 203 if (0 == g_interrupt_event) {
178 WARN_LOG(GSP, "cannot synchronize until GSP event has been created!"); 204 LOG_WARNING(Service_GSP, "cannot synchronize until GSP event has been created!");
179 return; 205 return;
180 } 206 }
181 if (0 == g_shared_memory) { 207 if (0 == g_shared_memory) {
182 WARN_LOG(GSP, "cannot synchronize until GSP shared memory has been created!"); 208 LOG_WARNING(Service_GSP, "cannot synchronize until GSP shared memory has been created!");
183 return; 209 return;
184 } 210 }
185 for (int thread_id = 0; thread_id < 0x4; ++thread_id) { 211 for (int thread_id = 0; thread_id < 0x4; ++thread_id) {
@@ -210,6 +236,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
210 memcpy(Memory::GetPointer(command.dma_request.dest_address), 236 memcpy(Memory::GetPointer(command.dma_request.dest_address),
211 Memory::GetPointer(command.dma_request.source_address), 237 Memory::GetPointer(command.dma_request.source_address),
212 command.dma_request.size); 238 command.dma_request.size);
239 SignalInterrupt(InterruptId::DMA);
213 break; 240 break;
214 241
215 // ctrulib homebrew sends all relevant command list data with this command, 242 // ctrulib homebrew sends all relevant command list data with this command,
@@ -218,13 +245,13 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
218 case CommandId::SET_COMMAND_LIST_LAST: 245 case CommandId::SET_COMMAND_LIST_LAST:
219 { 246 {
220 auto& params = command.set_command_list_last; 247 auto& params = command.set_command_list_last;
248
221 WriteGPURegister(GPU_REG_INDEX(command_processor_config.address), Memory::VirtualToPhysicalAddress(params.address) >> 3); 249 WriteGPURegister(GPU_REG_INDEX(command_processor_config.address), Memory::VirtualToPhysicalAddress(params.address) >> 3);
222 WriteGPURegister(GPU_REG_INDEX(command_processor_config.size), params.size >> 3); 250 WriteGPURegister(GPU_REG_INDEX(command_processor_config.size), params.size);
223 251
224 // TODO: Not sure if we are supposed to always write this .. seems to trigger processing though 252 // TODO: Not sure if we are supposed to always write this .. seems to trigger processing though
225 WriteGPURegister(GPU_REG_INDEX(command_processor_config.trigger), 1); 253 WriteGPURegister(GPU_REG_INDEX(command_processor_config.trigger), 1);
226 254
227 SignalInterrupt(InterruptId::P3D);
228 break; 255 break;
229 } 256 }
230 257
@@ -242,6 +269,8 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
242 WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].address_end), Memory::VirtualToPhysicalAddress(params.end2) >> 3); 269 WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].address_end), Memory::VirtualToPhysicalAddress(params.end2) >> 3);
243 WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].size), params.end2 - params.start2); 270 WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].size), params.end2 - params.start2);
244 WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].value), params.value2); 271 WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].value), params.value2);
272
273 SignalInterrupt(InterruptId::PSC0);
245 break; 274 break;
246 } 275 }
247 276
@@ -255,14 +284,9 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
255 WriteGPURegister(GPU_REG_INDEX(display_transfer_config.flags), params.flags); 284 WriteGPURegister(GPU_REG_INDEX(display_transfer_config.flags), params.flags);
256 WriteGPURegister(GPU_REG_INDEX(display_transfer_config.trigger), 1); 285 WriteGPURegister(GPU_REG_INDEX(display_transfer_config.trigger), 1);
257 286
258 // TODO(bunnei): Signalling all of these interrupts here is totally wrong, but it seems to 287 // TODO(bunnei): Determine if these interrupts should be signalled here.
259 // work well enough for running demos. Need to figure out how these all work and trigger
260 // them correctly.
261 SignalInterrupt(InterruptId::PSC0);
262 SignalInterrupt(InterruptId::PSC1); 288 SignalInterrupt(InterruptId::PSC1);
263 SignalInterrupt(InterruptId::PPF); 289 SignalInterrupt(InterruptId::PPF);
264 SignalInterrupt(InterruptId::P3D);
265 SignalInterrupt(InterruptId::DMA);
266 290
267 // Update framebuffer information if requested 291 // Update framebuffer information if requested
268 for (int screen_id = 0; screen_id < 2; ++screen_id) { 292 for (int screen_id = 0; screen_id < 2; ++screen_id) {
@@ -298,13 +322,15 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
298 } 322 }
299 323
300 default: 324 default:
301 ERROR_LOG(GSP, "unknown command 0x%08X", (int)command.id.Value()); 325 LOG_ERROR(Service_GSP, "unknown command 0x%08X", (int)command.id.Value());
302 } 326 }
303} 327}
304 328
305/// This triggers handling of the GX command written to the command buffer in shared memory. 329/// This triggers handling of the GX command written to the command buffer in shared memory.
306static void TriggerCmdReqQueue(Service::Interface* self) { 330static void TriggerCmdReqQueue(Service::Interface* self) {
307 331
332 LOG_TRACE(Service_GSP, "called");
333
308 // Iterate through each thread's command queue... 334 // Iterate through each thread's command queue...
309 for (unsigned thread_id = 0; thread_id < 0x4; ++thread_id) { 335 for (unsigned thread_id = 0; thread_id < 0x4; ++thread_id) {
310 CommandBuffer* command_buffer = (CommandBuffer*)GetCommandBuffer(thread_id); 336 CommandBuffer* command_buffer = (CommandBuffer*)GetCommandBuffer(thread_id);
@@ -320,6 +346,9 @@ static void TriggerCmdReqQueue(Service::Interface* self) {
320 command_buffer->number_commands = command_buffer->number_commands - 1; 346 command_buffer->number_commands = command_buffer->number_commands - 1;
321 } 347 }
322 } 348 }
349
350 u32* cmd_buff = Kernel::GetCommandBuffer();
351 cmd_buff[1] = 0; // No error
323} 352}
324 353
325const Interface::FunctionInfo FunctionTable[] = { 354const Interface::FunctionInfo FunctionTable[] = {
@@ -330,7 +359,7 @@ const Interface::FunctionInfo FunctionTable[] = {
330 {0x00050200, SetBufferSwap, "SetBufferSwap"}, 359 {0x00050200, SetBufferSwap, "SetBufferSwap"},
331 {0x00060082, nullptr, "SetCommandList"}, 360 {0x00060082, nullptr, "SetCommandList"},
332 {0x000700C2, nullptr, "RequestDma"}, 361 {0x000700C2, nullptr, "RequestDma"},
333 {0x00080082, nullptr, "FlushDataCache"}, 362 {0x00080082, FlushDataCache, "FlushDataCache"},
334 {0x00090082, nullptr, "InvalidateDataCache"}, 363 {0x00090082, nullptr, "InvalidateDataCache"},
335 {0x000A0044, nullptr, "RegisterInterruptEvents"}, 364 {0x000A0044, nullptr, "RegisterInterruptEvents"},
336 {0x000B0040, nullptr, "SetLcdForceBlack"}, 365 {0x000B0040, nullptr, "SetLcdForceBlack"},
@@ -367,7 +396,4 @@ Interface::Interface() {
367 g_thread_id = 1; 396 g_thread_id = 1;
368} 397}
369 398
370Interface::~Interface() {
371}
372
373} // namespace 399} // namespace
diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h
index 177ce8da6..932b6170f 100644
--- a/src/core/hle/service/gsp_gpu.h
+++ b/src/core/hle/service/gsp_gpu.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -158,19 +158,11 @@ static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrec
158/// Interface to "srv:" service 158/// Interface to "srv:" service
159class Interface : public Service::Interface { 159class Interface : public Service::Interface {
160public: 160public:
161
162 Interface(); 161 Interface();
163 162
164 ~Interface();
165
166 /**
167 * Gets the string port name used by CTROS for the service
168 * @return Port name of service
169 */
170 std::string GetPortName() const override { 163 std::string GetPortName() const override {
171 return "gsp::Gpu"; 164 return "gsp::Gpu";
172 } 165 }
173
174}; 166};
175 167
176/** 168/**
diff --git a/src/core/hle/service/hid_user.cpp b/src/core/hle/service/hid_user.cpp
index d29de1a52..99b0ea5a0 100644
--- a/src/core/hle/service/hid_user.cpp
+++ b/src/core/hle/service/hid_user.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h" 5#include "common/log.h"
@@ -55,7 +55,7 @@ static void UpdateNextCirclePadState() {
55/** 55/**
56 * Sets a Pad state (button or button combo) as pressed 56 * Sets a Pad state (button or button combo) as pressed
57 */ 57 */
58void PadButtonPress(PadState pad_state) { 58void PadButtonPress(const PadState& pad_state) {
59 next_state.hex |= pad_state.hex; 59 next_state.hex |= pad_state.hex;
60 UpdateNextCirclePadState(); 60 UpdateNextCirclePadState();
61} 61}
@@ -63,7 +63,7 @@ void PadButtonPress(PadState pad_state) {
63/** 63/**
64 * Sets a Pad state (button or button combo) as released 64 * Sets a Pad state (button or button combo) as released
65 */ 65 */
66void PadButtonRelease(PadState pad_state) { 66void PadButtonRelease(const PadState& pad_state) {
67 next_state.hex &= ~pad_state.hex; 67 next_state.hex &= ~pad_state.hex;
68 UpdateNextCirclePadState(); 68 UpdateNextCirclePadState();
69} 69}
@@ -153,7 +153,7 @@ void PadUpdateComplete() {
153 * 8 : Event signaled by HID_User 153 * 8 : Event signaled by HID_User
154 */ 154 */
155static void GetIPCHandles(Service::Interface* self) { 155static void GetIPCHandles(Service::Interface* self) {
156 u32* cmd_buff = Service::GetCommandBuffer(); 156 u32* cmd_buff = Kernel::GetCommandBuffer();
157 157
158 cmd_buff[1] = 0; // No error 158 cmd_buff[1] = 0; // No error
159 cmd_buff[3] = shared_mem; 159 cmd_buff[3] = shared_mem;
@@ -163,7 +163,7 @@ static void GetIPCHandles(Service::Interface* self) {
163 cmd_buff[7] = event_gyroscope; 163 cmd_buff[7] = event_gyroscope;
164 cmd_buff[8] = event_debug_pad; 164 cmd_buff[8] = event_debug_pad;
165 165
166 DEBUG_LOG(KERNEL, "called"); 166 LOG_TRACE(Service_HID, "called");
167} 167}
168 168
169const Interface::FunctionInfo FunctionTable[] = { 169const Interface::FunctionInfo FunctionTable[] = {
@@ -179,7 +179,6 @@ const Interface::FunctionInfo FunctionTable[] = {
179 {0x00170000, nullptr, "GetSoundVolume"}, 179 {0x00170000, nullptr, "GetSoundVolume"},
180}; 180};
181 181
182
183//////////////////////////////////////////////////////////////////////////////////////////////////// 182////////////////////////////////////////////////////////////////////////////////////////////////////
184// Interface class 183// Interface class
185 184
@@ -196,7 +195,4 @@ Interface::Interface() {
196 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 195 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
197} 196}
198 197
199Interface::~Interface() {
200}
201
202} // namespace 198} // namespace
diff --git a/src/core/hle/service/hid_user.h b/src/core/hle/service/hid_user.h
index 5ed97085d..5b96dda60 100644
--- a/src/core/hle/service/hid_user.h
+++ b/src/core/hle/service/hid_user.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -93,8 +93,8 @@ const PadState PAD_CIRCLE_UP = {{1u << 30}};
93const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; 93const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
94 94
95// Methods for updating the HID module's state 95// Methods for updating the HID module's state
96void PadButtonPress(PadState pad_state); 96void PadButtonPress(const PadState& pad_state);
97void PadButtonRelease(PadState pad_state); 97void PadButtonRelease(const PadState& pad_state);
98void PadUpdateComplete(); 98void PadUpdateComplete();
99 99
100/** 100/**
@@ -102,19 +102,11 @@ void PadUpdateComplete();
102 */ 102 */
103class Interface : public Service::Interface { 103class Interface : public Service::Interface {
104public: 104public:
105
106 Interface(); 105 Interface();
107 106
108 ~Interface();
109
110 /**
111 * Gets the string port name used by CTROS for the service
112 * @return Port name of service
113 */
114 std::string GetPortName() const override { 107 std::string GetPortName() const override {
115 return "hid:USER"; 108 return "hid:USER";
116 } 109 }
117
118}; 110};
119 111
120} // namespace 112} // namespace
diff --git a/src/core/hle/service/http_c.cpp b/src/core/hle/service/http_c.cpp
new file mode 100644
index 000000000..d0bff552f
--- /dev/null
+++ b/src/core/hle/service/http_c.cpp
@@ -0,0 +1,64 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/http_c.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace HTTP_C
11
12namespace HTTP_C {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010044, nullptr, "Initialize"},
16 {0x00020082, nullptr, "CreateContext"},
17 {0x00030040, nullptr, "CloseContext"},
18 {0x00040040, nullptr, "CancelConnection"},
19 {0x00050040, nullptr, "GetRequestState"},
20 {0x00060040, nullptr, "GetDownloadSizeState"},
21 {0x00070040, nullptr, "GetRequestError"},
22 {0x00080042, nullptr, "InitializeConnectionSession"},
23 {0x00090040, nullptr, "BeginRequest"},
24 {0x000A0040, nullptr, "BeginRequestAsync"},
25 {0x000B0082, nullptr, "ReceiveData"},
26 {0x000C0102, nullptr, "ReceiveDataTimeout"},
27 {0x000D0146, nullptr, "SetProxy"},
28 {0x000E0040, nullptr, "SetProxyDefault"},
29 {0x000F00C4, nullptr, "SetBasicAuthorization"},
30 {0x00100080, nullptr, "SetSocketBufferSize"},
31 {0x001100C4, nullptr, "AddRequestHeader"},
32 {0x001200C4, nullptr, "AddPostDataAscii"},
33 {0x001300C4, nullptr, "AddPostDataBinary"},
34 {0x00140082, nullptr, "AddPostDataRaw"},
35 {0x00150080, nullptr, "SetPostDataType"},
36 {0x001600C4, nullptr, "SendPostDataAscii"},
37 {0x00170144, nullptr, "SendPostDataAsciiTimeout"},
38 {0x001800C4, nullptr, "SendPostDataBinary"},
39 {0x00190144, nullptr, "SendPostDataBinaryTimeout"},
40 {0x001A0082, nullptr, "SendPostDataRaw"},
41 {0x001B0102, nullptr, "SendPOSTDataRawTimeout"},
42 {0x001C0080, nullptr, "SetPostDataEncoding"},
43 {0x001D0040, nullptr, "NotifyFinishSendPostData"},
44 {0x001E00C4, nullptr, "GetResponseHeader"},
45 {0x001F0144, nullptr, "GetResponseHeaderTimeout"},
46 {0x00200082, nullptr, "GetResponseData"},
47 {0x00210102, nullptr, "GetResponseDataTimeout"},
48 {0x00220040, nullptr, "GetResponseStatusCode"},
49 {0x002300C0, nullptr, "GetResponseStatusCodeTimeout"},
50 {0x00240082, nullptr, "AddTrustedRootCA"},
51 {0x00350186, nullptr, "SetDefaultProxy"},
52 {0x00360000, nullptr, "ClearDNSCache"},
53 {0x00370080, nullptr, "SetKeepAlive"},
54 {0x003800C0, nullptr, "Finalize"},
55};
56
57////////////////////////////////////////////////////////////////////////////////////////////////////
58// Interface class
59
60Interface::Interface() {
61 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
62}
63
64} // namespace
diff --git a/src/core/hle/service/http_c.h b/src/core/hle/service/http_c.h
new file mode 100644
index 000000000..5ea3d1df3
--- /dev/null
+++ b/src/core/hle/service/http_c.h
@@ -0,0 +1,23 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace HTTP_C
11
12namespace HTTP_C {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "http:C";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/ir_rst.cpp b/src/core/hle/service/ir_rst.cpp
index be15db231..b388afb15 100644
--- a/src/core/hle/service/ir_rst.cpp
+++ b/src/core/hle/service/ir_rst.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h" 5#include "common/log.h"
@@ -30,7 +30,4 @@ Interface::Interface() {
30 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 30 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
31} 31}
32 32
33Interface::~Interface() {
34}
35
36} // namespace 33} // namespace
diff --git a/src/core/hle/service/ir_rst.h b/src/core/hle/service/ir_rst.h
index 73effd7e3..deef701c5 100644
--- a/src/core/hle/service/ir_rst.h
+++ b/src/core/hle/service/ir_rst.h
@@ -1,6 +1,6 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included..
4 4
5#pragma once 5#pragma once
6 6
@@ -14,11 +14,7 @@ namespace IR_RST {
14class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15public: 15public:
16 Interface(); 16 Interface();
17 ~Interface(); 17
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const override { 18 std::string GetPortName() const override {
23 return "ir:rst"; 19 return "ir:rst";
24 } 20 }
diff --git a/src/core/hle/service/ir_u.cpp b/src/core/hle/service/ir_u.cpp
index aa9db6f6d..da6f38e41 100644
--- a/src/core/hle/service/ir_u.cpp
+++ b/src/core/hle/service/ir_u.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h" 5#include "common/log.h"
@@ -39,7 +39,4 @@ Interface::Interface() {
39 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 39 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
40} 40}
41 41
42Interface::~Interface() {
43}
44
45} // namespace 42} // namespace
diff --git a/src/core/hle/service/ir_u.h b/src/core/hle/service/ir_u.h
index 86d98d079..ec47a1524 100644
--- a/src/core/hle/service/ir_u.h
+++ b/src/core/hle/service/ir_u.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -14,11 +14,7 @@ namespace IR_U {
14class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15public: 15public:
16 Interface(); 16 Interface();
17 ~Interface(); 17
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const override { 18 std::string GetPortName() const override {
23 return "ir:u"; 19 return "ir:u";
24 } 20 }
diff --git a/src/core/hle/service/ldr_ro.cpp b/src/core/hle/service/ldr_ro.cpp
new file mode 100644
index 000000000..9c9e90a40
--- /dev/null
+++ b/src/core/hle/service/ldr_ro.cpp
@@ -0,0 +1,29 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/ldr_ro.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace LDR_RO
11
12namespace LDR_RO {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x000100C2, nullptr, "Initialize"},
16 {0x00020082, nullptr, "CRR_Load"},
17 {0x00030042, nullptr, "CRR_Unload"},
18 {0x000402C2, nullptr, "CRO_LoadAndFix"},
19 {0x000500C2, nullptr, "CRO_ApplyRelocationPatchesAndLink"}
20};
21
22////////////////////////////////////////////////////////////////////////////////////////////////////
23// Interface class
24
25Interface::Interface() {
26 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
27}
28
29} // namespace
diff --git a/src/core/hle/service/ldr_ro.h b/src/core/hle/service/ldr_ro.h
new file mode 100644
index 000000000..331637cde
--- /dev/null
+++ b/src/core/hle/service/ldr_ro.h
@@ -0,0 +1,23 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace LDR_RO
11
12namespace LDR_RO {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "ldr:ro";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/mic_u.cpp b/src/core/hle/service/mic_u.cpp
index d6f30e9ae..82bce9180 100644
--- a/src/core/hle/service/mic_u.cpp
+++ b/src/core/hle/service/mic_u.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h" 5#include "common/log.h"
@@ -37,7 +37,4 @@ Interface::Interface() {
37 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 37 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
38} 38}
39 39
40Interface::~Interface() {
41}
42
43} // namespace 40} // namespace
diff --git a/src/core/hle/service/mic_u.h b/src/core/hle/service/mic_u.h
index 2a495f3a9..dc795d14c 100644
--- a/src/core/hle/service/mic_u.h
+++ b/src/core/hle/service/mic_u.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -16,11 +16,7 @@ namespace MIC_U {
16class Interface : public Service::Interface { 16class Interface : public Service::Interface {
17public: 17public:
18 Interface(); 18 Interface();
19 ~Interface(); 19
20 /**
21 * Gets the string port name used by CTROS for the service
22 * @return Port name of service
23 */
24 std::string GetPortName() const override { 20 std::string GetPortName() const override {
25 return "mic:u"; 21 return "mic:u";
26 } 22 }
diff --git a/src/core/hle/service/ndm_u.cpp b/src/core/hle/service/ndm_u.cpp
index 37c0661bf..233b14f6d 100644
--- a/src/core/hle/service/ndm_u.cpp
+++ b/src/core/hle/service/ndm_u.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/hle.h" 5#include "core/hle/hle.h"
@@ -24,7 +24,4 @@ Interface::Interface() {
24 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 24 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
25} 25}
26 26
27Interface::~Interface() {
28}
29
30} // namespace 27} // namespace
diff --git a/src/core/hle/service/ndm_u.h b/src/core/hle/service/ndm_u.h
index 2ca9fcf22..51c4b3902 100644
--- a/src/core/hle/service/ndm_u.h
+++ b/src/core/hle/service/ndm_u.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -15,19 +15,11 @@ namespace NDM_U {
15 15
16class Interface : public Service::Interface { 16class Interface : public Service::Interface {
17public: 17public:
18
19 Interface(); 18 Interface();
20 19
21 ~Interface();
22
23 /**
24 * Gets the string port name used by CTROS for the service
25 * @return Port name of service
26 */
27 std::string GetPortName() const override { 20 std::string GetPortName() const override {
28 return "ndm:u"; 21 return "ndm:u";
29 } 22 }
30
31}; 23};
32 24
33} // namespace 25} // namespace
diff --git a/src/core/hle/service/news_u.cpp b/src/core/hle/service/news_u.cpp
new file mode 100644
index 000000000..b5adad4c6
--- /dev/null
+++ b/src/core/hle/service/news_u.cpp
@@ -0,0 +1,25 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/news_u.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace NEWS_U
11
12namespace NEWS_U {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x000100C8, nullptr, "AddNotification"},
16};
17
18////////////////////////////////////////////////////////////////////////////////////////////////////
19// Interface class
20
21Interface::Interface() {
22 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
23}
24
25} // namespace
diff --git a/src/core/hle/service/news_u.h b/src/core/hle/service/news_u.h
new file mode 100644
index 000000000..0473cd19c
--- /dev/null
+++ b/src/core/hle/service/news_u.h
@@ -0,0 +1,23 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace NEWS_U
11
12namespace NEWS_U {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "news:u";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/nim_aoc.cpp b/src/core/hle/service/nim_aoc.cpp
new file mode 100644
index 000000000..17d1c4ff5
--- /dev/null
+++ b/src/core/hle/service/nim_aoc.cpp
@@ -0,0 +1,31 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/log.h"
6#include "core/hle/hle.h"
7#include "core/hle/service/nim_aoc.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace NIM_AOC
11
12namespace NIM_AOC {
13
14const Interface::FunctionInfo FunctionTable[] = {
15 {0x00030042, nullptr, "SetApplicationId"},
16 {0x00040042, nullptr, "SetTin"},
17 {0x000902D0, nullptr, "ListContentSetsEx"},
18 {0x00180000, nullptr, "GetBalance"},
19 {0x001D0000, nullptr, "GetCustomerSupportCode"},
20 {0x00210000, nullptr, "Initialize"},
21 {0x00240282, nullptr, "CalculateContentsRequiredSize"},
22 {0x00250000, nullptr, "RefreshServerTime"},
23};
24////////////////////////////////////////////////////////////////////////////////////////////////////
25// Interface class
26
27Interface::Interface() {
28 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
29}
30
31} // namespace
diff --git a/src/core/hle/service/nim_aoc.h b/src/core/hle/service/nim_aoc.h
new file mode 100644
index 000000000..aeb71eed2
--- /dev/null
+++ b/src/core/hle/service/nim_aoc.h
@@ -0,0 +1,23 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "core/hle/service/service.h"
8
9////////////////////////////////////////////////////////////////////////////////////////////////////
10// Namespace NIM_AOC
11
12namespace NIM_AOC {
13
14class Interface : public Service::Interface {
15public:
16 Interface();
17
18 std::string GetPortName() const override {
19 return "nim:aoc";
20 }
21};
22
23} // namespace
diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp
index 14df86d85..ce456a966 100644
--- a/src/core/hle/service/nwm_uds.cpp
+++ b/src/core/hle/service/nwm_uds.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h" 5#include "common/log.h"
@@ -29,7 +29,4 @@ Interface::Interface() {
29 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 29 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
30} 30}
31 31
32Interface::~Interface() {
33}
34
35} // namespace 32} // namespace
diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h
index 69d2c2002..9043f5aa7 100644
--- a/src/core/hle/service/nwm_uds.h
+++ b/src/core/hle/service/nwm_uds.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -16,11 +16,7 @@ namespace NWM_UDS {
16class Interface : public Service::Interface { 16class Interface : public Service::Interface {
17public: 17public:
18 Interface(); 18 Interface();
19 ~Interface(); 19
20 /**
21 * Gets the string port name used by CTROS for the service
22 * @return Port name of service
23 */
24 std::string GetPortName() const override { 20 std::string GetPortName() const override {
25 return "nwm:UDS"; 21 return "nwm:UDS";
26 } 22 }
diff --git a/src/core/hle/service/pm_app.cpp b/src/core/hle/service/pm_app.cpp
index 90e9b1bfa..529dccafb 100644
--- a/src/core/hle/service/pm_app.cpp
+++ b/src/core/hle/service/pm_app.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h" 5#include "common/log.h"
@@ -29,7 +29,4 @@ Interface::Interface() {
29 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 29 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
30} 30}
31 31
32Interface::~Interface() {
33}
34
35} // namespace 32} // namespace
diff --git a/src/core/hle/service/pm_app.h b/src/core/hle/service/pm_app.h
index 28c38f582..c1fb1f9da 100644
--- a/src/core/hle/service/pm_app.h
+++ b/src/core/hle/service/pm_app.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -14,11 +14,7 @@ namespace PM_APP {
14class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15public: 15public:
16 Interface(); 16 Interface();
17 ~Interface(); 17
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const override { 18 std::string GetPortName() const override {
23 return "pm:app"; 19 return "pm:app";
24 } 20 }
diff --git a/src/core/hle/service/ptm_u.cpp b/src/core/hle/service/ptm_u.cpp
index d9122dbbc..d1498f05c 100644
--- a/src/core/hle/service/ptm_u.cpp
+++ b/src/core/hle/service/ptm_u.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h" 5#include "common/log.h"
@@ -11,15 +11,101 @@
11 11
12namespace PTM_U { 12namespace PTM_U {
13 13
14/// Charge levels used by PTM functions
15enum class ChargeLevels : u32 {
16 CriticalBattery = 1,
17 LowBattery = 2,
18 HalfFull = 3,
19 MostlyFull = 4,
20 CompletelyFull = 5,
21};
22
23static bool shell_open = true;
24
25static bool battery_is_charging = true;
26
27/**
28 * It is unknown if GetAdapterState is the same as GetBatteryChargeState,
29 * it is likely to just be a duplicate function of GetBatteryChargeState
30 * that controls another part of the HW.
31 * PTM_U::GetAdapterState service function
32 * Outputs:
33 * 1 : Result of function, 0 on success, otherwise error code
34 * 2 : Output of function, 0 = not charging, 1 = charging.
35 */
36static void GetAdapterState(Service::Interface* self) {
37 u32* cmd_buff = Kernel::GetCommandBuffer();
38
39 // TODO(purpasmart96): This function is only a stub,
40 // it returns a valid result without implementing full functionality.
41
42 cmd_buff[1] = 0; // No error
43 cmd_buff[2] = battery_is_charging ? 1 : 0;
44
45 LOG_WARNING(Service_PTM, "(STUBBED) called");
46}
47
48/*
49 * PTM_User::GetShellState service function.
50 * Outputs:
51 * 1 : Result of function, 0 on success, otherwise error code
52 * 2 : Whether the 3DS's physical shell casing is open (1) or closed (0)
53 */
54static void GetShellState(Service::Interface* self) {
55 u32* cmd_buff = Kernel::GetCommandBuffer();
56
57 cmd_buff[1] = 0;
58 cmd_buff[2] = shell_open ? 1 : 0;
59
60 LOG_TRACE(Service_PTM, "PTM_U::GetShellState called");
61}
62
63/**
64 * PTM_U::GetBatteryLevel service function
65 * Outputs:
66 * 1 : Result of function, 0 on success, otherwise error code
67 * 2 : Battery level, 5 = completely full battery, 4 = mostly full battery,
68 * 3 = half full battery, 2 = low battery, 1 = critical battery.
69 */
70static void GetBatteryLevel(Service::Interface* self) {
71 u32* cmd_buff = Kernel::GetCommandBuffer();
72
73 // TODO(purpasmart96): This function is only a stub,
74 // it returns a valid result without implementing full functionality.
75
76 cmd_buff[1] = 0; // No error
77 cmd_buff[2] = static_cast<u32>(ChargeLevels::CompletelyFull); // Set to a completely full battery
78
79 LOG_WARNING(Service_PTM, "(STUBBED) called");
80}
81
82/**
83 * PTM_U::GetBatteryChargeState service function
84 * Outputs:
85 * 1 : Result of function, 0 on success, otherwise error code
86 * 2 : Output of function, 0 = not charging, 1 = charging.
87 */
88static void GetBatteryChargeState(Service::Interface* self) {
89 u32* cmd_buff = Kernel::GetCommandBuffer();
90
91 // TODO(purpasmart96): This function is only a stub,
92 // it returns a valid result without implementing full functionality.
93
94 cmd_buff[1] = 0; // No error
95 cmd_buff[2] = battery_is_charging ? 1 : 0;
96
97 LOG_WARNING(Service_PTM, "(STUBBED) called");
98}
99
14const Interface::FunctionInfo FunctionTable[] = { 100const Interface::FunctionInfo FunctionTable[] = {
15 {0x00010002, nullptr, "RegisterAlarmClient"}, 101 {0x00010002, nullptr, "RegisterAlarmClient"},
16 {0x00020080, nullptr, "SetRtcAlarm"}, 102 {0x00020080, nullptr, "SetRtcAlarm"},
17 {0x00030000, nullptr, "GetRtcAlarm"}, 103 {0x00030000, nullptr, "GetRtcAlarm"},
18 {0x00040000, nullptr, "CancelRtcAlarm"}, 104 {0x00040000, nullptr, "CancelRtcAlarm"},
19 {0x00050000, nullptr, "GetAdapterState"}, 105 {0x00050000, GetAdapterState, "GetAdapterState"},
20 {0x00060000, nullptr, "GetShellState"}, 106 {0x00060000, GetShellState, "GetShellState"},
21 {0x00070000, nullptr, "GetBatteryLevel"}, 107 {0x00070000, GetBatteryLevel, "GetBatteryLevel"},
22 {0x00080000, nullptr, "GetBatteryChargeState"}, 108 {0x00080000, GetBatteryChargeState, "GetBatteryChargeState"},
23 {0x00090000, nullptr, "GetPedometerState"}, 109 {0x00090000, nullptr, "GetPedometerState"},
24 {0x000A0042, nullptr, "GetStepHistoryEntry"}, 110 {0x000A0042, nullptr, "GetStepHistoryEntry"},
25 {0x000B00C2, nullptr, "GetStepHistory"}, 111 {0x000B00C2, nullptr, "GetStepHistory"},
@@ -36,7 +122,4 @@ Interface::Interface() {
36 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 122 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
37} 123}
38 124
39Interface::~Interface() {
40}
41
42} // namespace 125} // namespace
diff --git a/src/core/hle/service/ptm_u.h b/src/core/hle/service/ptm_u.h
index f8d9f57be..a44624fd5 100644
--- a/src/core/hle/service/ptm_u.h
+++ b/src/core/hle/service/ptm_u.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -16,11 +16,7 @@ namespace PTM_U {
16class Interface : public Service::Interface { 16class Interface : public Service::Interface {
17public: 17public:
18 Interface(); 18 Interface();
19 ~Interface(); 19
20 /**
21 * Gets the string port name used by CTROS for the service
22 * @return Port name of service
23 */
24 std::string GetPortName() const override { 20 std::string GetPortName() const override {
25 return "ptm:u"; 21 return "ptm:u";
26 } 22 }
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index fed2268a0..0f3cc2aa8 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common.h" 5#include "common/common.h"
@@ -7,22 +7,30 @@
7 7
8#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
9#include "core/hle/service/ac_u.h" 9#include "core/hle/service/ac_u.h"
10#include "core/hle/service/act_u.h"
11#include "core/hle/service/am_app.h"
10#include "core/hle/service/am_net.h" 12#include "core/hle/service/am_net.h"
13#include "core/hle/service/apt_a.h"
11#include "core/hle/service/apt_u.h" 14#include "core/hle/service/apt_u.h"
12#include "core/hle/service/boss_u.h" 15#include "core/hle/service/boss_u.h"
13#include "core/hle/service/cfg_i.h" 16#include "core/hle/service/cecd_u.h"
14#include "core/hle/service/cfg_u.h" 17#include "core/hle/service/cfg/cfg_i.h"
18#include "core/hle/service/cfg/cfg_u.h"
15#include "core/hle/service/csnd_snd.h" 19#include "core/hle/service/csnd_snd.h"
16#include "core/hle/service/dsp_dsp.h" 20#include "core/hle/service/dsp_dsp.h"
17#include "core/hle/service/err_f.h" 21#include "core/hle/service/err_f.h"
18#include "core/hle/service/fs_user.h" 22#include "core/hle/service/fs/fs_user.h"
19#include "core/hle/service/frd_u.h" 23#include "core/hle/service/frd_u.h"
20#include "core/hle/service/gsp_gpu.h" 24#include "core/hle/service/gsp_gpu.h"
21#include "core/hle/service/hid_user.h" 25#include "core/hle/service/hid_user.h"
26#include "core/hle/service/http_c.h"
22#include "core/hle/service/ir_rst.h" 27#include "core/hle/service/ir_rst.h"
23#include "core/hle/service/ir_u.h" 28#include "core/hle/service/ir_u.h"
29#include "core/hle/service/ldr_ro.h"
24#include "core/hle/service/mic_u.h" 30#include "core/hle/service/mic_u.h"
25#include "core/hle/service/ndm_u.h" 31#include "core/hle/service/ndm_u.h"
32#include "core/hle/service/news_u.h"
33#include "core/hle/service/nim_aoc.h"
26#include "core/hle/service/nwm_uds.h" 34#include "core/hle/service/nwm_uds.h"
27#include "core/hle/service/pm_app.h" 35#include "core/hle/service/pm_app.h"
28#include "core/hle/service/ptm_u.h" 36#include "core/hle/service/ptm_u.h"
@@ -48,7 +56,8 @@ Manager::~Manager() {
48 56
49/// Add a service to the manager (does not create it though) 57/// Add a service to the manager (does not create it though)
50void Manager::AddService(Interface* service) { 58void Manager::AddService(Interface* service) {
51 m_port_map[service->GetPortName()] = Kernel::g_object_pool.Create(service); 59 // TOOD(yuriks): Fix error reporting
60 m_port_map[service->GetPortName()] = Kernel::g_handle_table.Create(service).ValueOr(INVALID_HANDLE);
52 m_services.push_back(service); 61 m_services.push_back(service);
53} 62}
54 63
@@ -62,7 +71,7 @@ void Manager::DeleteService(const std::string& port_name) {
62 71
63/// Get a Service Interface from its Handle 72/// Get a Service Interface from its Handle
64Interface* Manager::FetchFromHandle(Handle handle) { 73Interface* Manager::FetchFromHandle(Handle handle) {
65 return Kernel::g_object_pool.Get<Interface>(handle); 74 return Kernel::g_handle_table.Get<Interface>(handle);
66} 75}
67 76
68/// Get a Service Interface from its port 77/// Get a Service Interface from its port
@@ -84,35 +93,43 @@ void Init() {
84 93
85 g_manager->AddService(new SRV::Interface); 94 g_manager->AddService(new SRV::Interface);
86 g_manager->AddService(new AC_U::Interface); 95 g_manager->AddService(new AC_U::Interface);
96 g_manager->AddService(new ACT_U::Interface);
97 g_manager->AddService(new AM_APP::Interface);
87 g_manager->AddService(new AM_NET::Interface); 98 g_manager->AddService(new AM_NET::Interface);
99 g_manager->AddService(new APT_A::Interface);
88 g_manager->AddService(new APT_U::Interface); 100 g_manager->AddService(new APT_U::Interface);
89 g_manager->AddService(new BOSS_U::Interface); 101 g_manager->AddService(new BOSS_U::Interface);
102 g_manager->AddService(new CECD_U::Interface);
90 g_manager->AddService(new CFG_I::Interface); 103 g_manager->AddService(new CFG_I::Interface);
91 g_manager->AddService(new CFG_U::Interface); 104 g_manager->AddService(new CFG_U::Interface);
92 g_manager->AddService(new CSND_SND::Interface); 105 g_manager->AddService(new CSND_SND::Interface);
93 g_manager->AddService(new DSP_DSP::Interface); 106 g_manager->AddService(new DSP_DSP::Interface);
94 g_manager->AddService(new ERR_F::Interface); 107 g_manager->AddService(new ERR_F::Interface);
95 g_manager->AddService(new FRD_U::Interface); 108 g_manager->AddService(new FRD_U::Interface);
96 g_manager->AddService(new FS_User::Interface); 109 g_manager->AddService(new FS::FSUserInterface);
97 g_manager->AddService(new GSP_GPU::Interface); 110 g_manager->AddService(new GSP_GPU::Interface);
98 g_manager->AddService(new HID_User::Interface); 111 g_manager->AddService(new HID_User::Interface);
112 g_manager->AddService(new HTTP_C::Interface);
99 g_manager->AddService(new IR_RST::Interface); 113 g_manager->AddService(new IR_RST::Interface);
100 g_manager->AddService(new IR_U::Interface); 114 g_manager->AddService(new IR_U::Interface);
115 g_manager->AddService(new LDR_RO::Interface);
101 g_manager->AddService(new MIC_U::Interface); 116 g_manager->AddService(new MIC_U::Interface);
102 g_manager->AddService(new NDM_U::Interface); 117 g_manager->AddService(new NDM_U::Interface);
118 g_manager->AddService(new NEWS_U::Interface);
119 g_manager->AddService(new NIM_AOC::Interface);
103 g_manager->AddService(new NWM_UDS::Interface); 120 g_manager->AddService(new NWM_UDS::Interface);
104 g_manager->AddService(new PM_APP::Interface); 121 g_manager->AddService(new PM_APP::Interface);
105 g_manager->AddService(new PTM_U::Interface); 122 g_manager->AddService(new PTM_U::Interface);
106 g_manager->AddService(new SOC_U::Interface); 123 g_manager->AddService(new SOC_U::Interface);
107 g_manager->AddService(new SSL_C::Interface); 124 g_manager->AddService(new SSL_C::Interface);
108 125
109 NOTICE_LOG(HLE, "initialized OK"); 126 LOG_DEBUG(Service, "initialized OK");
110} 127}
111 128
112/// Shutdown ServiceManager 129/// Shutdown ServiceManager
113void Shutdown() { 130void Shutdown() {
114 delete g_manager; 131 delete g_manager;
115 NOTICE_LOG(HLE, "shutdown OK"); 132 LOG_DEBUG(Service, "shutdown OK");
116} 133}
117 134
118 135
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 20e7fb4d3..28b4ccd17 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -10,9 +10,11 @@
10#include <string> 10#include <string>
11 11
12#include "common/common.h" 12#include "common/common.h"
13#include "common/string_util.h"
13#include "core/mem_map.h" 14#include "core/mem_map.h"
14 15
15#include "core/hle/kernel/kernel.h" 16#include "core/hle/kernel/kernel.h"
17#include "core/hle/kernel/session.h"
16#include "core/hle/svc.h" 18#include "core/hle/svc.h"
17 19
18//////////////////////////////////////////////////////////////////////////////////////////////////// 20////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -20,30 +22,19 @@
20 22
21namespace Service { 23namespace Service {
22 24
23static const int kMaxPortSize = 0x08; ///< Maximum size of a port name (8 characters) 25static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
24static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header
25
26/**
27 * Returns a pointer to the command buffer in kernel memory
28 * @param offset Optional offset into command buffer
29 * @return Pointer to command buffer
30 */
31inline static u32* GetCommandBuffer(const int offset=0) {
32 return (u32*)Memory::GetPointer(Memory::KERNEL_MEMORY_VADDR + kCommandHeaderOffset + offset);
33}
34 26
35class Manager; 27class Manager;
36 28
37/// Interface to a CTROS service 29/// Interface to a CTROS service
38class Interface : public Kernel::Object { 30class Interface : public Kernel::Session {
31 // TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be
32 // just something that encapsulates a session and acts as a helper to implement service
33 // processes.
34
39 friend class Manager; 35 friend class Manager;
40public: 36public:
41
42 std::string GetName() const override { return GetPortName(); } 37 std::string GetName() const override { return GetPortName(); }
43 std::string GetTypeName() const override { return GetPortName(); }
44
45 static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Service; }
46 Kernel::HandleType GetHandleType() const override { return Kernel::HandleType::Service; }
47 38
48 typedef void (*Function)(Interface*); 39 typedef void (*Function)(Interface*);
49 40
@@ -63,7 +54,8 @@ public:
63 54
64 /// Allocates a new handle for the service 55 /// Allocates a new handle for the service
65 Handle CreateHandle(Kernel::Object *obj) { 56 Handle CreateHandle(Kernel::Object *obj) {
66 Handle handle = Kernel::g_object_pool.Create(obj); 57 // TODO(yuriks): Fix error reporting
58 Handle handle = Kernel::g_handle_table.Create(obj).ValueOr(INVALID_HANDLE);
67 m_handles.push_back(handle); 59 m_handles.push_back(handle);
68 return handle; 60 return handle;
69 } 61 }
@@ -71,29 +63,28 @@ public:
71 /// Frees a handle from the service 63 /// Frees a handle from the service
72 template <class T> 64 template <class T>
73 void DeleteHandle(const Handle handle) { 65 void DeleteHandle(const Handle handle) {
74 Kernel::g_object_pool.Destroy<T>(handle); 66 Kernel::g_handle_table.Close(handle);
75 m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end()); 67 m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end());
76 } 68 }
77 69
78 ResultVal<bool> SyncRequest() override { 70 ResultVal<bool> SyncRequest() override {
79 u32* cmd_buff = GetCommandBuffer(); 71 u32* cmd_buff = Kernel::GetCommandBuffer();
80 auto itr = m_functions.find(cmd_buff[0]); 72 auto itr = m_functions.find(cmd_buff[0]);
81 73
82 if (itr == m_functions.end()) { 74 if (itr == m_functions.end() || itr->second.func == nullptr) {
83 ERROR_LOG(OSHLE, "unknown/unimplemented function: port=%s, command=0x%08X", 75 // Number of params == bits 0-5 + bits 6-11
84 GetPortName().c_str(), cmd_buff[0]); 76 int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
85 77
86 // TODO(bunnei): Hack - ignore error 78 std::string error = "unknown/unimplemented function '%s': port=%s";
87 u32* cmd_buff = Service::GetCommandBuffer(); 79 for (int i = 1; i <= num_params; ++i) {
88 cmd_buff[1] = 0; 80 error += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]);
89 return MakeResult<bool>(false); 81 }
90 } 82
91 if (itr->second.func == nullptr) { 83 std::string name = (itr == m_functions.end()) ? Common::StringFromFormat("0x%08X", cmd_buff[0]) : itr->second.name;
92 ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s", 84
93 GetPortName().c_str(), itr->second.name.c_str()); 85 LOG_ERROR(Service, error.c_str(), name.c_str(), GetPortName().c_str());
94 86
95 // TODO(bunnei): Hack - ignore error 87 // TODO(bunnei): Hack - ignore error
96 u32* cmd_buff = Service::GetCommandBuffer();
97 cmd_buff[1] = 0; 88 cmd_buff[1] = 0;
98 return MakeResult<bool>(false); 89 return MakeResult<bool>(false);
99 } 90 }
@@ -103,12 +94,6 @@ public:
103 return MakeResult<bool>(false); // TODO: Implement return from actual function 94 return MakeResult<bool>(false); // TODO: Implement return from actual function
104 } 95 }
105 96
106 ResultVal<bool> WaitSynchronization() override {
107 // TODO(bunnei): ImplementMe
108 ERROR_LOG(OSHLE, "unimplemented function");
109 return UnimplementedFunction(ErrorModule::OS);
110 }
111
112protected: 97protected:
113 98
114 /** 99 /**
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index 2f8910468..ef4f9829d 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h" 5#include "common/log.h"
@@ -52,7 +52,4 @@ Interface::Interface() {
52 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 52 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
53} 53}
54 54
55Interface::~Interface() {
56}
57
58} // namespace 55} // namespace
diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h
index d5590a683..2edf3b482 100644
--- a/src/core/hle/service/soc_u.h
+++ b/src/core/hle/service/soc_u.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -14,11 +14,7 @@ namespace SOC_U {
14class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15public: 15public:
16 Interface(); 16 Interface();
17 ~Interface(); 17
18 /**
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const override { 18 std::string GetPortName() const override {
23 return "soc:U"; 19 return "soc:U";
24 } 20 }
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index 0e7fa9e3b..25fab1a4f 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/hle.h" 5#include "core/hle/hle.h"
@@ -14,17 +14,17 @@ namespace SRV {
14static Handle g_event_handle = 0; 14static Handle g_event_handle = 0;
15 15
16static void Initialize(Service::Interface* self) { 16static void Initialize(Service::Interface* self) {
17 DEBUG_LOG(OSHLE, "called"); 17 LOG_DEBUG(Service_SRV, "called");
18 18
19 u32* cmd_buff = Service::GetCommandBuffer(); 19 u32* cmd_buff = Kernel::GetCommandBuffer();
20 20
21 cmd_buff[1] = 0; // No error 21 cmd_buff[1] = 0; // No error
22} 22}
23 23
24static void GetProcSemaphore(Service::Interface* self) { 24static void GetProcSemaphore(Service::Interface* self) {
25 DEBUG_LOG(OSHLE, "called"); 25 LOG_TRACE(Service_SRV, "called");
26 26
27 u32* cmd_buff = Service::GetCommandBuffer(); 27 u32* cmd_buff = Kernel::GetCommandBuffer();
28 28
29 // TODO(bunnei): Change to a semaphore once these have been implemented 29 // TODO(bunnei): Change to a semaphore once these have been implemented
30 g_event_handle = Kernel::CreateEvent(RESETTYPE_ONESHOT, "SRV:Event"); 30 g_event_handle = Kernel::CreateEvent(RESETTYPE_ONESHOT, "SRV:Event");
@@ -36,16 +36,16 @@ static void GetProcSemaphore(Service::Interface* self) {
36 36
37static void GetServiceHandle(Service::Interface* self) { 37static void GetServiceHandle(Service::Interface* self) {
38 ResultCode res = RESULT_SUCCESS; 38 ResultCode res = RESULT_SUCCESS;
39 u32* cmd_buff = Service::GetCommandBuffer(); 39 u32* cmd_buff = Kernel::GetCommandBuffer();
40 40
41 std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); 41 std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize);
42 Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); 42 Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
43 43
44 if (nullptr != service) { 44 if (nullptr != service) {
45 cmd_buff[3] = service->GetHandle(); 45 cmd_buff[3] = service->GetHandle();
46 DEBUG_LOG(OSHLE, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]); 46 LOG_TRACE(Service_SRV, "called port=%s, handle=0x%08X", port_name.c_str(), cmd_buff[3]);
47 } else { 47 } else {
48 ERROR_LOG(OSHLE, "(UNIMPLEMENTED) called port=%s", port_name.c_str()); 48 LOG_ERROR(Service_SRV, "(UNIMPLEMENTED) called port=%s", port_name.c_str());
49 res = UnimplementedFunction(ErrorModule::SRV); 49 res = UnimplementedFunction(ErrorModule::SRV);
50 } 50 }
51 cmd_buff[1] = res.raw; 51 cmd_buff[1] = res.raw;
@@ -68,7 +68,4 @@ Interface::Interface() {
68 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 68 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
69} 69}
70 70
71Interface::~Interface() {
72}
73
74} // namespace 71} // namespace
diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h
index 6d5fe5048..653aba5cb 100644
--- a/src/core/hle/service/srv.h
+++ b/src/core/hle/service/srv.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hle/service/service.h" 5#include "core/hle/service/service.h"
@@ -11,21 +11,12 @@ namespace SRV {
11 11
12/// Interface to "srv:" service 12/// Interface to "srv:" service
13class Interface : public Service::Interface { 13class Interface : public Service::Interface {
14
15public: 14public:
16
17 Interface(); 15 Interface();
18 16
19 ~Interface();
20
21 /**
22 * Gets the string name used by CTROS for the service
23 * @return Port name of service
24 */
25 std::string GetPortName() const override { 17 std::string GetPortName() const override {
26 return "srv:"; 18 return "srv:";
27 } 19 }
28
29}; 20};
30 21
31} // namespace 22} // namespace
diff --git a/src/core/hle/service/ssl_c.cpp b/src/core/hle/service/ssl_c.cpp
index 4aa660ecc..360516cdf 100644
--- a/src/core/hle/service/ssl_c.cpp
+++ b/src/core/hle/service/ssl_c.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/log.h" 5#include "common/log.h"
@@ -25,7 +25,4 @@ Interface::Interface() {
25 Register(FunctionTable, ARRAY_SIZE(FunctionTable)); 25 Register(FunctionTable, ARRAY_SIZE(FunctionTable));
26} 26}
27 27
28Interface::~Interface() {
29}
30
31} // namespace 28} // namespace
diff --git a/src/core/hle/service/ssl_c.h b/src/core/hle/service/ssl_c.h
index 7b4e7fd8a..58e87c1cb 100644
--- a/src/core/hle/service/ssl_c.h
+++ b/src/core/hle/service/ssl_c.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -14,12 +14,8 @@ namespace SSL_C {
14class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15public: 15public:
16 Interface(); 16 Interface();
17 ~Interface(); 17
18 /** 18 std::string GetPortName() const override {
19 * Gets the string port name used by CTROS for the service
20 * @return Port name of service
21 */
22 std::string GetPortName() const {
23 return "ssl:C"; 19 return "ssl:C";
24 } 20 }
25}; 21};
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 87d768856..25944fc68 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map> 5#include <map>
@@ -12,6 +12,7 @@
12#include "core/hle/kernel/address_arbiter.h" 12#include "core/hle/kernel/address_arbiter.h"
13#include "core/hle/kernel/event.h" 13#include "core/hle/kernel/event.h"
14#include "core/hle/kernel/mutex.h" 14#include "core/hle/kernel/mutex.h"
15#include "core/hle/kernel/semaphore.h"
15#include "core/hle/kernel/shared_memory.h" 16#include "core/hle/kernel/shared_memory.h"
16#include "core/hle/kernel/thread.h" 17#include "core/hle/kernel/thread.h"
17 18
@@ -31,7 +32,7 @@ enum ControlMemoryOperation {
31 32
32/// Map application or GSP heap memory 33/// Map application or GSP heap memory
33static Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { 34static Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) {
34 DEBUG_LOG(SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", 35 LOG_TRACE(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",
35 operation, addr0, addr1, size, permissions); 36 operation, addr0, addr1, size, permissions);
36 37
37 switch (operation) { 38 switch (operation) {
@@ -43,19 +44,19 @@ static Result ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1,
43 44
44 // Map GSP heap memory 45 // Map GSP heap memory
45 case MEMORY_OPERATION_GSP_HEAP: 46 case MEMORY_OPERATION_GSP_HEAP:
46 *out_addr = Memory::MapBlock_HeapGSP(size, operation, permissions); 47 *out_addr = Memory::MapBlock_HeapLinear(size, operation, permissions);
47 break; 48 break;
48 49
49 // Unknown ControlMemory operation 50 // Unknown ControlMemory operation
50 default: 51 default:
51 ERROR_LOG(SVC, "unknown operation=0x%08X", operation); 52 LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation);
52 } 53 }
53 return 0; 54 return 0;
54} 55}
55 56
56/// Maps a memory block to specified address 57/// Maps a memory block to specified address
57static Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) { 58static Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other_permissions) {
58 DEBUG_LOG(SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", 59 LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",
59 handle, addr, permissions, other_permissions); 60 handle, addr, permissions, other_permissions);
60 61
61 Kernel::MemoryPermission permissions_type = static_cast<Kernel::MemoryPermission>(permissions); 62 Kernel::MemoryPermission permissions_type = static_cast<Kernel::MemoryPermission>(permissions);
@@ -63,12 +64,16 @@ static Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other
63 case Kernel::MemoryPermission::Read: 64 case Kernel::MemoryPermission::Read:
64 case Kernel::MemoryPermission::Write: 65 case Kernel::MemoryPermission::Write:
65 case Kernel::MemoryPermission::ReadWrite: 66 case Kernel::MemoryPermission::ReadWrite:
67 case Kernel::MemoryPermission::Execute:
68 case Kernel::MemoryPermission::ReadExecute:
69 case Kernel::MemoryPermission::WriteExecute:
70 case Kernel::MemoryPermission::ReadWriteExecute:
66 case Kernel::MemoryPermission::DontCare: 71 case Kernel::MemoryPermission::DontCare:
67 Kernel::MapSharedMemory(handle, addr, permissions_type, 72 Kernel::MapSharedMemory(handle, addr, permissions_type,
68 static_cast<Kernel::MemoryPermission>(other_permissions)); 73 static_cast<Kernel::MemoryPermission>(other_permissions));
69 break; 74 break;
70 default: 75 default:
71 ERROR_LOG(OSHLE, "unknown permissions=0x%08X", permissions); 76 LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions);
72 } 77 }
73 return 0; 78 return 0;
74} 79}
@@ -77,7 +82,7 @@ static Result MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 other
77static Result ConnectToPort(Handle* out, const char* port_name) { 82static Result ConnectToPort(Handle* out, const char* port_name) {
78 Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); 83 Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
79 84
80 DEBUG_LOG(SVC, "called port_name=%s", port_name); 85 LOG_TRACE(Kernel_SVC, "called port_name=%s", port_name);
81 _assert_msg_(KERNEL, (service != nullptr), "called, but service is not implemented!"); 86 _assert_msg_(KERNEL, (service != nullptr), "called, but service is not implemented!");
82 87
83 *out = service->GetHandle(); 88 *out = service->GetHandle();
@@ -87,17 +92,14 @@ static Result ConnectToPort(Handle* out, const char* port_name) {
87 92
88/// Synchronize to an OS service 93/// Synchronize to an OS service
89static Result SendSyncRequest(Handle handle) { 94static Result SendSyncRequest(Handle handle) {
90 // TODO(yuriks): ObjectPool::Get tries to check the Object type, which fails since this is a generic base Object, 95 Kernel::Session* session = Kernel::g_handle_table.Get<Kernel::Session>(handle);
91 // so we are forced to use GetFast and manually verify the handle. 96 if (session == nullptr) {
92 if (!Kernel::g_object_pool.IsValid(handle)) {
93 return InvalidHandle(ErrorModule::Kernel).raw; 97 return InvalidHandle(ErrorModule::Kernel).raw;
94 } 98 }
95 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
96 99
97 _assert_msg_(KERNEL, (object != nullptr), "called, but kernel object is nullptr!"); 100 LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s)", handle, session->GetName().c_str());
98 DEBUG_LOG(SVC, "called handle=0x%08X(%s)", handle, object->GetTypeName().c_str());
99 101
100 ResultVal<bool> wait = object->SyncRequest(); 102 ResultVal<bool> wait = session->SyncRequest();
101 if (wait.Succeeded() && *wait) { 103 if (wait.Succeeded() && *wait) {
102 Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct? 104 Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
103 } 105 }
@@ -108,7 +110,7 @@ static Result SendSyncRequest(Handle handle) {
108/// Close a handle 110/// Close a handle
109static Result CloseHandle(Handle handle) { 111static Result CloseHandle(Handle handle) {
110 // ImplementMe 112 // ImplementMe
111 ERROR_LOG(SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle); 113 LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called handle=0x%08X", handle);
112 return 0; 114 return 0;
113} 115}
114 116
@@ -117,13 +119,11 @@ static Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
117 // TODO(bunnei): Do something with nano_seconds, currently ignoring this 119 // TODO(bunnei): Do something with nano_seconds, currently ignoring this
118 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated 120 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
119 121
120 if (!Kernel::g_object_pool.IsValid(handle)) { 122 Kernel::Object* object = Kernel::g_handle_table.GetGeneric(handle);
123 if (object == nullptr)
121 return InvalidHandle(ErrorModule::Kernel).raw; 124 return InvalidHandle(ErrorModule::Kernel).raw;
122 }
123 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handle);
124 _dbg_assert_(KERNEL, object != nullptr);
125 125
126 DEBUG_LOG(SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(), 126 LOG_TRACE(Kernel_SVC, "called handle=0x%08X(%s:%s), nanoseconds=%lld", handle, object->GetTypeName().c_str(),
127 object->GetName().c_str(), nano_seconds); 127 object->GetName().c_str(), nano_seconds);
128 128
129 ResultVal<bool> wait = object->WaitSynchronization(); 129 ResultVal<bool> wait = object->WaitSynchronization();
@@ -143,17 +143,16 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count,
143 bool unlock_all = true; 143 bool unlock_all = true;
144 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated 144 bool wait_infinite = (nano_seconds == -1); // Used to wait until a thread has terminated
145 145
146 DEBUG_LOG(SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld", 146 LOG_TRACE(Kernel_SVC, "called handle_count=%d, wait_all=%s, nanoseconds=%lld",
147 handle_count, (wait_all ? "true" : "false"), nano_seconds); 147 handle_count, (wait_all ? "true" : "false"), nano_seconds);
148 148
149 // Iterate through each handle, synchronize kernel object 149 // Iterate through each handle, synchronize kernel object
150 for (s32 i = 0; i < handle_count; i++) { 150 for (s32 i = 0; i < handle_count; i++) {
151 if (!Kernel::g_object_pool.IsValid(handles[i])) { 151 Kernel::Object* object = Kernel::g_handle_table.GetGeneric(handles[i]);
152 if (object == nullptr)
152 return InvalidHandle(ErrorModule::Kernel).raw; 153 return InvalidHandle(ErrorModule::Kernel).raw;
153 }
154 Kernel::Object* object = Kernel::g_object_pool.GetFast<Kernel::Object>(handles[i]);
155 154
156 DEBUG_LOG(SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName().c_str(), 155 LOG_TRACE(Kernel_SVC, "\thandle[%d] = 0x%08X(%s:%s)", i, handles[i], object->GetTypeName().c_str(),
157 object->GetName().c_str()); 156 object->GetName().c_str());
158 157
159 // TODO(yuriks): Verify how the real function behaves when an error happens here 158 // TODO(yuriks): Verify how the real function behaves when an error happens here
@@ -181,7 +180,7 @@ static Result WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count,
181 180
182/// Create an address arbiter (to allocate access to shared resources) 181/// Create an address arbiter (to allocate access to shared resources)
183static Result CreateAddressArbiter(u32* arbiter) { 182static Result CreateAddressArbiter(u32* arbiter) {
184 DEBUG_LOG(SVC, "called"); 183 LOG_TRACE(Kernel_SVC, "called");
185 Handle handle = Kernel::CreateAddressArbiter(); 184 Handle handle = Kernel::CreateAddressArbiter();
186 *arbiter = handle; 185 *arbiter = handle;
187 return 0; 186 return 0;
@@ -189,13 +188,15 @@ static Result CreateAddressArbiter(u32* arbiter) {
189 188
190/// Arbitrate address 189/// Arbitrate address
191static Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) { 190static Result ArbitrateAddress(Handle arbiter, u32 address, u32 type, u32 value, s64 nanoseconds) {
191 LOG_TRACE(Kernel_SVC, "called handle=0x%08X, address=0x%08X, type=0x%08X, value=0x%08X", arbiter,
192 address, type, value);
192 return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type), 193 return Kernel::ArbitrateAddress(arbiter, static_cast<Kernel::ArbitrationType>(type),
193 address, value).raw; 194 address, value).raw;
194} 195}
195 196
196/// Used to output a message on a debug hardware unit - does nothing on a retail unit 197/// Used to output a message on a debug hardware unit - does nothing on a retail unit
197static void OutputDebugString(const char* string) { 198static void OutputDebugString(const char* string) {
198 OS_LOG(SVC, "%s", string); 199 LOG_DEBUG(Debug_Emulated, "%s", string);
199} 200}
200 201
201/// Get resource limit 202/// Get resource limit
@@ -204,14 +205,14 @@ static Result GetResourceLimit(Handle* resource_limit, Handle process) {
204 // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for 205 // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for
205 // the current KThread. 206 // the current KThread.
206 *resource_limit = 0xDEADBEEF; 207 *resource_limit = 0xDEADBEEF;
207 ERROR_LOG(SVC, "(UNIMPLEMENTED) called process=0x%08X", process); 208 LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called process=0x%08X", process);
208 return 0; 209 return 0;
209} 210}
210 211
211/// Get resource limit current values 212/// Get resource limit current values
212static Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names, 213static Result GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names,
213 s32 name_count) { 214 s32 name_count) {
214 ERROR_LOG(SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d", 215 LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d",
215 resource_limit, names, name_count); 216 resource_limit, names, name_count);
216 Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now 217 Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now
217 return 0; 218 return 0;
@@ -232,7 +233,7 @@ static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top
232 233
233 Core::g_app_core->SetReg(1, thread); 234 Core::g_app_core->SetReg(1, thread);
234 235
235 DEBUG_LOG(SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, " 236 LOG_TRACE(Kernel_SVC, "called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
236 "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point, 237 "threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point,
237 name.c_str(), arg, stack_top, priority, processor_id, thread); 238 name.c_str(), arg, stack_top, priority, processor_id, thread);
238 239
@@ -243,7 +244,7 @@ static Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top
243static u32 ExitThread() { 244static u32 ExitThread() {
244 Handle thread = Kernel::GetCurrentThreadHandle(); 245 Handle thread = Kernel::GetCurrentThreadHandle();
245 246
246 DEBUG_LOG(SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); // PC = 0x0010545C 247 LOG_TRACE(Kernel_SVC, "called, pc=0x%08X", Core::g_app_core->GetPC()); // PC = 0x0010545C
247 248
248 Kernel::StopThread(thread, __func__); 249 Kernel::StopThread(thread, __func__);
249 HLE::Reschedule(__func__); 250 HLE::Reschedule(__func__);
@@ -267,70 +268,83 @@ static Result SetThreadPriority(Handle handle, s32 priority) {
267/// Create a mutex 268/// Create a mutex
268static Result CreateMutex(Handle* mutex, u32 initial_locked) { 269static Result CreateMutex(Handle* mutex, u32 initial_locked) {
269 *mutex = Kernel::CreateMutex((initial_locked != 0)); 270 *mutex = Kernel::CreateMutex((initial_locked != 0));
270 DEBUG_LOG(SVC, "called initial_locked=%s : created handle=0x%08X", 271 LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X",
271 initial_locked ? "true" : "false", *mutex); 272 initial_locked ? "true" : "false", *mutex);
272 return 0; 273 return 0;
273} 274}
274 275
275/// Release a mutex 276/// Release a mutex
276static Result ReleaseMutex(Handle handle) { 277static Result ReleaseMutex(Handle handle) {
277 DEBUG_LOG(SVC, "called handle=0x%08X", handle); 278 LOG_TRACE(Kernel_SVC, "called handle=0x%08X", handle);
278 ResultCode res = Kernel::ReleaseMutex(handle); 279 ResultCode res = Kernel::ReleaseMutex(handle);
279 return res.raw; 280 return res.raw;
280} 281}
281 282
282/// Get current thread ID 283/// Get the ID for the specified thread.
283static Result GetThreadId(u32* thread_id, Handle thread) { 284static Result GetThreadId(u32* thread_id, Handle handle) {
284 ERROR_LOG(SVC, "(UNIMPLEMENTED) called thread=0x%08X", thread); 285 LOG_TRACE(Kernel_SVC, "called thread=0x%08X", handle);
285 return 0; 286 ResultCode result = Kernel::GetThreadId(thread_id, handle);
287 return result.raw;
288}
289
290/// Creates a semaphore
291static Result CreateSemaphore(Handle* semaphore, s32 initial_count, s32 max_count) {
292 ResultCode res = Kernel::CreateSemaphore(semaphore, initial_count, max_count);
293 LOG_TRACE(Kernel_SVC, "called initial_count=%d, max_count=%d, created handle=0x%08X",
294 initial_count, max_count, *semaphore);
295 return res.raw;
296}
297
298/// Releases a certain number of slots in a semaphore
299static Result ReleaseSemaphore(s32* count, Handle semaphore, s32 release_count) {
300 LOG_TRACE(Kernel_SVC, "called release_count=%d, handle=0x%08X", release_count, semaphore);
301 ResultCode res = Kernel::ReleaseSemaphore(count, semaphore, release_count);
302 return res.raw;
286} 303}
287 304
288/// Query memory 305/// Query memory
289static Result QueryMemory(void* info, void* out, u32 addr) { 306static Result QueryMemory(void* info, void* out, u32 addr) {
290 ERROR_LOG(SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr); 307 LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr);
291 return 0; 308 return 0;
292} 309}
293 310
294/// Create an event 311/// Create an event
295static Result CreateEvent(Handle* evt, u32 reset_type) { 312static Result CreateEvent(Handle* evt, u32 reset_type) {
296 *evt = Kernel::CreateEvent((ResetType)reset_type); 313 *evt = Kernel::CreateEvent((ResetType)reset_type);
297 DEBUG_LOG(SVC, "called reset_type=0x%08X : created handle=0x%08X", 314 LOG_TRACE(Kernel_SVC, "called reset_type=0x%08X : created handle=0x%08X",
298 reset_type, *evt); 315 reset_type, *evt);
299 return 0; 316 return 0;
300} 317}
301 318
302/// Duplicates a kernel handle 319/// Duplicates a kernel handle
303static Result DuplicateHandle(Handle* out, Handle handle) { 320static Result DuplicateHandle(Handle* out, Handle handle) {
304 DEBUG_LOG(SVC, "called handle=0x%08X", handle); 321 ResultVal<Handle> out_h = Kernel::g_handle_table.Duplicate(handle);
305 322 if (out_h.Succeeded()) {
306 // Translate kernel handles -> real handles 323 *out = *out_h;
307 if (handle == Kernel::CurrentThread) { 324 LOG_TRACE(Kernel_SVC, "duplicated 0x%08X to 0x%08X", handle, *out);
308 handle = Kernel::GetCurrentThreadHandle();
309 } 325 }
310 _assert_msg_(KERNEL, (handle != Kernel::CurrentProcess), 326 return out_h.Code().raw;
311 "(UNIMPLEMENTED) process handle duplication!");
312
313 // TODO(bunnei): FixMe - This is a hack to return the handle that we were asked to duplicate.
314 *out = handle;
315
316 return 0;
317} 327}
318 328
319/// Signals an event 329/// Signals an event
320static Result SignalEvent(Handle evt) { 330static Result SignalEvent(Handle evt) {
321 DEBUG_LOG(SVC, "called event=0x%08X", evt); 331 LOG_TRACE(Kernel_SVC, "called event=0x%08X", evt);
322 return Kernel::SignalEvent(evt).raw; 332 return Kernel::SignalEvent(evt).raw;
323} 333}
324 334
325/// Clears an event 335/// Clears an event
326static Result ClearEvent(Handle evt) { 336static Result ClearEvent(Handle evt) {
327 DEBUG_LOG(SVC, "called event=0x%08X", evt); 337 LOG_TRACE(Kernel_SVC, "called event=0x%08X", evt);
328 return Kernel::ClearEvent(evt).raw; 338 return Kernel::ClearEvent(evt).raw;
329} 339}
330 340
331/// Sleep the current thread 341/// Sleep the current thread
332static void SleepThread(s64 nanoseconds) { 342static void SleepThread(s64 nanoseconds) {
333 DEBUG_LOG(SVC, "called nanoseconds=%lld", nanoseconds); 343 LOG_TRACE(Kernel_SVC, "called nanoseconds=%lld", nanoseconds);
344
345 // Sleep current thread and check for next thread to schedule
346 Kernel::WaitCurrentThread(WAITTYPE_SLEEP);
347 HLE::Reschedule(__func__);
334} 348}
335 349
336/// This returns the total CPU ticks elapsed since the CPU was powered-on 350/// This returns the total CPU ticks elapsed since the CPU was powered-on
@@ -360,8 +374,8 @@ const HLE::FunctionDef SVC_Table[] = {
360 {0x12, nullptr, "Run"}, 374 {0x12, nullptr, "Run"},
361 {0x13, HLE::Wrap<CreateMutex>, "CreateMutex"}, 375 {0x13, HLE::Wrap<CreateMutex>, "CreateMutex"},
362 {0x14, HLE::Wrap<ReleaseMutex>, "ReleaseMutex"}, 376 {0x14, HLE::Wrap<ReleaseMutex>, "ReleaseMutex"},
363 {0x15, nullptr, "CreateSemaphore"}, 377 {0x15, HLE::Wrap<CreateSemaphore>, "CreateSemaphore"},
364 {0x16, nullptr, "ReleaseSemaphore"}, 378 {0x16, HLE::Wrap<ReleaseSemaphore>, "ReleaseSemaphore"},
365 {0x17, HLE::Wrap<CreateEvent>, "CreateEvent"}, 379 {0x17, HLE::Wrap<CreateEvent>, "CreateEvent"},
366 {0x18, HLE::Wrap<SignalEvent>, "SignalEvent"}, 380 {0x18, HLE::Wrap<SignalEvent>, "SignalEvent"},
367 {0x19, HLE::Wrap<ClearEvent>, "ClearEvent"}, 381 {0x19, HLE::Wrap<ClearEvent>, "ClearEvent"},
diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h
index 6be393d0b..ad780818e 100644
--- a/src/core/hle/svc.h
+++ b/src/core/hle/svc.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 3ad801c63..dd619cb16 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
@@ -21,12 +21,14 @@ namespace GPU {
21 21
22Regs g_regs; 22Regs g_regs;
23 23
24u32 g_cur_line = 0; ///< Current vertical screen line 24bool g_skip_frame = false; ///< True if the current frame was skipped
25u64 g_last_line_ticks = 0; ///< CPU tick count from last vertical screen line
26u64 g_last_frame_ticks = 0; ///< CPU tick count from last frame
27 25
28static u32 kFrameCycles = 0; ///< 268MHz / 60 frames per second 26static u64 frame_ticks = 0; ///< 268MHz / gpu_refresh_rate frames per second
29static u32 kFrameTicks = 0; ///< Approximate number of instructions/frame 27static u64 line_ticks = 0; ///< Number of ticks for a screen line
28static u32 cur_line = 0; ///< Current screen line
29static u64 last_update_tick = 0; ///< CPU ticl count from last GPU update
30static u64 frame_count = 0; ///< Number of frames drawn
31static bool last_skip_frame = false; ///< True if the last frame was skipped
30 32
31template <typename T> 33template <typename T>
32inline void Read(T &var, const u32 raw_addr) { 34inline void Read(T &var, const u32 raw_addr) {
@@ -34,8 +36,8 @@ inline void Read(T &var, const u32 raw_addr) {
34 u32 index = addr / 4; 36 u32 index = addr / 4;
35 37
36 // Reads other than u32 are untested, so I'd rather have them abort than silently fail 38 // Reads other than u32 are untested, so I'd rather have them abort than silently fail
37 if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { 39 if (index >= Regs::NumIds() || !std::is_same<T, u32>::value) {
38 ERROR_LOG(GPU, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); 40 LOG_ERROR(HW_GPU, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
39 return; 41 return;
40 } 42 }
41 43
@@ -48,8 +50,8 @@ inline void Write(u32 addr, const T data) {
48 u32 index = addr / 4; 50 u32 index = addr / 4;
49 51
50 // Writes other than u32 are untested, so I'd rather have them abort than silently fail 52 // Writes other than u32 are untested, so I'd rather have them abort than silently fail
51 if (index >= Regs::NumIds() || !std::is_same<T,u32>::value) { 53 if (index >= Regs::NumIds() || !std::is_same<T, u32>::value) {
52 ERROR_LOG(GPU, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); 54 LOG_ERROR(HW_GPU, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr);
53 return; 55 return;
54 } 56 }
55 57
@@ -73,7 +75,7 @@ inline void Write(u32 addr, const T data) {
73 for (u32* ptr = start; ptr < end; ++ptr) 75 for (u32* ptr = start; ptr < end; ++ptr)
74 *ptr = bswap32(config.value); // TODO: This is just a workaround to missing framebuffer format emulation 76 *ptr = bswap32(config.value); // TODO: This is just a workaround to missing framebuffer format emulation
75 77
76 DEBUG_LOG(GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress()); 78 LOG_TRACE(HW_GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress());
77 } 79 }
78 break; 80 break;
79 } 81 }
@@ -105,7 +107,7 @@ inline void Write(u32 addr, const T data) {
105 } 107 }
106 108
107 default: 109 default:
108 ERROR_LOG(GPU, "Unknown source framebuffer format %x", config.input_format.Value()); 110 LOG_ERROR(HW_GPU, "Unknown source framebuffer format %x", config.input_format.Value());
109 break; 111 break;
110 } 112 }
111 113
@@ -132,16 +134,16 @@ inline void Write(u32 addr, const T data) {
132 } 134 }
133 135
134 default: 136 default:
135 ERROR_LOG(GPU, "Unknown destination framebuffer format %x", config.output_format.Value()); 137 LOG_ERROR(HW_GPU, "Unknown destination framebuffer format %x", config.output_format.Value());
136 break; 138 break;
137 } 139 }
138 } 140 }
139 } 141 }
140 142
141 DEBUG_LOG(GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x", 143 LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), dst format %x",
142 config.output_height * config.output_width * 4, 144 config.output_height * config.output_width * 4,
143 config.GetPhysicalInputAddress(), config.input_width, config.input_height, 145 config.GetPhysicalInputAddress(), (u32)config.input_width, (u32)config.input_height,
144 config.GetPhysicalOutputAddress(), config.output_width, config.output_height, 146 config.GetPhysicalOutputAddress(), (u32)config.output_width, (u32)config.output_height,
145 config.output_format.Value()); 147 config.output_format.Value());
146 } 148 }
147 break; 149 break;
@@ -154,8 +156,7 @@ inline void Write(u32 addr, const T data) {
154 if (config.trigger & 1) 156 if (config.trigger & 1)
155 { 157 {
156 u32* buffer = (u32*)Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalAddress())); 158 u32* buffer = (u32*)Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalAddress()));
157 u32 size = config.size << 3; 159 Pica::CommandProcessor::ProcessCommandList(buffer, config.size);
158 Pica::CommandProcessor::ProcessCommandList(buffer, size);
159 } 160 }
160 break; 161 break;
161 } 162 }
@@ -180,37 +181,41 @@ template void Write<u8>(u32 addr, const u8 data);
180/// Update hardware 181/// Update hardware
181void Update() { 182void Update() {
182 auto& framebuffer_top = g_regs.framebuffer_config[0]; 183 auto& framebuffer_top = g_regs.framebuffer_config[0];
183 u64 current_ticks = Core::g_app_core->GetTicks();
184
185 // Update the frame after a certain number of CPU ticks have elapsed. This assumes that the
186 // active frame in memory is always complete to render. There also may be issues with this
187 // becoming out-of-synch with GSP synchrinization code (as follows). At this time, this seems to
188 // be the most effective solution for both homebrew and retail applications. With retail, this
189 // could be moved below (and probably would guarantee more accurate synchronization). However,
190 // primitive homebrew relies on a vertical blank interrupt to happen inevitably (regardless of a
191 // threading reschedule).
192
193 if ((current_ticks - g_last_frame_ticks) > GPU::kFrameTicks) {
194 VideoCore::g_renderer->SwapBuffers();
195 g_last_frame_ticks = current_ticks;
196 }
197 184
198 // Synchronize GPU on a thread reschedule: Because we cannot accurately predict a vertical 185 // Synchronize GPU on a thread reschedule: Because we cannot accurately predict a vertical
199 // blank, we need to simulate it. Based on testing, it seems that retail applications work more 186 // blank, we need to simulate it. Based on testing, it seems that retail applications work more
200 // accurately when this is signalled between thread switches. 187 // accurately when this is signalled between thread switches.
201 188
202 if (HLE::g_reschedule) { 189 if (HLE::g_reschedule) {
190 u64 current_ticks = Core::g_app_core->GetTicks();
191 u32 num_lines = static_cast<u32>((current_ticks - last_update_tick) / line_ticks);
203 192
204 // Synchronize line... 193 // Synchronize line...
205 if ((current_ticks - g_last_line_ticks) >= GPU::kFrameTicks / framebuffer_top.height) { 194 if (num_lines > 0) {
206 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0); 195 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0);
207 g_cur_line++; 196 cur_line += num_lines;
208 g_last_line_ticks = current_ticks; 197 last_update_tick += (num_lines * line_ticks);
209 } 198 }
210 199
211 // Synchronize frame... 200 // Synchronize frame...
212 if (g_cur_line >= framebuffer_top.height) { 201 if (cur_line >= framebuffer_top.height) {
213 g_cur_line = 0; 202 cur_line = 0;
203 frame_count++;
204 last_skip_frame = g_skip_frame;
205 g_skip_frame = (frame_count & Settings::values.frame_skip) != 0;
206
207 // Swap buffers based on the frameskip mode, which is a little bit tricky. When
208 // a frame is being skipped, nothing is being rendered to the internal framebuffer(s).
209 // So, we should only swap frames if the last frame was rendered. The rules are:
210 // - If frameskip == 0 (disabled), always swap buffers
211 // - If frameskip == 1, swap buffers every other frame (starting from the first frame)
212 // - If frameskip > 1, swap buffers every frameskip^n frames (starting from the second frame)
213
214 if ((((Settings::values.frame_skip != 1) ^ last_skip_frame) && last_skip_frame != g_skip_frame) ||
215 Settings::values.frame_skip == 0) {
216 VideoCore::g_renderer->SwapBuffers();
217 }
218
214 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1); 219 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1);
215 } 220 }
216 } 221 }
@@ -218,12 +223,6 @@ void Update() {
218 223
219/// Initialize hardware 224/// Initialize hardware
220void Init() { 225void Init() {
221 kFrameCycles = 268123480 / Settings::values.gpu_refresh_rate;
222 kFrameTicks = kFrameCycles / 3;
223
224 g_cur_line = 0;
225 g_last_frame_ticks = g_last_line_ticks = Core::g_app_core->GetTicks();
226
227 auto& framebuffer_top = g_regs.framebuffer_config[0]; 226 auto& framebuffer_top = g_regs.framebuffer_config[0];
228 auto& framebuffer_sub = g_regs.framebuffer_config[1]; 227 auto& framebuffer_sub = g_regs.framebuffer_config[1];
229 228
@@ -252,12 +251,19 @@ void Init() {
252 framebuffer_sub.color_format = Regs::PixelFormat::RGB8; 251 framebuffer_sub.color_format = Regs::PixelFormat::RGB8;
253 framebuffer_sub.active_fb = 0; 252 framebuffer_sub.active_fb = 0;
254 253
255 NOTICE_LOG(GPU, "initialized OK"); 254 frame_ticks = 268123480 / Settings::values.gpu_refresh_rate;
255 line_ticks = (GPU::frame_ticks / framebuffer_top.height);
256 cur_line = 0;
257 last_update_tick = Core::g_app_core->GetTicks();
258 last_skip_frame = false;
259 g_skip_frame = false;
260
261 LOG_DEBUG(HW_GPU, "initialized OK");
256} 262}
257 263
258/// Shutdown hardware 264/// Shutdown hardware
259void Shutdown() { 265void Shutdown() {
260 NOTICE_LOG(GPU, "shutdown OK"); 266 LOG_DEBUG(HW_GPU, "shutdown OK");
261} 267}
262 268
263} // namespace 269} // namespace
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index 3fa7b9ccf..292f496c1 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -169,7 +169,7 @@ struct Regs {
169 INSERT_PADDING_WORDS(0x331); 169 INSERT_PADDING_WORDS(0x331);
170 170
171 struct { 171 struct {
172 // command list size 172 // command list size (in bytes)
173 u32 size; 173 u32 size;
174 174
175 INSERT_PADDING_WORDS(0x1); 175 INSERT_PADDING_WORDS(0x1);
@@ -241,6 +241,7 @@ ASSERT_REG_POSITION(command_processor_config, 0x00638);
241static_assert(sizeof(Regs) == 0x1000 * sizeof(u32), "Invalid total size of register set"); 241static_assert(sizeof(Regs) == 0x1000 * sizeof(u32), "Invalid total size of register set");
242 242
243extern Regs g_regs; 243extern Regs g_regs;
244extern bool g_skip_frame;
244 245
245template <typename T> 246template <typename T>
246void Read(T &var, const u32 addr); 247void Read(T &var, const u32 addr);
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp
index 4d0719263..848ab5348 100644
--- a/src/core/hw/hw.cpp
+++ b/src/core/hw/hw.cpp
@@ -1,12 +1,11 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h" 5#include "common/common_types.h"
6 6
7#include "core/hw/hw.h" 7#include "core/hw/hw.h"
8#include "core/hw/gpu.h" 8#include "core/hw/gpu.h"
9#include "core/hw/ndma.h"
10 9
11namespace HW { 10namespace HW {
12 11
@@ -40,17 +39,12 @@ template <typename T>
40inline void Read(T &var, const u32 addr) { 39inline void Read(T &var, const u32 addr) {
41 switch (addr & 0xFFFFF000) { 40 switch (addr & 0xFFFFF000) {
42 41
43 // TODO(bunnei): What is the virtual address of NDMA?
44 // case VADDR_NDMA:
45 // NDMA::Read(var, addr);
46 // break;
47
48 case VADDR_GPU: 42 case VADDR_GPU:
49 GPU::Read(var, addr); 43 GPU::Read(var, addr);
50 break; 44 break;
51 45
52 default: 46 default:
53 ERROR_LOG(HW, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); 47 LOG_ERROR(HW_Memory, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
54 } 48 }
55} 49}
56 50
@@ -58,17 +52,12 @@ template <typename T>
58inline void Write(u32 addr, const T data) { 52inline void Write(u32 addr, const T data) {
59 switch (addr & 0xFFFFF000) { 53 switch (addr & 0xFFFFF000) {
60 54
61 // TODO(bunnei): What is the virtual address of NDMA?
62 // case VADDR_NDMA
63 // NDMA::Write(addr, data);
64 // break;
65
66 case VADDR_GPU: 55 case VADDR_GPU:
67 GPU::Write(addr, data); 56 GPU::Write(addr, data);
68 break; 57 break;
69 58
70 default: 59 default:
71 ERROR_LOG(HW, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr); 60 LOG_ERROR(HW_Memory, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr);
72 } 61 }
73} 62}
74 63
@@ -87,19 +76,17 @@ template void Write<u8>(u32 addr, const u8 data);
87/// Update hardware 76/// Update hardware
88void Update() { 77void Update() {
89 GPU::Update(); 78 GPU::Update();
90 NDMA::Update();
91} 79}
92 80
93/// Initialize hardware 81/// Initialize hardware
94void Init() { 82void Init() {
95 GPU::Init(); 83 GPU::Init();
96 NDMA::Init(); 84 LOG_DEBUG(HW, "initialized OK");
97 NOTICE_LOG(HW, "initialized OK");
98} 85}
99 86
100/// Shutdown hardware 87/// Shutdown hardware
101void Shutdown() { 88void Shutdown() {
102 NOTICE_LOG(HW, "shutdown OK"); 89 LOG_DEBUG(HW, "shutdown OK");
103} 90}
104 91
105} \ No newline at end of file 92} \ No newline at end of file
diff --git a/src/core/hw/hw.h b/src/core/hw/hw.h
index 1055ed94f..991c0a07d 100644
--- a/src/core/hw/hw.h
+++ b/src/core/hw/hw.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/core/hw/ndma.cpp b/src/core/hw/ndma.cpp
deleted file mode 100644
index e29a773f1..000000000
--- a/src/core/hw/ndma.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "common/common_types.h"
6
7#include "core/hw/ndma.h"
8
9namespace NDMA {
10
11template <typename T>
12inline void Read(T &var, const u32 addr) {
13 ERROR_LOG(NDMA, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
14}
15
16template <typename T>
17inline void Write(u32 addr, const T data) {
18 ERROR_LOG(NDMA, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, data, addr);
19}
20
21// Explicitly instantiate template functions because we aren't defining this in the header:
22
23template void Read<u64>(u64 &var, const u32 addr);
24template void Read<u32>(u32 &var, const u32 addr);
25template void Read<u16>(u16 &var, const u32 addr);
26template void Read<u8>(u8 &var, const u32 addr);
27
28template void Write<u64>(u32 addr, const u64 data);
29template void Write<u32>(u32 addr, const u32 data);
30template void Write<u16>(u32 addr, const u16 data);
31template void Write<u8>(u32 addr, const u8 data);
32
33/// Update hardware
34void Update() {
35}
36
37/// Initialize hardware
38void Init() {
39 NOTICE_LOG(GPU, "initialized OK");
40}
41
42/// Shutdown hardware
43void Shutdown() {
44 NOTICE_LOG(GPU, "shutdown OK");
45}
46
47} // namespace
diff --git a/src/core/hw/ndma.h b/src/core/hw/ndma.h
deleted file mode 100644
index d8fa3d40b..000000000
--- a/src/core/hw/ndma.h
+++ /dev/null
@@ -1,26 +0,0 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8
9namespace NDMA {
10
11template <typename T>
12inline void Read(T &var, const u32 addr);
13
14template <typename T>
15inline void Write(u32 addr, const T data);
16
17/// Update hardware
18void Update();
19
20/// Initialize hardware
21void Init();
22
23/// Shutdown hardware
24void Shutdown();
25
26} // namespace
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
new file mode 100644
index 000000000..4d072871a
--- /dev/null
+++ b/src/core/loader/3dsx.cpp
@@ -0,0 +1,234 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6#include <vector>
7
8#include "core/file_sys/archive_romfs.h"
9#include "core/loader/elf.h"
10#include "core/loader/ncch.h"
11#include "core/hle/service/fs/archive.h"
12#include "core/mem_map.h"
13
14#include "3dsx.h"
15
16
17namespace Loader {
18
19
20/**
21 * File layout:
22 * - File header
23 * - Code, rodata and data relocation table headers
24 * - Code segment
25 * - Rodata segment
26 * - Loadable (non-BSS) part of the data segment
27 * - Code relocation table
28 * - Rodata relocation table
29 * - Data relocation table
30 *
31 * Memory layout before relocations are applied:
32 * [0..codeSegSize) -> code segment
33 * [codeSegSize..rodataSegSize) -> rodata segment
34 * [rodataSegSize..dataSegSize) -> data segment
35 *
36 * Memory layout after relocations are applied: well, however the loader sets it up :)
37 * The entrypoint is always the start of the code segment.
38 * The BSS section must be cleared manually by the application.
39 */
40enum THREEDSX_Error {
41 ERROR_NONE = 0,
42 ERROR_READ = 1,
43 ERROR_FILE = 2,
44 ERROR_ALLOC = 3
45};
46static const u32 RELOCBUFSIZE = 512;
47
48// File header
49static const u32 THREEDSX_MAGIC = 0x58534433; // '3DSX'
50#pragma pack(1)
51struct THREEDSX_Header
52{
53 u32 magic;
54 u16 header_size, reloc_hdr_size;
55 u32 format_ver;
56 u32 flags;
57
58 // Sizes of the code, rodata and data segments +
59 // size of the BSS section (uninitialized latter half of the data segment)
60 u32 code_seg_size, rodata_seg_size, data_seg_size, bss_size;
61};
62
63// Relocation header: all fields (even extra unknown fields) are guaranteed to be relocation counts.
64struct THREEDSX_RelocHdr
65{
66 // # of absolute relocations (that is, fix address to post-relocation memory layout)
67 u32 cross_segment_absolute;
68 // # of cross-segment relative relocations (that is, 32bit signed offsets that need to be patched)
69 u32 cross_segment_relative;
70 // more?
71
72 // Relocations are written in this order:
73 // - Absolute relocations
74 // - Relative relocations
75};
76
77// Relocation entry: from the current pointer, skip X words and patch Y words
78struct THREEDSX_Reloc
79{
80 u16 skip, patch;
81};
82#pragma pack()
83
84struct THREEloadinfo
85{
86 u8* seg_ptrs[3]; // code, rodata & data
87 u32 seg_addrs[3];
88 u32 seg_sizes[3];
89};
90
91class THREEDSXReader {
92public:
93 static int Load3DSXFile(const std::string& filename, u32 base_addr);
94};
95
96static u32 TranslateAddr(u32 addr, THREEloadinfo *loadinfo, u32* offsets)
97{
98 if (addr < offsets[0])
99 return loadinfo->seg_addrs[0] + addr;
100 if (addr < offsets[1])
101 return loadinfo->seg_addrs[1] + addr - offsets[0];
102 return loadinfo->seg_addrs[2] + addr - offsets[1];
103}
104
105int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr)
106{
107 FileUtil::IOFile file(filename, "rb");
108 if (!file.IsOpen()) {
109 return ERROR_FILE;
110 }
111 THREEDSX_Header hdr;
112 if (file.ReadBytes(&hdr, sizeof(hdr)) != sizeof(hdr))
113 return ERROR_READ;
114
115 THREEloadinfo loadinfo;
116 //loadinfo segments must be a multiple of 0x1000
117 loadinfo.seg_sizes[0] = (hdr.code_seg_size + 0xFFF) &~0xFFF;
118 loadinfo.seg_sizes[1] = (hdr.rodata_seg_size + 0xFFF) &~0xFFF;
119 loadinfo.seg_sizes[2] = (hdr.data_seg_size + 0xFFF) &~0xFFF;
120 u32 offsets[2] = { loadinfo.seg_sizes[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] };
121 u32 data_load_size = (hdr.data_seg_size - hdr.bss_size + 0xFFF) &~0xFFF;
122 u32 bss_load_size = loadinfo.seg_sizes[2] - data_load_size;
123 u32 n_reloc_tables = hdr.reloc_hdr_size / 4;
124 std::vector<u8> all_mem(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2] + 3 * n_reloc_tables);
125
126 loadinfo.seg_addrs[0] = base_addr;
127 loadinfo.seg_addrs[1] = loadinfo.seg_addrs[0] + loadinfo.seg_sizes[0];
128 loadinfo.seg_addrs[2] = loadinfo.seg_addrs[1] + loadinfo.seg_sizes[1];
129 loadinfo.seg_ptrs[0] = &all_mem[0];
130 loadinfo.seg_ptrs[1] = loadinfo.seg_ptrs[0] + loadinfo.seg_sizes[0];
131 loadinfo.seg_ptrs[2] = loadinfo.seg_ptrs[1] + loadinfo.seg_sizes[1];
132
133 // Skip header for future compatibility
134 file.Seek(hdr.header_size, SEEK_SET);
135
136 // Read the relocation headers
137 u32* relocs = (u32*)(loadinfo.seg_ptrs[2] + hdr.data_seg_size);
138
139 for (u32 current_segment = 0; current_segment < 3; current_segment++) {
140 if (file.ReadBytes(&relocs[current_segment*n_reloc_tables], n_reloc_tables * 4) != n_reloc_tables * 4)
141 return ERROR_READ;
142 }
143
144 // Read the segments
145 if (file.ReadBytes(loadinfo.seg_ptrs[0], hdr.code_seg_size) != hdr.code_seg_size)
146 return ERROR_READ;
147 if (file.ReadBytes(loadinfo.seg_ptrs[1], hdr.rodata_seg_size) != hdr.rodata_seg_size)
148 return ERROR_READ;
149 if (file.ReadBytes(loadinfo.seg_ptrs[2], hdr.data_seg_size - hdr.bss_size) != hdr.data_seg_size - hdr.bss_size)
150 return ERROR_READ;
151
152 // BSS clear
153 memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size);
154
155 // Relocate the segments
156 for (u32 current_segment = 0; current_segment < 3; current_segment++) {
157 for (u32 current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) {
158 u32 n_relocs = relocs[current_segment*n_reloc_tables + current_segment_reloc_table];
159 if (current_segment_reloc_table >= 2) {
160 // We are not using this table - ignore it because we don't know what it dose
161 file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR);
162 continue;
163 }
164 static THREEDSX_Reloc reloc_table[RELOCBUFSIZE];
165
166 u32* pos = (u32*)loadinfo.seg_ptrs[current_segment];
167 u32* end_pos = pos + (loadinfo.seg_sizes[current_segment] / 4);
168
169 while (n_relocs) {
170 u32 remaining = std::min(RELOCBUFSIZE, n_relocs);
171 n_relocs -= remaining;
172
173 if (file.ReadBytes(reloc_table, remaining*sizeof(THREEDSX_Reloc)) != remaining*sizeof(THREEDSX_Reloc))
174 return ERROR_READ;
175
176 for (u32 current_inprogress = 0; current_inprogress < remaining && pos < end_pos; current_inprogress++) {
177 LOG_TRACE(Loader, "(t=%d,skip=%u,patch=%u)\n",
178 current_segment_reloc_table, (u32)reloc_table[current_inprogress].skip, (u32)reloc_table[current_inprogress].patch);
179 pos += reloc_table[current_inprogress].skip;
180 s32 num_patches = reloc_table[current_inprogress].patch;
181 while (0 < num_patches && pos < end_pos) {
182 u32 in_addr = (char*)pos - (char*)&all_mem[0];
183 u32 addr = TranslateAddr(*pos, &loadinfo, offsets);
184 LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)\n",
185 base_addr + in_addr, addr, current_segment_reloc_table, *pos);
186 switch (current_segment_reloc_table) {
187 case 0: *pos = (addr); break;
188 case 1: *pos = (addr - in_addr); break;
189 default: break; //this should never happen
190 }
191 pos++;
192 num_patches--;
193 }
194 }
195 }
196 }
197 }
198
199 // Write the data
200 memcpy(Memory::GetPointer(base_addr), &all_mem[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2]);
201
202 LOG_DEBUG(Loader, "CODE: %u pages\n", loadinfo.seg_sizes[0] / 0x1000);
203 LOG_DEBUG(Loader, "RODATA: %u pages\n", loadinfo.seg_sizes[1] / 0x1000);
204 LOG_DEBUG(Loader, "DATA: %u pages\n", data_load_size / 0x1000);
205 LOG_DEBUG(Loader, "BSS: %u pages\n", bss_load_size / 0x1000);
206
207 return ERROR_NONE;
208}
209
210 /// AppLoader_DSX constructor
211 AppLoader_THREEDSX::AppLoader_THREEDSX(const std::string& filename) : filename(filename) {
212 }
213
214 /// AppLoader_DSX destructor
215 AppLoader_THREEDSX::~AppLoader_THREEDSX() {
216 }
217
218 /**
219 * Loads a 3DSX file
220 * @return Success on success, otherwise Error
221 */
222 ResultStatus AppLoader_THREEDSX::Load() {
223 LOG_INFO(Loader, "Loading 3DSX file %s...", filename.c_str());
224 FileUtil::IOFile file(filename, "rb");
225 if (file.IsOpen()) {
226 THREEDSXReader::Load3DSXFile(filename, 0x00100000);
227 Kernel::LoadExec(0x00100000);
228 } else {
229 return ResultStatus::Error;
230 }
231 return ResultStatus::Success;
232 }
233
234} // namespace Loader
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h
new file mode 100644
index 000000000..da8836662
--- /dev/null
+++ b/src/core/loader/3dsx.h
@@ -0,0 +1,32 @@
1// Copyright 2014 Dolphin Emulator Project / Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "core/loader/loader.h"
9
10////////////////////////////////////////////////////////////////////////////////////////////////////
11// Loader namespace
12
13namespace Loader {
14
15/// Loads an 3DSX file
16class AppLoader_THREEDSX final : public AppLoader {
17public:
18 AppLoader_THREEDSX(const std::string& filename);
19 ~AppLoader_THREEDSX() override;
20
21 /**
22 * Load the bootable file
23 * @return ResultStatus result of function
24 */
25 ResultStatus Load() override;
26
27private:
28 std::string filename;
29 bool is_loaded;
30};
31
32} // namespace Loader
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 63d2496ed..354335014 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <string> 5#include <string>
@@ -254,18 +254,18 @@ const char *ElfReader::GetSectionName(int section) const {
254} 254}
255 255
256bool ElfReader::LoadInto(u32 vaddr) { 256bool ElfReader::LoadInto(u32 vaddr) {
257 DEBUG_LOG(MASTER_LOG, "String section: %i", header->e_shstrndx); 257 LOG_DEBUG(Loader, "String section: %i", header->e_shstrndx);
258 258
259 // Should we relocate? 259 // Should we relocate?
260 relocate = (header->e_type != ET_EXEC); 260 relocate = (header->e_type != ET_EXEC);
261 261
262 if (relocate) { 262 if (relocate) {
263 DEBUG_LOG(MASTER_LOG, "Relocatable module"); 263 LOG_DEBUG(Loader, "Relocatable module");
264 entryPoint += vaddr; 264 entryPoint += vaddr;
265 } else { 265 } else {
266 DEBUG_LOG(MASTER_LOG, "Prerelocated executable"); 266 LOG_DEBUG(Loader, "Prerelocated executable");
267 } 267 }
268 INFO_LOG(MASTER_LOG, "%i segments:", header->e_phnum); 268 LOG_DEBUG(Loader, "%i segments:", header->e_phnum);
269 269
270 // First pass : Get the bits into RAM 270 // First pass : Get the bits into RAM
271 u32 segment_addr[32]; 271 u32 segment_addr[32];
@@ -273,17 +273,17 @@ bool ElfReader::LoadInto(u32 vaddr) {
273 273
274 for (int i = 0; i < header->e_phnum; i++) { 274 for (int i = 0; i < header->e_phnum; i++) {
275 Elf32_Phdr *p = segments + i; 275 Elf32_Phdr *p = segments + i;
276 INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, 276 LOG_DEBUG(Loader, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr,
277 p->p_filesz, p->p_memsz); 277 p->p_filesz, p->p_memsz);
278 278
279 if (p->p_type == PT_LOAD) { 279 if (p->p_type == PT_LOAD) {
280 segment_addr[i] = base_addr + p->p_vaddr; 280 segment_addr[i] = base_addr + p->p_vaddr;
281 memcpy(Memory::GetPointer(segment_addr[i]), GetSegmentPtr(i), p->p_filesz); 281 memcpy(Memory::GetPointer(segment_addr[i]), GetSegmentPtr(i), p->p_filesz);
282 INFO_LOG(MASTER_LOG, "Loadable Segment Copied to %08x, size %08x", segment_addr[i], 282 LOG_DEBUG(Loader, "Loadable Segment Copied to %08x, size %08x", segment_addr[i],
283 p->p_memsz); 283 p->p_memsz);
284 } 284 }
285 } 285 }
286 INFO_LOG(MASTER_LOG, "Done loading."); 286 LOG_DEBUG(Loader, "Done loading.");
287 return true; 287 return true;
288} 288}
289 289
@@ -346,7 +346,7 @@ AppLoader_ELF::~AppLoader_ELF() {
346 * @return True on success, otherwise false 346 * @return True on success, otherwise false
347 */ 347 */
348ResultStatus AppLoader_ELF::Load() { 348ResultStatus AppLoader_ELF::Load() {
349 INFO_LOG(LOADER, "Loading ELF file %s...", filename.c_str()); 349 LOG_INFO(Loader, "Loading ELF file %s...", filename.c_str());
350 350
351 if (is_loaded) 351 if (is_loaded)
352 return ResultStatus::ErrorAlreadyLoaded; 352 return ResultStatus::ErrorAlreadyLoaded;
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 5ae88439a..c221cce6d 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -1,5 +1,5 @@
1// Copyright 2013 Dolphin Emulator Project / Citra Emulator Project 1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index a268e021a..87580cb2a 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -1,13 +1,16 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <memory> 5#include <string>
6
7#include "common/make_unique.h"
6 8
7#include "core/file_sys/archive_romfs.h" 9#include "core/file_sys/archive_romfs.h"
10#include "core/loader/3dsx.h"
8#include "core/loader/elf.h" 11#include "core/loader/elf.h"
9#include "core/loader/ncch.h" 12#include "core/loader/ncch.h"
10#include "core/hle/kernel/archive.h" 13#include "core/hle/service/fs/archive.h"
11#include "core/mem_map.h" 14#include "core/mem_map.h"
12 15
13//////////////////////////////////////////////////////////////////////////////////////////////////// 16////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -22,7 +25,7 @@ namespace Loader {
22 */ 25 */
23FileType IdentifyFile(const std::string &filename) { 26FileType IdentifyFile(const std::string &filename) {
24 if (filename.size() == 0) { 27 if (filename.size() == 0) {
25 ERROR_LOG(LOADER, "invalid filename %s", filename.c_str()); 28 LOG_ERROR(Loader, "invalid filename %s", filename.c_str());
26 return FileType::Error; 29 return FileType::Error;
27 } 30 }
28 31
@@ -42,6 +45,8 @@ FileType IdentifyFile(const std::string &filename) {
42 return FileType::CCI; 45 return FileType::CCI;
43 } else if (extension == ".bin") { 46 } else if (extension == ".bin") {
44 return FileType::BIN; 47 return FileType::BIN;
48 } else if (extension == ".3dsx") {
49 return FileType::THREEDSX;
45 } 50 }
46 return FileType::Unknown; 51 return FileType::Unknown;
47} 52}
@@ -52,10 +57,14 @@ FileType IdentifyFile(const std::string &filename) {
52 * @return ResultStatus result of function 57 * @return ResultStatus result of function
53 */ 58 */
54ResultStatus LoadFile(const std::string& filename) { 59ResultStatus LoadFile(const std::string& filename) {
55 INFO_LOG(LOADER, "Loading file %s...", filename.c_str()); 60 LOG_INFO(Loader, "Loading file %s...", filename.c_str());
56 61
57 switch (IdentifyFile(filename)) { 62 switch (IdentifyFile(filename)) {
58 63
64 //3DSX file format...
65 case FileType::THREEDSX:
66 return AppLoader_THREEDSX(filename).Load();
67
59 // Standard ELF file format... 68 // Standard ELF file format...
60 case FileType::ELF: 69 case FileType::ELF:
61 return AppLoader_ELF(filename).Load(); 70 return AppLoader_ELF(filename).Load();
@@ -67,7 +76,8 @@ ResultStatus LoadFile(const std::string& filename) {
67 76
68 // Load application and RomFS 77 // Load application and RomFS
69 if (ResultStatus::Success == app_loader.Load()) { 78 if (ResultStatus::Success == app_loader.Load()) {
70 Kernel::CreateArchive(new FileSys::Archive_RomFS(app_loader), "RomFS"); 79 Kernel::g_program_id = app_loader.GetProgramId();
80 Service::FS::CreateArchive(Common::make_unique<FileSys::Archive_RomFS>(app_loader), Service::FS::ArchiveIdCode::RomFS);
71 return ResultStatus::Success; 81 return ResultStatus::Success;
72 } 82 }
73 break; 83 break;
@@ -76,7 +86,7 @@ ResultStatus LoadFile(const std::string& filename) {
76 // Raw BIN file format... 86 // Raw BIN file format...
77 case FileType::BIN: 87 case FileType::BIN:
78 { 88 {
79 INFO_LOG(LOADER, "Loading BIN file %s...", filename.c_str()); 89 LOG_INFO(Loader, "Loading BIN file %s...", filename.c_str());
80 90
81 FileUtil::IOFile file(filename, "rb"); 91 FileUtil::IOFile file(filename, "rb");
82 92
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 68f843005..ec5534d41 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -22,6 +22,7 @@ enum class FileType {
22 CIA, 22 CIA,
23 ELF, 23 ELF,
24 BIN, 24 BIN,
25 THREEDSX, //3DSX
25}; 26};
26 27
27/// Return type for functions in Loader namespace 28/// Return type for functions in Loader namespace
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 343bb7523..0dc21699e 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <memory> 5#include <memory>
@@ -140,13 +140,13 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>&
140 // Iterate through the ExeFs archive until we find the .code file... 140 // Iterate through the ExeFs archive until we find the .code file...
141 FileUtil::IOFile file(filename, "rb"); 141 FileUtil::IOFile file(filename, "rb");
142 if (file.IsOpen()) { 142 if (file.IsOpen()) {
143 LOG_DEBUG(Loader, "%d sections:", kMaxSections);
143 for (int i = 0; i < kMaxSections; i++) { 144 for (int i = 0; i < kMaxSections; i++) {
144 // Load the specified section... 145 // Load the specified section...
145 if (strcmp((const char*)exefs_header.section[i].name, name) == 0) { 146 if (strcmp((const char*)exefs_header.section[i].name, name) == 0) {
146 INFO_LOG(LOADER, "ExeFS section %d:", i); 147 LOG_DEBUG(Loader, "%d - offset: 0x%08X, size: 0x%08X, name: %s", i,
147 INFO_LOG(LOADER, " name: %s", exefs_header.section[i].name); 148 exefs_header.section[i].offset, exefs_header.section[i].size,
148 INFO_LOG(LOADER, " offset: 0x%08X", exefs_header.section[i].offset); 149 exefs_header.section[i].name);
149 INFO_LOG(LOADER, " size: 0x%08X", exefs_header.section[i].size);
150 150
151 s64 section_offset = (exefs_header.section[i].offset + exefs_offset + 151 s64 section_offset = (exefs_header.section[i].offset + exefs_offset +
152 sizeof(ExeFs_Header)+ncch_offset); 152 sizeof(ExeFs_Header)+ncch_offset);
@@ -181,7 +181,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>&
181 } 181 }
182 } 182 }
183 } else { 183 } else {
184 ERROR_LOG(LOADER, "Unable to read file %s!", filename.c_str()); 184 LOG_ERROR(Loader, "Unable to read file %s!", filename.c_str());
185 return ResultStatus::Error; 185 return ResultStatus::Error;
186 } 186 }
187 return ResultStatus::ErrorNotUsed; 187 return ResultStatus::ErrorNotUsed;
@@ -194,7 +194,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>&
194 * @return True on success, otherwise false 194 * @return True on success, otherwise false
195 */ 195 */
196ResultStatus AppLoader_NCCH::Load() { 196ResultStatus AppLoader_NCCH::Load() {
197 INFO_LOG(LOADER, "Loading NCCH file %s...", filename.c_str()); 197 LOG_INFO(Loader, "Loading NCCH file %s...", filename.c_str());
198 198
199 if (is_loaded) 199 if (is_loaded)
200 return ResultStatus::ErrorAlreadyLoaded; 200 return ResultStatus::ErrorAlreadyLoaded;
@@ -205,7 +205,7 @@ ResultStatus AppLoader_NCCH::Load() {
205 205
206 // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)... 206 // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)...
207 if (0 == memcmp(&ncch_header.magic, "NCSD", 4)) { 207 if (0 == memcmp(&ncch_header.magic, "NCSD", 4)) {
208 WARN_LOG(LOADER, "Only loading the first (bootable) NCCH within the NCSD file!"); 208 LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
209 ncch_offset = 0x4000; 209 ncch_offset = 0x4000;
210 file.Seek(ncch_offset, 0); 210 file.Seek(ncch_offset, 0);
211 file.ReadBytes(&ncch_header, sizeof(NCCH_Header)); 211 file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
@@ -222,17 +222,17 @@ ResultStatus AppLoader_NCCH::Load() {
222 is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1; 222 is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1;
223 entry_point = exheader_header.codeset_info.text.address; 223 entry_point = exheader_header.codeset_info.text.address;
224 224
225 INFO_LOG(LOADER, "Name: %s", exheader_header.codeset_info.name); 225 LOG_INFO(Loader, "Name: %s", exheader_header.codeset_info.name);
226 INFO_LOG(LOADER, "Code compressed: %s", is_compressed ? "yes" : "no"); 226 LOG_DEBUG(Loader, "Code compressed: %s", is_compressed ? "yes" : "no");
227 INFO_LOG(LOADER, "Entry point: 0x%08X", entry_point); 227 LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point);
228 228
229 // Read ExeFS... 229 // Read ExeFS...
230 230
231 exefs_offset = ncch_header.exefs_offset * kBlockSize; 231 exefs_offset = ncch_header.exefs_offset * kBlockSize;
232 u32 exefs_size = ncch_header.exefs_size * kBlockSize; 232 u32 exefs_size = ncch_header.exefs_size * kBlockSize;
233 233
234 INFO_LOG(LOADER, "ExeFS offset: 0x%08X", exefs_offset); 234 LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset);
235 INFO_LOG(LOADER, "ExeFS size: 0x%08X", exefs_size); 235 LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size);
236 236
237 file.Seek(exefs_offset + ncch_offset, 0); 237 file.Seek(exefs_offset + ncch_offset, 0);
238 file.ReadBytes(&exefs_header, sizeof(ExeFs_Header)); 238 file.ReadBytes(&exefs_header, sizeof(ExeFs_Header));
@@ -243,7 +243,7 @@ ResultStatus AppLoader_NCCH::Load() {
243 243
244 return ResultStatus::Success; 244 return ResultStatus::Success;
245 } else { 245 } else {
246 ERROR_LOG(LOADER, "Unable to read file %s!", filename.c_str()); 246 LOG_ERROR(Loader, "Unable to read file %s!", filename.c_str());
247 } 247 }
248 return ResultStatus::Error; 248 return ResultStatus::Error;
249} 249}
@@ -297,8 +297,8 @@ ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
297 u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000; 297 u32 romfs_offset = ncch_offset + (ncch_header.romfs_offset * kBlockSize) + 0x1000;
298 u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000; 298 u32 romfs_size = (ncch_header.romfs_size * kBlockSize) - 0x1000;
299 299
300 INFO_LOG(LOADER, "RomFS offset: 0x%08X", romfs_offset); 300 LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset);
301 INFO_LOG(LOADER, "RomFS size: 0x%08X", romfs_size); 301 LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size);
302 302
303 buffer.resize(romfs_size); 303 buffer.resize(romfs_size);
304 304
@@ -307,12 +307,16 @@ ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
307 307
308 return ResultStatus::Success; 308 return ResultStatus::Success;
309 } 309 }
310 NOTICE_LOG(LOADER, "RomFS unused"); 310 LOG_DEBUG(Loader, "NCCH has no RomFS");
311 return ResultStatus::ErrorNotUsed; 311 return ResultStatus::ErrorNotUsed;
312 } else { 312 } else {
313 ERROR_LOG(LOADER, "Unable to read file %s!", filename.c_str()); 313 LOG_ERROR(Loader, "Unable to read file %s!", filename.c_str());
314 } 314 }
315 return ResultStatus::Error; 315 return ResultStatus::Error;
316} 316}
317 317
318u64 AppLoader_NCCH::GetProgramId() const {
319 return *reinterpret_cast<u64 const*>(&ncch_header.program_id[0]);
320}
321
318} // namespace Loader 322} // namespace Loader
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index 03116add8..fd9258970 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -191,6 +191,12 @@ public:
191 */ 191 */
192 ResultStatus ReadRomFS(std::vector<u8>& buffer) const override; 192 ResultStatus ReadRomFS(std::vector<u8>& buffer) const override;
193 193
194 /*
195 * Gets the program id from the NCCH header
196 * @return u64 Program id
197 */
198 u64 GetProgramId() const;
199
194private: 200private:
195 201
196 /** 202 /**
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp
index 74a93b1d9..eea6c5bf1 100644
--- a/src/core/mem_map.cpp
+++ b/src/core/mem_map.cpp
@@ -1,5 +1,5 @@
1 // Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common.h" 5#include "common/common.h"
@@ -18,7 +18,7 @@ static MemArena arena; ///< The MemArena class
18u8* g_exefs_code = nullptr; ///< ExeFS:/.code is loaded here 18u8* g_exefs_code = nullptr; ///< ExeFS:/.code is loaded here
19u8* g_system_mem = nullptr; ///< System memory 19u8* g_system_mem = nullptr; ///< System memory
20u8* g_heap = nullptr; ///< Application heap (main memory) 20u8* g_heap = nullptr; ///< Application heap (main memory)
21u8* g_heap_gsp = nullptr; ///< GSP heap (main memory) 21u8* g_heap_linear = nullptr; ///< Linear heap
22u8* g_vram = nullptr; ///< Video memory (VRAM) pointer 22u8* g_vram = nullptr; ///< Video memory (VRAM) pointer
23u8* g_shared_mem = nullptr; ///< Shared memory 23u8* g_shared_mem = nullptr; ///< Shared memory
24u8* g_kernel_mem; ///< Kernel memory 24u8* g_kernel_mem; ///< Kernel memory
@@ -36,13 +36,13 @@ static u8* physical_kernel_mem; ///< Kernel memory
36 36
37// We don't declare the IO region in here since its handled by other means. 37// We don't declare the IO region in here since its handled by other means.
38static MemoryView g_views[] = { 38static MemoryView g_views[] = {
39 {&g_exefs_code, &physical_exefs_code, EXEFS_CODE_VADDR, EXEFS_CODE_SIZE, 0}, 39 {&g_exefs_code, &physical_exefs_code, EXEFS_CODE_VADDR, EXEFS_CODE_SIZE, 0},
40 {&g_vram, &physical_vram, VRAM_VADDR, VRAM_SIZE, 0}, 40 {&g_vram, &physical_vram, VRAM_VADDR, VRAM_SIZE, 0},
41 {&g_heap, &physical_fcram, HEAP_VADDR, HEAP_SIZE, MV_IS_PRIMARY_RAM}, 41 {&g_heap, &physical_fcram, HEAP_VADDR, HEAP_SIZE, MV_IS_PRIMARY_RAM},
42 {&g_shared_mem, &physical_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, 0}, 42 {&g_shared_mem, &physical_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, 0},
43 {&g_system_mem, &physical_system_mem, SYSTEM_MEMORY_VADDR, SYSTEM_MEMORY_SIZE, 0}, 43 {&g_system_mem, &physical_system_mem, SYSTEM_MEMORY_VADDR, SYSTEM_MEMORY_SIZE, 0},
44 {&g_kernel_mem, &physical_kernel_mem, KERNEL_MEMORY_VADDR, KERNEL_MEMORY_SIZE, 0}, 44 {&g_kernel_mem, &physical_kernel_mem, KERNEL_MEMORY_VADDR, KERNEL_MEMORY_SIZE, 0},
45 {&g_heap_gsp, &physical_heap_gsp, HEAP_GSP_VADDR, HEAP_GSP_SIZE, 0}, 45 {&g_heap_linear, &physical_heap_gsp, HEAP_LINEAR_VADDR, HEAP_LINEAR_SIZE, 0},
46}; 46};
47 47
48/*static MemoryView views[] = 48/*static MemoryView views[] =
@@ -71,7 +71,7 @@ void Init() {
71 71
72 g_base = MemoryMap_Setup(g_views, kNumMemViews, flags, &arena); 72 g_base = MemoryMap_Setup(g_views, kNumMemViews, flags, &arena);
73 73
74 NOTICE_LOG(MEMMAP, "initialized OK, RAM at %p (mirror at 0 @ %p)", g_heap, 74 LOG_DEBUG(HW_Memory, "initialized OK, RAM at %p (mirror at 0 @ %p)", g_heap,
75 physical_fcram); 75 physical_fcram);
76} 76}
77 77
@@ -82,7 +82,7 @@ void Shutdown() {
82 arena.ReleaseSpace(); 82 arena.ReleaseSpace();
83 g_base = nullptr; 83 g_base = nullptr;
84 84
85 NOTICE_LOG(MEMMAP, "shutdown OK"); 85 LOG_DEBUG(HW_Memory, "shutdown OK");
86} 86}
87 87
88} // namespace 88} // namespace
diff --git a/src/core/mem_map.h b/src/core/mem_map.h
index a58c59244..a2ef9d3af 100644
--- a/src/core/mem_map.h
+++ b/src/core/mem_map.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -16,76 +16,85 @@ typedef u32 PAddr; ///< Represents a pointer in the physical address space.
16 16
17//////////////////////////////////////////////////////////////////////////////////////////////////// 17////////////////////////////////////////////////////////////////////////////////////////////////////
18 18
19enum { 19enum : u32 {
20 BOOTROM_SIZE = 0x00010000, ///< Bootrom (super secret code/data @ 0x8000) size 20 BOOTROM_SIZE = 0x00010000, ///< Bootrom (super secret code/data @ 0x8000) size
21 MPCORE_PRIV_SIZE = 0x00002000, ///< MPCore private memory region size 21 BOOTROM_PADDR = 0x00000000, ///< Bootrom physical address
22 DSP_SIZE = 0x00080000, ///< DSP memory size 22 BOOTROM_PADDR_END = (BOOTROM_PADDR + BOOTROM_SIZE),
23 AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size 23
24 24 BOOTROM_MIRROR_SIZE = 0x00010000, ///< Bootrom Mirror size
25 FCRAM_SIZE = 0x08000000, ///< FCRAM size 25 BOOTROM_MIRROR_PADDR = 0x00010000, ///< Bootrom Mirror physical address
26 FCRAM_PADDR = 0x20000000, ///< FCRAM physical address 26 BOOTROM_MIRROR_PADDR_END = (BOOTROM_MIRROR_PADDR + BOOTROM_MIRROR_SIZE),
27 FCRAM_PADDR_END = (FCRAM_PADDR + FCRAM_SIZE), ///< FCRAM end of physical space 27
28 FCRAM_VADDR = 0x08000000, ///< FCRAM virtual address 28 MPCORE_PRIV_SIZE = 0x00002000, ///< MPCore private memory region size
29 FCRAM_VADDR_END = (FCRAM_VADDR + FCRAM_SIZE), ///< FCRAM end of virtual space 29 MPCORE_PRIV_PADDR = 0x17E00000, ///< MPCore private memory region physical address
30 FCRAM_MASK = (FCRAM_SIZE - 1), ///< FCRAM mask 30 MPCORE_PRIV_PADDR_END = (MPCORE_PRIV_PADDR + MPCORE_PRIV_SIZE),
31 31
32 SHARED_MEMORY_SIZE = 0x04000000, ///< Shared memory size 32 FCRAM_SIZE = 0x08000000, ///< FCRAM size
33 SHARED_MEMORY_VADDR = 0x10000000, ///< Shared memory 33 FCRAM_PADDR = 0x20000000, ///< FCRAM physical address
34 SHARED_MEMORY_VADDR_END = (SHARED_MEMORY_VADDR + SHARED_MEMORY_SIZE), 34 FCRAM_PADDR_END = (FCRAM_PADDR + FCRAM_SIZE), ///< FCRAM end of physical space
35 SHARED_MEMORY_MASK = (SHARED_MEMORY_SIZE - 1), 35 FCRAM_VADDR = 0x08000000, ///< FCRAM virtual address
36 36 FCRAM_VADDR_END = (FCRAM_VADDR + FCRAM_SIZE), ///< FCRAM end of virtual space
37 CONFIG_MEMORY_SIZE = 0x00001000, ///< Configuration memory size 37
38 CONFIG_MEMORY_VADDR = 0x1FF80000, ///< Configuration memory virtual address 38 AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size
39 CONFIG_MEMORY_VADDR_END = (CONFIG_MEMORY_VADDR + CONFIG_MEMORY_SIZE), 39 AXI_WRAM_PADDR = 0x1FF80000, ///< AXI WRAM physical address
40 CONFIG_MEMORY_MASK = (CONFIG_MEMORY_SIZE - 1), 40 AXI_WRAM_PADDR_END = (AXI_WRAM_PADDR + AXI_WRAM_SIZE),
41 41
42 KERNEL_MEMORY_SIZE = 0x00001000, ///< Kernel memory size 42 SHARED_MEMORY_SIZE = 0x04000000, ///< Shared memory size
43 KERNEL_MEMORY_VADDR = 0xFFFF0000, ///< Kernel memory where the kthread objects etc are 43 SHARED_MEMORY_VADDR = 0x10000000, ///< Shared memory
44 KERNEL_MEMORY_VADDR_END = (KERNEL_MEMORY_VADDR + KERNEL_MEMORY_SIZE), 44 SHARED_MEMORY_VADDR_END = (SHARED_MEMORY_VADDR + SHARED_MEMORY_SIZE),
45 KERNEL_MEMORY_MASK = (KERNEL_MEMORY_SIZE - 1), 45
46 46 DSP_MEMORY_SIZE = 0x00080000, ///< DSP memory size
47 EXEFS_CODE_SIZE = 0x03F00000, 47 DSP_MEMORY_VADDR = 0x1FF00000, ///< DSP memory virtual address
48 EXEFS_CODE_VADDR = 0x00100000, ///< ExeFS:/.code is loaded here 48 DSP_MEMORY_VADDR_END = (DSP_MEMORY_VADDR + DSP_MEMORY_SIZE),
49 EXEFS_CODE_VADDR_END = (EXEFS_CODE_VADDR + EXEFS_CODE_SIZE), 49
50 EXEFS_CODE_MASK = 0x03FFFFFF, 50 CONFIG_MEMORY_SIZE = 0x00001000, ///< Configuration memory size
51 CONFIG_MEMORY_VADDR = 0x1FF80000, ///< Configuration memory virtual address
52 CONFIG_MEMORY_VADDR_END = (CONFIG_MEMORY_VADDR + CONFIG_MEMORY_SIZE),
53
54 SHARED_PAGE_SIZE = 0x00001000, ///< Shared page size
55 SHARED_PAGE_VADDR = 0x1FF81000, ///< Shared page virtual address
56 SHARED_PAGE_VADDR_END = (SHARED_PAGE_VADDR + SHARED_PAGE_SIZE),
57
58 KERNEL_MEMORY_SIZE = 0x00001000, ///< Kernel memory size
59 KERNEL_MEMORY_VADDR = 0xFFFF0000, ///< Kernel memory where the kthread objects etc are
60 KERNEL_MEMORY_VADDR_END = (KERNEL_MEMORY_VADDR + KERNEL_MEMORY_SIZE),
61
62 EXEFS_CODE_SIZE = 0x03F00000,
63 EXEFS_CODE_VADDR = 0x00100000, ///< ExeFS:/.code is loaded here
64 EXEFS_CODE_VADDR_END = (EXEFS_CODE_VADDR + EXEFS_CODE_SIZE),
51 65
52 // Region of FCRAM used by system 66 // Region of FCRAM used by system
53 SYSTEM_MEMORY_SIZE = 0x02C00000, ///< 44MB 67 SYSTEM_MEMORY_SIZE = 0x02C00000, ///< 44MB
54 SYSTEM_MEMORY_VADDR = 0x04000000, 68 SYSTEM_MEMORY_VADDR = 0x04000000,
55 SYSTEM_MEMORY_VADDR_END = (SYSTEM_MEMORY_VADDR + SYSTEM_MEMORY_SIZE), 69 SYSTEM_MEMORY_VADDR_END = (SYSTEM_MEMORY_VADDR + SYSTEM_MEMORY_SIZE),
56 SYSTEM_MEMORY_MASK = 0x03FFFFFF, 70
57 71 HEAP_SIZE = FCRAM_SIZE, ///< Application heap size
58 HEAP_SIZE = FCRAM_SIZE, ///< Application heap size 72 //HEAP_PADDR = HEAP_GSP_SIZE,
59 //HEAP_PADDR = HEAP_GSP_SIZE, 73 //HEAP_PADDR_END = (HEAP_PADDR + HEAP_SIZE),
60 //HEAP_PADDR_END = (HEAP_PADDR + HEAP_SIZE), 74 HEAP_VADDR = 0x08000000,
61 HEAP_VADDR = 0x08000000, 75 HEAP_VADDR_END = (HEAP_VADDR + HEAP_SIZE),
62 HEAP_VADDR_END = (HEAP_VADDR + HEAP_SIZE), 76
63 HEAP_MASK = (HEAP_SIZE - 1), 77 HEAP_LINEAR_SIZE = 0x08000000, ///< Linear heap size... TODO: Define correctly?
64 78 HEAP_LINEAR_VADDR = 0x14000000,
65 HEAP_GSP_SIZE = 0x02000000, ///< GSP heap size... TODO: Define correctly? 79 HEAP_LINEAR_VADDR_END = (HEAP_LINEAR_VADDR + HEAP_LINEAR_SIZE),
66 HEAP_GSP_VADDR = 0x14000000, 80 HEAP_LINEAR_PADDR = 0x00000000,
67 HEAP_GSP_VADDR_END = (HEAP_GSP_VADDR + HEAP_GSP_SIZE), 81 HEAP_LINEAR_PADDR_END = (HEAP_LINEAR_PADDR + HEAP_LINEAR_SIZE),
68 HEAP_GSP_PADDR = 0x00000000, 82
69 HEAP_GSP_PADDR_END = (HEAP_GSP_PADDR + HEAP_GSP_SIZE), 83 HARDWARE_IO_SIZE = 0x01000000,
70 HEAP_GSP_MASK = (HEAP_GSP_SIZE - 1), 84 HARDWARE_IO_PADDR = 0x10000000, ///< IO physical address start
71 85 HARDWARE_IO_VADDR = 0x1EC00000, ///< IO virtual address start
72 HARDWARE_IO_SIZE = 0x01000000, 86 HARDWARE_IO_PADDR_END = (HARDWARE_IO_PADDR + HARDWARE_IO_SIZE),
73 HARDWARE_IO_PADDR = 0x10000000, ///< IO physical address start 87 HARDWARE_IO_VADDR_END = (HARDWARE_IO_VADDR + HARDWARE_IO_SIZE),
74 HARDWARE_IO_VADDR = 0x1EC00000, ///< IO virtual address start 88
75 HARDWARE_IO_PADDR_END = (HARDWARE_IO_PADDR + HARDWARE_IO_SIZE), 89 VRAM_SIZE = 0x00600000,
76 HARDWARE_IO_VADDR_END = (HARDWARE_IO_VADDR + HARDWARE_IO_SIZE), 90 VRAM_PADDR = 0x18000000,
77 91 VRAM_VADDR = 0x1F000000,
78 VRAM_SIZE = 0x00600000, 92 VRAM_PADDR_END = (VRAM_PADDR + VRAM_SIZE),
79 VRAM_PADDR = 0x18000000, 93 VRAM_VADDR_END = (VRAM_VADDR + VRAM_SIZE),
80 VRAM_VADDR = 0x1F000000, 94
81 VRAM_PADDR_END = (VRAM_PADDR + VRAM_SIZE), 95 SCRATCHPAD_SIZE = 0x00004000, ///< Typical stack size - TODO: Read from exheader
82 VRAM_VADDR_END = (VRAM_VADDR + VRAM_SIZE), 96 SCRATCHPAD_VADDR_END = 0x10000000,
83 VRAM_MASK = 0x007FFFFF, 97 SCRATCHPAD_VADDR = (SCRATCHPAD_VADDR_END - SCRATCHPAD_SIZE), ///< Stack space
84
85 SCRATCHPAD_SIZE = 0x00004000, ///< Typical stack size - TODO: Read from exheader
86 SCRATCHPAD_VADDR_END = 0x10000000,
87 SCRATCHPAD_VADDR = (SCRATCHPAD_VADDR_END - SCRATCHPAD_SIZE), ///< Stack space
88 SCRATCHPAD_MASK = (SCRATCHPAD_SIZE - 1), ///< Scratchpad memory mask
89}; 98};
90 99
91//////////////////////////////////////////////////////////////////////////////////////////////////// 100////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -120,7 +129,7 @@ extern u8 *g_base;
120// These are guaranteed to point to "low memory" addresses (sub-32-bit). 129// These are guaranteed to point to "low memory" addresses (sub-32-bit).
121// 64-bit: Pointers to low-mem (sub-0x10000000) mirror 130// 64-bit: Pointers to low-mem (sub-0x10000000) mirror
122// 32-bit: Same as the corresponding physical/virtual pointers. 131// 32-bit: Same as the corresponding physical/virtual pointers.
123extern u8* g_heap_gsp; ///< GSP heap (main memory) 132extern u8* g_heap_linear; ///< Linear heap (main memory)
124extern u8* g_heap; ///< Application heap (main memory) 133extern u8* g_heap; ///< Application heap (main memory)
125extern u8* g_vram; ///< Video memory (VRAM) 134extern u8* g_vram; ///< Video memory (VRAM)
126extern u8* g_shared_mem; ///< Shared memory 135extern u8* g_shared_mem; ///< Shared memory
@@ -167,7 +176,7 @@ u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions);
167 * @param operation Memory map operation type 176 * @param operation Memory map operation type
168 * @param permissions Control memory permissions 177 * @param permissions Control memory permissions
169 */ 178 */
170u32 MapBlock_HeapGSP(u32 size, u32 operation, u32 permissions); 179u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions);
171 180
172inline const char* GetCharPointer(const VAddr address) { 181inline const char* GetCharPointer(const VAddr address) {
173 return (const char *)GetPointer(address); 182 return (const char *)GetPointer(address);
diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp
index 443d5ad7e..fdf382ed6 100644
--- a/src/core/mem_map_funcs.cpp
+++ b/src/core/mem_map_funcs.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map> 5#include <map>
@@ -13,7 +13,7 @@
13namespace Memory { 13namespace Memory {
14 14
15static std::map<u32, MemoryBlock> heap_map; 15static std::map<u32, MemoryBlock> heap_map;
16static std::map<u32, MemoryBlock> heap_gsp_map; 16static std::map<u32, MemoryBlock> heap_linear_map;
17static std::map<u32, MemoryBlock> shared_map; 17static std::map<u32, MemoryBlock> shared_map;
18 18
19/// Convert a physical address to virtual address 19/// Convert a physical address to virtual address
@@ -28,7 +28,7 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) {
28 return addr - FCRAM_PADDR + FCRAM_VADDR; 28 return addr - FCRAM_PADDR + FCRAM_VADDR;
29 } 29 }
30 30
31 ERROR_LOG(MEMMAP, "Unknown physical address @ 0x%08x", addr); 31 LOG_ERROR(HW_Memory, "Unknown physical address @ 0x%08x", addr);
32 return addr; 32 return addr;
33} 33}
34 34
@@ -44,7 +44,7 @@ PAddr VirtualToPhysicalAddress(const VAddr addr) {
44 return addr - FCRAM_VADDR + FCRAM_PADDR; 44 return addr - FCRAM_VADDR + FCRAM_PADDR;
45 } 45 }
46 46
47 ERROR_LOG(MEMMAP, "Unknown virtual address @ 0x%08x", addr); 47 LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x%08x", addr);
48 return addr; 48 return addr;
49} 49}
50 50
@@ -56,32 +56,27 @@ inline void Read(T &var, const VAddr vaddr) {
56 56
57 // Kernel memory command buffer 57 // Kernel memory command buffer
58 if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) { 58 if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
59 var = *((const T*)&g_kernel_mem[vaddr & KERNEL_MEMORY_MASK]); 59 var = *((const T*)&g_kernel_mem[vaddr - KERNEL_MEMORY_VADDR]);
60
61 // Hardware I/O register reads
62 // 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space
63 } else if ((vaddr >= HARDWARE_IO_VADDR) && (vaddr < HARDWARE_IO_VADDR_END)) {
64 HW::Read<T>(var, vaddr);
65 60
66 // ExeFS:/.code is loaded here 61 // ExeFS:/.code is loaded here
67 } else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) { 62 } else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
68 var = *((const T*)&g_exefs_code[vaddr & EXEFS_CODE_MASK]); 63 var = *((const T*)&g_exefs_code[vaddr - EXEFS_CODE_VADDR]);
69 64
70 // FCRAM - GSP heap 65 // FCRAM - linear heap
71 } else if ((vaddr >= HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) { 66 } else if ((vaddr >= HEAP_LINEAR_VADDR) && (vaddr < HEAP_LINEAR_VADDR_END)) {
72 var = *((const T*)&g_heap_gsp[vaddr & HEAP_GSP_MASK]); 67 var = *((const T*)&g_heap_linear[vaddr - HEAP_LINEAR_VADDR]);
73 68
74 // FCRAM - application heap 69 // FCRAM - application heap
75 } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) { 70 } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
76 var = *((const T*)&g_heap[vaddr & HEAP_MASK]); 71 var = *((const T*)&g_heap[vaddr - HEAP_VADDR]);
77 72
78 // Shared memory 73 // Shared memory
79 } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) { 74 } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
80 var = *((const T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK]); 75 var = *((const T*)&g_shared_mem[vaddr - SHARED_MEMORY_VADDR]);
81 76
82 // System memory 77 // System memory
83 } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) { 78 } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
84 var = *((const T*)&g_system_mem[vaddr & SYSTEM_MEMORY_MASK]); 79 var = *((const T*)&g_system_mem[vaddr - SYSTEM_MEMORY_VADDR]);
85 80
86 // Config memory 81 // Config memory
87 } else if ((vaddr >= CONFIG_MEMORY_VADDR) && (vaddr < CONFIG_MEMORY_VADDR_END)) { 82 } else if ((vaddr >= CONFIG_MEMORY_VADDR) && (vaddr < CONFIG_MEMORY_VADDR_END)) {
@@ -89,10 +84,10 @@ inline void Read(T &var, const VAddr vaddr) {
89 84
90 // VRAM 85 // VRAM
91 } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) { 86 } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
92 var = *((const T*)&g_vram[vaddr & VRAM_MASK]); 87 var = *((const T*)&g_vram[vaddr - VRAM_VADDR]);
93 88
94 } else { 89 } else {
95 ERROR_LOG(MEMMAP, "unknown Read%d @ 0x%08X", sizeof(var) * 8, vaddr); 90 LOG_ERROR(HW_Memory, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, vaddr);
96 } 91 }
97} 92}
98 93
@@ -101,36 +96,31 @@ inline void Write(const VAddr vaddr, const T data) {
101 96
102 // Kernel memory command buffer 97 // Kernel memory command buffer
103 if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) { 98 if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
104 *(T*)&g_kernel_mem[vaddr & KERNEL_MEMORY_MASK] = data; 99 *(T*)&g_kernel_mem[vaddr - KERNEL_MEMORY_VADDR] = data;
105
106 // Hardware I/O register writes
107 // 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space
108 } else if ((vaddr >= HARDWARE_IO_VADDR) && (vaddr < HARDWARE_IO_VADDR_END)) {
109 HW::Write<T>(vaddr, data);
110 100
111 // ExeFS:/.code is loaded here 101 // ExeFS:/.code is loaded here
112 } else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) { 102 } else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
113 *(T*)&g_exefs_code[vaddr & EXEFS_CODE_MASK] = data; 103 *(T*)&g_exefs_code[vaddr - EXEFS_CODE_VADDR] = data;
114 104
115 // FCRAM - GSP heap 105 // FCRAM - linear heap
116 } else if ((vaddr >= HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) { 106 } else if ((vaddr >= HEAP_LINEAR_VADDR) && (vaddr < HEAP_LINEAR_VADDR_END)) {
117 *(T*)&g_heap_gsp[vaddr & HEAP_GSP_MASK] = data; 107 *(T*)&g_heap_linear[vaddr - HEAP_LINEAR_VADDR] = data;
118 108
119 // FCRAM - application heap 109 // FCRAM - application heap
120 } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) { 110 } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
121 *(T*)&g_heap[vaddr & HEAP_MASK] = data; 111 *(T*)&g_heap[vaddr - HEAP_VADDR] = data;
122 112
123 // Shared memory 113 // Shared memory
124 } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) { 114 } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
125 *(T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK] = data; 115 *(T*)&g_shared_mem[vaddr - SHARED_MEMORY_VADDR] = data;
126 116
127 // System memory 117 // System memory
128 } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) { 118 } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
129 *(T*)&g_system_mem[vaddr & SYSTEM_MEMORY_MASK] = data; 119 *(T*)&g_system_mem[vaddr - SYSTEM_MEMORY_VADDR] = data;
130 120
131 // VRAM 121 // VRAM
132 } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) { 122 } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
133 *(T*)&g_vram[vaddr & VRAM_MASK] = data; 123 *(T*)&g_vram[vaddr - VRAM_VADDR] = data;
134 124
135 //} else if ((vaddr & 0xFFF00000) == 0x1FF00000) { 125 //} else if ((vaddr & 0xFFF00000) == 0x1FF00000) {
136 // _assert_msg_(MEMMAP, false, "umimplemented write to DSP memory"); 126 // _assert_msg_(MEMMAP, false, "umimplemented write to DSP memory");
@@ -141,41 +131,41 @@ inline void Write(const VAddr vaddr, const T data) {
141 131
142 // Error out... 132 // Error out...
143 } else { 133 } else {
144 ERROR_LOG(MEMMAP, "unknown Write%d 0x%08X @ 0x%08X", sizeof(data) * 8, data, vaddr); 134 LOG_ERROR(HW_Memory, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, vaddr);
145 } 135 }
146} 136}
147 137
148u8 *GetPointer(const VAddr vaddr) { 138u8 *GetPointer(const VAddr vaddr) {
149 // Kernel memory command buffer 139 // Kernel memory command buffer
150 if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) { 140 if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
151 return g_kernel_mem + (vaddr & KERNEL_MEMORY_MASK); 141 return g_kernel_mem + (vaddr - KERNEL_MEMORY_VADDR);
152 142
153 // ExeFS:/.code is loaded here 143 // ExeFS:/.code is loaded here
154 } else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) { 144 } else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
155 return g_exefs_code + (vaddr & EXEFS_CODE_MASK); 145 return g_exefs_code + (vaddr - EXEFS_CODE_VADDR);
156 146
157 // FCRAM - GSP heap 147 // FCRAM - linear heap
158 } else if ((vaddr >= HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) { 148 } else if ((vaddr >= HEAP_LINEAR_VADDR) && (vaddr < HEAP_LINEAR_VADDR_END)) {
159 return g_heap_gsp + (vaddr & HEAP_GSP_MASK); 149 return g_heap_linear + (vaddr - HEAP_LINEAR_VADDR);
160 150
161 // FCRAM - application heap 151 // FCRAM - application heap
162 } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) { 152 } else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
163 return g_heap + (vaddr & HEAP_MASK); 153 return g_heap + (vaddr - HEAP_VADDR);
164 154
165 // Shared memory 155 // Shared memory
166 } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) { 156 } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
167 return g_shared_mem + (vaddr & SHARED_MEMORY_MASK); 157 return g_shared_mem + (vaddr - SHARED_MEMORY_VADDR);
168 158
169 // System memory 159 // System memory
170 } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) { 160 } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
171 return g_system_mem + (vaddr & SYSTEM_MEMORY_MASK); 161 return g_system_mem + (vaddr - SYSTEM_MEMORY_VADDR);
172 162
173 // VRAM 163 // VRAM
174 } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) { 164 } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
175 return g_vram + (vaddr & VRAM_MASK); 165 return g_vram + (vaddr - VRAM_VADDR);
176 166
177 } else { 167 } else {
178 ERROR_LOG(MEMMAP, "unknown GetPointer @ 0x%08x", vaddr); 168 LOG_ERROR(HW_Memory, "unknown GetPointer @ 0x%08x", vaddr);
179 return 0; 169 return 0;
180 } 170 }
181} 171}
@@ -204,24 +194,24 @@ u32 MapBlock_Heap(u32 size, u32 operation, u32 permissions) {
204} 194}
205 195
206/** 196/**
207 * Maps a block of memory on the GSP heap 197 * Maps a block of memory on the linear heap
208 * @param size Size of block in bytes 198 * @param size Size of block in bytes
209 * @param operation Memory map operation type 199 * @param operation Memory map operation type
210 * @param flags Memory allocation flags 200 * @param flags Memory allocation flags
211 */ 201 */
212u32 MapBlock_HeapGSP(u32 size, u32 operation, u32 permissions) { 202u32 MapBlock_HeapLinear(u32 size, u32 operation, u32 permissions) {
213 MemoryBlock block; 203 MemoryBlock block;
214 204
215 block.base_address = HEAP_GSP_VADDR; 205 block.base_address = HEAP_LINEAR_VADDR;
216 block.size = size; 206 block.size = size;
217 block.operation = operation; 207 block.operation = operation;
218 block.permissions = permissions; 208 block.permissions = permissions;
219 209
220 if (heap_gsp_map.size() > 0) { 210 if (heap_linear_map.size() > 0) {
221 const MemoryBlock last_block = heap_gsp_map.rbegin()->second; 211 const MemoryBlock last_block = heap_linear_map.rbegin()->second;
222 block.address = last_block.address + last_block.size; 212 block.address = last_block.address + last_block.size;
223 } 213 }
224 heap_gsp_map[block.GetVirtualAddress()] = block; 214 heap_linear_map[block.GetVirtualAddress()] = block;
225 215
226 return block.GetVirtualAddress(); 216 return block.GetVirtualAddress();
227} 217}
@@ -239,7 +229,7 @@ u16 Read16(const VAddr addr) {
239 // Check for 16-bit unaligned memory reads... 229 // Check for 16-bit unaligned memory reads...
240 if (addr & 1) { 230 if (addr & 1) {
241 // TODO(bunnei): Implement 16-bit unaligned memory reads 231 // TODO(bunnei): Implement 16-bit unaligned memory reads
242 ERROR_LOG(MEMMAP, "16-bit unaligned memory reads are not implemented!"); 232 LOG_ERROR(HW_Memory, "16-bit unaligned memory reads are not implemented!");
243 } 233 }
244 234
245 return (u16)data; 235 return (u16)data;
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index c486f6274..8a14f75aa 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "settings.h" 5#include "settings.h"
diff --git a/src/core/settings.h b/src/core/settings.h
index 7e7a66b89..4b8928847 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -1,9 +1,11 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
6 6
7#include <string>
8
7namespace Settings { 9namespace Settings {
8 10
9struct Values { 11struct Values {
@@ -29,11 +31,12 @@ struct Values {
29 // Core 31 // Core
30 int cpu_core; 32 int cpu_core;
31 int gpu_refresh_rate; 33 int gpu_refresh_rate;
34 int frame_skip;
32 35
33 // Data Storage 36 // Data Storage
34 bool use_virtual_sd; 37 bool use_virtual_sd;
35 38
36 bool enable_log; 39 std::string log_filter;
37} extern values; 40} extern values;
38 41
39} 42}
diff --git a/src/core/system.cpp b/src/core/system.cpp
index 43d0eef2c..d6188f055 100644
--- a/src/core/system.cpp
+++ b/src/core/system.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/core.h" 5#include "core/core.h"
@@ -23,10 +23,10 @@ void Init(EmuWindow* emu_window) {
23 Core::Init(); 23 Core::Init();
24 Memory::Init(); 24 Memory::Init();
25 HW::Init(); 25 HW::Init();
26 Kernel::Init();
26 HLE::Init(); 27 HLE::Init();
27 CoreTiming::Init(); 28 CoreTiming::Init();
28 VideoCore::Init(emu_window); 29 VideoCore::Init(emu_window);
29 Kernel::Init();
30} 30}
31 31
32void RunLoopFor(int cycles) { 32void RunLoopFor(int cycles) {
@@ -37,13 +37,13 @@ void RunLoopUntil(u64 global_cycles) {
37} 37}
38 38
39void Shutdown() { 39void Shutdown() {
40 Core::Shutdown();
41 Memory::Shutdown();
42 HW::Shutdown();
43 HLE::Shutdown();
44 CoreTiming::Shutdown();
45 VideoCore::Shutdown(); 40 VideoCore::Shutdown();
41 CoreTiming::Shutdown();
42 HLE::Shutdown();
46 Kernel::Shutdown(); 43 Kernel::Shutdown();
44 HW::Shutdown();
45 Memory::Shutdown();
46 Core::Shutdown();
47} 47}
48 48
49} // namespace 49} // namespace
diff --git a/src/core/system.h b/src/core/system.h
index 2bc2edc75..05d836530 100644
--- a/src/core/system.h
+++ b/src/core/system.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/video_core/clipper.cpp b/src/video_core/clipper.cpp
index fbe4047ce..1744066ba 100644
--- a/src/video_core/clipper.cpp
+++ b/src/video_core/clipper.cpp
@@ -1,8 +1,8 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <vector> 5#include <boost/container/static_vector.hpp>
6 6
7#include "clipper.h" 7#include "clipper.h"
8#include "pica.h" 8#include "pica.h"
@@ -91,25 +91,31 @@ static void InitScreenCoordinates(OutputVertex& vtx)
91 viewport.zscale = float24::FromRawFloat24(registers.viewport_depth_range); 91 viewport.zscale = float24::FromRawFloat24(registers.viewport_depth_range);
92 viewport.offset_z = float24::FromRawFloat24(registers.viewport_depth_far_plane); 92 viewport.offset_z = float24::FromRawFloat24(registers.viewport_depth_far_plane);
93 93
94 float24 inv_w = float24::FromFloat32(1.f) / vtx.pos.w;
95 vtx.color *= inv_w;
96 vtx.tc0 *= inv_w;
97 vtx.tc1 *= inv_w;
98 vtx.tc2 *= inv_w;
99 vtx.pos.w = inv_w;
100
94 // TODO: Not sure why the viewport width needs to be divided by 2 but the viewport height does not 101 // TODO: Not sure why the viewport width needs to be divided by 2 but the viewport height does not
95 vtx.screenpos[0] = (vtx.pos.x / vtx.pos.w + float24::FromFloat32(1.0)) * viewport.halfsize_x + viewport.offset_x; 102 vtx.screenpos[0] = (vtx.pos.x * inv_w + float24::FromFloat32(1.0)) * viewport.halfsize_x + viewport.offset_x;
96 vtx.screenpos[1] = (vtx.pos.y / vtx.pos.w + float24::FromFloat32(1.0)) * viewport.halfsize_y + viewport.offset_y; 103 vtx.screenpos[1] = (vtx.pos.y * inv_w + float24::FromFloat32(1.0)) * viewport.halfsize_y + viewport.offset_y;
97 vtx.screenpos[2] = viewport.offset_z - vtx.pos.z / vtx.pos.w * viewport.zscale; 104 vtx.screenpos[2] = viewport.offset_z - vtx.pos.z * inv_w * viewport.zscale;
98} 105}
99 106
100void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) { 107void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) {
101 108 using boost::container::static_vector;
102 // TODO (neobrain): 109
103 // The list of output vertices has some fixed maximum size, 110 // Clipping a planar n-gon against a plane will remove at least 1 vertex and introduces 2 at
104 // however I haven't taken the time to figure out what it is exactly. 111 // the new edge (or less in degenerate cases). As such, we can say that each clipping plane
105 // For now, we hence just assume a maximal size of 1000 vertices. 112 // introduces at most 1 new vertex to the polygon. Since we start with a triangle and have a
106 const size_t max_vertices = 1000; 113 // fixed 6 clipping planes, the maximum number of vertices of the clipped polygon is 3 + 6 = 9.
107 std::vector<OutputVertex> buffer_vertices; 114 static const size_t MAX_VERTICES = 9;
108 std::vector<OutputVertex*> output_list{ &v0, &v1, &v2 }; 115 static_vector<OutputVertex, MAX_VERTICES> buffer_a = { v0, v1, v2 };
109 116 static_vector<OutputVertex, MAX_VERTICES> buffer_b;
110 // Make sure to reserve space for all vertices. 117 auto* output_list = &buffer_a;
111 // Without this, buffer reallocation would invalidate references. 118 auto* input_list = &buffer_b;
112 buffer_vertices.reserve(max_vertices);
113 119
114 // Simple implementation of the Sutherland-Hodgman clipping algorithm. 120 // Simple implementation of the Sutherland-Hodgman clipping algorithm.
115 // TODO: Make this less inefficient (currently lots of useless buffering overhead happens here) 121 // TODO: Make this less inefficient (currently lots of useless buffering overhead happens here)
@@ -120,48 +126,45 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) {
120 ClippingEdge(ClippingEdge::POS_Z, float24::FromFloat32(+1.0)), 126 ClippingEdge(ClippingEdge::POS_Z, float24::FromFloat32(+1.0)),
121 ClippingEdge(ClippingEdge::NEG_Z, float24::FromFloat32(-1.0)) }) { 127 ClippingEdge(ClippingEdge::NEG_Z, float24::FromFloat32(-1.0)) }) {
122 128
123 const std::vector<OutputVertex*> input_list = output_list; 129 std::swap(input_list, output_list);
124 output_list.clear(); 130 output_list->clear();
125 131
126 const OutputVertex* reference_vertex = input_list.back(); 132 const OutputVertex* reference_vertex = &input_list->back();
127 133
128 for (const auto& vertex : input_list) { 134 for (const auto& vertex : *input_list) {
129 // NOTE: This algorithm changes vertex order in some cases! 135 // NOTE: This algorithm changes vertex order in some cases!
130 if (edge.IsInside(*vertex)) { 136 if (edge.IsInside(vertex)) {
131 if (edge.IsOutSide(*reference_vertex)) { 137 if (edge.IsOutSide(*reference_vertex)) {
132 buffer_vertices.push_back(edge.GetIntersection(*vertex, *reference_vertex)); 138 output_list->push_back(edge.GetIntersection(vertex, *reference_vertex));
133 output_list.push_back(&(buffer_vertices.back()));
134 } 139 }
135 140
136 output_list.push_back(vertex); 141 output_list->push_back(vertex);
137 } else if (edge.IsInside(*reference_vertex)) { 142 } else if (edge.IsInside(*reference_vertex)) {
138 buffer_vertices.push_back(edge.GetIntersection(*vertex, *reference_vertex)); 143 output_list->push_back(edge.GetIntersection(vertex, *reference_vertex));
139 output_list.push_back(&(buffer_vertices.back()));
140 } 144 }
141 145 reference_vertex = &vertex;
142 reference_vertex = vertex;
143 } 146 }
144 147
145 // Need to have at least a full triangle to continue... 148 // Need to have at least a full triangle to continue...
146 if (output_list.size() < 3) 149 if (output_list->size() < 3)
147 return; 150 return;
148 } 151 }
149 152
150 InitScreenCoordinates(*(output_list[0])); 153 InitScreenCoordinates((*output_list)[0]);
151 InitScreenCoordinates(*(output_list[1])); 154 InitScreenCoordinates((*output_list)[1]);
152 155
153 for (size_t i = 0; i < output_list.size() - 2; i ++) { 156 for (size_t i = 0; i < output_list->size() - 2; i ++) {
154 OutputVertex& vtx0 = *(output_list[0]); 157 OutputVertex& vtx0 = (*output_list)[0];
155 OutputVertex& vtx1 = *(output_list[i+1]); 158 OutputVertex& vtx1 = (*output_list)[i+1];
156 OutputVertex& vtx2 = *(output_list[i+2]); 159 OutputVertex& vtx2 = (*output_list)[i+2];
157 160
158 InitScreenCoordinates(vtx2); 161 InitScreenCoordinates(vtx2);
159 162
160 DEBUG_LOG(GPU, 163 LOG_TRACE(Render_Software,
161 "Triangle %lu/%lu (%lu buffer vertices) at position (%.3f, %.3f, %.3f, %.3f), " 164 "Triangle %lu/%lu at position (%.3f, %.3f, %.3f, %.3f), "
162 "(%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and " 165 "(%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and "
163 "screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)", 166 "screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)",
164 i,output_list.size(), buffer_vertices.size(), 167 i, output_list->size(),
165 vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(), 168 vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(),
166 vtx1.pos.x.ToFloat32(), vtx1.pos.y.ToFloat32(), vtx1.pos.z.ToFloat32(), vtx1.pos.w.ToFloat32(), 169 vtx1.pos.x.ToFloat32(), vtx1.pos.y.ToFloat32(), vtx1.pos.z.ToFloat32(), vtx1.pos.w.ToFloat32(),
167 vtx2.pos.x.ToFloat32(), vtx2.pos.y.ToFloat32(), vtx2.pos.z.ToFloat32(), vtx2.pos.w.ToFloat32(), 170 vtx2.pos.x.ToFloat32(), vtx2.pos.y.ToFloat32(), vtx2.pos.z.ToFloat32(), vtx2.pos.w.ToFloat32(),
diff --git a/src/video_core/clipper.h b/src/video_core/clipper.h
index 14d31ca1e..19ce8e140 100644
--- a/src/video_core/clipper.h
+++ b/src/video_core/clipper.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 1ec727698..9602779f4 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "clipper.h" 5#include "clipper.h"
@@ -8,6 +8,8 @@
8#include "pica.h" 8#include "pica.h"
9#include "primitive_assembly.h" 9#include "primitive_assembly.h"
10#include "vertex_shader.h" 10#include "vertex_shader.h"
11#include "core/hle/service/gsp_gpu.h"
12#include "core/hw/gpu.h"
11 13
12#include "debug_utils/debug_utils.h" 14#include "debug_utils/debug_utils.h"
13 15
@@ -30,24 +32,40 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
30 if (id >= registers.NumIds()) 32 if (id >= registers.NumIds())
31 return; 33 return;
32 34
35 // If we're skipping this frame, only allow trigger IRQ
36 if (GPU::g_skip_frame && id != PICA_REG_INDEX(trigger_irq))
37 return;
38
33 // TODO: Figure out how register masking acts on e.g. vs_uniform_setup.set_value 39 // TODO: Figure out how register masking acts on e.g. vs_uniform_setup.set_value
34 u32 old_value = registers[id]; 40 u32 old_value = registers[id];
35 registers[id] = (old_value & ~mask) | (value & mask); 41 registers[id] = (old_value & ~mask) | (value & mask);
36 42
43 if (g_debug_context)
44 g_debug_context->OnEvent(DebugContext::Event::CommandLoaded, reinterpret_cast<void*>(&id));
45
37 DebugUtils::OnPicaRegWrite(id, registers[id]); 46 DebugUtils::OnPicaRegWrite(id, registers[id]);
38 47
39 switch(id) { 48 switch(id) {
49 // Trigger IRQ
50 case PICA_REG_INDEX(trigger_irq):
51 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D);
52 return;
53
40 // It seems like these trigger vertex rendering 54 // It seems like these trigger vertex rendering
41 case PICA_REG_INDEX(trigger_draw): 55 case PICA_REG_INDEX(trigger_draw):
42 case PICA_REG_INDEX(trigger_draw_indexed): 56 case PICA_REG_INDEX(trigger_draw_indexed):
43 { 57 {
44 DebugUtils::DumpTevStageConfig(registers.GetTevStages()); 58 DebugUtils::DumpTevStageConfig(registers.GetTevStages());
45 59
60 if (g_debug_context)
61 g_debug_context->OnEvent(DebugContext::Event::IncomingPrimitiveBatch, nullptr);
62
46 const auto& attribute_config = registers.vertex_attributes; 63 const auto& attribute_config = registers.vertex_attributes;
47 const u8* const base_address = Memory::GetPointer(attribute_config.GetBaseAddress()); 64 const u32 base_address = attribute_config.GetPhysicalBaseAddress();
48 65
49 // Information about internal vertex attributes 66 // Information about internal vertex attributes
50 const u8* vertex_attribute_sources[16]; 67 u32 vertex_attribute_sources[16];
68 std::fill(vertex_attribute_sources, &vertex_attribute_sources[16], 0xdeadbeef);
51 u32 vertex_attribute_strides[16]; 69 u32 vertex_attribute_strides[16];
52 u32 vertex_attribute_formats[16]; 70 u32 vertex_attribute_formats[16];
53 u32 vertex_attribute_elements[16]; 71 u32 vertex_attribute_elements[16];
@@ -57,10 +75,10 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
57 for (int loader = 0; loader < 12; ++loader) { 75 for (int loader = 0; loader < 12; ++loader) {
58 const auto& loader_config = attribute_config.attribute_loaders[loader]; 76 const auto& loader_config = attribute_config.attribute_loaders[loader];
59 77
60 const u8* load_address = base_address + loader_config.data_offset; 78 u32 load_address = base_address + loader_config.data_offset;
61 79
62 // TODO: What happens if a loader overwrites a previous one's data? 80 // TODO: What happens if a loader overwrites a previous one's data?
63 for (int component = 0; component < loader_config.component_count; ++component) { 81 for (unsigned component = 0; component < loader_config.component_count; ++component) {
64 u32 attribute_index = loader_config.GetComponent(component); 82 u32 attribute_index = loader_config.GetComponent(component);
65 vertex_attribute_sources[attribute_index] = load_address; 83 vertex_attribute_sources[attribute_index] = load_address;
66 vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count); 84 vertex_attribute_strides[attribute_index] = static_cast<u32>(loader_config.byte_count);
@@ -75,9 +93,9 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
75 bool is_indexed = (id == PICA_REG_INDEX(trigger_draw_indexed)); 93 bool is_indexed = (id == PICA_REG_INDEX(trigger_draw_indexed));
76 94
77 const auto& index_info = registers.index_array; 95 const auto& index_info = registers.index_array;
78 const u8* index_address_8 = (u8*)base_address + index_info.offset; 96 const u8* index_address_8 = Memory::GetPointer(PAddrToVAddr(base_address + index_info.offset));
79 const u16* index_address_16 = (u16*)index_address_8; 97 const u16* index_address_16 = (u16*)index_address_8;
80 bool index_u16 = (bool)index_info.format; 98 bool index_u16 = index_info.format != 0;
81 99
82 DebugUtils::GeometryDumper geometry_dumper; 100 DebugUtils::GeometryDumper geometry_dumper;
83 PrimitiveAssembler<VertexShader::OutputVertex> clipper_primitive_assembler(registers.triangle_topology.Value()); 101 PrimitiveAssembler<VertexShader::OutputVertex> clipper_primitive_assembler(registers.triangle_topology.Value());
@@ -96,21 +114,31 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
96 114
97 for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) { 115 for (int i = 0; i < attribute_config.GetNumTotalAttributes(); ++i) {
98 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 116 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
99 const u8* srcdata = vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]; 117 const u8* srcdata = Memory::GetPointer(PAddrToVAddr(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]));
118
119 // TODO(neobrain): Ocarina of Time 3D has GetNumTotalAttributes return 8,
120 // yet only provides 2 valid source data addresses. Need to figure out
121 // what's wrong there, until then we just continue when address lookup fails
122 if (srcdata == nullptr)
123 continue;
124
100 const float srcval = (vertex_attribute_formats[i] == 0) ? *(s8*)srcdata : 125 const float srcval = (vertex_attribute_formats[i] == 0) ? *(s8*)srcdata :
101 (vertex_attribute_formats[i] == 1) ? *(u8*)srcdata : 126 (vertex_attribute_formats[i] == 1) ? *(u8*)srcdata :
102 (vertex_attribute_formats[i] == 2) ? *(s16*)srcdata : 127 (vertex_attribute_formats[i] == 2) ? *(s16*)srcdata :
103 *(float*)srcdata; 128 *(float*)srcdata;
104 input.attr[i][comp] = float24::FromFloat32(srcval); 129 input.attr[i][comp] = float24::FromFloat32(srcval);
105 DEBUG_LOG(GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08lx + 0x%04lx: %f", 130 LOG_TRACE(HW_GPU, "Loaded component %x of attribute %x for vertex %x (index %x) from 0x%08x + 0x%08lx + 0x%04lx: %f",
106 comp, i, vertex, index, 131 comp, i, vertex, index,
107 attribute_config.GetBaseAddress(), 132 attribute_config.GetPhysicalBaseAddress(),
108 vertex_attribute_sources[i] - base_address, 133 vertex_attribute_sources[i] - base_address,
109 srcdata - vertex_attribute_sources[i], 134 vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i],
110 input.attr[i][comp].ToFloat32()); 135 input.attr[i][comp].ToFloat32());
111 } 136 }
112 } 137 }
113 138
139 if (g_debug_context)
140 g_debug_context->OnEvent(DebugContext::Event::VertexLoaded, (void*)&input);
141
114 // NOTE: When dumping geometry, we simply assume that the first input attribute 142 // NOTE: When dumping geometry, we simply assume that the first input attribute
115 // corresponds to the position for now. 143 // corresponds to the position for now.
116 DebugUtils::GeometryDumper::Vertex dumped_vertex = { 144 DebugUtils::GeometryDumper::Vertex dumped_vertex = {
@@ -132,9 +160,19 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
132 clipper_primitive_assembler.SubmitVertex(output, Clipper::ProcessTriangle); 160 clipper_primitive_assembler.SubmitVertex(output, Clipper::ProcessTriangle);
133 } 161 }
134 geometry_dumper.Dump(); 162 geometry_dumper.Dump();
163
164 if (g_debug_context)
165 g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr);
166
135 break; 167 break;
136 } 168 }
137 169
170 case PICA_REG_INDEX(vs_bool_uniforms):
171 for (unsigned i = 0; i < 16; ++i)
172 VertexShader::GetBoolUniform(i) = (registers.vs_bool_uniforms.Value() & (1 << i)) != 0;
173
174 break;
175
138 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[0], 0x2c1): 176 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[0], 0x2c1):
139 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[1], 0x2c2): 177 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[1], 0x2c2):
140 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[2], 0x2c3): 178 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[2], 0x2c3):
@@ -160,7 +198,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
160 auto& uniform = VertexShader::GetFloatUniform(uniform_setup.index); 198 auto& uniform = VertexShader::GetFloatUniform(uniform_setup.index);
161 199
162 if (uniform_setup.index > 95) { 200 if (uniform_setup.index > 95) {
163 ERROR_LOG(GPU, "Invalid VS uniform index %d", (int)uniform_setup.index); 201 LOG_ERROR(HW_GPU, "Invalid VS uniform index %d", (int)uniform_setup.index);
164 break; 202 break;
165 } 203 }
166 204
@@ -176,7 +214,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
176 uniform.x = float24::FromRawFloat24(uniform_write_buffer[2] & 0xFFFFFF); 214 uniform.x = float24::FromRawFloat24(uniform_write_buffer[2] & 0xFFFFFF);
177 } 215 }
178 216
179 DEBUG_LOG(GPU, "Set uniform %x to (%f %f %f %f)", (int)uniform_setup.index, 217 LOG_TRACE(HW_GPU, "Set uniform %x to (%f %f %f %f)", (int)uniform_setup.index,
180 uniform.x.ToFloat32(), uniform.y.ToFloat32(), uniform.z.ToFloat32(), 218 uniform.x.ToFloat32(), uniform.y.ToFloat32(), uniform.z.ToFloat32(),
181 uniform.w.ToFloat32()); 219 uniform.w.ToFloat32());
182 220
@@ -229,6 +267,9 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
229 default: 267 default:
230 break; 268 break;
231 } 269 }
270
271 if (g_debug_context)
272 g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id));
232} 273}
233 274
234static std::ptrdiff_t ExecuteCommandBlock(const u32* first_command_word) { 275static std::ptrdiff_t ExecuteCommandBlock(const u32* first_command_word) {
@@ -259,8 +300,9 @@ static std::ptrdiff_t ExecuteCommandBlock(const u32* first_command_word) {
259 300
260void ProcessCommandList(const u32* list, u32 size) { 301void ProcessCommandList(const u32* list, u32 size) {
261 u32* read_pointer = (u32*)list; 302 u32* read_pointer = (u32*)list;
303 u32 list_length = size / sizeof(u32);
262 304
263 while (read_pointer < list + size) { 305 while (read_pointer < list + list_length) {
264 read_pointer += ExecuteCommandBlock(read_pointer); 306 read_pointer += ExecuteCommandBlock(read_pointer);
265 } 307 }
266} 308}
diff --git a/src/video_core/command_processor.h b/src/video_core/command_processor.h
index 955f9daec..bb3d4150f 100644
--- a/src/video_core/command_processor.h
+++ b/src/video_core/command_processor.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 275b06b7c..5921185a6 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -3,6 +3,8 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <condition_variable>
7#include <list>
6#include <map> 8#include <map>
7#include <fstream> 9#include <fstream>
8#include <mutex> 10#include <mutex>
@@ -12,14 +14,62 @@
12#include <png.h> 14#include <png.h>
13#endif 15#endif
14 16
17#include <nihstro/shader_binary.h>
18
19#include "common/log.h"
15#include "common/file_util.h" 20#include "common/file_util.h"
16 21
22#include "video_core/math.h"
17#include "video_core/pica.h" 23#include "video_core/pica.h"
18 24
19#include "debug_utils.h" 25#include "debug_utils.h"
20 26
27using nihstro::DVLBHeader;
28using nihstro::DVLEHeader;
29using nihstro::DVLPHeader;
30
21namespace Pica { 31namespace Pica {
22 32
33void DebugContext::OnEvent(Event event, void* data) {
34 if (!breakpoints[event].enabled)
35 return;
36
37 {
38 std::unique_lock<std::mutex> lock(breakpoint_mutex);
39
40 // TODO: Should stop the CPU thread here once we multithread emulation.
41
42 active_breakpoint = event;
43 at_breakpoint = true;
44
45 // Tell all observers that we hit a breakpoint
46 for (auto& breakpoint_observer : breakpoint_observers) {
47 breakpoint_observer->OnPicaBreakPointHit(event, data);
48 }
49
50 // Wait until another thread tells us to Resume()
51 resume_from_breakpoint.wait(lock, [&]{ return !at_breakpoint; });
52 }
53}
54
55void DebugContext::Resume() {
56 {
57 std::unique_lock<std::mutex> lock(breakpoint_mutex);
58
59 // Tell all observers that we are about to resume
60 for (auto& breakpoint_observer : breakpoint_observers) {
61 breakpoint_observer->OnPicaResume();
62 }
63
64 // Resume the waiting thread (i.e. OnEvent())
65 at_breakpoint = false;
66 }
67
68 resume_from_breakpoint.notify_one();
69}
70
71std::shared_ptr<DebugContext> g_debug_context; // TODO: Get rid of this global
72
23namespace DebugUtils { 73namespace DebugUtils {
24 74
25void GeometryDumper::AddTriangle(Vertex& v0, Vertex& v1, Vertex& v2) { 75void GeometryDumper::AddTriangle(Vertex& v0, Vertex& v1, Vertex& v2) {
@@ -54,65 +104,6 @@ void GeometryDumper::Dump() {
54 } 104 }
55} 105}
56 106
57#pragma pack(1)
58struct DVLBHeader {
59 enum : u32 {
60 MAGIC_WORD = 0x424C5644, // "DVLB"
61 };
62
63 u32 magic_word;
64 u32 num_programs;
65// u32 dvle_offset_table[];
66};
67static_assert(sizeof(DVLBHeader) == 0x8, "Incorrect structure size");
68
69struct DVLPHeader {
70 enum : u32 {
71 MAGIC_WORD = 0x504C5644, // "DVLP"
72 };
73
74 u32 magic_word;
75 u32 version;
76 u32 binary_offset; // relative to DVLP start
77 u32 binary_size_words;
78 u32 swizzle_patterns_offset;
79 u32 swizzle_patterns_num_entries;
80 u32 unk2;
81};
82static_assert(sizeof(DVLPHeader) == 0x1C, "Incorrect structure size");
83
84struct DVLEHeader {
85 enum : u32 {
86 MAGIC_WORD = 0x454c5644, // "DVLE"
87 };
88
89 enum class ShaderType : u8 {
90 VERTEX = 0,
91 GEOMETRY = 1,
92 };
93
94 u32 magic_word;
95 u16 pad1;
96 ShaderType type;
97 u8 pad2;
98 u32 main_offset_words; // offset within binary blob
99 u32 endmain_offset_words;
100 u32 pad3;
101 u32 pad4;
102 u32 constant_table_offset;
103 u32 constant_table_size; // number of entries
104 u32 label_table_offset;
105 u32 label_table_size;
106 u32 output_register_table_offset;
107 u32 output_register_table_size;
108 u32 uniform_table_offset;
109 u32 uniform_table_size;
110 u32 symbol_table_offset;
111 u32 symbol_table_size;
112
113};
114static_assert(sizeof(DVLEHeader) == 0x40, "Incorrect structure size");
115#pragma pack()
116 107
117void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data, u32 swizzle_size, 108void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data, u32 swizzle_size,
118 u32 main_offset, const Regs::VSOutputAttributes* output_attributes) 109 u32 main_offset, const Regs::VSOutputAttributes* output_attributes)
@@ -155,7 +146,7 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data
155 146
156 // This is put into a try-catch block to make sure we notice unknown configurations. 147 // This is put into a try-catch block to make sure we notice unknown configurations.
157 std::vector<OutputRegisterInfo> output_info_table; 148 std::vector<OutputRegisterInfo> output_info_table;
158 for (int i = 0; i < 7; ++i) { 149 for (unsigned i = 0; i < 7; ++i) {
159 using OutputAttributes = Pica::Regs::VSOutputAttributes; 150 using OutputAttributes = Pica::Regs::VSOutputAttributes;
160 151
161 // TODO: It's still unclear how the attribute components map to the register! 152 // TODO: It's still unclear how the attribute components map to the register!
@@ -204,8 +195,8 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data
204 it->component_mask = it->component_mask | component_mask; 195 it->component_mask = it->component_mask | component_mask;
205 } 196 }
206 } catch (const std::out_of_range& ) { 197 } catch (const std::out_of_range& ) {
207 _dbg_assert_msg_(GPU, 0, "Unknown output attribute mapping"); 198 _dbg_assert_msg_(HW_GPU, 0, "Unknown output attribute mapping");
208 ERROR_LOG(GPU, "Unknown output attribute mapping: %03x, %03x, %03x, %03x", 199 LOG_ERROR(HW_GPU, "Unknown output attribute mapping: %03x, %03x, %03x, %03x",
209 (int)output_attributes[i].map_x.Value(), 200 (int)output_attributes[i].map_x.Value(),
210 (int)output_attributes[i].map_y.Value(), 201 (int)output_attributes[i].map_y.Value(),
211 (int)output_attributes[i].map_z.Value(), 202 (int)output_attributes[i].map_z.Value(),
@@ -232,8 +223,8 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data
232 dvlp.binary_size_words = binary_size; 223 dvlp.binary_size_words = binary_size;
233 QueueForWriting((u8*)binary_data, binary_size * sizeof(u32)); 224 QueueForWriting((u8*)binary_data, binary_size * sizeof(u32));
234 225
235 dvlp.swizzle_patterns_offset = write_offset - dvlp_offset; 226 dvlp.swizzle_info_offset = write_offset - dvlp_offset;
236 dvlp.swizzle_patterns_num_entries = swizzle_size; 227 dvlp.swizzle_info_num_entries = swizzle_size;
237 u32 dummy = 0; 228 u32 dummy = 0;
238 for (unsigned int i = 0; i < swizzle_size; ++i) { 229 for (unsigned int i = 0; i < swizzle_size; ++i) {
239 QueueForWriting((u8*)&swizzle_data[i], sizeof(swizzle_data[i])); 230 QueueForWriting((u8*)&swizzle_data[i], sizeof(swizzle_data[i]));
@@ -265,7 +256,7 @@ static int is_pica_tracing = false;
265void StartPicaTracing() 256void StartPicaTracing()
266{ 257{
267 if (is_pica_tracing) { 258 if (is_pica_tracing) {
268 ERROR_LOG(GPU, "StartPicaTracing called even though tracing already running!"); 259 LOG_WARNING(HW_GPU, "StartPicaTracing called even though tracing already running!");
269 return; 260 return;
270 } 261 }
271 262
@@ -298,7 +289,7 @@ void OnPicaRegWrite(u32 id, u32 value)
298std::unique_ptr<PicaTrace> FinishPicaTracing() 289std::unique_ptr<PicaTrace> FinishPicaTracing()
299{ 290{
300 if (!is_pica_tracing) { 291 if (!is_pica_tracing) {
301 ERROR_LOG(GPU, "FinishPicaTracing called even though tracing already running!"); 292 LOG_WARNING(HW_GPU, "FinishPicaTracing called even though tracing isn't running!");
302 return {}; 293 return {};
303 } 294 }
304 295
@@ -312,6 +303,173 @@ std::unique_ptr<PicaTrace> FinishPicaTracing()
312 return std::move(ret); 303 return std::move(ret);
313} 304}
314 305
306const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo& info, bool disable_alpha) {
307 // Images are split into 8x8 tiles. Each tile is composed of four 4x4 subtiles each
308 // of which is composed of four 2x2 subtiles each of which is composed of four texels.
309 // Each structure is embedded into the next-bigger one in a diagonal pattern, e.g.
310 // texels are laid out in a 2x2 subtile like this:
311 // 2 3
312 // 0 1
313 //
314 // The full 8x8 tile has the texels arranged like this:
315 //
316 // 42 43 46 47 58 59 62 63
317 // 40 41 44 45 56 57 60 61
318 // 34 35 38 39 50 51 54 55
319 // 32 33 36 37 48 49 52 53
320 // 10 11 14 15 26 27 30 31
321 // 08 09 12 13 24 25 28 29
322 // 02 03 06 07 18 19 22 23
323 // 00 01 04 05 16 17 20 21
324
325 const unsigned int block_width = 8;
326 const unsigned int block_height = 8;
327
328 const unsigned int coarse_x = x & ~7;
329 const unsigned int coarse_y = y & ~7;
330
331 // Interleave the lower 3 bits of each coordinate to get the intra-block offsets, which are
332 // arranged in a Z-order curve. More details on the bit manipulation at:
333 // https://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes/
334 unsigned int i = (x | (y << 8)) & 0x0707; // ---- -210
335 i = (i ^ (i << 2)) & 0x1313; // ---2 --10
336 i = (i ^ (i << 1)) & 0x1515; // ---2 -1-0
337 i = (i | (i >> 7)) & 0x3F;
338
339 source += coarse_y * info.stride;
340 const unsigned int offset = coarse_x * block_height + i;
341
342 switch (info.format) {
343 case Regs::TextureFormat::RGBA8:
344 {
345 const u8* source_ptr = source + offset * 4;
346 return { source_ptr[3], source_ptr[2], source_ptr[1], disable_alpha ? (u8)255 : source_ptr[0] };
347 }
348
349 case Regs::TextureFormat::RGB8:
350 {
351 const u8* source_ptr = source + offset * 3;
352 return { source_ptr[2], source_ptr[1], source_ptr[0], 255 };
353 }
354
355 case Regs::TextureFormat::RGBA5551:
356 {
357 const u16 source_ptr = *(const u16*)(source + offset * 2);
358 u8 r = (source_ptr >> 11) & 0x1F;
359 u8 g = ((source_ptr) >> 6) & 0x1F;
360 u8 b = (source_ptr >> 1) & 0x1F;
361 u8 a = source_ptr & 1;
362 return Math::MakeVec<u8>((r << 3) | (r >> 2), (g << 3) | (g >> 2), (b << 3) | (b >> 2), disable_alpha ? 255 : (a * 255));
363 }
364
365 case Regs::TextureFormat::RGB565:
366 {
367 const u16 source_ptr = *(const u16*)(source + offset * 2);
368 u8 r = (source_ptr >> 11) & 0x1F;
369 u8 g = ((source_ptr) >> 5) & 0x3F;
370 u8 b = (source_ptr) & 0x1F;
371 return Math::MakeVec<u8>((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2), 255);
372 }
373
374 case Regs::TextureFormat::RGBA4:
375 {
376 const u8* source_ptr = source + offset * 2;
377 u8 r = source_ptr[1] >> 4;
378 u8 g = source_ptr[1] & 0xFF;
379 u8 b = source_ptr[0] >> 4;
380 u8 a = source_ptr[0] & 0xFF;
381 r = (r << 4) | r;
382 g = (g << 4) | g;
383 b = (b << 4) | b;
384 a = (a << 4) | a;
385 return { r, g, b, disable_alpha ? (u8)255 : a };
386 }
387
388 case Regs::TextureFormat::IA8:
389 {
390 const u8* source_ptr = source + offset * 2;
391
392 // TODO: component order not verified
393
394 if (disable_alpha) {
395 // Show intensity as red, alpha as green
396 return { source_ptr[0], source_ptr[1], 0, 255 };
397 } else {
398 return { source_ptr[0], source_ptr[0], source_ptr[0], source_ptr[1]};
399 }
400 }
401
402 case Regs::TextureFormat::I8:
403 {
404 const u8* source_ptr = source + offset;
405 return { *source_ptr, *source_ptr, *source_ptr, 255 };
406 }
407
408 case Regs::TextureFormat::A8:
409 {
410 const u8* source_ptr = source + offset;
411
412 if (disable_alpha) {
413 return { *source_ptr, *source_ptr, *source_ptr, 255 };
414 } else {
415 return { 0, 0, 0, *source_ptr };
416 }
417 }
418
419 case Regs::TextureFormat::IA4:
420 {
421 const u8* source_ptr = source + offset / 2;
422
423 // TODO: component order not verified
424
425 u8 i = (*source_ptr) & 0xF;
426 u8 a = ((*source_ptr) & 0xF0) >> 4;
427 a |= a << 4;
428 i |= i << 4;
429
430 if (disable_alpha) {
431 // Show intensity as red, alpha as green
432 return { i, a, 0, 255 };
433 } else {
434 return { i, i, i, a };
435 }
436 }
437
438 case Regs::TextureFormat::A4:
439 {
440 const u8* source_ptr = source + offset / 2;
441
442 // TODO: component order not verified
443
444 u8 a = (coarse_x % 2) ? ((*source_ptr)&0xF) : (((*source_ptr) & 0xF0) >> 4);
445 a |= a << 4;
446
447 if (disable_alpha) {
448 return { *source_ptr, *source_ptr, *source_ptr, 255 };
449 } else {
450 return { 0, 0, 0, *source_ptr };
451 }
452 }
453
454 default:
455 LOG_ERROR(HW_GPU, "Unknown texture format: %x", (u32)info.format);
456 _dbg_assert_(HW_GPU, 0);
457 return {};
458 }
459}
460
461TextureInfo TextureInfo::FromPicaRegister(const Regs::TextureConfig& config,
462 const Regs::TextureFormat& format)
463{
464 TextureInfo info;
465 info.physical_address = config.GetPhysicalAddress();
466 info.width = config.width;
467 info.height = config.height;
468 info.format = format;
469 info.stride = Pica::Regs::NibblesPerPixel(info.format) * info.width / 2;
470 return info;
471}
472
315void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) { 473void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
316 // NOTE: Permanently enabling this just trashes hard disks for no reason. 474 // NOTE: Permanently enabling this just trashes hard disks for no reason.
317 // Hence, this is currently disabled. 475 // Hence, this is currently disabled.
@@ -341,7 +499,7 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
341 // Initialize write structure 499 // Initialize write structure
342 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); 500 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
343 if (png_ptr == nullptr) { 501 if (png_ptr == nullptr) {
344 ERROR_LOG(GPU, "Could not allocate write struct\n"); 502 LOG_ERROR(Debug_GPU, "Could not allocate write struct\n");
345 goto finalise; 503 goto finalise;
346 504
347 } 505 }
@@ -349,13 +507,13 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
349 // Initialize info structure 507 // Initialize info structure
350 info_ptr = png_create_info_struct(png_ptr); 508 info_ptr = png_create_info_struct(png_ptr);
351 if (info_ptr == nullptr) { 509 if (info_ptr == nullptr) {
352 ERROR_LOG(GPU, "Could not allocate info struct\n"); 510 LOG_ERROR(Debug_GPU, "Could not allocate info struct\n");
353 goto finalise; 511 goto finalise;
354 } 512 }
355 513
356 // Setup Exception handling 514 // Setup Exception handling
357 if (setjmp(png_jmpbuf(png_ptr))) { 515 if (setjmp(png_jmpbuf(png_ptr))) {
358 ERROR_LOG(GPU, "Error during png creation\n"); 516 LOG_ERROR(Debug_GPU, "Error during png creation\n");
359 goto finalise; 517 goto finalise;
360 } 518 }
361 519
@@ -375,34 +533,22 @@ void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data) {
375 png_write_info(png_ptr, info_ptr); 533 png_write_info(png_ptr, info_ptr);
376 534
377 buf = new u8[row_stride * texture_config.height]; 535 buf = new u8[row_stride * texture_config.height];
378 for (int y = 0; y < texture_config.height; ++y) { 536 for (unsigned y = 0; y < texture_config.height; ++y) {
379 for (int x = 0; x < texture_config.width; ++x) { 537 for (unsigned x = 0; x < texture_config.width; ++x) {
380 // Cf. rasterizer code for an explanation of this algorithm. 538 TextureInfo info;
381 int texel_index_within_tile = 0; 539 info.width = texture_config.width;
382 for (int block_size_index = 0; block_size_index < 3; ++block_size_index) { 540 info.height = texture_config.height;
383 int sub_tile_width = 1 << block_size_index; 541 info.stride = row_stride;
384 int sub_tile_height = 1 << block_size_index; 542 info.format = registers.texture0_format;
385 543 Math::Vec4<u8> texture_color = LookupTexture(data, x, y, info);
386 int sub_tile_index = (x & sub_tile_width) << block_size_index; 544 buf[3 * x + y * row_stride ] = texture_color.r();
387 sub_tile_index += 2 * ((y & sub_tile_height) << block_size_index); 545 buf[3 * x + y * row_stride + 1] = texture_color.g();
388 texel_index_within_tile += sub_tile_index; 546 buf[3 * x + y * row_stride + 2] = texture_color.b();
389 }
390
391 const int block_width = 8;
392 const int block_height = 8;
393
394 int coarse_x = (x / block_width) * block_width;
395 int coarse_y = (y / block_height) * block_height;
396
397 u8* source_ptr = (u8*)data + coarse_x * block_height * 3 + coarse_y * row_stride + texel_index_within_tile * 3;
398 buf[3 * x + y * row_stride ] = source_ptr[2];
399 buf[3 * x + y * row_stride + 1] = source_ptr[1];
400 buf[3 * x + y * row_stride + 2] = source_ptr[0];
401 } 547 }
402 } 548 }
403 549
404 // Write image data 550 // Write image data
405 for (auto y = 0; y < texture_config.height; ++y) 551 for (unsigned y = 0; y < texture_config.height; ++y)
406 { 552 {
407 u8* row_ptr = (u8*)buf + y * row_stride; 553 u8* row_ptr = (u8*)buf + y * row_stride;
408 u8* ptr = row_ptr; 554 u8* ptr = row_ptr;
@@ -431,26 +577,32 @@ void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig,6>& stages)
431 for (size_t index = 0; index < stages.size(); ++index) { 577 for (size_t index = 0; index < stages.size(); ++index) {
432 const auto& tev_stage = stages[index]; 578 const auto& tev_stage = stages[index];
433 579
434 const std::map<Source, std::string> source_map = { 580 static const std::map<Source, std::string> source_map = {
435 { Source::PrimaryColor, "PrimaryColor" }, 581 { Source::PrimaryColor, "PrimaryColor" },
436 { Source::Texture0, "Texture0" }, 582 { Source::Texture0, "Texture0" },
583 { Source::Texture1, "Texture1" },
584 { Source::Texture2, "Texture2" },
437 { Source::Constant, "Constant" }, 585 { Source::Constant, "Constant" },
438 { Source::Previous, "Previous" }, 586 { Source::Previous, "Previous" },
439 }; 587 };
440 588
441 const std::map<ColorModifier, std::string> color_modifier_map = { 589 static const std::map<ColorModifier, std::string> color_modifier_map = {
442 { ColorModifier::SourceColor, { "%source.rgb" } } 590 { ColorModifier::SourceColor, { "%source.rgb" } },
591 { ColorModifier::SourceAlpha, { "%source.aaa" } },
443 }; 592 };
444 const std::map<AlphaModifier, std::string> alpha_modifier_map = { 593 static const std::map<AlphaModifier, std::string> alpha_modifier_map = {
445 { AlphaModifier::SourceAlpha, "%source.a" } 594 { AlphaModifier::SourceAlpha, "%source.a" },
595 { AlphaModifier::OneMinusSourceAlpha, "(255 - %source.a)" },
446 }; 596 };
447 597
448 std::map<Operation, std::string> combiner_map = { 598 static const std::map<Operation, std::string> combiner_map = {
449 { Operation::Replace, "%source1" }, 599 { Operation::Replace, "%source1" },
450 { Operation::Modulate, "(%source1 * %source2) / 255" }, 600 { Operation::Modulate, "(%source1 * %source2) / 255" },
601 { Operation::Add, "(%source1 + %source2)" },
602 { Operation::Lerp, "lerp(%source1, %source2, %source3)" },
451 }; 603 };
452 604
453 auto ReplacePattern = 605 static auto ReplacePattern =
454 [](const std::string& input, const std::string& pattern, const std::string& replacement) -> std::string { 606 [](const std::string& input, const std::string& pattern, const std::string& replacement) -> std::string {
455 size_t start = input.find(pattern); 607 size_t start = input.find(pattern);
456 if (start == std::string::npos) 608 if (start == std::string::npos)
@@ -460,8 +612,8 @@ void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig,6>& stages)
460 ret.replace(start, pattern.length(), replacement); 612 ret.replace(start, pattern.length(), replacement);
461 return ret; 613 return ret;
462 }; 614 };
463 auto GetColorSourceStr = 615 static auto GetColorSourceStr =
464 [&source_map,&color_modifier_map,&ReplacePattern](const Source& src, const ColorModifier& modifier) { 616 [](const Source& src, const ColorModifier& modifier) {
465 auto src_it = source_map.find(src); 617 auto src_it = source_map.find(src);
466 std::string src_str = "Unknown"; 618 std::string src_str = "Unknown";
467 if (src_it != source_map.end()) 619 if (src_it != source_map.end())
@@ -474,8 +626,8 @@ void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig,6>& stages)
474 626
475 return ReplacePattern(modifier_str, "%source", src_str); 627 return ReplacePattern(modifier_str, "%source", src_str);
476 }; 628 };
477 auto GetColorCombinerStr = 629 static auto GetColorCombinerStr =
478 [&](const Regs::TevStageConfig& tev_stage) { 630 [](const Regs::TevStageConfig& tev_stage) {
479 auto op_it = combiner_map.find(tev_stage.color_op); 631 auto op_it = combiner_map.find(tev_stage.color_op);
480 std::string op_str = "Unknown op (%source1, %source2, %source3)"; 632 std::string op_str = "Unknown op (%source1, %source2, %source3)";
481 if (op_it != combiner_map.end()) 633 if (op_it != combiner_map.end())
@@ -485,8 +637,8 @@ void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig,6>& stages)
485 op_str = ReplacePattern(op_str, "%source2", GetColorSourceStr(tev_stage.color_source2, tev_stage.color_modifier2)); 637 op_str = ReplacePattern(op_str, "%source2", GetColorSourceStr(tev_stage.color_source2, tev_stage.color_modifier2));
486 return ReplacePattern(op_str, "%source3", GetColorSourceStr(tev_stage.color_source3, tev_stage.color_modifier3)); 638 return ReplacePattern(op_str, "%source3", GetColorSourceStr(tev_stage.color_source3, tev_stage.color_modifier3));
487 }; 639 };
488 auto GetAlphaSourceStr = 640 static auto GetAlphaSourceStr =
489 [&source_map,&alpha_modifier_map,&ReplacePattern](const Source& src, const AlphaModifier& modifier) { 641 [](const Source& src, const AlphaModifier& modifier) {
490 auto src_it = source_map.find(src); 642 auto src_it = source_map.find(src);
491 std::string src_str = "Unknown"; 643 std::string src_str = "Unknown";
492 if (src_it != source_map.end()) 644 if (src_it != source_map.end())
@@ -499,8 +651,8 @@ void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig,6>& stages)
499 651
500 return ReplacePattern(modifier_str, "%source", src_str); 652 return ReplacePattern(modifier_str, "%source", src_str);
501 }; 653 };
502 auto GetAlphaCombinerStr = 654 static auto GetAlphaCombinerStr =
503 [&](const Regs::TevStageConfig& tev_stage) { 655 [](const Regs::TevStageConfig& tev_stage) {
504 auto op_it = combiner_map.find(tev_stage.alpha_op); 656 auto op_it = combiner_map.find(tev_stage.alpha_op);
505 std::string op_str = "Unknown op (%source1, %source2, %source3)"; 657 std::string op_str = "Unknown op (%source1, %source2, %source3)";
506 if (op_it != combiner_map.end()) 658 if (op_it != combiner_map.end())
@@ -514,7 +666,7 @@ void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig,6>& stages)
514 stage_info += "Stage " + std::to_string(index) + ": " + GetColorCombinerStr(tev_stage) + " " + GetAlphaCombinerStr(tev_stage) + "\n"; 666 stage_info += "Stage " + std::to_string(index) + ": " + GetColorCombinerStr(tev_stage) + " " + GetAlphaCombinerStr(tev_stage) + "\n";
515 } 667 }
516 668
517 DEBUG_LOG(GPU, "%s", stage_info.c_str()); 669 LOG_TRACE(HW_GPU, "%s", stage_info.c_str());
518} 670}
519 671
520} // namespace 672} // namespace
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
index b1558cfae..f361a5385 100644
--- a/src/video_core/debug_utils/debug_utils.h
+++ b/src/video_core/debug_utils/debug_utils.h
@@ -5,13 +5,148 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <condition_variable>
9#include <list>
10#include <map>
8#include <memory> 11#include <memory>
12#include <mutex>
9#include <vector> 13#include <vector>
10 14
15#include "video_core/math.h"
11#include "video_core/pica.h" 16#include "video_core/pica.h"
12 17
13namespace Pica { 18namespace Pica {
14 19
20class DebugContext {
21public:
22 enum class Event {
23 FirstEvent = 0,
24
25 CommandLoaded = FirstEvent,
26 CommandProcessed,
27 IncomingPrimitiveBatch,
28 FinishedPrimitiveBatch,
29 VertexLoaded,
30
31 NumEvents
32 };
33
34 /**
35 * Inherit from this class to be notified of events registered to some debug context.
36 * Most importantly this is used for our debugger GUI.
37 *
38 * To implement event handling, override the OnPicaBreakPointHit and OnPicaResume methods.
39 * @warning All BreakPointObservers need to be on the same thread to guarantee thread-safe state access
40 * @todo Evaluate an alternative interface, in which there is only one managing observer and multiple child observers running (by design) on the same thread.
41 */
42 class BreakPointObserver {
43 public:
44 /// Constructs the object such that it observes events of the given DebugContext.
45 BreakPointObserver(std::shared_ptr<DebugContext> debug_context) : context_weak(debug_context) {
46 std::unique_lock<std::mutex> lock(debug_context->breakpoint_mutex);
47 debug_context->breakpoint_observers.push_back(this);
48 }
49
50 virtual ~BreakPointObserver() {
51 auto context = context_weak.lock();
52 if (context) {
53 std::unique_lock<std::mutex> lock(context->breakpoint_mutex);
54 context->breakpoint_observers.remove(this);
55
56 // If we are the last observer to be destroyed, tell the debugger context that
57 // it is free to continue. In particular, this is required for a proper Citra
58 // shutdown, when the emulation thread is waiting at a breakpoint.
59 if (context->breakpoint_observers.empty())
60 context->Resume();
61 }
62 }
63
64 /**
65 * Action to perform when a breakpoint was reached.
66 * @param event Type of event which triggered the breakpoint
67 * @param data Optional data pointer (if unused, this is a nullptr)
68 * @note This function will perform nothing unless it is overridden in the child class.
69 */
70 virtual void OnPicaBreakPointHit(Event, void*) {
71 }
72
73 /**
74 * Action to perform when emulation is resumed from a breakpoint.
75 * @note This function will perform nothing unless it is overridden in the child class.
76 */
77 virtual void OnPicaResume() {
78 }
79
80 protected:
81 /**
82 * Weak context pointer. This need not be valid, so when requesting a shared_ptr via
83 * context_weak.lock(), always compare the result against nullptr.
84 */
85 std::weak_ptr<DebugContext> context_weak;
86 };
87
88 /**
89 * Simple structure defining a breakpoint state
90 */
91 struct BreakPoint {
92 bool enabled = false;
93 };
94
95 /**
96 * Static constructor used to create a shared_ptr of a DebugContext.
97 */
98 static std::shared_ptr<DebugContext> Construct() {
99 return std::shared_ptr<DebugContext>(new DebugContext);
100 }
101
102 /**
103 * Used by the emulation core when a given event has happened. If a breakpoint has been set
104 * for this event, OnEvent calls the event handlers of the registered breakpoint observers.
105 * The current thread then is halted until Resume() is called from another thread (or until
106 * emulation is stopped).
107 * @param event Event which has happened
108 * @param data Optional data pointer (pass nullptr if unused). Needs to remain valid until Resume() is called.
109 */
110 void OnEvent(Event event, void* data);
111
112 /**
113 * Resume from the current breakpoint.
114 * @warning Calling this from the same thread that OnEvent was called in will cause a deadlock. Calling from any other thread is safe.
115 */
116 void Resume();
117
118 /**
119 * Delete all set breakpoints and resume emulation.
120 */
121 void ClearBreakpoints() {
122 breakpoints.clear();
123 Resume();
124 }
125
126 // TODO: Evaluate if access to these members should be hidden behind a public interface.
127 std::map<Event, BreakPoint> breakpoints;
128 Event active_breakpoint;
129 bool at_breakpoint = false;
130
131private:
132 /**
133 * Private default constructor to make sure people always construct this through Construct()
134 * instead.
135 */
136 DebugContext() = default;
137
138 /// Mutex protecting current breakpoint state and the observer list.
139 std::mutex breakpoint_mutex;
140
141 /// Used by OnEvent to wait for resumption.
142 std::condition_variable resume_from_breakpoint;
143
144 /// List of registered observers
145 std::list<BreakPointObserver*> breakpoint_observers;
146};
147
148extern std::shared_ptr<DebugContext> g_debug_context; // TODO: Get rid of this global
149
15namespace DebugUtils { 150namespace DebugUtils {
16 151
17// Simple utility class for dumping geometry data to an OBJ file 152// Simple utility class for dumping geometry data to an OBJ file
@@ -57,6 +192,28 @@ bool IsPicaTracing();
57void OnPicaRegWrite(u32 id, u32 value); 192void OnPicaRegWrite(u32 id, u32 value);
58std::unique_ptr<PicaTrace> FinishPicaTracing(); 193std::unique_ptr<PicaTrace> FinishPicaTracing();
59 194
195struct TextureInfo {
196 PAddr physical_address;
197 int width;
198 int height;
199 int stride;
200 Pica::Regs::TextureFormat format;
201
202 static TextureInfo FromPicaRegister(const Pica::Regs::TextureConfig& config,
203 const Pica::Regs::TextureFormat& format);
204};
205
206/**
207 * Lookup texel located at the given coordinates and return an RGBA vector of its color.
208 * @param source Source pointer to read data from
209 * @param s,t Texture coordinates to read from
210 * @param info TextureInfo object describing the texture setup
211 * @param disable_alpha This is used for debug widgets which use this method to display textures without providing a good way to visualize alpha by themselves. If true, this will return 255 for the alpha component, and either drop the information entirely or store it in an "unused" color channel.
212 * @todo Eventually we should get rid of the disable_alpha parameter.
213 */
214const Math::Vec4<u8> LookupTexture(const u8* source, int s, int t, const TextureInfo& info,
215 bool disable_alpha = false);
216
60void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data); 217void DumpTexture(const Pica::Regs::TextureConfig& texture_config, u8* data);
61 218
62void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig,6>& stages); 219void DumpTevStageConfig(const std::array<Pica::Regs::TevStageConfig,6>& stages);
diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h
index 1242eb58f..a51d49c92 100644
--- a/src/video_core/gpu_debugger.h
+++ b/src/video_core/gpu_debugger.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -39,7 +39,7 @@ public:
39 virtual void GXCommandProcessed(int total_command_count) 39 virtual void GXCommandProcessed(int total_command_count)
40 { 40 {
41 const GSP_GPU::Command& cmd = observed->ReadGXCommandHistory(total_command_count-1); 41 const GSP_GPU::Command& cmd = observed->ReadGXCommandHistory(total_command_count-1);
42 ERROR_LOG(GSP, "Received command: id=%x", (int)cmd.id.Value()); 42 LOG_TRACE(Debug_GPU, "Received command: id=%x", (int)cmd.id.Value());
43 } 43 }
44 44
45 protected: 45 protected:
@@ -85,7 +85,7 @@ public:
85 85
86 void UnregisterObserver(DebuggerObserver* observer) 86 void UnregisterObserver(DebuggerObserver* observer)
87 { 87 {
88 std::remove(observers.begin(), observers.end(), observer); 88 observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
89 observer->observed = nullptr; 89 observer->observed = nullptr;
90 } 90 }
91 91
diff --git a/src/video_core/math.h b/src/video_core/math.h
index 83ba81235..9622e7614 100644
--- a/src/video_core/math.h
+++ b/src/video_core/math.h
@@ -1,4 +1,4 @@
1// Licensed under GPLv2 1// Licensed under GPLv2 or any later version
2// Refer to the license.txt file included. 2// Refer to the license.txt file included.
3 3
4 4
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 5fe15a218..38bac748c 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -8,6 +8,7 @@
8#include <cstddef> 8#include <cstddef>
9#include <initializer_list> 9#include <initializer_list>
10#include <map> 10#include <map>
11#include <vector>
11 12
12#include "common/bit_field.h" 13#include "common/bit_field.h"
13#include "common/common_types.h" 14#include "common/common_types.h"
@@ -45,10 +46,16 @@ struct Regs {
45#define INSERT_PADDING_WORDS_HELPER2(x, y) INSERT_PADDING_WORDS_HELPER1(x, y) 46#define INSERT_PADDING_WORDS_HELPER2(x, y) INSERT_PADDING_WORDS_HELPER1(x, y)
46#define INSERT_PADDING_WORDS(num_words) u32 INSERT_PADDING_WORDS_HELPER2(pad, __LINE__)[(num_words)]; 47#define INSERT_PADDING_WORDS(num_words) u32 INSERT_PADDING_WORDS_HELPER2(pad, __LINE__)[(num_words)];
47 48
48 INSERT_PADDING_WORDS(0x41); 49 INSERT_PADDING_WORDS(0x10);
50
51 u32 trigger_irq;
52
53 INSERT_PADDING_WORDS(0x30);
49 54
50 BitField<0, 24, u32> viewport_size_x; 55 BitField<0, 24, u32> viewport_size_x;
56
51 INSERT_PADDING_WORDS(0x1); 57 INSERT_PADDING_WORDS(0x1);
58
52 BitField<0, 24, u32> viewport_size_y; 59 BitField<0, 24, u32> viewport_size_y;
53 60
54 INSERT_PADDING_WORDS(0x9); 61 INSERT_PADDING_WORDS(0x9);
@@ -98,6 +105,11 @@ struct Regs {
98 INSERT_PADDING_WORDS(0x17); 105 INSERT_PADDING_WORDS(0x17);
99 106
100 struct TextureConfig { 107 struct TextureConfig {
108 enum WrapMode : u32 {
109 ClampToEdge = 0,
110 Repeat = 2,
111 };
112
101 INSERT_PADDING_WORDS(0x1); 113 INSERT_PADDING_WORDS(0x1);
102 114
103 union { 115 union {
@@ -105,12 +117,17 @@ struct Regs {
105 BitField<16, 16, u32> width; 117 BitField<16, 16, u32> width;
106 }; 118 };
107 119
108 INSERT_PADDING_WORDS(0x2); 120 union {
121 BitField< 8, 2, WrapMode> wrap_s;
122 BitField<11, 2, WrapMode> wrap_t;
123 };
124
125 INSERT_PADDING_WORDS(0x1);
109 126
110 u32 address; 127 u32 address;
111 128
112 u32 GetPhysicalAddress() { 129 u32 GetPhysicalAddress() const {
113 return DecodeAddressRegister(address) - Memory::FCRAM_PADDR + Memory::HEAP_GSP_VADDR; 130 return DecodeAddressRegister(address);
114 } 131 }
115 132
116 // texture1 and texture2 store the texture format directly after the address 133 // texture1 and texture2 store the texture format directly after the address
@@ -125,17 +142,70 @@ struct Regs {
125 RGBA5551 = 2, 142 RGBA5551 = 2,
126 RGB565 = 3, 143 RGB565 = 3,
127 RGBA4 = 4, 144 RGBA4 = 4,
145 IA8 = 5,
146
147 I8 = 7,
148 A8 = 8,
149 IA4 = 9,
128 150
151 A4 = 11,
129 // TODO: Support for the other formats is not implemented, yet. 152 // TODO: Support for the other formats is not implemented, yet.
130 // Seems like they are luminance formats and compressed textures. 153 // Seems like they are luminance formats and compressed textures.
131 }; 154 };
132 155
133 BitField<0, 1, u32> texturing_enable; 156 static unsigned NibblesPerPixel(TextureFormat format) {
157 switch (format) {
158 case TextureFormat::RGBA8:
159 return 8;
160
161 case TextureFormat::RGB8:
162 return 6;
163
164 case TextureFormat::RGBA5551:
165 case TextureFormat::RGB565:
166 case TextureFormat::RGBA4:
167 case TextureFormat::IA8:
168 return 4;
169
170 case TextureFormat::A4:
171 return 1;
172
173 case TextureFormat::I8:
174 case TextureFormat::A8:
175 case TextureFormat::IA4:
176 default: // placeholder for yet unknown formats
177 return 2;
178 }
179 }
180
181 union {
182 BitField< 0, 1, u32> texture0_enable;
183 BitField< 1, 1, u32> texture1_enable;
184 BitField< 2, 1, u32> texture2_enable;
185 };
134 TextureConfig texture0; 186 TextureConfig texture0;
135 INSERT_PADDING_WORDS(0x8); 187 INSERT_PADDING_WORDS(0x8);
136 BitField<0, 4, TextureFormat> texture0_format; 188 BitField<0, 4, TextureFormat> texture0_format;
137 189 INSERT_PADDING_WORDS(0x2);
138 INSERT_PADDING_WORDS(0x31); 190 TextureConfig texture1;
191 BitField<0, 4, TextureFormat> texture1_format;
192 INSERT_PADDING_WORDS(0x2);
193 TextureConfig texture2;
194 BitField<0, 4, TextureFormat> texture2_format;
195 INSERT_PADDING_WORDS(0x21);
196
197 struct FullTextureConfig {
198 const bool enabled;
199 const TextureConfig config;
200 const TextureFormat format;
201 };
202 const std::array<FullTextureConfig, 3> GetTextures() const {
203 return {{
204 { texture0_enable.ToBool(), texture0, texture0_format },
205 { texture1_enable.ToBool(), texture1, texture1_format },
206 { texture2_enable.ToBool(), texture2, texture2_format }
207 }};
208 }
139 209
140 // 0xc0-0xff: Texture Combiner (akin to glTexEnv) 210 // 0xc0-0xff: Texture Combiner (akin to glTexEnv)
141 struct TevStageConfig { 211 struct TevStageConfig {
@@ -257,11 +327,11 @@ struct Regs {
257 327
258 INSERT_PADDING_WORDS(0x1); 328 INSERT_PADDING_WORDS(0x1);
259 329
260 inline u32 GetColorBufferAddress() const { 330 inline u32 GetColorBufferPhysicalAddress() const {
261 return Memory::PhysicalToVirtualAddress(DecodeAddressRegister(color_buffer_address)); 331 return DecodeAddressRegister(color_buffer_address);
262 } 332 }
263 inline u32 GetDepthBufferAddress() const { 333 inline u32 GetDepthBufferPhysicalAddress() const {
264 return Memory::PhysicalToVirtualAddress(DecodeAddressRegister(depth_buffer_address)); 334 return DecodeAddressRegister(depth_buffer_address);
265 } 335 }
266 336
267 inline u32 GetWidth() const { 337 inline u32 GetWidth() const {
@@ -285,9 +355,8 @@ struct Regs {
285 355
286 BitField<0, 29, u32> base_address; 356 BitField<0, 29, u32> base_address;
287 357
288 inline u32 GetBaseAddress() const { 358 u32 GetPhysicalBaseAddress() const {
289 // TODO: Ugly, should fix PhysicalToVirtualAddress instead 359 return DecodeAddressRegister(base_address);
290 return DecodeAddressRegister(base_address) - Memory::FCRAM_PADDR + Memory::HEAP_GSP_VADDR;
291 } 360 }
292 361
293 // Descriptor for internal vertex attributes 362 // Descriptor for internal vertex attributes
@@ -423,7 +492,11 @@ struct Regs {
423 492
424 BitField<8, 2, TriangleTopology> triangle_topology; 493 BitField<8, 2, TriangleTopology> triangle_topology;
425 494
426 INSERT_PADDING_WORDS(0x5b); 495 INSERT_PADDING_WORDS(0x51);
496
497 BitField<0, 16, u32> vs_bool_uniforms;
498
499 INSERT_PADDING_WORDS(0x9);
427 500
428 // Offset to shader program entry point (in words) 501 // Offset to shader program entry point (in words)
429 BitField<0, 16, u32> vs_main_offset; 502 BitField<0, 16, u32> vs_main_offset;
@@ -517,26 +590,27 @@ struct Regs {
517 static std::string GetCommandName(int index) { 590 static std::string GetCommandName(int index) {
518 std::map<u32, std::string> map; 591 std::map<u32, std::string> map;
519 592
520 // TODO: MSVC does not support using offsetof() on non-static data members even though this
521 // is technically allowed since C++11. Hence, this functionality is disabled until
522 // MSVC properly supports it.
523 #ifndef _MSC_VER
524 Regs regs;
525 #define ADD_FIELD(name) \ 593 #define ADD_FIELD(name) \
526 do { \ 594 do { \
527 map.insert({PICA_REG_INDEX(name), #name}); \ 595 map.insert({PICA_REG_INDEX(name), #name}); \
528 for (u32 i = PICA_REG_INDEX(name) + 1; i < PICA_REG_INDEX(name) + sizeof(regs.name) / 4; ++i) \ 596 /* TODO: change to Regs::name when VS2015 and other compilers support it */ \
597 for (u32 i = PICA_REG_INDEX(name) + 1; i < PICA_REG_INDEX(name) + sizeof(Regs().name) / 4; ++i) \
529 map.insert({i, #name + std::string("+") + std::to_string(i-PICA_REG_INDEX(name))}); \ 598 map.insert({i, #name + std::string("+") + std::to_string(i-PICA_REG_INDEX(name))}); \
530 } while(false) 599 } while(false)
531 600
601 ADD_FIELD(trigger_irq);
532 ADD_FIELD(viewport_size_x); 602 ADD_FIELD(viewport_size_x);
533 ADD_FIELD(viewport_size_y); 603 ADD_FIELD(viewport_size_y);
534 ADD_FIELD(viewport_depth_range); 604 ADD_FIELD(viewport_depth_range);
535 ADD_FIELD(viewport_depth_far_plane); 605 ADD_FIELD(viewport_depth_far_plane);
536 ADD_FIELD(viewport_corner); 606 ADD_FIELD(viewport_corner);
537 ADD_FIELD(texturing_enable); 607 ADD_FIELD(texture0_enable);
538 ADD_FIELD(texture0); 608 ADD_FIELD(texture0);
539 ADD_FIELD(texture0_format); 609 ADD_FIELD(texture0_format);
610 ADD_FIELD(texture1);
611 ADD_FIELD(texture1_format);
612 ADD_FIELD(texture2);
613 ADD_FIELD(texture2_format);
540 ADD_FIELD(tev_stage0); 614 ADD_FIELD(tev_stage0);
541 ADD_FIELD(tev_stage1); 615 ADD_FIELD(tev_stage1);
542 ADD_FIELD(tev_stage2); 616 ADD_FIELD(tev_stage2);
@@ -550,6 +624,7 @@ struct Regs {
550 ADD_FIELD(trigger_draw); 624 ADD_FIELD(trigger_draw);
551 ADD_FIELD(trigger_draw_indexed); 625 ADD_FIELD(trigger_draw_indexed);
552 ADD_FIELD(triangle_topology); 626 ADD_FIELD(triangle_topology);
627 ADD_FIELD(vs_bool_uniforms);
553 ADD_FIELD(vs_main_offset); 628 ADD_FIELD(vs_main_offset);
554 ADD_FIELD(vs_input_register_map); 629 ADD_FIELD(vs_input_register_map);
555 ADD_FIELD(vs_uniform_setup); 630 ADD_FIELD(vs_uniform_setup);
@@ -557,7 +632,6 @@ struct Regs {
557 ADD_FIELD(vs_swizzle_patterns); 632 ADD_FIELD(vs_swizzle_patterns);
558 633
559 #undef ADD_FIELD 634 #undef ADD_FIELD
560 #endif // _MSC_VER
561 635
562 // Return empty string if no match is found 636 // Return empty string if no match is found
563 return map[index]; 637 return map[index];
@@ -593,6 +667,7 @@ private:
593#ifndef _MSC_VER 667#ifndef _MSC_VER
594#define ASSERT_REG_POSITION(field_name, position) static_assert(offsetof(Regs, field_name) == position * 4, "Field "#field_name" has invalid position") 668#define ASSERT_REG_POSITION(field_name, position) static_assert(offsetof(Regs, field_name) == position * 4, "Field "#field_name" has invalid position")
595 669
670ASSERT_REG_POSITION(trigger_irq, 0x10);
596ASSERT_REG_POSITION(viewport_size_x, 0x41); 671ASSERT_REG_POSITION(viewport_size_x, 0x41);
597ASSERT_REG_POSITION(viewport_size_y, 0x43); 672ASSERT_REG_POSITION(viewport_size_y, 0x43);
598ASSERT_REG_POSITION(viewport_depth_range, 0x4d); 673ASSERT_REG_POSITION(viewport_depth_range, 0x4d);
@@ -600,9 +675,13 @@ ASSERT_REG_POSITION(viewport_depth_far_plane, 0x4e);
600ASSERT_REG_POSITION(vs_output_attributes[0], 0x50); 675ASSERT_REG_POSITION(vs_output_attributes[0], 0x50);
601ASSERT_REG_POSITION(vs_output_attributes[1], 0x51); 676ASSERT_REG_POSITION(vs_output_attributes[1], 0x51);
602ASSERT_REG_POSITION(viewport_corner, 0x68); 677ASSERT_REG_POSITION(viewport_corner, 0x68);
603ASSERT_REG_POSITION(texturing_enable, 0x80); 678ASSERT_REG_POSITION(texture0_enable, 0x80);
604ASSERT_REG_POSITION(texture0, 0x81); 679ASSERT_REG_POSITION(texture0, 0x81);
605ASSERT_REG_POSITION(texture0_format, 0x8e); 680ASSERT_REG_POSITION(texture0_format, 0x8e);
681ASSERT_REG_POSITION(texture1, 0x91);
682ASSERT_REG_POSITION(texture1_format, 0x96);
683ASSERT_REG_POSITION(texture2, 0x99);
684ASSERT_REG_POSITION(texture2_format, 0x9e);
606ASSERT_REG_POSITION(tev_stage0, 0xc0); 685ASSERT_REG_POSITION(tev_stage0, 0xc0);
607ASSERT_REG_POSITION(tev_stage1, 0xc8); 686ASSERT_REG_POSITION(tev_stage1, 0xc8);
608ASSERT_REG_POSITION(tev_stage2, 0xd0); 687ASSERT_REG_POSITION(tev_stage2, 0xd0);
@@ -616,6 +695,7 @@ ASSERT_REG_POSITION(num_vertices, 0x228);
616ASSERT_REG_POSITION(trigger_draw, 0x22e); 695ASSERT_REG_POSITION(trigger_draw, 0x22e);
617ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f); 696ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f);
618ASSERT_REG_POSITION(triangle_topology, 0x25e); 697ASSERT_REG_POSITION(triangle_topology, 0x25e);
698ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0);
619ASSERT_REG_POSITION(vs_main_offset, 0x2ba); 699ASSERT_REG_POSITION(vs_main_offset, 0x2ba);
620ASSERT_REG_POSITION(vs_input_register_map, 0x2bb); 700ASSERT_REG_POSITION(vs_input_register_map, 0x2bb);
621ASSERT_REG_POSITION(vs_uniform_setup, 0x2c0); 701ASSERT_REG_POSITION(vs_uniform_setup, 0x2c0);
@@ -677,6 +757,26 @@ struct float24 {
677 return float24::FromFloat32(ToFloat32() - flt.ToFloat32()); 757 return float24::FromFloat32(ToFloat32() - flt.ToFloat32());
678 } 758 }
679 759
760 float24& operator *= (const float24& flt) {
761 value *= flt.ToFloat32();
762 return *this;
763 }
764
765 float24& operator /= (const float24& flt) {
766 value /= flt.ToFloat32();
767 return *this;
768 }
769
770 float24& operator += (const float24& flt) {
771 value += flt.ToFloat32();
772 return *this;
773 }
774
775 float24& operator -= (const float24& flt) {
776 value -= flt.ToFloat32();
777 return *this;
778 }
779
680 float24 operator - () const { 780 float24 operator - () const {
681 return float24::FromFloat32(-ToFloat32()); 781 return float24::FromFloat32(-ToFloat32());
682 } 782 }
@@ -697,6 +797,14 @@ struct float24 {
697 return ToFloat32() <= flt.ToFloat32(); 797 return ToFloat32() <= flt.ToFloat32();
698 } 798 }
699 799
800 bool operator == (const float24& flt) const {
801 return ToFloat32() == flt.ToFloat32();
802 }
803
804 bool operator != (const float24& flt) const {
805 return ToFloat32() != flt.ToFloat32();
806 }
807
700private: 808private:
701 // Stored as a regular float, merely for convenience 809 // Stored as a regular float, merely for convenience
702 // TODO: Perform proper arithmetic on this! 810 // TODO: Perform proper arithmetic on this!
@@ -714,5 +822,15 @@ union CommandHeader {
714 BitField<31, 1, u32> group_commands; 822 BitField<31, 1, u32> group_commands;
715}; 823};
716 824
825// TODO: Ugly, should fix PhysicalToVirtualAddress instead
826inline static u32 PAddrToVAddr(u32 addr) {
827 if (addr >= Memory::VRAM_PADDR && addr < Memory::VRAM_PADDR + Memory::VRAM_SIZE) {
828 return addr - Memory::VRAM_PADDR + Memory::VRAM_VADDR;
829 } else if (addr >= Memory::FCRAM_PADDR && addr < Memory::FCRAM_PADDR + Memory::FCRAM_SIZE) {
830 return addr - Memory::FCRAM_PADDR + Memory::HEAP_LINEAR_VADDR;
831 } else {
832 return 0;
833 }
834}
717 835
718} // namespace 836} // namespace
diff --git a/src/video_core/primitive_assembly.cpp b/src/video_core/primitive_assembly.cpp
index dabf2d1a3..242a07e26 100644
--- a/src/video_core/primitive_assembly.cpp
+++ b/src/video_core/primitive_assembly.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "pica.h" 5#include "pica.h"
@@ -30,20 +30,27 @@ void PrimitiveAssembler<VertexType>::SubmitVertex(VertexType& vtx, TriangleHandl
30 } 30 }
31 break; 31 break;
32 32
33 case Regs::TriangleTopology::Strip:
33 case Regs::TriangleTopology::Fan: 34 case Regs::TriangleTopology::Fan:
34 if (buffer_index == 2) { 35 if (strip_ready) {
35 buffer_index = 0; 36 // TODO: Should be "buffer[0], buffer[1], vtx" instead!
36 37 // Not quite sure why we need this order for things to show up properly.
37 triangle_handler(buffer[0], buffer[1], vtx); 38 // Maybe a bug in the rasterizer?
39 triangle_handler(buffer[1], buffer[0], vtx);
40 }
41 buffer[buffer_index] = vtx;
38 42
39 buffer[1] = vtx; 43 if (topology == Regs::TriangleTopology::Strip) {
40 } else { 44 strip_ready |= (buffer_index == 1);
41 buffer[buffer_index++] = vtx; 45 buffer_index = !buffer_index;
46 } else if (topology == Regs::TriangleTopology::Fan) {
47 buffer_index = 1;
48 strip_ready = true;
42 } 49 }
43 break; 50 break;
44 51
45 default: 52 default:
46 ERROR_LOG(GPU, "Unknown triangle topology %x:", (int)topology); 53 LOG_ERROR(HW_GPU, "Unknown triangle topology %x:", (int)topology);
47 break; 54 break;
48 } 55 }
49} 56}
diff --git a/src/video_core/primitive_assembly.h b/src/video_core/primitive_assembly.h
index ea2e2f61e..52ff4cd89 100644
--- a/src/video_core/primitive_assembly.h
+++ b/src/video_core/primitive_assembly.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -37,6 +37,7 @@ private:
37 37
38 int buffer_index; 38 int buffer_index;
39 VertexType buffer[2]; 39 VertexType buffer[2];
40 bool strip_ready = false;
40}; 41};
41 42
42 43
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index a35f0c0d8..a80148872 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
@@ -18,7 +18,7 @@ namespace Pica {
18namespace Rasterizer { 18namespace Rasterizer {
19 19
20static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) { 20static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
21 u32* color_buffer = (u32*)Memory::GetPointer(registers.framebuffer.GetColorBufferAddress()); 21 u32* color_buffer = reinterpret_cast<u32*>(Memory::GetPointer(PAddrToVAddr(registers.framebuffer.GetColorBufferPhysicalAddress())));
22 u32 value = (color.a() << 24) | (color.r() << 16) | (color.g() << 8) | color.b(); 22 u32 value = (color.a() << 24) | (color.r() << 16) | (color.g() << 8) | color.b();
23 23
24 // Assuming RGBA8 format until actual framebuffer format handling is implemented 24 // Assuming RGBA8 format until actual framebuffer format handling is implemented
@@ -26,14 +26,14 @@ static void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
26} 26}
27 27
28static u32 GetDepth(int x, int y) { 28static u32 GetDepth(int x, int y) {
29 u16* depth_buffer = (u16*)Memory::GetPointer(registers.framebuffer.GetDepthBufferAddress()); 29 u16* depth_buffer = reinterpret_cast<u16*>(Memory::GetPointer(PAddrToVAddr(registers.framebuffer.GetDepthBufferPhysicalAddress())));
30 30
31 // Assuming 16-bit depth buffer format until actual format handling is implemented 31 // Assuming 16-bit depth buffer format until actual format handling is implemented
32 return *(depth_buffer + x + y * registers.framebuffer.GetWidth()); 32 return *(depth_buffer + x + y * registers.framebuffer.GetWidth());
33} 33}
34 34
35static void SetDepth(int x, int y, u16 value) { 35static void SetDepth(int x, int y, u16 value) {
36 u16* depth_buffer = (u16*)Memory::GetPointer(registers.framebuffer.GetDepthBufferAddress()); 36 u16* depth_buffer = reinterpret_cast<u16*>(Memory::GetPointer(PAddrToVAddr(registers.framebuffer.GetDepthBufferPhysicalAddress())));
37 37
38 // Assuming 16-bit depth buffer format until actual format handling is implemented 38 // Assuming 16-bit depth buffer format until actual format handling is implemented
39 *(depth_buffer + x + y * registers.framebuffer.GetWidth()) = value; 39 *(depth_buffer + x + y * registers.framebuffer.GetWidth()) = value;
@@ -106,6 +106,11 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
106 int bias1 = IsRightSideOrFlatBottomEdge(vtxpos[1].xy(), vtxpos[2].xy(), vtxpos[0].xy()) ? -1 : 0; 106 int bias1 = IsRightSideOrFlatBottomEdge(vtxpos[1].xy(), vtxpos[2].xy(), vtxpos[0].xy()) ? -1 : 0;
107 int bias2 = IsRightSideOrFlatBottomEdge(vtxpos[2].xy(), vtxpos[0].xy(), vtxpos[1].xy()) ? -1 : 0; 107 int bias2 = IsRightSideOrFlatBottomEdge(vtxpos[2].xy(), vtxpos[0].xy(), vtxpos[1].xy()) ? -1 : 0;
108 108
109 auto w_inverse = Math::MakeVec(v0.pos.w, v1.pos.w, v2.pos.w);
110
111 auto textures = registers.GetTextures();
112 auto tev_stages = registers.GetTevStages();
113
109 // TODO: Not sure if looping through x first might be faster 114 // TODO: Not sure if looping through x first might be faster
110 for (u16 y = min_y; y < max_y; y += 0x10) { 115 for (u16 y = min_y; y < max_y; y += 0x10) {
111 for (u16 x = min_x; x < max_x; x += 0x10) { 116 for (u16 x = min_x; x < max_x; x += 0x10) {
@@ -129,6 +134,11 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
129 if (w0 < 0 || w1 < 0 || w2 < 0) 134 if (w0 < 0 || w1 < 0 || w2 < 0)
130 continue; 135 continue;
131 136
137 auto baricentric_coordinates = Math::MakeVec(float24::FromFloat32(static_cast<float>(w0)),
138 float24::FromFloat32(static_cast<float>(w1)),
139 float24::FromFloat32(static_cast<float>(w2)));
140 float24 interpolated_w_inverse = float24::FromFloat32(1.0f) / Math::Dot(w_inverse, baricentric_coordinates);
141
132 // Perspective correct attribute interpolation: 142 // Perspective correct attribute interpolation:
133 // Attribute values cannot be calculated by simple linear interpolation since 143 // Attribute values cannot be calculated by simple linear interpolation since
134 // they are not linear in screen space. For example, when interpolating a 144 // they are not linear in screen space. For example, when interpolating a
@@ -145,19 +155,9 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
145 // 155 //
146 // The generalization to three vertices is straightforward in baricentric coordinates. 156 // The generalization to three vertices is straightforward in baricentric coordinates.
147 auto GetInterpolatedAttribute = [&](float24 attr0, float24 attr1, float24 attr2) { 157 auto GetInterpolatedAttribute = [&](float24 attr0, float24 attr1, float24 attr2) {
148 auto attr_over_w = Math::MakeVec(attr0 / v0.pos.w, 158 auto attr_over_w = Math::MakeVec(attr0, attr1, attr2);
149 attr1 / v1.pos.w,
150 attr2 / v2.pos.w);
151 auto w_inverse = Math::MakeVec(float24::FromFloat32(1.f) / v0.pos.w,
152 float24::FromFloat32(1.f) / v1.pos.w,
153 float24::FromFloat32(1.f) / v2.pos.w);
154 auto baricentric_coordinates = Math::MakeVec(float24::FromFloat32(static_cast<float>(w0)),
155 float24::FromFloat32(static_cast<float>(w1)),
156 float24::FromFloat32(static_cast<float>(w2)));
157
158 float24 interpolated_attr_over_w = Math::Dot(attr_over_w, baricentric_coordinates); 159 float24 interpolated_attr_over_w = Math::Dot(attr_over_w, baricentric_coordinates);
159 float24 interpolated_w_inverse = Math::Dot(w_inverse, baricentric_coordinates); 160 return interpolated_attr_over_w * interpolated_w_inverse;
160 return interpolated_attr_over_w / interpolated_w_inverse;
161 }; 161 };
162 162
163 Math::Vec4<u8> primary_color{ 163 Math::Vec4<u8> primary_color{
@@ -167,60 +167,48 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
167 (u8)(GetInterpolatedAttribute(v0.color.a(), v1.color.a(), v2.color.a()).ToFloat32() * 255) 167 (u8)(GetInterpolatedAttribute(v0.color.a(), v1.color.a(), v2.color.a()).ToFloat32() * 255)
168 }; 168 };
169 169
170 Math::Vec4<u8> texture_color{}; 170 Math::Vec2<float24> uv[3];
171 float24 u = GetInterpolatedAttribute(v0.tc0.u(), v1.tc0.u(), v2.tc0.u()); 171 uv[0].u() = GetInterpolatedAttribute(v0.tc0.u(), v1.tc0.u(), v2.tc0.u());
172 float24 v = GetInterpolatedAttribute(v0.tc0.v(), v1.tc0.v(), v2.tc0.v()); 172 uv[0].v() = GetInterpolatedAttribute(v0.tc0.v(), v1.tc0.v(), v2.tc0.v());
173 if (registers.texturing_enable) { 173 uv[1].u() = GetInterpolatedAttribute(v0.tc1.u(), v1.tc1.u(), v2.tc1.u());
174 // Images are split into 8x8 tiles. Each tile is composed of four 4x4 subtiles each 174 uv[1].v() = GetInterpolatedAttribute(v0.tc1.v(), v1.tc1.v(), v2.tc1.v());
175 // of which is composed of four 2x2 subtiles each of which is composed of four texels. 175 uv[2].u() = GetInterpolatedAttribute(v0.tc2.u(), v1.tc2.u(), v2.tc2.u());
176 // Each structure is embedded into the next-bigger one in a diagonal pattern, e.g. 176 uv[2].v() = GetInterpolatedAttribute(v0.tc2.v(), v1.tc2.v(), v2.tc2.v());
177 // texels are laid out in a 2x2 subtile like this: 177
178 // 2 3 178 Math::Vec4<u8> texture_color[3]{};
179 // 0 1 179 for (int i = 0; i < 3; ++i) {
180 // 180 const auto& texture = textures[i];
181 // The full 8x8 tile has the texels arranged like this: 181 if (!texture.enabled)
182 // 182 continue;
183 // 42 43 46 47 58 59 62 63 183
184 // 40 41 44 45 56 57 60 61 184 _dbg_assert_(HW_GPU, 0 != texture.config.address);
185 // 34 35 38 39 50 51 54 55 185
186 // 32 33 36 37 48 49 52 53 186 int s = (int)(uv[i].u() * float24::FromFloat32(static_cast<float>(texture.config.width))).ToFloat32();
187 // 10 11 14 15 26 27 30 31 187 int t = (int)(uv[i].v() * float24::FromFloat32(static_cast<float>(texture.config.height))).ToFloat32();
188 // 08 09 12 13 24 25 28 29 188 auto GetWrappedTexCoord = [](Regs::TextureConfig::WrapMode mode, int val, unsigned size) {
189 // 02 03 06 07 18 19 22 23 189 switch (mode) {
190 // 00 01 04 05 16 17 20 21 190 case Regs::TextureConfig::ClampToEdge:
191 191 val = std::max(val, 0);
192 // TODO: This is currently hardcoded for RGB8 192 val = std::min(val, (int)size - 1);
193 u32* texture_data = (u32*)Memory::GetPointer(registers.texture0.GetPhysicalAddress()); 193 return val;
194 194
195 // TODO(neobrain): Not sure if this swizzling pattern is used for all textures. 195 case Regs::TextureConfig::Repeat:
196 // To be flexible in case different but similar patterns are used, we keep this 196 return (int)(((unsigned)val) % size);
197 // somewhat inefficient code around for now. 197
198 int s = (int)(u * float24::FromFloat32(static_cast<float>(registers.texture0.width))).ToFloat32(); 198 default:
199 int t = (int)(v * float24::FromFloat32(static_cast<float>(registers.texture0.height))).ToFloat32(); 199 LOG_ERROR(HW_GPU, "Unknown texture coordinate wrapping mode %x\n", (int)mode);
200 int texel_index_within_tile = 0; 200 _dbg_assert_(HW_GPU, 0);
201 for (int block_size_index = 0; block_size_index < 3; ++block_size_index) { 201 return 0;
202 int sub_tile_width = 1 << block_size_index; 202 }
203 int sub_tile_height = 1 << block_size_index; 203 };
204 204 s = GetWrappedTexCoord(registers.texture0.wrap_s, s, registers.texture0.width);
205 int sub_tile_index = (s & sub_tile_width) << block_size_index; 205 t = GetWrappedTexCoord(registers.texture0.wrap_t, t, registers.texture0.height);
206 sub_tile_index += 2 * ((t & sub_tile_height) << block_size_index); 206
207 texel_index_within_tile += sub_tile_index; 207 u8* texture_data = Memory::GetPointer(PAddrToVAddr(texture.config.GetPhysicalAddress()));
208 } 208 auto info = DebugUtils::TextureInfo::FromPicaRegister(texture.config, texture.format);
209 209
210 const int block_width = 8; 210 texture_color[i] = DebugUtils::LookupTexture(texture_data, s, t, info);
211 const int block_height = 8; 211 DebugUtils::DumpTexture(texture.config, texture_data);
212
213 int coarse_s = (s / block_width) * block_width;
214 int coarse_t = (t / block_height) * block_height;
215
216 const int row_stride = registers.texture0.width * 3;
217 u8* source_ptr = (u8*)texture_data + coarse_s * block_height * 3 + coarse_t * row_stride + texel_index_within_tile * 3;
218 texture_color.r() = source_ptr[2];
219 texture_color.g() = source_ptr[1];
220 texture_color.b() = source_ptr[0];
221 texture_color.a() = 0xFF;
222
223 DebugUtils::DumpTexture(registers.texture0, (u8*)texture_data);
224 } 212 }
225 213
226 // Texture environment - consists of 6 stages of color and alpha combining. 214 // Texture environment - consists of 6 stages of color and alpha combining.
@@ -231,28 +219,35 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
231 // with some basic arithmetic. Alpha combiners can be configured separately but work 219 // with some basic arithmetic. Alpha combiners can be configured separately but work
232 // analogously. 220 // analogously.
233 Math::Vec4<u8> combiner_output; 221 Math::Vec4<u8> combiner_output;
234 for (auto tev_stage : registers.GetTevStages()) { 222 for (const auto& tev_stage : tev_stages) {
235 using Source = Regs::TevStageConfig::Source; 223 using Source = Regs::TevStageConfig::Source;
236 using ColorModifier = Regs::TevStageConfig::ColorModifier; 224 using ColorModifier = Regs::TevStageConfig::ColorModifier;
237 using AlphaModifier = Regs::TevStageConfig::AlphaModifier; 225 using AlphaModifier = Regs::TevStageConfig::AlphaModifier;
238 using Operation = Regs::TevStageConfig::Operation; 226 using Operation = Regs::TevStageConfig::Operation;
239 227
240 auto GetColorSource = [&](Source source) -> Math::Vec3<u8> { 228 auto GetColorSource = [&](Source source) -> Math::Vec4<u8> {
241 switch (source) { 229 switch (source) {
242 case Source::PrimaryColor: 230 case Source::PrimaryColor:
243 return primary_color.rgb(); 231 return primary_color;
244 232
245 case Source::Texture0: 233 case Source::Texture0:
246 return texture_color.rgb(); 234 return texture_color[0];
235
236 case Source::Texture1:
237 return texture_color[1];
238
239 case Source::Texture2:
240 return texture_color[2];
247 241
248 case Source::Constant: 242 case Source::Constant:
249 return {tev_stage.const_r, tev_stage.const_g, tev_stage.const_b}; 243 return {tev_stage.const_r, tev_stage.const_g, tev_stage.const_b, tev_stage.const_a};
250 244
251 case Source::Previous: 245 case Source::Previous:
252 return combiner_output.rgb(); 246 return combiner_output;
253 247
254 default: 248 default:
255 ERROR_LOG(GPU, "Unknown color combiner source %d\n", (int)source); 249 LOG_ERROR(HW_GPU, "Unknown color combiner source %d\n", (int)source);
250 _dbg_assert_(HW_GPU, 0);
256 return {}; 251 return {};
257 } 252 }
258 }; 253 };
@@ -263,7 +258,13 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
263 return primary_color.a(); 258 return primary_color.a();
264 259
265 case Source::Texture0: 260 case Source::Texture0:
266 return texture_color.a(); 261 return texture_color[0].a();
262
263 case Source::Texture1:
264 return texture_color[1].a();
265
266 case Source::Texture2:
267 return texture_color[2].a();
267 268
268 case Source::Constant: 269 case Source::Constant:
269 return tev_stage.const_a; 270 return tev_stage.const_a;
@@ -272,18 +273,24 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
272 return combiner_output.a(); 273 return combiner_output.a();
273 274
274 default: 275 default:
275 ERROR_LOG(GPU, "Unknown alpha combiner source %d\n", (int)source); 276 LOG_ERROR(HW_GPU, "Unknown alpha combiner source %d\n", (int)source);
277 _dbg_assert_(HW_GPU, 0);
276 return 0; 278 return 0;
277 } 279 }
278 }; 280 };
279 281
280 auto GetColorModifier = [](ColorModifier factor, const Math::Vec3<u8>& values) -> Math::Vec3<u8> { 282 auto GetColorModifier = [](ColorModifier factor, const Math::Vec4<u8>& values) -> Math::Vec3<u8> {
281 switch (factor) 283 switch (factor)
282 { 284 {
283 case ColorModifier::SourceColor: 285 case ColorModifier::SourceColor:
284 return values; 286 return values.rgb();
287
288 case ColorModifier::SourceAlpha:
289 return { values.a(), values.a(), values.a() };
290
285 default: 291 default:
286 ERROR_LOG(GPU, "Unknown color factor %d\n", (int)factor); 292 LOG_ERROR(HW_GPU, "Unknown color factor %d\n", (int)factor);
293 _dbg_assert_(HW_GPU, 0);
287 return {}; 294 return {};
288 } 295 }
289 }; 296 };
@@ -292,8 +299,13 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
292 switch (factor) { 299 switch (factor) {
293 case AlphaModifier::SourceAlpha: 300 case AlphaModifier::SourceAlpha:
294 return value; 301 return value;
302
303 case AlphaModifier::OneMinusSourceAlpha:
304 return 255 - value;
305
295 default: 306 default:
296 ERROR_LOG(GPU, "Unknown color factor %d\n", (int)factor); 307 LOG_ERROR(HW_GPU, "Unknown alpha factor %d\n", (int)factor);
308 _dbg_assert_(HW_GPU, 0);
297 return 0; 309 return 0;
298 } 310 }
299 }; 311 };
@@ -306,8 +318,21 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
306 case Operation::Modulate: 318 case Operation::Modulate:
307 return ((input[0] * input[1]) / 255).Cast<u8>(); 319 return ((input[0] * input[1]) / 255).Cast<u8>();
308 320
321 case Operation::Add:
322 {
323 auto result = input[0] + input[1];
324 result.r() = std::min(255, result.r());
325 result.g() = std::min(255, result.g());
326 result.b() = std::min(255, result.b());
327 return result.Cast<u8>();
328 }
329
330 case Operation::Lerp:
331 return ((input[0] * input[2] + input[1] * (Math::MakeVec<u8>(255, 255, 255) - input[2]).Cast<u8>()) / 255).Cast<u8>();
332
309 default: 333 default:
310 ERROR_LOG(GPU, "Unknown color combiner operation %d\n", (int)op); 334 LOG_ERROR(HW_GPU, "Unknown color combiner operation %d\n", (int)op);
335 _dbg_assert_(HW_GPU, 0);
311 return {}; 336 return {};
312 } 337 }
313 }; 338 };
@@ -320,8 +345,15 @@ void ProcessTriangle(const VertexShader::OutputVertex& v0,
320 case Operation::Modulate: 345 case Operation::Modulate:
321 return input[0] * input[1] / 255; 346 return input[0] * input[1] / 255;
322 347
348 case Operation::Add:
349 return std::min(255, input[0] + input[1]);
350
351 case Operation::Lerp:
352 return (input[0] * input[2] + input[1] * (255 - input[2])) / 255;
353
323 default: 354 default:
324 ERROR_LOG(GPU, "Unknown alpha combiner operation %d\n", (int)op); 355 LOG_ERROR(HW_GPU, "Unknown alpha combiner operation %d\n", (int)op);
356 _dbg_assert_(HW_GPU, 0);
325 return 0; 357 return 0;
326 } 358 }
327 }; 359 };
diff --git a/src/video_core/rasterizer.h b/src/video_core/rasterizer.h
index 500be9462..42148f8b1 100644
--- a/src/video_core/rasterizer.h
+++ b/src/video_core/rasterizer.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index bce402b88..b77f29c11 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp
index a0eb0418c..e982e3746 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_util.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "gl_shader_util.h" 5#include "gl_shader_util.h"
@@ -20,9 +20,9 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
20 int info_log_length; 20 int info_log_length;
21 21
22 // Compile Vertex Shader 22 // Compile Vertex Shader
23 DEBUG_LOG(GPU, "Compiling vertex shader."); 23 LOG_DEBUG(Render_OpenGL, "Compiling vertex shader...");
24 24
25 glShaderSource(vertex_shader_id, 1, &vertex_shader, NULL); 25 glShaderSource(vertex_shader_id, 1, &vertex_shader, nullptr);
26 glCompileShader(vertex_shader_id); 26 glCompileShader(vertex_shader_id);
27 27
28 // Check Vertex Shader 28 // Check Vertex Shader
@@ -31,14 +31,18 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
31 31
32 if (info_log_length > 1) { 32 if (info_log_length > 1) {
33 std::vector<char> vertex_shader_error(info_log_length); 33 std::vector<char> vertex_shader_error(info_log_length);
34 glGetShaderInfoLog(vertex_shader_id, info_log_length, NULL, &vertex_shader_error[0]); 34 glGetShaderInfoLog(vertex_shader_id, info_log_length, nullptr, &vertex_shader_error[0]);
35 DEBUG_LOG(GPU, "%s", &vertex_shader_error[0]); 35 if (result) {
36 LOG_DEBUG(Render_OpenGL, "%s", &vertex_shader_error[0]);
37 } else {
38 LOG_ERROR(Render_OpenGL, "Error compiling vertex shader:\n%s", &vertex_shader_error[0]);
39 }
36 } 40 }
37 41
38 // Compile Fragment Shader 42 // Compile Fragment Shader
39 DEBUG_LOG(GPU, "Compiling fragment shader."); 43 LOG_DEBUG(Render_OpenGL, "Compiling fragment shader...");
40 44
41 glShaderSource(fragment_shader_id, 1, &fragment_shader, NULL); 45 glShaderSource(fragment_shader_id, 1, &fragment_shader, nullptr);
42 glCompileShader(fragment_shader_id); 46 glCompileShader(fragment_shader_id);
43 47
44 // Check Fragment Shader 48 // Check Fragment Shader
@@ -47,12 +51,16 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
47 51
48 if (info_log_length > 1) { 52 if (info_log_length > 1) {
49 std::vector<char> fragment_shader_error(info_log_length); 53 std::vector<char> fragment_shader_error(info_log_length);
50 glGetShaderInfoLog(fragment_shader_id, info_log_length, NULL, &fragment_shader_error[0]); 54 glGetShaderInfoLog(fragment_shader_id, info_log_length, nullptr, &fragment_shader_error[0]);
51 DEBUG_LOG(GPU, "%s", &fragment_shader_error[0]); 55 if (result) {
56 LOG_DEBUG(Render_OpenGL, "%s", &fragment_shader_error[0]);
57 } else {
58 LOG_ERROR(Render_OpenGL, "Error compiling fragment shader:\n%s", &fragment_shader_error[0]);
59 }
52 } 60 }
53 61
54 // Link the program 62 // Link the program
55 DEBUG_LOG(GPU, "Linking program."); 63 LOG_DEBUG(Render_OpenGL, "Linking program...");
56 64
57 GLuint program_id = glCreateProgram(); 65 GLuint program_id = glCreateProgram();
58 glAttachShader(program_id, vertex_shader_id); 66 glAttachShader(program_id, vertex_shader_id);
@@ -65,8 +73,12 @@ GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
65 73
66 if (info_log_length > 1) { 74 if (info_log_length > 1) {
67 std::vector<char> program_error(info_log_length); 75 std::vector<char> program_error(info_log_length);
68 glGetProgramInfoLog(program_id, info_log_length, NULL, &program_error[0]); 76 glGetProgramInfoLog(program_id, info_log_length, nullptr, &program_error[0]);
69 DEBUG_LOG(GPU, "%s", &program_error[0]); 77 if (result) {
78 LOG_DEBUG(Render_OpenGL, "%s", &program_error[0]);
79 } else {
80 LOG_ERROR(Render_OpenGL, "Error linking shader:\n%s", &program_error[0]);
81 }
70 } 82 }
71 83
72 glDeleteShader(vertex_shader_id); 84 glDeleteShader(vertex_shader_id);
diff --git a/src/video_core/renderer_opengl/gl_shader_util.h b/src/video_core/renderer_opengl/gl_shader_util.h
index 986cbabc0..9b93a8a0c 100644
--- a/src/video_core/renderer_opengl/gl_shader_util.h
+++ b/src/video_core/renderer_opengl/gl_shader_util.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/video_core/renderer_opengl/gl_shaders.h b/src/video_core/renderer_opengl/gl_shaders.h
index 0f88ab802..746a37afe 100644
--- a/src/video_core/renderer_opengl/gl_shaders.h
+++ b/src/video_core/renderer_opengl/gl_shaders.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index abbb4c2cb..4df3a5e25 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/hw/gpu.h" 5#include "core/hw/gpu.h"
@@ -61,7 +61,7 @@ void RendererOpenGL::SwapBuffers() {
61 for(int i : {0, 1}) { 61 for(int i : {0, 1}) {
62 const auto& framebuffer = GPU::g_regs.framebuffer_config[i]; 62 const auto& framebuffer = GPU::g_regs.framebuffer_config[i];
63 63
64 if (textures[i].width != framebuffer.width || textures[i].height != framebuffer.height) { 64 if (textures[i].width != (GLsizei)framebuffer.width || textures[i].height != (GLsizei)framebuffer.height) {
65 // Reallocate texture if the framebuffer size has changed. 65 // Reallocate texture if the framebuffer size has changed.
66 // This is expected to not happen very often and hence should not be a 66 // This is expected to not happen very often and hence should not be a
67 // performance problem. 67 // performance problem.
@@ -90,7 +90,7 @@ void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig&
90 const VAddr framebuffer_vaddr = Memory::PhysicalToVirtualAddress( 90 const VAddr framebuffer_vaddr = Memory::PhysicalToVirtualAddress(
91 framebuffer.active_fb == 1 ? framebuffer.address_left2 : framebuffer.address_left1); 91 framebuffer.active_fb == 1 ? framebuffer.address_left2 : framebuffer.address_left1);
92 92
93 DEBUG_LOG(GPU, "0x%08x bytes from 0x%08x(%dx%d), fmt %x", 93 LOG_TRACE(Render_OpenGL, "0x%08x bytes from 0x%08x(%dx%d), fmt %x",
94 framebuffer.stride * framebuffer.height, 94 framebuffer.stride * framebuffer.height,
95 framebuffer_vaddr, (int)framebuffer.width, 95 framebuffer_vaddr, (int)framebuffer.width,
96 (int)framebuffer.height, (int)framebuffer.format); 96 (int)framebuffer.height, (int)framebuffer.format);
@@ -98,15 +98,15 @@ void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig&
98 const u8* framebuffer_data = Memory::GetPointer(framebuffer_vaddr); 98 const u8* framebuffer_data = Memory::GetPointer(framebuffer_vaddr);
99 99
100 // TODO: Handle other pixel formats 100 // TODO: Handle other pixel formats
101 _dbg_assert_msg_(RENDER, framebuffer.color_format == GPU::Regs::PixelFormat::RGB8, 101 _dbg_assert_msg_(Render_OpenGL, framebuffer.color_format == GPU::Regs::PixelFormat::RGB8,
102 "Unsupported 3DS pixel format."); 102 "Unsupported 3DS pixel format.");
103 103
104 size_t pixel_stride = framebuffer.stride / 3; 104 size_t pixel_stride = framebuffer.stride / 3;
105 // OpenGL only supports specifying a stride in units of pixels, not bytes, unfortunately 105 // OpenGL only supports specifying a stride in units of pixels, not bytes, unfortunately
106 _dbg_assert_(RENDER, pixel_stride * 3 == framebuffer.stride); 106 _dbg_assert_(Render_OpenGL, pixel_stride * 3 == framebuffer.stride);
107 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default 107 // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default
108 // only allows rows to have a memory alignement of 4. 108 // only allows rows to have a memory alignement of 4.
109 _dbg_assert_(RENDER, pixel_stride % 4 == 0); 109 _dbg_assert_(Render_OpenGL, pixel_stride % 4 == 0);
110 110
111 glBindTexture(GL_TEXTURE_2D, texture.handle); 111 glBindTexture(GL_TEXTURE_2D, texture.handle);
112 glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride); 112 glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride);
@@ -240,14 +240,14 @@ MathUtil::Rectangle<unsigned> RendererOpenGL::GetViewportExtent() {
240 MathUtil::Rectangle<unsigned> viewport_extent; 240 MathUtil::Rectangle<unsigned> viewport_extent;
241 if (window_aspect_ratio > emulation_aspect_ratio) { 241 if (window_aspect_ratio > emulation_aspect_ratio) {
242 // Window is narrower than the emulation content => apply borders to the top and bottom 242 // Window is narrower than the emulation content => apply borders to the top and bottom
243 unsigned viewport_height = emulation_aspect_ratio * framebuffer_width; 243 unsigned viewport_height = static_cast<unsigned>(std::round(emulation_aspect_ratio * framebuffer_width));
244 viewport_extent.left = 0; 244 viewport_extent.left = 0;
245 viewport_extent.top = (framebuffer_height - viewport_height) / 2; 245 viewport_extent.top = (framebuffer_height - viewport_height) / 2;
246 viewport_extent.right = viewport_extent.left + framebuffer_width; 246 viewport_extent.right = viewport_extent.left + framebuffer_width;
247 viewport_extent.bottom = viewport_extent.top + viewport_height; 247 viewport_extent.bottom = viewport_extent.top + viewport_height;
248 } else { 248 } else {
249 // Otherwise, apply borders to the left and right sides of the window. 249 // Otherwise, apply borders to the left and right sides of the window.
250 unsigned viewport_width = framebuffer_height / emulation_aspect_ratio; 250 unsigned viewport_width = static_cast<unsigned>(std::round(framebuffer_height / emulation_aspect_ratio));
251 viewport_extent.left = (framebuffer_width - viewport_width) / 2; 251 viewport_extent.left = (framebuffer_width - viewport_width) / 2;
252 viewport_extent.top = 0; 252 viewport_extent.top = 0;
253 viewport_extent.right = viewport_extent.left + viewport_width; 253 viewport_extent.right = viewport_extent.left + viewport_width;
@@ -263,11 +263,11 @@ void RendererOpenGL::Init() {
263 263
264 int err = ogl_LoadFunctions(); 264 int err = ogl_LoadFunctions();
265 if (ogl_LOAD_SUCCEEDED != err) { 265 if (ogl_LOAD_SUCCEEDED != err) {
266 ERROR_LOG(RENDER, "Failed to initialize GL functions! Exiting..."); 266 LOG_CRITICAL(Render_OpenGL, "Failed to initialize GL functions! Exiting...");
267 exit(-1); 267 exit(-1);
268 } 268 }
269 269
270 NOTICE_LOG(RENDER, "GL_VERSION: %s\n", glGetString(GL_VERSION)); 270 LOG_INFO(Render_OpenGL, "GL_VERSION: %s", glGetString(GL_VERSION));
271 InitOpenGLObjects(); 271 InitOpenGLObjects();
272} 272}
273 273
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h
index 7fdcec731..cf78c1e77 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.h
+++ b/src/video_core/renderer_opengl/renderer_opengl.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/video_core/utils.cpp b/src/video_core/utils.cpp
index f1156a493..c7cc93cea 100644
--- a/src/video_core/utils.cpp
+++ b/src/video_core/utils.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <stdio.h> 5#include <stdio.h>
diff --git a/src/video_core/utils.h b/src/video_core/utils.h
index 21380a908..63ebccbde 100644
--- a/src/video_core/utils.h
+++ b/src/video_core/utils.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp
index 96625791c..bed5081a0 100644
--- a/src/video_core/vertex_shader.cpp
+++ b/src/video_core/vertex_shader.cpp
@@ -1,12 +1,26 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <stack>
6
7#include <boost/range/algorithm.hpp>
8
9#include <common/file_util.h>
10
11#include <core/mem_map.h>
12
13#include <nihstro/shader_bytecode.h>
14
15
5#include "pica.h" 16#include "pica.h"
6#include "vertex_shader.h" 17#include "vertex_shader.h"
7#include "debug_utils/debug_utils.h" 18#include "debug_utils/debug_utils.h"
8#include <core/mem_map.h> 19
9#include <common/file_util.h> 20using nihstro::Instruction;
21using nihstro::RegisterType;
22using nihstro::SourceRegister;
23using nihstro::SwizzlePattern;
10 24
11namespace Pica { 25namespace Pica {
12 26
@@ -14,13 +28,14 @@ namespace VertexShader {
14 28
15static struct { 29static struct {
16 Math::Vec4<float24> f[96]; 30 Math::Vec4<float24> f[96];
17} shader_uniforms;
18 31
32 std::array<bool,16> b;
33} shader_uniforms;
19 34
20// TODO: Not sure where the shader binary and swizzle patterns are supposed to be loaded to! 35// TODO: Not sure where the shader binary and swizzle patterns are supposed to be loaded to!
21// For now, we just keep these local arrays around. 36// For now, we just keep these local arrays around.
22static u32 shader_memory[1024]; 37static std::array<u32, 1024> shader_memory;
23static u32 swizzle_data[1024]; 38static std::array<u32, 1024> swizzle_data;
24 39
25void SubmitShaderMemoryChange(u32 addr, u32 value) 40void SubmitShaderMemoryChange(u32 addr, u32 value)
26{ 41{
@@ -37,6 +52,21 @@ Math::Vec4<float24>& GetFloatUniform(u32 index)
37 return shader_uniforms.f[index]; 52 return shader_uniforms.f[index];
38} 53}
39 54
55bool& GetBoolUniform(u32 index)
56{
57 return shader_uniforms.b[index];
58}
59
60const std::array<u32, 1024>& GetShaderBinary()
61{
62 return shader_memory;
63}
64
65const std::array<u32, 1024>& GetSwizzlePatterns()
66{
67 return swizzle_data;
68}
69
40struct VertexShaderState { 70struct VertexShaderState {
41 u32* program_counter; 71 u32* program_counter;
42 72
@@ -44,13 +74,23 @@ struct VertexShaderState {
44 float24* output_register_table[7*4]; 74 float24* output_register_table[7*4];
45 75
46 Math::Vec4<float24> temporary_registers[16]; 76 Math::Vec4<float24> temporary_registers[16];
47 bool status_registers[2]; 77 bool conditional_code[2];
78
79 // Two Address registers and one loop counter
80 // TODO: How many bits do these actually have?
81 s32 address_registers[3];
48 82
49 enum { 83 enum {
50 INVALID_ADDRESS = 0xFFFFFFFF 84 INVALID_ADDRESS = 0xFFFFFFFF
51 }; 85 };
52 u32 call_stack[8]; // TODO: What is the maximal call stack depth? 86
53 u32* call_stack_pointer; 87 struct CallStackElement {
88 u32 final_address;
89 u32 return_address;
90 };
91
92 // TODO: Is there a maximal size for this?
93 std::stack<CallStackElement> call_stack;
54 94
55 struct { 95 struct {
56 u32 max_offset; // maximum program counter ever reached 96 u32 max_offset; // maximum program counter ever reached
@@ -59,49 +99,105 @@ struct VertexShaderState {
59}; 99};
60 100
61static void ProcessShaderCode(VertexShaderState& state) { 101static void ProcessShaderCode(VertexShaderState& state) {
102
103 // Placeholder for invalid inputs
104 static float24 dummy_vec4_float24[4];
105
62 while (true) { 106 while (true) {
63 bool increment_pc = true; 107 if (!state.call_stack.empty()) {
108 if (state.program_counter - shader_memory.data() == state.call_stack.top().final_address) {
109 state.program_counter = &shader_memory[state.call_stack.top().return_address];
110 state.call_stack.pop();
111
112 // TODO: Is "trying again" accurate to hardware?
113 continue;
114 }
115 }
116
64 bool exit_loop = false; 117 bool exit_loop = false;
65 const Instruction& instr = *(const Instruction*)state.program_counter; 118 const Instruction& instr = *(const Instruction*)state.program_counter;
66 state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + (state.program_counter - shader_memory));
67
68 const float24* src1_ = (instr.common.src1 < 0x10) ? state.input_register_table[instr.common.src1.GetIndex()]
69 : (instr.common.src1 < 0x20) ? &state.temporary_registers[instr.common.src1.GetIndex()].x
70 : (instr.common.src1 < 0x80) ? &shader_uniforms.f[instr.common.src1.GetIndex()].x
71 : nullptr;
72 const float24* src2_ = (instr.common.src2 < 0x10) ? state.input_register_table[instr.common.src2.GetIndex()]
73 : &state.temporary_registers[instr.common.src2.GetIndex()].x;
74 float24* dest = (instr.common.dest < 0x08) ? state.output_register_table[4*instr.common.dest.GetIndex()]
75 : (instr.common.dest < 0x10) ? nullptr
76 : (instr.common.dest < 0x20) ? &state.temporary_registers[instr.common.dest.GetIndex()][0]
77 : nullptr;
78
79 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id]; 119 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.common.operand_desc_id];
80 const bool negate_src1 = (swizzle.negate != 0);
81 120
82 float24 src1[4] = { 121 auto call = [&](VertexShaderState& state, u32 offset, u32 num_instructions, u32 return_offset) {
83 src1_[(int)swizzle.GetSelectorSrc1(0)], 122 state.program_counter = &shader_memory[offset] - 1; // -1 to make sure when incrementing the PC we end up at the correct offset
84 src1_[(int)swizzle.GetSelectorSrc1(1)], 123 state.call_stack.push({ offset + num_instructions, return_offset });
85 src1_[(int)swizzle.GetSelectorSrc1(2)],
86 src1_[(int)swizzle.GetSelectorSrc1(3)],
87 }; 124 };
88 if (negate_src1) { 125 u32 binary_offset = state.program_counter - shader_memory.data();
89 src1[0] = src1[0] * float24::FromFloat32(-1); 126
90 src1[1] = src1[1] * float24::FromFloat32(-1); 127 state.debug.max_offset = std::max<u32>(state.debug.max_offset, 1 + binary_offset);
91 src1[2] = src1[2] * float24::FromFloat32(-1); 128
92 src1[3] = src1[3] * float24::FromFloat32(-1); 129 auto LookupSourceRegister = [&](const SourceRegister& source_reg) -> const float24* {
93 } 130 switch (source_reg.GetRegisterType()) {
94 const float24 src2[4] = { 131 case RegisterType::Input:
95 src2_[(int)swizzle.GetSelectorSrc2(0)], 132 return state.input_register_table[source_reg.GetIndex()];
96 src2_[(int)swizzle.GetSelectorSrc2(1)], 133
97 src2_[(int)swizzle.GetSelectorSrc2(2)], 134 case RegisterType::Temporary:
98 src2_[(int)swizzle.GetSelectorSrc2(3)], 135 return &state.temporary_registers[source_reg.GetIndex()].x;
136
137 case RegisterType::FloatUniform:
138 return &shader_uniforms.f[source_reg.GetIndex()].x;
139
140 default:
141 return dummy_vec4_float24;
142 }
99 }; 143 };
100 144
101 switch (instr.opcode) { 145 switch (instr.opcode.GetInfo().type) {
146 case Instruction::OpCodeType::Arithmetic:
147 {
148 bool is_inverted = 0 != (instr.opcode.GetInfo().subtype & Instruction::OpCodeInfo::SrcInversed);
149 if (is_inverted) {
150 // TODO: We don't really support this properly: For instance, the address register
151 // offset needs to be applied to SRC2 instead, etc.
152 // For now, we just abort in this situation.
153 LOG_CRITICAL(HW_GPU, "Bad condition...");
154 exit(0);
155 }
156
157 const int address_offset = (instr.common.address_register_index == 0)
158 ? 0 : state.address_registers[instr.common.address_register_index - 1];
159
160 const float24* src1_ = LookupSourceRegister(instr.common.GetSrc1(is_inverted) + address_offset);
161 const float24* src2_ = LookupSourceRegister(instr.common.GetSrc2(is_inverted));
162
163 const bool negate_src1 = ((bool)swizzle.negate_src1 != false);
164 const bool negate_src2 = ((bool)swizzle.negate_src2 != false);
165
166 float24 src1[4] = {
167 src1_[(int)swizzle.GetSelectorSrc1(0)],
168 src1_[(int)swizzle.GetSelectorSrc1(1)],
169 src1_[(int)swizzle.GetSelectorSrc1(2)],
170 src1_[(int)swizzle.GetSelectorSrc1(3)],
171 };
172 if (negate_src1) {
173 src1[0] = src1[0] * float24::FromFloat32(-1);
174 src1[1] = src1[1] * float24::FromFloat32(-1);
175 src1[2] = src1[2] * float24::FromFloat32(-1);
176 src1[3] = src1[3] * float24::FromFloat32(-1);
177 }
178 float24 src2[4] = {
179 src2_[(int)swizzle.GetSelectorSrc2(0)],
180 src2_[(int)swizzle.GetSelectorSrc2(1)],
181 src2_[(int)swizzle.GetSelectorSrc2(2)],
182 src2_[(int)swizzle.GetSelectorSrc2(3)],
183 };
184 if (negate_src2) {
185 src2[0] = src2[0] * float24::FromFloat32(-1);
186 src2[1] = src2[1] * float24::FromFloat32(-1);
187 src2[2] = src2[2] * float24::FromFloat32(-1);
188 src2[3] = src2[3] * float24::FromFloat32(-1);
189 }
190
191 float24* dest = (instr.common.dest < 0x08) ? state.output_register_table[4*instr.common.dest.GetIndex()]
192 : (instr.common.dest < 0x10) ? dummy_vec4_float24
193 : (instr.common.dest < 0x20) ? &state.temporary_registers[instr.common.dest.GetIndex()][0]
194 : dummy_vec4_float24;
195
196 state.debug.max_opdesc_id = std::max<u32>(state.debug.max_opdesc_id, 1+instr.common.operand_desc_id);
197
198 switch (instr.opcode.EffectiveOpCode()) {
102 case Instruction::OpCode::ADD: 199 case Instruction::OpCode::ADD:
103 { 200 {
104 state.debug.max_opdesc_id = std::max<u32>(state.debug.max_opdesc_id, 1+instr.common.operand_desc_id);
105 for (int i = 0; i < 4; ++i) { 201 for (int i = 0; i < 4; ++i) {
106 if (!swizzle.DestComponentEnabled(i)) 202 if (!swizzle.DestComponentEnabled(i))
107 continue; 203 continue;
@@ -114,7 +210,6 @@ static void ProcessShaderCode(VertexShaderState& state) {
114 210
115 case Instruction::OpCode::MUL: 211 case Instruction::OpCode::MUL:
116 { 212 {
117 state.debug.max_opdesc_id = std::max<u32>(state.debug.max_opdesc_id, 1+instr.common.operand_desc_id);
118 for (int i = 0; i < 4; ++i) { 213 for (int i = 0; i < 4; ++i) {
119 if (!swizzle.DestComponentEnabled(i)) 214 if (!swizzle.DestComponentEnabled(i))
120 continue; 215 continue;
@@ -125,10 +220,18 @@ static void ProcessShaderCode(VertexShaderState& state) {
125 break; 220 break;
126 } 221 }
127 222
223 case Instruction::OpCode::MAX:
224 for (int i = 0; i < 4; ++i) {
225 if (!swizzle.DestComponentEnabled(i))
226 continue;
227
228 dest[i] = std::max(src1[i], src2[i]);
229 }
230 break;
231
128 case Instruction::OpCode::DP3: 232 case Instruction::OpCode::DP3:
129 case Instruction::OpCode::DP4: 233 case Instruction::OpCode::DP4:
130 { 234 {
131 state.debug.max_opdesc_id = std::max<u32>(state.debug.max_opdesc_id, 1+instr.common.operand_desc_id);
132 float24 dot = float24::FromFloat32(0.f); 235 float24 dot = float24::FromFloat32(0.f);
133 int num_components = (instr.opcode == Instruction::OpCode::DP3) ? 3 : 4; 236 int num_components = (instr.opcode == Instruction::OpCode::DP3) ? 3 : 4;
134 for (int i = 0; i < num_components; ++i) 237 for (int i = 0; i < num_components; ++i)
@@ -146,7 +249,6 @@ static void ProcessShaderCode(VertexShaderState& state) {
146 // Reciprocal 249 // Reciprocal
147 case Instruction::OpCode::RCP: 250 case Instruction::OpCode::RCP:
148 { 251 {
149 state.debug.max_opdesc_id = std::max<u32>(state.debug.max_opdesc_id, 1+instr.common.operand_desc_id);
150 for (int i = 0; i < 4; ++i) { 252 for (int i = 0; i < 4; ++i) {
151 if (!swizzle.DestComponentEnabled(i)) 253 if (!swizzle.DestComponentEnabled(i))
152 continue; 254 continue;
@@ -162,7 +264,6 @@ static void ProcessShaderCode(VertexShaderState& state) {
162 // Reciprocal Square Root 264 // Reciprocal Square Root
163 case Instruction::OpCode::RSQ: 265 case Instruction::OpCode::RSQ:
164 { 266 {
165 state.debug.max_opdesc_id = std::max<u32>(state.debug.max_opdesc_id, 1+instr.common.operand_desc_id);
166 for (int i = 0; i < 4; ++i) { 267 for (int i = 0; i < 4; ++i) {
167 if (!swizzle.DestComponentEnabled(i)) 268 if (!swizzle.DestComponentEnabled(i))
168 continue; 269 continue;
@@ -175,9 +276,21 @@ static void ProcessShaderCode(VertexShaderState& state) {
175 break; 276 break;
176 } 277 }
177 278
279 case Instruction::OpCode::MOVA:
280 {
281 for (int i = 0; i < 2; ++i) {
282 if (!swizzle.DestComponentEnabled(i))
283 continue;
284
285 // TODO: Figure out how the rounding is done on hardware
286 state.address_registers[i] = static_cast<s32>(src1[i].ToFloat32());
287 }
288
289 break;
290 }
291
178 case Instruction::OpCode::MOV: 292 case Instruction::OpCode::MOV:
179 { 293 {
180 state.debug.max_opdesc_id = std::max<u32>(state.debug.max_opdesc_id, 1+instr.common.operand_desc_id);
181 for (int i = 0; i < 4; ++i) { 294 for (int i = 0; i < 4; ++i) {
182 if (!swizzle.DestComponentEnabled(i)) 295 if (!swizzle.DestComponentEnabled(i))
183 continue; 296 continue;
@@ -187,39 +300,137 @@ static void ProcessShaderCode(VertexShaderState& state) {
187 break; 300 break;
188 } 301 }
189 302
190 case Instruction::OpCode::RET: 303 case Instruction::OpCode::CMP:
191 if (*state.call_stack_pointer == VertexShaderState::INVALID_ADDRESS) { 304 for (int i = 0; i < 2; ++i) {
192 exit_loop = true; 305 // TODO: Can you restrict to one compare via dest masking?
193 } else { 306
194 // Jump back to call stack position, invalidate call stack entry, move up call stack pointer 307 auto compare_op = instr.common.compare_op;
195 state.program_counter = &shader_memory[*state.call_stack_pointer]; 308 auto op = (i == 0) ? compare_op.x.Value() : compare_op.y.Value();
196 *state.call_stack_pointer-- = VertexShaderState::INVALID_ADDRESS; 309
310 switch (op) {
311 case compare_op.Equal:
312 state.conditional_code[i] = (src1[i] == src2[i]);
313 break;
314
315 case compare_op.NotEqual:
316 state.conditional_code[i] = (src1[i] != src2[i]);
317 break;
318
319 case compare_op.LessThan:
320 state.conditional_code[i] = (src1[i] < src2[i]);
321 break;
322
323 case compare_op.LessEqual:
324 state.conditional_code[i] = (src1[i] <= src2[i]);
325 break;
326
327 case compare_op.GreaterThan:
328 state.conditional_code[i] = (src1[i] > src2[i]);
329 break;
330
331 case compare_op.GreaterEqual:
332 state.conditional_code[i] = (src1[i] >= src2[i]);
333 break;
334
335 default:
336 LOG_ERROR(HW_GPU, "Unknown compare mode %x", static_cast<int>(op));
337 break;
338 }
197 } 339 }
340 break;
341
342 default:
343 LOG_ERROR(HW_GPU, "Unhandled arithmetic instruction: 0x%02x (%s): 0x%08x",
344 (int)instr.opcode.Value(), instr.opcode.GetInfo().name, instr.hex);
345 _dbg_assert_(HW_GPU, 0);
346 break;
347 }
198 348
349 break;
350 }
351 default:
352 // Handle each instruction on its own
353 switch (instr.opcode) {
354 case Instruction::OpCode::END:
355 exit_loop = true;
199 break; 356 break;
200 357
201 case Instruction::OpCode::CALL: 358 case Instruction::OpCode::CALL:
202 increment_pc = false; 359 call(state,
360 instr.flow_control.dest_offset,
361 instr.flow_control.num_instructions,
362 binary_offset + 1);
363 break;
203 364
204 _dbg_assert_(GPU, state.call_stack_pointer - state.call_stack < sizeof(state.call_stack)); 365 case Instruction::OpCode::NOP:
366 break;
367
368 case Instruction::OpCode::IFU:
369 if (shader_uniforms.b[instr.flow_control.bool_uniform_id]) {
370 call(state,
371 binary_offset + 1,
372 instr.flow_control.dest_offset - binary_offset - 1,
373 instr.flow_control.dest_offset + instr.flow_control.num_instructions);
374 } else {
375 call(state,
376 instr.flow_control.dest_offset,
377 instr.flow_control.num_instructions,
378 instr.flow_control.dest_offset + instr.flow_control.num_instructions);
379 }
205 380
206 *++state.call_stack_pointer = state.program_counter - shader_memory;
207 // TODO: Does this offset refer to the beginning of shader memory?
208 state.program_counter = &shader_memory[instr.flow_control.offset_words];
209 break; 381 break;
210 382
211 case Instruction::OpCode::FLS: 383 case Instruction::OpCode::IFC:
212 // TODO: Do whatever needs to be done here? 384 {
385 // TODO: Do we need to consider swizzlers here?
386
387 auto flow_control = instr.flow_control;
388 bool results[3] = { (bool)flow_control.refx == state.conditional_code[0],
389 (bool)flow_control.refy == state.conditional_code[1] };
390
391 switch (flow_control.op) {
392 case flow_control.Or:
393 results[2] = results[0] || results[1];
394 break;
395
396 case flow_control.And:
397 results[2] = results[0] && results[1];
398 break;
399
400 case flow_control.JustX:
401 results[2] = results[0];
402 break;
403
404 case flow_control.JustY:
405 results[2] = results[1];
406 break;
407 }
408
409 if (results[2]) {
410 call(state,
411 binary_offset + 1,
412 instr.flow_control.dest_offset - binary_offset - 1,
413 instr.flow_control.dest_offset + instr.flow_control.num_instructions);
414 } else {
415 call(state,
416 instr.flow_control.dest_offset,
417 instr.flow_control.num_instructions,
418 instr.flow_control.dest_offset + instr.flow_control.num_instructions);
419 }
420
213 break; 421 break;
422 }
214 423
215 default: 424 default:
216 ERROR_LOG(GPU, "Unhandled instruction: 0x%02x (%s): 0x%08x", 425 LOG_ERROR(HW_GPU, "Unhandled instruction: 0x%02x (%s): 0x%08x",
217 (int)instr.opcode.Value(), instr.GetOpCodeName().c_str(), instr.hex); 426 (int)instr.opcode.Value(), instr.opcode.GetInfo().name, instr.hex);
218 break; 427 break;
428 }
429
430 break;
219 } 431 }
220 432
221 if (increment_pc) 433 ++state.program_counter;
222 ++state.program_counter;
223 434
224 if (exit_loop) 435 if (exit_loop)
225 break; 436 break;
@@ -238,7 +449,7 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes)
238 // Setup input register table 449 // Setup input register table
239 const auto& attribute_register_map = registers.vs_input_register_map; 450 const auto& attribute_register_map = registers.vs_input_register_map;
240 float24 dummy_register; 451 float24 dummy_register;
241 std::fill(&state.input_register_table[0], &state.input_register_table[16], &dummy_register); 452 boost::fill(state.input_register_table, &dummy_register);
242 if(num_attributes > 0) state.input_register_table[attribute_register_map.attribute0_register] = &input.attr[0].x; 453 if(num_attributes > 0) state.input_register_table[attribute_register_map.attribute0_register] = &input.attr[0].x;
243 if(num_attributes > 1) state.input_register_table[attribute_register_map.attribute1_register] = &input.attr[1].x; 454 if(num_attributes > 1) state.input_register_table[attribute_register_map.attribute1_register] = &input.attr[1].x;
244 if(num_attributes > 2) state.input_register_table[attribute_register_map.attribute2_register] = &input.attr[2].x; 455 if(num_attributes > 2) state.input_register_table[attribute_register_map.attribute2_register] = &input.attr[2].x;
@@ -258,6 +469,10 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes)
258 469
259 // Setup output register table 470 // Setup output register table
260 OutputVertex ret; 471 OutputVertex ret;
472 // Zero output so that attributes which aren't output won't have denormals in them, which will
473 // slow us down later.
474 memset(&ret, 0, sizeof(ret));
475
261 for (int i = 0; i < 7; ++i) { 476 for (int i = 0; i < 7; ++i) {
262 const auto& output_register_map = registers.vs_output_attributes[i]; 477 const auto& output_register_map = registers.vs_output_attributes[i];
263 478
@@ -270,18 +485,15 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes)
270 state.output_register_table[4*i+comp] = ((float24*)&ret) + semantics[comp]; 485 state.output_register_table[4*i+comp] = ((float24*)&ret) + semantics[comp];
271 } 486 }
272 487
273 state.status_registers[0] = false; 488 state.conditional_code[0] = false;
274 state.status_registers[1] = false; 489 state.conditional_code[1] = false;
275 std::fill(state.call_stack, state.call_stack + sizeof(state.call_stack) / sizeof(state.call_stack[0]),
276 VertexShaderState::INVALID_ADDRESS);
277 state.call_stack_pointer = &state.call_stack[0];
278 490
279 ProcessShaderCode(state); 491 ProcessShaderCode(state);
280 DebugUtils::DumpShader(shader_memory, state.debug.max_offset, swizzle_data, 492 DebugUtils::DumpShader(shader_memory.data(), state.debug.max_offset, swizzle_data.data(),
281 state.debug.max_opdesc_id, registers.vs_main_offset, 493 state.debug.max_opdesc_id, registers.vs_main_offset,
282 registers.vs_output_attributes); 494 registers.vs_output_attributes);
283 495
284 DEBUG_LOG(GPU, "Output vertex: pos (%.2f, %.2f, %.2f, %.2f), col(%.2f, %.2f, %.2f, %.2f), tc0(%.2f, %.2f)", 496 LOG_TRACE(Render_Software, "Output vertex: pos (%.2f, %.2f, %.2f, %.2f), col(%.2f, %.2f, %.2f, %.2f), tc0(%.2f, %.2f)",
285 ret.pos.x.ToFloat32(), ret.pos.y.ToFloat32(), ret.pos.z.ToFloat32(), ret.pos.w.ToFloat32(), 497 ret.pos.x.ToFloat32(), ret.pos.y.ToFloat32(), ret.pos.z.ToFloat32(), ret.pos.w.ToFloat32(),
286 ret.color.x.ToFloat32(), ret.color.y.ToFloat32(), ret.color.z.ToFloat32(), ret.color.w.ToFloat32(), 498 ret.color.x.ToFloat32(), ret.color.y.ToFloat32(), ret.color.z.ToFloat32(), ret.color.w.ToFloat32(),
287 ret.tc0.u().ToFloat32(), ret.tc0.v().ToFloat32()); 499 ret.tc0.u().ToFloat32(), ret.tc0.v().ToFloat32());
diff --git a/src/video_core/vertex_shader.h b/src/video_core/vertex_shader.h
index bfb6fb6e3..af3fb2a2f 100644
--- a/src/video_core/vertex_shader.h
+++ b/src/video_core/vertex_shader.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once
@@ -27,15 +27,18 @@ struct OutputVertex {
27 Math::Vec4<float24> dummy; // quaternions (not implemented, yet) 27 Math::Vec4<float24> dummy; // quaternions (not implemented, yet)
28 Math::Vec4<float24> color; 28 Math::Vec4<float24> color;
29 Math::Vec2<float24> tc0; 29 Math::Vec2<float24> tc0;
30 Math::Vec2<float24> tc1;
31 float24 pad[6];
32 Math::Vec2<float24> tc2;
30 33
31 // Padding for optimal alignment 34 // Padding for optimal alignment
32 float24 pad[14]; 35 float24 pad2[4];
33 36
34 // Attributes used to store intermediate results 37 // Attributes used to store intermediate results
35 38
36 // position after perspective divide 39 // position after perspective divide
37 Math::Vec3<float24> screenpos; 40 Math::Vec3<float24> screenpos;
38 float24 pad2; 41 float24 pad3;
39 42
40 // Linear interpolation 43 // Linear interpolation
41 // factor: 0=this, 1=vtx 44 // factor: 0=this, 1=vtx
@@ -44,6 +47,8 @@ struct OutputVertex {
44 47
45 // TODO: Should perform perspective correct interpolation here... 48 // TODO: Should perform perspective correct interpolation here...
46 tc0 = tc0 * factor + vtx.tc0 * (float24::FromFloat32(1) - factor); 49 tc0 = tc0 * factor + vtx.tc0 * (float24::FromFloat32(1) - factor);
50 tc1 = tc1 * factor + vtx.tc1 * (float24::FromFloat32(1) - factor);
51 tc2 = tc2 * factor + vtx.tc2 * (float24::FromFloat32(1) - factor);
47 52
48 screenpos = screenpos * factor + vtx.screenpos * (float24::FromFloat32(1) - factor); 53 screenpos = screenpos * factor + vtx.screenpos * (float24::FromFloat32(1) - factor);
49 54
@@ -61,222 +66,16 @@ struct OutputVertex {
61static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); 66static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD");
62static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size"); 67static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size");
63 68
64union Instruction {
65 enum class OpCode : u32 {
66 ADD = 0x0,
67 DP3 = 0x1,
68 DP4 = 0x2,
69
70 MUL = 0x8,
71
72 MAX = 0xC,
73 MIN = 0xD,
74 RCP = 0xE,
75 RSQ = 0xF,
76
77 MOV = 0x13,
78
79 RET = 0x21,
80 FLS = 0x22, // Flush
81 CALL = 0x24,
82 };
83
84 std::string GetOpCodeName() const {
85 std::map<OpCode, std::string> map = {
86 { OpCode::ADD, "ADD" },
87 { OpCode::DP3, "DP3" },
88 { OpCode::DP4, "DP4" },
89 { OpCode::MUL, "MUL" },
90 { OpCode::MAX, "MAX" },
91 { OpCode::MIN, "MIN" },
92 { OpCode::RCP, "RCP" },
93 { OpCode::RSQ, "RSQ" },
94 { OpCode::MOV, "MOV" },
95 { OpCode::RET, "RET" },
96 { OpCode::FLS, "FLS" },
97 };
98 auto it = map.find(opcode);
99 if (it == map.end())
100 return "UNK";
101 else
102 return it->second;
103 }
104
105 u32 hex;
106
107 BitField<0x1a, 0x6, OpCode> opcode;
108
109 // General notes:
110 //
111 // When two input registers are used, one of them uses a 5-bit index while the other
112 // one uses a 7-bit index. This is because at most one floating point uniform may be used
113 // as an input.
114
115
116 // Format used e.g. by arithmetic instructions and comparisons
117 // "src1" and "src2" specify register indices (i.e. indices referring to groups of 4 floats),
118 // while "dest" addresses individual floats.
119 union {
120 BitField<0x00, 0x5, u32> operand_desc_id;
121
122 template<class BitFieldType>
123 struct SourceRegister : BitFieldType {
124 enum RegisterType {
125 Input,
126 Temporary,
127 FloatUniform
128 };
129
130 RegisterType GetRegisterType() const {
131 if (BitFieldType::Value() < 0x10)
132 return Input;
133 else if (BitFieldType::Value() < 0x20)
134 return Temporary;
135 else
136 return FloatUniform;
137 }
138
139 int GetIndex() const {
140 if (GetRegisterType() == Input)
141 return BitFieldType::Value();
142 else if (GetRegisterType() == Temporary)
143 return BitFieldType::Value() - 0x10;
144 else // if (GetRegisterType() == FloatUniform)
145 return BitFieldType::Value() - 0x20;
146 }
147
148 std::string GetRegisterName() const {
149 std::map<RegisterType, std::string> type = {
150 { Input, "i" },
151 { Temporary, "t" },
152 { FloatUniform, "f" },
153 };
154 return type[GetRegisterType()] + std::to_string(GetIndex());
155 }
156 };
157
158 SourceRegister<BitField<0x07, 0x5, u32>> src2;
159 SourceRegister<BitField<0x0c, 0x7, u32>> src1;
160
161 struct : BitField<0x15, 0x5, u32>
162 {
163 enum RegisterType {
164 Output,
165 Temporary,
166 Unknown
167 };
168 RegisterType GetRegisterType() const {
169 if (Value() < 0x8)
170 return Output;
171 else if (Value() < 0x10)
172 return Unknown;
173 else
174 return Temporary;
175 }
176 int GetIndex() const {
177 if (GetRegisterType() == Output)
178 return Value();
179 else if (GetRegisterType() == Temporary)
180 return Value() - 0x10;
181 else
182 return Value();
183 }
184 std::string GetRegisterName() const {
185 std::map<RegisterType, std::string> type = {
186 { Output, "o" },
187 { Temporary, "t" },
188 { Unknown, "u" }
189 };
190 return type[GetRegisterType()] + std::to_string(GetIndex());
191 }
192 } dest;
193 } common;
194
195 // Format used for flow control instructions ("if")
196 union {
197 BitField<0x00, 0x8, u32> num_instructions;
198 BitField<0x0a, 0xc, u32> offset_words;
199 } flow_control;
200};
201static_assert(std::is_standard_layout<Instruction>::value, "Structure is not using standard layout!");
202
203union SwizzlePattern {
204 u32 hex;
205
206 enum class Selector : u32 {
207 x = 0,
208 y = 1,
209 z = 2,
210 w = 3
211 };
212
213 Selector GetSelectorSrc1(int comp) const {
214 Selector selectors[] = {
215 src1_selector_0, src1_selector_1, src1_selector_2, src1_selector_3
216 };
217 return selectors[comp];
218 }
219
220 Selector GetSelectorSrc2(int comp) const {
221 Selector selectors[] = {
222 src2_selector_0, src2_selector_1, src2_selector_2, src2_selector_3
223 };
224 return selectors[comp];
225 }
226
227 bool DestComponentEnabled(int i) const {
228 return (dest_mask & (0x8 >> i)) != 0;
229 }
230
231 std::string SelectorToString(bool src2) const {
232 std::map<Selector, std::string> map = {
233 { Selector::x, "x" },
234 { Selector::y, "y" },
235 { Selector::z, "z" },
236 { Selector::w, "w" }
237 };
238 std::string ret;
239 for (int i = 0; i < 4; ++i) {
240 ret += map.at(src2 ? GetSelectorSrc2(i) : GetSelectorSrc1(i));
241 }
242 return ret;
243 }
244
245 std::string DestMaskToString() const {
246 std::string ret;
247 for (int i = 0; i < 4; ++i) {
248 if (!DestComponentEnabled(i))
249 ret += "_";
250 else
251 ret += "xyzw"[i];
252 }
253 return ret;
254 }
255
256 // Components of "dest" that should be written to: LSB=dest.w, MSB=dest.x
257 BitField< 0, 4, u32> dest_mask;
258
259 BitField< 4, 1, u32> negate; // negates src1
260
261 BitField< 5, 2, Selector> src1_selector_3;
262 BitField< 7, 2, Selector> src1_selector_2;
263 BitField< 9, 2, Selector> src1_selector_1;
264 BitField<11, 2, Selector> src1_selector_0;
265
266 BitField<14, 2, Selector> src2_selector_3;
267 BitField<16, 2, Selector> src2_selector_2;
268 BitField<18, 2, Selector> src2_selector_1;
269 BitField<20, 2, Selector> src2_selector_0;
270
271 BitField<31, 1, u32> flag; // not sure what this means, maybe it's the sign?
272};
273
274void SubmitShaderMemoryChange(u32 addr, u32 value); 69void SubmitShaderMemoryChange(u32 addr, u32 value);
275void SubmitSwizzleDataChange(u32 addr, u32 value); 70void SubmitSwizzleDataChange(u32 addr, u32 value);
276 71
277OutputVertex RunShader(const InputVertex& input, int num_attributes); 72OutputVertex RunShader(const InputVertex& input, int num_attributes);
278 73
279Math::Vec4<float24>& GetFloatUniform(u32 index); 74Math::Vec4<float24>& GetFloatUniform(u32 index);
75bool& GetBoolUniform(u32 index);
76
77const std::array<u32, 1024>& GetShaderBinary();
78const std::array<u32, 1024>& GetSwizzlePatterns();
280 79
281} // namespace 80} // namespace
282 81
diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp
index c779771c5..c9707e5f1 100644
--- a/src/video_core/video_core.cpp
+++ b/src/video_core/video_core.cpp
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common.h" 5#include "common/common.h"
@@ -17,8 +17,8 @@
17 17
18namespace VideoCore { 18namespace VideoCore {
19 19
20EmuWindow* g_emu_window = NULL; ///< Frontend emulator window 20EmuWindow* g_emu_window = nullptr; ///< Frontend emulator window
21RendererBase* g_renderer = NULL; ///< Renderer plugin 21RendererBase* g_renderer = nullptr; ///< Renderer plugin
22int g_current_frame = 0; 22int g_current_frame = 0;
23 23
24/// Initialize the video core 24/// Initialize the video core
@@ -30,13 +30,13 @@ void Init(EmuWindow* emu_window) {
30 30
31 g_current_frame = 0; 31 g_current_frame = 0;
32 32
33 NOTICE_LOG(VIDEO, "initialized OK"); 33 LOG_DEBUG(Render, "initialized OK");
34} 34}
35 35
36/// Shutdown the video core 36/// Shutdown the video core
37void Shutdown() { 37void Shutdown() {
38 delete g_renderer; 38 delete g_renderer;
39 NOTICE_LOG(VIDEO, "shutdown OK"); 39 LOG_DEBUG(Render, "shutdown OK");
40} 40}
41 41
42} // namespace 42} // namespace
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h
index 609aac513..b782f17bd 100644
--- a/src/video_core/video_core.h
+++ b/src/video_core/video_core.h
@@ -1,5 +1,5 @@
1// Copyright 2014 Citra Emulator Project 1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once 5#pragma once